[cdo] 01/11: New upstream 1.8.0

Alastair McKinstry mckinstry at moszumanska.debian.org
Thu Apr 20 10:40:35 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 95a63f3c514d0ccb546034cc61212eb18db9b685
Author: Alastair McKinstry <mckinstry at debian.org>
Date:   Wed Mar 1 14:08:10 2017 +0000

    New upstream 1.8.0
---
 ChangeLog                                     |   137 +
 NEWS                                          |    21 +
 OPERATORS                                     |     7 +-
 cdo.spec                                      |     2 +-
 config/default                                |   104 +-
 configure                                     |    74 +-
 configure.ac                                  |     9 +-
 contrib/cdoCompletion.bash                    |    18 +-
 contrib/cdoCompletion.tcsh                    |    18 +-
 contrib/cdoCompletion.zsh                     |    18 +-
 doc/cdo.pdf                                   |   Bin 2658585 -> 2676082 bytes
 doc/cdo_eca.pdf                               |   Bin 214623 -> 215421 bytes
 doc/cdo_magics.pdf                            |   Bin 829846 -> 829886 bytes
 doc/cdo_refcard.pdf                           |   Bin 92975 -> 94001 bytes
 libcdi/ChangeLog                              |   105 +-
 libcdi/Makefile.in                            |     4 -
 libcdi/NEWS                                   |     8 +
 libcdi/app/Makefile.in                        |     4 -
 libcdi/app/cdi.c                              |   204 +-
 libcdi/app/printinfo.h                        |   640 +-
 libcdi/configure                              |   558 +-
 libcdi/configure.ac                           |     2 +-
 libcdi/doc/cdi_cman.pdf                       |   Bin 335148 -> 335590 bytes
 libcdi/doc/cdi_fman.pdf                       |   Bin 363677 -> 364027 bytes
 libcdi/examples/Makefile.in                   |     4 -
 libcdi/examples/cdi_copy.c                    |     2 +-
 libcdi/examples/cdi_write.c                   |     2 +-
 libcdi/examples/cdi_write_ens.c               |     2 +-
 libcdi/examples/cdi_write_f2003.f90           |     2 +-
 libcdi/examples/cdi_write_hybrid.c            |     2 +-
 libcdi/examples/pio/Makefile.in               |     4 -
 libcdi/examples/pio/collectData.c             |     2 +-
 libcdi/examples/pio/collectData2003.F90       |     2 +-
 libcdi/examples/pio/collectDataNStreams.c     |     2 +-
 libcdi/examples/pio/compareResourcesArray.c   |     4 +-
 libcdi/interfaces/Makefile.in                 |     4 -
 libcdi/m4/acx_options.m4                      |    86 +-
 libcdi/src/Makefile.am                        |    13 +-
 libcdi/src/Makefile.in                        |   117 +-
 libcdi/src/basetime.c                         |    13 +-
 libcdi/src/basetime.h                         |     4 +-
 libcdi/src/cdf.c                              |    14 +-
 libcdi/src/cdf_int.c                          |    13 +
 libcdi/src/cdf_int.h                          |     1 +
 libcdi/src/cdf_lazy_grid.c                    |   535 +
 libcdi/src/cdf_lazy_grid.h                    |    60 +
 libcdi/src/cdf_read.c                         |    80 +-
 libcdi/src/cdf_util.c                         |   335 +
 libcdi/src/cdf_util.h                         |    30 +
 libcdi/src/cdf_write.c                        |   401 +-
 libcdi/src/cdi.h                              |   347 +-
 libcdi/src/cdi.inc                            |   601 +-
 libcdi/src/cdiFortran.c                       |    90 +-
 libcdi/src/{vlist_att.c => cdi_att.c}         |   352 +-
 libcdi/src/cdi_att.h                          |    53 +
 libcdi/src/cdi_int.c                          |    31 +-
 libcdi/src/cdi_int.h                          |    40 +-
 libcdi/src/cdilib.c                           | 70426 ++++++++++++------------
 libcdi/src/cgribex.h                          |     8 +-
 libcdi/src/cgribexlib.c                       |   360 +-
 libcdi/src/config.h.in                        |    18 -
 libcdi/src/file.c                             |     4 +-
 libcdi/src/gaussgrid.c                        |   214 +-
 libcdi/src/gaussgrid.h                        |     3 +
 libcdi/src/grb_read.c                         |    16 +-
 libcdi/src/grb_write.c                        |    25 +-
 libcdi/src/gribapi.c                          |     6 +-
 libcdi/src/gribapi_utilities.c                |   475 +-
 libcdi/src/grid.c                             |  2345 +-
 libcdi/src/grid.h                             |   111 +-
 libcdi/src/ieg.h                              |     1 -
 libcdi/src/institution.c                      |    48 +-
 libcdi/src/iterator.c                         |   318 +-
 libcdi/src/iterator_grib.c                    |     2 +-
 libcdi/src/mo_cdi.f90                         |   762 +-
 libcdi/src/model.c                            |    40 +-
 libcdi/src/pio_interface.c                    |     6 +-
 libcdi/src/pio_mpi_fw_at_all.c                |     2 +-
 libcdi/src/pio_mpi_fw_at_reblock.c            |     2 +-
 libcdi/src/pio_serialize.c                    |    28 +-
 libcdi/src/pio_server.c                       |    22 +-
 libcdi/src/pio_util.c                         |     4 +-
 libcdi/src/resource_handle.c                  |    47 +-
 libcdi/src/resource_handle.h                  |     1 +
 libcdi/src/resource_unpack.c                  |     6 +-
 libcdi/src/serialize.c                        |    18 +-
 libcdi/src/serialize.h                        |    22 +-
 libcdi/src/stream.c                           |   368 +-
 libcdi/src/stream_cdf.c                       |  7180 ---
 libcdi/src/stream_cdf.h                       |     8 +
 libcdi/src/stream_cdf_i.c                     |  4074 ++
 libcdi/src/stream_cdf_o.c                     |  2115 +
 libcdi/src/stream_cgribex.c                   |   641 +-
 libcdi/src/stream_ext.c                       |   436 +-
 libcdi/src/stream_fcommon.c                   |    42 -
 libcdi/src/stream_fcommon.h                   |    20 -
 libcdi/src/stream_grb.c                       |    13 +-
 libcdi/src/stream_gribapi.c                   |   370 +-
 libcdi/src/stream_history.c                   |    24 +-
 libcdi/src/stream_ieg.c                       |   783 +-
 libcdi/src/stream_read.c                      |    54 +-
 libcdi/src/stream_record.c                    |   134 +-
 libcdi/src/stream_srv.c                       |   402 +-
 libcdi/src/stream_var.c                       |    39 +-
 libcdi/src/stream_write.c                     |    93 +-
 libcdi/src/table.c                            |    62 +-
 libcdi/src/taxis.c                            |   232 +-
 libcdi/src/taxis.h                            |    12 +-
 libcdi/src/util.c                             |     7 +-
 libcdi/src/varscan.c                          |   389 +-
 libcdi/src/varscan.h                          |     4 +-
 libcdi/src/vlist.c                            |   256 +-
 libcdi/src/vlist.h                            |    70 +-
 libcdi/src/vlist_att.h                        |    30 -
 libcdi/src/vlist_var.c                        |   197 +-
 libcdi/src/zaxis.c                            |   785 +-
 libcdi/src/zaxis.h                            |    47 +
 libcdi/tests/Makefile.in                      |     4 -
 libcdi/tests/cksum_write.c                    |    20 +-
 libcdi/tests/deco2d_model.c                   |     2 +-
 libcdi/tests/pio_write.c                      |    18 +-
 libcdi/tests/simple_model.c                   |     2 +-
 libcdi/tests/simple_model_helper.c            |    16 +-
 libcdi/tests/test_cdf_read.c                  |    30 +-
 libcdi/tests/test_cdf_write.c                 |     6 +-
 libcdi/tests/test_grib.c                      |     2 +-
 libcdi/tests/test_resource_copy.c             |    20 +-
 m4/acx_options.m4                             |     7 +-
 src/Adisit.c                                  |   171 +-
 src/Afterburner.c                             |    86 +-
 src/Arith.c                                   |    27 +-
 src/Arithc.c                                  |    10 +-
 src/Arithdays.c                               |    61 +-
 src/Arithlat.c                                |    41 +-
 src/CDIread.c                                 |    68 +-
 src/CDItest.c                                 |     6 +-
 src/CDIwrite.c                                |    62 +-
 src/CMOR.c                                    |   804 +-
 src/CMOR_lite.c                               |   573 +
 src/CMOR_table.c                              |   163 +
 src/Cat.c                                     |    40 +-
 src/Change.c                                  |   157 +-
 src/Change_e5slm.c                            |    53 +-
 src/Cloudlayer.c                              |    24 +-
 src/Collgrid.c                                |    58 +-
 src/Command.c                                 |    23 +-
 src/Comp.c                                    |   119 +-
 src/Compc.c                                   |    51 +-
 src/Complextorect.c                           |    58 +-
 src/Cond.c                                    |    51 +-
 src/Cond2.c                                   |    55 +-
 src/Condc.c                                   |    43 +-
 src/Consecstat.c                              |    45 +-
 src/Copy.c                                    |     8 +-
 src/{Timedt.c => Deltat.c}                    |     8 +-
 src/Deltime.c                                 |     7 +-
 src/Derivepar.c                               |     7 +-
 src/Detrend.c                                 |    25 +-
 src/Diff.c                                    |    10 +-
 src/Distgrid.c                                |   158 +-
 src/Duplicate.c                               |    13 +-
 src/EOFs.c                                    |   143 +-
 src/Echam5ini.c                               |    32 +-
 src/Enlarge.c                                 |    43 +-
 src/Enlargegrid.c                             |    75 +-
 src/Ensstat.c                                 |    75 +-
 src/Ensstat3.c                                |    73 +-
 src/Ensval.c                                  |    73 +-
 src/Eof3d.c                                   |   199 +-
 src/Eofcoeff.c                                |   111 +-
 src/Eofcoeff3d.c                              |   116 +-
 src/Exprf.c                                   |    26 +-
 src/FC.c                                      |    28 +-
 src/Filedes.c                                 |   270 +-
 src/Fillmiss.c                                |    16 +-
 src/Filter.c                                  |    65 +-
 src/Fldrms.c                                  |    57 +-
 src/Fldstat.c                                 |   100 +-
 src/Fldstat2.c                                |    40 +-
 src/Fourier.c                                 |    41 +-
 src/Gengrid.c                                 |    72 +-
 src/Gradsdes.c                                |   138 +-
 src/Gridboxstat.c                             |   123 +-
 src/Gridcell.c                                |    97 +-
 src/Gridsearch.c                              |   264 +-
 src/Harmonic.c                                |    95 +-
 src/Hi.c                                      |    59 +-
 src/Histogram.c                               |    93 +-
 src/Importamsr.c                              |    54 +-
 src/Importbinary.c                            |    87 +-
 src/Importcmsaf.c                             |   122 +-
 src/Importobs.c                               |    24 +-
 src/Info.c                                    |    83 +-
 src/Input.c                                   |     9 +-
 src/Intgrid.c                                 |   220 +-
 src/Intgridtraj.c                             |    98 +-
 src/Intlevel.c                                |    53 +-
 src/Intlevel3d.c                              |    16 +-
 src/Intntime.c                                |   108 +-
 src/Inttime.c                                 |   100 +-
 src/Intyear.c                                 |    93 +-
 src/Invert.c                                  |   122 +-
 src/Invertlev.c                               |     8 +-
 src/Isosurface.c                              |    97 +-
 src/Kvl.c                                     |   200 -
 src/Log.c                                     |    30 +-
 src/Makefile.am                               |    35 +-
 src/Makefile.in                               |   518 +-
 src/MapReduce.c                               |    14 +-
 src/Maskbox.c                                 |   213 +-
 src/Mastrfu.c                                 |    12 +-
 src/Math.c                                    |     2 +-
 src/Merge.c                                   |   116 +-
 src/Mergegrid.c                               |    98 +-
 src/Mergetime.c                               |     9 +-
 src/Merstat.c                                 |    12 +-
 src/Monarith.c                                |    70 +-
 src/Mrotuv.c                                  |   123 +-
 src/Mrotuvb.c                                 |    48 +-
 src/Ninfo.c                                   |    72 +-
 src/Nmldump.c                                 |   103 +
 src/Nmltest.c                                 |    57 -
 src/Output.c                                  |   165 +-
 src/Outputgmt.c                               |   129 +-
 src/Pack.c                                    |    38 +-
 src/Pardup.c                                  |    13 +-
 src/Pinfo.c                                   |    62 +-
 src/Pressure.c                                |    58 +-
 src/Regres.c                                  |    75 +-
 src/Remap.c                                   |   219 +-
 src/Remapeta.c                                |    92 +-
 src/Replace.c                                 |    41 +-
 src/Replacevalues.c                           |    76 +-
 src/Rhopot.c                                  |    92 +-
 src/Rotuv.c                                   |    96 +-
 src/Runpctl.c                                 |    60 +-
 src/Runstat.c                                 |    78 +-
 src/Seascount.c                               |    74 +-
 src/Seaspctl.c                                |    57 +-
 src/Seasstat.c                                |    46 +-
 src/Selbox.c                                  |   384 +-
 src/Select.c                                  |   297 +-
 src/Selindex.c                                |   229 +
 src/Seloperator.c                             |    10 +-
 src/Selrec.c                                  |    49 +-
 src/Seltime.c                                 |    50 +-
 src/Selvar.c                                  |   142 +-
 src/Set.c                                     |    56 +-
 src/Setattribute.c                            |   277 +
 src/Setbox.c                                  |     7 +-
 src/Setgatt.c                                 |    43 +-
 src/Setgrid.c                                 |   115 +-
 src/Sethalo.c                                 |   143 +-
 src/Setmiss.c                                 |     9 +-
 src/Setpartab.c                               |   774 +-
 src/Setrcaname.c                              |     8 +-
 src/Settime.c                                 |    42 +-
 src/Setzaxis.c                                |    15 +-
 src/Shiftxy.c                                 |   298 +
 src/Showinfo.c                                |     4 +-
 src/Sinfo.c                                   |    21 +-
 src/Smooth.c                                  |   123 +-
 src/Sort.c                                    |     8 +-
 src/Sorttimestamp.c                           |    53 +-
 src/Specinfo.c                                |   133 +-
 src/Spectral.c                                |    28 +-
 src/Spectrum.c                                |    65 +-
 src/Split.c                                   |   102 +-
 src/Splitrec.c                                |    11 +-
 src/Splitsel.c                                |    41 +-
 src/Splittime.c                               |    28 +-
 src/Splityear.c                               |    23 +-
 src/Subtrend.c                                |    60 +-
 src/Tee.c                                     |     2 +-
 src/Templates.c                               |     4 +-
 src/Test.c                                    |    48 +-
 src/Tests.c                                   |    56 +-
 src/Timcount.c                                |    63 +-
 src/Timcumsum.c                               |   116 +
 src/Timpctl.c                                 |    42 +-
 src/Timselpctl.c                              |    36 +-
 src/Timselstat.c                              |    27 +-
 src/Timsort.c                                 |    44 +-
 src/Timstat.c                                 |   100 +-
 src/Timstat2.c                                |    14 +-
 src/Timstat3.c                                |   119 +-
 src/Tinfo.c                                   |    22 +-
 src/Tocomplex.c                               |    63 +-
 src/Transpose.c                               |   101 +-
 src/Trend.c                                   |    84 +-
 src/Trms.c                                    |    85 +-
 src/Tstepcount.c                              |    56 +-
 src/Vargen.c                                  |    44 +-
 src/Varrms.c                                  |    69 +-
 src/Verifygrid.c                              |   420 +-
 src/Vertcum.c                                 |    52 +-
 src/Vertintap.c                               |    44 +-
 src/Vertintml.c                               |   242 +-
 src/Vertstat.c                                |    55 +-
 src/Vertwind.c                                |   126 +-
 src/Wct.c                                     |    44 +-
 src/Wind.c                                    |    23 +-
 src/Writegrid.c                               |    23 +-
 src/Writerandom.c                             |    56 +-
 src/XTimstat.c                                |   119 +-
 src/YAR.c                                     |    24 +-
 src/Ydayarith.c                               |     4 +-
 src/Ydaypctl.c                                |    13 +-
 src/Ydaystat.c                                |    14 +-
 src/Ydrunpctl.c                               |    22 +-
 src/Ydrunstat.c                               |    26 +-
 src/Yearmonstat.c                             |    24 +-
 src/Yhourarith.c                              |    47 +-
 src/Yhourstat.c                               |    63 +-
 src/Ymonarith.c                               |    16 +-
 src/Ymonpctl.c                                |    13 +-
 src/Ymonstat.c                                |    64 +-
 src/Yseaspctl.c                               |    13 +-
 src/Yseasstat.c                               |    20 +-
 src/Zonstat.c                                 |     8 +-
 src/after_fctrans.c                           |     2 +-
 src/after_namelist.c                          |    41 +-
 src/afterburnerlib.c                          |     2 +-
 src/array.c                                   |    81 +
 src/array.h                                   |    13 +
 src/cdo.c                                     |   220 +-
 src/cdo.h                                     |     2 +-
 src/cdo_getopt.c                              |     2 +-
 src/cdo_getopt.h                              |     2 +-
 src/cdo_history.c                             |     6 +-
 src/cdo_int.h                                 |    37 +-
 src/cdo_pthread.c                             |     2 +-
 src/cdo_vlist.c                               |   148 +-
 src/cdotest.c                                 |     4 +-
 src/cmortable_parser.c                        |   321 +
 src/commandline.c                             |     2 +-
 src/compare.h                                 |     4 +-
 src/convert_units.c                           |   190 +
 src/convert_units.h                           |    27 +
 src/datetime.c                                |     6 +-
 src/ecacore.c                                 |    78 +-
 src/ecacore.h                                 |     6 +-
 src/ecautil.c                                 |    55 +-
 src/ecautil.h                                 |    54 +-
 src/exception.c                               |    22 +-
 src/expr.c                                    |    61 +-
 src/expr.h                                    |     2 +-
 src/expr_fun.c                                |     6 +-
 src/expr_fun.h                                |     4 +-
 src/features.c                                |     3 -
 src/field.c                                   |   132 +-
 src/field.h                                   |   160 +-
 src/field2.c                                  |    59 +-
 src/fieldc.c                                  |    19 +-
 src/fieldmem.c                                |    16 +-
 src/fieldmer.c                                |    24 +-
 src/fieldzon.c                                |    26 +-
 src/functs.h                                  |     3 -
 src/grid.c                                    |   943 +-
 src/grid.h                                    |    15 +-
 src/grid_area.c                               |    78 +-
 src/grid_from_name.c                          |   400 +
 src/grid_gme.c                                |   185 +-
 src/grid_print.c                              |   422 +
 src/grid_read.c                               |   335 +
 src/grid_read_pingo.c                         |   192 +
 src/grid_rot.c                                |    80 +-
 src/grid_search.c                             |     2 +-
 src/grid_search.h                             |     2 +-
 src/griddes.c                                 |  1540 +-
 src/griddes.h                                 |    37 +-
 src/griddes_h5.c                              |   104 +-
 src/griddes_nc.c                              |    12 +-
 src/gridreference.c                           |    36 +-
 src/hetaeta.c                                 |    78 +-
 src/hetaeta.h                                 |    21 +-
 src/institution.c                             |     2 +-
 src/interpol.c                                |   567 +-
 src/interpol.h                                |     6 +-
 src/json/jsmn.c                               |   331 +
 src/json/jsmn.h                               |    79 +
 src/kdtreelib/kdtree.h                        |    11 +
 src/kdtreelib/kdtree_common.c                 |    52 +-
 src/kdtreelib/pmergesort.c                    |    79 +-
 src/kdtreelib/qsort.c                         |   321 +
 src/kvlist.c                                  |   428 -
 src/kvlist.h                                  |    32 -
 src/list.c                                    |   285 +-
 src/list.h                                    |    75 +-
 src/{list.c => listarray.c}                   |   107 +-
 src/{list.h => listarray.h}                   |    32 +-
 src/listbuf.c                                 |    70 +
 src/listbuf.h                                 |    20 +
 src/merge_sort2.c                             |    19 +-
 src/modules.c                                 |   154 +-
 src/modules.h                                 |    16 +-
 src/namelist.c                                |   728 +-
 src/namelist.h                                |    97 +-
 src/namelist_parser.c                         |   141 +
 src/operator_help.h                           |  1475 +-
 src/parse_literal.c                           |   136 +
 src/percentiles_hist.c                        |     6 +-
 src/percentiles_hist.h                        |     6 +-
 src/pipe.c                                    |    12 +-
 src/pipe.h                                    |     2 +-
 src/pmlist.c                                  |   507 +-
 src/pmlist.h                                  |    97 +-
 src/printinfo.h                               |   649 +-
 src/process.c                                 |     6 +-
 src/process.h                                 |     2 +-
 src/pstream.c                                 |   129 +-
 src/pstream.h                                 |     2 +-
 src/pstream_int.h                             |     2 +-
 src/pstream_write.h                           |     2 +-
 src/readline.c                                |     2 +-
 src/remap.h                                   |    23 +-
 src/remap_conserv.c                           |    11 +-
 src/remap_scrip_io.c                          |    48 +-
 src/remap_search_latbins.c                    |     2 +-
 src/remaplib.c                                |   465 +-
 src/sellist.c                                 |   361 +
 src/sellist.h                                 |    63 +
 src/specspace.c                               |     8 +-
 src/stdnametable.c                            |    12 +-
 src/table.c                                   |    11 +-
 src/timer.c                                   |    52 +-
 src/util.c                                    |   249 +-
 src/util.h                                    |    19 +-
 src/zaxis.c                                   |   472 +-
 src/zaxis_print.c                             |   107 +
 test/Arithc.test.in                           |     2 +-
 test/{Fldstat.test.in => Comp.test.in}        |    23 +-
 test/{Fldstat.test.in => Compc.test.in}       |    19 +-
 test/EOF.test.in                              |    64 +
 test/Fldstat.test.in                          |     9 +-
 test/{Fldstat.test.in => Gridboxstat.test.in} |     7 +-
 test/Makefile.am                              |    12 +-
 test/Makefile.in                              |    64 +-
 test/MapReduce.test.in                        |     5 +-
 test/{Fldstat.test.in => Merstat.test.in}     |     9 +-
 test/Multiyearstat.test.in                    |    49 +
 test/Ninfo.test.in                            |    12 +-
 test/{Timstat.test.in => Runstat.test.in}     |    11 +-
 test/{Ymonstat.test.in => Seasstat.test.in}   |    11 +-
 test/{Timstat.test.in => Timselstat.test.in}  |    11 +-
 test/Timstat.test.in                          |    51 +-
 test/{Fldstat.test.in => Vertstat.test.in}    |    15 +-
 test/{Fldstat.test.in => Zonstat.test.in}     |     9 +-
 test/data/Makefile.am                         |    17 +-
 test/data/Makefile.in                         |    17 +-
 test/data/comp_eqc_ref                        |   Bin 0 -> 16480 bytes
 test/data/comp_gec_ref                        |   Bin 0 -> 16480 bytes
 test/data/comp_gtc_ref                        |   Bin 0 -> 16480 bytes
 test/data/comp_lec_ref                        |   Bin 0 -> 16480 bytes
 test/data/comp_ltc_ref                        |   Bin 0 -> 16480 bytes
 test/data/comp_nec_ref                        |   Bin 0 -> 16480 bytes
 test/data/comptest.srv                        |   Bin 0 -> 16480 bytes
 test/data/dayavg_ref                          |   Bin 0 -> 1612 bytes
 test/data/daymax_ref                          |   Bin 0 -> 1612 bytes
 test/data/daymean_ref                         |   Bin 0 -> 1612 bytes
 test/data/daymin_ref                          |   Bin 0 -> 1612 bytes
 test/data/daystd1_ref                         |   Bin 0 -> 1612 bytes
 test/data/daystd_ref                          |   Bin 0 -> 1612 bytes
 test/data/daysum_ref                          |   Bin 0 -> 1612 bytes
 test/data/dayvar1_ref                         |   Bin 0 -> 1612 bytes
 test/data/dayvar_ref                          |   Bin 0 -> 1612 bytes
 test/data/eof_ref                             |   Bin 0 -> 9008 bytes
 test/data/eval_ref                            |   Bin 0 -> 1508 bytes
 test/data/griddes.icon_cell                   |   314 +-
 test/data/griddes.r18x9                       |     3 +
 test/data/meravg_ref                          |   Bin 0 -> 608 bytes
 test/data/mermax_ref                          |   Bin 0 -> 608 bytes
 test/data/mermean_ref                         |   Bin 0 -> 608 bytes
 test/data/mermin_ref                          |   Bin 0 -> 608 bytes
 test/data/merstd1_ref                         |   Bin 0 -> 608 bytes
 test/data/merstd_ref                          |   Bin 0 -> 608 bytes
 test/data/mersum_ref                          |   Bin 0 -> 608 bytes
 test/data/mervar1_ref                         |   Bin 0 -> 608 bytes
 test/data/mervar_ref                          |   Bin 0 -> 608 bytes
 test/data/monavg_ref                          |   Bin 0 -> 624 bytes
 test/data/monmax_ref                          |   Bin 0 -> 624 bytes
 test/data/monmean_ref                         |   Bin 0 -> 624 bytes
 test/data/monmin_ref                          |   Bin 0 -> 624 bytes
 test/data/monstd1_ref                         |   Bin 0 -> 624 bytes
 test/data/monstd_ref                          |   Bin 0 -> 624 bytes
 test/data/monsum_ref                          |   Bin 0 -> 624 bytes
 test/data/monvar1_ref                         |   Bin 0 -> 624 bytes
 test/data/monvar_ref                          |   Bin 0 -> 624 bytes
 test/data/pcoeff00000                         |   Bin 0 -> 1508 bytes
 test/data/psl_DJF_anom.grb                    |   Bin 0 -> 132472 bytes
 test/data/runavg_ref                          |   Bin 0 -> 2548 bytes
 test/data/runmax_ref                          |   Bin 0 -> 2548 bytes
 test/data/runmean_ref                         |   Bin 0 -> 2548 bytes
 test/data/runmin_ref                          |   Bin 0 -> 2548 bytes
 test/data/runstd1_ref                         |   Bin 0 -> 2548 bytes
 test/data/runstd_ref                          |   Bin 0 -> 2548 bytes
 test/data/runsum_ref                          |   Bin 0 -> 2548 bytes
 test/data/runvar1_ref                         |   Bin 0 -> 2548 bytes
 test/data/runvar_ref                          |   Bin 0 -> 2548 bytes
 test/data/seasavg_ref                         |   Bin 0 -> 1092 bytes
 test/data/seasmax_ref                         |   Bin 0 -> 1092 bytes
 test/data/seasmean_ref                        |   Bin 0 -> 1092 bytes
 test/data/seasmin_ref                         |   Bin 0 -> 1092 bytes
 test/data/seasstd1_ref                        |   Bin 0 -> 1092 bytes
 test/data/seasstd_ref                         |   Bin 0 -> 1092 bytes
 test/data/seassum_ref                         |   Bin 0 -> 1092 bytes
 test/data/seasvar1_ref                        |   Bin 0 -> 1092 bytes
 test/data/seasvar_ref                         |   Bin 0 -> 1092 bytes
 test/data/timavg_ref                          |   Bin 52 -> 52 bytes
 test/data/timmax_ref                          |   Bin 52 -> 52 bytes
 test/data/timmean_ref                         |   Bin 52 -> 52 bytes
 test/data/timmin_ref                          |   Bin 52 -> 52 bytes
 test/data/timstd1_ref                         |   Bin 52 -> 52 bytes
 test/data/timstd_ref                          |   Bin 52 -> 52 bytes
 test/data/timsum_ref                          |   Bin 52 -> 52 bytes
 test/data/timvar1_ref                         |   Bin 52 -> 52 bytes
 test/data/timvar_ref                          |   Bin 52 -> 52 bytes
 test/data/ts_1d_1year                         |   Bin 0 -> 18980 bytes
 test/data/ts_6h_1mon                          |   Bin 0 -> 6448 bytes
 test/data/ts_mm_5years                        |   Bin 3120 -> 3120 bytes
 test/data/vertavg_ref                         |   Bin 0 -> 5040 bytes
 test/data/vertint_ref                         |   Bin 0 -> 5040 bytes
 test/data/vertmax_ref                         |   Bin 0 -> 5040 bytes
 test/data/vertmean_ref                        |   Bin 0 -> 5040 bytes
 test/data/vertmin_ref                         |   Bin 0 -> 5040 bytes
 test/data/vertstd1_ref                        |   Bin 0 -> 5040 bytes
 test/data/vertstd_ref                         |   Bin 0 -> 5040 bytes
 test/data/vertsum_ref                         |   Bin 0 -> 5040 bytes
 test/data/vertvar1_ref                        |   Bin 0 -> 5040 bytes
 test/data/vertvar_ref                         |   Bin 0 -> 5040 bytes
 test/data/yearavg_ref                         |   Bin 0 -> 260 bytes
 test/data/yearmax_ref                         |   Bin 0 -> 260 bytes
 test/data/yearmean_ref                        |   Bin 0 -> 260 bytes
 test/data/yearmin_ref                         |   Bin 0 -> 260 bytes
 test/data/yearstd1_ref                        |   Bin 0 -> 260 bytes
 test/data/yearstd_ref                         |   Bin 0 -> 260 bytes
 test/data/yearsum_ref                         |   Bin 0 -> 260 bytes
 test/data/yearvar1_ref                        |   Bin 0 -> 260 bytes
 test/data/yearvar_ref                         |   Bin 0 -> 260 bytes
 test/data/ymonavg_ref                         |   Bin 624 -> 624 bytes
 test/data/ymonmax_ref                         |   Bin 624 -> 624 bytes
 test/data/ymonmean_ref                        |   Bin 624 -> 624 bytes
 test/data/ymonmin_ref                         |   Bin 624 -> 624 bytes
 test/data/ymonstd1_ref                        |   Bin 624 -> 624 bytes
 test/data/ymonstd_ref                         |   Bin 624 -> 624 bytes
 test/data/ymonsum_ref                         |   Bin 624 -> 624 bytes
 test/data/ymonvar1_ref                        |   Bin 624 -> 624 bytes
 test/data/ymonvar_ref                         |   Bin 624 -> 624 bytes
 test/data/yseasavg_ref                        |   Bin 0 -> 208 bytes
 test/data/yseasmax_ref                        |   Bin 0 -> 208 bytes
 test/data/yseasmean_ref                       |   Bin 0 -> 208 bytes
 test/data/yseasmin_ref                        |   Bin 0 -> 208 bytes
 test/data/yseasstd1_ref                       |   Bin 0 -> 208 bytes
 test/data/yseasstd_ref                        |   Bin 0 -> 208 bytes
 test/data/yseassum_ref                        |   Bin 0 -> 208 bytes
 test/data/yseasvar1_ref                       |   Bin 0 -> 208 bytes
 test/data/yseasvar_ref                        |   Bin 0 -> 208 bytes
 test/data/zonavg_ref                          |   Bin 0 -> 352 bytes
 test/data/zonmax_ref                          |   Bin 0 -> 352 bytes
 test/data/zonmean_ref                         |   Bin 0 -> 352 bytes
 test/data/zonmin_ref                          |   Bin 0 -> 352 bytes
 test/data/zonstd1_ref                         |   Bin 0 -> 352 bytes
 test/data/zonstd_ref                          |   Bin 0 -> 352 bytes
 test/data/zonsum_ref                          |   Bin 0 -> 352 bytes
 test/data/zonvar1_ref                         |   Bin 0 -> 352 bytes
 test/data/zonvar_ref                          |   Bin 0 -> 352 bytes
 566 files changed, 65366 insertions(+), 66341 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index b0fdeb5..7f2cb81 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,140 @@
+2017-02-14  Uwe Schulzweida
+
+	* Using CDI library version 1.8.0
+	* Version 1.8.0 release
+
+2017-02-07  Uwe Schulzweida
+
+	* New operator setattribute: set attributes
+
+2017-02-03  Uwe Schulzweida
+
+	* using CDI library version 1.8.0rc7
+	* Version 1.8.0rc7 release
+
+2017-02-03  Uwe Schulzweida
+
+	* Reverse: adjust date/time by -1 second (introduced in last revision)
+
+2017-01-28  Uwe Schulzweida
+
+	* Info: check floating-point exceptions
+
+2017-01-25  Uwe Schulzweida
+
+	* New operator timrange: time range (timmax-timmin)
+	* New operator fldrange: field range (fldmax-fldmin)
+	* remap:  optimzation for constant links per value
+
+2017-01-24  Uwe Schulzweida
+
+	* write_remap_scrip: write NeCDF4 for data larger than 8GB
+
+2017-01-19  Uwe Schulzweida
+
+	* using CDI library version 1.8.0rc6
+	* Version 1.8.0rc6 release
+
+2017-01-17  Uwe Schulzweida
+
+	* check hdf5 grid files for NetCDF4 attributes [Bug #7480]
+
+2017-01-11  Uwe Schulzweida
+
+	* env CDO_GRIDSEARCH_RADIUS: added support for units deg, rad, km, m [request: Stefan Hagemann]
+
+2017-01-03  Uwe Schulzweida
+
+	* eofcoeff: changed docu to "non weighted" (bug fix) [report: Torben Kunz]
+
+2017-01-02  Reiner Schnur
+
+	* griddx/griddy: changed yv to xv in call to grid_to_radian() (bug fix)
+
+2016-11-24  Uwe Schulzweida
+
+	* using CDI library version 1.8.0rc5
+	* Version 1.8.0rc5 release
+
+2016-11-14  Uwe Schulzweida
+
+	* Cond: bug fix for ntsteps1 == 1 && ntsteps2 != 1
+
+2016-11-10  Uwe Schulzweida
+
+	* New operator timcumsum: Cumulative sum over time.
+
+2016-11-04  Uwe Schulzweida
+
+	* using CDI library version 1.8.0rc4
+	* Version 1.8.0rc4 release
+
+2016-10-31  Uwe Schulzweida
+
+	* Setpartab: added support for user defined attributes
+
+2016-10-20  Uwe Schulzweida
+
+	* New operator cmorlite: apply variable_entry of cmor tables
+
+2016-10-19  Uwe Schulzweida
+
+	* conv_cmor_table: added support for CMOR CMIP6 tables
+
+2016-10-05  Uwe Schulzweida
+
+	* ml2pl: interpolation failed for data on hybrid half levels [Bug #7225]
+
+2016-10-04  Uwe Schulzweida
+
+	* using CDI library version 1.8.0rc3
+	* Version 1.8.0rc3 release
+
+2016-09-24  Uwe Schulzweida
+
+	* remapnn: optimize sort in kdtree (speedup ~20%)
+
+2016-09-19  Uwe Schulzweida
+
+	* New operator shiftx/shifty - Shift fields on rectangular grid in x/y direction
+
+2016-08-29  Uwe Schulzweida
+
+	* CDO option -v includes -W
+
+2016-08-18  Uwe Schulzweida
+
+	* using CDI library version 1.8.0rc2
+	* Version 1.8.0rc2 released
+
+2016-08-16  Uwe Schulzweida
+
+	* setzaxis: added support for internal zaxis name height_<value>_<units>
+
+2016-08-11  Uwe Schulzweida
+
+	* Changed handling of rotated lon/lat grids
+
+2016-08-10  Uwe Schulzweida
+
+	* Changed default of option -f nc to netCDF2
+
+2016-07-29  Uwe Schulzweida
+
+	* New operator selindex - Select grid indices
+
+2016-07-18  Uwe Schulzweida
+
+	* setgrid: added parameter regularnn
+
+2016-07-15  Uwe Schulzweida
+
+	* masklonlatbox: added support for unstructured grids
+
+2016-07-02  Uwe Schulzweida
+
+	* pstreamOpenAppend: added call to set_comp() (bug fix)
+
 2016-06-28  Uwe Schulzweida
 
 	* using CDI library version 1.7.2
diff --git a/NEWS b/NEWS
index f4a556c..1d31332 100644
--- a/NEWS
+++ b/NEWS
@@ -1,8 +1,28 @@
 CDO NEWS
 --------
 
+Version 1.8.0 (26 October 2016):
+
+   New features:
+     * NetCDF: Improved support for horizontal and vertical grids 
+     * Changed default of option -f nc to netCDF2
+     * masklonlatbox: added support for unstructured grids
+     * setpartabn: added support for user defined attributes
+     * Reverse: adjust date/time by -1 second (introduced in last revision)
+   New operators:
+     * setattribute: Set attributes
+     * cmorlite: Apply variable_entry of cmor tables
+     * timcumsum: Cumulative sum over time.
+     * shiftx/shifty: Shift fields on rectilinear/curvilinear grids in x/y direction
+   Fixed bugs:
+     * Cond: bug fix for ntsteps1 == 1 && ntsteps2 != 1
+     * ml2pl: interpolation failed for data on hybrid half levels [Bug #7225]
+
 Version 1.7.2 (28 June 2016):
 
+   New features:
+     * Adjust date/time by -1 second if the varification time is 00:00:00 and
+       the verification date is equal to upper time bound
    New operators:
      * smooth: Smooth grid points
      * ap2hl: Air pressure to height level interpolation
@@ -20,6 +40,7 @@ Version 1.7.2 (28 June 2016):
      * mul: wrong result for missval*0 (bug was introduced in 1.7.1)
      * nint: wrong result (replaced round() by lround())
      * shaded, contour, grfill: set NAN missvals to -9e33 [Bug: #6677]
+     * expr: fix problem with missing values in time constant mask and a timeseries
 
 Version 1.7.1 (25 February 2016):
 
diff --git a/OPERATORS b/OPERATORS
index 999dfcd..a8b555d 100644
--- a/OPERATORS
+++ b/OPERATORS
@@ -121,6 +121,7 @@ Operator catalog:
 -------------------------------------------------------------
    Modification
 -------------------------------------------------------------
+   Setattributes setattribute    Set attributes
    Setpartab     setpartabp      Set parameter table
    Setpartab     setpartabn      Set parameter table
    Set           setcodetab      Set parameter code table
@@ -153,10 +154,10 @@ Operator catalog:
    Setgrid       setgridarea     Set grid cell area
    Setzaxis      setzaxis        Set z-axis
    Setzaxis      genlevelbounds  Generate level bounds
-   Setgatt       setgatt         Set global attribute
-   Setgatt       setgatts        Set global attributes
    Invert        invertlat       Invert latitudes
    Invertlev     invertlev       Invert levels
+   Shiftxy       shiftx          Shift x
+   Shiftxy       shifty          Shift y
    Maskregion    maskregion      Mask regions
    Maskbox       masklonlatbox   Mask a longitude/latitude box
    Maskbox       maskindexbox    Mask an index box
@@ -231,6 +232,7 @@ Operator catalog:
 -------------------------------------------------------------
    Statistical values
 -------------------------------------------------------------
+   Timcumsum     timcumsum       Cumulative sum over all timesteps
    Consecstat    consecsum       Consecutive Sum
    Consecstat    consects        Consecutive Timesteps
    Ensstat       ensmin          Ensemble minimum
@@ -547,6 +549,7 @@ Operator catalog:
    Strbre        strbre          Strong breeze days index per time period
    Strgal        strgal          Strong gale days index per time period
    Hurr          hurr            Hurricane days index per time period
+   CMORlite      cmorlite        CMOR lite
 -------------------------------------------------------------
    Magics
 -------------------------------------------------------------
diff --git a/cdo.spec b/cdo.spec
index ae1fd3d..2b81c8c 100644
--- a/cdo.spec
+++ b/cdo.spec
@@ -4,7 +4,7 @@
 
 Name:           cdo
 #BuildRequires:  
-Version:        1.7.2
+Version:        1.8.0
 Release:        1
 Summary:        Climate Data Operators
 License:        GNU GENERAL PUBLIC LICENSE Version 2, June 1991
diff --git a/config/default b/config/default
index 36a86a6..7d80d25 100755
--- a/config/default
+++ b/config/default
@@ -24,6 +24,8 @@ do
   shift
 done
 #
+if test -z "$COMP" ; then COMP=gcc ; fi
+#
 set -x
 #
 case "${HOSTNAME}" in
@@ -39,12 +41,12 @@ case "${HOSTNAME}" in
                  --with-libxml2=/usr \
                  --with-magics=$HOME/local/Magics-2.25.3 \
                  --with-proj=/opt/local \
-                 --with-szlib=$HOME/local"
+                 --with-szlib=$HOME/local/libaec-0.3.2"
 
         if  test "$COMP" = icpc ; then
 	  ${CONFPATH}configure --enable-cxx \
                     $CDOLIBS \
-	            CC=icc CXX=icpc CFLAGS="-g -Wall -O2 -qopt-report=5 -march=native"
+	            CC=icc CXX="icpc --std=c++11" CFLAGS="-g -Wall -O2 -qopt-report=5 -march=native"
         elif  test "$COMP" = icc ; then
 	  ${CONFPATH}configure  \
                     $CDOLIBS \
@@ -52,7 +54,7 @@ case "${HOSTNAME}" in
         elif  test "$COMP" = clang++ ; then
 	  ${CONFPATH}configure --enable-cxx \
                     $CDOLIBS \
-	            CC=clang CXX=clang++ CFLAGS="-g -Wall -O3"
+	            CC=clang CXX="clang++ --std=c++11" CFLAGS="-g -Wall -O3"
         elif  test "$COMP" = clang ; then
 	  ${CONFPATH}configure  \
                     $CDOLIBS \
@@ -60,14 +62,16 @@ case "${HOSTNAME}" in
         elif  test "$COMP" = g++ ; then
 	  ${CONFPATH}configure --enable-cxx \
                     $CDOLIBS \
-	            CC=gcc CXX=g++ CFLAGS="-g -Wall -W -Wfloat-equal -pedantic -O3 -march=native"
-        else
+	            CC=gcc CXX="g++ --std=c++11" CFLAGS="-g -Wall -W -Wfloat-equal -pedantic -O3 -march=native"
+        elif  test "$COMP" = gcc ; then
 	  ${CONFPATH}configure --prefix=$HOME/local \
                     --enable-maintainer-mode \
                     $CDOLIBS \
 	            CC=gcc CFLAGS="-g -pipe -Wall -W -Wfloat-equal -Wwrite-strings -pedantic -O3 -march=native -fstack-protector"
 #                    --with-libxml2=/usr 
 #                    --with-magics=/Users/m214003/local/magics-2.14.9
+        else
+	  ${CONFPATH}configure  $CDOLIBS  CC=$COMP
         fi
 	;;
     hama*)
@@ -91,7 +95,7 @@ case "${HOSTNAME}" in
 	  ${CONFPATH}configure --enable-cxx --prefix=$HOME/local \
                     $CDOLIBS \
 	            CC=icc CXX=icpc CFLAGS="-g -Wall -O2 -qopt-report=5 -march=native" CXX=icpc
-        elif  test "$COMP" = icpc ; then
+        elif  test "$COMP" = icc ; then
 	  ${CONFPATH}configure \
                     $CDOLIBS \
 	            CC=icc CFLAGS="-g -Wall -Wwrite-strings -O2 -qopt-report=5 -march=native"
@@ -103,6 +107,10 @@ case "${HOSTNAME}" in
 	  ${CONFPATH}configure  \
                     $CDOLIBS \
 	            CC=clang CFLAGS="-g -Wall -Wwrite-strings -Ofast -march=native"
+        elif  test "$COMP" = pgcc ; then
+	  ${CONFPATH}configure  \
+                    $CDOLIBS \
+	            CC=pgcc CFLAGS="-g -fast"
         elif  test "$COMP" = g++ ; then
 	  ${CONFPATH}configure --enable-cxx \
                     $CDOLIBS \
@@ -116,9 +124,11 @@ case "${HOSTNAME}" in
 #                    --with-magics=/Users/m214003/local/Magics-2.18.14nio \
         fi
 	;;
+# win7 based cygwin virtual machine
     cdo4windows-cyg)
         CDOLIBS="--with-netcdf=/usr/local \
                  --with-hdf5=/usr/local \
+                 --with-grib_api=/usr/local
                  --with-udunits2=/usr \
                  --with-proj=/usr"
 
@@ -128,12 +138,13 @@ case "${HOSTNAME}" in
                     --enable-cxx \
                     --enable-maintainer-mode \
                     $CDOLIBS \
-	            CC=g++ CFLAGS="-g -Wall -O2 -DPIC -pie -mwindows" \
+	            CC=gcc CXX=g++ CFLAGS="-g -Wall -O2 -DPIC -pie -mwindows" \
                     LDFLAGS='-L/usr/local/lib' \
                     LIBS='-lpthread -lm -lcurl -lhdf5_hl -lhdf5 -lz  -lsz -laec -ldl'
         else
 	  ${CONFPATH}configure --prefix=$HOME/local \
                     --enable-maintainer-mode \
+                    --enable-all-static \
                     $CDOLIBS \
 	            CC=gcc CFLAGS="-g -Wall -O2 -DPIC -pie -mwindows" \
                     LDFLAGS='-L/usr/local/lib' \
@@ -168,7 +179,7 @@ case "${HOSTNAME}" in
         CDOLIBS="--with-grib_api=/sw/squeeze-x64/grib_api-1.13.0-static-gccsys \
                  --with-netcdf=/sw/squeeze-x64/netcdf-4.2-static \
                  --with-hdf5=/sw/squeeze-x64/hdf5-1.8.8-static \
-                 --with-szlib=/sw/squeeze-x64/szip-2.1 \
+                 --with-szlib=/sw/squeeze-x64/libaec-0.3.2-gcc48 \
                  --with-udunits2=/sw/squeeze-x64/udunits-2.1.19 \
                  --with-proj=/sw/squeeze-x64/proj-4.7.0 LIBS=-lz"
 
@@ -207,12 +218,53 @@ case "${HOSTNAME}" in
                     CC=gcc CFLAGS='-g -Wall -O3'
 	fi
 	;;
+# jessie workstation x64
+    breeze*)
+        CDOLIBS="--with-grib_api=/sw/jessie-x64/grib_api-1.14.3-static-gccsys \
+                 --with-netcdf=/sw/jessie-x64/netcdf-4.3.3.1-gccsys \
+                 --with-udunits2=/sw/jessie-x64/udunits-2.2.20-gccsys \
+                 --with-proj=/sw/jessie-x64/proj4-4.9.3-gccsys LIBS=-lz"
+        if  test "$COMP" = icpc ; then
+          ${CONFPATH}configure --enable-cxx --prefix=$HOME/local --exec_prefix=$HOME/local/thunder \
+                    --with-fftw3 \
+                    $CDOLIBS \
+	            CC=icc CXX=icpc CFLAGS="-g -Wall -O2 -qopt-report=5 -march=native"
+        elif  test "$COMP" = icc ; then
+          ${CONFPATH}configure --prefix=$HOME/local --exec_prefix=$HOME/local/thunder \
+                    --with-fftw3 \
+                    $CDOLIBS \
+	            CC=icc CFLAGS="-g -Wall -O2 -qopt-report=5 -march=native"
+        elif  test "$COMP" = pgcc ; then
+          ${CONFPATH}configure --prefix=$HOME/local --exec_prefix=$HOME/local/thunder \
+                    $CDOLIBS \
+	            CC=pgcc CFLAGS="-g"
+        elif  test "$COMP" = clang ; then
+          ${CONFPATH}configure              --prefix=$HOME/local --exec_prefix=$HOME/local/thunder \
+                    --with-fftw3 \
+                    $CDOLIBS \
+	            CC=clang CXX=clang++ CFLAGS="-g -O2"
+        elif  test "$COMP" = clang++ ; then
+          ${CONFPATH}configure --enable-cxx --prefix=$HOME/local --exec_prefix=$HOME/local/thunder \
+                    --with-fftw3 \
+                    $CDOLIBS \
+	            CC=clang CXX=clang++ CFLAGS="-g -O2"
+        elif  test "$COMP" = g++ ; then
+	  ${CONFPATH}configure --enable-cxx \
+                    $CDOLIBS \
+	            CC=gcc CXX=g++ CFLAGS="-g -Wall -O3"
+	else
+          ${CONFPATH}configure --prefix=$HOME/local --exec_prefix=$HOME/local/thunder \
+                    --with-fftw3 \
+                    $CDOLIBS \
+                    CC=gcc CFLAGS='-g -Wall -O3'
+	fi
+	;;
 # mistral
     mlogin*)
         CDOLIBS="--with-grib_api=/sw/rhel6-x64/grib_api/grib_api-1.13.0-gcc48 \
                  --with-netcdf=/sw/rhel6-x64/netcdf/netcdf_c-4.3.2-gcc48 \
                  --with-hdf5=/sw/rhel6-x64/hdf5/hdf5-1.8.14-threadsafe-gcc48 \
-                 --with-szlib=/sw/rhel6-x64/sys/szip-2.1-gcc48 \
+                 --with-szlib=/sw/rhel6-x64/sys/libaec-0.3.2-gcc48 \
                  --with-udunits2=/sw/rhel6-x64/util/udunits-2.2.17-gcc48 \
                  --with-proj=/sw/rhel6-x64/graphics/proj4-4.9.1-gcc48"
 #                 --with-magics=/sw/rhel6-x64/graphics/magicsxx-2.18.15-gfxonly-gcc48 \
@@ -272,6 +324,7 @@ case "${HOSTNAME}" in
                     --program-suffix=-dev \
                     --enable-maintainer-mode \
                     --enable-data \
+	            --with-magics \
 	            --with-netcdf \
 	              --with-hdf5 \
                      --with-szlib \
@@ -281,9 +334,17 @@ case "${HOSTNAME}" in
                   --with-fftw3    \
                   --with-proj     \
                       --with-pic  \
-                      CC=$COMP CFLAGS="-g -Wall -O3" LIBS="-lopenjpeg" LDFLAGS='-lelf -v'
+                      CC=$COMP CPPFLAGS=-I/usr/include/magics CFLAGS="-g -Wall -O3" LIBS="-lopenjpeg" LDFLAGS='-lelf -v'
         ;;
       g++|clang++)
+        case "$COMP" in
+          g++)
+            CC=gcc
+            ;;
+          clang++)
+            CC=clang
+            ;;
+        esac
  	${CONFPATH}configure --prefix=$HOME/local \
                     --program-suffix=-dev \
                     --enable-maintainer-mode \
@@ -298,7 +359,7 @@ case "${HOSTNAME}" in
                   --with-fftw3    \
                   --with-proj     \
                       --with-pic  \
-                      CC=$COMP CFLAGS="-g -Wall -O2" LIBS=-lopenjpeg
+                      CC=$CC CXX=$COMP CFLAGS="-g -Wall -O2" CXXFLAGS="-g -Wall -O2" LIBS=-lopenjpeg
 	;;
       esac
     ;;
@@ -420,27 +481,6 @@ case "${HOSTNAME}" in
                     AR="ar -X 64"  LDFLAGS="-brtl" \
 	            CC=xlc_r CFLAGS="-g -O3 -q64 -qhot -qstrict -qarch=auto -qtune=auto -qsmp=omp -DHAVE_MMAP -qthreaded"
 	;;
-# win7 based cygwin virtual machine
-    cdo4windows-cyg)
-        if  test "$COMP" = gcc ; then
-          ${CONFPATH}configure \
-                      --with-netcdf \
-                      --with-hdf5 \
-                      --with-proj \
-                      --with-fftw3 \
-                      --with-udunits \
-                      CC=gcc CFLAGS='-g -Wall -O3'
-        elif  test "$COMP" = g++ ; then
-          ${CONFPATH}configure \
-                      --with-netcdf \
-                      --with-hdf5 \
-                      --with-proj \
-                      --with-fftw3 \
-                      --with-udunits \
-                      --enable-cxx \
-                      CC=gcc CXX=g++ CFLAGS='-g -Wall -O3' CXXFLAGS='-g -Wall -O3'
-        fi
-        ;;
     *)
 	echo "configuration for hostname $HOSTNAME not found!"
 	;;
diff --git a/configure b/configure
index ca8b3d0..9423cfa 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.68 for cdo 1.7.2.
+# Generated by GNU Autoconf 2.68 for cdo 1.8.0.
 #
 # Report bugs to <http://mpimet.mpg.de/cdo>.
 #
@@ -570,8 +570,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='cdo'
 PACKAGE_TARNAME='cdo'
-PACKAGE_VERSION='1.7.2'
-PACKAGE_STRING='cdo 1.7.2'
+PACKAGE_VERSION='1.8.0'
+PACKAGE_STRING='cdo 1.8.0'
 PACKAGE_BUGREPORT='http://mpimet.mpg.de/cdo'
 PACKAGE_URL=''
 
@@ -1395,7 +1395,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.7.2 to adapt to many kinds of systems.
+\`configure' configures cdo 1.8.0 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1465,7 +1465,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of cdo 1.7.2:";;
+     short | recursive ) echo "Configuration of cdo 1.8.0:";;
    esac
   cat <<\_ACEOF
 
@@ -1613,7 +1613,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-cdo configure 1.7.2
+cdo configure 1.8.0
 generated by GNU Autoconf 2.68
 
 Copyright (C) 2010 Free Software Foundation, Inc.
@@ -2206,7 +2206,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by cdo $as_me 1.7.2, which was
+It was created by cdo $as_me 1.8.0, which was
 generated by GNU Autoconf 2.68.  Invocation command line was
 
   $ $0 $@
@@ -3155,7 +3155,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='cdo'
- VERSION='1.7.2'
+ VERSION='1.8.0'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -18942,7 +18942,19 @@ fi
 
 
                             if test "x$NC_CONFIG" != "x"; then :
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking netcdf's nc2 support" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking netcdf's OpenDAP support" >&5
+$as_echo_n "checking netcdf's OpenDAP support... " >&6; }
+                                   if test "x$($NC_CONFIG --has-dap)" = "xyes"; then :
+
+$as_echo "#define HAVE_LIBNC_DAP 1" >>confdefs.h
+
+                                          { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+                                  { $as_echo "$as_me:${as_lineno-$LINENO}: checking netcdf's nc2 support" >&5
 $as_echo_n "checking netcdf's nc2 support... " >&6; }
                                    if test "x$($NC_CONFIG --has-nc2)" = "xyes"; then :
 
@@ -19204,7 +19216,7 @@ for ac_lib in '' netcdf; do
     ac_res="none required"
   else
     ac_res=-l$ac_lib
-    LIBS="-l$ac_lib -lhdf5_hl -lhdf5 $ac_func_search_save_LIBS"
+    LIBS="-l$ac_lib -lhdf5 $ac_func_search_save_LIBS"
   fi
   if ac_fn_c_try_link "$LINENO"; then :
   ac_cv_search_H5TS_mutex_lock=$ac_res
@@ -21056,11 +21068,17 @@ done
 
 ac_config_files="$ac_config_files test/File.test test/Read_grib.test test/Read_netcdf.test test/Copy_netcdf.test"
 
+ac_config_files="$ac_config_files test/Comp.test test/Compc.test"
+
 ac_config_files="$ac_config_files test/Cat.test test/Gridarea.test test/Genweights.test test/Remap.test"
 
-ac_config_files="$ac_config_files test/Select.test test/Spectral.test test/Timstat.test test/Vertint.test"
+ac_config_files="$ac_config_files test/EOF.test test/Select.test test/Spectral.test test/Vertint.test"
+
+ac_config_files="$ac_config_files test/Timstat.test test/Timselstat.test test/Seasstat.test test/Runstat.test test/Multiyearstat.test"
+
+ac_config_files="$ac_config_files test/Gridboxstat.test test/Vertstat.test test/Fldstat.test test/Fldpctl.test test/Ensstat.test test/Enspctl.test"
 
-ac_config_files="$ac_config_files test/Ymonstat.test test/Fldstat.test test/Fldpctl.test test/Ensstat.test test/Enspctl.test"
+ac_config_files="$ac_config_files test/Merstat.test test/Zonstat.test"
 
 ac_config_files="$ac_config_files test/Afterburner.test test/Detrend.test test/Arithc.test test/Arith.test test/Expr.test"
 
@@ -21644,7 +21662,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by cdo $as_me 1.7.2, which was
+This file was extended by cdo $as_me 1.8.0, which was
 generated by GNU Autoconf 2.68.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -21710,7 +21728,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-cdo config.status 1.7.2
+cdo config.status 1.8.0
 configured by $0, generated by GNU Autoconf 2.68,
   with options \\"\$ac_cs_config\\"
 
@@ -22221,19 +22239,29 @@ do
     "test/Read_grib.test") CONFIG_FILES="$CONFIG_FILES test/Read_grib.test" ;;
     "test/Read_netcdf.test") CONFIG_FILES="$CONFIG_FILES test/Read_netcdf.test" ;;
     "test/Copy_netcdf.test") CONFIG_FILES="$CONFIG_FILES test/Copy_netcdf.test" ;;
+    "test/Comp.test") CONFIG_FILES="$CONFIG_FILES test/Comp.test" ;;
+    "test/Compc.test") CONFIG_FILES="$CONFIG_FILES test/Compc.test" ;;
     "test/Cat.test") CONFIG_FILES="$CONFIG_FILES test/Cat.test" ;;
     "test/Gridarea.test") CONFIG_FILES="$CONFIG_FILES test/Gridarea.test" ;;
     "test/Genweights.test") CONFIG_FILES="$CONFIG_FILES test/Genweights.test" ;;
     "test/Remap.test") CONFIG_FILES="$CONFIG_FILES test/Remap.test" ;;
+    "test/EOF.test") CONFIG_FILES="$CONFIG_FILES test/EOF.test" ;;
     "test/Select.test") CONFIG_FILES="$CONFIG_FILES test/Select.test" ;;
     "test/Spectral.test") CONFIG_FILES="$CONFIG_FILES test/Spectral.test" ;;
-    "test/Timstat.test") CONFIG_FILES="$CONFIG_FILES test/Timstat.test" ;;
     "test/Vertint.test") CONFIG_FILES="$CONFIG_FILES test/Vertint.test" ;;
-    "test/Ymonstat.test") CONFIG_FILES="$CONFIG_FILES test/Ymonstat.test" ;;
+    "test/Timstat.test") CONFIG_FILES="$CONFIG_FILES test/Timstat.test" ;;
+    "test/Timselstat.test") CONFIG_FILES="$CONFIG_FILES test/Timselstat.test" ;;
+    "test/Seasstat.test") CONFIG_FILES="$CONFIG_FILES test/Seasstat.test" ;;
+    "test/Runstat.test") CONFIG_FILES="$CONFIG_FILES test/Runstat.test" ;;
+    "test/Multiyearstat.test") CONFIG_FILES="$CONFIG_FILES test/Multiyearstat.test" ;;
+    "test/Gridboxstat.test") CONFIG_FILES="$CONFIG_FILES test/Gridboxstat.test" ;;
+    "test/Vertstat.test") CONFIG_FILES="$CONFIG_FILES test/Vertstat.test" ;;
     "test/Fldstat.test") CONFIG_FILES="$CONFIG_FILES test/Fldstat.test" ;;
     "test/Fldpctl.test") CONFIG_FILES="$CONFIG_FILES test/Fldpctl.test" ;;
     "test/Ensstat.test") CONFIG_FILES="$CONFIG_FILES test/Ensstat.test" ;;
     "test/Enspctl.test") CONFIG_FILES="$CONFIG_FILES test/Enspctl.test" ;;
+    "test/Merstat.test") CONFIG_FILES="$CONFIG_FILES test/Merstat.test" ;;
+    "test/Zonstat.test") CONFIG_FILES="$CONFIG_FILES test/Zonstat.test" ;;
     "test/Afterburner.test") CONFIG_FILES="$CONFIG_FILES test/Afterburner.test" ;;
     "test/Detrend.test") CONFIG_FILES="$CONFIG_FILES test/Detrend.test" ;;
     "test/Arithc.test") CONFIG_FILES="$CONFIG_FILES test/Arithc.test" ;;
@@ -23742,19 +23770,29 @@ _LT_EOF
     "test/Read_grib.test":F) chmod a+x "$ac_file" ;;
     "test/Read_netcdf.test":F) chmod a+x "$ac_file" ;;
     "test/Copy_netcdf.test":F) chmod a+x "$ac_file" ;;
+    "test/Comp.test":F) chmod a+x "$ac_file" ;;
+    "test/Compc.test":F) chmod a+x "$ac_file" ;;
     "test/Cat.test":F) chmod a+x "$ac_file" ;;
     "test/Gridarea.test":F) chmod a+x "$ac_file" ;;
     "test/Genweights.test":F) chmod a+x "$ac_file" ;;
     "test/Remap.test":F) chmod a+x "$ac_file" ;;
+    "test/EOF.test":F) chmod a+x "$ac_file" ;;
     "test/Select.test":F) chmod a+x "$ac_file" ;;
     "test/Spectral.test":F) chmod a+x "$ac_file" ;;
-    "test/Timstat.test":F) chmod a+x "$ac_file" ;;
     "test/Vertint.test":F) chmod a+x "$ac_file" ;;
-    "test/Ymonstat.test":F) chmod a+x "$ac_file" ;;
+    "test/Timstat.test":F) chmod a+x "$ac_file" ;;
+    "test/Timselstat.test":F) chmod a+x "$ac_file" ;;
+    "test/Seasstat.test":F) chmod a+x "$ac_file" ;;
+    "test/Runstat.test":F) chmod a+x "$ac_file" ;;
+    "test/Multiyearstat.test":F) chmod a+x "$ac_file" ;;
+    "test/Gridboxstat.test":F) chmod a+x "$ac_file" ;;
+    "test/Vertstat.test":F) chmod a+x "$ac_file" ;;
     "test/Fldstat.test":F) chmod a+x "$ac_file" ;;
     "test/Fldpctl.test":F) chmod a+x "$ac_file" ;;
     "test/Ensstat.test":F) chmod a+x "$ac_file" ;;
     "test/Enspctl.test":F) chmod a+x "$ac_file" ;;
+    "test/Merstat.test":F) chmod a+x "$ac_file" ;;
+    "test/Zonstat.test":F) chmod a+x "$ac_file" ;;
     "test/Afterburner.test":F) chmod a+x "$ac_file" ;;
     "test/Detrend.test":F) chmod a+x "$ac_file" ;;
     "test/Arithc.test":F) chmod a+x "$ac_file" ;;
diff --git a/configure.ac b/configure.ac
index 0c0ff2c..6f50636 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,7 +4,7 @@
 #  autoconf 2.68
 #  libtool  2.4.2
 
-AC_INIT([cdo], [1.7.2], [http://mpimet.mpg.de/cdo])
+AC_INIT([cdo], [1.8.0], [http://mpimet.mpg.de/cdo])
 
 AC_DEFINE_UNQUOTED(CDO, ["$PACKAGE_VERSION"], [CDO version])
 
@@ -248,9 +248,12 @@ AC_REQUIRE_AUX_FILE([tap-driver.sh])
 AC_PROG_AWK
 
 AC_CONFIG_FILES([test/File.test test/Read_grib.test test/Read_netcdf.test test/Copy_netcdf.test],[chmod a+x "$ac_file"])
+AC_CONFIG_FILES([test/Comp.test test/Compc.test],[chmod a+x "$ac_file"])
 AC_CONFIG_FILES([test/Cat.test test/Gridarea.test test/Genweights.test test/Remap.test],[chmod a+x "$ac_file"])
-AC_CONFIG_FILES([test/Select.test test/Spectral.test test/Timstat.test test/Vertint.test],[chmod a+x "$ac_file"])
-AC_CONFIG_FILES([test/Ymonstat.test test/Fldstat.test test/Fldpctl.test test/Ensstat.test test/Enspctl.test],[chmod a+x "$ac_file"])
+AC_CONFIG_FILES([test/EOF.test test/Select.test test/Spectral.test test/Vertint.test],[chmod a+x "$ac_file"])
+AC_CONFIG_FILES([test/Timstat.test test/Timselstat.test test/Seasstat.test test/Runstat.test test/Multiyearstat.test],[chmod a+x "$ac_file"])
+AC_CONFIG_FILES([test/Gridboxstat.test test/Vertstat.test test/Fldstat.test test/Fldpctl.test test/Ensstat.test test/Enspctl.test],[chmod a+x "$ac_file"])
+AC_CONFIG_FILES([test/Merstat.test test/Zonstat.test],[chmod a+x "$ac_file"])
 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"])
diff --git a/contrib/cdoCompletion.bash b/contrib/cdoCompletion.bash
index b6b8203..f3e9c41 100644
--- a/contrib/cdoCompletion.bash
+++ b/contrib/cdoCompletion.bash
@@ -6,6 +6,7 @@ complete -W "
 --no_warnings \
 --operators \
 --percentile \
+--precision \
 --reduce_dim \
 --sort \
 --timestat_date \
@@ -67,6 +68,7 @@ chunit -chunit \
 chvar -chvar \
 cloudlayer -cloudlayer \
 cmor -cmor \
+cmorlite -cmorlite \
 codetab -codetab \
 collgrid -collgrid \
 complextorect -complextorect \
@@ -86,6 +88,7 @@ daymax -daymax \
 daymean -daymean \
 daymin -daymin \
 daypctl -daypctl \
+dayrange -dayrange \
 daystd -daystd \
 daystd1 -daystd1 \
 daysum -daysum \
@@ -99,6 +102,7 @@ delname -delname \
 delparam -delparam \
 deltap -deltap \
 deltap_fl -deltap_fl \
+deltat -deltat \
 delvar -delvar \
 detrend -detrend \
 diff -diff \
@@ -112,6 +116,7 @@ divc -divc \
 divcoslat -divcoslat \
 divdpm -divdpm \
 divdpy -divdpy \
+dump_cmor_table -dump_cmor_table \
 dumpmap -dumpmap \
 duplicate -duplicate \
 dv2ps -dv2ps \
@@ -200,6 +205,7 @@ fldmax -fldmax \
 fldmean -fldmean \
 fldmin -fldmin \
 fldpctl -fldpctl \
+fldrange -fldrange \
 fldrms -fldrms \
 fldstd -fldstd \
 fldstd1 -fldstd1 \
@@ -266,6 +272,7 @@ hourmax -hourmax \
 hourmean -hourmean \
 hourmin -hourmin \
 hourpctl -hourpctl \
+hourrange -hourrange \
 hourstd -hourstd \
 hourstd1 -hourstd1 \
 hoursum -hoursum \
@@ -299,7 +306,6 @@ int -int \
 interpolate -interpolate \
 intgrid -intgrid \
 intgridbil -intgridbil \
-intgridcon -intgridcon \
 intgridtraj -intgridtraj \
 intlevel -intlevel \
 intlevel3d -intlevel3d \
@@ -370,6 +376,7 @@ monmean -monmean \
 monmin -monmin \
 monmul -monmul \
 monpctl -monpctl \
+monrange -monrange \
 monstd -monstd \
 monstd1 -monstd1 \
 monsub -monsub \
@@ -430,7 +437,6 @@ pow -pow \
 pressure_fl -pressure_fl \
 pressure_hl -pressure_hl \
 random -random \
-read_cmor_table -read_cmor_table \
 reci -reci \
 reducegrid -reducegrid \
 regres -regres \
@@ -488,6 +494,7 @@ select -select \
 selgrid -selgrid \
 selgridname -selgridname \
 selhour -selhour \
+selindex -selindex \
 selindexbox -selindexbox \
 sellevel -sellevel \
 sellevidx -sellevidx \
@@ -510,6 +517,7 @@ selvar -selvar \
 selyear -selyear \
 selzaxis -selzaxis \
 selzaxisname -selzaxisname \
+setattribute -setattribute \
 setcalendar -setcalendar \
 setcindexbox -setcindexbox \
 setclonlatbox -setclonlatbox \
@@ -559,6 +567,8 @@ setyear -setyear \
 setzaxis -setzaxis \
 shaded -shaded \
 shifttime -shifttime \
+shiftx -shiftx \
+shifty -shifty \
 showcode -showcode \
 showdate -showdate \
 showformat -showformat \
@@ -632,11 +642,12 @@ timavg -timavg \
 timcor -timcor \
 timcount -timcount \
 timcovar -timcovar \
-timedt -timedt \
+timcumsum -timcumsum \
 timmax -timmax \
 timmean -timmean \
 timmin -timmin \
 timpctl -timpctl \
+timrange -timrange \
 timselavg -timselavg \
 timselmax -timselmax \
 timselmean -timselmean \
@@ -717,6 +728,7 @@ yearmin -yearmin \
 yearmonavg -yearmonavg \
 yearmonmean -yearmonmean \
 yearpctl -yearpctl \
+yearrange -yearrange \
 yearstd -yearstd \
 yearstd1 -yearstd1 \
 yearsum -yearsum \
diff --git a/contrib/cdoCompletion.tcsh b/contrib/cdoCompletion.tcsh
index abfbcef..ce59c15 100644
--- a/contrib/cdoCompletion.tcsh
+++ b/contrib/cdoCompletion.tcsh
@@ -6,6 +6,7 @@ set cdoCmpl = (\
 -no_warnings \
 -operators \
 -percentile \
+-precision \
 -reduce_dim \
 -sort \
 -timestat_date \
@@ -67,6 +68,7 @@ chunit \
 chvar \
 cloudlayer \
 cmor \
+cmorlite \
 codetab \
 collgrid \
 complextorect \
@@ -86,6 +88,7 @@ daymax \
 daymean \
 daymin \
 daypctl \
+dayrange \
 daystd \
 daystd1 \
 daysum \
@@ -99,6 +102,7 @@ delname \
 delparam \
 deltap \
 deltap_fl \
+deltat \
 delvar \
 detrend \
 diff \
@@ -112,6 +116,7 @@ divc \
 divcoslat \
 divdpm \
 divdpy \
+dump_cmor_table \
 dumpmap \
 duplicate \
 dv2ps \
@@ -200,6 +205,7 @@ fldmax \
 fldmean \
 fldmin \
 fldpctl \
+fldrange \
 fldrms \
 fldstd \
 fldstd1 \
@@ -266,6 +272,7 @@ hourmax \
 hourmean \
 hourmin \
 hourpctl \
+hourrange \
 hourstd \
 hourstd1 \
 hoursum \
@@ -299,7 +306,6 @@ int \
 interpolate \
 intgrid \
 intgridbil \
-intgridcon \
 intgridtraj \
 intlevel \
 intlevel3d \
@@ -370,6 +376,7 @@ monmean \
 monmin \
 monmul \
 monpctl \
+monrange \
 monstd \
 monstd1 \
 monsub \
@@ -430,7 +437,6 @@ pow \
 pressure_fl \
 pressure_hl \
 random \
-read_cmor_table \
 reci \
 reducegrid \
 regres \
@@ -488,6 +494,7 @@ select \
 selgrid \
 selgridname \
 selhour \
+selindex \
 selindexbox \
 sellevel \
 sellevidx \
@@ -510,6 +517,7 @@ selvar \
 selyear \
 selzaxis \
 selzaxisname \
+setattribute \
 setcalendar \
 setcindexbox \
 setclonlatbox \
@@ -559,6 +567,8 @@ setyear \
 setzaxis \
 shaded \
 shifttime \
+shiftx \
+shifty \
 showcode \
 showdate \
 showformat \
@@ -632,11 +642,12 @@ timavg \
 timcor \
 timcount \
 timcovar \
-timedt \
+timcumsum \
 timmax \
 timmean \
 timmin \
 timpctl \
+timrange \
 timselavg \
 timselmax \
 timselmean \
@@ -717,6 +728,7 @@ yearmin \
 yearmonavg \
 yearmonmean \
 yearpctl \
+yearrange \
 yearstd \
 yearstd1 \
 yearsum \
diff --git a/contrib/cdoCompletion.zsh b/contrib/cdoCompletion.zsh
index 19a7d08..4698ad5 100644
--- a/contrib/cdoCompletion.zsh
+++ b/contrib/cdoCompletion.zsh
@@ -6,6 +6,7 @@ compctl -k "(
 --no_warnings \
 --operators \
 --percentile \
+--precision \
 --reduce_dim \
 --sort \
 --timestat_date \
@@ -67,6 +68,7 @@ chunit -chunit \
 chvar -chvar \
 cloudlayer -cloudlayer \
 cmor -cmor \
+cmorlite -cmorlite \
 codetab -codetab \
 collgrid -collgrid \
 complextorect -complextorect \
@@ -86,6 +88,7 @@ daymax -daymax \
 daymean -daymean \
 daymin -daymin \
 daypctl -daypctl \
+dayrange -dayrange \
 daystd -daystd \
 daystd1 -daystd1 \
 daysum -daysum \
@@ -99,6 +102,7 @@ delname -delname \
 delparam -delparam \
 deltap -deltap \
 deltap_fl -deltap_fl \
+deltat -deltat \
 delvar -delvar \
 detrend -detrend \
 diff -diff \
@@ -112,6 +116,7 @@ divc -divc \
 divcoslat -divcoslat \
 divdpm -divdpm \
 divdpy -divdpy \
+dump_cmor_table -dump_cmor_table \
 dumpmap -dumpmap \
 duplicate -duplicate \
 dv2ps -dv2ps \
@@ -200,6 +205,7 @@ fldmax -fldmax \
 fldmean -fldmean \
 fldmin -fldmin \
 fldpctl -fldpctl \
+fldrange -fldrange \
 fldrms -fldrms \
 fldstd -fldstd \
 fldstd1 -fldstd1 \
@@ -266,6 +272,7 @@ hourmax -hourmax \
 hourmean -hourmean \
 hourmin -hourmin \
 hourpctl -hourpctl \
+hourrange -hourrange \
 hourstd -hourstd \
 hourstd1 -hourstd1 \
 hoursum -hoursum \
@@ -299,7 +306,6 @@ int -int \
 interpolate -interpolate \
 intgrid -intgrid \
 intgridbil -intgridbil \
-intgridcon -intgridcon \
 intgridtraj -intgridtraj \
 intlevel -intlevel \
 intlevel3d -intlevel3d \
@@ -370,6 +376,7 @@ monmean -monmean \
 monmin -monmin \
 monmul -monmul \
 monpctl -monpctl \
+monrange -monrange \
 monstd -monstd \
 monstd1 -monstd1 \
 monsub -monsub \
@@ -430,7 +437,6 @@ pow -pow \
 pressure_fl -pressure_fl \
 pressure_hl -pressure_hl \
 random -random \
-read_cmor_table -read_cmor_table \
 reci -reci \
 reducegrid -reducegrid \
 regres -regres \
@@ -488,6 +494,7 @@ select -select \
 selgrid -selgrid \
 selgridname -selgridname \
 selhour -selhour \
+selindex -selindex \
 selindexbox -selindexbox \
 sellevel -sellevel \
 sellevidx -sellevidx \
@@ -510,6 +517,7 @@ selvar -selvar \
 selyear -selyear \
 selzaxis -selzaxis \
 selzaxisname -selzaxisname \
+setattribute -setattribute \
 setcalendar -setcalendar \
 setcindexbox -setcindexbox \
 setclonlatbox -setclonlatbox \
@@ -559,6 +567,8 @@ setyear -setyear \
 setzaxis -setzaxis \
 shaded -shaded \
 shifttime -shifttime \
+shiftx -shiftx \
+shifty -shifty \
 showcode -showcode \
 showdate -showdate \
 showformat -showformat \
@@ -632,11 +642,12 @@ timavg -timavg \
 timcor -timcor \
 timcount -timcount \
 timcovar -timcovar \
-timedt -timedt \
+timcumsum -timcumsum \
 timmax -timmax \
 timmean -timmean \
 timmin -timmin \
 timpctl -timpctl \
+timrange -timrange \
 timselavg -timselavg \
 timselmax -timselmax \
 timselmean -timselmean \
@@ -717,6 +728,7 @@ yearmin -yearmin \
 yearmonavg -yearmonavg \
 yearmonmean -yearmonmean \
 yearpctl -yearpctl \
+yearrange -yearrange \
 yearstd -yearstd \
 yearstd1 -yearstd1 \
 yearsum -yearsum \
diff --git a/doc/cdo.pdf b/doc/cdo.pdf
index f90f8bc..62e5998 100644
Binary files a/doc/cdo.pdf and b/doc/cdo.pdf differ
diff --git a/doc/cdo_eca.pdf b/doc/cdo_eca.pdf
index bbf744a..1457d38 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 7c43b62..e2a0b66 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 1f8d601..6c0a1dd 100644
Binary files a/doc/cdo_refcard.pdf and b/doc/cdo_refcard.pdf differ
diff --git a/libcdi/ChangeLog b/libcdi/ChangeLog
index e9c44ad..94862ae 100644
--- a/libcdi/ChangeLog
+++ b/libcdi/ChangeLog
@@ -1,4 +1,107 @@
-2016-06-??  Uwe Schulzweida
+2017-02-14  Uwe Schulzweida
+
+        * using CGRIBEX library version 1.7.6
+	* Version 1.8.0 released
+
+2017-01-19  Uwe Schulzweida
+
+	* Version 1.8.0rc6 released
+
+2016-12-20  Uwe Schulzweida
+
+	* Added support for GRIB level type 210
+
+2016-11-24  Uwe Schulzweida
+
+	* Version 1.8.0rc5 released
+
+2016-11-04  Uwe Schulzweida
+
+	* Version 1.8.0rc4 released
+
+2016-11-04  Uwe Schulzweida
+
+	* cgribexVarCompare: bug fix for different kind of instant step types
+
+2016-10-10  Uwe Schulzweida
+
+	* NetCDF: added support for grid datatype integer
+	* NetCDF: added support for proj coordinate without mapping attribute
+
+2016-10-04  Uwe Schulzweida
+
+	* Version 1.8.0rc3 released
+
+2016-10-04  Uwe Schulzweida
+
+	* Changed default name of pressure levels to plev
+
+2016-09-26  Uwe Schulzweida
+
+	* Added read support for hybrid sigma pressure coordinate with formula term P0
+
+2016-09-22  Uwe Schulzweida
+
+	* GRIB: sort only unsorted pressure levels
+
+2016-09-19  Uwe Schulzweida
+
+	* time axis: added support for NC_FLOAT
+
+2016-09-15  Uwe Schulzweida
+
+	* zaxis: added support for user defined attributes
+
+2016-08-29  Uwe Schulzweida
+
+	* CDI_cmor_mode: Convert Zaxis with one level to Scalar Z-Coordinate on all input streams
+
+2016-08-18  Uwe Schulzweida
+
+	* Version 1.8.0rc2 released
+
+2016-08-15  Uwe Schulzweida
+
+	* zaxisDefPositive: bug fix
+	* Skip netCDF attribute cell_measures if grid area variable not found
+	* Changed interface for GME grid parameter
+
+2016-08-12  Uwe Schulzweida
+
+	* Removed obsolete grid type GRID_LCC2
+
+2016-08-11  Uwe Schulzweida
+
+	* Removed obsolete grid type GRID_LAEA
+	* Removed obsolete grid type GRID_SINUSOIDAL
+	* Removed obsolete CDI grid functions gridXXXXpole(), gridXXXYpole(), gridXXXAngle() and gridIsRotated()
+
+2016-08-11  Uwe Schulzweida
+
+	* Version 1.8.0rc1 released
+
+2016-08-01  Uwe Schulzweida
+
+	* grb, grb2 write: added support for projection CDI_PROJ_RLL
+	* grb, grb2, ieg read: added support for projection CDI_PROJ_RLL
+
+2016-07-30  Uwe Schulzweida
+
+	* ieg write: added support for projection CDI_PROJ_RLL
+
+2016-07-28  Uwe Schulzweida
+
+	* iegWriteVarSliceDP: does not work (bug fix)
+
+2016-07-02  Uwe Schulzweida
+
+	* streamOpenAppend: call to gribContainersNew() missing (bug fix) [Bug #6944]
+
+2016-06-17  Uwe Schulzweida
+
+	* netCDF4: added support for attribute type NC_BYTE, NC_UBYTE, NC_USHORT and NC_UINT
+
+2016-06-10  Uwe Schulzweida
 
 	* Version 1.7.2 released
 
diff --git a/libcdi/Makefile.in b/libcdi/Makefile.in
index 2639d34..d48da22 100644
--- a/libcdi/Makefile.in
+++ b/libcdi/Makefile.in
@@ -293,11 +293,9 @@ INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
 INSTALL_SCRIPT = @INSTALL_SCRIPT@
 INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-JASPER_LIBS = @JASPER_LIBS@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
 LIBOBJS = @LIBOBJS@
-LIBPNG_LIBS = @LIBPNG_LIBS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
@@ -321,7 +319,6 @@ NM = @NM@
 NMEDIT = @NMEDIT@
 OBJDUMP = @OBJDUMP@
 OBJEXT = @OBJEXT@
-OPENJPEG_LIBS = @OPENJPEG_LIBS@
 OTOOL = @OTOOL@
 OTOOL64 = @OTOOL64@
 PACKAGE = @PACKAGE@
@@ -403,7 +400,6 @@ localstatedir = @localstatedir@
 mandir = @mandir@
 mkdir_p = @mkdir_p@
 oldincludedir = @oldincludedir@
-openjpeg_LIBS = @openjpeg_LIBS@
 pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
diff --git a/libcdi/NEWS b/libcdi/NEWS
index 148b2e3..487f972 100644
--- a/libcdi/NEWS
+++ b/libcdi/NEWS
@@ -1,7 +1,15 @@
 CDI NEWS
 --------
 
+Version 1.8.0 (26 October 2016):
 
+   New features:
+     * Refactor horizontal and vertical grid module
+     * netCDF4: added support for attribute type NC_BYTE, NC_UBYTE, NC_USHORT and NC_UINT
+   Fixed bugs:
+     * iegWriteVarSliceDP: does not work (bug fix)
+     * streamOpenAppend: call to gribContainersNew() missing (bug fix) [Bug #6944]
+        
 Version 1.7.0 (27 October 2015):
 
    New features:
diff --git a/libcdi/app/Makefile.in b/libcdi/app/Makefile.in
index 1c1baf6..bcaa36a 100644
--- a/libcdi/app/Makefile.in
+++ b/libcdi/app/Makefile.in
@@ -266,11 +266,9 @@ INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
 INSTALL_SCRIPT = @INSTALL_SCRIPT@
 INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-JASPER_LIBS = @JASPER_LIBS@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
 LIBOBJS = @LIBOBJS@
-LIBPNG_LIBS = @LIBPNG_LIBS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
@@ -294,7 +292,6 @@ NM = @NM@
 NMEDIT = @NMEDIT@
 OBJDUMP = @OBJDUMP@
 OBJEXT = @OBJEXT@
-OPENJPEG_LIBS = @OPENJPEG_LIBS@
 OTOOL = @OTOOL@
 OTOOL64 = @OTOOL64@
 PACKAGE = @PACKAGE@
@@ -376,7 +373,6 @@ localstatedir = @localstatedir@
 mandir = @mandir@
 mkdir_p = @mkdir_p@
 oldincludedir = @oldincludedir@
-openjpeg_LIBS = @openjpeg_LIBS@
 pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
diff --git a/libcdi/app/cdi.c b/libcdi/app/cdi.c
index 399b9b0..b392bb6 100644
--- a/libcdi/app/cdi.c
+++ b/libcdi/app/cdi.c
@@ -66,7 +66,7 @@ static int DefaultFileType  = CDI_UNDEFID;
 static int DefaultDataType  = CDI_UNDEFID;
 static int DefaultByteorder = CDI_UNDEFID;
 
-static int comptype  = COMPRESS_NONE;  // Compression type
+static int comptype  = CDI_COMPRESS_NONE;  // Compression type
 static int complevel = 0;              // Compression level
 
 enum datamode {SP_MODE, DP_MODE};
@@ -75,7 +75,7 @@ static int datamode = DP_MODE;
 static
 void version(void)
 {
-  int   filetypes[] = {FILETYPE_SRV, FILETYPE_EXT, FILETYPE_IEG, FILETYPE_GRB, FILETYPE_GRB2, FILETYPE_NC, FILETYPE_NC2, FILETYPE_NC4, FILETYPE_NC4C};
+  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};
    const char *typenames[] = {        "srv",        "ext",        "ieg",        "grb",        "grb2",        "nc",        "nc2",        "nc4",        "nc4c"};
 
   fprintf(stderr, "CDI version 1.8\n");
@@ -252,9 +252,7 @@ void printInfo(int vdate, int vtime, char *varname, double level,
   else
     {
       int nvals_r = 0, nvals_i = 0;
-      double arrsum_r, arrsum_i, arrmean_r = 0, arrmean_i = 0;
-      arrsum_r = 0;
-      arrsum_i = 0;
+      double arrsum_r = 0, arrsum_i = 0, arrmean_r = 0, arrmean_i = 0;
 
       for ( i = 0; i < datasize; i++ )
 	{
@@ -277,7 +275,7 @@ void printInfo(int vdate, int vtime, char *varname, double level,
       fprintf(stdout, "  -  (%#12.5g,%#12.5g)  -", arrmean_r, arrmean_i);
     }
 
-  fprintf(stdout, " : %-11s\n", varname);
+  fprintf(stdout, " : %-14s\n", varname);
 
   if ( imiss != nmiss && nmiss > 0 )
     fprintf(stdout, "Found %d of %d missing values!\n", imiss, nmiss);
@@ -331,16 +329,8 @@ static
 void printShortinfo(int streamID, int vlistID, int vardis)
 {
   int varID;
-  int gridsize = 0;
-  int gridID, zaxisID, param;
-  int vdate, vtime;
-  int ntsteps;
-  int levelsize;
-  int tsteptype, taxisID;
   char tmpname[CDI_MAX_NAME];
   char varname[CDI_MAX_NAME];
-  const char *modelptr, *instptr;
-  int datatype;
   int year, month, day, hour, minute, second;
   char pstr[4];
   char paramstr[32];
@@ -365,28 +355,28 @@ void printShortinfo(int streamID, int vlistID, int vardis)
 
       for ( varID = 0; varID < nvars; varID++ )
 	{
-	  param   = vlistInqVarParam(vlistID, varID);
-	  gridID  = vlistInqVarGrid(vlistID, varID);
-	  zaxisID = vlistInqVarZaxis(vlistID, varID);
+	  int param   = vlistInqVarParam(vlistID, varID);
+	  int gridID  = vlistInqVarGrid(vlistID, varID);
+	  int zaxisID = vlistInqVarZaxis(vlistID, varID);
 
 	  fprintf(stdout, "%6d : ", varID + 1);
 
 	  /* institute info */
-	  instptr = institutInqNamePtr(vlistInqVarInstitut(vlistID, varID));
+	  const char *instptr = institutInqNamePtr(vlistInqVarInstitut(vlistID, varID));
 	  strcpy(tmpname, "unknown");
 	  if ( instptr ) strncpy(tmpname, instptr, CDI_MAX_NAME);
 	  limit_string_length(tmpname, CDI_MAX_NAME);
 	  fprintf(stdout, "%-8s ", tmpname);
 
 	  /* source info */
-	  modelptr = modelInqNamePtr(vlistInqVarModel(vlistID, varID));
+	  const char *modelptr = modelInqNamePtr(vlistInqVarModel(vlistID, varID));
 	  strcpy(tmpname, "unknown");
 	  if ( modelptr ) strncpy(tmpname, modelptr, CDI_MAX_NAME);
 	  limit_string_length(tmpname, CDI_MAX_NAME);
 	  fprintf(stdout, "%-8s ", tmpname);
 
 	  /* tsteptype */
-	  tsteptype = vlistInqVarTsteptype(vlistID, varID);
+	  int tsteptype = vlistInqVarTsteptype(vlistID, varID);
 	  if      ( tsteptype == TSTEP_CONSTANT ) fprintf(stdout, "%-8s ", "constant");
 	  else if ( tsteptype == TSTEP_INSTANT  ) fprintf(stdout, "%-8s ", "instant");
 	  else if ( tsteptype == TSTEP_INSTANT2 ) fprintf(stdout, "%-8s ", "instant");
@@ -408,34 +398,34 @@ void printShortinfo(int streamID, int vlistID, int vardis)
             }
 
 	  /* layer info */
-	  levelsize = zaxisInqSize(zaxisID);
+          int levelsize = zaxisInqSize(zaxisID);
 	  fprintf(stdout, "%6d ", levelsize);
 	  fprintf(stdout, "%3d ", vlistZaxisIndex(vlistID, zaxisID) + 1);
 
 	  /* grid info */
-	  gridsize = gridInqSize(gridID);
+	  int gridsize = gridInqSize(gridID);
 	  fprintf(stdout, "%9d ", gridsize);
 	  fprintf(stdout, "%3d ", vlistGridIndex(vlistID, gridID) + 1);
 
 	  /* datatype */
-	  datatype = vlistInqVarDatatype(vlistID, varID);
-	  if      ( datatype == DATATYPE_PACK   ) strcpy(pstr, "P0");
+          int datatype = vlistInqVarDatatype(vlistID, varID);
+	  if      ( datatype == CDI_DATATYPE_PACK   ) strcpy(pstr, "P0");
 	  else if ( datatype > 0 && datatype <= 32  ) sprintf(pstr, "P%d", datatype);
-	  else if ( datatype == DATATYPE_CPX32  ) strcpy(pstr, "C32");
-	  else if ( datatype == DATATYPE_CPX64  ) strcpy(pstr, "C64");
-	  else if ( datatype == DATATYPE_FLT32  ) strcpy(pstr, "F32");
-	  else if ( datatype == DATATYPE_FLT64  ) strcpy(pstr, "F64");
-	  else if ( datatype == DATATYPE_INT8   ) strcpy(pstr, "I8");
-	  else if ( datatype == DATATYPE_INT16  ) strcpy(pstr, "I16");
-	  else if ( datatype == DATATYPE_INT32  ) strcpy(pstr, "I32");
-	  else if ( datatype == DATATYPE_UINT8  ) strcpy(pstr, "U8");
-	  else if ( datatype == DATATYPE_UINT16 ) strcpy(pstr, "U16");
-	  else if ( datatype == DATATYPE_UINT32 ) strcpy(pstr, "U32");
+	  else if ( datatype == CDI_DATATYPE_CPX32  ) strcpy(pstr, "C32");
+	  else if ( datatype == CDI_DATATYPE_CPX64  ) strcpy(pstr, "C64");
+	  else if ( datatype == CDI_DATATYPE_FLT32  ) strcpy(pstr, "F32");
+	  else if ( datatype == CDI_DATATYPE_FLT64  ) strcpy(pstr, "F64");
+	  else if ( datatype == CDI_DATATYPE_INT8   ) strcpy(pstr, "I8");
+	  else if ( datatype == CDI_DATATYPE_INT16  ) strcpy(pstr, "I16");
+	  else if ( datatype == CDI_DATATYPE_INT32  ) strcpy(pstr, "I32");
+	  else if ( datatype == CDI_DATATYPE_UINT8  ) strcpy(pstr, "U8");
+	  else if ( datatype == CDI_DATATYPE_UINT16 ) strcpy(pstr, "U16");
+	  else if ( datatype == CDI_DATATYPE_UINT32 ) strcpy(pstr, "U32");
 	  else                                    strcpy(pstr, "-1");
 
 	  fprintf(stdout, " %-3s", pstr);
 
-	  if ( vlistInqVarCompType(vlistID, varID) == COMPRESS_NONE )
+	  if ( vlistInqVarCompType(vlistID, varID) == CDI_COMPRESS_NONE )
 	    fprintf(stdout, "  ");
 	  else
 	    fprintf(stdout, "z ");
@@ -445,13 +435,13 @@ void printShortinfo(int streamID, int vlistID, int vardis)
 
 	  cdiParamToString(param, paramstr, sizeof(paramstr));
 
-	  if (vardis)
+	  if ( vardis )
             {
               vlistInqVarName(vlistID, varID, varname);
-              fprintf(stdout, "%-11s", varname);
+              fprintf(stdout, "%-14s", varname);
             }
 	  else
-	    fprintf(stdout, "%-11s", paramstr);
+	    fprintf(stdout, "%-14s", paramstr);
 
 	  fprintf(stdout, "\n");
 	}
@@ -474,8 +464,8 @@ void printShortinfo(int streamID, int vlistID, int vardis)
           printSubtypeInfo(vlistID);
         }
 
-      taxisID = vlistInqTaxis(vlistID);
-      ntsteps = vlistNtsteps(vlistID);
+      int taxisID = vlistInqTaxis(vlistID);
+      int ntsteps = vlistNtsteps(vlistID);
 
       if ( ntsteps != 0 )
 	{
@@ -488,10 +478,8 @@ void printShortinfo(int streamID, int vlistID, int vardis)
 	    {
 	      if ( taxisInqType(taxisID) == TAXIS_RELATIVE )
 		{
-                  int calendar, tunits;
-
-		  vdate = taxisInqRdate(taxisID);
-		  vtime = taxisInqRtime(taxisID);
+		  int vdate = taxisInqRdate(taxisID);
+		  int vtime = taxisInqRtime(taxisID);
 
 		  cdiDecodeDate(vdate, &year, &month, &day);
 		  cdiDecodeTime(vtime, &hour, &minute, &second);
@@ -499,10 +487,10 @@ void printShortinfo(int streamID, int vlistID, int vardis)
 		  fprintf(stdout, "     RefTime = %4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d",
 			  year, month, day, hour, minute, second);
 
-		  tunits = taxisInqTunit(taxisID);
+		  int tunits = taxisInqTunit(taxisID);
 		  if ( tunits != CDI_UNDEFID )  fprintf(stdout, "  Units = %s", tunit2str(tunits));
 
-		  calendar = taxisInqCalendar(taxisID);
+		  int calendar = taxisInqCalendar(taxisID);
 		  if ( calendar != CDI_UNDEFID )  fprintf(stdout, "  Calendar = %s", calendar2str(calendar));
 
 		  if ( taxisHasBounds(taxisID) )
@@ -563,12 +551,12 @@ void setDefaultDataType(char *datatypestr)
 	  if      ( nbits > 0 && nbits < 32 ) DefaultDataType = nbits;
 	  else if ( nbits == 32 )
 	    {
-	      if ( DefaultFileType == FILETYPE_GRB )
-		DefaultDataType = DATATYPE_PACK32;
+	      if ( DefaultFileType == CDI_FILETYPE_GRB )
+		DefaultDataType = CDI_DATATYPE_PACK32;
 	      else
-		DefaultDataType = DATATYPE_FLT32;
+		DefaultDataType = CDI_DATATYPE_FLT32;
 	    }
-	  else if ( nbits == 64 ) DefaultDataType = DATATYPE_FLT64;
+	  else if ( nbits == 64 ) DefaultDataType = CDI_DATATYPE_FLT64;
 	  else
 	    {
 	      fprintf(stderr, "Unsupported number of bits %d!\n", nbits);
@@ -580,9 +568,9 @@ void setDefaultDataType(char *datatypestr)
 	{
 	  if ( dtype == D_INT )
 	    {
-	      if      ( nbits ==  8 ) DefaultDataType = DATATYPE_INT8;
-	      else if ( nbits == 16 ) DefaultDataType = DATATYPE_INT16;
-	      else if ( nbits == 32 ) DefaultDataType = DATATYPE_INT32;
+	      if      ( nbits ==  8 ) DefaultDataType = CDI_DATATYPE_INT8;
+	      else if ( nbits == 16 ) DefaultDataType = CDI_DATATYPE_INT16;
+	      else if ( nbits == 32 ) DefaultDataType = CDI_DATATYPE_INT32;
 	      else
 		{
 		  fprintf(stderr, "Unsupported number of bits = %d for datatype INT!\n", nbits);
@@ -592,7 +580,7 @@ void setDefaultDataType(char *datatypestr)
 	  /*
 	  else if ( dtype == D_UINT )
 	    {
-	      if      ( nbits ==  8 ) DefaultDataType = DATATYPE_UINT8;
+	      if      ( nbits ==  8 ) DefaultDataType = CDI_DATATYPE_UINT8;
 	      else
 		{
 		  fprintf(stderr, "Unsupported number of bits = %d for datatype UINT!\n", nbits);
@@ -602,8 +590,8 @@ void setDefaultDataType(char *datatypestr)
 	  */
 	  else if ( dtype == D_FLT )
 	    {
-	      if      ( nbits == 32 ) DefaultDataType = DATATYPE_FLT32;
-	      else if ( nbits == 64 ) DefaultDataType = DATATYPE_FLT64;
+	      if      ( nbits == 32 ) DefaultDataType = CDI_DATATYPE_FLT32;
+	      else if ( nbits == 64 ) DefaultDataType = CDI_DATATYPE_FLT64;
 	      else
 		{
 		  fprintf(stderr, "Unsupported number of bits = %d for datatype FLT!\n", nbits);
@@ -612,8 +600,8 @@ void setDefaultDataType(char *datatypestr)
 	    }
 	  else if ( dtype == D_CPX )
 	    {
-	      if      ( nbits == 32 ) DefaultDataType = DATATYPE_CPX32;
-	      else if ( nbits == 64 ) DefaultDataType = DATATYPE_CPX64;
+	      if      ( nbits == 32 ) DefaultDataType = CDI_DATATYPE_CPX32;
+	      else if ( nbits == 64 ) DefaultDataType = CDI_DATATYPE_CPX64;
 	      else
 		{
 		  fprintf(stderr, "Unsupported number of bits = %d for datatype CPX!\n", nbits);
@@ -650,16 +638,17 @@ void setDefaultFileType(char *filetypestr)
     {
       char *ftstr = filetypestr;
 
-      if      ( memcmp(filetypestr, "grb2", 4)  == 0 ) { ftstr += 4; DefaultFileType = FILETYPE_GRB2;}
-      else if ( memcmp(filetypestr, "grb1", 4)  == 0 ) { ftstr += 4; DefaultFileType = FILETYPE_GRB; }
-      else if ( memcmp(filetypestr, "grb",  3)  == 0 ) { ftstr += 3; DefaultFileType = FILETYPE_GRB; }
-      else if ( memcmp(filetypestr, "nc2",  3)  == 0 ) { ftstr += 3; DefaultFileType = FILETYPE_NC2; }
-      else if ( memcmp(filetypestr, "nc4c", 4)  == 0 ) { ftstr += 4; DefaultFileType = FILETYPE_NC4C;}
-      else if ( memcmp(filetypestr, "nc4",  3)  == 0 ) { ftstr += 3; DefaultFileType = FILETYPE_NC4; }
-      else if ( memcmp(filetypestr, "nc",   2)  == 0 ) { ftstr += 2; DefaultFileType = FILETYPE_NC;  }
-      else if ( memcmp(filetypestr, "srv",  3)  == 0 ) { ftstr += 3; DefaultFileType = FILETYPE_SRV; }
-      else if ( memcmp(filetypestr, "ext",  3)  == 0 ) { ftstr += 3; DefaultFileType = FILETYPE_EXT; }
-      else if ( memcmp(filetypestr, "ieg",  3)  == 0 ) { ftstr += 3; DefaultFileType = FILETYPE_IEG; }
+      if      ( memcmp(filetypestr, "grb2", 4)  == 0 ) { ftstr += 4; DefaultFileType = CDI_FILETYPE_GRB2;}
+      else if ( memcmp(filetypestr, "grb1", 4)  == 0 ) { ftstr += 4; DefaultFileType = CDI_FILETYPE_GRB; }
+      else if ( memcmp(filetypestr, "grb",  3)  == 0 ) { ftstr += 3; DefaultFileType = CDI_FILETYPE_GRB; }
+      else if ( memcmp(filetypestr, "nc2",  3)  == 0 ) { ftstr += 3; DefaultFileType = CDI_FILETYPE_NC2; }
+      else if ( memcmp(filetypestr, "nc4c", 4)  == 0 ) { ftstr += 4; DefaultFileType = CDI_FILETYPE_NC4C;}
+      else if ( memcmp(filetypestr, "nc4",  3)  == 0 ) { ftstr += 3; DefaultFileType = CDI_FILETYPE_NC4; }
+      else if ( memcmp(filetypestr, "nc1",  3)  == 0 ) { ftstr += 3; DefaultFileType = CDI_FILETYPE_NC;  }
+      else if ( memcmp(filetypestr, "nc",   2)  == 0 ) { ftstr += 2; DefaultFileType = CDI_FILETYPE_NC2; }
+      else if ( memcmp(filetypestr, "srv",  3)  == 0 ) { ftstr += 3; DefaultFileType = CDI_FILETYPE_SRV; }
+      else if ( memcmp(filetypestr, "ext",  3)  == 0 ) { ftstr += 3; DefaultFileType = CDI_FILETYPE_EXT; }
+      else if ( memcmp(filetypestr, "ieg",  3)  == 0 ) { ftstr += 3; DefaultFileType = CDI_FILETYPE_IEG; }
       else
 	{
 	  fprintf(stderr, "Unsupported filetype %s!\n", filetypestr);
@@ -702,7 +691,7 @@ int handle_error(int cdiErrno, const char *fmt, ...)
 
   fprintf(stderr, "%s\n", cdiStringError(cdiErrno));
 
-  return (cdiErrno);
+  return cdiErrno;
 }
 
 static
@@ -712,20 +701,20 @@ void defineCompress(const char *arg)
 
   if      ( strncmp(arg, "szip", len) == 0 )
     {
-      comptype = COMPRESS_SZIP;
+      comptype = CDI_COMPRESS_SZIP;
     }
   else if ( strncmp(arg, "jpeg", len) == 0 )
     {
-      comptype = COMPRESS_JPEG;
+      comptype = CDI_COMPRESS_JPEG;
     }
   else if ( strncmp(arg, "gzip", len) == 0 )
     {
-      comptype = COMPRESS_GZIP;
+      comptype = CDI_COMPRESS_GZIP;
       complevel = 6;
     }
   else if ( strncmp(arg, "zip", 3) == 0 )
     {
-      comptype = COMPRESS_ZIP;
+      comptype = CDI_COMPRESS_ZIP;
       if ( len == 5 && arg[3] == '_' && isdigit(arg[4]) )
 	complevel = atoi(&arg[4]);
       else
@@ -843,51 +832,34 @@ int main(int argc, char *argv[])
 
   if ( fname1 )
     {
-      double *data = NULL;
-      double missval;
-      double level;
       int nmiss;
       int number;
       int datasize = 0;
-      int streamID1 = CDI_UNDEFID;
       int streamID2 = CDI_UNDEFID;
       int filetype;
       int gridID, zaxisID;
       int param;
-      int vdate, vtime;
-      int nrecs, nvars;
+      int nrecs;
       int levelID, levelsize;
       int nts = 0;
       int gridsize = 0;
       int recID;
-      int tsID;
-      int ntsteps = 0;
-      int taxisID1, taxisID2 = CDI_UNDEFID;
-      int vlistID1, vlistID2 = CDI_UNDEFID;
+      int taxisID2 = CDI_UNDEFID;
+      int vlistID2 = CDI_UNDEFID;
 
-      streamID1 = streamOpenRead(fname1);
-      if ( streamID1 < 0 )
-	return (handle_error(streamID1, "Open failed on %s", fname1));
+      int streamID1 = streamOpenRead(fname1);
+      if ( streamID1 < 0 ) return handle_error(streamID1, "Open failed on %s", fname1);
 
-      vlistID1 = streamInqVlist(streamID1);
+      int vlistID1 = streamInqVlist(streamID1);
 
-      if ( Longinfo )
-	{
-	  int ngrids, nzaxis;
-	  vlistPrint(vlistID1);
-	  ngrids = vlistNgrids(vlistID1);
-	  nzaxis = vlistNzaxis(vlistID1);
-	  for ( gridID = 0; gridID < ngrids; gridID++ ) gridPrint(gridID, gridID, 1);
-	  for ( zaxisID = 0; zaxisID < nzaxis; zaxisID++ ) zaxisPrint(zaxisID, zaxisID);
-	}
+      if ( Longinfo ) vlistPrint(vlistID1);
 
-      nvars   = vlistNvars(vlistID1);
-      taxisID1 = vlistInqTaxis(vlistID1);
-      ntsteps = vlistNtsteps(vlistID1);
+      int nvars = vlistNvars(vlistID1);
+      int taxisID1 = vlistInqTaxis(vlistID1);
+      int ntsteps = vlistNtsteps(vlistID1);
 
-      if (Debug)
-        fprintf(stderr, "nvars   = %d\n"
-                "ntsteps = %d\n", nvars, ntsteps);
+      if ( Debug )
+        fprintf(stderr, "nvars   = %d\nntsteps = %d\n", nvars, ntsteps);
 
       if ( fname2 )
         {
@@ -918,12 +890,12 @@ int main(int argc, char *argv[])
 
 	  streamID2 = streamOpenWrite(fname2, filetype);
 	  if ( streamID2 < 0 )
-	    return (handle_error(streamID2, "Open failed on %s", fname2));
+	    return handle_error(streamID2, "Open failed on %s", fname2);
 
 	  if ( DefaultByteorder != CDI_UNDEFID )
 	    streamDefByteorder(streamID2, DefaultByteorder);
 
-	  if ( comptype != COMPRESS_NONE )
+	  if ( comptype != CDI_COMPRESS_NONE )
 	    {
 	      streamDefCompType(streamID2, comptype);
 	      streamDefCompLevel(streamID2, complevel);
@@ -935,14 +907,13 @@ int main(int argc, char *argv[])
 	}
 
       if ( vlistNumber(vlistID1) != CDI_REAL ) datasize *= 2;
-      data = (double *) malloc((size_t)datasize * sizeof (double));
+      double *data = (double *) malloc((size_t)datasize * sizeof (double));
 
       /*
 	nts = cdiInqTimeSize(streamID1);
       */
-      if (Debug)
-	printf("nts = %d streamID1 = %d, streamID2 = %d\n",
-               nts, streamID1, streamID2);
+      if ( Debug )
+	printf("nts = %d streamID1 = %d, streamID2 = %d\n", nts, streamID1, streamID2);
 
       if ( Shortinfo )
 	{
@@ -950,7 +921,7 @@ int main(int argc, char *argv[])
 	  printShortinfo(streamID1, vlistID1, Vardis);
 	}
 
-      tsID = 0;
+      int tsID = 0;
       if ( Info || fname2 )
       while ( (nrecs = streamInqTimestep(streamID1, tsID)) > 0 )
 	{
@@ -959,8 +930,8 @@ int main(int argc, char *argv[])
               taxisCopyTimestep(taxisID2, taxisID1);
               streamDefTimestep(streamID2, tsID);
             }
-	  vdate = taxisInqVdate(taxisID1);
-	  vtime = taxisInqVtime(taxisID1);
+	  int vdate = taxisInqVdate(taxisID1);
+	  int vtime = taxisInqVtime(taxisID1);
 
 	  if ( Debug )
 	    fprintf(stdout, "tsID = %d nrecs = %d date = %d time = %d\n", tsID, nrecs, vdate, vtime);
@@ -986,8 +957,8 @@ int main(int argc, char *argv[])
 			 varID, param, gridID, zaxisID, levelID);
 		  */
 		  gridsize = gridInqSize(gridID);
-		  level    = zaxisInqLevel(zaxisID, levelID);
-		  missval  = vlistInqVarMissval(vlistID1, varID);
+		  double level   = zaxisInqLevels(zaxisID, NULL) ? zaxisInqLevel(zaxisID, levelID) : levelID+1;
+                  double missval = vlistInqVarMissval(vlistID1, varID);
 
 		  if ( Info )
 		    printInfo(vdate, vtime, varname, level, gridsize, number, nmiss, missval, data, Vardis);
@@ -1023,12 +994,12 @@ int main(int argc, char *argv[])
 			    varID, param, gridID, zaxisID);
 
 		  gridsize = gridInqSize(gridID);
-		  missval  = vlistInqVarMissval(vlistID1, varID);
+		  double missval = vlistInqVarMissval(vlistID1, varID);
 
 		  levelsize = zaxisInqSize(zaxisID);
 		  for ( levelID = 0; levelID < levelsize; levelID++ )
 		    {
-		      level = zaxisInqLevel(zaxisID, levelID);
+                      double level = zaxisInqLevels(zaxisID, NULL) ? zaxisInqLevel(zaxisID, levelID) : levelID+1;
 		      streamReadVarSlice(streamID1, varID, levelID, data, &nmiss);
 
 		      if ( Info )
@@ -1039,6 +1010,7 @@ int main(int argc, char *argv[])
 		    }
 		}
 	    }
+
 	  tsID++;
         }
 
@@ -1058,7 +1030,7 @@ int main(int argc, char *argv[])
   if ( wTable )
     tableWrite(wTable, itableID);
 
-  return (0);
+  return 0;
 }
 /*
  * Local Variables:
diff --git a/libcdi/app/printinfo.h b/libcdi/app/printinfo.h
index 3a10ffe..f019c8e 100644
--- a/libcdi/app/printinfo.h
+++ b/libcdi/app/printinfo.h
@@ -9,6 +9,14 @@
 #define DATE_FORMAT "%5.4d-%2.2d-%2.2d"
 #define TIME_FORMAT "%2.2d:%2.2d:%2.2d"
 
+void my_reset_text_color(FILE *fp)
+{
+  (void)fp;
+#ifdef CDO
+  reset_text_color(fp);
+#endif
+}
+
 void datetime2str(int date, int time, char *datetimestr, int maxlen)
 {
   int year, month, day;
@@ -50,31 +58,31 @@ void printFiletype(int streamID, int vlistID)
 
   switch ( filetype )
     {
-    case FILETYPE_GRB:
+    case CDI_FILETYPE_GRB:
       printf("GRIB");
       break;
-    case FILETYPE_GRB2:
+    case CDI_FILETYPE_GRB2:
       printf("GRIB2");
       break;
-    case FILETYPE_NC:
+    case CDI_FILETYPE_NC:
       printf("NetCDF");
       break;
-    case FILETYPE_NC2:
+    case CDI_FILETYPE_NC2:
       printf("NetCDF2");
       break;
-    case FILETYPE_NC4:
+    case CDI_FILETYPE_NC4:
       printf("NetCDF4");
       break;
-    case FILETYPE_NC4C:
+    case CDI_FILETYPE_NC4C:
       printf("NetCDF4 classic");
       break;
-    case FILETYPE_SRV:
+    case CDI_FILETYPE_SRV:
       printf("SERVICE");
       break;
-    case FILETYPE_EXT:
+    case CDI_FILETYPE_EXT:
       printf("EXTRA");
       break;
-    case FILETYPE_IEG:
+    case CDI_FILETYPE_IEG:
       printf("IEG");
       break;
     default:
@@ -82,7 +90,7 @@ void printFiletype(int streamID, int vlistID)
       break;
     }
 
-  if ( filetype == FILETYPE_SRV || filetype == FILETYPE_EXT || filetype == FILETYPE_IEG )
+  if ( filetype == CDI_FILETYPE_SRV || filetype == CDI_FILETYPE_EXT || filetype == CDI_FILETYPE_IEG )
     {
       switch ( streamInqByteorder(streamID) )
 	{
@@ -95,40 +103,31 @@ void printFiletype(int streamID, int vlistID)
 	}
     }
 
-  if ( filetype == FILETYPE_GRB || filetype == FILETYPE_NC4 || filetype == FILETYPE_NC4C )
+  if ( filetype == CDI_FILETYPE_GRB || filetype == CDI_FILETYPE_NC4 || filetype == CDI_FILETYPE_NC4C )
     {
-      int nvars, varID;
-      int comptype;
-
-      nvars = vlistNvars(vlistID);
-
-      for ( varID = 0; varID < nvars; varID++ )
+      int nvars = vlistNvars(vlistID);
+      for ( int varID = 0; varID < nvars; varID++ )
 	{
-	  comptype = vlistInqVarCompType(vlistID, varID);
+	  int comptype = vlistInqVarCompType(vlistID, varID);
 	  if ( comptype )
 	    {
-	      if ( comptype == COMPRESS_SZIP )
-		printf(" SZIP");
-	      else if ( comptype == COMPRESS_ZIP )
-		printf(" ZIP");
+	      if      ( comptype == CDI_COMPRESS_SZIP ) printf(" SZIP");
+	      else if ( comptype == CDI_COMPRESS_ZIP  ) printf(" ZIP");
 
 	      break;
 	    }
 	}
     }
 
-  if ( filetype == FILETYPE_GRB2 )
+  if ( filetype == CDI_FILETYPE_GRB2 )
     {
-      int comptype;
       int nvars = vlistNvars(vlistID);
       for ( int varID = 0; varID < nvars; varID++ )
 	{
-	  comptype = vlistInqVarCompType(vlistID, varID);
+	  int comptype = vlistInqVarCompType(vlistID, varID);
 	  if ( comptype )
 	    {
-	      if ( comptype == COMPRESS_JPEG )
-		printf(" JPEG");
-
+	      if ( comptype == CDI_COMPRESS_JPEG ) printf(" JPEG");
 	      break;
 	    }
 	}
@@ -138,250 +137,349 @@ void printFiletype(int streamID, int vlistID)
 }
 
 static
-void printGridInfo(int vlistID)
+void print_xvals(int gridID, int dig)
 {
-  char xname[CDI_MAX_NAME], yname[CDI_MAX_NAME], xunits[CDI_MAX_NAME], yunits[CDI_MAX_NAME];
-  unsigned char uuidOfHGrid[CDI_UUID_SIZE];
+  int xsize = gridInqXsize(gridID);
+  if ( xsize > 0 && gridInqXvals(gridID, NULL) )
+    {
+      char xname[CDI_MAX_NAME], xunits[CDI_MAX_NAME];
+      gridInqXname(gridID, xname);
+      gridInqXunits(gridID, xunits);
 
-  int ngrids = vlistNgrids(vlistID);
-  for ( int index = 0; index < ngrids; index++ )
+      double xfirst = gridInqXval(gridID, 0);
+      double xlast  = gridInqXval(gridID, xsize-1);
+      double xinc   = gridInqXinc(gridID);
+      fprintf(stdout, "%33s : %.*g", xname, dig, xfirst);
+      if ( xsize > 1 )
+        {
+          fprintf(stdout, " to %.*g", dig, xlast);
+          if ( IS_NOT_EQUAL(xinc, 0) )
+            fprintf(stdout, " by %.*g", dig, xinc);
+        }
+      fprintf(stdout, " %s", xunits);
+      if ( gridIsCircular(gridID) ) fprintf(stdout, "  circular");
+      fprintf(stdout, "\n");
+    }
+}
+
+static
+void print_yvals(int gridID, int dig)
+{
+  int ysize = gridInqYsize(gridID);
+  if ( ysize > 0 && gridInqYvals(gridID, NULL) )
     {
-      int gridID   = vlistGrid(vlistID, index);
-      int gridtype = gridInqType(gridID);
-      int trunc    = gridInqTrunc(gridID);
-      int gridsize = gridInqSize(gridID);
-      int xsize    = gridInqXsize(gridID);
-      int ysize    = gridInqYsize(gridID);
-      int xysize   = xsize*ysize;
-      int prec     = gridInqPrec(gridID);
+      char yname[CDI_MAX_NAME], yunits[CDI_MAX_NAME];
+      gridInqYname(gridID, yname);
+      gridInqYunits(gridID, yunits);
 
-      int dig = (prec == DATATYPE_FLT64) ? 15 : 7;
+      double yfirst = gridInqYval(gridID, 0);
+      double ylast  = gridInqYval(gridID, ysize-1);
+      double yinc   = gridInqYinc(gridID);
+      fprintf(stdout, "%33s : %.*g", yname, dig, yfirst);
+      if ( ysize > 1 )
+        {
+          int gridtype = gridInqType(gridID);
+          fprintf(stdout, " to %.*g", dig, ylast);
+          if ( IS_NOT_EQUAL(yinc, 0) && gridtype != GRID_GAUSSIAN && gridtype != GRID_GAUSSIAN_REDUCED )
+            fprintf(stdout, " by %.*g", dig, yinc);
+        }
+      fprintf(stdout, " %s", yunits);
+      fprintf(stdout, "\n");
+    }
+}
 
+static
+void print_xyvals2D(int gridID, int dig)
+{
+  if ( gridInqXvals(gridID, NULL) && gridInqYvals(gridID, NULL) )
+    {
+      char xname[CDI_MAX_NAME], yname[CDI_MAX_NAME], xunits[CDI_MAX_NAME], yunits[CDI_MAX_NAME];
       gridInqXname(gridID, xname);
       gridInqYname(gridID, yname);
       gridInqXunits(gridID, xunits);
       gridInqYunits(gridID, yunits);
 
-      fprintf(stdout, "  %4d : %-24s", index+1, gridNamePtr(gridtype));
+      int gridsize = gridInqSize(gridID);
+      double *xvals2D = (double*) malloc((size_t)gridsize*sizeof(double));
+      double *yvals2D = (double*) malloc((size_t)gridsize*sizeof(double));
 
-      if ( gridtype == GRID_LONLAT   ||
-	   gridtype == GRID_LCC2 ||
-	   gridtype == GRID_LAEA ||
-	   gridtype == GRID_SINUSOIDAL ||
-	   gridtype == GRID_GENERIC ||
-	   gridtype == GRID_GAUSSIAN ||
-	   gridtype == GRID_GAUSSIAN_REDUCED )
-	{
-	  double yfirst = gridInqYval(gridID, 0);
-	  double ylast  = gridInqYval(gridID, ysize-1);
-	  double yinc   = gridInqYinc(gridID);
+      gridInqXvals(gridID, xvals2D);
+      gridInqYvals(gridID, yvals2D);
 
-          fprintf(stdout, " : points=%d", gridsize);
-	  if ( gridtype == GRID_GAUSSIAN_REDUCED )
-	    fprintf(stdout, "  nlat=%d", ysize);
-	  else if ( xysize )
-	    fprintf(stdout, " (%dx%d)", xsize, ysize);
+      double xfirst = xvals2D[0];
+      double xlast  = xvals2D[0];
+      double yfirst = yvals2D[0];
+      double ylast  = yvals2D[0];
+      for ( int i = 1; i < gridsize; i++ )
+        {
+          if ( xvals2D[i] < xfirst ) xfirst = xvals2D[i];
+          if ( xvals2D[i] > xlast  ) xlast  = xvals2D[i];
+          if ( yvals2D[i] < yfirst ) yfirst = yvals2D[i];
+          if ( yvals2D[i] > ylast  ) ylast  = yvals2D[i];
+        }
 
-	  if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
-	    fprintf(stdout, "  np=%d", gridInqNP(gridID));
+      double xinc = 0;
+      double yinc = 0;
+      int gridtype = gridInqType(gridID);
+      if ( gridtype == GRID_CURVILINEAR )
+        {
+          int xsize = gridInqXsize(gridID);
+          if ( xsize > 1 )
+            {
+              double *xvals = (double*) malloc(xsize*sizeof(double));
+              for ( int 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++ )
+                if ( fabs(fabs(xvals[i-1] - xvals[i]) - xinc) > 0.01*xinc ) { xinc = 0; break; }
+              free(xvals);
+            }
+          int ysize = gridInqYsize(gridID);
+          if ( ysize > 1 )
+            {
+              double *yvals = (double*) malloc(ysize*sizeof(double));
+              for ( int 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++ )
+                if ( fabs(fabs(yvals[i-1] - yvals[i]) - yinc) > 0.01*yinc ) { yinc = 0; break; }
+              free(yvals);
+            }
+        }
 
-	  fprintf(stdout, "\n");
+      fprintf(stdout, "%33s : %.*g to %.*g", xname, dig, xfirst, dig, xlast);
+      if ( IS_NOT_EQUAL(xinc, 0) )
+        fprintf(stdout, " by %.*g", dig, xinc);
+      fprintf(stdout, " %s", xunits);
+      if ( gridIsCircular(gridID) ) fprintf(stdout, "  circular");
+      fprintf(stdout, "\n");
+      fprintf(stdout, "%33s : %.*g to %.*g", yname, dig, yfirst, dig, ylast);
+      if ( IS_NOT_EQUAL(yinc, 0) )
+        fprintf(stdout, " by %.*g", dig, yinc);
+      fprintf(stdout, " %s", xunits);
+      fprintf(stdout, "\n");
 
-          bool lxcoord = true, lycoord = true;
-          if ( gridInqXvals(gridID, NULL) == 0 ) lxcoord = false;
-          if ( gridInqYvals(gridID, NULL) == 0 ) lycoord = false;
+      free(xvals2D);
+      free(yvals2D);
+    }
+}
 
-	  if ( xsize > 0 && lxcoord )
-	    {
-              double xfirst = gridInqXval(gridID, 0);
-              double xlast  = gridInqXval(gridID, xsize-1);
-              double xinc   = gridInqXinc(gridID);
-              fprintf(stdout, "%33s : %.*g", xname, dig, xfirst);
-              if ( xsize > 1 )
-                {
-                  fprintf(stdout, " to %.*g", dig, xlast);
-                  if ( IS_NOT_EQUAL(xinc, 0) )
-                    fprintf(stdout, " by %.*g", dig, xinc);
-                }
-              fprintf(stdout, " %s", xunits);
-              if ( gridIsCircular(gridID) ) fprintf(stdout, "  circular");
-              fprintf(stdout, "\n");
-	    }
+static
+void printGridInfoKernel(int gridID, int index, bool lproj)
+{
+  int gridtype = gridInqType(gridID);
 
-	  if ( ysize > 0 && lycoord )
-	    {
-	      fprintf(stdout, "%33s : %.*g", yname, dig, yfirst);
-	      if ( ysize > 1 )
-                {
-                  fprintf(stdout, " to %.*g", dig, ylast);
-                  if ( IS_NOT_EQUAL(yinc, 0) && gridtype != GRID_GAUSSIAN && gridtype != GRID_GAUSSIAN_REDUCED )
-                    fprintf(stdout, " by %.*g", dig, yinc);
-                }
-              fprintf(stdout, " %s", yunits);
-	      fprintf(stdout, "\n");
-	    }
+  if ( lproj && gridtype != GRID_PROJECTION )
+    fprintf(stderr, "Internal problem (%s): sub grid not equal GRID_PROJECTION!\n", __func__);
 
-	  if ( gridIsRotated(gridID) )
-	    {
-	      double lonpole = gridInqXpole(gridID);
-	      double latpole = gridInqYpole(gridID);
-	      double angle   = gridInqAngle(gridID);
-	      fprintf(stdout, "%33s : lon=%.*g  lat=%.*g", "northpole", dig, lonpole, dig, latpole);
-	      if ( IS_NOT_EQUAL(angle, 0) ) fprintf(stdout, "  angle=%.*g", dig, angle);
-	      fprintf(stdout, "\n");
-	    }
+  int trunc    = gridInqTrunc(gridID);
+  int gridsize = gridInqSize(gridID);
+  int xsize    = gridInqXsize(gridID);
+  int ysize    = gridInqYsize(gridID);
+  int xysize   = xsize*ysize;
 
-	  if ( gridInqXbounds(gridID, NULL) || gridInqYbounds(gridID, NULL) )
-	    {
-	      fprintf(stdout, "%33s :", "available");
-	      if ( gridInqXbounds(gridID, NULL) && gridInqYbounds(gridID, NULL) ) fprintf(stdout, " cellbounds");
-	      if ( gridHasArea(gridID) )          fprintf(stdout, " area");
-	      if ( gridInqMask(gridID, NULL) )    fprintf(stdout, " mask");
-	      fprintf(stdout, "\n");
-	    }
+  // int prec     = gridInqPrec(gridID);
+  // int dig = (prec == CDI_DATATYPE_FLT64) ? 15 : 7;
+  int dig = 7;
 
-	  if ( gridtype == GRID_LAEA )
-	    {
-	      double a, lon_0, lat_0;
-	      gridInqLaea(gridID, &a, &lon_0, &lat_0);
-	      fprintf(stdout, "%33s : a=%g  lon_0=%g  lat_0=%g\n", "projpar", a, lon_0, lat_0);
-	    }
+  if ( !lproj )
+    {
+      fprintf(stdout, "  %4d : ", index+1);
+#ifdef CDO
+      set_text_color(stdout, RESET, BLUE);
+#endif
+      fprintf(stdout, "%-24s", gridNamePtr(gridtype));
+      my_reset_text_color(stdout);
+      fprintf(stdout, " : ");
+    }
+
+  if ( gridtype == GRID_LONLAT     ||
+       gridtype == GRID_PROJECTION ||
+       gridtype == GRID_GENERIC    ||
+       gridtype == GRID_GAUSSIAN   ||
+       gridtype == GRID_GAUSSIAN_REDUCED )
+    {
+      if ( !lproj )
+        {
+#ifdef CDO
+          set_text_color(stdout, RESET, GREEN);
+#endif
+          fprintf(stdout, "points=%d", gridsize);
+          if ( gridtype == GRID_GAUSSIAN_REDUCED )
+            fprintf(stdout, "  nlat=%d", ysize);
+          else if ( xysize )
+            fprintf(stdout, " (%dx%d)", xsize, ysize);
+
+          if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
+            fprintf(stdout, "  np=%d", gridInqNP(gridID));
+          my_reset_text_color(stdout);
 
-	  if ( gridtype == GRID_LCC2 )
-	    {
-	      double a, lon_0, lat_0, lat_1, lat_2;
-	      gridInqLcc2(gridID, &a, &lon_0, &lat_0, &lat_1, &lat_2);
-	      fprintf(stdout, "%33s : a=%7.0f  lon_0=%g  lat_0=%g  lat_1=%g  lat_2=%g\n",
-                      "projpar", a, lon_0, lat_0, lat_1, lat_2);
-	    }
-	}
-      else if ( gridtype == GRID_SPECTRAL )
-	{
-	  fprintf(stdout, " : points=%d  nsp=%d  truncation=%d", gridsize, gridsize/2, trunc);
-          if ( gridInqComplexPacking(gridID) ) fprintf(stdout, "  complexPacking");
           fprintf(stdout, "\n");
-	}
-      else if ( gridtype == GRID_FOURIER )
-	{
-	  fprintf(stdout, " : points=%d  nfc=%d  truncation=%d\n", gridsize, gridsize/2, trunc);
-	}
-      else if ( gridtype == GRID_GME )
-	{
-	  int ni = gridInqGMEni(gridID);
-	  int nd = gridInqGMEnd(gridID);
-	  fprintf(stdout, " : points=%d  nd=%d  ni=%d\n", gridsize, nd, ni);
-	}
-      else if ( gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED )
-	{
-	  if ( gridtype == GRID_CURVILINEAR )
-	    fprintf(stdout, " : points=%d (%dx%d)", gridsize, xsize, ysize);
-	  else
-	    fprintf(stdout, " : points=%d", gridsize);
+        }
+
+      char name[CDI_MAX_NAME]; name[0] = 0;
+      cdiGridInqKeyStr(gridID, CDI_KEY_MAPNAME, CDI_MAX_NAME, name);
+      if ( gridtype == GRID_PROJECTION || name[0] )
+        {
+          if ( name[0] == 0 ) strcpy(name, "undefined");
+#ifdef CDO
+          set_text_color(stdout, RESET, BLUE);
+#endif
+          fprintf(stdout, "         %24s", "mapping");
+          my_reset_text_color(stdout);
+          fprintf(stdout, " : ");
+#ifdef CDO
+          set_text_color(stdout, RESET, GREEN);
+#endif
+          fprintf(stdout, "%s\n", name);
+          my_reset_text_color(stdout);
+        }
 
-          if ( gridtype == GRID_UNSTRUCTURED && gridInqNvertex(gridID) > 0 )
-	    fprintf(stdout, "  nvertex=%d", gridInqNvertex(gridID));
+      print_xvals(gridID, dig);
+      print_yvals(gridID, dig);
 
+      if ( gridInqXbounds(gridID, NULL) || gridInqYbounds(gridID, NULL) )
+        {
+          fprintf(stdout, "%33s :", "available");
+          if ( gridInqXbounds(gridID, NULL) && gridInqYbounds(gridID, NULL) ) fprintf(stdout, " cellbounds");
+          if ( gridHasArea(gridID) )          fprintf(stdout, " area");
+          if ( gridInqMask(gridID, NULL) )    fprintf(stdout, " mask");
           fprintf(stdout, "\n");
+        }
+    }
+  else if ( gridtype == GRID_SPECTRAL )
+    {
+#ifdef CDO
+      set_text_color(stdout, RESET, GREEN);
+#endif
+      fprintf(stdout, "points=%d  nsp=%d  truncation=%d", gridsize, gridsize/2, trunc);
+      if ( gridInqComplexPacking(gridID) ) fprintf(stdout, "  complexPacking");
+      my_reset_text_color(stdout);
+      fprintf(stdout, "\n");
+    }
+  else if ( gridtype == GRID_FOURIER )
+    {
+#ifdef CDO
+      set_text_color(stdout, RESET, GREEN);
+#endif
+      fprintf(stdout, "points=%d  nfc=%d  truncation=%d\n", gridsize, gridsize/2, trunc);
+      my_reset_text_color(stdout);
+    }
+  else if ( gridtype == GRID_GME )
+    {
+      int nd, ni, ni2, ni3;
+      gridInqParamGME(gridID, &nd, &ni, &ni2, &ni3);
+#ifdef CDO
+      set_text_color(stdout, RESET, GREEN);
+#endif
+      fprintf(stdout, "points=%d  nd=%d  ni=%d\n", gridsize, nd, ni);
+      my_reset_text_color(stdout);
+    }
+  else if ( gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED )
+    {
+#ifdef CDO
+      set_text_color(stdout, RESET, GREEN);
+#endif
+      if ( gridtype == GRID_CURVILINEAR )
+        fprintf(stdout, "points=%d (%dx%d)", gridsize, xsize, ysize);
+      else
+        fprintf(stdout, "points=%d", gridsize);
 
-          if ( gridtype == GRID_UNSTRUCTURED )
-            {
-              int number   = gridInqNumber(gridID);
-              int position = gridInqPosition(gridID);
+      if ( gridtype == GRID_UNSTRUCTURED && gridInqNvertex(gridID) > 0 )
+        fprintf(stdout, "  nvertex=%d", gridInqNvertex(gridID));
+      my_reset_text_color(stdout);
 
-              if ( number > 0 )
-                {
-                  fprintf(stdout, "%33s : number=%d  position=%d\n", "grid", number, position);
-                }
+      fprintf(stdout, "\n");
 
-              if ( gridInqReference(gridID, NULL) )
-                {
-                  char reference_link[8192];
-                  gridInqReference(gridID, reference_link);
-                  fprintf(stdout, "%33s : %s\n", "uri", reference_link);
-                }
+      if ( gridtype == GRID_UNSTRUCTURED )
+        {
+          int number   = gridInqNumber(gridID);
+          int position = gridInqPosition(gridID);
+          if ( number > 0 )
+            fprintf(stdout, "%33s : number=%d  position=%d\n", "grid", number, position);
+
+          if ( gridInqReference(gridID, NULL) )
+            {
+              char reference_link[8192];
+              gridInqReference(gridID, reference_link);
+              fprintf(stdout, "%33s : %s\n", "uri", reference_link);
             }
+        }
 
-	  if ( gridInqXvals(gridID, NULL) && gridInqYvals(gridID, NULL) )
-	    {
-	      double *xvals = (double*) malloc((size_t)gridsize*sizeof(double));
-	      double *yvals = (double*) malloc((size_t)gridsize*sizeof(double));
-
-	      gridInqXvals(gridID, xvals);
-	      gridInqYvals(gridID, yvals);
-
-	      double xfirst = xvals[0];
-	      double xlast  = xvals[0];
-	      double yfirst = yvals[0];
-	      double ylast  = yvals[0];
-	      for ( int i = 1; i < gridsize; i++ )
-		{
-		  if ( xvals[i] < xfirst ) xfirst = xvals[i];
-		  if ( xvals[i] > xlast  ) xlast  = xvals[i];
-		  if ( yvals[i] < yfirst ) yfirst = yvals[i];
-		  if ( yvals[i] > ylast  ) ylast  = yvals[i];
-		}
-
-	      fprintf(stdout, "%33s : %.*g to %.*g %s", xname, dig, xfirst, dig, xlast, xunits);
-	      if ( gridIsCircular(gridID) ) fprintf(stdout, "  circular");
-	      fprintf(stdout, "\n");
-	      fprintf(stdout, "%33s : %.*g to %.*g %s\n", yname, dig, yfirst, dig, ylast, yunits);
-
-	      free(xvals);
-	      free(yvals);
-	    }
-	}
-      else if ( gridtype == GRID_LCC )
-	{
-	  double originLon, originLat, lonParY, lat1, lat2, xincm, yincm;
-	  int projflag, scanflag;
+      print_xyvals2D(gridID, dig);
+    }
+  else if ( gridtype == GRID_LCC )
+    {
+      double originLon, originLat, lonParY, lat1, lat2, xincm, yincm;
+      int projflag, scanflag;
 
-	  gridInqLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
-		     &projflag, &scanflag);
+      gridInqParamLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
+                 &projflag, &scanflag);
 
-	  fprintf(stdout, " : points=%d (%dx%d)  ", gridsize, xsize, ysize);
-	  if ( (projflag&128) == 0 )
-	    fprintf(stdout, "North Pole\n");
-	  else
-	    fprintf(stdout, "South Pole\n");
+#ifdef CDO
+      set_text_color(stdout, RESET, GREEN);
+#endif
+      fprintf(stdout, "points=%d (%dx%d)  ", gridsize, xsize, ysize);
+      if ( (projflag&128) == 0 )
+        fprintf(stdout, "North Pole\n");
+      else
+        fprintf(stdout, "South Pole\n");
+      my_reset_text_color(stdout);
 
-	  fprintf(stdout, "%33s : originLon=%g  originLat=%g  lonParY=%g\n", " ", originLon, originLat, lonParY);
-	  fprintf(stdout, "%33s : lat1=%g  lat2=%g  xinc=%g m  yinc=%g m\n", " ", lat1, lat2, xincm, yincm);
-	}
-      else /* if ( gridtype == GRID_GENERIC ) */
-	{
-	  if ( ysize == 0 )
-	    fprintf(stdout, " : points=%d\n", gridsize);
-	  else
-            fprintf(stdout, " : points=%d (%dx%d)\n", gridsize, xsize, ysize);
-	}
+      fprintf(stdout, "%33s : originLon=%g  originLat=%g  lonParY=%g\n", " ", originLon, originLat, lonParY);
+      fprintf(stdout, "%33s : lat1=%g  lat2=%g  xinc=%g m  yinc=%g m\n", " ", lat1, lat2, xincm, yincm);
+    }
+  else /* if ( gridtype == GRID_GENERIC ) */
+    {
+#ifdef CDO
+      set_text_color(stdout, RESET, GREEN);
+#endif
+      if ( ysize == 0 )
+        fprintf(stdout, "points=%d\n", gridsize);
+      else
+        fprintf(stdout, "points=%d (%dx%d)\n", gridsize, xsize, ysize);
+      my_reset_text_color(stdout);
+    }
 
-      if ( gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED || gridtype == GRID_LCC )
-	{
-	  if ( gridHasArea(gridID) ||
-	       gridInqXbounds(gridID, NULL) || gridInqYbounds(gridID, NULL) )
-	    {
-	      fprintf(stdout, "%33s :", "available");
-	      if ( gridInqXbounds(gridID, NULL) && gridInqYbounds(gridID, NULL) ) fprintf(stdout, " cellbounds");
-	      if ( gridHasArea(gridID) )          fprintf(stdout, " area");
-	      if ( gridInqMask(gridID, NULL) )    fprintf(stdout, " mask");
-	      fprintf(stdout, "\n");
-	    }
-	}
+  if ( gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED || gridtype == GRID_LCC )
+    {
+      if ( gridHasArea(gridID) ||
+           gridInqXbounds(gridID, NULL) || gridInqYbounds(gridID, NULL) )
+        {
+          fprintf(stdout, "%33s :", "available");
+          if ( gridInqXbounds(gridID, NULL) && gridInqYbounds(gridID, NULL) ) fprintf(stdout, " cellbounds");
+          if ( gridHasArea(gridID) )          fprintf(stdout, " area");
+          if ( gridInqMask(gridID, NULL) )    fprintf(stdout, " mask");
+          fprintf(stdout, "\n");
+        }
+    }
 
-      gridInqUUID(gridID, uuidOfHGrid);
-      if ( !cdiUUIDIsNull(uuidOfHGrid) )
+  unsigned char uuidOfHGrid[CDI_UUID_SIZE];
+  gridInqUUID(gridID, uuidOfHGrid);
+  if ( !cdiUUIDIsNull(uuidOfHGrid) )
+    {
+      char uuidOfHGridStr[37];
+      cdiUUID2Str(uuidOfHGrid, uuidOfHGridStr);
+      if ( uuidOfHGridStr[0] != 0  && strlen(uuidOfHGridStr) == 36 )
         {
-          char uuidOfHGridStr[37];
-          cdiUUID2Str(uuidOfHGrid, uuidOfHGridStr);
-          if ( uuidOfHGridStr[0] != 0  && strlen(uuidOfHGridStr) == 36 )
-            {
-	      fprintf(stdout, "%33s : %s\n", "uuid", uuidOfHGridStr);
-            }
+          fprintf(stdout, "%33s : %s\n", "uuid", uuidOfHGridStr);
         }
     }
 }
 
 static
+void printGridInfo(int vlistID)
+{
+  int ngrids = vlistNgrids(vlistID);
+  for ( int index = 0; index < ngrids; index++ )
+    {
+      int gridID = vlistGrid(vlistID, index);
+      printGridInfoKernel(gridID, index, false);
+      int projID = gridInqProj(gridID);
+      if ( projID != CDI_UNDEFID )
+        printGridInfoKernel(projID, index, true);
+    }
+}
+
+static
 void printZaxisInfo(int vlistID)
 {
   char zaxisname[CDI_MAX_NAME], zname[CDI_MAX_NAME], zunits[CDI_MAX_NAME];
@@ -394,53 +492,70 @@ void printZaxisInfo(int vlistID)
       int zaxistype = zaxisInqType(zaxisID);
       int ltype     = zaxisInqLtype(zaxisID);
       int levelsize = zaxisInqSize(zaxisID);
-      int prec      = zaxisInqPrec(zaxisID);
-
-      int dig = (prec == DATATYPE_FLT64) ? 15 : 7;
+      // int prec      = zaxisInqPrec(zaxisID);
+      // int dig = (prec == CDI_DATATYPE_FLT64) ? 15 : 7;
+      int dig = 7;
 
       zaxisName(zaxistype, zaxisname);
       zaxisInqName(zaxisID, zname);
       zaxisInqUnits(zaxisID, zunits);
       zunits[12] = 0;
 
+      fprintf(stdout, "  %4d : ", vlistZaxisIndex(vlistID, zaxisID)+1);
+#ifdef CDO
+      set_text_color(stdout, RESET, BLUE);
+#endif
       if ( zaxistype == ZAXIS_GENERIC && ltype != 0 )
-        fprintf(stdout, "  %4d : %-12s (ltype=%3d) :", vlistZaxisIndex(vlistID, zaxisID)+1, zaxisname, ltype);
+        fprintf(stdout, "%-12s (ltype=%3d)", zaxisname, ltype);
       else
-        fprintf(stdout, "  %4d : %-24s :", vlistZaxisIndex(vlistID, zaxisID)+1, zaxisname);
+        fprintf(stdout, "%-24s", zaxisname);
+      my_reset_text_color(stdout);
 
+      fprintf(stdout, " :");
+
+#ifdef CDO
+      set_text_color(stdout, RESET, GREEN);
+#endif
       fprintf(stdout, " levels=%d", levelsize);
+      bool zscalar = (levelsize == 1) ? zaxisInqScalar(zaxisID) : false;
+      if ( zscalar ) fprintf(stdout, "  scalar");
+      my_reset_text_color(stdout);
       fprintf(stdout, "\n");
 
-      double *levels = (double*) malloc((size_t)levelsize*sizeof(double));
-      zaxisInqLevels(zaxisID, levels);
-
-      if ( !(zaxistype == ZAXIS_SURFACE && levelsize == 1 && !(fabs(levels[0]) > 0)) )
+      if ( zaxisInqLevels(zaxisID, NULL) )
         {
-          double zfirst = levels[0];
-          double zlast  = levels[levelsize-1];
-          if ( levelsize > 2 )
+          double *levels = (double*) malloc((size_t)levelsize*sizeof(double));
+          zaxisInqLevels(zaxisID, levels);
+
+          if ( !(zaxistype == ZAXIS_SURFACE && levelsize == 1 && !(fabs(levels[0]) > 0)) )
             {
-              int levelID;
-              zinc = (levels[levelsize-1] - levels[0]) / (levelsize-1);
-              for ( levelID = 2; levelID < levelsize; ++levelID )
-                if ( fabs(fabs(levels[levelID] - levels[levelID-1]) - zinc) > 0.001*zinc ) break;
+              double zfirst = levels[0];
+              double zlast  = levels[levelsize-1];
+              if ( levelsize > 2 )
+                {
+                  zinc = (levels[levelsize-1] - levels[0]) / (levelsize-1);
+                  for ( int levelID = 2; levelID < levelsize; ++levelID )
+                    if ( fabs(fabs(levels[levelID] - levels[levelID-1]) - zinc) > 0.001*zinc )
+                      {
+                        zinc = 0;
+                        break;
+                      }
+                }
 
-              if ( levelID < levelsize ) zinc = 0;
+              fprintf(stdout, "%33s : %.*g", zname, dig, zfirst);
+              if ( levelsize > 1 )
+                {
+                  fprintf(stdout, " to %.*g", dig, zlast);
+                  if ( IS_NOT_EQUAL(zinc, 0) )
+                    fprintf(stdout, " by %.*g", dig, zinc);
+                }
+              fprintf(stdout, " %s", zunits);
+              fprintf(stdout, "\n");
             }
 
-          fprintf(stdout, "%33s : %.*g", zname, dig, zfirst);
-          if ( levelsize > 1 )
-            {
-              fprintf(stdout, " to %.*g", dig, zlast);
-              if ( IS_NOT_EQUAL(zinc, 0) )
-                fprintf(stdout, " by %.*g", dig, zinc);
-            }
-          fprintf(stdout, " %s", zunits);
-          fprintf(stdout, "\n");
+          free(levels);
         }
 
-      free(levels);
-
       if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
         {
           double level1, level2;
@@ -463,9 +578,8 @@ void printZaxisInfo(int vlistID)
 
       if ( zaxistype == ZAXIS_HYBRID )
         {
-          char psname[CDI_MAX_NAME];
-          psname[0] = 0;
-          zaxisInqPsName(zaxisID, psname);
+          char psname[CDI_MAX_NAME]; psname[0] = 0;
+          cdiZaxisInqKeyStr(zaxisID, CDI_KEY_PSNAME, CDI_MAX_NAME, psname);
           int vctsize = zaxisInqVctSize(zaxisID);
           if ( vctsize || psname[0] )
             {
@@ -533,7 +647,7 @@ int printDateTime(int ntimeout, int vdate, int vtime)
 
   fprintf(stdout, " %s %s", vdatestr, vtimestr);
 
-  return (++ntimeout);
+  return ++ntimeout;
 }
 
 #define NUM_TIMESTEP 60
diff --git a/libcdi/configure b/libcdi/configure
index b3db107..4129851 100755
--- a/libcdi/configure
+++ b/libcdi/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.68 for cdi 1.7.2.
+# Generated by GNU Autoconf 2.68 for cdi 1.8.0.
 #
 # Report bugs to <http://mpimet.mpg.de/cdi>.
 #
@@ -570,8 +570,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='cdi'
 PACKAGE_TARNAME='cdi'
-PACKAGE_VERSION='1.7.2'
-PACKAGE_STRING='cdi 1.7.2'
+PACKAGE_VERSION='1.8.0'
+PACKAGE_STRING='cdi 1.8.0'
 PACKAGE_BUGREPORT='http://mpimet.mpg.de/cdi'
 PACKAGE_URL=''
 
@@ -688,10 +688,6 @@ HAVE_LIBGRIB_API_FALSE
 HAVE_LIBGRIB_API_TRUE
 GRIB_API_LIBS
 GRIB_API_INCLUDE
-LIBPNG_LIBS
-OPENJPEG_LIBS
-openjpeg_LIBS
-JASPER_LIBS
 NETCDF_LIBS
 NETCDF_INCLUDE
 NETCDF_ROOT
@@ -862,9 +858,6 @@ enable_largefile
 with_threads
 with_szlib
 with_netcdf
-with_jasper
-with_openjpeg
-with_libpng
 with_grib_api
 enable_grib
 enable_cgribex
@@ -1467,7 +1460,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.7.2 to adapt to many kinds of systems.
+\`configure' configures cdi 1.8.0 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1537,7 +1530,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of cdi 1.7.2:";;
+     short | recursive ) echo "Configuration of cdi 1.8.0:";;
    esac
   cat <<\_ACEOF
 
@@ -1592,16 +1585,6 @@ Optional Packages:
                           NETCDF4 compression
   --with-netcdf=<yes|no|directory> (default=no)
                           location of NetCDF library (lib and include subdirs)
-  --with-jasper=<directory>
-                          Specify location of JASPER library. You must specify
-                          its location if GRIB_API was built with JASPER.
-  --with-openjpeg=<directory>
-                          Specify location of openjpeg library. You must
-                          specify its location if GRIB_API was built with
-                          openjpeg.
-  --with-libpng=<directory>
-                          Specify location of LIBPNG library. You must specify
-                          its location if GRIB_API was built with LIBPNG.
   --with-grib_api=<yes|no|directory>
                           library for grib2 compression; if a directory is
                           given, it will be used as a value for
@@ -1740,7 +1723,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-cdi configure 1.7.2
+cdi configure 1.8.0
 generated by GNU Autoconf 2.68
 
 Copyright (C) 2010 Free Software Foundation, Inc.
@@ -2585,7 +2568,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by cdi $as_me 1.7.2, which was
+It was created by cdi $as_me 1.8.0, which was
 generated by GNU Autoconf 2.68.  Invocation command line was
 
   $ $0 $@
@@ -3537,7 +3520,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='cdi'
- VERSION='1.7.2'
+ VERSION='1.8.0'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -23406,7 +23389,7 @@ Usage: $0 [OPTIONS]
 Report bugs to <bug-libtool at gnu.org>."
 
 lt_cl_version="\
-cdi config.lt 1.7.2
+cdi config.lt 1.8.0
 configured by $0, generated by GNU Autoconf 2.68.
 
 Copyright (C) 2011 Free Software Foundation, Inc.
@@ -27167,7 +27150,19 @@ fi
 
 
                             if test "x$NC_CONFIG" != "x"; then :
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking netcdf's nc2 support" >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking netcdf's OpenDAP support" >&5
+$as_echo_n "checking netcdf's OpenDAP support... " >&6; }
+                                   if test "x$($NC_CONFIG --has-dap)" = "xyes"; then :
+
+$as_echo "#define HAVE_LIBNC_DAP 1" >>confdefs.h
+
+                                          { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+                                  { $as_echo "$as_me:${as_lineno-$LINENO}: checking netcdf's nc2 support" >&5
 $as_echo_n "checking netcdf's nc2 support... " >&6; }
                                    if test "x$($NC_CONFIG --has-nc2)" = "xyes"; then :
 
@@ -27429,7 +27424,7 @@ for ac_lib in '' netcdf; do
     ac_res="none required"
   else
     ac_res=-l$ac_lib
-    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+    LIBS="-l$ac_lib -lhdf5 $ac_func_search_save_LIBS"
   fi
   if ac_fn_c_try_link "$LINENO"; then :
   ac_cv_search_H5TS_mutex_lock=$ac_res
@@ -27490,7 +27485,7 @@ for ac_lib in '' netcdf; do
     ac_res="none required"
   else
     ac_res=-l$ac_lib
-    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+    LIBS="-l$ac_lib -lhdf5 $ac_func_search_save_LIBS"
   fi
   if ac_fn_c_try_link "$LINENO"; then :
   ac_cv_search_H5get_libversion=$ac_res
@@ -27529,507 +27524,6 @@ fi
 
 
 #  ----------------------------------------------------------------------
-#  Link application with JASPER library (needed for GRIB2 compression)
-JASPER_LIBS=''
-
-# Check whether --with-jasper was given.
-if test "${with_jasper+set}" = set; then :
-  withval=$with_jasper; case "$with_jasper" in #(
-  no) :
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for jasper library" >&5
-$as_echo_n "checking for jasper library... " >&6; }
-                           { $as_echo "$as_me:${as_lineno-$LINENO}: result: suppressed" >&5
-$as_echo "suppressed" >&6; } ;; #(
-  yes) :
-    for ac_header in jasper.h
-do :
-  ac_fn_c_check_header_mongrel "$LINENO" "jasper.h" "ac_cv_header_jasper_h" "$ac_includes_default"
-if test "x$ac_cv_header_jasper_h" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_JASPER_H 1
-_ACEOF
-
-fi
-
-done
-
-                            { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing jas_init" >&5
-$as_echo_n "checking for library containing jas_init... " >&6; }
-if ${ac_cv_search_jas_init+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_func_search_save_LIBS=$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 jas_init ();
-int
-main ()
-{
-return jas_init ();
-  ;
-  return 0;
-}
-_ACEOF
-for ac_lib in '' jasper; do
-  if test -z "$ac_lib"; then
-    ac_res="none required"
-  else
-    ac_res=-l$ac_lib
-    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
-  fi
-  if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_search_jas_init=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext
-  if ${ac_cv_search_jas_init+:} false; then :
-  break
-fi
-done
-if ${ac_cv_search_jas_init+:} false; then :
-
-else
-  ac_cv_search_jas_init=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_jas_init" >&5
-$as_echo "$ac_cv_search_jas_init" >&6; }
-ac_res=$ac_cv_search_jas_init
-if test "$ac_res" != no; then :
-  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-$as_echo "#define HAVE_LIBJASPER 1" >>confdefs.h
-
-else
-  as_fn_error $? "Could not link to jasper library! Required for GRIB_API" "$LINENO" 5
-fi
-
-                            JASPER_LIBS=" -ljasper"
- ;; #(
-  *) :
-    JASPER_ROOT=$with_jasper
-                          if test -d "$JASPER_ROOT"; then :
-  LDFLAGS="$LDFLAGS -L$JASPER_ROOT/lib"
-                                 CPPFLAGS="$CPPFLAGS -I$JASPER_ROOT/include"
-                                 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing jas_stream_memopen" >&5
-$as_echo_n "checking for library containing jas_stream_memopen... " >&6; }
-if ${ac_cv_search_jas_stream_memopen+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_func_search_save_LIBS=$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 jas_stream_memopen ();
-int
-main ()
-{
-return jas_stream_memopen ();
-  ;
-  return 0;
-}
-_ACEOF
-for ac_lib in '' jasper; do
-  if test -z "$ac_lib"; then
-    ac_res="none required"
-  else
-    ac_res=-l$ac_lib
-    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
-  fi
-  if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_search_jas_stream_memopen=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext
-  if ${ac_cv_search_jas_stream_memopen+:} false; then :
-  break
-fi
-done
-if ${ac_cv_search_jas_stream_memopen+:} false; then :
-
-else
-  ac_cv_search_jas_stream_memopen=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_jas_stream_memopen" >&5
-$as_echo "$ac_cv_search_jas_stream_memopen" >&6; }
-ac_res=$ac_cv_search_jas_stream_memopen
-if test "$ac_res" != no; then :
-  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-$as_echo "#define HAVE_LIBJASPER 1" >>confdefs.h
-
-else
-  as_fn_error $? "Could not link to jasper library! Required for GRIB_API" "$LINENO" 5
-fi
-
-                                 JASPER_LIBS=" -L$JASPER_ROOT/lib -ljasper"
-else
-  as_fn_error $? "$JASPER_ROOT is not a directory! JASPER suppressed" "$LINENO" 5
-fi ;; #(
-  *) :
-     ;;
-esac
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the JASPER library" >&5
-$as_echo_n "checking for the JASPER library... " >&6; }
-             { $as_echo "$as_me:${as_lineno-$LINENO}: result: suppressed" >&5
-$as_echo "suppressed" >&6; }
-fi
-
-
-#  ----------------------------------------------------------------------
-#  Link application with openjpeg library (needed for GRIB2 compression)
-OPENJPEG_LIBS=''
-
-# Check whether --with-openjpeg was given.
-if test "${with_openjpeg+set}" = set; then :
-  withval=$with_openjpeg; case "$with_openjpeg" in #(
-  no) :
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openjpeg library" >&5
-$as_echo_n "checking for openjpeg library... " >&6; }
-                           { $as_echo "$as_me:${as_lineno-$LINENO}: result: suppressed" >&5
-$as_echo "suppressed" >&6; } ;; #(
-  yes) :
-    for ac_header in openjpeg.h
-do :
-  ac_fn_c_check_header_mongrel "$LINENO" "openjpeg.h" "ac_cv_header_openjpeg_h" "$ac_includes_default"
-if test "x$ac_cv_header_openjpeg_h" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_OPENJPEG_H 1
-_ACEOF
-
-fi
-
-done
-
-                            { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opj_image_create" >&5
-$as_echo_n "checking for library containing opj_image_create... " >&6; }
-if ${ac_cv_search_opj_image_create+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_func_search_save_LIBS=$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 opj_image_create ();
-int
-main ()
-{
-return opj_image_create ();
-  ;
-  return 0;
-}
-_ACEOF
-for ac_lib in '' openjpeg; do
-  if test -z "$ac_lib"; then
-    ac_res="none required"
-  else
-    ac_res=-l$ac_lib
-    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
-  fi
-  if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_search_opj_image_create=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext
-  if ${ac_cv_search_opj_image_create+:} false; then :
-  break
-fi
-done
-if ${ac_cv_search_opj_image_create+:} false; then :
-
-else
-  ac_cv_search_opj_image_create=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opj_image_create" >&5
-$as_echo "$ac_cv_search_opj_image_create" >&6; }
-ac_res=$ac_cv_search_opj_image_create
-if test "$ac_res" != no; then :
-  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-$as_echo "#define HAVE_LIBOPENJPEG 1" >>confdefs.h
-
-else
-  as_fn_error $? "Could not link to openjpeg library! Required for GRIB_API" "$LINENO" 5
-fi
-
-                            openjpeg_LIBS=" -lopenjpeg"
- ;; #(
-  *) :
-    OPENJPEG_ROOT=$with_openjpeg
-                          if test -d "$OPENJPEG_ROOT"; then :
-  LDFLAGS="$LDFLAGS -L$OPENJPEG_ROOT/lib"
-                                 CPPFLAGS="$CPPFLAGS -I$OPENJPEG_ROOT/include"
-                                 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opj_image_create" >&5
-$as_echo_n "checking for library containing opj_image_create... " >&6; }
-if ${ac_cv_search_opj_image_create+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_func_search_save_LIBS=$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 opj_image_create ();
-int
-main ()
-{
-return opj_image_create ();
-  ;
-  return 0;
-}
-_ACEOF
-for ac_lib in '' openjpeg; do
-  if test -z "$ac_lib"; then
-    ac_res="none required"
-  else
-    ac_res=-l$ac_lib
-    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
-  fi
-  if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_search_opj_image_create=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext
-  if ${ac_cv_search_opj_image_create+:} false; then :
-  break
-fi
-done
-if ${ac_cv_search_opj_image_create+:} false; then :
-
-else
-  ac_cv_search_opj_image_create=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opj_image_create" >&5
-$as_echo "$ac_cv_search_opj_image_create" >&6; }
-ac_res=$ac_cv_search_opj_image_create
-if test "$ac_res" != no; then :
-  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-$as_echo "#define HAVE_LIBOPENJPEG 1" >>confdefs.h
-
-else
-  as_fn_error $? "Could not link to openjpeg library! Required for GRIB_API" "$LINENO" 5
-fi
-
-                                 OPENJPEG_LIBS=" -L$OPENJPEG_ROOT/lib -lopenjpeg"
-else
-  as_fn_error $? "$OPENJPEG_ROOT is not a directory! openjpeg suppressed" "$LINENO" 5
-fi ;; #(
-  *) :
-     ;;
-esac
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the openjpeg library" >&5
-$as_echo_n "checking for the openjpeg library... " >&6; }
-             { $as_echo "$as_me:${as_lineno-$LINENO}: result: suppressed" >&5
-$as_echo "suppressed" >&6; }
-fi
-
-
-#  ----------------------------------------------------------------------
-#  Link application with LIBPNG library (needed for GRIB2 compression)
-LIBPNG_LIBS=''
-
-# Check whether --with-libpng was given.
-if test "${with_libpng+set}" = set; then :
-  withval=$with_libpng; case "$with_libpng" in #(
-  no) :
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libpng library" >&5
-$as_echo_n "checking for libpng library... " >&6; }
-                           { $as_echo "$as_me:${as_lineno-$LINENO}: result: suppressed" >&5
-$as_echo "suppressed" >&6; } ;; #(
-  yes) :
-    for ac_header in png.h
-do :
-  ac_fn_c_check_header_mongrel "$LINENO" "png.h" "ac_cv_header_png_h" "$ac_includes_default"
-if test "x$ac_cv_header_png_h" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE_PNG_H 1
-_ACEOF
-
-fi
-
-done
-
-                            { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing png_warning" >&5
-$as_echo_n "checking for library containing png_warning... " >&6; }
-if ${ac_cv_search_png_warning+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_func_search_save_LIBS=$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 png_warning ();
-int
-main ()
-{
-return png_warning ();
-  ;
-  return 0;
-}
-_ACEOF
-for ac_lib in '' png; do
-  if test -z "$ac_lib"; then
-    ac_res="none required"
-  else
-    ac_res=-l$ac_lib
-    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
-  fi
-  if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_search_png_warning=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext
-  if ${ac_cv_search_png_warning+:} false; then :
-  break
-fi
-done
-if ${ac_cv_search_png_warning+:} false; then :
-
-else
-  ac_cv_search_png_warning=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_png_warning" >&5
-$as_echo "$ac_cv_search_png_warning" >&6; }
-ac_res=$ac_cv_search_png_warning
-if test "$ac_res" != no; then :
-  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-$as_echo "#define HAVE_LIBLIBPNG 1" >>confdefs.h
-
-else
-  as_fn_error $? "Could not link to libpng library! Required for GRIB_API" "$LINENO" 5
-fi
-
-                            LIBPNG_LIBS=" -lpng"
- ;; #(
-  *) :
-    LIBPNG_ROOT=$with_libpng
-                          if test -d "$LIBPNG_ROOT"; then :
-  LDFLAGS="$LDFLAGS -L$LIBPNG_ROOT/lib"
-                                 CPPFLAGS="$CPPFLAGS -I$LIBPNG_ROOT/include"
-                                 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing png_warning" >&5
-$as_echo_n "checking for library containing png_warning... " >&6; }
-if ${ac_cv_search_png_warning+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_func_search_save_LIBS=$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 png_warning ();
-int
-main ()
-{
-return png_warning ();
-  ;
-  return 0;
-}
-_ACEOF
-for ac_lib in '' png; do
-  if test -z "$ac_lib"; then
-    ac_res="none required"
-  else
-    ac_res=-l$ac_lib
-    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
-  fi
-  if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_search_png_warning=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext
-  if ${ac_cv_search_png_warning+:} false; then :
-  break
-fi
-done
-if ${ac_cv_search_png_warning+:} false; then :
-
-else
-  ac_cv_search_png_warning=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_png_warning" >&5
-$as_echo "$ac_cv_search_png_warning" >&6; }
-ac_res=$ac_cv_search_png_warning
-if test "$ac_res" != no; then :
-  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-$as_echo "#define HAVE_LIBLIBPNG 1" >>confdefs.h
-
-else
-  as_fn_error $? "Could not link to libpng library! Required for GRIB_API" "$LINENO" 5
-fi
-
-                                 LIBPNG_LIBS=" -L$LIBPNG_ROOT/lib -lpng"
-else
-  as_fn_error $? "$LIBPNG_ROOT is not a directory! LIBPNG suppressed" "$LINENO" 5
-fi ;; #(
-  *) :
-     ;;
-esac
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the LIBPNG library" >&5
-$as_echo_n "checking for the LIBPNG library... " >&6; }
-             { $as_echo "$as_me:${as_lineno-$LINENO}: result: suppressed" >&5
-$as_echo "suppressed" >&6; }
-fi
-
-
-#  ----------------------------------------------------------------------
 #  Compile application with GRIB_API library (for GRIB2 support)
 GRIB_API_INCLUDE=''
 GRIB_API_LIBS=''
@@ -31040,7 +30534,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by cdi $as_me 1.7.2, which was
+This file was extended by cdi $as_me 1.8.0, which was
 generated by GNU Autoconf 2.68.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -31106,7 +30600,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-cdi config.status 1.7.2
+cdi config.status 1.8.0
 configured by $0, generated by GNU Autoconf 2.68,
   with options \\"\$ac_cs_config\\"
 
diff --git a/libcdi/configure.ac b/libcdi/configure.ac
index 578f31c..63bedad 100644
--- a/libcdi/configure.ac
+++ b/libcdi/configure.ac
@@ -4,7 +4,7 @@
 #  autoconf 2.68
 #  libtool  2.4.2
 
-AC_INIT([cdi], [1.7.2], [http://mpimet.mpg.de/cdi])
+AC_INIT([cdi], [1.8.0], [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 703625c..a3cb233 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 f9593d1..2e7d37b 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 49afd26..906edca 100644
--- a/libcdi/examples/Makefile.in
+++ b/libcdi/examples/Makefile.in
@@ -314,11 +314,9 @@ INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
 INSTALL_SCRIPT = @INSTALL_SCRIPT@
 INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-JASPER_LIBS = @JASPER_LIBS@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
 LIBOBJS = @LIBOBJS@
-LIBPNG_LIBS = @LIBPNG_LIBS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
@@ -342,7 +340,6 @@ NM = @NM@
 NMEDIT = @NMEDIT@
 OBJDUMP = @OBJDUMP@
 OBJEXT = @OBJEXT@
-OPENJPEG_LIBS = @OPENJPEG_LIBS@
 OTOOL = @OTOOL@
 OTOOL64 = @OTOOL64@
 PACKAGE = @PACKAGE@
@@ -424,7 +421,6 @@ localstatedir = @localstatedir@
 mandir = @mandir@
 mkdir_p = @mkdir_p@
 oldincludedir = @oldincludedir@
-openjpeg_LIBS = @openjpeg_LIBS@
 pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
diff --git a/libcdi/examples/cdi_copy.c b/libcdi/examples/cdi_copy.c
index fa98702..3de9a1c 100644
--- a/libcdi/examples/cdi_copy.c
+++ b/libcdi/examples/cdi_copy.c
@@ -28,7 +28,7 @@ int main(void)
   int varID2 = 1;
 
   // Open the output dataset (GRIB format)
-  int streamID2  = streamOpenWrite("example.grb", FILETYPE_GRB);
+  int streamID2  = streamOpenWrite("example.grb", CDI_FILETYPE_GRB);
   if ( streamID2 < 0 )
     {
       fprintf(stderr, "%s\n", cdiStringError(streamID2));
diff --git a/libcdi/examples/cdi_write.c b/libcdi/examples/cdi_write.c
index 0910c99..6a8926d 100644
--- a/libcdi/examples/cdi_write.c
+++ b/libcdi/examples/cdi_write.c
@@ -47,7 +47,7 @@ int main(void)
   vlistDefTaxis(vlistID, taxisID);
 
   // Create a dataset in netCDF format
-  int streamID = streamOpenWrite("example.nc", FILETYPE_NC);
+  int streamID = streamOpenWrite("example.nc", CDI_FILETYPE_NC);
   if ( streamID < 0 )
     {
       fprintf(stderr, "%s\n", cdiStringError(streamID));
diff --git a/libcdi/examples/cdi_write_ens.c b/libcdi/examples/cdi_write_ens.c
index 6adea9f..f89af0e 100644
--- a/libcdi/examples/cdi_write_ens.c
+++ b/libcdi/examples/cdi_write_ens.c
@@ -7,7 +7,7 @@
 int main(void)
 {
   char fname[] = "test_ens.grb2";
-  int filetype = FILETYPE_GRB2;
+  int filetype = CDI_FILETYPE_GRB2;
   int nlat = 18, nlon = 2*nlat;
   double *data = NULL;
   int nlevel;
diff --git a/libcdi/examples/cdi_write_f2003.f90 b/libcdi/examples/cdi_write_f2003.f90
index 890f157..9b25ed2 100644
--- a/libcdi/examples/cdi_write_f2003.f90
+++ b/libcdi/examples/cdi_write_f2003.f90
@@ -58,7 +58,7 @@
       CALL vlistDefTaxis(vlistID, taxisID)
 
 !     Create a dataset in netCDF format
-      streamID = streamOpenWrite(C_CHAR_"example.nc"//C_NULL_CHAR, FILETYPE_NC)
+      streamID = streamOpenWrite(C_CHAR_"example.nc"//C_NULL_CHAR, CDI_FILETYPE_NC)
       IF ( streamID < 0 ) THEN
          msg => cdiStringError(streamID)
          WRITE(0,'(132a)') msg
diff --git a/libcdi/examples/cdi_write_hybrid.c b/libcdi/examples/cdi_write_hybrid.c
index e697393..7eadc0e 100644
--- a/libcdi/examples/cdi_write_hybrid.c
+++ b/libcdi/examples/cdi_write_hybrid.c
@@ -72,7 +72,7 @@ int main(void)
   vlistDefTaxis(vlistID, taxisID);
 
   // Create a dataset in netCDF format
-  streamID = streamOpenWrite("example.nc", FILETYPE_NC);
+  streamID = streamOpenWrite("example.nc", CDI_FILETYPE_NC);
   if ( streamID < 0 )
     {
       fprintf(stderr, "%s\n", cdiStringError(streamID));
diff --git a/libcdi/examples/pio/Makefile.in b/libcdi/examples/pio/Makefile.in
index 1536458..5f27b58 100644
--- a/libcdi/examples/pio/Makefile.in
+++ b/libcdi/examples/pio/Makefile.in
@@ -308,11 +308,9 @@ INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
 INSTALL_SCRIPT = @INSTALL_SCRIPT@
 INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-JASPER_LIBS = @JASPER_LIBS@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
 LIBOBJS = @LIBOBJS@
-LIBPNG_LIBS = @LIBPNG_LIBS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
@@ -336,7 +334,6 @@ NM = @NM@
 NMEDIT = @NMEDIT@
 OBJDUMP = @OBJDUMP@
 OBJEXT = @OBJEXT@
-OPENJPEG_LIBS = @OPENJPEG_LIBS@
 OTOOL = @OTOOL@
 OTOOL64 = @OTOOL64@
 PACKAGE = @PACKAGE@
@@ -418,7 +415,6 @@ localstatedir = @localstatedir@
 mandir = @mandir@
 mkdir_p = @mkdir_p@
 oldincludedir = @oldincludedir@
-openjpeg_LIBS = @openjpeg_LIBS@
 pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
diff --git a/libcdi/examples/pio/collectData.c b/libcdi/examples/pio/collectData.c
index 7ee2ba1..1b2d987 100644
--- a/libcdi/examples/pio/collectData.c
+++ b/libcdi/examples/pio/collectData.c
@@ -30,7 +30,7 @@ uniform_partition_start(int set_interval[2], int nparts, int part_idx);
 static void modelRun(MPI_Comm commModel)
 {
   enum {
-    filetype    = FILETYPE_GRB,
+    filetype    = CDI_FILETYPE_GRB,
     ntfiles     = 2,
     ntsteps     = 3,
     nVars       = 5,
diff --git a/libcdi/examples/pio/collectData2003.F90 b/libcdi/examples/pio/collectData2003.F90
index 70e5fee..bec482c 100644
--- a/libcdi/examples/pio/collectData2003.F90
+++ b/libcdi/examples/pio/collectData2003.F90
@@ -72,7 +72,7 @@ CONTAINS
     INTEGER, PARAMETER :: nts      =  3   ! Number of time steps
     INTEGER, PARAMETER :: vdate    = 19850101
     INTEGER, PARAMETER :: vtime    = 120000
-    INTEGER, PARAMETER :: filetype = FILETYPE_GRB
+    INTEGER, PARAMETER :: filetype = CDI_FILETYPE_GRB
 
     INTEGER :: gridID, zaxisID1, zaxisID2, taxisID
     INTEGER :: vlistID, varID1, varID2, streamID, tsID
diff --git a/libcdi/examples/pio/collectDataNStreams.c b/libcdi/examples/pio/collectDataNStreams.c
index 98e4098..58a9501 100644
--- a/libcdi/examples/pio/collectDataNStreams.c
+++ b/libcdi/examples/pio/collectDataNStreams.c
@@ -42,7 +42,7 @@ uniform_partition_start(int set_interval[2], int nparts, int part_idx);
 static void modelRun(MPI_Comm commModel)
 {
   enum {
-    filetype    = FILETYPE_GRB,
+    filetype    = CDI_FILETYPE_GRB,
     nStreams    = 5,
     MAXNSTREAMS = 25,
     ntfiles     = 2,
diff --git a/libcdi/examples/pio/compareResourcesArray.c b/libcdi/examples/pio/compareResourcesArray.c
index 2a3d5ad..6d359f0 100644
--- a/libcdi/examples/pio/compareResourcesArray.c
+++ b/libcdi/examples/pio/compareResourcesArray.c
@@ -146,7 +146,7 @@ static int defineVlist ( int gridID, int zaxisID, int taxisID )
   vlistDefVarName(vlistID, varID1, "varname1");
   {
     int globfac[] = { 23, 42 };
-    vlistDefAttInt(vlistID, varID1, "seer's globule factors", DATATYPE_INT16,
+    vlistDefAttInt(vlistID, varID1, "seer's globule factors", CDI_DATATYPE_INT16,
                    2, globfac);
   }
   vlistDefVarName(vlistID, varID2, "varname2");
@@ -198,7 +198,7 @@ static void modelRun ( MPI_Comm comm )
   instID  = defineInstitute ();
   defineModel(instID);
   vlistID = defineVlist     ( gridID, zaxisID, taxisID);
-  streamID = streamOpenWrite("example.grb", FILETYPE_GRB);
+  streamID = streamOpenWrite("example.grb", CDI_FILETYPE_GRB);
   if ( streamID < 0 ) xabort ( "Could not open file" );
   defineStream ( streamID, vlistID );
 
diff --git a/libcdi/interfaces/Makefile.in b/libcdi/interfaces/Makefile.in
index a7c5b60..49bc178 100644
--- a/libcdi/interfaces/Makefile.in
+++ b/libcdi/interfaces/Makefile.in
@@ -292,11 +292,9 @@ INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
 INSTALL_SCRIPT = @INSTALL_SCRIPT@
 INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-JASPER_LIBS = @JASPER_LIBS@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
 LIBOBJS = @LIBOBJS@
-LIBPNG_LIBS = @LIBPNG_LIBS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
@@ -320,7 +318,6 @@ NM = @NM@
 NMEDIT = @NMEDIT@
 OBJDUMP = @OBJDUMP@
 OBJEXT = @OBJEXT@
-OPENJPEG_LIBS = @OPENJPEG_LIBS@
 OTOOL = @OTOOL@
 OTOOL64 = @OTOOL64@
 PACKAGE = @PACKAGE@
@@ -402,7 +399,6 @@ localstatedir = @localstatedir@
 mandir = @mandir@
 mkdir_p = @mkdir_p@
 oldincludedir = @oldincludedir@
-openjpeg_LIBS = @openjpeg_LIBS@
 pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
diff --git a/libcdi/m4/acx_options.m4 b/libcdi/m4/acx_options.m4
index 8782e58..58ca0f4 100644
--- a/libcdi/m4/acx_options.m4
+++ b/libcdi/m4/acx_options.m4
@@ -80,6 +80,10 @@ AC_ARG_WITH([netcdf],
                             NETCDF_LIBS=" -lnetcdf"
                             AC_CHECK_PROG(NC_CONFIG,nc-config,nc-config)
                             AS_IF([test "x$NC_CONFIG" != "x"],
+                                  [AC_MSG_CHECKING([netcdf's OpenDAP support])
+                                   AS_IF([test "x$($NC_CONFIG --has-dap)" = "xyes"],
+                                         [AC_DEFINE([HAVE_LIBNC_DAP],[1],[Define to 1 for NetCDF OpenDAP])
+                                          AC_MSG_RESULT([yes])],[AC_MSG_RESULT([no])])]
                                   [AC_MSG_CHECKING([netcdf's nc2 support])
                                    AS_IF([test "x$($NC_CONFIG --has-nc2)" = "xyes"],
                                          [AC_DEFINE([HAVE_NETCDF2],[1],[Define to 1 for NetCDF2 support])
@@ -137,11 +141,11 @@ AC_ARG_WITH([netcdf],
 
 AS_IF([test "x$ENABLE_NC4HDF5" = "xyes"],
       [AC_SEARCH_LIBS([H5TS_mutex_lock], [netcdf],
-               [AC_DEFINE([HAVE_NC4HDF5_THREADSAFE],[1],[Define to 1 for NetCDF4/HDF5 threadsafe support])],,)])
+               [AC_DEFINE([HAVE_NC4HDF5_THREADSAFE],[1],[Define to 1 for NetCDF4/HDF5 threadsafe support])],,[-lhdf5])])
 
 AS_IF([test "x$ENABLE_NC4HDF5" = "xyes"],
       [AC_SEARCH_LIBS([H5get_libversion], [netcdf],
-               [AC_DEFINE([HAVE_H5GET_LIBVERSION],[1],[Define to 1 for H5get_libversion support])],,)])
+               [AC_DEFINE([HAVE_H5GET_LIBVERSION],[1],[Define to 1 for H5get_libversion support])],,[-lhdf5])])
 
 AC_SUBST([ENABLE_NETCDF])
 AC_SUBST([ENABLE_NC2])
@@ -151,84 +155,6 @@ AC_SUBST([NETCDF_ROOT])
 AC_SUBST([NETCDF_INCLUDE])
 AC_SUBST([NETCDF_LIBS])
 #  ----------------------------------------------------------------------
-#  Link application with JASPER library (needed for GRIB2 compression)
-JASPER_LIBS=''
-AC_ARG_WITH([jasper],
-            [AS_HELP_STRING([--with-jasper=<directory>],
-                            [Specify location of JASPER library. You must specify its location if GRIB_API was built with JASPER.])],
-            [AS_CASE(["$with_jasper"],
-                     [no],[AC_MSG_CHECKING([for jasper library])
-                           AC_MSG_RESULT([suppressed])],
-                     [yes],[AC_CHECK_HEADERS([jasper.h])
-                            AC_SEARCH_LIBS([jas_init],[jasper],[AC_DEFINE([HAVE_LIBJASPER],[1],[Define to 1 for JPEG compression for GRIB2])],
-                                           [AC_MSG_ERROR([Could not link to jasper library! Required for GRIB_API])])
-                            AC_SUBST([JASPER_LIBS],[" -ljasper"])],
-                     [*],[JASPER_ROOT=$with_jasper
-                          AS_IF([test -d "$JASPER_ROOT"],
-                                [LDFLAGS="$LDFLAGS -L$JASPER_ROOT/lib"
-                                 CPPFLAGS="$CPPFLAGS -I$JASPER_ROOT/include"
-                                 AC_SEARCH_LIBS([jas_stream_memopen],
-                                                [jasper],
-                                                [AC_DEFINE([HAVE_LIBJASPER],[1],[Define to 1 for JPEG compression for GRIB2])],
-                                                [AC_MSG_ERROR([Could not link to jasper library! Required for GRIB_API])])
-                                 JASPER_LIBS=" -L$JASPER_ROOT/lib -ljasper"],
-                                [AC_MSG_ERROR([$JASPER_ROOT is not a directory! JASPER suppressed])])])],
-            [AC_MSG_CHECKING([for the JASPER library])
-             AC_MSG_RESULT([suppressed])])
-AC_SUBST([JASPER_LIBS])
-#  ----------------------------------------------------------------------
-#  Link application with openjpeg library (needed for GRIB2 compression)
-OPENJPEG_LIBS=''
-AC_ARG_WITH([openjpeg],
-            [AS_HELP_STRING([--with-openjpeg=<directory>],
-                            [Specify location of openjpeg library. You must specify its location if GRIB_API was built with openjpeg.])],
-            [AS_CASE(["$with_openjpeg"],
-                     [no],[AC_MSG_CHECKING([for openjpeg library])
-                           AC_MSG_RESULT([suppressed])],
-                     [yes],[AC_CHECK_HEADERS([openjpeg.h])
-                            AC_SEARCH_LIBS([opj_image_create],[openjpeg],[AC_DEFINE([HAVE_LIBOPENJPEG],[1],[Define to 1 for JPEG compression for GRIB2])],
-                                           [AC_MSG_ERROR([Could not link to openjpeg library! Required for GRIB_API])])
-                            AC_SUBST([openjpeg_LIBS],[" -lopenjpeg"])],
-                     [*],[OPENJPEG_ROOT=$with_openjpeg
-                          AS_IF([test -d "$OPENJPEG_ROOT"],
-                                [LDFLAGS="$LDFLAGS -L$OPENJPEG_ROOT/lib"
-                                 CPPFLAGS="$CPPFLAGS -I$OPENJPEG_ROOT/include"
-                                 AC_SEARCH_LIBS([opj_image_create],
-                                                [openjpeg],
-                                                [AC_DEFINE([HAVE_LIBOPENJPEG],[1],[Define to 1 for JPEG compression for GRIB2])],
-                                                [AC_MSG_ERROR([Could not link to openjpeg library! Required for GRIB_API])])
-                                 OPENJPEG_LIBS=" -L$OPENJPEG_ROOT/lib -lopenjpeg"],
-                                [AC_MSG_ERROR([$OPENJPEG_ROOT is not a directory! openjpeg suppressed])])])],
-            [AC_MSG_CHECKING([for the openjpeg library])
-             AC_MSG_RESULT([suppressed])])
-AC_SUBST([OPENJPEG_LIBS])
-#  ----------------------------------------------------------------------
-#  Link application with LIBPNG library (needed for GRIB2 compression)
-LIBPNG_LIBS=''
-AC_ARG_WITH([libpng],
-            [AS_HELP_STRING([--with-libpng=<directory>],
-                            [Specify location of LIBPNG library. You must specify its location if GRIB_API was built with LIBPNG.])],
-            [AS_CASE(["$with_libpng"],
-                     [no],[AC_MSG_CHECKING([for libpng library])
-                           AC_MSG_RESULT([suppressed])],
-                     [yes],[AC_CHECK_HEADERS([png.h])
-                            AC_SEARCH_LIBS([png_warning],[png],[AC_DEFINE([HAVE_LIBLIBPNG],[1],[Define to 1 for PNG compression for GRIB2])],
-                                           [AC_MSG_ERROR([Could not link to libpng library! Required for GRIB_API])])
-                            AC_SUBST([LIBPNG_LIBS],[" -lpng"])],
-                     [*],[LIBPNG_ROOT=$with_libpng
-                          AS_IF([test -d "$LIBPNG_ROOT"],
-                                [LDFLAGS="$LDFLAGS -L$LIBPNG_ROOT/lib"
-                                 CPPFLAGS="$CPPFLAGS -I$LIBPNG_ROOT/include"
-                                 AC_SEARCH_LIBS([png_warning],
-                                                [png],
-                                                [AC_DEFINE([HAVE_LIBLIBPNG],[1],[Define to 1 for PNG compression for GRIB2])],
-                                                [AC_MSG_ERROR([Could not link to libpng library! Required for GRIB_API])])
-                                 LIBPNG_LIBS=" -L$LIBPNG_ROOT/lib -lpng"],
-                                [AC_MSG_ERROR([$LIBPNG_ROOT is not a directory! LIBPNG suppressed])])])],
-            [AC_MSG_CHECKING([for the LIBPNG library])
-             AC_MSG_RESULT([suppressed])])
-AC_SUBST([LIBPNG_LIBS])
-#  ----------------------------------------------------------------------
 #  Compile application with GRIB_API library (for GRIB2 support)
 GRIB_API_INCLUDE=''
 GRIB_API_LIBS=''
diff --git a/libcdi/src/Makefile.am b/libcdi/src/Makefile.am
index bc78a1e..0bdb6c4 100644
--- a/libcdi/src/Makefile.am
+++ b/libcdi/src/Makefile.am
@@ -24,6 +24,8 @@ libcdi_la_SOURCES = 	 \
 	cdf.h	 	 \
 	cdf_int.c	 \
 	cdf_int.h	 \
+	cdf_util.c	 \
+	cdf_util.h	 \
 	cdi.h	 	 \
 	cdi_error.c      \
 	cdi_limits.h	 \
@@ -71,7 +73,8 @@ libcdi_la_SOURCES = 	 \
 	resource_handle.h\
 	service.h	 \
 	servicelib.c     \
-	stream_cdf.c     \
+	stream_cdf_i.c   \
+	stream_cdf_o.c   \
 	stream_cdf.h	 \
 	stream_cgribex.c \
 	stream_cgribex.h \
@@ -83,8 +86,6 @@ libcdi_la_SOURCES = 	 \
 	stream_history.c \
 	stream_ieg.c     \
 	stream_ieg.h	 \
-	stream_fcommon.c \
-	stream_fcommon.h \
 	cdi_int.c        \
 	cdi_int.h	 \
 	stream_record.c  \
@@ -95,6 +96,8 @@ libcdi_la_SOURCES = 	 \
         grb_read.c       \
         cdf_write.c      \
         cdf_read.c       \
+        cdf_lazy_grid.c  \
+        cdf_lazy_grid.h  \
         subtype.c        \
         subtype.h        \
 	swap.h	 	 \
@@ -112,8 +115,8 @@ libcdi_la_SOURCES = 	 \
 	version.c      	 \
 	vlist.c 	 \
 	vlist.h	         \
-	vlist_att.c 	 \
-	vlist_att.h 	 \
+	cdi_att.c 	 \
+	cdi_att.h 	 \
 	vlist_var.c 	 \
 	vlist_var.h	 \
 	zaxis.c		 \
diff --git a/libcdi/src/Makefile.in b/libcdi/src/Makefile.in
index ec0a5df..be115a8 100644
--- a/libcdi/src/Makefile.in
+++ b/libcdi/src/Makefile.in
@@ -168,26 +168,27 @@ LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 libcdi_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
 am__libcdi_la_SOURCES_DIST = basetime.c basetime.h binary.c binary.h \
-	calendar.c calendar.h cdf.c cdf.h cdf_int.c cdf_int.h cdi.h \
-	cdi_error.c cdi_limits.h cdi_util.c cgribex.h cgribexlib.c \
-	datetime.h dmemory.c dmemory.h cksum.c cksum.h cdi_cksum.c \
-	cdi_cksum.h cdi_uuid.h dtypes.h error.c error.h exse.h extra.h \
-	extralib.c file.c file.h gaussgrid.c gaussgrid.h gribapi.c \
-	gribapi.h gribapi_utilities.h grid.c grid.h ieg.h ieglib.c \
-	input_file.c input_file.h institution.c institution.h model.c \
-	model.h namespace.c namespace.h serialize.h serialize.c \
+	calendar.c calendar.h cdf.c cdf.h cdf_int.c cdf_int.h \
+	cdf_util.c cdf_util.h cdi.h cdi_error.c cdi_limits.h \
+	cdi_util.c cgribex.h cgribexlib.c datetime.h dmemory.c \
+	dmemory.h cksum.c cksum.h cdi_cksum.c cdi_cksum.h cdi_uuid.h \
+	dtypes.h error.c error.h exse.h extra.h extralib.c file.c \
+	file.h gaussgrid.c gaussgrid.h gribapi.c gribapi.h \
+	gribapi_utilities.h grid.c grid.h ieg.h ieglib.c input_file.c \
+	input_file.h institution.c institution.h model.c model.h \
+	namespace.c namespace.h serialize.h serialize.c \
 	referenceCounting.c referenceCounting.h resource_handle.c \
-	resource_handle.h service.h servicelib.c stream_cdf.c \
-	stream_cdf.h stream_cgribex.c stream_cgribex.h stream_ext.c \
-	stream_ext.h stream_grb.c stream_grb.h stream_gribapi.h \
-	stream_history.c stream_ieg.c stream_ieg.h stream_fcommon.c \
-	stream_fcommon.h cdi_int.c cdi_int.h stream_record.c \
-	stream_srv.c stream_srv.h stream_var.c grb_write.c grb_read.c \
-	cdf_write.c cdf_read.c subtype.c subtype.h swap.h table.c \
-	table.h tablepar.h taxis.c taxis.h timebase.c timebase.h \
-	tsteps.c util.c varscan.c varscan.h version.c vlist.c vlist.h \
-	vlist_att.c vlist_att.h vlist_var.c vlist_var.h zaxis.c \
-	zaxis.h stream.c stream_write.c stream_read.c swap.c \
+	resource_handle.h service.h servicelib.c stream_cdf_i.c \
+	stream_cdf_o.c stream_cdf.h stream_cgribex.c stream_cgribex.h \
+	stream_ext.c stream_ext.h stream_grb.c stream_grb.h \
+	stream_gribapi.h stream_history.c stream_ieg.c stream_ieg.h \
+	cdi_int.c cdi_int.h stream_record.c stream_srv.c stream_srv.h \
+	stream_var.c grb_write.c grb_read.c cdf_write.c cdf_read.c \
+	cdf_lazy_grid.c cdf_lazy_grid.h subtype.c subtype.h swap.h \
+	table.c table.h tablepar.h taxis.c taxis.h timebase.c \
+	timebase.h tsteps.c util.c varscan.c varscan.h version.c \
+	vlist.c vlist.h cdi_att.c cdi_att.h vlist_var.c vlist_var.h \
+	zaxis.c zaxis.h stream.c stream_write.c stream_read.c swap.c \
 	iterator.c iterator.h iterator_fallback.c iterator_fallback.h \
 	iterator_grib.c iterator_grib.h cfortran.h cdiFortran.c \
 	gribapi_utilities.c stream_gribapi.c
@@ -196,20 +197,20 @@ am__objects_1 = cdiFortran.lo
 am__objects_3 = gribapi_utilities.lo stream_gribapi.lo
 @HAVE_LIBGRIB_API_TRUE at am__objects_4 = $(am__objects_3)
 am_libcdi_la_OBJECTS = basetime.lo binary.lo calendar.lo cdf.lo \
-	cdf_int.lo cdi_error.lo cdi_util.lo cgribexlib.lo dmemory.lo \
-	cksum.lo cdi_cksum.lo error.lo extralib.lo file.lo \
+	cdf_int.lo cdf_util.lo cdi_error.lo cdi_util.lo cgribexlib.lo \
+	dmemory.lo cksum.lo cdi_cksum.lo error.lo extralib.lo file.lo \
 	gaussgrid.lo gribapi.lo grid.lo ieglib.lo input_file.lo \
 	institution.lo model.lo namespace.lo serialize.lo \
 	referenceCounting.lo resource_handle.lo servicelib.lo \
-	stream_cdf.lo stream_cgribex.lo stream_ext.lo stream_grb.lo \
-	stream_history.lo stream_ieg.lo stream_fcommon.lo cdi_int.lo \
-	stream_record.lo stream_srv.lo stream_var.lo grb_write.lo \
-	grb_read.lo cdf_write.lo cdf_read.lo subtype.lo table.lo \
-	taxis.lo timebase.lo tsteps.lo util.lo varscan.lo version.lo \
-	vlist.lo vlist_att.lo vlist_var.lo zaxis.lo stream.lo \
-	stream_write.lo stream_read.lo swap.lo iterator.lo \
-	iterator_fallback.lo iterator_grib.lo $(am__objects_2) \
-	$(am__objects_4)
+	stream_cdf_i.lo stream_cdf_o.lo stream_cgribex.lo \
+	stream_ext.lo stream_grb.lo stream_history.lo stream_ieg.lo \
+	cdi_int.lo stream_record.lo stream_srv.lo stream_var.lo \
+	grb_write.lo grb_read.lo cdf_write.lo cdf_read.lo \
+	cdf_lazy_grid.lo subtype.lo table.lo taxis.lo timebase.lo \
+	tsteps.lo util.lo varscan.lo version.lo vlist.lo cdi_att.lo \
+	vlist_var.lo zaxis.lo stream.lo stream_write.lo stream_read.lo \
+	swap.lo iterator.lo iterator_fallback.lo iterator_grib.lo \
+	$(am__objects_2) $(am__objects_4)
 libcdi_la_OBJECTS = $(am_libcdi_la_OBJECTS)
 AM_V_lt = $(am__v_lt_ at AM_V@)
 am__v_lt_ = $(am__v_lt_ at AM_DEFAULT_V@)
@@ -377,11 +378,9 @@ INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
 INSTALL_SCRIPT = @INSTALL_SCRIPT@
 INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-JASPER_LIBS = @JASPER_LIBS@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
 LIBOBJS = @LIBOBJS@
-LIBPNG_LIBS = @LIBPNG_LIBS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
@@ -405,7 +404,6 @@ NM = @NM@
 NMEDIT = @NMEDIT@
 OBJDUMP = @OBJDUMP@
 OBJEXT = @OBJEXT@
-OPENJPEG_LIBS = @OPENJPEG_LIBS@
 OTOOL = @OTOOL@
 OTOOL64 = @OTOOL64@
 PACKAGE = @PACKAGE@
@@ -487,7 +485,6 @@ localstatedir = @localstatedir@
 mandir = @mandir@
 mkdir_p = @mkdir_p@
 oldincludedir = @oldincludedir@
-openjpeg_LIBS = @openjpeg_LIBS@
 pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
@@ -511,29 +508,29 @@ noinst_LTLIBRARIES = libcdiresunpack.la $(am__append_1) \
 @ENABLE_CDI_LIB_TRUE at include_HEADERS = cdi.h cdi.inc $(am__append_5)
 AM_CFLAGS = $(PPM_CORE_CFLAGS) $(YAXT_CFLAGS) $(MPI_C_INCLUDE)
 libcdi_la_SOURCES = basetime.c basetime.h binary.c binary.h calendar.c \
-	calendar.h cdf.c cdf.h cdf_int.c cdf_int.h cdi.h cdi_error.c \
-	cdi_limits.h cdi_util.c cgribex.h cgribexlib.c datetime.h \
-	dmemory.c dmemory.h cksum.c cksum.h cdi_cksum.c cdi_cksum.h \
-	cdi_uuid.h dtypes.h error.c error.h exse.h extra.h extralib.c \
-	file.c file.h gaussgrid.c gaussgrid.h gribapi.c gribapi.h \
-	gribapi_utilities.h grid.c grid.h ieg.h ieglib.c input_file.c \
-	input_file.h institution.c institution.h model.c model.h \
-	namespace.c namespace.h serialize.h serialize.c \
-	referenceCounting.c referenceCounting.h resource_handle.c \
-	resource_handle.h service.h servicelib.c stream_cdf.c \
+	calendar.h cdf.c cdf.h cdf_int.c cdf_int.h cdf_util.c \
+	cdf_util.h cdi.h cdi_error.c cdi_limits.h cdi_util.c cgribex.h \
+	cgribexlib.c datetime.h dmemory.c dmemory.h cksum.c cksum.h \
+	cdi_cksum.c cdi_cksum.h cdi_uuid.h dtypes.h error.c error.h \
+	exse.h extra.h extralib.c file.c file.h gaussgrid.c \
+	gaussgrid.h gribapi.c gribapi.h gribapi_utilities.h grid.c \
+	grid.h ieg.h ieglib.c input_file.c input_file.h institution.c \
+	institution.h model.c model.h namespace.c namespace.h \
+	serialize.h serialize.c referenceCounting.c \
+	referenceCounting.h resource_handle.c resource_handle.h \
+	service.h servicelib.c stream_cdf_i.c stream_cdf_o.c \
 	stream_cdf.h stream_cgribex.c stream_cgribex.h stream_ext.c \
 	stream_ext.h stream_grb.c stream_grb.h stream_gribapi.h \
-	stream_history.c stream_ieg.c stream_ieg.h stream_fcommon.c \
-	stream_fcommon.h cdi_int.c cdi_int.h stream_record.c \
-	stream_srv.c stream_srv.h stream_var.c grb_write.c grb_read.c \
-	cdf_write.c cdf_read.c subtype.c subtype.h swap.h table.c \
-	table.h tablepar.h taxis.c taxis.h timebase.c timebase.h \
-	tsteps.c util.c varscan.c varscan.h version.c vlist.c vlist.h \
-	vlist_att.c vlist_att.h vlist_var.c vlist_var.h zaxis.c \
-	zaxis.h stream.c stream_write.c stream_read.c swap.c \
-	iterator.c iterator.h iterator_fallback.c iterator_fallback.h \
-	iterator_grib.c iterator_grib.h $(am__append_2) \
-	$(am__append_3)
+	stream_history.c stream_ieg.c stream_ieg.h cdi_int.c cdi_int.h \
+	stream_record.c stream_srv.c stream_srv.h stream_var.c \
+	grb_write.c grb_read.c cdf_write.c cdf_read.c cdf_lazy_grid.c \
+	cdf_lazy_grid.h subtype.c subtype.h swap.h table.c table.h \
+	tablepar.h taxis.c taxis.h timebase.c timebase.h tsteps.c \
+	util.c varscan.c varscan.h version.c vlist.c vlist.h cdi_att.c \
+	cdi_att.h vlist_var.c vlist_var.h zaxis.c zaxis.h stream.c \
+	stream_write.c stream_read.c swap.c iterator.c iterator.h \
+	iterator_fallback.c iterator_fallback.h iterator_grib.c \
+	iterator_grib.h $(am__append_2) $(am__append_3)
 
 # cfortran.h is an optional part of libcdi
 libcdi_la_USE_FC_extra_sources = \
@@ -692,9 +689,12 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/calendar.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdf.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdf_int.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdf_lazy_grid.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdf_read.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdf_util.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdf_write.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdiFortran.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdi_att.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdi_cksum.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdi_error.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdi_int.Plo at am__quote@
@@ -747,10 +747,10 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/serialize.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/servicelib.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stream.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stream_cdf.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stream_cdf_i.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stream_cdf_o.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stream_cgribex.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stream_ext.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stream_fcommon.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stream_grb.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stream_gribapi.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/stream_history.Plo at am__quote@
@@ -770,7 +770,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/varscan.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/version.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/vlist.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/vlist_att.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/vlist_var.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/zaxis.Plo at am__quote@
 
@@ -942,8 +941,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@install-exec-local:
 @ENABLE_CDI_LIB_FALSE at uninstall-local:
+ at ENABLE_CDI_LIB_FALSE@install-exec-local:
 clean: clean-am
 
 clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
diff --git a/libcdi/src/basetime.c b/libcdi/src/basetime.c
index 3d4d5e3..2efc45d 100644
--- a/libcdi/src/basetime.c
+++ b/libcdi/src/basetime.c
@@ -3,24 +3,23 @@
 #endif
 
 #include <stdio.h>
+#include <stdbool.h>
 
 #include "error.h"
 #include "cdi.h"
 #include "basetime.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;
 }
 /*
diff --git a/libcdi/src/basetime.h b/libcdi/src/basetime.h
index 8a56f5a..a5a9631 100644
--- a/libcdi/src/basetime.h
+++ b/libcdi/src/basetime.h
@@ -1,6 +1,8 @@
 #ifndef _BASETIME_H
 #define _BASETIME_H
 
+#include <stdbool.h>
+
 //#define USE_TIMECACHE 1
 #define MAX_TIMECACHE_SIZE 1024
 
@@ -17,7 +19,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;
diff --git a/libcdi/src/cdf.c b/libcdi/src/cdf.c
index 6fb0a85..b7ed6c3 100644
--- a/libcdi/src/cdf.c
+++ b/libcdi/src/cdf.c
@@ -114,22 +114,22 @@ static int cdfOpenFile(const char *filename, const char *mode, int *filetype)
 	      (void) nc_inq_format(ncid, &format);
 	      if ( format == NC_FORMAT_NETCDF4_CLASSIC )
 		{
-		  *filetype = FILETYPE_NC4C;
+		  *filetype = CDI_FILETYPE_NC4C;
 		}
 	    }
 #endif
 	  break;
 	case 'w':
 #if  defined  (NC_64BIT_OFFSET)
-	  if      ( *filetype == FILETYPE_NC2  ) writemode |= 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;
+	  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);
@@ -146,7 +146,7 @@ static int cdfOpenFile(const char *filename, const char *mode, int *filetype)
 
 int cdfOpen(const char *filename, const char *mode)
 {
-  int filetype = FILETYPE_NC;
+  int filetype = CDI_FILETYPE_NC;
 
   if ( CDF_Debug )
     Message("Open %s with mode %c", filename, *mode);
@@ -164,7 +164,7 @@ int cdfOpen64(const char *filename, const char *mode)
 {
   int fileID = -1;
   int open_file = TRUE;
-  int filetype = FILETYPE_NC2;
+  int filetype = CDI_FILETYPE_NC2;
 
   if ( CDF_Debug )
     Message("Open %s with mode %c", filename, *mode);
diff --git a/libcdi/src/cdf_int.c b/libcdi/src/cdf_int.c
index e9d1fbb..65f83e8 100644
--- a/libcdi/src/cdf_int.c
+++ b/libcdi/src/cdf_int.c
@@ -690,6 +690,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;
diff --git a/libcdi/src/cdf_int.h b/libcdi/src/cdf_int.h
index 223091e..91de788 100644
--- a/libcdi/src/cdf_int.h
+++ b/libcdi/src/cdf_int.h
@@ -76,6 +76,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);
diff --git a/libcdi/src/cdf_lazy_grid.c b/libcdi/src/cdf_lazy_grid.c
new file mode 100644
index 0000000..37bdabd
--- /dev/null
+++ b/libcdi/src/cdf_lazy_grid.c
@@ -0,0 +1,535 @@
+#if defined (HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#include "stream_cdf.h"
+#include "cdf_lazy_grid.h"
+
+
+static struct gridVirtTable cdfLazyGridVtable;
+double *cdfPendingLoad;
+#ifdef HAVE_LIBPTHREAD
+static pthread_once_t cdfLazyInitialized = PTHREAD_ONCE_INIT;
+#else
+static bool cdfLazyInitialized;
+#endif
+
+
+#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
+
+
+#ifdef HAVE_LIBNETCDF
+
+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 cdfLazyGridDelete(grid_t *grid)
+{
+  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
+  void (*baseDestroy)(grid_t *grid) = cdfGrid->baseVtable->destroy;
+  cdfLazyGridDestroy(cdfGrid);
+  baseDestroy(grid);
+}
+
+static void cdfLazyGridDestroyOnce(void)
+{
+  /*
+#ifdef HAVE_MMAP
+  size_t pgSize = cdiGetPageSize(false);
+  munmap(cdfPendingLoad, pgSize);
+#endif
+  */
+}
+
+static void
+cdfLazyGridDefArea(grid_t *grid, const double *area)
+{
+  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);
+}
+
+
+static const double *
+cdfLazyGridInqAreaPtr(grid_t *grid)
+{
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lock_lazy_load(lazyGrid);
+  if (grid->area == cdfPendingLoad)
+    {
+      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);
+}
+
+static void
+cdfLazyGridInqArea(grid_t *grid, double *area)
+{
+  grid->vtable->inqAreaPtr(grid);
+  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
+  lazyGrid->baseVtable->inqArea(grid, area);
+}
+
+
+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);
+}
+
+static const double *
+cdfLazyGridInqXValsPtr(grid_t *grid)
+{
+  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 const double *
+cdfLazyGridInqYValsPtr(grid_t *grid)
+{
+  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);
+}
+
+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 )
+    {
+      /* prevent full load if only first/last values get inspected */
+      if ( index == 0 || index == size - 1 )
+        {
+          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
+        {
+          const double *grid_vals = inqValsPtr(grid);
+          v = grid_vals[index];
+        }
+    }
+  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->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);
+}
+
+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->x.vals, 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->y.vals, grid->vtable->inqYValsPtr);
+  unlock_lazy_load(lazyGrid);
+  return rv;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+
+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);
+}
+
+static void
+cdfLazyGridDefXBounds(grid_t *grid, const double *xbounds)
+{
+  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);
+}
+
+static void
+cdfLazyGridDefYBounds(grid_t *grid, const double *ybounds)
+{
+  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);
+}
+
+static const double *
+cdfLazyGridInqYBoundsPtr(grid_t *grid)
+{
+  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);
+}
+
+static void
+cdfLazyGridCopyScalarFields(grid_t *gridptrOrig, grid_t *gridptrDup)
+{
+  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);
+}
+
+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 ( gridptrOrig->x.vals != NULL && gridptrOrig->x.vals != cdfPendingLoad )
+    {
+      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->x.size;
+
+      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;
+
+      gridptrDup->y.vals = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->y.vals, gridptrOrig->y.vals, size * sizeof (double));
+    }
+
+  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));
+    }
+
+  if ( gridptrOrig->y.bounds != NULL && gridptrOrig->y.bounds != cdfPendingLoad )
+    {
+      size_t size = (irregular ? gridsize : (size_t)gridptrOrig->y.size)
+        * (size_t)gridptrOrig->nvertex;
+
+      gridptrDup->y.bounds = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->y.bounds, gridptrOrig->y.bounds, size * sizeof (double));
+    }
+
+  {
+    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));
+      }
+  }
+
+  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));
+    }
+
+  if ( gridptrOrig->mask_gme != NULL )
+    {
+      size_t size = gridsize;
+
+      gridptrDup->mask_gme = (mask_t *)Malloc(size * sizeof (mask_t));
+      memcpy(gridptrDup->mask_gme, gridptrOrig->mask_gme, size * sizeof(mask_t));
+    }
+}
+
+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;
+}
+
+static void
+cdfLazyGridInitOnce(void)
+{
+  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
+}
+
+static void
+cdfBaseGridInit(grid_t *grid, int gridtype)
+{
+  grid_init(grid);
+  cdiGridTypeInit(grid, gridtype, 0);
+}
+
+static void
+cdfLazyGridInit(struct cdfLazyGrid *grid, int gridtype)
+{
+#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);
+}
+
+
+void cdfLazyGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype)
+{
+  struct cdfLazyGrid *restrict grid = *gridpptr;
+  if (!grid)
+    *gridpptr = grid = (struct cdfLazyGrid *)Malloc(sizeof (*grid));
+  cdfLazyGridInit(grid, gridtype);
+}
+
+
+void cdfBaseGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype)
+{
+  struct cdfLazyGrid *restrict grid = *gridpptr;
+  if (!grid)
+    *gridpptr = grid = (struct cdfLazyGrid *)Malloc(sizeof (grid_t));
+  cdfBaseGridInit((grid_t*)grid, 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:
+ */
diff --git a/libcdi/src/cdf_lazy_grid.h b/libcdi/src/cdf_lazy_grid.h
new file mode 100644
index 0000000..3da5ca0
--- /dev/null
+++ b/libcdi/src/cdf_lazy_grid.h
@@ -0,0 +1,60 @@
+#ifndef  CDF_LAZY_GRID_H_
+#define  CDF_LAZY_GRID_H_
+
+#if defined (HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#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>
+#endif
+
+#include <string.h>
+
+#include "dmemory.h"
+#include "cdf_int.h"
+#include "grid.h"
+
+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
+};
+
+
+extern double *cdfPendingLoad;
+
+void cdfLazyGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype);
+void cdfBaseGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype);
+
+void cdfLazyGridDestroy(struct cdfLazyGrid *lazyGrid);
+
+#endif
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
diff --git a/libcdi/src/cdf_read.c b/libcdi/src/cdf_read.c
index 3445640..ba33aad 100644
--- a/libcdi/src/cdf_read.c
+++ b/libcdi/src/cdf_read.c
@@ -16,10 +16,6 @@
 #include "vlist.h"
 
 
-#undef  UNDEFID
-#define UNDEFID  CDI_UNDEFID
-
-
 static
 void cdfReadGridTraj(stream_t *streamptr, int gridID)
 {
@@ -27,8 +23,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].xdimID;
+  int latID = streamptr->ncgrid[gridindex].ydimID;
 
   int tsID = streamptr->curTsID;
   size_t index = (size_t)tsID;
@@ -53,15 +49,15 @@ void cdfGetSlapDescription(stream_t *streamptr, int varID, size_t (*start)[4], s
 
   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].xdimID;
+      yid = streamptr->ncgrid[gridindex].ydimID;
     }
   int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
   int zid = streamptr->zaxisID[zaxisindex];
@@ -74,9 +70,9 @@ void cdfGetSlapDescription(stream_t *streamptr, int varID, size_t (*start)[4], s
       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 ( 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));
 #undef addDimension
 
   assert(ndims <= (int)(sizeof(*start)/sizeof(**start)));
@@ -314,18 +310,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]);
 }
@@ -355,18 +345,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);
 }
@@ -377,7 +361,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:
@@ -385,12 +369,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].xdimID;
         break;
 
       default:
-        (*outDimIds)[0] = streamptr->xdimID[gridindex];
-        (*outDimIds)[1] = streamptr->ydimID[gridindex];
+        (*outDimIds)[0] = streamptr->ncgrid[gridindex].xdimID;
+        (*outDimIds)[1] = streamptr->ncgrid[gridindex].ydimID;
         break;
     }
 
@@ -402,8 +386,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;
@@ -448,7 +432,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;
 
@@ -465,7 +449,7 @@ void cdfGetSliceSlapDescription(stream_t *streamptr, int varId, int levelId, boo
     {
       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");
@@ -594,7 +578,7 @@ void cdfReadVarSliceDP(stream_t *streamptr, int varID, int levelID, double *data
   size_t xsize = (size_t)gridInqXsize(gridId);
   size_t ysize = (size_t)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);
@@ -606,7 +590,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);
@@ -651,7 +635,7 @@ void cdfReadVarSliceSP(stream_t *streamptr, int varID, int levelID, float *data,
   size_t xsize = (size_t)gridInqXsize(gridId);
   size_t ysize = (size_t)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);
@@ -663,7 +647,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);
diff --git a/libcdi/src/cdf_util.c b/libcdi/src/cdf_util.c
new file mode 100644
index 0000000..5ed8afa
--- /dev/null
+++ b/libcdi/src/cdf_util.c
@@ -0,0 +1,335 @@
+#include <string.h>
+#include <ctype.h>
+#include "dmemory.h"
+#include "cdi.h"
+#include "cdf_util.h"
+#include "error.h"
+
+
+void str_tolower(char *str)
+{
+  if ( str )
+    for ( size_t i = 0; str[i]; ++i )
+      str[i] = (char)tolower((int)str[i]);
+}
+
+bool str_is_equal(const char *vstr, const char *cstr)
+{
+  bool is_equal = false;
+  size_t clen = (cstr != NULL) ? strlen(cstr) : 0;
+
+  if ( vstr && *vstr ) is_equal = (memcmp(vstr, cstr, clen) == 0);
+
+  return is_equal;
+}
+
+int get_timeunit(size_t len, const char *ptu)
+{
+  int timeunit = -1;
+
+  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 )
+    {
+      if ( ptu[0] == 's' ) timeunit = TUNIT_SECOND;
+    }
+
+  return timeunit;
+}
+
+
+bool is_time_units(const char *timeunits)
+{
+  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;
+}
+
+
+bool is_timeaxis_units(const char *timeunits)
+{
+  bool status = false;
+
+  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;
+}
+
+
+bool is_height_units(const char *units)
+{
+  bool status = false;
+  int u0 = units[0];
+
+  if ( (u0=='m' && (!units[1] || strncmp(units, "meter", 5) == 0)) ||
+       (!units[2] && units[1]=='m' && (u0=='c' || u0=='d' || u0=='k')) )
+    {
+      status = true;
+    }
+
+  return status;
+}
+
+
+bool is_pressure_units(const char *units)
+{
+  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;
+}
+
+
+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;
+}
+
+
+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;
+    }
+
+  if ( status == false && 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;
+    }
+
+  if ( status == false && 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, "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") ||
+       str_is_equal(attstring, "gregorian") )
+    *calendar = CALENDAR_STANDARD;
+  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);
+}
diff --git a/libcdi/src/cdf_util.h b/libcdi/src/cdf_util.h
new file mode 100644
index 0000000..5756423
--- /dev/null
+++ b/libcdi/src/cdf_util.h
@@ -0,0 +1,30 @@
+#ifndef  CDF_UTIL_H_
+#define  CDF_UTIL_H_
+
+#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);
+
+#endif
diff --git a/libcdi/src/cdf_write.c b/libcdi/src/cdf_write.c
index 942f0c7..8d94bff 100644
--- a/libcdi/src/cdf_write.c
+++ b/libcdi/src/cdf_write.c
@@ -13,13 +13,9 @@
 #include "vlist.h"
 
 
-#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;
@@ -27,56 +23,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;
@@ -85,7 +80,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;
@@ -103,7 +98,7 @@ void cdfDefVarMissval(stream_t *streamptr, int varID, int dtype, int lcheck)
 
       if ( lcheck && streamptr->ncmode == 2 ) cdf_enddef(fileID);
 
-      streamptr->vars[varID].defmiss = TRUE;
+      streamptr->vars[varID].defmiss = true;
     }
 }
 
@@ -114,7 +109,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 )
@@ -137,7 +132,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 )
@@ -156,7 +151,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;
@@ -164,8 +159,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;
@@ -174,37 +169,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];
@@ -214,7 +219,7 @@ void cdfDefineAttributes(int vlistID, int varID, int fileID, int ncvarID)
             cdf_put_att_double(fileID, ncvarID, attname, NC_DOUBLE, len, attflt);
         }
     }
-  
+
   Free(attBuf);
 }
 
@@ -230,7 +235,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);
 
@@ -248,7 +253,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;
 
@@ -257,7 +262,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);
@@ -273,14 +278,48 @@ 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;
@@ -295,7 +334,7 @@ int cdfDefVar(stream_t *streamptr, int varID)
   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;
@@ -312,25 +351,25 @@ int cdfDefVar(stream_t *streamptr, int varID)
   vlistInqVarDimorder(vlistID, varID, &dimorder);
 
   int gridsize  = gridInqSize(gridID);
-  if ( gridsize > 1 ) lchunk = TRUE;
+  bool lchunk = (gridsize > 1);
   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].xdimID;
+      yid = streamptr->ncgrid[gridindex].ydimID;
+      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!");
@@ -340,41 +379,41 @@ int cdfDefVar(stream_t *streamptr, int varID)
 
   if ( tsteptype != TSTEP_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;
   */
   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 )
+          if ( chunktype == CDI_CHUNK_LINES )
             chunks[ndims] = 1;
           else
             chunks[ndims] = ysize;
           dims[ndims] = yid;
           ndims++;
         }
-      else if ( dimorder[id] == 1 && xid != UNDEFID )
+      else if ( dimorder[id] == 1 && xid != CDI_UNDEFID )
         {
           chunks[ndims] = xsize;
           dims[ndims] = xid;
@@ -397,24 +436,17 @@ int cdfDefVar(stream_t *streamptr, int varID)
   if ( units    == NULL )    units = tableInqParUnitsPtr(tableID, code);
   if ( name )
     {
-      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++;
 
@@ -443,7 +475,7 @@ int cdfDefVar(stream_t *streamptr, int varID)
 
       char *varname2 = varname+strlen(varname);
 
-      int checkname = TRUE;
+      bool checkname = true;
       int iz = 0;
 
       while ( checkname )
@@ -451,7 +483,7 @@ 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++;
 
@@ -471,9 +503,9 @@ 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 ( lchunk && (streamptr->filetype == CDI_FILETYPE_NC4 || streamptr->filetype == CDI_FILETYPE_NC4C) )
     {
-      if ( chunktype == CHUNK_AUTO )
+      if ( chunktype == CDI_CHUNK_AUTO )
         retval = nc_def_var_chunking(fileID, ncvarid, NC_CHUNKED, NULL);
       else
         retval = nc_def_var_chunking(fileID, ncvarid, NC_CHUNKED, chunks);
@@ -482,9 +514,9 @@ int cdfDefVar(stream_t *streamptr, int varID)
     }
 #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);
         }
@@ -492,45 +524,16 @@ 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);
 
@@ -550,15 +553,14 @@ 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 )
     {
@@ -571,42 +573,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 )
     {
       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" );
     }
-  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].xvarID;
+      int ncyvarID = streamptr->ncgrid[gridindex].yvarID;
       if ( ncyvarID != CDI_UNDEFID )
         {
           size_t len = strlen(coordinates);
@@ -623,9 +611,9 @@ 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];
+      int ncxvarID = streamptr->ncgrid[gridindex].xvarID;
+      int ncyvarID = streamptr->ncgrid[gridindex].yvarID;
+      int ncavarID = streamptr->ncgrid[gridindex].avarID;
       if ( ncyvarID != CDI_UNDEFID )
         {
           size_t len = strlen(coordinates);
@@ -692,7 +680,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);
@@ -731,14 +719,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 */
@@ -779,25 +759,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].xdimID;
+  int latID = streamptr->ncgrid[gridindex].ydimID;
 
   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, int nmiss)
 {
   const double *pdata_dp = (const double *) data;
   double *mdata_dp = NULL;
@@ -806,7 +784,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);
@@ -874,8 +852,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 )
             {
@@ -888,7 +866,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);
@@ -910,7 +888,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);
@@ -925,9 +903,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) )
@@ -941,7 +918,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 )
@@ -982,7 +959,7 @@ 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;
+  bool swapxy = false;
   int ndims = 0;
   int idim;
 
@@ -1002,16 +979,16 @@ void cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data
   int zaxisID   = vlistInqVarZaxis(vlistID, varID);
   int tsteptype = vlistInqVarTsteptype(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].xdimID;
+      yid = streamptr->ncgrid[gridindex].ydimID;
     }
 
   int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
@@ -1024,14 +1001,14 @@ void cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data
       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);
@@ -1040,7 +1017,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);
@@ -1074,11 +1051,11 @@ void cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
 {
   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;
+  bool swapxy = false;
   int ndims = 0;
   int idim;
   int streamID = streamptr->self;
@@ -1107,9 +1084,9 @@ 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].xdimID;
+      yid = streamptr->ncgrid[gridindex].ydimID;
     }
 
   int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
@@ -1121,7 +1098,7 @@ void cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
       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]
@@ -1130,7 +1107,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);
@@ -1140,7 +1117,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);
@@ -1180,7 +1157,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);
 
@@ -1205,15 +1182,15 @@ 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].xdimID;
+      yid = streamptr->ncgrid[gridindex].ydimID;
     }
 
   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 )
@@ -1225,20 +1202,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);
@@ -1270,3 +1247,13 @@ 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:
+ */
diff --git a/libcdi/src/cdi.h b/libcdi/src/cdi.h
index 69b253d..c9cc8cb 100644
--- a/libcdi/src/cdi.h
+++ b/libcdi/src/cdi.h
@@ -15,102 +15,126 @@ 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_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
 
 /* 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)
+#define  CDI_FILETYPE_NC4           5   // File type NetCDF version 4
+#define  CDI_FILETYPE_NC4C          6   // File type NetCDF version 4 (classic)
+#define  CDI_FILETYPE_SRV           7   // File type SERVICE
+#define  CDI_FILETYPE_EXT           8   // File type EXTRA
+#define  CDI_FILETYPE_IEG           9   // 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
@@ -120,9 +144,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 */
 
@@ -137,10 +161,12 @@ 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  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 */
 
@@ -355,9 +381,9 @@ const char *streamFilesuffix(int filetype);
 
 off_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);
@@ -378,7 +404,7 @@ void    streamReadVarSliceF(int streamID, int varID, int levelID, float data[],
 void    streamWriteVarChunk(int streamID, int varID, const int rect[3][2], const double data[], int 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);
@@ -673,27 +699,29 @@ const char *vlistInqVarNamePtr(int vlistID, int varID);
 const char *vlistInqVarLongnamePtr(int vlistID, int varID);
 const char *vlistInqVarUnitsPtr(int vlistID, int varID);
 
-/* VLIST attributes */
+/* CDI attributes */
 
-/*      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);
+/*      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);
 
-/*      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);
+int     cdiCopyAtts(int cdiID1, int varID1, int cdiID2, int varID2);
 
-/*      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);
+/*      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);
+
+/*      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 */
@@ -709,7 +737,7 @@ 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);
@@ -720,6 +748,15 @@ 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);
 
@@ -757,21 +794,38 @@ void    gridDefYvals(int gridID, const double yvals[]);
 int     gridInqYvals(int gridID, double yvals[]);
 
 /* 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);
@@ -831,24 +885,9 @@ 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 */
 
@@ -884,18 +923,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);
-
-/* 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);
+/* 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 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 originLon, double originLat, double lonParY, double lat1, double lat2, double xinc, double yinc, int projflag, int scanflag);
+void    gridInqParamLCC(int gridID, double *originLon, double *originLat, double *lonParY, double *lat1, double *lat2, double *xinc, double *yinc, int *projflag, int *scanflag);
 
 void    gridDefArea(int gridID, const double area[]);
 void    gridInqArea(int gridID, double area[]);
@@ -929,6 +967,7 @@ int     gridInqComplexPacking(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);
@@ -945,15 +984,13 @@ 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[]);
 
 /*      zaxisInqLevels: Get all levels of a Z-axis */
-void    zaxisInqLevels(int zaxisID, double levels[]);
+int     zaxisInqLevels(int zaxisID, double levels[]);
 
 /*      zaxisDefLevel: Define one level of a Z-axis */
 void    zaxisDefLevel(int zaxisID, int levelID, double levels);
@@ -979,18 +1016,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);
@@ -1013,12 +1043,6 @@ 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);
 
@@ -1031,7 +1055,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);
diff --git a/libcdi/src/cdi.inc b/libcdi/src/cdi.inc
index 333e1e2..103b388 100644
--- a/libcdi/src/cdi.inc
+++ b/libcdi/src/cdi.inc
@@ -1,10 +1,10 @@
 ! This file was automatically generated, don't edit!
 !
-! Fortran interface for CDI library version 1.7.2
+! Fortran interface for CDI library version 1.8.0
 !
 ! Author:
 ! -------
-! Uwe Schulzweida, MPI-MET, Hamburg,   April 2016
+! Uwe Schulzweida, MPI-MET, Hamburg,   February 2017
 !
 
       INTEGER    CDI_MAX_NAME          
@@ -52,8 +52,24 @@
 !
 !  File types
 !
-      INTEGER    FILETYPE_UNDEF        
-      PARAMETER (FILETYPE_UNDEF         = -1)
+      INTEGER    CDI_FILETYPE_GRB      
+      PARAMETER (CDI_FILETYPE_GRB       =  1)
+      INTEGER    CDI_FILETYPE_GRB2     
+      PARAMETER (CDI_FILETYPE_GRB2      =  2)
+      INTEGER    CDI_FILETYPE_NC       
+      PARAMETER (CDI_FILETYPE_NC        =  3)
+      INTEGER    CDI_FILETYPE_NC2      
+      PARAMETER (CDI_FILETYPE_NC2       =  4)
+      INTEGER    CDI_FILETYPE_NC4      
+      PARAMETER (CDI_FILETYPE_NC4       =  5)
+      INTEGER    CDI_FILETYPE_NC4C     
+      PARAMETER (CDI_FILETYPE_NC4C      =  6)
+      INTEGER    CDI_FILETYPE_SRV      
+      PARAMETER (CDI_FILETYPE_SRV       =  7)
+      INTEGER    CDI_FILETYPE_EXT      
+      PARAMETER (CDI_FILETYPE_EXT       =  8)
+      INTEGER    CDI_FILETYPE_IEG      
+      PARAMETER (CDI_FILETYPE_IEG       =  9)
       INTEGER    FILETYPE_GRB          
       PARAMETER (FILETYPE_GRB           =  1)
       INTEGER    FILETYPE_GRB2         
@@ -75,110 +91,136 @@
 !
 !  Compress types
 !
-      INTEGER    COMPRESS_NONE         
-      PARAMETER (COMPRESS_NONE          =  0)
-      INTEGER    COMPRESS_SZIP         
-      PARAMETER (COMPRESS_SZIP          =  1)
-      INTEGER    COMPRESS_GZIP         
-      PARAMETER (COMPRESS_GZIP          =  2)
-      INTEGER    COMPRESS_BZIP2        
-      PARAMETER (COMPRESS_BZIP2         =  3)
-      INTEGER    COMPRESS_ZIP          
-      PARAMETER (COMPRESS_ZIP           =  4)
-      INTEGER    COMPRESS_JPEG         
-      PARAMETER (COMPRESS_JPEG          =  5)
+      INTEGER    CDI_COMPRESS_NONE     
+      PARAMETER (CDI_COMPRESS_NONE      =  0)
+      INTEGER    CDI_COMPRESS_SZIP     
+      PARAMETER (CDI_COMPRESS_SZIP      =  1)
+      INTEGER    CDI_COMPRESS_GZIP     
+      PARAMETER (CDI_COMPRESS_GZIP      =  2)
+      INTEGER    CDI_COMPRESS_BZIP2    
+      PARAMETER (CDI_COMPRESS_BZIP2     =  3)
+      INTEGER    CDI_COMPRESS_ZIP      
+      PARAMETER (CDI_COMPRESS_ZIP       =  4)
+      INTEGER    CDI_COMPRESS_JPEG     
+      PARAMETER (CDI_COMPRESS_JPEG      =  5)
 !
 !  external data types
 !
+      INTEGER    CDI_DATATYPE_PACK     
+      PARAMETER (CDI_DATATYPE_PACK      =  0)
+      INTEGER    CDI_DATATYPE_PACK1    
+      PARAMETER (CDI_DATATYPE_PACK1     =  1)
+      INTEGER    CDI_DATATYPE_PACK2    
+      PARAMETER (CDI_DATATYPE_PACK2     =  2)
+      INTEGER    CDI_DATATYPE_PACK3    
+      PARAMETER (CDI_DATATYPE_PACK3     =  3)
+      INTEGER    CDI_DATATYPE_PACK4    
+      PARAMETER (CDI_DATATYPE_PACK4     =  4)
+      INTEGER    CDI_DATATYPE_PACK5    
+      PARAMETER (CDI_DATATYPE_PACK5     =  5)
+      INTEGER    CDI_DATATYPE_PACK6    
+      PARAMETER (CDI_DATATYPE_PACK6     =  6)
+      INTEGER    CDI_DATATYPE_PACK7    
+      PARAMETER (CDI_DATATYPE_PACK7     =  7)
+      INTEGER    CDI_DATATYPE_PACK8    
+      PARAMETER (CDI_DATATYPE_PACK8     =  8)
+      INTEGER    CDI_DATATYPE_PACK9    
+      PARAMETER (CDI_DATATYPE_PACK9     =  9)
+      INTEGER    CDI_DATATYPE_PACK10   
+      PARAMETER (CDI_DATATYPE_PACK10    = 10)
+      INTEGER    CDI_DATATYPE_PACK11   
+      PARAMETER (CDI_DATATYPE_PACK11    = 11)
+      INTEGER    CDI_DATATYPE_PACK12   
+      PARAMETER (CDI_DATATYPE_PACK12    = 12)
+      INTEGER    CDI_DATATYPE_PACK13   
+      PARAMETER (CDI_DATATYPE_PACK13    = 13)
+      INTEGER    CDI_DATATYPE_PACK14   
+      PARAMETER (CDI_DATATYPE_PACK14    = 14)
+      INTEGER    CDI_DATATYPE_PACK15   
+      PARAMETER (CDI_DATATYPE_PACK15    = 15)
+      INTEGER    CDI_DATATYPE_PACK16   
+      PARAMETER (CDI_DATATYPE_PACK16    = 16)
+      INTEGER    CDI_DATATYPE_PACK17   
+      PARAMETER (CDI_DATATYPE_PACK17    = 17)
+      INTEGER    CDI_DATATYPE_PACK18   
+      PARAMETER (CDI_DATATYPE_PACK18    = 18)
+      INTEGER    CDI_DATATYPE_PACK19   
+      PARAMETER (CDI_DATATYPE_PACK19    = 19)
+      INTEGER    CDI_DATATYPE_PACK20   
+      PARAMETER (CDI_DATATYPE_PACK20    = 20)
+      INTEGER    CDI_DATATYPE_PACK21   
+      PARAMETER (CDI_DATATYPE_PACK21    = 21)
+      INTEGER    CDI_DATATYPE_PACK22   
+      PARAMETER (CDI_DATATYPE_PACK22    = 22)
+      INTEGER    CDI_DATATYPE_PACK23   
+      PARAMETER (CDI_DATATYPE_PACK23    = 23)
+      INTEGER    CDI_DATATYPE_PACK24   
+      PARAMETER (CDI_DATATYPE_PACK24    = 24)
+      INTEGER    CDI_DATATYPE_PACK25   
+      PARAMETER (CDI_DATATYPE_PACK25    = 25)
+      INTEGER    CDI_DATATYPE_PACK26   
+      PARAMETER (CDI_DATATYPE_PACK26    = 26)
+      INTEGER    CDI_DATATYPE_PACK27   
+      PARAMETER (CDI_DATATYPE_PACK27    = 27)
+      INTEGER    CDI_DATATYPE_PACK28   
+      PARAMETER (CDI_DATATYPE_PACK28    = 28)
+      INTEGER    CDI_DATATYPE_PACK29   
+      PARAMETER (CDI_DATATYPE_PACK29    = 29)
+      INTEGER    CDI_DATATYPE_PACK30   
+      PARAMETER (CDI_DATATYPE_PACK30    = 30)
+      INTEGER    CDI_DATATYPE_PACK31   
+      PARAMETER (CDI_DATATYPE_PACK31    = 31)
+      INTEGER    CDI_DATATYPE_PACK32   
+      PARAMETER (CDI_DATATYPE_PACK32    = 32)
+      INTEGER    CDI_DATATYPE_CPX32    
+      PARAMETER (CDI_DATATYPE_CPX32     = 64)
+      INTEGER    CDI_DATATYPE_CPX64    
+      PARAMETER (CDI_DATATYPE_CPX64     = 128)
+      INTEGER    CDI_DATATYPE_FLT32    
+      PARAMETER (CDI_DATATYPE_FLT32     = 132)
+      INTEGER    CDI_DATATYPE_FLT64    
+      PARAMETER (CDI_DATATYPE_FLT64     = 164)
+      INTEGER    CDI_DATATYPE_INT8     
+      PARAMETER (CDI_DATATYPE_INT8      = 208)
+      INTEGER    CDI_DATATYPE_INT16    
+      PARAMETER (CDI_DATATYPE_INT16     = 216)
+      INTEGER    CDI_DATATYPE_INT32    
+      PARAMETER (CDI_DATATYPE_INT32     = 232)
+      INTEGER    CDI_DATATYPE_UINT8    
+      PARAMETER (CDI_DATATYPE_UINT8     = 308)
+      INTEGER    CDI_DATATYPE_UINT16   
+      PARAMETER (CDI_DATATYPE_UINT16    = 316)
+      INTEGER    CDI_DATATYPE_UINT32   
+      PARAMETER (CDI_DATATYPE_UINT32    = 332)
       INTEGER    DATATYPE_PACK         
       PARAMETER (DATATYPE_PACK          =  0)
-      INTEGER    DATATYPE_PACK1        
-      PARAMETER (DATATYPE_PACK1         =  1)
-      INTEGER    DATATYPE_PACK2        
-      PARAMETER (DATATYPE_PACK2         =  2)
-      INTEGER    DATATYPE_PACK3        
-      PARAMETER (DATATYPE_PACK3         =  3)
-      INTEGER    DATATYPE_PACK4        
-      PARAMETER (DATATYPE_PACK4         =  4)
-      INTEGER    DATATYPE_PACK5        
-      PARAMETER (DATATYPE_PACK5         =  5)
-      INTEGER    DATATYPE_PACK6        
-      PARAMETER (DATATYPE_PACK6         =  6)
-      INTEGER    DATATYPE_PACK7        
-      PARAMETER (DATATYPE_PACK7         =  7)
       INTEGER    DATATYPE_PACK8        
       PARAMETER (DATATYPE_PACK8         =  8)
-      INTEGER    DATATYPE_PACK9        
-      PARAMETER (DATATYPE_PACK9         =  9)
-      INTEGER    DATATYPE_PACK10       
-      PARAMETER (DATATYPE_PACK10        = 10)
-      INTEGER    DATATYPE_PACK11       
-      PARAMETER (DATATYPE_PACK11        = 11)
-      INTEGER    DATATYPE_PACK12       
-      PARAMETER (DATATYPE_PACK12        = 12)
-      INTEGER    DATATYPE_PACK13       
-      PARAMETER (DATATYPE_PACK13        = 13)
-      INTEGER    DATATYPE_PACK14       
-      PARAMETER (DATATYPE_PACK14        = 14)
-      INTEGER    DATATYPE_PACK15       
-      PARAMETER (DATATYPE_PACK15        = 15)
       INTEGER    DATATYPE_PACK16       
       PARAMETER (DATATYPE_PACK16        = 16)
-      INTEGER    DATATYPE_PACK17       
-      PARAMETER (DATATYPE_PACK17        = 17)
-      INTEGER    DATATYPE_PACK18       
-      PARAMETER (DATATYPE_PACK18        = 18)
-      INTEGER    DATATYPE_PACK19       
-      PARAMETER (DATATYPE_PACK19        = 19)
-      INTEGER    DATATYPE_PACK20       
-      PARAMETER (DATATYPE_PACK20        = 20)
-      INTEGER    DATATYPE_PACK21       
-      PARAMETER (DATATYPE_PACK21        = 21)
-      INTEGER    DATATYPE_PACK22       
-      PARAMETER (DATATYPE_PACK22        = 22)
-      INTEGER    DATATYPE_PACK23       
-      PARAMETER (DATATYPE_PACK23        = 23)
       INTEGER    DATATYPE_PACK24       
       PARAMETER (DATATYPE_PACK24        = 24)
-      INTEGER    DATATYPE_PACK25       
-      PARAMETER (DATATYPE_PACK25        = 25)
-      INTEGER    DATATYPE_PACK26       
-      PARAMETER (DATATYPE_PACK26        = 26)
-      INTEGER    DATATYPE_PACK27       
-      PARAMETER (DATATYPE_PACK27        = 27)
-      INTEGER    DATATYPE_PACK28       
-      PARAMETER (DATATYPE_PACK28        = 28)
-      INTEGER    DATATYPE_PACK29       
-      PARAMETER (DATATYPE_PACK29        = 29)
-      INTEGER    DATATYPE_PACK30       
-      PARAMETER (DATATYPE_PACK30        = 30)
-      INTEGER    DATATYPE_PACK31       
-      PARAMETER (DATATYPE_PACK31        = 31)
-      INTEGER    DATATYPE_PACK32       
-      PARAMETER (DATATYPE_PACK32        = 32)
-      INTEGER    DATATYPE_CPX32        
-      PARAMETER (DATATYPE_CPX32         = 64)
-      INTEGER    DATATYPE_CPX64        
-      PARAMETER (DATATYPE_CPX64         = 128)
       INTEGER    DATATYPE_FLT32        
       PARAMETER (DATATYPE_FLT32         = 132)
       INTEGER    DATATYPE_FLT64        
       PARAMETER (DATATYPE_FLT64         = 164)
-      INTEGER    DATATYPE_INT8         
-      PARAMETER (DATATYPE_INT8          = 208)
-      INTEGER    DATATYPE_INT16        
-      PARAMETER (DATATYPE_INT16         = 216)
       INTEGER    DATATYPE_INT32        
       PARAMETER (DATATYPE_INT32         = 232)
-      INTEGER    DATATYPE_UINT8        
-      PARAMETER (DATATYPE_UINT8         = 308)
-      INTEGER    DATATYPE_UINT16       
-      PARAMETER (DATATYPE_UINT16        = 316)
-      INTEGER    DATATYPE_UINT32       
-      PARAMETER (DATATYPE_UINT32        = 332)
 !
 !  internal data types
 !
+      INTEGER    CDI_DATATYPE_INT      
+      PARAMETER (CDI_DATATYPE_INT       = 251)
+      INTEGER    CDI_DATATYPE_FLT      
+      PARAMETER (CDI_DATATYPE_FLT       = 252)
+      INTEGER    CDI_DATATYPE_TXT      
+      PARAMETER (CDI_DATATYPE_TXT       = 253)
+      INTEGER    CDI_DATATYPE_CPX      
+      PARAMETER (CDI_DATATYPE_CPX       = 254)
+      INTEGER    CDI_DATATYPE_UCHAR    
+      PARAMETER (CDI_DATATYPE_UCHAR     = 255)
+      INTEGER    CDI_DATATYPE_LONG     
+      PARAMETER (CDI_DATATYPE_LONG      = 256)
       INTEGER    DATATYPE_INT          
       PARAMETER (DATATYPE_INT           = 251)
       INTEGER    DATATYPE_FLT          
@@ -194,12 +236,12 @@
 !
 !  Chunks
 !
-      INTEGER    CHUNK_AUTO            
-      PARAMETER (CHUNK_AUTO             =  1)
-      INTEGER    CHUNK_GRID            
-      PARAMETER (CHUNK_GRID             =  2)
-      INTEGER    CHUNK_LINES           
-      PARAMETER (CHUNK_LINES            =  3)
+      INTEGER    CDI_CHUNK_AUTO        
+      PARAMETER (CDI_CHUNK_AUTO         =  1)
+      INTEGER    CDI_CHUNK_GRID        
+      PARAMETER (CDI_CHUNK_GRID         =  2)
+      INTEGER    CDI_CHUNK_LINES       
+      PARAMETER (CDI_CHUNK_LINES        =  3)
 !
 !  GRID types
 !
@@ -225,14 +267,16 @@
       PARAMETER (GRID_CURVILINEAR       = 10)
       INTEGER    GRID_LCC              
       PARAMETER (GRID_LCC               = 11)
-      INTEGER    GRID_LCC2             
-      PARAMETER (GRID_LCC2              = 12)
-      INTEGER    GRID_LAEA             
-      PARAMETER (GRID_LAEA              = 13)
-      INTEGER    GRID_SINUSOIDAL       
-      PARAMETER (GRID_SINUSOIDAL        = 14)
       INTEGER    GRID_PROJECTION       
-      PARAMETER (GRID_PROJECTION        = 15)
+      PARAMETER (GRID_PROJECTION        = 12)
+      INTEGER    CDI_PROJ_RLL          
+      PARAMETER (CDI_PROJ_RLL           = 21)
+      INTEGER    CDI_PROJ_LCC          
+      PARAMETER (CDI_PROJ_LCC           = 22)
+      INTEGER    CDI_PROJ_LAEA         
+      PARAMETER (CDI_PROJ_LAEA          = 23)
+      INTEGER    CDI_PROJ_SINU         
+      PARAMETER (CDI_PROJ_SINU          = 24)
 !
 !  ZAXIS types
 !
@@ -600,7 +644,7 @@
       EXTERNAL        streamInqNvars
 
 !
-!  STREAM var I/O routines
+!  STREAM var I/O routines (random access)
 !
 !                     streamWriteVar
 !                                    (INTEGER         streamID,
@@ -671,7 +715,7 @@
       EXTERNAL        streamWriteVarChunk
 
 !
-!  STREAM record I/O routines
+!  STREAM record I/O routines (sequential access)
 !
 !                     streamDefRecord
 !                                    (INTEGER         streamID,
@@ -1340,78 +1384,85 @@
       EXTERNAL        vlistInqVarUnitsPtr
 
 !
-!  VLIST attributes
+!  CDI attributes
 !
-      INTEGER         vlistInqNatts
-!                                    (INTEGER         vlistID,
+      INTEGER         cdiInqNatts
+!                                    (INTEGER         cdiID,
 !                                     INTEGER         varID,
 !                                     INTEGER         nattsp)
-      EXTERNAL        vlistInqNatts
+      EXTERNAL        cdiInqNatts
 
-      INTEGER         vlistInqAtt
-!                                    (INTEGER         vlistID,
+      INTEGER         cdiInqAtt
+!                                    (INTEGER         cdiID,
 !                                     INTEGER         varID,
 !                                     INTEGER         attrnum,
 !                                     CHARACTER*(*)   name,
 !                                     INTEGER         typep,
 !                                     INTEGER         lenp)
-      EXTERNAL        vlistInqAtt
+      EXTERNAL        cdiInqAtt
 
-      INTEGER         vlistDelAtt
-!                                    (INTEGER         vlistID,
+      INTEGER         cdiDelAtt
+!                                    (INTEGER         cdiID,
 !                                     INTEGER         varID,
 !                                     CHARACTER*(*)   name)
-      EXTERNAL        vlistDelAtt
+      EXTERNAL        cdiDelAtt
 
-      INTEGER         vlistDefAttInt
-!                                    (INTEGER         vlistID,
+      INTEGER         cdiCopyAtts
+!                                    (INTEGER         cdiID1,
+!                                     INTEGER         varID1,
+!                                     INTEGER         cdiID2,
+!                                     INTEGER         varID2)
+      EXTERNAL        cdiCopyAtts
+
+      INTEGER         cdiDefAttInt
+!                                    (INTEGER         cdiID,
 !                                     INTEGER         varID,
 !                                     CHARACTER*(*)   name,
 !                                     INTEGER         type,
 !                                     INTEGER         len,
 !                                     INTEGER         ip(*))
-      EXTERNAL        vlistDefAttInt
+      EXTERNAL        cdiDefAttInt
 
-      INTEGER         vlistDefAttFlt
-!                                    (INTEGER         vlistID,
+      INTEGER         cdiDefAttFlt
+!                                    (INTEGER         cdiID,
 !                                     INTEGER         varID,
 !                                     CHARACTER*(*)   name,
 !                                     INTEGER         type,
 !                                     INTEGER         len,
 !                                     DOUBLEPRECISION dp(*))
-      EXTERNAL        vlistDefAttFlt
+      EXTERNAL        cdiDefAttFlt
 
-      INTEGER         vlistDefAttTxt
-!                                    (INTEGER         vlistID,
+      INTEGER         cdiDefAttTxt
+!                                    (INTEGER         cdiID,
 !                                     INTEGER         varID,
 !                                     CHARACTER*(*)   name,
 !                                     INTEGER         len,
 !                                     CHARACTER*(*)   tp_cbuf)
-      EXTERNAL        vlistDefAttTxt
+      EXTERNAL        cdiDefAttTxt
 
-      INTEGER         vlistInqAttInt
-!                                    (INTEGER         vlistID,
+      INTEGER         cdiInqAttInt
+!                                    (INTEGER         cdiID,
 !                                     INTEGER         varID,
 !                                     CHARACTER*(*)   name,
 !                                     INTEGER         mlen,
 !                                     INTEGER         ip(*))
-      EXTERNAL        vlistInqAttInt
+      EXTERNAL        cdiInqAttInt
 
-      INTEGER         vlistInqAttFlt
-!                                    (INTEGER         vlistID,
+      INTEGER         cdiInqAttFlt
+!                                    (INTEGER         cdiID,
 !                                     INTEGER         varID,
 !                                     CHARACTER*(*)   name,
 !                                     INTEGER         mlen,
 !                                     DOUBLEPRECISION dp(*))
-      EXTERNAL        vlistInqAttFlt
+      EXTERNAL        cdiInqAttFlt
 
-      INTEGER         vlistInqAttTxt
-!                                    (INTEGER         vlistID,
+      INTEGER         cdiInqAttTxt
+!                                    (INTEGER         cdiID,
 !                                     INTEGER         varID,
 !                                     CHARACTER*(*)   name,
 !                                     INTEGER         mlen,
 !                                     CHARACTER*(*)   tp_cbuf)
-      EXTERNAL        vlistInqAttTxt
+      EXTERNAL        cdiInqAttTxt
 
 !
 !  GRID routines
@@ -1451,7 +1502,6 @@
 
 !                     gridPrint
 !                                    (INTEGER         gridID,
-!                                     INTEGER         index,
 !                                     INTEGER         opt)
       EXTERNAL        gridPrint
 
@@ -1468,6 +1518,19 @@
 !                                    (INTEGER         gridID)
       EXTERNAL        gridDuplicate
 
+!                     gridDefProj
+!                                    (INTEGER         gridID,
+!                                     INTEGER         projID)
+      EXTERNAL        gridDefProj
+
+      INTEGER         gridInqProj
+!                                    (INTEGER         gridID)
+      EXTERNAL        gridInqProj
+
+      INTEGER         gridInqProjType
+!                                    (INTEGER         gridID)
+      EXTERNAL        gridInqProjType
+
       INTEGER         gridInqType
 !                                    (INTEGER         gridID)
       EXTERNAL        gridInqType
@@ -1526,37 +1589,70 @@
 !
 !  CDI grid string key values
 !
-      INTEGER    CDI_GRID_XNAME        
-      PARAMETER (CDI_GRID_XNAME         = 901)
-      INTEGER    CDI_GRID_YNAME        
-      PARAMETER (CDI_GRID_YNAME         = 902)
-      INTEGER    CDI_GRID_XDIMNAME     
-      PARAMETER (CDI_GRID_XDIMNAME      = 903)
-      INTEGER    CDI_GRID_YDIMNAME     
-      PARAMETER (CDI_GRID_YDIMNAME      = 904)
-      INTEGER    CDI_GRID_VDIMNAME     
-      PARAMETER (CDI_GRID_VDIMNAME      = 905)
-      INTEGER    CDI_GRID_XLONGNAME    
-      PARAMETER (CDI_GRID_XLONGNAME     = 906)
-      INTEGER    CDI_GRID_YLONGNAME    
-      PARAMETER (CDI_GRID_YLONGNAME     = 907)
-      INTEGER    CDI_GRID_XUNITS       
-      PARAMETER (CDI_GRID_XUNITS        = 908)
-      INTEGER    CDI_GRID_YUNITS       
-      PARAMETER (CDI_GRID_YUNITS        = 909)
-      INTEGER         cdiGridDefString
+      INTEGER    CDI_KEY_XNAME         
+      PARAMETER (CDI_KEY_XNAME          = 901)
+      INTEGER    CDI_KEY_XDIMNAME      
+      PARAMETER (CDI_KEY_XDIMNAME       = 902)
+      INTEGER    CDI_KEY_XLONGNAME     
+      PARAMETER (CDI_KEY_XLONGNAME      = 903)
+      INTEGER    CDI_KEY_XUNITS        
+      PARAMETER (CDI_KEY_XUNITS         = 904)
+      INTEGER    CDI_KEY_YNAME         
+      PARAMETER (CDI_KEY_YNAME          = 911)
+      INTEGER    CDI_KEY_YDIMNAME      
+      PARAMETER (CDI_KEY_YDIMNAME       = 912)
+      INTEGER    CDI_KEY_YLONGNAME     
+      PARAMETER (CDI_KEY_YLONGNAME      = 913)
+      INTEGER    CDI_KEY_YUNITS        
+      PARAMETER (CDI_KEY_YUNITS         = 914)
+      INTEGER    CDI_KEY_VDIMNAME      
+      PARAMETER (CDI_KEY_VDIMNAME       = 920)
+      INTEGER    CDI_KEY_MAPPING       
+      PARAMETER (CDI_KEY_MAPPING        = 921)
+      INTEGER    CDI_KEY_MAPNAME       
+      PARAMETER (CDI_KEY_MAPNAME        = 922)
+!
+!  CDI zaxis string key values
+!
+      INTEGER    CDI_KEY_NAME          
+      PARAMETER (CDI_KEY_NAME           = 941)
+      INTEGER    CDI_KEY_DIMNAME       
+      PARAMETER (CDI_KEY_DIMNAME        = 942)
+      INTEGER    CDI_KEY_LONGNAME      
+      PARAMETER (CDI_KEY_LONGNAME       = 943)
+      INTEGER    CDI_KEY_UNITS         
+      PARAMETER (CDI_KEY_UNITS          = 944)
+      INTEGER    CDI_KEY_PSNAME        
+      PARAMETER (CDI_KEY_PSNAME         = 950)
+      INTEGER    CDI_KEY_P0NAME        
+      PARAMETER (CDI_KEY_P0NAME         = 951)
+      INTEGER    CDI_KEY_P0VALUE       
+      PARAMETER (CDI_KEY_P0VALUE        = 952)
+      INTEGER         cdiGridDefKeyStr
 !                                    (INTEGER         gridID,
 !                                     INTEGER         key,
 !                                     INTEGER         size,
 !                                     CHARACTER*(*)   mesg)
-      EXTERNAL        cdiGridDefString
+      EXTERNAL        cdiGridDefKeyStr
 
-      INTEGER         cdiGridInqString
+      INTEGER         cdiGridInqKeyStr
 !                                    (INTEGER         gridID,
 !                                     INTEGER         key,
 !                                     INTEGER         size,
 !                                     CHARACTER*(*)   mesg)
-      EXTERNAL        cdiGridInqString
+      EXTERNAL        cdiGridInqKeyStr
+
+      INTEGER         cdiZaxisDefKeyFlt
+!                                    (INTEGER         zaxisID,
+!                                     INTEGER         key,
+!                                     DOUBLEPRECISION value)
+      EXTERNAL        cdiZaxisDefKeyFlt
+
+      INTEGER         cdiZaxisInqKeyFlt
+!                                    (INTEGER         zaxisID,
+!                                     INTEGER         key,
+!                                     DOUBLEPRECISION value)
+      EXTERNAL        cdiZaxisInqKeyFlt
 
 !                     gridDefXname
 !                                    (INTEGER         gridID,
@@ -1659,37 +1755,6 @@
 !                                    (INTEGER         gridID)
       EXTERNAL        gridIsCircular
 
-      INTEGER         gridIsRotated
-!                                    (INTEGER         gridID)
-      EXTERNAL        gridIsRotated
-
-!                     gridDefXpole
-!                                    (INTEGER         gridID,
-!                                     DOUBLEPRECISION xpole)
-      EXTERNAL        gridDefXpole
-
-      DOUBLEPRECISION gridInqXpole
-!                                    (INTEGER         gridID)
-      EXTERNAL        gridInqXpole
-
-!                     gridDefYpole
-!                                    (INTEGER         gridID,
-!                                     DOUBLEPRECISION ypole)
-      EXTERNAL        gridDefYpole
-
-      DOUBLEPRECISION gridInqYpole
-!                                    (INTEGER         gridID)
-      EXTERNAL        gridInqYpole
-
-!                     gridDefAngle
-!                                    (INTEGER         gridID,
-!                                     DOUBLEPRECISION angle)
-      EXTERNAL        gridDefAngle
-
-      DOUBLEPRECISION gridInqAngle
-!                                    (INTEGER         gridID)
-      EXTERNAL        gridInqAngle
-
       INTEGER         gridInqTrunc
 !                                    (INTEGER         gridID)
       EXTERNAL        gridInqTrunc
@@ -1700,45 +1765,6 @@
       EXTERNAL        gridDefTrunc
 
 !
-!  Hexagonal GME grid
-!
-!                     gridDefGMEnd
-!                                    (INTEGER         gridID,
-!                                     INTEGER         nd)
-      EXTERNAL        gridDefGMEnd
-
-      INTEGER         gridInqGMEnd
-!                                    (INTEGER         gridID)
-      EXTERNAL        gridInqGMEnd
-
-!                     gridDefGMEni
-!                                    (INTEGER         gridID,
-!                                     INTEGER         ni)
-      EXTERNAL        gridDefGMEni
-
-      INTEGER         gridInqGMEni
-!                                    (INTEGER         gridID)
-      EXTERNAL        gridInqGMEni
-
-!                     gridDefGMEni2
-!                                    (INTEGER         gridID,
-!                                     INTEGER         ni2)
-      EXTERNAL        gridDefGMEni2
-
-      INTEGER         gridInqGMEni2
-!                                    (INTEGER         gridID)
-      EXTERNAL        gridInqGMEni2
-
-!                     gridDefGMEni3
-!                                    (INTEGER         gridID,
-!                                     INTEGER         ni3)
-      EXTERNAL        gridDefGMEni3
-
-      INTEGER         gridInqGMEni3
-!                                    (INTEGER         gridID)
-      EXTERNAL        gridInqGMEni3
-
-!
 !  Reference of an unstructured grid
 !
 !                     gridDefNumber
@@ -1780,9 +1806,45 @@
       EXTERNAL        gridInqUUID
 
 !
+!  Rotated Lon/Lat grid
+!
+!                     gridDefParamRLL
+!                                    (INTEGER         gridID,
+!                                     DOUBLEPRECISION xpole,
+!                                     DOUBLEPRECISION ypole,
+!                                     DOUBLEPRECISION angle)
+      EXTERNAL        gridDefParamRLL
+
+!                     gridInqParamRLL
+!                                    (INTEGER         gridID,
+!                                     DOUBLEPRECISION xpole,
+!                                     DOUBLEPRECISION ypole,
+!                                     DOUBLEPRECISION angle)
+      EXTERNAL        gridInqParamRLL
+
+!
+!  Hexagonal GME grid
+!
+!                     gridDefParamGME
+!                                    (INTEGER         gridID,
+!                                     INTEGER         nd,
+!                                     INTEGER         ni,
+!                                     INTEGER         ni2,
+!                                     INTEGER         ni3)
+      EXTERNAL        gridDefParamGME
+
+!                     gridInqParamGME
+!                                    (INTEGER         gridID,
+!                                     INTEGER         nd,
+!                                     INTEGER         ni,
+!                                     INTEGER         ni2,
+!                                     INTEGER         ni3)
+      EXTERNAL        gridInqParamGME
+
+!
 !  Lambert Conformal Conic grid (GRIB version)
 !
-!                     gridDefLCC
+!                     gridDefParamLCC
 !                                    (INTEGER         gridID,
 !                                     DOUBLEPRECISION originLon,
 !                                     DOUBLEPRECISION originLat,
@@ -1793,9 +1855,9 @@
 !                                     DOUBLEPRECISION yinc,
 !                                     INTEGER         projflag,
 !                                     INTEGER         scanflag)
-      EXTERNAL        gridDefLCC
+      EXTERNAL        gridDefParamLCC
 
-!                     gridInqLCC
+!                     gridInqParamLCC
 !                                    (INTEGER         gridID,
 !                                     DOUBLEPRECISION originLon,
 !                                     DOUBLEPRECISION originLat,
@@ -1806,45 +1868,7 @@
 !                                     DOUBLEPRECISION yinc,
 !                                     INTEGER         projflag,
 !                                     INTEGER         scanflag)
-      EXTERNAL        gridInqLCC
-
-!
-!  Lambert Conformal Conic 2 grid (PROJ version)
-!
-!                     gridDefLcc2
-!                                    (INTEGER         gridID,
-!                                     DOUBLEPRECISION earth_radius,
-!                                     DOUBLEPRECISION lon_0,
-!                                     DOUBLEPRECISION lat_0,
-!                                     DOUBLEPRECISION lat_1,
-!                                     DOUBLEPRECISION lat_2)
-      EXTERNAL        gridDefLcc2
-
-!                     gridInqLcc2
-!                                    (INTEGER         gridID,
-!                                     DOUBLEPRECISION earth_radius,
-!                                     DOUBLEPRECISION lon_0,
-!                                     DOUBLEPRECISION lat_0,
-!                                     DOUBLEPRECISION lat_1,
-!                                     DOUBLEPRECISION lat_2)
-      EXTERNAL        gridInqLcc2
-
-!
-!  Lambert Azimuthal Equal Area grid
-!
-!                     gridDefLaea
-!                                    (INTEGER         gridID,
-!                                     DOUBLEPRECISION earth_radius,
-!                                     DOUBLEPRECISION lon_0,
-!                                     DOUBLEPRECISION lat_0)
-      EXTERNAL        gridDefLaea
-
-!                     gridInqLaea
-!                                    (INTEGER         gridID,
-!                                     DOUBLEPRECISION earth_radius,
-!                                     DOUBLEPRECISION lon_0,
-!                                     DOUBLEPRECISION lat_0)
-      EXTERNAL        gridInqLaea
+      EXTERNAL        gridInqParamLCC
 
 !                     gridDefArea
 !                                    (INTEGER         gridID,
@@ -1922,6 +1946,10 @@
 !                                     CHARACTER*(*)   zaxisname)
       EXTERNAL        zaxisName
 
+      CHARACTER(80)   zaxisNamePtr
+!                                    (INTEGER         leveltype)
+      EXTERNAL        zaxisNamePtr
+
       INTEGER         zaxisCreate
 !                                    (INTEGER         zaxistype,
 !                                     INTEGER         size)
@@ -1943,14 +1971,8 @@
 !                                    (INTEGER         zaxisID)
       EXTERNAL        zaxisDuplicate
 
-!                     zaxisResize
-!                                    (INTEGER         zaxisID,
-!                                     INTEGER         size)
-      EXTERNAL        zaxisResize
-
 !                     zaxisPrint
-!                                    (INTEGER         zaxisID,
-!                                     INTEGER         index)
+!                                    (INTEGER         zaxisID)
       EXTERNAL        zaxisPrint
 
 !                     zaxisDefLevels
@@ -1958,7 +1980,7 @@
 !                                     DOUBLEPRECISION levels(*))
       EXTERNAL        zaxisDefLevels
 
-!                     zaxisInqLevels
+      INTEGER         zaxisInqLevels
 !                                    (INTEGER         zaxisID,
 !                                     DOUBLEPRECISION levels(*))
       EXTERNAL        zaxisInqLevels
@@ -2002,32 +2024,19 @@
 !                                     INTEGER*1(16)   uuid)
       EXTERNAL        zaxisInqUUID
 
-!
-!  CDI zaxis string key values
-!
-      INTEGER    CDI_ZAXIS_NAME        
-      PARAMETER (CDI_ZAXIS_NAME         = 801)
-      INTEGER    CDI_ZAXIS_DIMNAME     
-      PARAMETER (CDI_ZAXIS_DIMNAME      = 802)
-      INTEGER    CDI_ZAXIS_VDIMNAME    
-      PARAMETER (CDI_ZAXIS_VDIMNAME     = 803)
-      INTEGER    CDI_ZAXIS_LONGNAME    
-      PARAMETER (CDI_ZAXIS_LONGNAME     = 804)
-      INTEGER    CDI_ZAXIS_UNITS       
-      PARAMETER (CDI_ZAXIS_UNITS        = 805)
-      INTEGER         cdiZaxisDefString
+      INTEGER         cdiZaxisDefKeyStr
 !                                    (INTEGER         zaxisID,
 !                                     INTEGER         key,
 !                                     INTEGER         size,
 !                                     CHARACTER*(*)   mesg)
-      EXTERNAL        cdiZaxisDefString
+      EXTERNAL        cdiZaxisDefKeyStr
 
-      INTEGER         cdiZaxisInqString
+      INTEGER         cdiZaxisInqKeyStr
 !                                    (INTEGER         zaxisID,
 !                                     INTEGER         key,
 !                                     INTEGER         size,
 !                                     CHARACTER*(*)   mesg)
-      EXTERNAL        cdiZaxisInqString
+      EXTERNAL        cdiZaxisInqKeyStr
 
 !                     zaxisDefName
 !                                    (INTEGER         zaxisID,
@@ -2064,16 +2073,6 @@
 !                                     CHARACTER*(*)   stdname)
       EXTERNAL        zaxisInqStdname
 
-!                     zaxisDefPsName
-!                                    (INTEGER         zaxisID,
-!                                     CHARACTER*(*)   psname_optional)
-      EXTERNAL        zaxisDefPsName
-
-!                     zaxisInqPsName
-!                                    (INTEGER         zaxisID,
-!                                     CHARACTER*(*)   psname)
-      EXTERNAL        zaxisInqPsName
-
 !                     zaxisDefPrec
 !                                    (INTEGER         zaxisID,
 !                                     INTEGER         prec)
diff --git a/libcdi/src/cdiFortran.c b/libcdi/src/cdiFortran.c
index 2b83d70..2202400 100644
--- a/libcdi/src/cdiFortran.c
+++ b/libcdi/src/cdiFortran.c
@@ -134,7 +134,7 @@ FCALLSCFUN1 (STRING, streamFilename, STREAMFILENAME, streamfilename, INT)
 FCALLSCFUN1 (STRING, streamFilesuffix, STREAMFILESUFFIX, streamfilesuffix, 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)
@@ -146,7 +146,7 @@ FCALLSCSUB5 (streamReadVarSlice, STREAMREADVARSLICE, streamreadvarslice, INT, IN
 FCALLSCSUB5 (streamReadVarSliceF, STREAMREADVARSLICEF, streamreadvarslicef, INT, INT, INT, FLOATV, PINT)
 FCALLSCSUB5 (streamWriteVarChunk, 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)
@@ -287,17 +287,18 @@ FCALLSCFUN2 (STRING, vlistInqVarNamePtr, VLISTINQVARNAMEPTR, vlistinqvarnameptr,
 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  */
 
@@ -308,10 +309,13 @@ 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)
+FCALLSCSUB2 (gridPrint, GRIDPRINT, gridprint, INT, INT)
 FCALLSCFUN2 (INT, gridCreate, 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)
@@ -327,8 +331,13 @@ FCALLSCFUN2 (INT, gridInqYvals, GRIDINQYVALS, gridinqyvals, INT, DOUBLEV)
 
 /*  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)
@@ -350,27 +359,9 @@ FCALLSCFUN2 (DOUBLE, gridInqYval, 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)
@@ -382,20 +373,20 @@ 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)
+FCALLSCSUB10 (gridDefParamLCC, GRIDDEFPARAMLCC, griddefparamlcc, INT, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, INT, INT)
+FCALLSCSUB10 (gridInqParamLCC, GRIDINQPARAMLCC, gridinqparamlcc, INT, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PINT, PINT)
 FCALLSCSUB2 (gridDefArea, GRIDDEFAREA, griddefarea, INT, DOUBLEV)
 FCALLSCSUB2 (gridInqArea, GRIDINQAREA, gridinqarea, INT, DOUBLEV)
 FCALLSCFUN1 (INT, gridHasArea, GRIDHASAREA, gridhasarea, INT)
@@ -414,15 +405,15 @@ FCALLSCFUN1 (INT, gridInqComplexPacking, GRIDINQCOMPLEXPACKING, gridinqcomplexpa
 /*  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)
 FCALLSCSUB3 (zaxisDefLevel, ZAXISDEFLEVEL, zaxisdeflevel, INT, INT, DOUBLE)
 FCALLSCFUN2 (DOUBLE, zaxisInqLevel, ZAXISINQLEVEL, zaxisinqlevel, INT, INT)
 FCALLSCSUB2 (zaxisDefNlevRef, ZAXISDEFNLEVREF, zaxisdefnlevref, INT, INT)
@@ -431,11 +422,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)
@@ -443,8 +431,6 @@ 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 (zaxisDefPositive, ZAXISDEFPOSITIVE, zaxisdefpositive, INT, INT)
diff --git a/libcdi/src/vlist_att.c b/libcdi/src/cdi_att.c
similarity index 50%
rename from libcdi/src/vlist_att.c
rename to libcdi/src/cdi_att.c
index aea6650..2f1450d 100644
--- a/libcdi/src/vlist_att.c
+++ b/libcdi/src/cdi_att.c
@@ -1,5 +1,5 @@
 #ifdef HAVE_CONFIG_H
-#  include "config.h"
+#include "config.h"
 #endif
 
 #include <assert.h>
@@ -12,9 +12,13 @@
 #include "cdi.h"
 #include "cdi_int.h"
 #include "vlist.h"
-#include "vlist_att.h"
+#include "cdi_att.h"
 #include "error.h"
 #include "serialize.h"
+#include "grid.h"
+#include "zaxis.h"
+#include "resource_unpack.h"
+
 
 static
 cdi_atts_t *get_attsp(vlist_t *vlistptr, int varID)
@@ -31,7 +35,7 @@ cdi_atts_t *get_attsp(vlist_t *vlistptr, int varID)
 	attsp = &(vlistptr->vars[varID].atts);
     }
 
-  return (attsp);
+  return attsp;
 }
 
 static
@@ -49,27 +53,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);
@@ -77,7 +78,7 @@ cdi_att_t *new_att(cdi_atts_t *attsp, const char *name)
   attp->namesz = slen;
   attp->xvalue = NULL;
 
-  return (attp);
+  return attp;
 }
 
 static
@@ -97,44 +98,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
@@ -144,22 +165,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]);
 
@@ -177,102 +196,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);
-    }
-
-  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);
-  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);
-    }
+    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);
+  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);
@@ -289,184 +285,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:
@@ -477,8 +467,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);
@@ -502,8 +491,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;
@@ -511,30 +500,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);
@@ -543,50 +533,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:
@@ -595,22 +584,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);
 }
 
 /*
diff --git a/libcdi/src/cdi_att.h b/libcdi/src/cdi_att.h
new file mode 100644
index 0000000..8c8799b
--- /dev/null
+++ b/libcdi/src/cdi_att.h
@@ -0,0 +1,53 @@
+#ifndef CDI_ATT_H
+#define CDI_ATT_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef _CDI_LIMITS_H
+#include "cdi_limits.h"
+#endif
+
+/*
+ * 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;
+
+
+typedef struct {
+  size_t     nalloc;		/* number allocated >= nelems */
+  size_t     nelems;		/* length of the array */
+  cdi_att_t  value[MAX_ATTRIBUTES];
+} cdi_atts_t;
+
+
+int cdiAttsGetSize(void *p, int varID, void *context);
+
+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
+
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
diff --git a/libcdi/src/cdi_int.c b/libcdi/src/cdi_int.c
index 5050709..0894198 100644
--- a/libcdi/src/cdi_int.c
+++ b/libcdi/src/cdi_int.c
@@ -28,7 +28,7 @@ int cdiDefaultModelID  = CDI_UNDEFID;
 int cdiDefaultTableID  = CDI_UNDEFID;
 //int cdiNcMissingValue  = CDI_UNDEFID;
 int cdiNcChunksizehint = CDI_UNDEFID;
-int cdiChunkType       = CHUNK_GRID;
+int cdiChunkType       = CDI_CHUNK_GRID;
 int cdiSplitLtype105   = CDI_UNDEFID;
 
 int cdiIgnoreAttCoordinates = FALSE;
@@ -67,6 +67,7 @@ int cdiGribApiDebug     = 0;
 int cdiDefaultLeveltype = -1;
 int cdiDataUnreduced = 0;
 int cdiSortName = 0;
+int cdiSortParam = 0;
 int cdiHaveMissval = 0;
 
 
@@ -191,30 +192,30 @@ int cdiHaveFiletype(int filetype)
   switch (filetype)
     {
 #if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:  { status = 1; break; }
+    case CDI_FILETYPE_SRV:  { status = 1; break; }
 #endif
 #if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:  { status = 1; break; }
+    case CDI_FILETYPE_EXT:  { status = 1; break; }
 #endif
 #if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:  { status = 1; break; }
+    case CDI_FILETYPE_IEG:  { status = 1; break; }
 #endif
 #if  defined  (HAVE_LIBGRIB)
 #if  defined  (HAVE_LIBGRIB_API) || defined  (HAVE_LIBCGRIBEX)
-    case FILETYPE_GRB:  { status = 1; break; }
+    case CDI_FILETYPE_GRB:  { status = 1; break; }
 #endif
 #if  defined  (HAVE_LIBGRIB_API)
-    case FILETYPE_GRB2: { status = 1; break; }
+    case CDI_FILETYPE_GRB2: { status = 1; break; }
 #endif
 #endif
 #if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:   { status = 1; break; }
+    case CDI_FILETYPE_NC:   { status = 1; break; }
 #if  defined  (HAVE_NETCDF2)
-    case FILETYPE_NC2:  { status = 1; break; }
+    case CDI_FILETYPE_NC2:  { status = 1; break; }
 #endif
 #if  defined  (HAVE_NETCDF4)
-    case FILETYPE_NC4:  { status = 1; break; }
-    case FILETYPE_NC4C: { status = 1; break; }
+    case CDI_FILETYPE_NC4:  { status = 1; break; }
+    case CDI_FILETYPE_NC4C: { status = 1; break; }
 #endif
 #endif
     default: { status = 0; break; }
@@ -237,9 +238,9 @@ void cdiSetChunk(const char *chunkAlgo)
   //size_t len = strlen(chunkAlgo);
   int algo = -1;
 
-  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;
+  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 )
     {
@@ -297,6 +298,9 @@ void cdiInitialize(void)
       value = cdiGetenvInt("CDI_SORTNAME");
       if ( value >= 0 ) cdiSortName = (int) value;
 
+      value = cdiGetenvInt("CDI_SORTPARAM");
+      if ( value >= 0 ) cdiSortParam = (int) value;
+
       value = cdiGetenvInt("CDI_HAVE_MISSVAL");
       if ( value >= 0 ) cdiHaveMissval = (int) value;
 
@@ -420,6 +424,7 @@ 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;
diff --git a/libcdi/src/cdi_int.h b/libcdi/src/cdi_int.h
index f558ac6..f01011e 100644
--- a/libcdi/src/cdi_int.h
+++ b/libcdi/src/cdi_int.h
@@ -188,14 +188,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;
 
@@ -208,6 +208,17 @@ typedef struct {
 }
 VCT;
 
+#ifdef HAVE_LIBNETCDF
+typedef struct {
+  int gridID;
+  int xdimID;
+  int ydimID;
+  int xvarID;
+  int yvarID;
+  int avarID;
+}
+ncgrid_t;
+#endif
 
 typedef struct {
   int         self;
@@ -233,22 +244,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
@@ -290,6 +300,7 @@ typedef enum {
 } CdiTimeType;
 
 
+#define  CDI_FILETYPE_UNDEF          -1   /* Unknown/not yet defined file type */
 
 
 extern int CDI_Debug;      /* If set to 1, debuggig (default 0)            */
@@ -307,6 +318,7 @@ extern int cdiChunkType;
 extern int cdiSplitLtype105;
 extern int cdiDataUnreduced;
 extern int cdiSortName;
+extern int cdiSortParam;
 extern int cdiHaveMissval;
 extern int cdiIgnoreAttCoordinates;
 extern int cdiIgnoreValidRange;
@@ -341,8 +353,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);
@@ -366,6 +376,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);
diff --git a/libcdi/src/cdilib.c b/libcdi/src/cdilib.c
index 95fc3dd..d96eb3e 100644
--- a/libcdi/src/cdilib.c
+++ b/libcdi/src/cdilib.c
@@ -1,7 +1,7 @@
 
-/* Automatically generated by m214003 at 2016-04-18, do not edit */
+/* Automatically generated by m214003 at 2016-09-16, do not edit */
 
-/* CDILIB_VERSION="1.7.2rc3" */
+/* CDILIB_VERSION="1.8.0rc3" */
 
 #ifdef _ARCH_PWR6
 #pragma options nostrict
@@ -199,12 +199,12 @@ extern "C" {
 
 /* 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 */
 
@@ -262,9 +262,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 +279,12 @@ 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  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 */
 
@@ -497,9 +499,9 @@ const char *streamFilesuffix(int filetype);
 
 off_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);
@@ -520,7 +522,7 @@ void    streamReadVarSliceF(int streamID, int varID, int levelID, float data[],
 void    streamWriteVarChunk(int streamID, int varID, const int rect[3][2], const double data[], int 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);
@@ -815,27 +817,27 @@ const char *vlistInqVarNamePtr(int vlistID, int varID);
 const char *vlistInqVarLongnamePtr(int vlistID, int varID);
 const char *vlistInqVarUnitsPtr(int vlistID, int varID);
 
-/* VLIST attributes */
+/* CDI attributes */
 
-/*      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);
+/*      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);
 
-/*      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 */
@@ -862,6 +864,18 @@ 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);
+
+/*      gridDefProjType: Define the projection type */
+void    gridDefProjType(int gridID, int projtype);
+
+/*      gridInqProjType: Get the projection type */
+int     gridInqProjType(int gridID);
+
 /*      gridInqType: Get the type of a Grid */
 int     gridInqType(int gridID);
 
@@ -899,21 +913,30 @@ void    gridDefYvals(int gridID, const double yvals[]);
 int     gridInqYvals(int gridID, double yvals[]);
 
 /* 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_MAPNAME     921  // Grid mapping var name
+#define  CDI_KEY_MAPPING     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
+
+//      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);
 
 /*      gridDefXname: Define the name of a X-axis */
 void    gridDefXname(int gridID, const char *xname);
@@ -973,24 +996,9 @@ 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 +1034,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);
-
-/* 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);
+/* 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 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 originLon, double originLat, double lonParY, double lat1, double lat2, double xinc, double yinc, int projflag, int scanflag);
+void    gridInqParamLCC(int gridID, double *originLon, double *originLat, double *lonParY, double *lat1, double *lat2, double *xinc, double *yinc, int *projflag, int *scanflag);
 
 void    gridDefArea(int gridID, const double area[]);
 void    gridInqArea(int gridID, double area[]);
@@ -1121,18 +1128,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
+//      cdiZaxisDefKeyStr: Define a CDI Z-axis string value from a key
+int     cdiZaxisDefKeyStr(int zaxisID, int key, int size, const char *mesg);
 
-//      cdiZaxisDefString: Define a CDI Z-axis string value from a key
-int     cdiZaxisDefString(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,12 +1155,6 @@ 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);
 
@@ -1173,7 +1167,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);
@@ -1390,6 +1383,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 +1401,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 +1422,22 @@ void basetimeInit(basetime_t *basetime);
 #endif
 
 #include <stdio.h>
+#include <stdbool.h>
 
 
-#undef  UNDEFID
-#define UNDEFID  CDI_UNDEFID
+#undef  CDI_UNDEFID
+#define CDI_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;
 }
 /*
@@ -1988,35 +1984,33 @@ static int month_366[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 
 int calendar_dpy(int calendar)
 {
-  int dpy = 0;
+  int daysperyear = 0;
 
-  if      ( calendar == CALENDAR_360DAYS ) dpy = 360;
-  else if ( calendar == CALENDAR_365DAYS ) dpy = 365;
-  else if ( calendar == CALENDAR_366DAYS ) dpy = 366;
+  if      ( calendar == CALENDAR_360DAYS ) daysperyear = 360;
+  else if ( calendar == CALENDAR_365DAYS ) daysperyear = 365;
+  else if ( calendar == CALENDAR_366DAYS ) daysperyear = 366;
 
-  return (dpy);
+  return daysperyear;
 }
 
 
 int days_per_month(int calendar, int year, int month)
 {
-  int dayspermonth = 0;
   int *dpm = NULL;
-  int dpy;
+  int daysperyear = calendar_dpy(calendar);
 
-  dpy = calendar_dpy(calendar);
-
-  if      ( dpy == 360 ) dpm = month_360;
-  else if ( dpy == 365 ) dpm = month_365;
-  else                   dpm = month_366;
+  if      ( daysperyear == 360 ) dpm = month_360;
+  else if ( daysperyear == 365 ) dpm = month_365;
+  else                           dpm = month_366;
 
+  int dayspermonth = 0;
   if ( month >= 1 && month <= 12 )
     dayspermonth = dpm[month-1];
   /*
   else
     fprintf(stderr, "days_per_month: month %d out of range\n", month);
   */
-  if ( dpy == 0 && month == 2 )
+  if ( daysperyear == 0 && month == 2 )
     {
       if ( (year%4 == 0 && year%100 != 0) || year%400 == 0 )
 	dayspermonth = 29;
@@ -2024,40 +2018,25 @@ int days_per_month(int calendar, int year, int month)
 	dayspermonth = 28;
     }
 
-  return (dayspermonth);
+  return dayspermonth;
 }
 
 
 int days_per_year(int calendar, int year)
 {
-  int daysperyear;
-  int dpy;
-
-  dpy = calendar_dpy(calendar);
+  int daysperyear = calendar_dpy(calendar);
 
-  if ( dpy == 0 )
+  if ( daysperyear == 0 )
     {
-      if ( calendar == CALENDAR_STANDARD )
-	{
-	  if ( year == 1582 )
-	    dpy = 355;
-	  else if ( (year%4 == 0 && year%100 != 0) || year%400 == 0 )
-	    dpy = 366;
-	  else
-	    dpy = 365;
-	}
+      if ( year == 1582 && calendar == CALENDAR_STANDARD )
+        daysperyear = 355;
+      else if ( (year%4 == 0 && year%100 != 0) || year%400 == 0 )
+        daysperyear = 366;
       else
-	{
-	  if ( (year%4 == 0 && year%100 != 0) || year%400 == 0 )
-	    dpy = 366;
-	  else
-	    dpy = 365;
-	}
+        daysperyear = 365;
     }
 
-  daysperyear = dpy;
-  
-  return (daysperyear);
+  return daysperyear;
 }
 
 
@@ -2087,7 +2066,6 @@ 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 i;
   int *dpm = NULL;
   long rval = (long)dpy * year + day;
 
@@ -2095,8 +2073,8 @@ static int encode_day(int dpy, int year, int month, int day)
   else if ( dpy == 365 ) dpm = month_365;
   else if ( dpy == 366 ) dpm = month_366;
 
-  if ( dpm ) for ( i = 0; i < month-1; i++ ) rval += dpm[i];
-  if (rval > INT_MAX || rval < INT_MIN)
+  if ( dpm ) for ( int i = 0; i < month-1; i++ ) rval += dpm[i];
+  if ( rval > INT_MAX || rval < INT_MIN )
     Error("Unhandled date: %ld", rval);
 
   return (int)rval;
@@ -2106,9 +2084,7 @@ static int encode_day(int dpy, int year, int month, int day)
 void encode_caldaysec(int calendar, int year, int month, int day, int hour, int minute, int second,
 		      int *julday, int *secofday)
 {
-  int dpy;
-
-  dpy = calendar_dpy(calendar);
+  int dpy = calendar_dpy(calendar);
 
   if ( dpy == 360 || dpy == 365 || dpy == 366 )
     *julday = encode_day(dpy, year, month, day);
@@ -2119,12 +2095,10 @@ void encode_caldaysec(int calendar, int year, int month, int day, int hour, int
 }
 
 
-void decode_caldaysec(int calendar, int julday, int secofday, 
+void decode_caldaysec(int calendar, int julday, int secofday,
 		      int *year, int *month, int *day, int *hour, int *minute, int *second)
 {
-  int dpy;
-
-  dpy = calendar_dpy(calendar);
+  int dpy = calendar_dpy(calendar);
 
   if ( dpy == 360 || dpy == 365 || dpy == 366 )
     decode_day(dpy, julday, year, month, day);
@@ -2140,39 +2114,34 @@ void decode_caldaysec(int calendar, int julday, int secofday,
 #ifdef TEST
 static int date_to_calday(int calendar, int date)
 {
-  int calday;
-  int dpy;
-  int year, month, day;
-
-  dpy = calendar_dpy(calendar);
+  int dpy = calendar_dpy(calendar);
 
+  int year, month, day;
   cdiDecodeDate(date, &year, &month, &day);
 
+  int calday;
   if ( dpy == 360 || dpy == 365 || dpy == 366 )
     calday = encode_day(dpy, year, month, day);
   else
     calday = encode_julday(calendar, year, month, day);
 
-  return (calday);
+  return calday;
 }
 
 
 static int calday_to_date(int calendar, int calday)
 {
-  int date;
-  int dpy;
   int year, month, day;
-
-  dpy = calendar_dpy(calendar);
+  int dpy = calendar_dpy(calendar);
 
   if ( dpy == 360 || dpy == 365 || dpy == 366 )
     decode_day(dpy, calday, &year, &month, &day);
   else
     decode_julday(calendar, calday, &year, &month, &day);
 
-  date = cdiEncodeDate(year, month, day);
+  int date = cdiEncodeDate(year, month, day);
 
-  return (date);
+  return date;
 }
 
 
@@ -2437,6 +2406,7 @@ enum reshListMismatch {
 
 int reshListCompare(int nsp0, int nsp1);
 void reshListPrint(FILE *fp);
+int reshGetTxCode(cdiResH resH);
 
 #endif
 /*
@@ -2451,6 +2421,8 @@ void reshListPrint(FILE *fp);
 #ifndef _TAXIS_H
 #define _TAXIS_H
 
+#include <stdbool.h>
+
 #ifndef RESOURCE_HANDLE_H
 #endif
 
@@ -2458,7 +2430,7 @@ typedef struct {
   /* Date format  YYYYMMDD */
   /* Time format    hhmmss */
   int     self;
-  short   used;
+  bool    used;
   short   has_bounds;
   int     type;           // time type
   int     vdate;          // verification date
@@ -2470,7 +2442,7 @@ 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
@@ -2909,14 +2881,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;
 
@@ -2929,6 +2901,17 @@ typedef struct {
 }
 VCT;
 
+#ifdef HAVE_LIBNETCDF
+typedef struct {
+  int gridID;
+  int xdimID;
+  int ydimID;
+  int xvarID;
+  int yvarID;
+  int avarID;
+}
+ncgrid_t;
+#endif
 
 typedef struct {
   int         self;
@@ -2954,17 +2937,17 @@ 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;
+  int         xdimID[MAX_GRIDS_PS];
+  int         ydimID[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;
@@ -3087,6 +3070,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);
@@ -3422,7 +3407,7 @@ static int cdfOpenFile(const char *filename, const char *mode, int *filetype)
 #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);
@@ -4373,223 +4358,6 @@ void cdf_inq_attid(int ncid, int varid, const char *name, int *attnump)
  * 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)
-{
-  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);
-}
-
-/*
- * 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"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
 #ifndef _DMEMORY_H
 #define _DMEMORY_H
 
@@ -4645,134 +4413,371 @@ 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                            */
+bool str_is_equal(const char *vstr, const char *cstr)
+{
+  bool is_equal = false;
+  size_t clen = (cstr != NULL) ? strlen(cstr) : 0;
 
-const char *gribapiLibraryVersionString(void);
-void gribContainersNew(stream_t * streamptr);
-void gribContainersDelete(stream_t * streamptr);
+  if ( vstr && *vstr ) is_equal = (memcmp(vstr, cstr, clen) == 0);
 
-#ifdef HAVE_LIBGRIB_API
-static inline void *gribHandleNew(int editionNumber)
+  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!");
+  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 )
+    {
+      if ( ptu[0] == 's' ) timeunit = TUNIT_SECOND;
+    }
 
-  return gh;
+  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);
+  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");
 
-  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;
+  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);
+  bool status = false;
+  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;
+  if ( (u0=='m' && (!units[1] || strncmp(units, "meter", 5) == 0)) ||
+       (!units[2] && units[1]=='m' && (u0=='c' || u0=='d' || u0=='k')) )
+    {
+      status = true;
+    }
+
+  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;
+    }
+
+  if ( status == false && 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;
+    }
+
+  if ( status == false && 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, "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") ||
+       str_is_equal(attstring, "gregorian") )
+    *calendar = CALENDAR_STANDARD;
+  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);
@@ -4786,6 +4791,8 @@ void   cdfDefRecord(stream_t * streamptr);
 
 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);
 
@@ -4801,6 +4808,8 @@ void   cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
 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);
+
 #endif
 /*
  * Local Variables:
@@ -4811,700 +4820,789 @@ 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 */
-
-/* Triangular grids */
-
-#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 */
-
-#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                          */
-
-/* Gaussian grids */
+#ifndef _GRID_H
+#define _GRID_H
 
-#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     */
+#include <stdbool.h>
 
-/* 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               */
 
+typedef unsigned char mask_t;
 
-#define  ISEC2_Reduced              (isec2[16])  /* 0: regular, 1: reduced grid                   */
+typedef struct grid_t grid_t;
 
-#define  ISEC2_RowLonPtr            (&isec2[22])
-#define  ISEC2_RowLon(i)            (isec2[22+i]) /* Number of points along each parallel         */
+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);
+};
 
-/* */
+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;
+  int     size;                  // number of values
+  short   flag;                  // 0: undefined 1:vals 2:first+inc
+  double  first, last, inc;
+  double *vals;
+  double *bounds;
+};
 
-#define  ISEC2_LatSP                (isec2[12])  /* Latitude of the southern pole of rotation     */
-#define  ISEC2_LonSP                (isec2[13])  /* Longitude of the southern pole of rotation    */
+// Lambert Conformal Conic
+struct grid_lcc_t {
+  double  originLon;
+  double  originLat;
+  double  lonParY;
+  double  lat1;
+  double  lat2;
+  double  xinc;
+  double  yinc;
+  int     projflag;
+  int     scanflag;
+  short   defined;
+};
 
-#define  FSEC2_RotAngle             (fsec2[ 0])  /* Angle of rotation                             */
-#define  FSEC2_StrFact              (fsec2[ 1])  /* Stretching factor                             */
+// GME Grid
+struct grid_gme_t {
+  int     nd, ni, ni2, ni3;       /* parameter for GRID_GME         */
+};
 
-/*
- *  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);
+struct grid_t {
+  char    vdimname[CDI_MAX_NAME];
+  char    mapname[CDI_MAX_NAME];
+  char    mapping[CDI_MAX_NAME];
+  char   *name;
+  int     self;
+  int     type;                   /* grid type                      */
+  int     prec;                   /* grid precision                 */
+  int     proj;                   /* grid projection                */
+  int     projtype;               /* grid projection type           */
+  mask_t *mask;
+  mask_t *mask_gme;
+  double *area;
+  struct grid_lcc_t  lcc;
+  struct grid_gme_t  gme;
+  short   isCyclic;               /* TRUE for global cyclic grids   */
+  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     np;                     /* number of parallels between a pole and the equator */
+  bool    lcomplex;
+  bool    hasdims;
+  struct gridaxis_t x;
+  struct gridaxis_t y;
+  const struct gridVirtTable *vtable;
+  cdi_atts_t atts;
+};
 
 
-const char *cgribexLibraryVersion(void);
+void grid_init(grid_t *gridptr);
+void cdiGridTypeInit(grid_t *gridptr, int gridtype, int size);
+void grid_free(grid_t *gridptr);
+grid_t *grid_to_pointer(int gridID);
+extern const struct gridVirtTable cdiGridVtable;
 
-void  gribDebug(int debug);
-void  gribSetCalendar(int calendar);
+unsigned cdiGridCount(void);
 
-void  gribDateTime(int *isec1, int *date, int *time);
-int   gribRefDate(int *isec1);
-int   gribRefTime(int *isec1);
-int   gribTimeIsFC(int *isec1);
+void gridVerifyProj(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 *gridInqXvalsPtr(int gridID);
+const double *gridInqYvalsPtr(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 double *gridInqXboundsPtr(int gridID);
+const double *gridInqYboundsPtr(int gridID);
+const double *gridInqAreaPtr(int gridID);
 
-int   gribGetZip(long recsize, unsigned char *gribbuffer, long *urecsize);
+const char *gridInqReferencePtr(int gridID);
 
-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 gridGenerate(const grid_t *grid);
 
-int   gribOpen(const char *filename, const char *mode);
-void  gribClose(int fileID);
+//int gridIsEqual(int gridID1, int gridID2);
 
-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 cdiGridGetIndexList(unsigned, int * );
 
-int   grib_info_for_grads(off_t recpos, long recsize, unsigned char *gribbuffer, int *intnum, float *fltnum, off_t *bignum);
+void
+gridUnpack(char * unpackBuffer, int unpackBufferSize,
+           int * unpackBufferPos, int originNamespace, void *context,
+           int force_id);
 
-double calculate_pfactor_float(const float* spectralField, long fieldTruncation, long subsetTruncation);
-double calculate_pfactor_double(const double* spectralField, long fieldTruncation, long subsetTruncation);
+struct addIfNewRes
+{
+  int Id;
+  int isNew;
+};
 
+struct addIfNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode);
 
-#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;
-
-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;
-
-char *cdiPartabPath   = NULL;
-int   cdiPartabIntern = 1;
+#include <string.h>
 
-double cdiDefaultMissval = -9.E33;
 
-static const char Filetypes[][9] = {
-  "UNKNOWN",
-  "GRIB",
-  "GRIB2",
-  "NetCDF",
-  "NetCDF2",
-  "NetCDF4",
-  "NetCDF4c",
-  "SERVICE",
-  "EXTRA",
-  "IEG",
-  "HDF5",
+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
 };
 
-int CDI_Debug   = 0;    /* If set to 1, debugging           */
-int CDI_Recopt = 0;
 
-int cdiGribApiDebug     = 0;
-int cdiDefaultLeveltype = -1;
-int cdiDataUnreduced = 0;
-int cdiSortName = 0;
-int cdiHaveMissval = 0;
+extern double *cdfPendingLoad;
 
+void cdfLazyGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype);
+void cdfBaseGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype);
 
-static long cdiGetenvInt(const char *envName)
-{
-  char *envString;
-  long envValue = -1;
-  long fact = 1;
+void cdfLazyGridDestroy(struct cdfLazyGrid *lazyGrid);
 
-  envString = getenv(envName);
+#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 ( 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;
-	    }
-	}
+static struct gridVirtTable cdfLazyGridVtable;
+double *cdfPendingLoad;
+#ifdef HAVE_LIBPTHREAD
+static pthread_once_t cdfLazyInitialized = PTHREAD_ONCE_INIT;
+#else
+static bool cdfLazyInitialized;
+#endif
 
-      if ( fact ) envValue = fact*atol(envString);
 
-      if ( CDI_Debug ) Message("set %s to %ld", envName, envValue);
-    }
+#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
 
-  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);
-
-  if ( algo != -1 )
-    {
-      cdiChunkType = algo;
-      if ( CDI_Debug ) Message("set ChunkAlgo to %s", chunkAlgo);
-    }
+    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->x.vals == cdfPendingLoad)
+    grid->x.vals = NULL;
+  cdfGrid->xValsGet.datasetNCId = -1;
+  cdfGrid->xValsGet.varNCId = -1;
+  cdfGrid->baseVtable->defXVals(grid, vals);
+  unlock_lazy_load(cdfGrid);
+}
 
-void cdiInitialize(void)
+static void
+cdfLazyGridDefYVals(grid_t *grid, const double *vals)
 {
-  static int Init_CDI = FALSE;
-  char *envstr;
-  long value;
+  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);
+}
 
-  if ( ! Init_CDI )
-    {
-      Init_CDI = TRUE;
+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->x.vals, grid->vtable->inqXValsPtr);
+  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 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->y.vals, grid->vtable->inqYValsPtr);
+  unlock_lazy_load(lazyGrid);
+  return rv;
+}
 
-      value = cdiGetenvInt("CDI_DEBUG");
-      if ( value >= 0 ) CDI_Debug = (int) value;
+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_GRIBAPI_DEBUG");
-      if ( value >= 0 ) cdiGribApiDebug = (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_RECOPT");
-      if ( value >= 0 ) CDI_Recopt = (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_REGULARGRID");
-      if ( value >= 0 ) cdiDataUnreduced = (int) value;
 
-      value = cdiGetenvInt("CDI_SORTNAME");
-      if ( value >= 0 ) cdiSortName = (int) value;
+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);
+}
 
-      value = cdiGetenvInt("CDI_HAVE_MISSVAL");
-      if ( value >= 0 ) cdiHaveMissval = (int) value;
+static void
+cdfLazyGridDefXBounds(grid_t *grid, const double *xbounds)
+{
+  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);
+}
 
-      value = cdiGetenvInt("CDI_LEVELTYPE");
-      if ( value >= 0 ) cdiDefaultLeveltype = (int) value;
+static void
+cdfLazyGridDefYBounds(grid_t *grid, const double *ybounds)
+{
+  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);
+}
 
-      value = cdiGetenvInt("CDI_NETCDF_HDR_PAD");
-      if ( value >= 0 ) CDI_netcdf_hdr_pad = (size_t) value;
+static const double *
+cdfLazyGridInqYBoundsPtr(grid_t *grid)
+{
+  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);
+}
 
-      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);
+static void
+cdfLazyGridCopyScalarFields(grid_t *gridptrOrig, grid_t *gridptrDup)
+{
+  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);
+}
 
-      envstr = getenv("CDI_CHUNK_ALGO");
-      if ( envstr ) cdiSetChunk(envstr);
+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));
+    }
 
-      envstr = getenv("SPLIT_LTYPE_105");
-      if ( envstr ) cdiSplitLtype105 = atoi(envstr);
+  if ( gridptrOrig->x.vals != NULL && gridptrOrig->x.vals != cdfPendingLoad )
+    {
+      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->x.size;
 
-      envstr = getenv("IGNORE_ATT_COORDINATES");
-      if ( envstr ) cdiIgnoreAttCoordinates = atoi(envstr);
+      gridptrDup->x.vals = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->x.vals, gridptrOrig->x.vals, size * sizeof (double));
+    }
 
-      envstr = getenv("IGNORE_VALID_RANGE");
-      if ( envstr ) cdiIgnoreValidRange = atoi(envstr);
+  if ( gridptrOrig->y.vals != NULL && gridptrOrig->y.vals != cdfPendingLoad )
+    {
+      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->y.size;
 
-      envstr = getenv("CDI_SKIP_RECORDS");
-      if ( envstr )
-	{
-	  cdiSkipRecords = atoi(envstr);
-	  cdiSkipRecords = cdiSkipRecords > 0 ? cdiSkipRecords : 0;
-	}
+      gridptrDup->y.vals = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->y.vals, gridptrOrig->y.vals, size * sizeof (double));
+    }
 
-      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!");
-	    }
-	}
+  if ( gridptrOrig->x.bounds != NULL && gridptrOrig->x.bounds != cdfPendingLoad )
+    {
+      size_t size  = (irregular ? gridsize : (size_t)gridptrOrig->x.size)
+        * (size_t)gridptrOrig->nvertex;
 
-      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!");
-	    }
-	}
+      gridptrDup->x.bounds = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->x.bounds, gridptrOrig->x.bounds, size * sizeof (double));
+    }
 
-      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);
-            }
-        }
+  if ( gridptrOrig->y.bounds != NULL && gridptrOrig->y.bounds != cdfPendingLoad )
+    {
+      size_t size = (irregular ? gridsize : (size_t)gridptrOrig->y.size)
+        * (size_t)gridptrOrig->nvertex;
 
+      gridptrDup->y.bounds = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->y.bounds, gridptrOrig->y.bounds, size * sizeof (double));
+    }
 
-      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 ( gridptrOrig->area != NULL && gridptrOrig->area != cdfPendingLoad )
+      {
+        size_t size = gridsize;
 
-	  if ( CDI_Debug )
-	    Message("Default calendar set to %s!", envstr);
-	}
-#if  defined  (HAVE_LIBCGRIBEX)
-      gribSetCalendar(cdiDefaultCalendar);
-#endif
+        gridptrDup->area = (double *)Malloc(size * sizeof (double));
+        memcpy(gridptrDup->area, gridptrOrig->area, size * sizeof (double));
+      }
+  }
 
-      envstr = getenv("PARTAB_INTERN");
-      if ( envstr ) cdiPartabIntern = atoi(envstr);
+  if ( gridptrOrig->mask != NULL )
+    {
+      size_t size = gridsize;
 
-      envstr = getenv("PARTAB_PATH");
-      if ( envstr ) cdiPartabPath = strdup(envstr);
+      gridptrDup->mask = (mask_t *)Malloc(size * sizeof(mask_t));
+      memcpy(gridptrDup->mask, gridptrOrig->mask, size * sizeof (mask_t));
     }
-}
 
+  if ( gridptrOrig->mask_gme != NULL )
+    {
+      size_t size = gridsize;
 
-const char *strfiletype(int filetype)
-{
-  const char *name;
-  int size = (int) (sizeof(Filetypes)/sizeof(char *));
+      gridptrDup->mask_gme = (mask_t *)Malloc(size * sizeof (mask_t));
+      memcpy(gridptrDup->mask_gme, gridptrOrig->mask_gme, size * sizeof(mask_t));
+    }
+}
 
-  if ( filetype > 0 && filetype < size )
-    name = Filetypes[filetype];
-  else
-    name = Filetypes[0];
+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;
+}
 
-  return (name);
+static void
+cdfLazyGridInitOnce(void)
+{
+  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
 }
 
+static void
+cdfBaseGridInit(grid_t *grid, int gridtype)
+{
+  grid_init(grid);
+  cdiGridTypeInit(grid, gridtype, 0);
+}
 
-void cdiDefGlobal(const char *string, int val)
+static void
+cdfLazyGridInit(struct cdfLazyGrid *grid, int gridtype)
 {
-  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);
+#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);
 }
 
 
-void cdiDefMissval(double missval)
+void cdfLazyGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype)
 {
-  cdiInitialize();
-
-  cdiDefaultMissval = missval;
+  struct cdfLazyGrid *restrict grid = *gridpptr;
+  if (!grid)
+    *gridpptr = grid = (struct cdfLazyGrid *)Malloc(sizeof (*grid));
+  cdfLazyGridInit(grid, gridtype);
 }
 
 
-double cdiInqMissval(void)
+void cdfBaseGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype)
 {
-  cdiInitialize();
-
-  return (cdiDefaultMissval);
+  struct cdfLazyGrid *restrict grid = *gridpptr;
+  if (!grid)
+    *gridpptr = grid = (struct cdfLazyGrid *)Malloc(sizeof (grid_t));
+  cdfBaseGridInit((grid_t*)grid, gridtype);
 }
-
 /*
  * Local Variables:
  * c-file-style: "Java"
@@ -5514,167 +5612,213 @@ double cdiInqMissval(void)
  * require-trailing-newline: t
  * End:
  */
+#ifndef CDI_CKSUM_H_
+#define CDI_CKSUM_H_
 
-#if defined (HAVE_CONFIG_H)
-#endif
-
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
+#include <inttypes.h>
 
+uint32_t cdiCheckSum(int type, int count, const void *data);
 
-void cdiDecodeParam(int param, int *pnum, int *pcat, int *pdis)
-{
-  unsigned uparam = (unsigned)param;
-  unsigned upnum;
+#endif
 
-  *pdis = 0xff   & uparam;
-  *pcat = 0xff   & uparam >> 8;
-  upnum = 0xffff & uparam >> 16;
-  if ( upnum > 0x7fffU ) upnum = 0x8000U - upnum;
-  *pnum = (int)upnum;
-}
+/*
+ * 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>
 
-int cdiEncodeParam(int pnum, int pcat, int pdis)
-{
-  unsigned uparam, upnum;
+void
+memcrc_r(uint32_t *state, const unsigned char *block, size_t block_len);
 
-  if ( pcat < 0 || pcat > 255 ) pcat = 255;
-  if ( pdis < 0 || pdis > 255 ) pdis = 255;
+void
+memcrc_r_eswap(uint32_t *state, const unsigned char *elems, size_t num_elems,
+               size_t elem_size);
 
-  upnum = (unsigned)pnum;
-  if ( pnum < 0 ) upnum = (unsigned)(0x8000 - pnum);
+uint32_t
+memcrc_finish(uint32_t *state, off_t total_size);
 
-  uparam = upnum << 16 | (unsigned)(pcat << 8) | (unsigned)pdis;
+uint32_t
+memcrc(const unsigned char *b, size_t n);
 
-  return ((int)uparam);
-}
+/*
+ * 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
 
-void cdiDecodeDate(int date, int *year, int *month, int *day)
-{
+#include <string.h>
 
-  int iyear = date / 10000;
-  *year = iyear;
-  int idate = abs(date - iyear * 10000),
-    imonth = idate / 100;
-  *month = imonth;
-  *day   = idate - imonth * 100;
-}
+#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);
 
-int cdiEncodeDate(int year, int month, int day)
+/*
+ * (de-)marshalling function for common data structures
+ */
+static inline int
+serializeStrTabGetPackSize(const char **strTab, int numStr,
+                           void *context)
 {
-  int iyear = abs(year),
-    date = iyear * 10000 + month * 100 + day;
-  if ( year < 0 ) date = -date;
-  return (date);
+  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;
 }
 
-
-void cdiDecodeTime(int time, int *hour, int *minute, int *second)
+static inline void
+serializeStrTabPack(const char **strTab, int numStr,
+                    void *buf, int buf_size, int *position, void *context)
 {
-  int ihour = time / 10000,
-    itime = time - ihour * 10000,
-    iminute = itime / 100;
-  *hour   = ihour;
-  *minute = iminute;
-  *second = itime - iminute * 100;
+  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);
 }
 
-
-int cdiEncodeTime(int hour, int minute, int second)
+static inline void
+serializeStrTabUnpack(const void *buf, int buf_size, int *position,
+                      char **strTab, int numStr, void *context)
 {
-  int time = hour*10000 + minute*100 + second;
-
-  return time;
-}
-
-
-void cdiParamToString(int param, char *paramstr, int maxlen)
-{
-  int dis, cat, num;
-  int len;
+  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);
+}
 
-  cdiDecodeParam(param, &num, &cat, &dis);
+/*
+ * 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);
 
-  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);
+#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
 
-  if ( len >= maxlen || len < 0)
-    fprintf(stderr, "Internal problem (%s): size of input string is too small!\n", __func__);
-}
+#include <inttypes.h>
+#include <sys/types.h>
+#include <stdlib.h>
 
 
-const char *cdiUnitNamePtr(int cdi_unit)
+uint32_t cdiCheckSum(int type, int count, const void *buffer)
 {
-  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;
+  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;
 }
 
-size_t
-cdiGetPageSize(bool largePageAlign)
+/*
+ * 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)
 {
-  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
+  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:
     {
-#  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
+      const char *cp = strerror(errno);
+      if ( cp == NULL ) break;
+      return cp;
     }
-  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;
-}
+  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:
@@ -5685,11986 +5829,10084 @@ cdiGetPageSize(bool largePageAlign)
  * require-trailing-newline: t
  * End:
  */
+#ifndef _GRIBAPI_H
+#define _GRIBAPI_H
 
-/* Automatically generated by m214003 at 2016-02-19, do not edit */
-
-/* CGRIBEXLIB_VERSION="1.7.4" */
-
-#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"
+#ifdef HAVE_LIBGRIB_API
+#include <grib_api.h>
+#ifndef  _ERROR_H
 #endif
-
-#ifdef _ARCH_PWR6
-#pragma options nostrict
 #endif
 
-#if defined (HAVE_CONFIG_H)
+#ifndef  _CDI_INT_H
 #endif
 
-#include <string.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <sys/types.h>
-#include <inttypes.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                                          */
 
-#ifndef _TEMPLATES_H
-#define _TEMPLATES_H
+/* 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                            */
 
-#define CAT(X,Y)      X##_##Y
-#define TEMPLATE(X,Y) CAT(X,Y)
+const char *gribapiLibraryVersionString(void);
+void gribContainersNew(stream_t * streamptr);
+void gribContainersDelete(stream_t * streamptr);
 
-#endif 
-#ifndef GRIB_INT_H
-#define GRIB_INT_H
+#ifdef HAVE_LIBGRIB_API
+static inline void *gribHandleNew(int editionNumber)
+{
+  void *gh = (void *)grib_handle_new_from_samples(NULL, (editionNumber == 1) ? "GRIB1" : "GRIB2");
 
-#if defined (HAVE_CONFIG_H)
-#endif
+  if ( gh == NULL ) Error("grib_handle_new_from_samples failed!");
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-#include <float.h>
+  return gh;
+}
 
+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);
 
-#if ! defined   (_CGRIBEX_H)
-#endif
-#if ! defined   (_ERROR_H)
-#endif
-#if ! defined   (_DTYPES_H)
-#endif
+  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;
+}
 
-#if ! defined   (FALSE)
-#  define  FALSE  0
-#endif
+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);
 
-#if ! defined   (TRUE)
-#  define  TRUE  1
-#endif
+  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;
+}
 
-#if ! defined   (UCHAR)
-#  define  UCHAR  unsigned char
-#endif
+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);
 
+  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 (CRAY) || defined (SX) || defined (__uxpch__)
-#  define VECTORCODE
+static inline void gribHandleDelete(void *gh)
+{
+  grib_handle_delete((struct grib_handle *)gh);
+}
+#else
+#define gribHandleNew(editionNumber) (NULL)
+#define gribHandleDelete(gh)
 #endif
 
+typedef struct {
+  int init;
+  void *gribHandle;
+}
+gribContainer_t;
 
-#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
+#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
 
-#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 <stdio.h>
+#include <sys/types.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
+#define  GRIB_MISSVAL  -9.E33
 
-#ifndef IS_EQUAL
-#  define IS_NOT_EQUAL(x,y) (x < y || y < x)
-#  define IS_EQUAL(x,y)     (!IS_NOT_EQUAL(x,y))
-#endif
+/* 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
 
-/* dummy use of unused parameters to silence compiler warnings */
-#ifndef UNUSED
-#  define  UNUSED(x) (void)(x)
-#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                                   */
 
-#define  JP23SET    0x7FFFFF  /* 2**23 - 1 (---> 8388607)  */
+/*
+ *  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                               */
 
-#define  POW_2_M24  0.000000059604644775390625  /*  pow(2.0, -24.0) */
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+/*
+ *  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
 
-#define intpow2(x) (ldexp(1.0, (x)))
 
-int gribrec_len(unsigned b1, unsigned b2, unsigned b3);
-int correct_bdslen(int bdslen, long recsize, long gribpos);
+#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    */
 
-/* CDI converter routines */
+#define  ISEC1_ECMWF_LocalExtension (isec1[36])
+#define  ISEC1_ECMWF_Class          (isec1[37])
 
-/* param format:  DDDCCCNNN */
 
-void    cdiDecodeParam(int param, int *dis, int *cat, int *num);
-int     cdiEncodeParam(int dis, int cat, int num);
+/*
+ *  Macros for the grid definition section ( Section 2 )
+ */
+#define  ISEC2_GridType             (isec2[ 0])  /* Data representation type */
 
-/* date format:  YYYYMMDD */
-/* time format:  hhmmss   */
+/* Triangular grids */
 
-void    cdiDecodeDate(int date, int *year, int *month, int *day);
-int     cdiEncodeDate(int year, int month, int day);
+#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)          */
 
-void    cdiDecodeTime(int time, int *hour, int *minute, int *second);
-int     cdiEncodeTime(int hour, int minute, int second);
+/* Spherical harmonic coeficients */
 
-/* CALENDAR types */
+#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                          */
 
-#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
+/* Gaussian grids */
 
-extern FILE *grprsm;
+#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     */
 
-extern int  CGRIBEX_Debug;
+/* 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               */
 
-void   gprintf(const char *caller, const char *fmt, ...);
 
-void   grsdef(void);
+#define  ISEC2_Reduced              (isec2[16])  /* 0: regular, 1: reduced grid                   */
 
-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);
+#define  ISEC2_RowLonPtr            (&isec2[22])
+#define  ISEC2_RowLon(i)            (isec2[22+i]) /* Number of points along each parallel         */
 
-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);
+/* */
 
-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);
-
-#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);
-#endif
-long   unpackInt64(const unsigned char *cp, unsigned INT64 *up, long bc, long tc);
+#define  ISEC2_LatSP                (isec2[12])  /* Latitude of the southern pole of rotation     */
+#define  ISEC2_LonSP                (isec2[13])  /* Longitude of the southern pole of rotation    */
 
-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);
+#define  FSEC2_RotAngle             (fsec2[ 0])  /* Angle of rotation                             */
+#define  FSEC2_StrFact              (fsec2[ 1])  /* Stretching factor                             */
 
-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);
+/*
+ *  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                  */
 
-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);
 
-#if defined (__cplusplus)
-}
+#ifdef __cplusplus
+extern "C" {
 #endif
 
-#endif  /* GRIB_INT_H */
-#ifndef _GRIBDECODE_H
-#define _GRIBDECODE_H
 
-#define  UNDEFINED          9.999e20
+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);
 
 
-#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))
+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);
 
-/* 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))
+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);
 
-#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')
 
-/* GRIB1 Section 0: Indicator Section (IS) */
+const char *cgribexLibraryVersion(void);
 
-#define  GRIB1_SECLEN(s)     GET_INT3(s[ 4], s[ 5], s[ 6])
-#define  GRIB_EDITION(s)     GET_UINT1(s[ 7])
+void  gribDebug(int debug);
+void  gribSetCalendar(int calendar);
 
-/* GRIB1 Section 1: Product Definition Section (PDS) */
+void  gribDateTime(int *isec1, int *date, int *time);
+int   gribRefDate(int *isec1);
+int   gribRefTime(int *isec1);
+int   gribTimeIsFC(int *isec1);
 
-#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])
+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);
 
+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);
 
-/* GRIB1 Section 2: Grid Description Section (GDS) */
+int   gribGetZip(long recsize, unsigned char *gribbuffer, long *urecsize);
 
-#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])
+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   gribOpen(const char *filename, const char *mode);
+void  gribClose(int fileID);
 
-/* 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])
+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);
 
-/* 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])
+int   grib_info_for_grads(off_t recpos, long recsize, unsigned char *gribbuffer, int *intnum, float *fltnum, off_t *bignum);
 
-/* 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])))
+double calculate_pfactor_float(const float* spectralField, long fieldTruncation, long subsetTruncation);
+double calculate_pfactor_double(const double* spectralField, long fieldTruncation, long subsetTruncation);
 
-/* 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])
 
-/* GRIB1 Section 3: Bit Map Section (BMS) */
+#if defined (__cplusplus)
+}
+#endif
 
-#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])
+#endif  /* _CGRIBEX_H */ 
 
-/* GRIB1 Section 4: Binary Data Section (BDS) */
+#if defined (HAVE_CONFIG_H)
+#endif
 
-#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])
+#include <stdarg.h>
+#include <ctype.h>
 
-/* GRIB1 Section 5: End Section (ES) */
+#ifdef HAVE_LIBNETCDF
+#endif
 
-/* GRIB2 */
+#if  defined  (HAVE_LIBCGRIBEX)
+#endif
 
-#define  GRIB2_SECLEN(section)   (GET_UINT4(section[0], section[1], section[2], section[3]))
-#define  GRIB2_SECNUM(section)   (GET_UINT1(section[4]))
+int cdiDefaultCalendar = CALENDAR_PROLEPTIC;
 
-#endif  /* _GRIBDECODE_H */
-#ifndef _GRIB_ENCODE_H
-#define _GRIB_ENCODE_H
+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;
 
+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;
 
-#define PutnZero(n) \
-{ \
-  for ( size_t i = z >= 0 ? (size_t)z : 0; i < (size_t)(z+n); i++ ) lGrib[i] = 0; \
-  z += n; \
-}
+char *cdiPartabPath   = NULL;
+int   cdiPartabIntern = 1;
 
-#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)))
+double cdiDefaultMissval = -9.E33;
 
-#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);}
+static const char Filetypes[][9] = {
+  "UNKNOWN",
+  "GRIB",
+  "GRIB2",
+  "NetCDF",
+  "NetCDF2",
+  "NetCDF4",
+  "NetCDF4c",
+  "SERVICE",
+  "EXTRA",
+  "IEG",
+  "HDF5",
+};
 
-#define Put1Real(Value)          \
-{                                \
-  confp3(Value, &exponent, &mantissa, BitsPerInt, 1); \
-  Put1Byte(exponent);            \
-  Put3Byte(mantissa);            \
-}
+int CDI_Debug   = 0;    /* If set to 1, debugging           */
+int CDI_Recopt = 0;
 
-#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 -openmp -DOMP_SIMD minmax_val.c
- result on hama2 (icc 16.0.0):
-     float:
-minmax_val: fmin: -500000  fmax: 499999  time:   0.63s
-    double:
-minmax_val: fmin: -500000  fmax: 499999  time:   2.98s
-orig      : fmin: -500000  fmax: 499999  time:   2.83s
-simd      : fmin: -500000  fmax: 499999  time:   2.82s
-avx       : fmin: -500000  fmax: 499999  time:   3.17s
+int cdiGribApiDebug     = 0;
+int cdiDefaultLeveltype = -1;
+int cdiDataUnreduced = 0;
+int cdiSortName = 0;
+int cdiHaveMissval = 0;
 
-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
 
-gcc -g -Wall -O3 -march=native -std=c99 -DTEST_MINMAXVAL -fopenmp -DOMP_SIMD 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
+static long cdiGetenvInt(const char *envName)
+{
+  char *envString;
+  long envValue = -1;
+  long fact = 1;
 
-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
+  envString = getenv(envName);
 
-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
+  if ( envString )
+    {
+      int loop, len;
 
-#include <stdlib.h>
+      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;
+	    }
+	}
 
-//#undef _GET_X86_COUNTER
-//#undef _GET_IBM_COUNTER
-//#undef _GET_MACH_COUNTER
-//#undef _ARCH_PWR6
+      if ( fact ) envValue = fact*atol(envString);
 
-#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
+      if ( CDI_Debug ) Message("set %s to %ld", envName, envValue);
+    }
 
-#if   defined(__GNUC__) && !defined(__ICC) && !defined(__clang__)
-#if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 4)
-#define GNUC_PUSH_POP
+  return (envValue);
+}
+
+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);
+}
+
+void cdiPrintVersion(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(__GNUC__) && (__GNUC__ >= 4)
-#elif defined(__ICC)    && (__ICC >= 1100)
-#elif defined(__clang__)
-#else
-#define DISABLE_SIMD
+#if  defined  (HAVE_LIBNETCDF)
+  fprintf(stderr, "  NetCDF library version : %s\n", cdfLibraryVersion());
 #endif
-
-#if !defined(TEST_MINMAXVAL)
-#define DISABLE_SIMD
+#if  defined  (HAVE_NC4HDF5)
+  fprintf(stderr, "    HDF5 library version : %s\n", hdfLibraryVersion());
 #endif
-
-#if defined(DISABLE_SIMD)
-# if defined(ENABLE_AVX)
-#  define _ENABLE_AVX
-# endif
-# if defined(ENABLE_SSE2)
-#  define _ENABLE_SSE2
-# endif
+#if  defined  (HAVE_LIBSERVICE)
+  fprintf(stderr, " SERVICE library version : %s\n", srvLibraryVersion());
 #endif
-
-#if !defined(DISABLE_SIMD)
-# if defined(__AVX__)
-#  define _ENABLE_AVX
-# endif
-# if defined(__SSE2__)
-#  define _ENABLE_SSE2
-# endif
+#if  defined  (HAVE_LIBEXTRA)
+  fprintf(stderr, "   EXTRA library version : %s\n", extLibraryVersion());
 #endif
-
-#include <float.h>
-#include <stdint.h>
-#include <inttypes.h>
-
-#if defined(_ENABLE_AVX)
-#include <immintrin.h>
-#elif defined(_ENABLE_SSE2)
-#include <emmintrin.h>
+#if  defined  (HAVE_LIBIEG)
+  fprintf(stderr, "     IEG library version : %s\n", iegLibraryVersion());
 #endif
+  fprintf(stderr, "    FILE library version : %s\n", fileLibraryVersion());
+}
 
-
-#if defined(_ENABLE_AVX)
-
-static
-void avx_minmax_val_double(const double *restrict buf, size_t nframes, double *min, double *max)
+void cdiDebug(int level)
 {
-  double fmin[4], fmax[4];
-  __m256d current_max, current_min, work;
-
-  // 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);
-
-  // Work input until "buf" reaches 32 byte alignment
-  while ( ((unsigned long)buf) % 32 != 0 && nframes > 0) {
+  if ( level == 1 || (level &  2) ) CDI_Debug = 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 ( CDI_Debug ) Message("debug level %d", level);
 
-  while (nframes >= 16) {
+  if ( level == 1 || (level &  4) ) memDebug(1);
 
-    (void) _mm_prefetch((const char *)(buf+8), _MM_HINT_NTA);
+  if ( level == 1 || (level &  8) ) fileDebug(1);
 
-    work = _mm256_load_pd(buf);
-    current_min = _mm256_min_pd(current_min, work);
-    current_max = _mm256_max_pd(current_max, work);
-    buf += 4;
+  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
+    }
 
-    work = _mm256_load_pd(buf);
-    current_min = _mm256_min_pd(current_min, work);
-    current_max = _mm256_max_pd(current_max, work);
-    buf += 4;
+  if ( CDI_Debug )
+    {
+      cdiPrintDefaults();
+      cdiPrintDatatypes();
+    }
+}
 
-    (void) _mm_prefetch((const char *)(buf+8), _MM_HINT_NTA);
 
-    work = _mm256_load_pd(buf);
-    current_min = _mm256_min_pd(current_min, work);
-    current_max = _mm256_max_pd(current_max, work);
-    buf += 4;
+int cdiHaveFiletype(int filetype)
+{
+  int status = 0;
 
-    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;
-  }
-
-  // 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;
-  }
-
-  // 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--;
-  }
+  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; }
+    }
 
-  // find min & max value through shuffle tricks
+  return (status);
+}
 
-  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 cdiDefTableID(int tableID)
+{
+  cdiDefaultTableID = tableID;
+  int modelID = cdiDefaultModelID = tableInqModel(tableID);
+  cdiDefaultInstID = modelInqInstitut(modelID);
+}
 
-  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);
+static
+void cdiSetChunk(const char *chunkAlgo)
+{
+  //char *pch;
+  //size_t len = strlen(chunkAlgo);
+  int algo = -1;
 
-  *min = fmin[0];
-  *max = fmax[0];
+  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 )
+    {
+      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);
 
-  return;
+  if ( algo != -1 )
+    {
+      cdiChunkType = algo;
+      if ( CDI_Debug ) Message("set ChunkAlgo to %s", chunkAlgo);
+    }
 }
 
-#elif defined(_ENABLE_SSE2)
 
-static
-void sse2_minmax_val_double(const double *restrict buf, size_t nframes, double *min, double *max)
+void cdiInitialize(void)
 {
-  __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 +
+  static int Init_CDI = FALSE;
+  char *envstr;
+  long value;
 
-    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;
-  }
+  if ( ! Init_CDI )
+    {
+      Init_CDI = TRUE;
 
-  // 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;
-  }
+#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
 
-  // 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--;
-  }
+      value = cdiGetenvInt("CDI_DEBUG");
+      if ( value >= 0 ) CDI_Debug = (int) value;
 
-  // 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);
+      value = cdiGetenvInt("CDI_GRIBAPI_DEBUG");
+      if ( value >= 0 ) cdiGribApiDebug = (int) value;
 
-  return;
-}
+      value = cdiGetenvInt("CDI_RECOPT");
+      if ( value >= 0 ) CDI_Recopt = (int) value;
 
-#endif // SIMD
+      value = cdiGetenvInt("CDI_REGULARGRID");
+      if ( value >= 0 ) cdiDataUnreduced = (int) value;
 
-#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
+      value = cdiGetenvInt("CDI_SORTNAME");
+      if ( value >= 0 ) cdiSortName = (int) value;
 
-  // to allow pipelining we have to unroll 
+      value = cdiGetenvInt("CDI_HAVE_MISSVAL");
+      if ( value >= 0 ) cdiHaveMissval = (int) value;
 
-  {
-    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];
+      value = cdiGetenvInt("CDI_LEVELTYPE");
+      if ( value >= 0 ) cdiDefaultLeveltype = (int) value;
 
-    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]);
-	  }
-      }
+      value = cdiGetenvInt("CDI_NETCDF_HDR_PAD");
+      if ( value >= 0 ) CDI_netcdf_hdr_pad = (size_t) value;
 
-    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]);
-      }
+      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);
 
-    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
+      envstr = getenv("CDI_CHUNK_ALGO");
+      if ( envstr ) cdiSetChunk(envstr);
 
-#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));
-#endif
+      envstr = getenv("SPLIT_LTYPE_105");
+      if ( envstr ) cdiSplitLtype105 = atoi(envstr);
 
-#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;
+      envstr = getenv("IGNORE_ATT_COORDINATES");
+      if ( envstr ) cdiIgnoreAttCoordinates = atoi(envstr);
 
-#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];
-    }
+      envstr = getenv("IGNORE_VALID_RANGE");
+      if ( envstr ) cdiIgnoreValidRange = atoi(envstr);
 
-  *fmin = dmin;
-  *fmax = dmax;
-}
+      envstr = getenv("CDI_SKIP_RECORDS");
+      if ( envstr )
+	{
+	  cdiSkipRecords = atoi(envstr);
+	  cdiSkipRecords = cdiSkipRecords > 0 ? cdiSkipRecords : 0;
+	}
 
-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;
+      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!");
+	    }
+	}
 
-#if   defined(CRAY)
-#pragma _CRI ivdep
-#elif defined(SX)
-#pragma vdir nodep
-#elif defined(__uxp__)
-#pragma loop novrec
-#elif defined (__ICC)
-#pragma ivdep
+      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
-  for ( size_t i = 0; i < datasize; ++i )
-    {
-      dmin = dmin < data[i] ? dmin : data[i];
-      dmax = dmax > data[i] ? dmax : data[i];
-    }
 
-  *fmin = dmin;
-  *fmax = dmax;
+      envstr = getenv("PARTAB_INTERN");
+      if ( envstr ) cdiPartabIntern = atoi(envstr);
+
+      envstr = getenv("PARTAB_PATH");
+      if ( envstr ) cdiPartabPath = strdup(envstr);
+    }
 }
-#if defined(GNUC_PUSH_POP)
-#pragma GCC pop_options
-#endif
 
-// TEST
-#if defined(OMP_SIMD)
 
-#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)
+const char *strfiletype(int filetype)
 {
-  double dmin = *fmin, dmax = *fmax;
+  const char *name;
+  int size = (int) (sizeof(Filetypes)/sizeof(char *));
 
-#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];
-    }
+  if ( filetype > 0 && filetype < size )
+    name = Filetypes[filetype];
+  else
+    name = Filetypes[0];
 
-  *fmin = dmin;
-  *fmax = dmax;
+  return (name);
 }
-#if defined(GNUC_PUSH_POP)
-#pragma GCC pop_options
-#endif
-#endif
 
-static
-void minmax_val_double(const double *restrict data, long idatasize, double *fmin, double *fmax)
+
+void cdiDefGlobal(const char *string, int val)
 {
-#if defined(_GET_X86_COUNTER) || defined(_GET_MACH_COUNTER) 
-  uint64_t start_minmax, end_minmax;
-#endif
-  size_t datasize = (size_t)idatasize;
+  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);
+}
 
-  if ( idatasize >= 1 ) ; else return;
 
-#if defined(_GET_X86_COUNTER) 
-  start_minmax = _rdtsc();
-#endif
-#if defined(_GET_MACH_COUNTER) 
-  start_minmax = mach_absolute_time();
-#endif
+void cdiDefMissval(double missval)
+{
+  cdiInitialize();
 
-#if defined(_ENABLE_AVX)
+  cdiDefaultMissval = missval;
+}
 
-  avx_minmax_val_double(data, datasize, fmin, fmax);
 
-#elif defined(_ENABLE_SSE2)
+double cdiInqMissval(void)
+{
+  cdiInitialize();
 
-  sse2_minmax_val_double(data, datasize, fmin, fmax);
+  return (cdiDefaultMissval);
+}
 
-#else
+/*
+ * 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(_ARCH_PWR6)
-#define __UNROLL_DEPTH_1 6
+#if defined (HAVE_CONFIG_H)
+#endif
 
-  // to allow pipelining we have to unroll 
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
 
-#if defined(_GET_IBM_COUNTER)
-  hpmStart(1, "minmax fsel");
-#endif
 
-  pwr6_minmax_val_double_unrolled6(data, datasize, fmin, fmax);
+void cdiDecodeParam(int param, int *pnum, int *pcat, int *pdis)
+{
+  unsigned uparam = (unsigned)param;
+  unsigned upnum;
 
-#if defined(_GET_IBM_COUNTER) 
-  hpmStop(1);
-#endif
+  *pdis = 0xff   & uparam;
+  *pcat = 0xff   & uparam >> 8;
+  upnum = 0xffff & uparam >> 16;
+  if ( upnum > 0x7fffU ) upnum = 0x8000U - upnum;
+  *pnum = (int)upnum;
+}
 
-#undef __UNROLL_DEPTH_1
 
-#else // original loop
+int cdiEncodeParam(int pnum, int pcat, int pdis)
+{
+  unsigned uparam, upnum;
 
-#if defined(_GET_IBM_COUNTER) 
-  hpmStart(1, "minmax base");
-#endif
+  if ( pcat < 0 || pcat > 255 ) pcat = 255;
+  if ( pdis < 0 || pdis > 255 ) pdis = 255;
 
-  minmax_val_double_orig(data, datasize, fmin, fmax);
+  upnum = (unsigned)pnum;
+  if ( pnum < 0 ) upnum = (unsigned)(0x8000 - pnum);
 
-#if defined(_GET_IBM_COUNTER) 
-  hpmStop(1);
-#endif
+  uparam = upnum << 16 | (unsigned)(pcat << 8) | (unsigned)pdis;
 
-#endif // _ARCH_PWR6 && original loop
-#endif // SIMD
+  return ((int)uparam);
+}
 
-#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
 
-  return;
+void cdiDecodeDate(int date, int *year, int *month, int *day)
+{
+
+  int iyear = date / 10000;
+  *year = iyear;
+  int idate = abs(date - iyear * 10000),
+    imonth = idate / 100;
+  *month = imonth;
+  *day   = idate - imonth * 100;
 }
 
-#if defined(TEST_MINMAXVAL)
 
-#include <stdio.h>
-#include <sys/time.h>
+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);
+}
 
-static
-double dtime()
+
+void cdiDecodeTime(int time, int *hour, int *minute, int *second)
 {
-  double tseconds = 0.0;
-  struct timeval mytime;
-  gettimeofday(&mytime, NULL);
-  tseconds = (double) (mytime.tv_sec + (double)mytime.tv_usec*1.0e-6);
-  return (tseconds);
+  int ihour = time / 10000,
+    itime = time - ihour * 10000,
+    iminute = itime / 100;
+  *hour   = ihour;
+  *minute = iminute;
+  *second = itime - iminute * 100;
 }
 
-#define NRUN 10000
 
-int main(void)
+int cdiEncodeTime(int hour, int minute, int second)
 {
-  long datasize = 1000000;
-  double t_begin, t_end;
+  int time = hour*10000 + minute*100 + second;
 
-#if   defined(_OPENMP)
-  printf("_OPENMP=%d\n", _OPENMP);
-#endif
+  return time;
+}
 
-#if   defined(__ICC)
-  printf("icc\n");
-#elif defined(__clang__)
-  printf("clang\n");
-#elif defined(__GNUC__)
-  printf("gcc\n");
-#endif
 
-  {
-    float fmin, fmax;
-    float *data_sp = (float*) malloc(datasize*sizeof(float));
+void cdiParamToString(int param, char *paramstr, int maxlen)
+{
+  int dis, cat, num;
+  int len;
 
-    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);
+  cdiDecodeParam(param, &num, &cat, &dis);
 
-    printf("float:\n");
+  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);
 
-    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);
-    free(data_sp);
-  }
+  if ( len >= maxlen || len < 0)
+    fprintf(stderr, "Internal problem (%s): size of input string is too small!\n", __func__);
+}
 
-  {
-    double fmin, fmax;
-    double *data_dp = (double*) malloc(datasize*sizeof(double));
 
-    // 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);
+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;
+}
 
-    printf("double:\n");
+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;
+}
 
-    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);
 
-    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);
+/*
+ * 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(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
+/* Automatically generated by m214003 at 2016-06-03, do not edit */
 
-#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);
+/* CGRIBEXLIB_VERSION="1.7.5" */
+
+#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
-    free(data_dp);
-  }
 
-  return (0);
-}
-#endif // TEST_MINMAXVAL
+#ifdef _ARCH_PWR6
+#pragma options nostrict
+#endif
 
-#undef DISABLE_SIMD
-#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.0):
-   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 defined (HAVE_CONFIG_H)
+#endif
 
-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: 3.96739s
-unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 4.30871s
-  double:
-    orig: val1: 1  val2: 1  val3: 2  valn: 66  time: 6.24448s
-unrolled: val1: 1  val2: 1  val3: 2  valn: 66  time: 8.66679s
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <inttypes.h>
 
-###
-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
 
-###
-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
+#ifndef _TEMPLATES_H
+#define _TEMPLATES_H
 
-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
+#define CAT(X,Y)      X##_##Y
+#define TEMPLATE(X,Y) CAT(X,Y)
 
-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
+#endif 
+#ifndef GRIB_INT_H
+#define GRIB_INT_H
 
-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
+#if defined (HAVE_CONFIG_H)
 #endif
 
-#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)
+#include <math.h>
+#include <float.h>
+
+
+#if ! defined   (_CGRIBEX_H)
+#endif
+#if ! defined   (_ERROR_H)
+#endif
+#if ! defined   (_DTYPES_H)
 #endif
 
-//#undef _GET_X86_COUNTER
-//#undef _GET_MACH_COUNTER
-//#undef _GET_IBM_COUNTER
-//#undef _ARCH_PWR6
+#if ! defined   (FALSE)
+#  define  FALSE  0
+#endif
 
-#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>
+#if ! defined   (TRUE)
+#  define  TRUE  1
 #endif
 
-#include <stdint.h>
+#if ! defined   (UCHAR)
+#  define  UCHAR  unsigned char
+#endif
 
-#if   defined(__GNUC__) && (__GNUC__ >= 4)
-#elif defined(__ICC)    && (__ICC >= 1100)
-#elif defined(__clang__)
+
+#if defined (CRAY) || defined (SX) || defined (__uxpch__)
+#  define VECTORCODE
+#endif
+
+
+#if defined (VECTORCODE)
+#if  defined  (INT32)
+#  define  GRIBPACK     unsigned INT32
+#  define  PACK_GRIB    packInt32
+#  define  UNPACK_GRIB  unpackInt32
 #else
-#define DISABLE_SIMD
+#  define  GRIBPACK     unsigned INT64
+#  define  PACK_GRIB    packInt64
+#  define  UNPACK_GRIB  unpackInt64
+#endif
+#else
+#  define  GRIBPACK     unsigned char
 #endif
 
-//#define DISABLE_SIMD
+#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])
 
-#ifdef DISABLE_SIMD
-# ifdef ENABLE_AVX
-#  define _ENABLE_AVX
-# endif
-# ifdef ENABLE_SSE4_1
-#  define _ENABLE_SSE4_1
-# endif
+#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 DISABLE_SIMD
-# ifdef __AVX__
-#  define _ENABLE_AVX
-# endif
-# ifdef __SSE4_1__
-#  define _ENABLE_SSE4_1
-# 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
 
-#if defined _ENABLE_AVX
-#include <immintrin.h>
-#elif defined _ENABLE_SSE4_1
-#include <smmintrin.h>
+/* dummy use of unused parameters to silence compiler warnings */
+#ifndef UNUSED
+#  define  UNUSED(x) (void)(x)
 #endif
 
-#if defined _ENABLE_AVX
+#define  JP23SET    0x7FFFFF  /* 2**23 - 1 (---> 8388607)  */
 
-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));
+#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 __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;  
+#define intpow2(x) (ldexp(1.0, (x)))
 
-  residual = datasize % 16;
+int gribrec_len(unsigned b1, unsigned b2, unsigned b3);
+int correct_bdslen(int 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 = _mm256_loadu_pd (dval);
-      d0 = _mm256_sub_pd (d0, c0);
-      d0 = _mm256_mul_pd (d0, c1);
-      d0 = _mm256_add_pd (d0, c2);
+/* param format:  DDDCCCNNN */
 
-      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    cdiDecodeParam(int param, int *pnum, int *pcat, int *pdis);
+int     cdiEncodeParam(int pnum, int pcat, int pdis);
 
-      //_____________________________________________________________________________
+/* date format:  YYYYMMDD */
+/* time format:  hhmmss   */
 
-      s0 = _mm_packus_epi32(i0, i1);
-      s0 = _mm_shuffle_epi8 (s0, swap);
-      (void) _mm_storeu_si128 (sgrib, s0);
+void    cdiDecodeDate(int date, int *year, int *month, int *day);
+int     cdiEncodeDate(int year, int month, int day);
 
-      //_____________________________________________________________________________
+void    cdiDecodeTime(int time, int *hour, int *minute, int *second);
+int     cdiEncodeTime(int hour, int minute, int second);
 
-      (void) _mm_prefetch((const char*)(dval+16), _MM_HINT_NTA);
+/* CALENDAR types */
 
-      //_____________________________________________________________________________
-      
-      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);
+#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
 
-      //_____________________________________________________________________________
-      
-      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);
+extern FILE *grprsm;
 
-      //_____________________________________________________________________________
+extern int  CGRIBEX_Debug;
 
-      s1 = _mm_packus_epi32(i2, i3);
-      s1 = _mm_shuffle_epi8 (s1, swap);
-      (void) _mm_storeu_si128 (sgrib+1, s1);
+void   gprintf(const char *caller, const char *fmt, ...);
 
-      //_____________________________________________________________________________
-           
-      dval += 16;
-      sgrib += 2;
-    }
+void   grsdef(void);
 
-  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;
+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);
 
-  return;
-}
+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 grib_encode_array_2byte_double avx_encode_array_2byte_double
+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);
 
-#elif defined _ENABLE_SSE4_1
+#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);
+#endif
+long   unpackInt64(const unsigned char *cp, unsigned INT64 *up, long bc, long tc);
 
-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));
+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);
 
-  const __m128i swap = _mm_set_epi8(14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1);
+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);
 
-  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;  
 
-  residual = datasize % 16;
+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);
 
-  for (i = 0; i < (datasize-residual); i += 16)
-    {
-      (void) _mm_prefetch((const char*)(dval+8), _MM_HINT_NTA);
-      //_____________________________________________________________________________
+#if defined (__cplusplus)
+}
+#endif
 
-      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);
+#endif  /* GRIB_INT_H */
+#ifndef _GRIBDECODE_H
+#define _GRIBDECODE_H
 
-      i0 = _mm_cvttpd_epi32 (d0);
-      i4 = _mm_cvttpd_epi32 (d4);  
-      i0 = _mm_unpacklo_epi64 (i0, i4);
+#define  UNDEFINED          9.999e20
 
-      //_____________________________________________________________________________
-      
-      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);
 
-      //_____________________________________________________________________________
+#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))
 
-      s0 = _mm_packus_epi32(i0, i1);
-      s0 = _mm_shuffle_epi8 (s0, swap);
-      (void) _mm_storeu_si128 (sgrib, s0);
+/* 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')
 
-      (void) _mm_prefetch((const char*)(dval+16), _MM_HINT_NTA);
+/* GRIB1 Section 0: Indicator Section (IS) */
 
-      //_____________________________________________________________________________
-      
-      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);
+#define  GRIB1_SECLEN(s)     GET_INT3(s[ 4], s[ 5], s[ 6])
+#define  GRIB_EDITION(s)     GET_UINT1(s[ 7])
 
-      //_____________________________________________________________________________
-      
-      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);
+/* GRIB1 Section 1: Product Definition Section (PDS) */
 
-      //_____________________________________________________________________________
+#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])
 
-      s1 = _mm_packus_epi32(i2, i3);
-      s1 = _mm_shuffle_epi8 (s1, swap);
-      (void) _mm_storeu_si128 (sgrib+1, s1);
 
-      //_____________________________________________________________________________
-           
-      dval += 16;
-      sgrib += 2;
-    }
+/* GRIB1 Section 2: Grid Description Section (GDS) */
 
-  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;
-	}
-    }
+#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])
 
-  *gz += 2*datasize;
-  
-  return;
-}
 
-#define grib_encode_array_2byte_double sse41_encode_array_2byte_double
+/* 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])
 
-#else
+/* 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])
 
-#define grib_encode_array_2byte_double encode_array_2byte_double
+/* 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])))
 
-#endif // SIMD variants
+/* 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])
 
+/* GRIB1 Section 3: Bit Map Section (BMS) */
 
-#ifdef TEST_ENCODE
+#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 CAT(X,Y)      X##_##Y
-#define TEMPLATE(X,Y) CAT(X,Y)
+/* GRIB1 Section 4: Binary Data Section (BDS) */
 
-#ifdef T
-#undef T
-#endif
-#define T double
+#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])
 
-#ifdef T
-#undef T
-#endif
-#define T float
+/* GRIB1 Section 5: End Section (ES) */
 
+/* GRIB2 */
 
-#include <sys/time.h>
+#define  GRIB2_SECLEN(section)   (GET_UINT4(section[0], section[1], section[2], section[3]))
+#define  GRIB2_SECNUM(section)   (GET_UINT1(section[4]))
 
-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);
-}
+#endif  /* _GRIBDECODE_H */
+#ifndef _GRIB_ENCODE_H
+#define _GRIB_ENCODE_H
 
-#define NRUN 10000
+#include <limits.h>
 
-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);
+#define PutnZero(n) \
+{ \
+  for ( size_t i = z >= 0 ? (size_t)z : 0; i < (size_t)(z+n); i++ ) lGrib[i] = 0; \
+  z += n; \
 }
 
-int main(void)
-{
-  long datasize = 1000000;
-  double t_begin, t_end;
+#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)))
 
-  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 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);}
 
-  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);
+enum {
+  BitsPerInt = (int) (sizeof(int) * CHAR_BIT),
+};
 
-  int PackStart = 0;
-  int nbpv = 16;
-  double zref = data[0];
-  size_t z;
-  double factor = 0.00390625;
-  int s = 256;
 
-  if ( 0 )
-    {
-      encode_array_float(0, 0, 0, NULL, NULL, 0, 0, NULL);
-      encode_array_double(0, 0, 0, NULL, NULL, 0, 0, NULL);
-    }
+#define Put1Real(Value)          \
+{                                \
+  confp3(Value, &exponent, &mantissa, BitsPerInt, 1); \
+  Put1Byte(exponent);            \
+  Put3Byte(mantissa);            \
+}
 
-#if   defined(__ICC)
-  printf("icc\n");
-#elif defined(__clang__)
-  printf("clang\n");
-#elif defined(__GNUC__)
-  printf("gcc\n");
-#endif
+#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
 
-  printf("float:\n");
+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
 
-  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);
+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
 
-  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);
+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
 
-  printf("double:\n");
+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
 
-  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);
+#include <stdlib.h>
 
-  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);
+//#undef _GET_X86_COUNTER
+//#undef _GET_IBM_COUNTER
+//#undef _GET_MACH_COUNTER
+//#undef _ARCH_PWR6
 
-#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);
+#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
 
-  return 0;
-}
-#endif // TEST_ENCODE
+#if   defined(__GNUC__) && !defined(__ICC) && !defined(__clang__)
+#if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 4)
+#define GNUC_PUSH_POP
+#endif
+#endif
 
-#undef DISABLE_SIMD
-#undef _ENABLE_AVX
-#undef _ENABLE_SSE4_1
+#ifndef DISABLE_SIMD
+#if   defined(__GNUC__) && (__GNUC__ >= 4)
+#elif defined(__ICC)    && (__ICC >= 1100)
+#elif defined(__clang__)
+#else
+#define DISABLE_SIMD
+#endif
+#endif
 
+#ifdef DISABLE_SIMD
+#define DISABLE_SIMD_MINMAXVAL
+#endif
 
-void confp3(double pval, int *kexp, int *kmant, int kbits, int kround)
-{
-  /*
+#if !defined(TEST_MINMAXVAL)
+#define DISABLE_SIMD_MINMAXVAL
+#endif
 
-    Purpose:
-    --------
+#ifdef DISABLE_SIMD_MINMAXVAL
+# if defined(ENABLE_AVX)
+#  define _ENABLE_AVX
+# endif
+# if defined(ENABLE_SSE2)
+#  define _ENABLE_SSE2
+# endif
+#endif
 
-    Convert floating point number from machine
-    representation to GRIB representation.
+#ifndef DISABLE_SIMD_MINMAXVAL
+# if defined(__AVX__)
+#  define _ENABLE_AVX
+# endif
+# if defined(__SSE2__)
+#  define _ENABLE_SSE2
+# endif
+#endif
 
-    Input Parameters:
-    -----------------
+#include <float.h>
+#include <stdint.h>
+#include <inttypes.h>
 
-       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).
-
-    Output Parameters:
-    ------------------
-
-       kexp    - 8 Bit signed exponent.
-       kmant   - 24 Bit mantissa.
-
-    Method:
-    -------
-
-    Floating point number represented as 8 bit signed
-    exponent and 24 bit mantissa in integer values.
-
-    Externals.
-    ----------
-
-    decfp2    - Decode from IBM floating point format.
-
-    Reference:
-    ----------
-
-    WMO Manual on Codes re GRIB representation.
-
-    Comments:
-    ---------
-
-    Routine aborts if an invalid conversion type parameter
-    is used or if a 24 bit mantissa is not produced.
+#if defined(_ENABLE_AVX)
+#include <immintrin.h>
+#elif defined(_ENABLE_SSE2)
+#include <emmintrin.h>
+#endif
 
-    Author:
-    -------
-     
-    John Hennessy   ECMWF   18.06.91
 
-    Modifications:
-    --------------
+#if defined(_ENABLE_AVX)
 
-    Uwe Schulzweida   MPIfM   01/04/2001
+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;
 
-    Convert to C from EMOS library version 130
+  // 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);
 
-    Uwe Schulzweida   MPIfM   02/08/2002
+  // Work input until "buf" reaches 32 byte alignment
+  while ( ((unsigned long)buf) % 32 != 0 && nframes > 0) {
 
-     - speed up by factor 1.6 on NEC SX6
-        - replace 1.0 / pow(16.0, (double)(iexp - 70)) by rpow16m70tab[iexp]
-  */
+    // 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--;
+  }
 
-  // extern int CGRIBEX_Debug;
+  while (nframes >= 16) {
 
-  /* ----------------------------------------------------------------- */
-  /*   Section 1 . Initialise                                          */
-  /* ----------------------------------------------------------------- */
+    (void) _mm_prefetch((const char *)(buf+8), _MM_HINT_NTA);
 
-  /*  Check conversion type parameter. */
+    work = _mm256_load_pd(buf);
+    current_min = _mm256_min_pd(current_min, work);
+    current_max = _mm256_max_pd(current_max, work);
+    buf += 4;
 
-  int iround = kround;
-  if ( iround != 0 && iround != 1 )
-    {
-      Error("Invalid conversion type = %d", iround);
+    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 rounding to 'up'. */
-     iround = 1;
-    }
+    (void) _mm_prefetch((const char *)(buf+8), _MM_HINT_NTA);
 
-  /* ----------------------------------------------------------------- */
-  /*   Section 2 . Convert value of zero.                              */
-  /* ----------------------------------------------------------------- */
+    work = _mm256_load_pd(buf);
+    current_min = _mm256_min_pd(current_min, work);
+    current_max = _mm256_max_pd(current_max, work);
+    buf += 4;
 
-  if ( ! (fabs(pval) > 0))
-    {
-      *kexp  = 0;
-      *kmant = 0;
-      // iexp   = 0;
-      // isign  = 0;
-      goto LABEL900;
-    }
+    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;
+  }
 
-  /* ----------------------------------------------------------------- */
-  /*   Section 3 . Convert other values.                               */
-  /* ----------------------------------------------------------------- */
-  {
-    double zeps = kbits != 32 ? 1.0e-12 : 1.0e-8;
-    double zref = pval;
+  // 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;
+  }
 
-    /*  Sign of value. */
+  // 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--;
+  }
 
-    int isign = zref >= 0.0 ? 0 : 128;
-    zref = fabs(zref);
+  // find min & max value through shuffle tricks
 
-    /*  Exponent. */
+  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);
 
-    int iexp = (int) (log(zref)/log(16.0) + 65.0 + zeps);
+  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);
 
-    /* only ANSI C99 has log2 */
-    /* iexp = (int) (log2(zref) * 0.25 + 65.0 + zeps); */
+  *min = fmin[0];
+  *max = fmax[0];
 
-    if ( iexp < 0   ) iexp = 0;
-    if ( iexp > 127 ) iexp = 127;
+  return;
+}
 
-    double rpowref;
-    /*
-      rpowref = zref / pow(16.0, (double)(iexp - 70));
-    */
+#elif defined(_ENABLE_SSE2)
 
-    rpowref = ldexp(zref, 4 * -(iexp - 70));
+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 +
 
-    /*  Mantissa. */
+    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;
+  }
 
-    if ( iround == 0 )
-    {
-      /*  Closest number in GRIB format less than original number. */
-      /*  Truncate for positive numbers. */
-      /*  Round up for negative numbers. */
+  // 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;
+  }
 
-      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). */
+  // 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--;
+  }
 
-      *kmant = (int)lround(rpowref);
-    }
+  // 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);
 
-    /*  Check that mantissa value does not exceed 24 bits. */
-    /*  If it does, adjust the exponent upwards and recalculate */
-    /*  the mantissa. */
-    /*  16777215 = 2**24 - 1 */
+  return;
+}
 
-    if ( *kmant > 16777215 )
-    {
+#endif // SIMD
 
-    LABEL350:
+#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
 
-      ++iexp;
+  // to allow pipelining we have to unroll 
 
-      /*  Check for exponent overflow during adjustment  */
+  {
+    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];
 
-      if ( iexp > 127 )
+    for ( j = 0; j < __UNROLL_DEPTH_1; j++) 
       {
-        Message("Exponent overflow");
-        Message("Original number = %30.20f", pval);
-        Message("Sign = %3d, Exponent = %3d, Mantissa = %12d",
-                isign, iexp, *kmant);
-
-        Error("Exponent overflow");
+	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]);
+	  }
+      }
 
-        /*  If not aborting, arbitrarily set value to zero  */
+    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]);
+      }
 
-        Message("Value arbitrarily set to zero.");
-        *kexp  = 0;
-        *kmant = 0;
-        // iexp  = 0;
-        // isign = 0;
-        goto LABEL900;
+    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
 
-      rpowref = ldexp(zref, 4 * -(iexp - 70));
+#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 ( iround == 0 )
-      {
-        /*  Closest number in GRIB format less than original number. */
-        /*  Truncate for positive numbers. */
-        /*  Round up for negative numbers. */
+#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;
 
-        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). */
+#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];
+    }
 
-        *kmant = (int)lround(rpowref);
-      }
+  *fmin = dmin;
+  *fmax = dmax;
+}
 
-      /*  Repeat calculation (with modified exponent) if still have */
-      /*  mantissa overflow. */
+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;
 
-      if ( *kmant > 16777215 ) goto LABEL350;
+#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];
     }
 
-    /*  Add sign bit to exponent. */
+  *fmin = dmin;
+  *fmax = dmax;
+}
+#if defined(GNUC_PUSH_POP)
+#pragma GCC pop_options
+#endif
 
-    *kexp = iexp + isign;
-  }
+// TEST
+#if defined(OMP_SIMD)
 
-  /* ----------------------------------------------------------------- */
-  /*   Section 9. Return                                               */
-  /* ----------------------------------------------------------------- */
+#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;
 
-LABEL900:
-  /*
-  if ( CGRIBEX_Debug )
+#if defined(_OPENMP)
+#pragma omp simd reduction(min:dmin) reduction(max:dmax)
+#endif
+  for ( size_t i = 0; i < datasize; ++i )
     {
-      double zval;
-
-      Message("Conversion type parameter = %4d", kround);
-      Message("Original number = %30.20f", pval);
+      dmin = dmin < data[i] ? dmin : data[i];
+      dmax = dmax > data[i] ? dmax : data[i];
+    }
 
-      zval = decfp2(*kexp, *kmant);
+  *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;
 
-      Message("Converted to      %30.20f", zval);
-      Message("Sign = %3d, Exponent = %3d, Mantissa = %12d", isign, iexp, *kmant);
+#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];
     }
-  */
-  return;
-} /* confp3 */
-#include <math.h>
 
+  *fmin = dmin;
+  *fmax = dmax;
+}
+#if defined(GNUC_PUSH_POP)
+#pragma GCC pop_options
+#endif
+#endif
 
-double decfp2(int kexp, int kmant)
+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;
 
-    Purpose:
-    --------
+  if ( idatasize >= 1 ) ; else return;
 
-    Convert GRIB representation of a floating point
-    number to machine representation.
+#if defined(_GET_X86_COUNTER) 
+  start_minmax = _rdtsc();
+#endif
+#if defined(_GET_MACH_COUNTER) 
+  start_minmax = mach_absolute_time();
+#endif
 
-    Input Parameters:
-    -----------------
+#if defined(_ENABLE_AVX)
 
-    kexp    - 8 Bit signed exponent.
-    kmant   - 24 Bit mantissa.
+  avx_minmax_val_double(data, datasize, fmin, fmax);
 
-    Output Parameters:
-    ------------------
+#elif defined(_ENABLE_SSE2)
 
-    Return value   - Floating point number represented
-                     by kexp and kmant.
+  sse2_minmax_val_double(data, datasize, fmin, fmax);
 
-    Method:
-    -------
+#else
 
-    Floating point number represented as 8 bit exponent
-    and 24 bit mantissa in integer values converted to
-    machine floating point format.
+#if defined(_ARCH_PWR6)
+#define __UNROLL_DEPTH_1 6
 
-    Externals:
-    ----------
+  // to allow pipelining we have to unroll 
 
-    None.
+#if defined(_GET_IBM_COUNTER)
+  hpmStart(1, "minmax fsel");
+#endif
 
-    Reference:
-    ----------
+  pwr6_minmax_val_double_unrolled6(data, datasize, fmin, fmax);
 
-    WMO Manual on Codes re GRIB representation.
+#if defined(_GET_IBM_COUNTER) 
+  hpmStop(1);
+#endif
 
-    Comments:
-    ---------
+#undef __UNROLL_DEPTH_1
 
-    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.
+#else // original loop
 
-    Author:
-    -------
-
-    John Hennessy   ECMWF   18.06.91
+#if defined(_GET_IBM_COUNTER) 
+  hpmStart(1, "minmax base");
+#endif
 
-    Modifications:
-    --------------
+  minmax_val_double_orig(data, datasize, fmin, fmax);
 
-    Uwe Schulzweida   MPIfM   01/04/2001
+#if defined(_GET_IBM_COUNTER) 
+  hpmStop(1);
+#endif
 
-     - Convert to C from EMOS library version 130
+#endif // _ARCH_PWR6 && original loop
+#endif // SIMD
 
-    Uwe Schulzweida   MPIfM   02/08/2002
+#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
 
-     - 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]
-  */
+  return;
+}
 
-  double pval;
-  //extern int CGRIBEX_Debug;
-  /* ----------------------------------------------------------------- */
-  /*   Section 1 . Convert value of 0.0. Ignore sign bit.              */
-  /* ----------------------------------------------------------------- */
+#if defined(TEST_MINMAXVAL)
 
-  //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;
-    }
+#include <stdio.h>
+#include <sys/time.h>
 
-  /* ----------------------------------------------------------------- */
-  /*   Section 2 . Convert other values.                               */
-  /* ----------------------------------------------------------------- */
+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);
+}
 
-  /*  Sign of value. */
+#define NRUN 10000
 
-  int iexp  = kexp,
-    isign = (iexp < 128) * 2 - 1;
+int main(void)
+{
+  long datasize = 1000000;
+  double t_begin, t_end;
 
-  iexp -= iexp < 128 ? 0 : 128;
+#if   defined(_OPENMP)
+  printf("_OPENMP=%d\n", _OPENMP);
+#endif
 
-  /*  Decode value. */
+#if   defined(__ICC)
+  printf("icc\n");
+#elif defined(__clang__)
+  printf("clang\n");
+#elif defined(__GNUC__)
+  printf("gcc\n");
+#endif
 
-  /* pval = isign * pow(2.0, -24.0) * kmant * pow(16.0, (double)(iexp - 64)); */
+  {
+    float fmin, fmax;
+    float *data_sp = (float*) malloc(datasize*sizeof(float));
 
-  iexp -= 64;
+    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);
 
-  pval = ldexp(1.0, 4 * iexp) * isign * POW_2_M24 * kmant;
+    printf("float:\n");
 
-  /* ----------------------------------------------------------------- */
-  /*   Section 9. Return to calling routine.                           */
-  /* ----------------------------------------------------------------- */
+    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);
 
-LABEL900:
+#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
 
-  //if ( CGRIBEX_Debug ) Message("Returned value = %f", pval);
+    free(data_sp);
+  }
 
-  return (pval);
-} /* decfp2 */
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdarg.h>
+  {
+    double fmin, fmax;
+    double *data_dp = (double*) malloc(datasize*sizeof(double));
 
+    // 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);
 
+    printf("double:\n");
 
-int gribRefDate(int *isec1)
-{
-  int date, ryear, rmonth, rday;
-  int century;
+    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);
 
-  century = ISEC1_Century;
-  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_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);
 
-  ryear   = ISEC1_Year;
+#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
 
-  /* if ( century != 0 ) */
-    {
-      if ( ryear == 100 )
-	{
-	  ryear = 0;
-	  century += 1;
-	}
+#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);
+  }
 
-      if ( ryear != 255 )
-	{
-	  ryear = century*100 + ryear;
-	  if ( ISEC1_Century < 0 ) ryear = -ryear;
-	}
-      else
-	ryear = 1;
-    }
+  return (0);
+}
+#endif // TEST_MINMAXVAL
 
-  rmonth  = ISEC1_Month;
-  rday    = ISEC1_Day;
+#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
 
-  date = cdiEncodeDate(ryear, rmonth, rday);
+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
 
-  return (date) ;
-}
+###
+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 gribRefTime(int *isec1)
-{
-  int time, rhour, rminute;
+###
+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
 
-  rhour   = ISEC1_Hour;
-  rminute = ISEC1_Minute;
+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
 
-  time = cdiEncodeTime(rhour, rminute, 0);
+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
 
-  return (time) ;
-}
+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
 
+#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
 
-int gribTimeIsFC(int *isec1)
-{
-  int isFC = FALSE;
-  int time_period;
+//#undef _GET_X86_COUNTER
+//#undef _GET_MACH_COUNTER
+//#undef _GET_IBM_COUNTER
+//#undef _ARCH_PWR6
 
-  if ( ISEC1_TimeRange == 10 )
-    time_period = (ISEC1_TimePeriod1<<8) + ISEC1_TimePeriod2;
-  else
-    time_period = ISEC1_TimePeriod1;
+#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
 
-  if ( time_period > 0 && ISEC1_Day > 0 )
-    {
-      if ( ISEC1_TimeRange == 0 || ISEC1_TimeRange == 10 ) isFC = TRUE;
-    }
+#include <stdint.h>
 
-  return (isFC);
-}
+#ifndef DISABLE_SIMD
+#if   defined(__GNUC__) && (__GNUC__ >= 4)
+#elif defined(__ICC)    && (__ICC >= 1100)
+#elif defined(__clang__)
+#else
+#define DISABLE_SIMD
+#endif
+#endif
 
+#ifdef DISABLE_SIMD
+#define DISABLE_SIMD_ENCODE
+#endif
 
-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;
+//#define DISABLE_SIMD_ENCODE
 
-  int century = ISEC1_Century;
-  int ryear   = ISEC1_Year;
+#ifdef DISABLE_SIMD_ENCODE
+# ifdef ENABLE_AVX
+#  define _ENABLE_AVX
+# endif
+# ifdef ENABLE_SSE4_1
+#  define _ENABLE_SSE4_1
+# endif
+#endif
 
-  if ( century == -255 && ryear == 127 )
-    {
-      century = 0;
-      ryear = 0;
-    }
-  else
-    {
-      if ( century < 0 ) century = -century;
-      century -= 1;
+#ifndef DISABLE_SIMD_ENCODE
+# ifdef __AVX__
+#  define _ENABLE_AVX
+# endif
+# ifdef __SSE4_1__
+#  define _ENABLE_SSE4_1
+# endif
+#endif
 
-      /* if ( century != 0 ) */
-      {
-        if ( ryear == 100 )
-          {
-            ryear = 0;
-            century += 1;
-          }
+#if defined _ENABLE_AVX
+#include <immintrin.h>
+#elif defined _ENABLE_SSE4_1
+#include <smmintrin.h>
+#endif
 
-        if ( ryear != 255 )
-          {
-            ryear = century*100 + ryear;
-            if ( ISEC1_Century < 0 ) ryear = -ryear;
-          }
-        else
-          ryear = 1;
-      }
-    }
+#if defined _ENABLE_AVX
 
-  int rmonth  = ISEC1_Month;
-  int rday    = ISEC1_Day;
+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));
 
-  int rhour   = ISEC1_Hour;
-  int rminute = ISEC1_Minute;
-  int second  = 0;
+  const __m128i swap = _mm_set_epi8(14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1);
 
-  /* printf("ref %d/%d/%d %d:%d\n", ryear, rmonth, rday, rhour, rminute); */
+  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 ( 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;
+  residual = datasize % 16;
 
-  if ( time_period > 0 && rday > 0 )
+  for (i = 0; i < (datasize-residual); i += 16)
     {
-      encode_caldaysec(grib_calendar, ryear, rmonth, rday, rhour, rminute, second, &julday, &secofday);
+      (void) _mm_prefetch((const char*)(dval+8), _MM_HINT_NTA);
+      //_____________________________________________________________________________
 
-      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;
-	}
+      d0 = _mm256_loadu_pd (dval);
+      d0 = _mm256_sub_pd (d0, c0);
+      d0 = _mm256_mul_pd (d0, c1);
+      d0 = _mm256_add_pd (d0, c2);
 
-      julday_add_seconds(addsec, &julday, &secofday);
+      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);
 
-      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);
+      //_____________________________________________________________________________
 
-  return;
-}
+      s0 = _mm_packus_epi32(i0, i1);
+      s0 = _mm_shuffle_epi8 (s0, swap);
+      (void) _mm_storeu_si128 (sgrib, s0);
 
+      //_____________________________________________________________________________
 
-void gprintf(const char *caller, const char *fmt, ...)
-{
-  va_list args;
+      (void) _mm_prefetch((const char*)(dval+16), _MM_HINT_NTA);
 
-  if ( grprsm == NULL ) Error("GRIBEX initialization missing!");
-	
-  va_start(args, fmt);
+      //_____________________________________________________________________________
+      
+      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);
 
-   fprintf(grprsm, "%-18s : ", caller);
-  vfprintf(grprsm, fmt, args);
-   fprintf(grprsm, "\n");
+      //_____________________________________________________________________________
+      
+      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);
 
-  va_end(args);
-}
+      //_____________________________________________________________________________
 
+      s1 = _mm_packus_epi32(i2, i3);
+      s1 = _mm_shuffle_epi8 (s1, swap);
+      (void) _mm_storeu_si128 (sgrib+1, s1);
 
-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;
+      //_____________________________________________________________________________
+           
+      dval += 16;
+      sgrib += 2;
+    }
 
-  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
+  if (i != datasize)
     {
-      Error("oper %c unsupported!", yfunc);
-      *kret=-9;
+      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 grib_encode_array_2byte_double avx_encode_array_2byte_double
 
-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)
+#elif defined _ENABLE_SSE4_1
+
+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) 
 {
-  int yfunc = *hoper;
+  size_t i, j, residual;
+  const double *dval = data;
+  __m128i *sgrib = (__m128i *) (lGrib+(*gz));
 
-  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' )
+  const __m128i swap = _mm_set_epi8(14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1);
+
+  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;  
+
+  residual = datasize % 16;
+
+  for (i = 0; i < (datasize-residual); i += 16)
     {
-      fprintf(stderr, " cgribex: Version is %s\n", cgribexLibraryVersion());
+      (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);
+
+      i0 = _mm_cvttpd_epi32 (d0);
+      i4 = _mm_cvttpd_epi32 (d4);  
+      i0 = _mm_unpacklo_epi64 (i0, i4);
+
+      //_____________________________________________________________________________
+      
+      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);
+
+      //_____________________________________________________________________________
+
+      s0 = _mm_packus_epi32(i0, i1);
+      s0 = _mm_shuffle_epi8 (s0, swap);
+      (void) _mm_storeu_si128 (sgrib, s0);
+
+      //_____________________________________________________________________________
+
+      (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;
     }
-  else
+
+  if (i != datasize) 
     {
-      Error("oper %c unsupported!", yfunc);
-      *kret=-9;
+      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;
+	}
     }
-}
 
-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 */
+  *gz += 2*datasize;
+  
+  return;
+}
 
-void gribSetDebug(int debug)
-{
-  CGRIBEX_Debug = debug;
+#define grib_encode_array_2byte_double sse41_encode_array_2byte_double
 
-  if ( CGRIBEX_Debug )
-    Message("debug level %d", debug);
-}
+#else
 
+#define grib_encode_array_2byte_double encode_array_2byte_double
 
-void gribFixZSE(int flag)
-{
-  CGRIBEX_Fix_ZSE = flag;
+#endif // SIMD variants
 
-  if ( CGRIBEX_Debug )
-    Message("Fix ZeroShiftError set to %d", flag);
-}
 
+#ifdef TEST_ENCODE
 
-void gribSetConst(int flag)
-{
-  CGRIBEX_Const = flag;
+#define CAT(X,Y)      X##_##Y
+#define TEMPLATE(X,Y) CAT(X,Y)
 
-  if ( CGRIBEX_Debug )
-    Message("Const set to %d", flag);
-}
+#ifdef T
+#undef T
+#endif
+#define T double
 
+#ifdef T
+#undef T
+#endif
+#define T float
 
-void gribSetRound(int round)
-{
-  UNUSED(round);
-}
 
+#include <sys/time.h>
 
-void gribSetRefDP(double refval)
+static
+double dtime()
 {
-  UNUSED(refval);
+  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
 
-void gribSetRefSP(float refval)
+static
+void pout(char *name, int s, unsigned char *lgrib, long datasize, double tt)
 {
-  gribSetRefDP((double) refval);
+  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);
 }
 
-
-void gribSetValueCheck(int vcheck)
+int main(void)
 {
-  UNUSED(vcheck);
-}
-#include <string.h>
-#include <math.h>
+  long datasize = 1000000;
+  double t_begin, t_end;
 
+  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));
 
+  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);
 
-void gribPrintSec0(int *isec0)
-{
-  /*
+  int PackStart = 0;
+  int nbpv = 16;
+  double zref = data[0];
+  size_t z;
+  double factor = 0.00390625;
+  int s = 256;
 
-    Print the information in the Indicator
-    Section (Section 0) of decoded GRIB data.
+  if ( 0 )
+    {
+      encode_array_float(0, 0, 0, NULL, NULL, 0, 0, NULL);
+      encode_array_double(0, 0, 0, NULL, NULL, 0, 0, NULL);
+    }
 
-    Input Parameters:
+#if   defined(__ICC)
+  printf("icc\n");
+#elif defined(__clang__)
+  printf("clang\n");
+#elif defined(__GNUC__)
+  printf("gcc\n");
+#endif
 
-       isec0 - Array of decoded integers from Section 0
+  printf("float:\n");
 
+  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);
 
-    Converted from EMOS routine GRPRS0.
+  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);
 
-       Uwe Schulzweida   MPIfM   01/04/2001
+  printf("double:\n");
 
-  */
+  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);
 
-  grsdef();
+  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);
 
-  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);
+#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
+
+  return 0;
 }
+#endif // TEST_ENCODE
 
-void gribPrintSec1(int *isec0, int *isec1)
+#undef DISABLE_SIMD_ENCODE
+#undef _ENABLE_AVX
+#undef _ENABLE_SSE4_1
+
+
+void confp3(double pval, int *kexp, int *kmant, int kbits, int kround)
 {
   /*
 
-    Print the information in the Product Definition
-    Section (Section 1) of decoded GRIB data.
+    Purpose:
+    --------
+
+    Convert floating point number from machine
+    representation to GRIB representation.
 
     Input Parameters:
+    -----------------
 
-       isec0 - Array of decoded integers from Section 0
+       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).
 
-       isec1 - Array of decoded integers from Section 1
+    Output Parameters:
+    ------------------
 
-    Comments:
+       kexp    - 8 Bit signed exponent.
+       kmant   - 24 Bit mantissa.
 
-       When decoding data from Experimental Edition or Edition 0,
-       routine GRIBEX adds the additional fields available in
-       Edition 1.
+    Method:
+    -------
 
+    Floating point number represented as 8 bit signed
+    exponent and 24 bit mantissa in integer values.
 
-    Converted from EMOS routine GRPRS1.
+    Externals.
+    ----------
 
-       Uwe Schulzweida   MPIfM   01/04/2001
+    decfp2    - Decode from IBM floating point format.
 
-  */
+    Reference:
+    ----------
 
-  int iprev, icurr, ioffset;
-  int ibit, ierr, iout, iyear;
-  int jloop, jiloop;
-  float value;
+    WMO Manual on Codes re GRIB representation.
 
-  char hversion[9];
-  /*
-  char hfirst[121], hsecond[121], hthird[121], hfourth[121];
-  */
+    Comments:
+    ---------
 
-  grsdef();
+    Routine aborts if an invalid conversion type parameter
+    is used or if a 24 bit mantissa is not produced.
 
-  /*
-    -----------------------------------------------------------------
-    Section 0 . Print required information.
-    -----------------------------------------------------------------
-  */
+    Author:
+    -------
+     
+    John Hennessy   ECMWF   18.06.91
 
-  fprintf(grprsm, " \n");
-  fprintf(grprsm, " Section 1 - Product Definition Section.\n");
-  fprintf(grprsm, " ---------------------------------------\n");
+    Modifications:
+    --------------
 
-  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]);
+    Uwe Schulzweida   MPIfM   01/04/2001
 
-  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]);
+    Convert to C from EMOS library version 130
 
-  /*
-      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
+    Uwe Schulzweida   MPIfM   02/08/2002
+
+     - speed up by factor 1.6 on NEC SX6
+        - replace 1.0 / pow(16.0, (double)(iexp - 70)) by rpow16m70tab[iexp]
   */
 
-  if ( isec1[5] != 127 )
-    {
-      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]);
-    }
-  else
-    {
-      fprintf(grprsm, " Satellite identifier.                %9d\n", isec1[6]);
-      fprintf(grprsm, " Spectral band.                       %9d\n", isec1[7]);
-    }
+  // extern int CGRIBEX_Debug;
 
-  iyear = isec1[9];
-  if ( iyear != 255 )
+  /* ----------------------------------------------------------------- */
+  /*   Section 1 . Initialise                                          */
+  /* ----------------------------------------------------------------- */
+
+  /*  Check conversion type parameter. */
+
+  int iround = kround;
+  if ( iround != 0 && iround != 1 )
     {
-      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);
+      Error("Invalid conversion type = %d", iround);
+
+      /*  If not aborting, arbitrarily set rounding to 'up'. */
+     iround = 1;
     }
-  else
+
+  /* ----------------------------------------------------------------- */
+  /*   Section 2 . Convert value of zero.                              */
+  /* ----------------------------------------------------------------- */
+
+  if ( ! (fabs(pval) > 0))
     {
-      fprintf(grprsm, " Year of reference time of data MISSING  (=255)\n");
+      *kexp  = 0;
+      *kmant = 0;
+      // iexp   = 0;
+      // isign  = 0;
+      goto LABEL900;
     }
 
-  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]);
+  /* ----------------------------------------------------------------- */
+  /*   Section 3 . Convert other values.                               */
+  /* ----------------------------------------------------------------- */
+  {
+    double zeps = kbits != 32 ? 1.0e-12 : 1.0e-8;
+    double zref = pval;
 
-  /*   Print sub-centre  */
-  fprintf(grprsm, " Sub-centre identifier.               %9d\n", ISEC1_SubCenterID);
+    /*  Sign of value. */
 
-  /*   Decimal scale factor  */
-  fprintf(grprsm, " Units decimal scaling factor.        %9d\n", isec1[22]);
+    int isign = zref >= 0.0 ? 0 : 128;
+    zref = fabs(zref);
 
-  /*
-    -----------------------------------------------------------------
-    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]);
-	}
-    }
-
-  /*
-    -----------------------------------------------------------------
-    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.  */
-
-      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]);
-	    }
-
-	  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);
+    /*  Exponent. */
 
-  /* Number of bytes/words to be processed in fast loop */
+    int iexp = (int) (log(zref)/log(16.0) + 65.0 + zeps);
 
-  inner -= trail;
-  inner /= ipack;
+    /* only ANSI C99 has log2 */
+    /* iexp = (int) (log2(zref) * 0.25 + 65.0 + zeps); */
 
-  ip0 = up + head;
-  ip1 = ip0 + 1;
-  ip2 = ip0 + 2;
-  ip3 = ip0 + 3;
+    if ( iexp < 0   ) iexp = 0;
+    if ( iexp > 127 ) iexp = 127;
 
-  up0 = (unsigned INT32 *) (cp + head);
+    double rpowref;
+    /*
+      rpowref = zref / pow(16.0, (double)(iexp - 70));
+    */
 
-  /* 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 
-   */
+    rpowref = ldexp(zref, 4 * -(iexp - 70));
 
-  j = 0;
+    /*  Mantissa. */
 
-  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
+    if ( iround == 0 )
     {
-      for ( i = 0 ; i < inner ; i++ )
-	{
-	  up0[i] =          (   ip3[j]          << 24 ) 
-	                 |  ( ( ip2[j] & 0xFF ) << 16 )
-                         |  ( ( ip1[j] & 0xFF ) <<  8 )
-                         |    ( ip0[j] & 0xFF ) ;
-	  j += ipack;
-	}
-    }
+      /*  Closest number in GRIB format less than original number. */
+      /*  Truncate for positive numbers. */
+      /*  Round up for negative numbers. */
 
-  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 ( isign == 0 )
+	*kmant = (int)rpowref;
+      else
+	*kmant = (int)lround(rpowref + 0.5);
     }
-
-  if ( tc != -1 )
+    else
     {
-      bc++;
-      *cp0 = (unsigned char) tc;
+      /*  Closest number in GRIB format to the original number   */
+      /*  (equal to, greater than or less than original number). */
+
+      *kmant = (int)lround(rpowref);
     }
 
-  return (bc);
-}
-#endif
+    /*  Check that mantissa value does not exceed 24 bits. */
+    /*  If it does, adjust the exponent upwards and recalculate */
+    /*  the mantissa. */
+    /*  16777215 = 2**24 - 1 */
 
-/* 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]; */
+    if ( *kmant > 16777215 )
+    {
 
-#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);
+    LABEL350:
 
-  UNUSED(tc);
+      ++iexp;
 
-  /* Bytes until first word boundary in source buffer */
+      /*  Check for exponent overflow during adjustment  */
 
-  head = ( (long) cp ) & (ipack-1);
-  if ( head != 0 ) head = ipack - head;
-  if ( head > bc ) head = bc;
+      if ( iexp > 127 )
+      {
+        Message("Exponent overflow");
+        Message("Original number = %30.20f", pval);
+        Message("Sign = %3d, Exponent = %3d, Mantissa = %12d",
+                isign, iexp, *kmant);
 
-  inner = bc - head;
+        Error("Exponent overflow");
 
-  /* Trailing bytes which do not make a full word */
- 
-  trail = inner & (ipack-1);
- 
-  /* Number of bytes/words to be processed in fast loop */
+        /*  If not aborting, arbitrarily set value to zero  */
 
-  inner -= trail;
-  inner /= ipack;
+        Message("Value arbitrarily set to zero.");
+        *kexp  = 0;
+        *kmant = 0;
+        // iexp  = 0;
+        // isign = 0;
+        goto LABEL900;
+      }
 
-  ip0 = up + head;
-  ip1 = ip0 + 1;
-  ip2 = ip0 + 2;
-  ip3 = ip0 + 3;
+      rpowref = ldexp(zref, 4 * -(iexp - 70));
 
-  up0 = (unsigned INT32 *) (cp + head);
+      if ( iround == 0 )
+      {
+        /*  Closest number in GRIB format less than original number. */
+        /*  Truncate for positive numbers. */
+        /*  Round up for negative numbers. */
 
-  /* Process any bytes until the first word boundary 
-   * of our source buffer 
-   */
-  for ( i = 0 ; i < head ; i++ ) up[i] = (unsigned INT32) cp[i];
+        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). */
 
-  j = 0;
+        *kmant = (int)lround(rpowref);
+      }
 
-  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;
+      /*  Repeat calculation (with modified exponent) if still have */
+      /*  mantissa overflow. */
 
-	  j += ipack;
-	}
+      if ( *kmant > 16777215 ) goto LABEL350;
     }
-  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;
-	}
-    }
+    /*  Add sign bit to exponent. */
 
-  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;
+    *kexp = iexp + isign;
   }
-  */
 
-  return (bc);
-}
-#endif
-#include <stdio.h>
+  /* ----------------------------------------------------------------- */
+  /*   Section 9. Return                                               */
+  /* ----------------------------------------------------------------- */
 
-void prtbin(int kin, int knbit, int *kout, int *kerr)
-{
+LABEL900:
   /*
+  if ( CGRIBEX_Debug )
+    {
+      double zval;
 
-    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.
-
-
-    Input Parameters:
-    
-       kin   - Integer variable containing binary number.
-
-       knbit - Number of bits in binary number.
-
-    Output Parameters:
-
-       kout  - Integer variable containing decimal value
-               with ones and zeroes corresponding to those of
-	       the input binary number.
-
-       kerr  - 0, If no error.
-               1, Number of bits in binary number exceeds
-	          maximum allowed or is less than 1.
-
-
-    Converted from EMOS routine PRTBIN.
-
-       Uwe Schulzweida   MPIfM   01/04/2001
+      Message("Conversion type parameter = %4d", kround);
+      Message("Original number = %30.20f", pval);
 
-  */
-  int idec;
-  int ik;
-  int itemp;
-  int j;
+      zval = decfp2(*kexp, *kmant);
 
-  /*
-    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;
+      Message("Converted to      %30.20f", zval);
+      Message("Sign = %3d, Exponent = %3d, Mantissa = %12d", isign, iexp, *kmant);
     }
-  else
-    *kerr = 0;
-  /*
-    -----------------------------------------------------------------
-    Section 1. Generate required number.
-    -----------------------------------------------------------------
   */
-  *kout = 0;
-  ik    = kin;
-  idec  = 1;
-
-  for ( j = 0; j < knbit; j++ )
-    {
-      itemp = ik - ( (ik/2)*2 );
-      *kout = (*kout) + itemp * idec;
-      ik    = ik / 2;
-      idec  = idec * 10;
-    }
-
   return;
-}
+} /* confp3 */
+#include <math.h>
 
 
-void ref2ibm(double *pref, int kbits)
+double decfp2(int kexp, int kmant)
 {
   /*
 
     Purpose:
     --------
 
-    Code and check reference value in IBM format
+    Convert GRIB representation of a floating point
+    number to machine representation.
 
     Input Parameters:
     -----------------
 
-    pref       - Reference value
-    kbits      - Number of bits per computer word.
+    kexp    - 8 Bit signed exponent.
+    kmant   - 24 Bit mantissa.
 
     Output Parameters:
     ------------------
 
-    pref       - Reference value
+    Return value   - Floating point number represented
+                     by kexp and kmant.
 
     Method:
     -------
 
-    Codes in IBM format, then decides to ensure that reference 
-    value used for packing is not different from that stored
-    because of packing differences.
+    Floating point number represented as 8 bit exponent
+    and 24 bit mantissa in integer values converted to
+    machine floating point format.
 
-    Externals.
+    Externals:
     ----------
 
-    confp3    - Encode into IBM floating point format.
-    decfp2    - Decode from IBM floating point format.
+    None.
 
     Reference:
     ----------
 
-    None.
+    WMO Manual on Codes re GRIB representation.
 
     Comments:
-    --------
+    ---------
 
-    None.
+    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.
 
     Author:
     -------
 
-    J.D.Chambers     ECMWF      17:05:94
+    John Hennessy   ECMWF   18.06.91
 
     Modifications:
     --------------
 
     Uwe Schulzweida   MPIfM   01/04/2001
 
-    Convert to C from EMOS library version 130
+     - Convert to C from EMOS library version 130
 
+    Uwe Schulzweida   MPIfM   02/08/2002
+
+     - 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]
   */
 
-  static int itrnd;
-  static int kexp, kmant;
-  static double ztemp, zdumm;
-  extern int CGRIBEX_Debug;
+  double pval;
+  //extern int CGRIBEX_Debug;
+  /* ----------------------------------------------------------------- */
+  /*   Section 1 . Convert value of 0.0. Ignore sign bit.              */
+  /* ----------------------------------------------------------------- */
+
+  //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;
+    }
 
   /* ----------------------------------------------------------------- */
-  /*   Section 1. Convert to and from IBM format.                      */
+  /*   Section 2 . Convert other values.                               */
   /* ----------------------------------------------------------------- */
 
-  /*  Convert floating point reference value to IBM representation. */
+  /*  Sign of value. */
 
-  itrnd = 1;
-  zdumm = ztemp = *pref;
-  confp3(zdumm, &kexp, &kmant, kbits, itrnd);
+  int iexp  = kexp,
+    isign = (iexp < 128) * 2 - 1;
 
-  if ( kexp == 0 && kmant == 0 ) return;
+  iexp -= iexp < 128 ? 0 : 128;
 
-  /*  Set reference value to that actually stored in the GRIB code. */
+  /*  Decode value. */
 
-  *pref = decfp2(kexp, kmant);
+  /* pval = isign * pow(2.0, -24.0) * kmant * pow(16.0, (double)(iexp - 64)); */
+
+  iexp -= 64;
+
+  pval = ldexp(1.0, 4 * iexp) * isign * POW_2_M24 * kmant;
+
+  /* ----------------------------------------------------------------- */
+  /*   Section 9. Return to calling routine.                           */
+  /* ----------------------------------------------------------------- */
+
+LABEL900:
+
+  //if ( CGRIBEX_Debug ) Message("Returned value = %f", pval);
+
+  return (pval);
+} /* decfp2 */
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdarg.h>
+
+
+
+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 ( ryear != 255 )
+	{
+	  ryear = century*100 + ryear;
+	  if ( ISEC1_Century < 0 ) ryear = -ryear;
+	}
+      else
+	ryear = 1;
+    }
+
+  rmonth  = ISEC1_Month;
+  rday    = ISEC1_Day;
+
+  date = cdiEncodeDate(ryear, rmonth, rday);
+
+  return (date) ;
+}
+
+
+int gribRefTime(int *isec1)
+{
+  int time, rhour, rminute;
+
+  rhour   = ISEC1_Hour;
+  rminute = ISEC1_Minute;
+
+  time = cdiEncodeTime(rhour, rminute, 0);
+
+  return (time) ;
+}
+
+
+int gribTimeIsFC(int *isec1)
+{
+  int isFC = FALSE;
+  int time_period;
+
+  if ( ISEC1_TimeRange == 10 )
+    time_period = (ISEC1_TimePeriod1<<8) + ISEC1_TimePeriod2;
+  else
+    time_period = ISEC1_TimePeriod1;
+
+  if ( time_period > 0 && ISEC1_Day > 0 )
+    {
+      if ( ISEC1_TimeRange == 0 || ISEC1_TimeRange == 10 ) isFC = TRUE;
+    }
+
+  return (isFC);
+}
+
+
+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;
+
+  int century = ISEC1_Century;
+  int ryear   = ISEC1_Year;
+
+  if ( century == -255 && ryear == 127 )
+    {
+      century = 0;
+      ryear = 0;
+    }
+  else
+    {
+      if ( century < 0 ) century = -century;
+      century -= 1;
+
+      /* if ( century != 0 ) */
+      {
+        if ( ryear == 100 )
+          {
+            ryear = 0;
+            century += 1;
+          }
+
+        if ( ryear != 255 )
+          {
+            ryear = century*100 + ryear;
+            if ( ISEC1_Century < 0 ) ryear = -ryear;
+          }
+        else
+          ryear = 1;
+      }
+    }
 
-  /*  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.                         */
+  int rmonth  = ISEC1_Month;
+  int rday    = ISEC1_Day;
 
-  if ( ztemp < *pref )
-    {
-      /*  Convert floating point to GRIB representation */
-      /*  using truncation to ensure that the converted */
-      /*  number is smaller than the original one.      */
+  int rhour   = ISEC1_Hour;
+  int rminute = ISEC1_Minute;
+  int second  = 0;
 
-      itrnd = 0;
-      zdumm = *pref = ztemp;
-      confp3(zdumm, &kexp, &kmant, kbits, itrnd);
+  /* printf("ref %d/%d/%d %d:%d\n", ryear, rmonth, rday, rhour, rminute); */
 
-      /*  Set reference value to that stored in the GRIB code. */
+  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;
 
-      *pref = decfp2(kexp, kmant);
+  if ( time_period > 0 && rday > 0 )
+    {
+      encode_caldaysec(grib_calendar, ryear, rmonth, rday, rhour, rminute, second, &julday, &secofday);
 
-      if ( ztemp < *pref )
+      addsec = 0;
+      switch ( ISEC1_TimeUnit )
 	{
-	  if ( CGRIBEX_Debug )
+	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 )
 	    {
-	      Message("Reference value error.");
-	      Message("Notify Met.Applications Section.");
-	      Message("ZTEMP = ", ztemp);
-	      Message("PREF = ", pref);
+	      gprintf(__func__, "Time unit %d unsupported", ISEC1_TimeUnit);
+	      lprint = FALSE;
 	    }
-	  *pref = ztemp;
+	  break;
 	}
-    }
-
-  return;
-} /* ref2ibm */
-#include <math.h>
-#include <string.h>
 
+      julday_add_seconds(addsec, &julday, &secofday);
 
-int correct_bdslen(int bdslen, long recsize, long gribpos)
-{
+      decode_caldaysec(grib_calendar, julday, secofday, &ryear, &rmonth, &rday, &rhour, &rminute, &second);
+    }
   /*
-    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.
+  printf("new %d/%d/%d %d:%d\n", ryear, rmonth, rday, rhour, rminute);
   */
-  if ( recsize > JP23SET ) bdslen = (int)(recsize - gribpos - bdslen);
-  return (bdslen);
+  *date = cdiEncodeDate(ryear, rmonth, rday);
+  *time = cdiEncodeTime(rhour, rminute, 0);
+
+  return;
 }
 
 
-int grib1Sections(unsigned char *gribbuffer, long gribbufsize, unsigned char **pdsp,
-		  unsigned char **gdsp, unsigned char **bmsp, unsigned char **bdsp, long *gribrecsize)
+void gprintf(const char *caller, const char *fmt, ...)
 {
-  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;
+  va_list args;
 
-  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);
-    }
+  if ( grprsm == NULL ) Error("GRIBEX initialization missing!");
+	
+  va_start(args, fmt);
 
-  recsize = gribrec_len(section[4], section[5], section[6]);
+   fprintf(grprsm, "%-18s : ", caller);
+  vfprintf(grprsm, fmt, args);
+   fprintf(grprsm, "\n");
 
-  gribversion = GRIB_EDITION(section);
-  if ( GRIB1_SECLEN(section) == 24 && gribversion == 0 ) gribversion = 0;
+  va_end(args);
+}
 
-  if ( gribversion == 1 )
-    grib1offset = 4;
-  else
-    grib1offset = 0;
 
-  pds = is + 4 + grib1offset;
-  bufpointer = pds + PDS_Len;
-  gribsize += 4 + grib1offset + PDS_Len;
+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 ( PDS_HAS_GDS )
+  if ( yfunc == 'C' )
     {
-      gds = bufpointer;
-      bufpointer += GDS_Len;
-      gribsize += GDS_Len;
+      grib_encode_double(isec0, isec1, isec2, fsec2, isec3,
+			 fsec3, isec4, fsec4, klenp, kgrib,
+			 kleng, kword, yfunc, kret);
     }
-  else
+  else if ( yfunc == 'D' || yfunc == 'J' || yfunc == 'R' )
     {
-      gds = NULL;
+      grib_decode_double(isec0, isec1, isec2, fsec2, isec3,
+			 fsec3, isec4, fsec4, klenp, kgrib,
+			 kleng, kword, yfunc, kret);
     }
-
-  if ( PDS_HAS_BMS )
+  else if ( yfunc == 'V' )
     {
-      bms = bufpointer;
-      bufpointer += BMS_Len;
-      gribsize += BMS_Len;
+      fprintf(stderr, "  cgribex: Version is %s\n", cgribexLibraryVersion());
     }
   else
     {
-      bms = NULL;
+      Error("oper %c unsupported!", yfunc);
+      *kret=-9;
     }
+}
 
-  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;
+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 ( gribbufsize < gribsize )
+  if ( yfunc == 'C' )
     {
-      fprintf(stderr, "Length of GRIB message is inconsistent (grib_buffer_size=%ld < grib_record_size=%ld)!\n", gribbufsize, gribsize);
-      return (1);
+      grib_encode_float(isec0, isec1, isec2, fsec2, isec3,
+			fsec3, isec4, fsec4, klenp, kgrib,
+			kleng, kword, yfunc, kret);
     }
-
-  /* end section - "7777" in ascii */
-  if ( !GRIB_FIN(bufpointer) )
+  else if ( yfunc == 'D' || yfunc == 'J' || yfunc == 'R' )
     {
-      fprintf(stderr, "Missing GRIB end section: found >%c%c%c%c<\n",
-	      bufpointer[0], bufpointer[1], bufpointer[2], bufpointer[3]);
-      return (-2);
+      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;
     }
-
-  return (0);
 }
 
+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 */
 
-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)
+void gribSetDebug(int debug)
 {
-  unsigned char *section;
-  long sec_len;
-  int sec_num;
-  int gribversion;
-  int i, msec;
-  long gribsize;
-  long grib_len = 0;
-
-  UNUSED(gribbufsize);
+  CGRIBEX_Debug = debug;
 
-  *idsp = NULL;
-  *lusp = NULL;
-  *gdsp = NULL;
-  *pdsp = NULL;
-  *drsp = NULL;
-  *bmsp = NULL;
-  *bdsp = NULL;
+  if ( CGRIBEX_Debug )
+    Message("debug level %d", debug);
+}
 
-  section = gribbuffer;
-  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 gribFixZSE(int flag)
+{
+  CGRIBEX_Fix_ZSE = flag;
 
-  gribversion = GRIB_EDITION(section);
-  if ( gribversion != 2 )
-    {
-      fprintf(stderr, "wrong GRIB version %d\n", gribversion);
-      return (-1);      
-    }
+  if ( CGRIBEX_Debug )
+    Message("Fix ZeroShiftError set to %d", flag);
+}
 
-  gribsize = 0;
-  for ( i = 0; i < 8; i++ ) gribsize = (gribsize << 8) | section[8+i];
 
-  grib_len += sec_len;
-  section  += sec_len;
+void gribSetConst(int flag)
+{
+  CGRIBEX_Const = flag;
 
-  /* section 1 */
-  sec_len = GRIB2_SECLEN(section);
-  sec_num = GRIB2_SECNUM(section);
-  //fprintf(stderr, "ids %d %ld\n", sec_num, sec_len);
+  if ( CGRIBEX_Debug )
+    Message("Const set to %d", flag);
+}
 
-  if ( sec_num != 1 )
-    {
-      fprintf(stderr, "Unexpected section1 number %d\n", sec_num);
-      return (-1);
-    }
 
-  *idsp = section;
+void gribSetRound(int round)
+{
+  UNUSED(round);
+}
 
-  grib_len += sec_len;
-  section  += sec_len;
 
-  /* section 2 and 3 */
-  sec_len = GRIB2_SECLEN(section);
-  sec_num = GRIB2_SECNUM(section);
-  //fprintf(stderr, "lus %d %ld\n", sec_num, sec_len);
+void gribSetRefDP(double refval)
+{
+  UNUSED(refval);
+}
 
-  if ( sec_num == 2 )
-    {
-      *lusp = section;
 
-      grib_len += sec_len;
-      section  += sec_len;
+void gribSetRefSP(float refval)
+{
+  gribSetRefDP((double) refval);
+}
 
-      /* section 3 */
-      sec_len = GRIB2_SECLEN(section);
-      //sec_num = GRIB2_SECNUM(section);
-      //fprintf(stderr, "gds %d %ld\n", sec_num, sec_len);
 
-      *gdsp = section;
-    }
-  else if ( sec_num == 3 )
-    {
-      *gdsp = section;
-    }
-  else
-    {
-      fprintf(stderr, "Unexpected section3 number %d\n", sec_num);
-      return (-1);
-    }
+void gribSetValueCheck(int vcheck)
+{
+  UNUSED(vcheck);
+}
+#include <string.h>
+#include <math.h>
 
-  grib_len += sec_len;
-  section  += sec_len;
 
-  /* section 4 */
-  sec_len = GRIB2_SECLEN(section);
-  sec_num = GRIB2_SECNUM(section);
-  //fprintf(stderr, "pds %d %ld\n", sec_num, sec_len);
 
-  if ( sec_num != 4 )
-    {
-      fprintf(stderr, "Unexpected section4 number %d\n", sec_num);
-      return (-1);
-    }
+void gribPrintSec0(int *isec0)
+{
+  /*
 
-  *pdsp = section;
+    Print the information in the Indicator
+    Section (Section 0) of decoded GRIB data.
 
-  grib_len += sec_len;
-  section  += sec_len;
+    Input Parameters:
 
-  /* section 5 */
-  sec_len = GRIB2_SECLEN(section);
-  sec_num = GRIB2_SECNUM(section);
-  //fprintf(stderr, "drs %d %ld\n", sec_num, sec_len);
+       isec0 - Array of decoded integers from Section 0
 
-  if ( sec_num != 5 )
-    {
-      fprintf(stderr, "Unexpected section5 number %d\n", sec_num);
-      return (-1);
-    }
 
-  *drsp = section;
+    Converted from EMOS routine GRPRS0.
 
-  grib_len += sec_len;
-  section  += sec_len;
+       Uwe Schulzweida   MPIfM   01/04/2001
 
-  /* section 6 */
-  sec_len = GRIB2_SECLEN(section);
-  sec_num = GRIB2_SECNUM(section);
-  //fprintf(stderr, "bms %d %ld\n", sec_num, sec_len);
+  */
 
-  if ( sec_num != 6 )
-    {
-      fprintf(stderr, "Unexpected section6 number %d\n", sec_num);
-      return (-1);
-    }
+  grsdef();
 
-  *bmsp = section;
+  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);
+}
 
-  grib_len += sec_len;
-  section  += sec_len;
+void gribPrintSec1(int *isec0, int *isec1)
+{
+  /*
 
-  /* section 7 */
-  sec_len = GRIB2_SECLEN(section);
-  sec_num = GRIB2_SECNUM(section);
-  //fprintf(stderr, "bds %d %ld\n", sec_num, sec_len);
+    Print the information in the Product Definition
+    Section (Section 1) of decoded GRIB data.
 
-  if ( sec_num != 7 )
-    {
-      fprintf(stderr, "Unexpected section7 number %d\n", sec_num);
-      return (-1);
-    }
+    Input Parameters:
 
-  *bdsp = section;
+       isec0 - Array of decoded integers from Section 0
 
-  grib_len += sec_len;
-  section  += sec_len;
+       isec1 - Array of decoded integers from Section 1
 
-  /* skip multi GRIB sections */
-  msec = 1;
-  while ( !GRIB_FIN(section) )
-    {
-      sec_len = GRIB2_SECLEN(section);
-      sec_num = GRIB2_SECNUM(section);
+    Comments:
 
-      if ( sec_num < 1 || sec_num > 7 ) break;
+       When decoding data from Experimental Edition or Edition 0,
+       routine GRIBEX adds the additional fields available in
+       Edition 1.
 
-      if ( sec_num == 7 )
-	fprintf(stderr, "Skipped unsupported multi GRIB section %d!\n", ++msec);
 
-      if ( (grib_len + sec_len) > gribsize ) break;
+    Converted from EMOS routine GRPRS1.
 
-      grib_len += sec_len;
-      section  += sec_len;
-    }
+       Uwe Schulzweida   MPIfM   01/04/2001
 
-  /* 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 iprev, icurr, ioffset;
+  int ibit, ierr, iout, iyear;
+  int jloop, jiloop;
+  float value;
 
+  char hversion[9];
+  /*
+  char hfirst[121], hsecond[121], hthird[121], hfourth[121];
+  */
 
-int grib_info_for_grads(off_t recpos, long recsize, unsigned char *gribbuffer,
-			int *intnum, float *fltnum, off_t *bignum)
-{
-  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;
+  grsdef();
 
-  section = gribbuffer;
-  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);
-    }
+  /*
+    -----------------------------------------------------------------
+    Section 0 . Print required information.
+    -----------------------------------------------------------------
+  */
 
-  gribversion = GRIB_EDITION(section);
-  if ( GRIB1_SECLEN(section) == 24 && gribversion == 0 ) gribversion = 0;
+  fprintf(grprsm, " \n");
+  fprintf(grprsm, " Section 1 - Product Definition Section.\n");
+  fprintf(grprsm, " ---------------------------------------\n");
 
-  if ( gribversion == 1 )
-    grib1offset = 4;
-  else
-    grib1offset = 0;
+  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]);
 
-  pds = is + 4 + grib1offset;
-  bufpointer = pds + PDS_Len;
-  gribsize += 4 + grib1offset + PDS_Len;
+  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]);
 
-  if ( PDS_HAS_GDS )
-    {
-      gds = bufpointer;
-      bufpointer += GDS_Len;
-      gribsize += GDS_Len;
-    }
-  else
-    {
-      gds = NULL;
-    }
+  /*
+      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 ( PDS_HAS_BMS )
+  if ( isec1[5] != 127 )
     {
-      bms = bufpointer;
-      bufpointer += BMS_Len;
-
-      bpos = recpos + gribsize + 6;
-
-      gribsize += BMS_Len;
+      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]);
     }
   else
     {
-      bms = NULL;
+      fprintf(grprsm, " Satellite identifier.                %9d\n", isec1[6]);
+      fprintf(grprsm, " Spectral band.                       %9d\n", isec1[7]);
     }
 
-  bds = bufpointer;
-
-  dpos = recpos + gribsize + 11;
-
-  bdslen = BDS_Len;
-  bdslen = correct_bdslen(bdslen, recsize, bds-gribbuffer);
-  bufpointer += bdslen;
-  gribsize += bdslen;
-  gribsize += 4;
-
-  if ( gribsize > recsize )
+  iyear = isec1[9];
+  if ( iyear != 255 )
     {
-      fprintf(stderr, "GRIB buffer size %ld too small! Min size = %ld\n", recsize, gribsize);
-      return (1);
+      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);
     }
-
-  /* end section - "7777" in ascii */
-  if ( !GRIB_FIN(bufpointer) )
+  else
     {
-      fprintf(stderr, "Missing end section >%2x %2x %2x %2x<\n",
-	      bufpointer[0], bufpointer[1], bufpointer[2], bufpointer[3]);
+      fprintf(grprsm, " Year of reference time of data MISSING  (=255)\n");
     }
 
-  {
-    int bs = BDS_BinScale;
-    if ( bs > 32767 ) bs = 32768-bs;
-    bsf = ldexpf(1.0f, bs);
-  }
-
-  bignum[0] = dpos;
-  bignum[1] = bms ? bpos : -999;
-  intnum[0] = BDS_NumBits;
-
-  /*  fltnum[0] = 1.0; */
-  fltnum[0] = powf(10.0f, (float)PDS_DecimalScale);
-  fltnum[1] = bsf;
-  fltnum[2] = (float)BDS_RefValue;
+  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]);
   /*
-  printf("intnum %d %d %d\n", intnum[0], intnum[1], intnum[2]);
-  printf("fltnum %g %g %g\n", fltnum[0], fltnum[1], fltnum[2]);
+     All ECMWF data in GRIB Editions before Edition 1 is decoded
+     as 20th century data. Other centres are decoded as missing.
   */
-  return (0);
-}
+  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]);
 
+  /*   Print sub-centre  */
+  fprintf(grprsm, " Sub-centre identifier.               %9d\n", ISEC1_SubCenterID);
 
-void grib1PrintALL(int nrec, long offset, long recpos, long recsize, unsigned char *gribbuffer)
-{
-  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;
+  /*   Decimal scale factor  */
+  fprintf(grprsm, " Units decimal scaling factor.        %9d\n", isec1[22]);
 
-  if ( header )
+  /*
+    -----------------------------------------------------------------
+    Section 1 . Print local DWD information.
+    -----------------------------------------------------------------
+  */
+  if ( (ISEC1_CenterID == 78 || ISEC1_CenterID == 215 || ISEC1_CenterID == 250) &&
+       (isec1[36] == 253     || isec1[36] == 254) )
     {
-      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;
+      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]);
+	}
     }
 
-  is = gribbuffer;
+  /*
+    -----------------------------------------------------------------
+    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.  */
 
-  if ( gribrec_len(is[4], is[5], is[6]) > JP23SET ) llarge = 1;
+      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");
 
-  long gribrecsize;
-  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;
-    }
+      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]);
 
-  if ( gds == NULL )
-    GridType = -1;
-  else
-    GridType = GDS_GridType;
+	  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]);
 
-  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;
+	  for (jloop = 0; jloop < isec1[52]; jloop++)
+	    fprintf(grprsm, " Forecast number                      %9d\n", isec1[jloop+53]);
 
-  bdslen = BDS_Len;
-  bdslen = correct_bdslen(bdslen, recsize, bds-gribbuffer);
+	  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]);
+	    }
 
-  if ( ((BDS_Flag >> 4)&1) && (BDS_Z == 128 || BDS_Z == 130) )
-    {
-      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;
-    }
+	  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(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');
+      fprintf(grprsm, " Number of ICE fields used:           %9d\n", isec1[45]);
 
-  if ( nerr > 0 ) fprintf(stdout, " <-- GRIB data corrupted!");
-  fprintf(stdout, "\n");
-}
+      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;
 
-void grib2PrintALL(int nrec, long offset, long recpos, long recsize, unsigned char *gribbuffer)
-{
-  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;
+	  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 ( 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 ( 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]);
 
-  is = gribbuffer;
+	    fprintf(grprsm, " Number of ICE fields used:           %9d\n", isec1[45]);
 
-  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;
+	    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");
+	      } 
+	  }
+	}
     }
-
-  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 ( (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;
-    }
+    -----------------------------------------------------------------
+    Section 3 . Print Washington ensemble product information.
+    -----------------------------------------------------------------
   */
-  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);
+    Washington EPS products (but not reformatted Washington EPS
+    products.
   */
-  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 gribPrintALL(int nrec, long offset, long recpos, long recsize, unsigned char *gribbuffer)
-{
-  int gribversion;
-
-  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 grib1PrintPDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
-{
-  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(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;
-
-  long gribrecsize;
-  nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
-  if ( nerr < 0 )
-    {
-      fprintf(stdout, "%5d : GRIB message error\n", nrec);
-      return;
-    }
-
-  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);
-    }
-
-  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]);
-
-  if ( year < 0 )
-    {
-      date = (-year)*10000+PDS_Month*100+PDS_Day;
-      century = -century;
-    }
-  else
+  if ( (isec1[1] == 7 && isec1[23] == 1) && (! (ISEC1_SubCenterID == 98)) )
     {
-      date =    year*10000+PDS_Month*100+PDS_Day;
+      /*   CALL KWPRS1 (iSEC0,iSEC1)*/
     }
-      
-  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");
-}
-
-
-void gribPrintPDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
-{
-  int gribversion;
-
-  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);
+    -----------------------------------------------------------------
+    Section 4 . Print local MPIM information.
+    -----------------------------------------------------------------
   */
-  else
+  if (isec1[ 1] == 252 && isec1[36] == 1)
     {
-      fprintf(stdout, "%5d :%4ld%9ld%7ld : GRIB version %d unsupported\n",
-	      nrec, 0L, recpos, recsize, gribversion); 
+      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 grib1PrintGDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
+void printQuasi(int *isec2)
 {
-  static int header = 1;
-  int nerr;
-  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
+  /*
 
-  UNUSED(recpos);
+    Print the qusai-regular information in the Grid Description
+    Section (Section 2) 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;
-    }
+       isec2 - Array of decoded integers from Section 2.
 
-  fprintf(stdout, "%5d :", nrec);
+    Comments:
 
-  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");
+       Only data representation types catered for are Gaussian
+       grid, latitude/longitude grid, Spherical Harmonics,
+       Polar stereographic and Space view perspective.
 
-  if ( nerr > 0 ) fprintf(stdout, " <-- GRIB data corrupted!");
-  fprintf(stdout, "\n");
-}
+    Converted from EMOS routine PTQUASI.
 
+       Uwe Schulzweida   MPIfM   01/04/2001
 
-void gribPrintGDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
-{
-  int gribversion;
+  */
 
-  gribversion = gribVersion(gribbuffer, (size_t)recsize);
+  char yout[64];
+  int nextlat, latcnt;
+  int j;
+  int ntos;
 
-  if ( gribversion == 0 || gribversion == 1 )
-    grib1PrintGDS(nrec, recpos, recsize, gribbuffer);
   /*
-  else if ( gribversion == 2 )
-    grib2PrintGDS(nrec, recpos, recsize, gribbuffer);
+    -----------------------------------------------------------------
+    Section 1. Print quasi-grid data.
+    -----------------------------------------------------------------
   */
-  else
-    {
-      fprintf(stdout, "%5d :%4ld%9ld%7ld : GRIB version %d unsupported\n",
-	      nrec, 0L, recpos, recsize, gribversion); 
-    }
-}
-
-
-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;
-
-  UNUSED(recpos);
-
-  if ( header )
-    {
-      fprintf(stdout, 
-      "  Rec : Code Level     BMS    Size\n");
-/*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
-      header = 0;
-    }
-
-  long gribrecsize;
-  nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
-  if ( nerr < 0 )
-    {
-      fprintf(stdout, "%5d : GRIB message error\n", nrec);
-      return;
-    }
-
-  if ( PDS_LevelType == 100 )
-    level = PDS_Level * 100;
-  else if ( PDS_LevelType == 99 )
-    level = PDS_Level;
-  else
-    level = PDS_Level1;
+  /*
+    See if scanning is north->south or south->north
+  */
+  fprintf(grprsm, "  Number of points along a parallel varies.\n");
 
-  fprintf(stdout, "%5d :", nrec);
+  ntos = ( fmod((double) isec2[10], 128.) < 64 );
 
-  if ( bms )
-    fprintf(stdout, "%4d%7d %7d %7d",
-	    PDS_Parameter, level,
-	    BMS_Len, BMS_BitmapSize);
+  if ( ntos )
+    fprintf(grprsm, "  Number of points.   Parallel. (North to South)\n");
   else
-    fprintf(stdout, "%4d%7d Bit Map Section not defined", PDS_Parameter, level);
-
-  if ( nerr > 0 ) fprintf(stdout, " <-- GRIB data corrupted!");
-  fprintf(stdout, "\n");
-}
+    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);
 
-void gribPrintBMS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
-{
-  int gribversion;
+  for ( j = 0; j < latcnt; j++ )
+    {
+      nextlat = nextlat + 1;
+      sprintf(yout, "%4d", nextlat);
 
-  gribversion = gribVersion(gribbuffer, (size_t)recsize);
+      /*       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;
 
-  if ( gribversion == 0 || gribversion == 1 )
-    grib1PrintBMS(nrec, recpos, recsize, gribbuffer);
-  /*
-  else if ( gribversion == 2 )
-    grib2PrintBMS(nrec, recpos, recsize, gribbuffer);
-  */
-  else
-    {
-      fprintf(stdout, "%5d :%4ld%9ld%7ld : GRIB version %d unsupported\n",
-	      nrec, 0L, recpos, recsize, gribversion); 
+    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 grib1PrintBDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
+void gribPrintSec2DP(int *isec0, int *isec2, double *fsec2)
 {
-  static int header = 1;
-  int level, nerr;
-  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
-  double cr = 1;
-  double refval, scale;
-
-  UNUSED(recpos);
-
-  if ( header )
-    {
-      fprintf(stdout, 
-      "  Rec : Code Level     BDS Flag     Scale   RefValue Bits  CR\n");
-/*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
-      header = 0;
-    }
+  /*
 
-  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 Grid Description
+    Section (Section 2) of decoded GRIB data.
 
-  if ( PDS_LevelType == 100 )
-    level = PDS_Level * 100;
-  else if ( PDS_LevelType == 99 )
-    level = PDS_Level;
-  else
-    level = PDS_Level1;
+    Input Parameters:
 
-  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;
-    }
+       isec0  - Array of decoded integers from Section 0
 
-  refval = BDS_RefValue;
+       isec2  - Array of decoded integers from Section 2
 
-  if ( BDS_BinScale < 0 )
-    scale = 1.0/pow(2.0, (double) -BDS_BinScale);
-  else
-    scale = pow(2.0, (double) BDS_BinScale);
+       fsec2  - Array of decoded floats from Section 2
 
-  if ( PDS_DecimalScale )
-    {
-      double decscale;
-      decscale = pow(10.0, (double)-PDS_DecimalScale);
-      refval *= decscale;
-      scale  *= decscale;
-    }
+    Comments:
 
-  fprintf(stdout, "%5d :", nrec);
+       Only data representation types catered for are Gaussian
+       grid, latitude/longitude grid, Spherical Harmonics,
+       Polar stereographic and Space view perspective.
 
-  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");
-}
+    Converted from EMOS routine GRPRS2.
 
+       Uwe Schulzweida   MPIfM   01/04/2001
 
-void gribPrintBDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
-{
-  int gribversion;
+  */
 
-  gribversion = gribVersion(gribbuffer, (size_t)recsize);
+  int i, ibit, iedit, ierr, iout, iresol;
 
-  if ( gribversion == 0 || gribversion == 1 )
-    grib1PrintBDS(nrec, recpos, recsize, gribbuffer);
+  grsdef();
   /*
-  else if ( gribversion == 2 )
-    grib2PrintBDS(nrec, recpos, recsize, gribbuffer);
+    -----------------------------------------------------------------
+    Section 1 . Print GRIB Edition number.
+    -----------------------------------------------------------------
   */
-  else
+  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, "%5d :%4ld%9ld%7ld : GRIB version %d unsupported\n",
-	      nrec, 0L, recpos, recsize, gribversion); 
+      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);
 
-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;
+      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]);
 
-  UNUSED(recpos);
+      ibit = 8;
+      iresol = isec2[5] + isec2[17] + isec2[18];
+      prtbin(iresol, ibit, &iout, &ierr);
 
-  long gribrecsize;
-  nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
-  if ( nerr < 0 )
-    {
-      fprintf(stdout, "%5d : GRIB message error\n", nrec);
-      return;
-    }
+      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");
 
-  if ( nerr > 0 )
-    {
-      fprintf(stdout, "%5d : <-- GRIB data corrupted!\n", nrec);
-      return;
-    }
+      fprintf(grprsm, " Number of parallels between pole and equator.%9d\n", isec2[9]);
 
-  if ( PDS_LevelType == 100 )
-    level = PDS_Level * 100;
-  else if ( PDS_LevelType == 99 )
-    level = PDS_Level;
-  else
-    level = PDS_Level1;
+      ibit = 8;
+      prtbin(isec2[10], ibit, &iout, &ierr);
 
-  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, " Scanning mode flags (Code Table 8)            %8.8d\n", iout);
+      fprintf(grprsm, " Number of vertical coordinate parameters.    %9d\n", isec2[11]);
+      goto LABEL800;
     }
-
-  if ( IS_EQUAL(cr, 1) && BDS_NumBits == 24 )
+  /*
+    -----------------------------------------------------------------
+    Section 4 . Print Latitude / longitude grid data.
+    -----------------------------------------------------------------
+  */
+  if ( isec2[0] ==  0 || isec2[0] == 10 || 
+       isec2[0] == 20 || isec2[0] == 30 )
     {
-      fprintf(stdout, "GRIB record %5d : code = %4d   level = %7d\n", nrec, PDS_Parameter, level);
-    }
-}
+      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]);
 
-static
-void repair1(unsigned char *gbuf, long gbufsize)
-{
-  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; */
+      ibit = 8;
+      iresol = isec2[5] + isec2[17] + isec2[18];
+      prtbin(iresol, ibit, &iout, &ierr);
 
-  long gribrecsize;
-  nerr = grib1Sections(gbuf, gbufsize, &pds, &gds, &bms, &bds, &gribrecsize);
-  if ( nerr < 0 )
-    {
-      fprintf(stdout, "GRIB message error\n");
-      return;
-    }
+      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 ( nerr > 0 )
+      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 data corrupted!\n");
-      return;
+      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;
     }
-
-  /* recLen = gribrec_len(gbuf[4], gbuf[5], gbuf[6]); */
-  /* if ( recLen > JP23SET ) llarge = TRUE; */
-
-  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 ( lspherc )
+  /*
+    -----------------------------------------------------------------
+    Section 6 . Print Lambert conformal data.
+    -----------------------------------------------------------------
+  */
+  if ( isec2[0] == 3 )
     {
-      if ( lcomplex  )
-	{
-	  int jup, ioff;
-	  jup  = bds[15];
-	  ioff = (jup+1)*(jup+2);
-	  bds_ext = 4 + 3 + 4*ioff;
-	}
-      else
-	{
-	  bds_ext = 4;
-	}
+      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;
     }
-
-  datstart = bds_head + bds_ext;
-
-  source = bds + datstart;
-
-  sourceLen = (size_t)(((((bds_len - datstart)*8-bds_ubits)/bds_nbits)*bds_nbits)/8);
-
-  if ( bds_nbits == 24 )
+  /*
+    -----------------------------------------------------------------
+    Section 7 . Print space view perspective or orthographic data.
+    -----------------------------------------------------------------
+  */
+  if ( isec2[0] == 90 )
     {
-      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);
+      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]);
 
-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;
+      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]);
 
-  long gribrecsize;
-  nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
-  if ( nerr < 0 )
+      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(stdout, "%5d : GRIB message error\n", nrec);
-      return;
+      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 ( nerr > 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(stdout, "%5d : <-- GRIB data corrupted!\n", nrec);
-      return;
+      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]);
     }
-
-  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 )
+  /*
+    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 )
     {
-      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, " \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]);
     }
-
-  if ( IS_EQUAL(cr, 1) && BDS_NumBits == 24 )
+  /*
+    Stretched grid information ...
+  */
+  if ( isec2[0] == 20 || isec2[0] == 30 || 
+       isec2[0] == 24 || isec2[0] == 34 || 
+       isec2[0] == 70 || isec2[0] == 80 )
     {
-      fprintf(stdout, "Repair GRIB record %5d : code = %4d   level = %7d\n", nrec, PDS_Parameter, level);
-      repair1(gribbuffer, recsize);
+      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;
 }
-#include <stdio.h>
-#include <string.h>
 
-#if defined (HAVE_CONFIG_H)
-#endif
+void gribPrintSec2SP(int *isec0, int *isec2, float  *fsec2sp)
+{
+  int inum;
+  int j;
+  double *fsec2;
+
+  inum = 10 + isec2[11];
 
-#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)
+  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);
 }
-#endif
 
-#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
+void gribPrintSec3DP(int *isec0, int *isec3, double *fsec3)
+{
+  /*
 
-#  define PIXELS_PER_BLOCK    (8)
-#  define PIXELS_PER_SCANLINE (PIXELS_PER_BLOCK*128)
+    Print the information in the Bit-Map Section
+    (Section 3) of decoded GRIB data.
 
-#  define MIN_COMPRESS        (0.95)
-#  define MIN_SIZE            (256)
-#endif
+    Input Parameters:
 
-#define  Z_SZIP  128
-#define  Z_AEC   130
+       isec0  - Array of decoded integers from Section 0
 
+       isec3  - Array of decoded integers from Section 3
 
-#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      )))
+       fsec3  - Array of decoded floats from Section 3
 
 
-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;
+    Converted from EMOS routine GRPRS3.
 
-  int gribversion = gribVersion(gribbuffer, (size_t)recsize);
+       Uwe Schulzweida   MPIfM   01/04/2001
 
-  if ( gribversion == 2 ) return (compress);
+  */
 
-  long gribrecsize;
-  nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
-  if ( nerr < 0 )
-    {
-      fprintf(stdout, "GRIB message error\n");
-      return (compress);
-    }
+  UNUSED(isec0);
 
-  if ( nerr > 0 )
-    {
-      fprintf(stdout, "GRIB data corrupted!\n");
-      return (compress);
-    }
+  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;
+  fprintf(grprsm, " \n");
+  fprintf(grprsm, " Section 3 - Bit-map Section.\n");
+  fprintf(grprsm, " -------------------------------------\n");
 
-  *urecsize = 0;
-  if ( lcompress )
-    {
-      compress = BDS_Z;
-      if ( compress == Z_SZIP || compress == Z_AEC )
-	{
-	  gribsize = gribrec_len(bds[14], bds[15], bds[16]);
-	}
-    }
+  if ( isec3[0] != 0 )
+    fprintf(grprsm, " Predetermined bit-map number.                %9d\n", isec3[0]);
+  else
+    fprintf(grprsm, " No predetermined bit-map.\n");
 
-  *urecsize = gribsize;
+  fprintf(grprsm, " Missing data value for integer data.    %14d\n", isec3[1]);
 
-  return (compress);
+  fprintf(grprsm, " Missing data value for real data. %20.6g\n", fsec3[1]);
 }
 
-
-int  gribZip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize)
+void gribPrintSec3SP(int *isec0, int *isec3, float  *fsec3sp)
 {
-  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;
+  double fsec3[2];
 
-  gribLen = gribrec_len(dbuf[4], dbuf[5], dbuf[6]);
-  if ( gribLen > JP23SET ) llarge = TRUE;
+  fsec3[0] = fsec3sp[0];
+  fsec3[1] = fsec3sp[1];
+  
+  gribPrintSec3DP(isec0, isec3, fsec3);
+}
 
-  rec_len = gribLen;
+void gribPrintSec4DP(int *isec0, int *isec4, double *fsec4)
+{
+  /*
 
-  long gribrecsize;
-  nerr = grib1Sections(dbuf, dbufsize, &pds, &gds, &bms, &bds, &gribrecsize);
-  if ( nerr < 0 )
-    {
-      fprintf(stdout, "GRIB message error\n");
-      return (rec_len);
-    }
+    Print the information in the Binary Data Section
+    (Section 4) of decoded GRIB data.
 
-  if ( nerr > 0 )
-    {
-      fprintf(stdout, "GRIB data corrupted!\n");
-      return (rec_len);
-    }
+    Input Parameters:
 
-#if  defined (HAVE_LIBSZ) || defined (HAVE_LIBAEC)
+       isec0  - Array of decoded integers from Section 0
 
-  {
-    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;
+       isec4  - Array of decoded integers from Section 4
 
-    bds_zstart  = 14;
-    bds_zoffset = 12;
-    if ( llarge ) bds_zoffset += 2;
+       fsec4  - Array of decoded floats from Section 4
 
-    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 defined (HAVE_LIBSZ)
-    if ( bds_nbits == 24 )
-      bits_per_sample    = 8;
-    else
-#endif
-      bits_per_sample    = bds_nbits;
+    Converted from EMOS routine GRPRS4.
 
-#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
+       Uwe Schulzweida   MPIfM   01/04/2001
 
-    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;
-	  }
-      }
+  */
+  int inum;
+  int j;
 
-    datstart = bds_head + bds_ext;
+  UNUSED(isec0);
 
-    datsize = ((((bds_len - datstart)*8-bds_ubits)/bds_nbits)*bds_nbits)/8;
+  grsdef();
 
-    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;
+  /*
+    -----------------------------------------------------------------
+    Section 1 . Print integer information from isec4.
+    -----------------------------------------------------------------
+  */
+  fprintf(grprsm, " \n");
+  fprintf(grprsm, " Section 4 - Binary Data  Section.\n");
+  fprintf(grprsm, " -------------------------------------\n");
 
-#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
+  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.
+    -----------------------------------------------------------------
+  */
 
-#if defined (HAVE_LIBAEC)
-    strm.next_in = source;
-    strm.avail_in = sourceLen;
-    strm.next_out = dest;
-    strm.avail_out = destLen;
+  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);
 
-    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);
-      }
+  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
+      */
+    }
+}
 
-    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 gribPrintSec4SP(int *isec0, int *isec4, float  *fsec4sp)
+{
+  int inum;
+  int j;
+  double fsec4[20];
 
-	BDS_Flag -= bds_ubits;
-    
-	gribLenOld = gribLen;
+  inum = isec4[0];
+  if ( inum <  0 ) inum = -inum;
+  if ( inum > 20 ) inum = 20;
 
-	if ( bds_ext )
-	  for ( i = bds_ext-1; i >= 0; --i )
-	    bds[bds_zoffset+bds_head+i] = bds[bds_head+i];
+  for ( j = 0; j < inum; j++ ) fsec4[j] = fsec4sp[j];
+  
+  gribPrintSec4DP(isec0, isec4, fsec4);
+}
 
-	/*
-	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;
+void gribPrintSec4Wave(int *isec4)
+{
+  /*
 
-	    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);
-	  }
+    Print the wave coordinate information in the Binary Data
+    Section (Section 4) of decoded GRIB data.
 
-	bdsLen = datstart + bds_zoffset + destLen;
+    Input Parameters:
 
-	bds[11] = 0;
-	bds[12] = 0;
-#if defined (HAVE_LIBAEC)
-	BDS_Z   = Z_AEC;
-#else
-	BDS_Z   = Z_SZIP;
-#endif
+       isec4 - Array of decoded integers from Section 4
 
-	BDS_Flag += 16;
-	if ( (bdsLen%2) == 1 )
-	  {
-	    BDS_Flag += 8;
-	    bds[bdsLen++] = 0;
-	  }
+    Comments:
 
-	SetLen3(bds, 0, bdsLen);
+       Wave coordinate information held in isec4 are 32-bit floats,
+       hence the PTEMP and NTEMP used for printing are 4-byte variables.
 
-	gribLen = (bds - dbuf) + bdsLen;
 
-	dbuf[gribLen++] = '7';
-	dbuf[gribLen++] = '7';
-	dbuf[gribLen++] = '7';
-	dbuf[gribLen++] = '7';
+    Converted from EMOS routine GRPRS4W.
 
-	if ( llarge )
-	  {
-	    long itemp;
-	    long bdslen = gribLen - 4;
+       Uwe Schulzweida   MPIfM   01/04/2001
 
-	    /*
-	      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;
+  */
+  int    jloop;
+  int    ntemp[100];
+  float *ptemp;
 
-	    itemp = gribLen / (-120);
-	    itemp = JP23SET - itemp + 1;
+  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
 
-	    SetLen3(dbuf, 4, itemp);
+#include <string.h>
+#include <ctype.h>
 
-	    bdslen = gribLen - bdslen;
 
-	    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);
-    */
-  }
 
-#else
-  
-  UNUSED(sbuf);
-  UNUSED(sbufsize);
+int gribOpen(const char *filename, const char *mode)
+{
+  int fileID = fileOpen(filename, mode);
 
-  if ( libszwarn )
+#if defined (__sun)
+  if ( fileID != FILE_UNDEFID && tolower(*mode) == 'r' )
     {
-      Warning("Compression disabled, szlib or libaec not available!");
-      libszwarn = 0;
+      fileSetBufferType(fileID, FILE_BUFTYPE_MMAP);
     }
 #endif
 
-  if ( llarge )
-    while ( gribLen%120 ) dbuf[gribLen++] = 0;
-  else
-    while ( gribLen & 7 ) dbuf[gribLen++] = 0;
+  return fileID;  
+}
 
-  rec_len = gribLen;
 
-  return (rec_len);
+void gribClose(int fileID)
+{
+  fileClose(fileID);
 }
 
 
-int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize)
+off_t gribGetPos(int fileID)
 {
-#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;
+  return fileGetPos(fileID);
+}
 
-  UNUSED(dbufsize);
 
-  long gribrecsize;
-  int nerr = grib1Sections(sbuf, sbufsize, &pds, &gds, &bms, &bds, &gribrecsize);
-  if ( nerr < 0 )
+int gribCheckFiletype(int fileID)
+{
+  int found = 0;
+  char buffer[4];
+
+  if ( fileRead(fileID, buffer, 4) != 4 ) return found;
+
+  if ( memcmp(buffer, "GRIB", 4) == 0 )
     {
-      fprintf(stdout, "GRIB message error\n");
-      return (0);
+      found = 1;
+      if ( CGRIBEX_Debug ) Message("found GRIB file = %s", fileInqName(fileID));
     }
-
-  if ( nerr > 0 )
+  else
     {
-      fprintf(stdout, "GRIB data corrupted!\n");
-      return (0);
+      long offset;
+      int ierr = gribFileSeek(fileID, &offset);
+      fileRewind(fileID);
+      if ( !ierr )
+	{
+	  found = 1;
+	  if ( CGRIBEX_Debug ) Message("found seek GRIB file = %s", fileInqName(fileID));
+	}
     }
 
-  bds_zstart = 14;
-
-  int recLen = gribrec_len(bds[bds_zstart], bds[bds_zstart+1], bds[bds_zstart+2]);
-  if ( recLen > JP23SET ) llarge = TRUE;
+  return found;
+}
 
-  bds_zoffset = 12;
-  if ( llarge ) bds_zoffset += 2;
 
-  /* 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; */
+int gribCheckSeek(int fileID, long *offset, int *version)
+{
+  int ierr = gribFileSeek(fileID, offset);
 
-  if ( lspherc )
+  *version = -1;
+  if ( !ierr )
     {
-      if ( lcomplex  )
-	{
-	  int jup, ioff;
-	  jup  = bds[bds_zoffset+15];
-	  ioff = (jup+1)*(jup+2);
-	  bds_ext = 4 + 3 + 4*ioff;
-	}
-      else
-	{
-	  bds_ext = 4;
-	}
+      char buffer[4];
+     if ( fileRead(fileID, buffer, 4) == 4 )
+	*version = buffer[3];
     }
 
-  size_t datstart = bds_head + (size_t)bds_ext;
+  return ierr;
+}
 
-  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 )
+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)
     {
-      fprintf(stdout, "GRIB message error\n");
-      return (0);
+      int ch = filePtrGetc(fileptr);
+      if ( ch == EOF ) return (-1);
+      buffer[i] = (unsigned char)ch;
     }
+  /*
+  fileRead(fileID, buffer, 4);
+  */
 
-  if ( nerr > 0 )
+  while ( retry-- )
     {
-      fprintf(stdout, "GRIB data corrupted!\n");
-      return (0);
+      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];
     }
 
-  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]));
+  if ( CGRIBEX_Debug ) Message("record offset = %d", (int) *offset);
 
-  BDS_Flag = (unsigned char)(BDS_Flag - 16);
+  return 1;
+}
 
-  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
+int gribFileSeek(int fileID, long *offset)
+{
+  /* position file pointer after GRIB */
+  const long GRIB = 0x47524942;
+  long code = 0;
+  int ch;
+  int retry = 4096*4096;
 
-#if defined (HAVE_LIBSZ)
-    if ( bds_nbits == 24 )
-      bits_per_sample    = 8;
-    else
-#endif
-      bits_per_sample    = bds_nbits;
+  *offset = 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
+  void *fileptr = filePtr(fileID);
 
-    if ( bds_ext )
-      for ( i = 0; i < bds_ext; ++i )
-	bds[bds_head+i] = bds[bds_zoffset+bds_head+i];
+  while ( retry-- )
+    {
+      ch = filePtrGetc(fileptr);
+      if ( ch == EOF ) return (-1);
+    
+      code = ( (code << 8) + ch ) & 0xFFFFFFFF;
 
-    /*
-    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);
-    */
+      if ( code == GRIB )
+	{
+	  if ( CGRIBEX_Debug )
+	    Message("record offset = %d", (int) *offset);
+	  return (0);
+	}
 
-    tmpLen = destLen;
-#if defined (HAVE_LIBAEC)
-    strm.next_in   = source;
-    strm.avail_in  = sourceLen;
-    strm.next_out  = dest;
-    strm.avail_out = tmpLen;
+      (*offset)++;
+    }
 
-    status = aec_buffer_decode(&strm);
-    if ( status != AEC_OK )
-      Warning("AEC ERROR: %d code %3d level %3d", status, PDS_Parameter, PDS_Level2);
+  if ( CGRIBEX_Debug ) Message("record offset = %d", (int) *offset);
 
-    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);
+  return 1;
+}
 
-#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;
+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;
 
-    if ( (bdsLen%2) == 1 )
-      {
-	BDS_Flag += 8;
-	bds[bdsLen++] = 0;
-      }
+  *offset = 0;
 
-    SetLen3(bds, 0, bdsLen);
+  void *fileptr = filePtr(fileID);
 
-    gribLen = (bds - dbuf) + bdsLen;
-    
-    dbuf[gribLen++] = '7';
-    dbuf[gribLen++] = '7';
-    dbuf[gribLen++] = '7';
-    dbuf[gribLen++] = '7';
+  while ( retry-- )
+    {
+      if ( i >= nread )
+	{
+	  nread = (int) filePtrRead(fileptr, buffer, buffersize);
+	  if ( nread == 0 ) return (-1);
+	  i = 0;
+	}
 
-    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;
+      ch = buffer[i++];
+      code = ( (code << 8) + ch ) & 0xFFFFFFFFL;
 
-	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);
+      if ( code == GRIB )
+	{
+	  /* printf("end: %d %d\n", nread, i); */
+	  if ( CGRIBEX_Debug )
+	    Message("record offset = %d", (int) *offset);
 
-	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
+	  if ( i != nread ) fileSetPos(fileID, (off_t) i-nread, SEEK_CUR);
 
-  return (int)gribLen;
-}
-#include <stdio.h>
-#include <math.h>
+	  return (0);
+	}
+
+      (*offset)++;
+    }
 
+  if ( CGRIBEX_Debug ) Message("record offset = %d", (int) *offset);
 
+  return 1;
+}
 
-static
-int rowina2(double *p, int ko, int ki, double *pw,
-	    int kcode, double msval, int *kret)
+static inline int
+read3ByteMSBFirst(void *fileptr)
 {
-  /* System generated locals */
-  int pw_dim1, pw_offset, i_1;
+  unsigned b1 = (unsigned)(filePtrGetc(fileptr));
+  unsigned b2 = (unsigned)(filePtrGetc(fileptr));
+  unsigned b3 = (unsigned)(filePtrGetc(fileptr));
+  return (int)((b1 << 16) + (b2 << 8) + b3);
+}
 
-  /* Local variables */
-  double zwt1, zrdi, zpos;
-  int jl, ip;
-  double zdo, zwt;
+int gribReadSize(int fileID)
+{
+  void *fileptr = filePtr(fileID);
+  off_t pos = fileGetPos(fileID); 
 
-  /* Parameter adjustments */
-  --p;
-  pw_dim1 = ko + 3;
-  pw_offset = pw_dim1;
-  pw -= pw_offset;
+  unsigned b1 = (unsigned) filePtrGetc(fileptr);
+  unsigned b2 = (unsigned) filePtrGetc(fileptr);
+  unsigned b3 = (unsigned) filePtrGetc(fileptr);
 
-  /* **** 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. */
+  int gribsize = gribrec_len(b1, b2, b3);
+  int gribversion = filePtrGetc(fileptr);
 
-  /*     Output Parameters. */
-  /*     ------------------ */
-  /*     P     - Now contains KO values. */
-  /*     KRET  - Return code */
-  /*             0, OK */
-  /*             Non-zero, error */
+  if ( gribsize == 24 )
+    {
+      if ( gribversion != 1 && gribversion != 2 ) gribversion = 0;
+    }
 
-  /*     Author. */
-  /*     ------- */
-  /*     J.D.Chambers    ECMWF     22.07.94 */
+  if ( CGRIBEX_Debug )
+    Message("gribversion = %d", gribversion);
 
-  /*     ********************************    */
-  /*     Section 1.  Linear interpolation .. */
-  /*     ********************************    */
+  if ( gribversion == 0 )
+    {
+      int pdssize = 0, gdssize = 0, bmssize = 0, bdssize = 0;
+      int issize = 4, essize = 4;
+      int flag = 0;
 
-  *kret = 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 ( kcode == 1 )
-    {
-      /*    Move input values to work array */
-      for ( jl = 1; jl <= ki; ++jl )
-	pw[jl + pw_dim1] = p[jl];
+      if ( flag & 128 )
+	{
+	  gdssize = read3ByteMSBFirst(fileptr);
+	  fileSetPos(fileID, (off_t) gdssize-3, SEEK_CUR);
+	  if ( CGRIBEX_Debug ) Message("gdssize     = %d", gdssize);
+	}
 
-      /*    Arrange wrap-around value in work array */
-      pw[ki + 1 + pw_dim1] = p[1];
+      if ( flag & 64 )
+	{
+	  bmssize = read3ByteMSBFirst(fileptr);
+	  fileSetPos(fileID, (off_t) bmssize-3, SEEK_CUR);
+	  if ( CGRIBEX_Debug ) Message("bmssize     = %d", bmssize);
+	}
 
-      /*    Set up constants to be used to figure out weighting for */
-      /*    values in interpolation. */
-      zrdi = (double) ki;
-      zdo = 1.0 / (double) ko;
+      bdssize = read3ByteMSBFirst(fileptr);
+      if ( CGRIBEX_Debug ) Message("bdssize     = %d", bdssize);
 
-      /*    Loop through the output points */
-      for ( jl = 1; jl <= ko; ++jl )
+      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;
 
-	  /*    Calculate weight from the start of row */
-	  zpos = (jl - 1) * zdo;
-	  zwt = zpos * zrdi;
+	  pdssize = read3ByteMSBFirst(fileptr);
+	  if ( CGRIBEX_Debug ) Message("pdssize     = %d", pdssize);
 
-	  /*    Get the current array position(minus 1) from the weight - */
-	  /*    note the implicit truncation. */
-	  ip = (int) zwt;
+	  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 the left value is missing, use the right value */
-	  if ( IS_EQUAL(pw[ip + 1 + pw_dim1], msval) )
+	  if ( flag & 128 )
 	    {
-	      p[jl] = pw[ip + 2 + pw_dim1];
+	      gdssize = read3ByteMSBFirst(fileptr);
+	      fileSetPos(fileID, (off_t) gdssize-3, SEEK_CUR);
+	      if ( CGRIBEX_Debug ) Message("gdssize     = %d", gdssize);
 	    }
-	  /*    If the right value is missing, use the left value */
-	  else if ( IS_EQUAL(pw[ip + 2 + pw_dim1], msval) )
+	  
+	  if ( flag & 64 )
 	    {
-	      p[jl] = pw[ip + 1 + pw_dim1];
+	      bmssize = read3ByteMSBFirst(fileptr);
+	      fileSetPos(fileID, (off_t) bmssize-3, SEEK_CUR);
+	      if ( CGRIBEX_Debug ) Message("bmssize     = %d", bmssize);
 	    }
-	  /*    If neither missing, interpolate ... */
-	  else
-	    {
 
-	      /*       Adjust the weight to range (0.0 to 1.0) */
-	      zwt -= ip;
+	  bdssize = read3ByteMSBFirst(fileptr);
+	  bdssize = correct_bdslen(bdssize, gribsize, issize+pdssize+gdssize+bmssize);
+	  if ( CGRIBEX_Debug ) Message("bdssize     = %d", bdssize);
 
-	      /*       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];
-	    }
+	  gribsize = issize+pdssize+gdssize+bmssize+bdssize+essize;
 	}
-
-      /*     *******************************    */
-      /*     Section 2.  Cubic interpolation .. */
-      /*     *******************************    */
-
     }
-  else if ( kcode == 3 )
+  else if ( gribversion == 2 )
     {
-      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;
-	}
-
+      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
     {
-      /*    **************************************    */
-      /*    Section 3.  Invalid interpolation code .. */
-      /*    **************************************    */
-      fprintf(stderr," ROWINA2:");
-      fprintf(stderr," Invalid interpolation code = %2d\n",kcode);
-      *kret = 2;
+      gribsize = 0;
+      Warning("GRIB version %d unsupported!", gribversion);
     }
 
-L900:
-    return 0;
-} /* rowina2 */
-
-
-
-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;
-
-   /* Local variables */
-   int ilii, ilio, icode;
-   double *zline = NULL;
-   double *zwork = NULL;
-   int iregno, iquano, j210, j220, j230, j240, j225;
-
-
-   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!");
-
-   /* 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. */
+  if ( filePtrEOF(fileptr) ) gribsize = 0;
 
+  if ( CGRIBEX_Debug )
+    Message("gribsize    = %d", gribsize);
 
-/* ------------------------------ */
-/* Section 1. Set initial values. */
-/* ------------------------------ */
+  fileSetPos(fileID, pos, SEEK_SET);
 
-   *kret = 0;
+  return gribsize;
+}
 
-/* Check input parameters. */
 
-   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;
-   }
+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);
+    }
 
-/* Set array indices to 0. */
+  if      ( ierr == -1 ) return 0;
+  else if ( ierr ==  1 ) return 0;
 
-   ilii = 0;
-   ilio = 0;
+  int recSize = gribReadSize(fileID);
 
-/* Establish values of loop parameters. */
+  if ( CGRIBEX_Debug ) Message("recsize = %d", recSize);
 
-   if (kcode > 10) {
+  fileSetPos(fileID, (off_t) -4, SEEK_CUR);
 
-/*    Quasi-regular along longitude lines. */
+  return recSize;
+}
 
-      iquano = klon;
-      iregno = klat;
-      icode = kcode - 10;
-   } else {
 
-/*    Quasi-regular along latitude lines. */
+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);
+    }
 
-      iquano = klat;
-      iregno = klon;
-      icode = kcode;
-   }
+  if      ( ierr == -1 ) { *buffersize = 0; return -1; }
+  else if ( ierr ==  1 ) { *buffersize = 0; return -2; }
 
-/*     -------------------------------------------------------- */
-/**    Section 2. Interpolate field from quasi to regular grid. */
-/*     -------------------------------------------------------- */
+  size_t recSize  = (size_t)gribReadSize(fileID);
+  size_t readSize = recSize;
 
-   i_1 = iquano;
-   for (j230 = 1; j230 <= i_1; ++j230) {
+  if ( readSize > *buffersize )
+    {
+      readSize = *buffersize;
+      ierr = -3;          // Tell the caller that the buffer was insufficient.
+    }
 
-      if (iregno != kpoint[j230]) {
+  *buffersize = recSize;  // Inform the caller about the record size.
 
-/*       Line contains less values than required,so */
-/*       extract quasi-regular grid values for a line */
+  // 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';
 
-         i_2 = kpoint[j230];
-         for (j210 = 1; j210 <= i_2; ++j210) {
-            ++ilii;
-            zline[j210 - 1] = pfield[ilii];
-         }
+  readSize -= 4;
+  // Read the rest of the record into the buffer.
+  size_t nread = fileRead(fileID, &buffer[4], readSize);
 
-/*       and interpolate this line. */
+  if ( nread != readSize ) ierr = 1;
 
-         rowina2(zline, iregno, kpoint[j230], zwork, icode, msval, kret);
-         if (*kret != 0) goto L900;
+  return ierr;
+}
 
-/*       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];
-         }
+int gribWrite(int fileID, unsigned char *buffer, size_t buffersize)
+{
+  int  nwrite = 0;
 
-      } else {
+  if ( (nwrite = (int)(fileWrite(fileID, buffer, buffersize))) != (int) buffersize )
+    {
+      perror(__func__);
+      nwrite = -1;
+    }
 
-/*       Line contains the required number of values, so add */
-/*       this line to the temporary array. */
+  return nwrite;
+}
 
-         i_2 = iregno;
-         for (j225 = 1; j225 <= i_2; ++j225) {
-            ++ilio;
-            ++ilii;
-            ztemp[ilio - 1] = pfield[ilii];
-         }
-      }
-   }
 
-/* Copy temporary array to user array. */
+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));
 
-   i_1 = klon * klat;
-   for (j240 = 1; j240 <= i_1; ++j240) {
-      pfield[j240] = ztemp[j240 - 1];
-   }
+  if ( needRescaling ) gribsize *= 120;
 
-/* -------------------------------------------------------- */
-/* Section 9. Return to calling routine. Format statements. */
-/* -------------------------------------------------------- */
+  return gribsize;
+}
 
-L900:
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
 
-   Free(zline);
-   Free(zwork);
 
-   return 0;
-} /* qu2reg2 */
+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;
+}
 
-#ifdef T
-#undef T
-#endif
-#define T double
-#ifdef T
 
-/* calculate_pfactor: source code from grib_api-1.8.0 */
-double TEMPLATE(calculate_pfactor,T)(const T *spectralField, long fieldTruncation, long subsetTruncation)
+void grsdef(void)
 {
-  /*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
-   */
+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;
 
-  range = (double) (ismax - ismin +1);
+  if ( ! lfirst ) return;
 
-  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));
+    ----------------------------------------------------------------
+    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;
+    }
 
-  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;
-      }
+    Set GRIB value checking on.
+  */
+  nvck   = 1;
+  
+  envString = getenv("GRIBEX_CHECK");
+  if ( envString )
+    {
+      if ( !strncmp(envString, "OFF", 3) )
+        nvck = 0;
+      else
+        nvck = 1;
     }
   /*
-  // 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;
+    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);
+	    }
+	}
     }
-
   /*
-  // Ensure the norms have a value which is not too small in case of
-  // problems with math functions (e.g. LOG).
-   */
+    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;
+}
 
-  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;
-  }
+/* 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]; */
 
-  /*
-  // Do linear fit to find the slope
-   */
+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 */
 
-  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;
+  head = ( (long) cp ) & (ipack-1);
+  if ( head != 0 ) head = ipack - head;
 
-  /*
-  // Perform a least square fit for the equation
-   */
+  inner = bc - head;
 
-  for( loop = ismin; loop <= ismax; loop++ ) {
+  /* Trailing bytes which do not make a full word */
 
-    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;
+  trail = inner & (ipack-1);
 
-  Free(weights);
-  Free(norms);
+  /* Number of bytes/words to be processed in fast loop */
 
-  pFactor = -slope;
-  if( pFactor < -9999.9 ) pFactor = -9999.9;
-  if( pFactor > 9999.9 )  pFactor = 9999.9;
+  inner -= trail;
+  inner /= ipack;
 
-  return pFactor;
-}
+  ip0 = up + head;
+  ip1 = ip0 + 1;
+  ip2 = ip0 + 2;
+  ip3 = ip0 + 3;
+  ip4 = ip0 + 4;
+  ip5 = ip0 + 5;
+  ip6 = ip0 + 6;
+  ip7 = ip0 + 7;
 
-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));
+  up0 = (unsigned INT64 *) (cp + head);
 
-  if ( scale == NULL ) SysError("No Memory!");
+  /* 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 ( pcScale < -10000 || pcScale > 10000 )
+  j = 0;
+
+  if ( IS_BIGENDIAN() )
     {
-      fprintf(stderr, " %s: Invalid power given %6d\n", __func__, pcScale);
-      return;
-   }
+#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;
+	}
+    }
 
-  /* Setup scaling factors = n(n+1)^^p for n = 1 to truncation */
+  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 ( pcScale == 0 ) return;
+  if ( tc != -1 )
+    {
+      bc++;
+      *cp0 = (unsigned char) tc;
+    }
+#endif
+  return (bc);
+}
 
-  power = (double) pcScale / 1000.;
-  scale[0] = 1.0;
+/* 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]; */
 
-  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));
+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);
 
-  if ( inv )
-    for ( int n = 1; n <= trunc; n++ ) scale[n] = 1.0 / scale[n];
+  UNUSED(tc);
 
-  /* Scale the values */
+  /* Bytes until first word boundary in source buffer */
 
-  size_t index = 0;
+  head = ( (long) cp ) & (ipack-1);
+  if ( head != 0 ) head = ipack - head;
+  if ( head > bc ) head = bc;
 
-  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]);
-        }
+  inner = bc - head;
 
-  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]);
-      }
+  /* Trailing bytes which do not make a full word */
+ 
+  trail = inner & (ipack-1);
+ 
+  /* Number of bytes/words to be processed in fast loop */
 
-  Free(scale);
-}
+  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;
 
-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;
+  up0 = (unsigned INT64 *) (cp + head);
 
-  if ( fphelp == NULL ) SysError("No Memory!");
+  /* Process any bytes until the first word boundary 
+   * of our source buffer 
+   */
+  for ( i = 0 ; i < head ; i++ ) up[i] = (unsigned INT64) cp[i];
 
-  index = inext = 0;
+  j = 0;
 
-  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 ( 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;
 
-  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;
-      }
+	  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;
 
-  for ( m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
+	  j += ipack;
+	}
+    }
 
-  Free(fphelp);
+  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]; */
 
-void TEMPLATE(gather_complex,T)(T *fpdata, size_t pcStart, size_t trunc, size_t nsp)
+#if  defined  (INT32)
+long packInt32(unsigned INT32 *up, unsigned char *cp, long bc, long tc)
 {
-  T *restrict fphelp = (T*) Malloc(nsp*sizeof(T));
-  size_t inext = 0;
+  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 */
 
-  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;
-      }
+  head = ( (long) cp ) & (ipack-1);
+  if ( head != 0 ) head = ipack - head;
 
-  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;
-      }
+  inner = bc - head;
 
-  for ( size_t m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
+  /* Trailing bytes which do not make a full word */
 
-  Free(fphelp);
-}
+  trail = inner & (ipack-1);
 
+  /* Number of bytes/words to be processed in fast loop */
 
-void TEMPLATE(scm0,T)(T *pdl, T *pdr, T *pfl, T *pfr, int klg)
-{
-  /* System generated locals */
-  double r_1;
+  inner -= trail;
+  inner /= ipack;
 
-  /* Local variables */
-  int jl;
-  double zfac, zeps, zbeta;
-  double zalpha;
+  ip0 = up + head;
+  ip1 = ip0 + 1;
+  ip2 = ip0 + 2;
+  ip3 = ip0 + 3;
 
-  /* **** 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 INT32 *) (cp + head);
 
-  /*  define constants */
+  /* 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 
+   */
 
-  zeps = 1.0e-12;
-  zfac = (1.0 - zeps) * 3.0;
+  j = 0;
 
-  for ( jl = 0; jl < klg; ++jl )
+  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
     {
-      if ( (r_1 = pfr[jl] - pfl[jl], fabs(r_1)) > zeps )
+      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] = zfac * (pfr[jl] - pfl[jl]);
-	  if ( zbeta  > zfac ) pdr[jl] = zfac * (pfr[jl] - pfl[jl]);
+	  up0[i] =          (   ip3[j]          << 24 ) 
+	                 |  ( ( ip2[j] & 0xFF ) << 16 )
+                         |  ( ( ip1[j] & 0xFF ) <<  8 )
+                         |    ( ip0[j] & 0xFF ) ;
+	  j += ipack;
 	}
-      else
+    }
+
+  cp0 = (unsigned char *) ( up0 + inner );
+  if ( trail > 0 )
+    {
+      up0[inner] = 0;
+      for ( i = 0 ; i < trail ; i ++ )
 	{
-	  pdl[jl] = 0.0;
-	  pdr[jl] = 0.0;
+	  *cp0 = (unsigned char) ip0[ipack*inner+i];
+	  cp0++;
 	}
     }
-} /* 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 ( tc != -1 )
+    {
+      bc++;
+      *cp0 = (unsigned char) tc;
+    }
+
+  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]; */
+
+#if  defined  (INT32)
+long unpackInt32(const unsigned char *cp, unsigned INT32 *up, long bc, long tc)
 {
-  /*
-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;
+  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);
 
-  /* Local variables */
-  int jl, ip;
-  double zwt1, zrdi, zpos;
-  double zdo, zwt;
+  UNUSED(tc);
 
-  UNUSED(omisng);
+  /* Bytes until first word boundary in source 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;
+  if ( head > bc ) head = bc;
 
-  *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 */
+ 
+  trail = inner & (ipack-1);
+ 
+  /* Number of bytes/words to be processed in fast loop */
 
-      if ( operio )
-	{
-	  /* Arrange wrap-around value in work array */
-	  pw[ki + 1 + pw_dim1] = p[1];
+  inner -= trail;
+  inner /= ipack;
 
-	  /* 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];
+  ip0 = up + head;
+  ip1 = ip0 + 1;
+  ip2 = ip0 + 2;
+  ip3 = ip0 + 3;
 
-	  /* Set up constants to be used to figure out weighting for */
-	  /* values in interpolation. */
-	  zrdi = (double) (ki-1);
-	  zdo = 1.0 / (double) (ko-1);
- 	}
+  up0 = (unsigned INT32 *) (cp + head);
 
-      /*    Loop through the output points */
-      for ( jl = 1; jl <= ko; ++jl )
-	{
+  /* Process any bytes until the first word boundary 
+   * of our source buffer 
+   */
+  for ( i = 0 ; i < head ; i++ ) up[i] = (unsigned INT32) cp[i];
 
-	  /* Calculate weight from the start of row */
-	  zpos = (jl - 1) * zdo;
-	  zwt = zpos * zrdi;
+  j = 0;
 
-	  /* 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 ( 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;
 
-          /* 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]);
-		}
-	    }
+	  j += ipack;
 	}
     }
-  else if ( kcode == 3 )
+  else
     {
-      /*     *******************************    */
-      /*     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 )
+      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);
-	}
-
-      TEMPLATE(scm0,T)(&pw[(pw_dim1 << 1) + 1], &pw[pw_dim1 * 3 + 2],
-		       &pw[pw_dim1 + 1], &pw[pw_dim1 + 2], ki);
+	  ip3[j] = (up0[i] >> 24) & 0xFF;
+	  ip2[j] = (up0[i] >> 16) & 0xFF;
+	  ip1[j] = (up0[i] >>  8) & 0xFF;
+	  ip0[j] = (up0[i])       & 0xFF;
 
-      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);
+	  j += ipack;
 	}
-
     }
-  else
+
+  if ( trail > 0 )
     {
-      /*    **************************************    */
-      /*    Section 3.  Invalid interpolation code .. */
-      /*    **************************************    */
-      fprintf(stderr," ROWINA3:");
-      fprintf(stderr," Invalid interpolation code = %2d\n",kcode);
-      *kret = 2;
+      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;
+  }
+  */
 
-L900:
-    return 0;
-} /* rowina3 */
-
+  return (bc);
+}
+#endif
+#include <stdio.h>
 
-int TEMPLATE(qu2reg3,T)(T *pfield, int *kpoint, int klat, int klon,
-			T msval, int *kret, int omisng, int operio, int oveggy)
+void prtbin(int kin, int knbit, int *kout, int *kerr)
 {
   /*
-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;
+    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.
 
-   ztemp = (T*) Malloc((size_t)klon*(size_t)klat*sizeof(T));
 
-   zline = (T*) Malloc(2*(size_t)klon*sizeof(T));
+    Input Parameters:
+    
+       kin   - Integer variable containing binary number.
 
-   zwork = (T*) Malloc(3*(2*(size_t)klon+3)*sizeof(T));
+       knbit - Number of bits in binary number.
 
-   /* Parameter adjustments */
-   --pfield;
-   --kpoint;
+    Output Parameters:
 
-/* ------------------------------ */
-/* Section 1. Set initial values. */
-/* ------------------------------ */
+       kout  - Integer variable containing decimal value
+               with ones and zeroes corresponding to those of
+	       the input binary number.
 
-   *kret = 0;
+       kerr  - 0, If no error.
+               1, Number of bits in binary number exceeds
+	          maximum allowed or is less than 1.
 
-/* Check input parameters. */
 
-   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;
-   }
+    Converted from EMOS routine PRTBIN.
+
+       Uwe Schulzweida   MPIfM   01/04/2001
+
+  */
+  int idec;
+  int ik;
+  int itemp;
+  int j;
+
+  /*
+    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;
+
+  for ( j = 0; j < knbit; j++ )
+    {
+      itemp = ik - ( (ik/2)*2 );
+      *kout = (*kout) + itemp * idec;
+      ik    = ik / 2;
+      idec  = idec * 10;
+    }
+
+  return;
+}
 
-/* Set array indices to 0. */
 
-   ilii = 0;
-   ilio = 0;
+void ref2ibm(double *pref, int kbits)
+{
+  /*
 
-/* Establish values of loop parameters. */
+    Purpose:
+    --------
 
-   if (kcode > 10) {
+    Code and check reference value in IBM format
 
-/*    Quasi-regular along longitude lines. */
+    Input Parameters:
+    -----------------
 
-      iquano = klon;
-      iregno = klat;
-      icode = kcode - 10;
-   } else {
+    pref       - Reference value
+    kbits      - Number of bits per computer word.
 
-/*    Quasi-regular along latitude lines. */
+    Output Parameters:
+    ------------------
 
-      iquano = klat;
-      iregno = klon;
-      icode = kcode;
-   }
+    pref       - Reference value
 
-/*     -------------------------------------------------------- */
-/**    Section 2. Interpolate field from quasi to regular grid. */
-/*     -------------------------------------------------------- */
+    Method:
+    -------
 
-   i_1 = iquano;
-   for (j230 = 1; j230 <= i_1; ++j230) {
+    Codes in IBM format, then decides to ensure that reference 
+    value used for packing is not different from that stored
+    because of packing differences.
 
-      if (iregno != kpoint[j230]) {
+    Externals.
+    ----------
 
-/*       Line contains less values than required,so */
-/*       extract quasi-regular grid values for a line */
+    confp3    - Encode into IBM floating point format.
+    decfp2    - Decode from IBM floating point format.
 
-         i_2 = kpoint[j230];
-         for (j210 = 1; j210 <= i_2; ++j210) {
-            ++ilii;
-            zline[j210 - 1] = pfield[ilii];
-         }
+    Reference:
+    ----------
 
-/*       and interpolate this line. */
+    None.
 
-         TEMPLATE(rowina3,T)(zline, iregno, kpoint[j230], zwork, icode, msval, kret, omisng, operio , oveggy);
-         if (*kret != 0) goto L900;
+    Comments:
+    --------
 
-/*       Add regular grid values for this line to the
-         temporary array. */
+    None.
 
-         i_2 = iregno;
-         for (j220 = 1; j220 <= i_2; ++j220) {
-            ++ilio;
-            ztemp[ilio - 1] = zline[j220 - 1];
-         }
+    Author:
+    -------
 
-      } else {
+    J.D.Chambers     ECMWF      17:05:94
 
-/*       Line contains the required number of values, so add */
-/*       this line to the temporary array. */
+    Modifications:
+    --------------
 
-         i_2 = iregno;
-         for (j225 = 1; j225 <= i_2; ++j225) {
-            ++ilio;
-            ++ilii;
-            ztemp[ilio - 1] = pfield[ilii];
-         }
-      }
-   }
+    Uwe Schulzweida   MPIfM   01/04/2001
 
-/* Copy temporary array to user array. */
+    Convert to C from EMOS library version 130
 
-   i_1 = klon * klat;
-   for (j240 = 1; j240 <= i_1; ++j240) {
-      pfield[j240] = ztemp[j240 - 1];
-   }
+  */
 
-/* -------------------------------------------------------- */
-/* Section 9. Return to calling routine. Format statements. */
-/* -------------------------------------------------------- */
+  static int itrnd;
+  static int kexp, kmant;
+  static double ztemp, zdumm;
+  extern int CGRIBEX_Debug;
 
-L900:
+  /* ----------------------------------------------------------------- */
+  /*   Section 1. Convert to and from IBM format.                      */
+  /* ----------------------------------------------------------------- */
 
-   Free(zwork);
-   Free(zline);
-   Free(ztemp);
+  /*  Convert floating point reference value to IBM representation. */
 
-   return 0;
-} /* qu2reg3 */
+  itrnd = 1;
+  zdumm = ztemp = *pref;
+  confp3(zdumm, &kexp, &kmant, kbits, itrnd);
 
-#endif /* T */
+  if ( kexp == 0 && kmant == 0 ) return;
 
-/*
- * Local Variables:
- * mode: c
- * End:
- */
+  /*  Set reference value to that actually stored in the GRIB code. */
 
-#ifdef T
-#undef T
-#endif
-#define T float
-#ifdef T
+  *pref = decfp2(kexp, kmant);
 
-/* 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;
+  /*  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.                         */
 
-  /*
-  // Setup the weights
-   */
+  if ( ztemp < *pref )
+    {
+      /*  Convert floating point to GRIB representation */
+      /*  using truncation to ensure that the converted */
+      /*  number is smaller than the original one.      */
 
-  range = (double) (ismax - ismin +1);
+      itrnd = 0;
+      zdumm = *pref = ztemp;
+      confp3(zdumm, &kexp, &kmant, kbits, itrnd);
 
-  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));
+      /*  Set reference value to that stored in the GRIB code. */
 
-  for( loop = 0; loop < ismax+1; loop++ ) norms[loop] = 0.0;
-  /*
-  // Form norms for the rows which contain part of the unscaled subset.
-   */
+      *pref = decfp2(kexp, kmant);
 
-  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;
-      }
+      if ( ztemp < *pref )
+	{
+	  if ( CGRIBEX_Debug )
+	    {
+	      Message("Reference value error.");
+	      Message("Notify Met.Applications Section.");
+	      Message("ZTEMP = ", ztemp);
+	      Message("PREF = ", pref);
+	    }
+	  *pref = ztemp;
+	}
     }
-  /*
-  // 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;
-    }
+  return;
+} /* ref2ibm */
+#include <math.h>
+#include <string.h>
 
+
+int correct_bdslen(int bdslen, long recsize, long gribpos)
+{
   /*
-  // Ensure the norms have a value which is not too small in case of
-  // problems with math functions (e.g. LOG).
-   */
+    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);
+}
 
-  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;
-  }
 
-  /*
-  // Do linear fit to find the slope
-   */
+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;
 
-  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;
+  *gribrecsize = 0;
+  *pdsp = NULL;
+  *gdsp = NULL;
+  *bmsp = NULL;
+  *bdsp = NULL;
 
-  /*
-  // Perform a least square fit for the equation
-   */
+  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);
+    }
 
-  for( loop = ismin; loop <= ismax; loop++ ) {
+  recsize = gribrec_len(section[4], section[5], section[6]);
 
-    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;
+  gribversion = GRIB_EDITION(section);
+  if ( GRIB1_SECLEN(section) == 24 && gribversion == 0 ) gribversion = 0;
 
-  Free(weights);
-  Free(norms);
+  if ( gribversion == 1 )
+    grib1offset = 4;
+  else
+    grib1offset = 0;
 
-  pFactor = -slope;
-  if( pFactor < -9999.9 ) pFactor = -9999.9;
-  if( pFactor > 9999.9 )  pFactor = 9999.9;
+  pds = is + 4 + grib1offset;
+  bufpointer = pds + PDS_Len;
+  gribsize += 4 + grib1offset + PDS_Len;
 
-  return pFactor;
-}
+  if ( PDS_HAS_GDS )
+    {
+      gds = bufpointer;
+      bufpointer += GDS_Len;
+      gribsize += GDS_Len;
+    }
+  else
+    {
+      gds = NULL;
+    }
 
-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 ( PDS_HAS_BMS )
+    {
+      bms = bufpointer;
+      bufpointer += BMS_Len;
+      gribsize += BMS_Len;
+    }
+  else
+    {
+      bms = NULL;
+    }
 
-  if ( scale == NULL ) SysError("No Memory!");
+  bds = bufpointer;
+  bdslen = BDS_Len;
+  bdslen = correct_bdslen(bdslen, recsize, gribsize);
+  bufpointer += bdslen;
+  gribsize += bdslen;
+  gribsize += 4;
 
-  if ( pcScale < -10000 || pcScale > 10000 )
+  *pdsp = pds;
+  *gdsp = gds;
+  *bmsp = bms;
+  *bdsp = bds;
+
+  *gribrecsize = gribsize;
+
+  if ( gribbufsize < gribsize )
     {
-      fprintf(stderr, " %s: Invalid power given %6d\n", __func__, pcScale);
-      return;
-   }
+      fprintf(stderr, "Length of GRIB message is inconsistent (grib_buffer_size=%ld < grib_record_size=%ld)!\n", gribbufsize, gribsize);
+      return (1);
+    }
 
-  /* Setup scaling factors = n(n+1)^^p for n = 1 to truncation */
+  /* 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);
+    }
 
-  if ( pcScale == 0 ) return;
+  return (0);
+}
 
-  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 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;
 
-  if ( inv )
-    for ( int n = 1; n <= trunc; n++ ) scale[n] = 1.0 / scale[n];
+  UNUSED(gribbufsize);
 
-  /* Scale the values */
+  *idsp = NULL;
+  *lusp = NULL;
+  *gdsp = NULL;
+  *pdsp = NULL;
+  *drsp = NULL;
+  *bmsp = NULL;
+  *bdsp = NULL;
 
-  size_t index = 0;
+  section = gribbuffer;
+  sec_len = 16;
 
-  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 ( !GRIB_START(section) )
+    {
+      fprintf(stderr, "wrong indicator section >%c%c%c%c<\n",
+	      section[0], section[1], section[2], section[3]);
+      return (-1);
+    }
 
-  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]);
-      }
+  gribversion = GRIB_EDITION(section);
+  if ( gribversion != 2 )
+    {
+      fprintf(stderr, "wrong GRIB version %d\n", gribversion);
+      return (-1);      
+    }
 
-  Free(scale);
-}
+  gribsize = 0;
+  for ( i = 0; i < 8; i++ ) gribsize = (gribsize << 8) | section[8+i];
 
+  grib_len += sec_len;
+  section  += sec_len;
 
-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;
+  /* section 1 */
+  sec_len = GRIB2_SECLEN(section);
+  sec_num = GRIB2_SECNUM(section);
+  //fprintf(stderr, "ids %d %ld\n", sec_num, sec_len);
 
-  if ( fphelp == NULL ) SysError("No Memory!");
+  if ( sec_num != 1 )
+    {
+      fprintf(stderr, "Unexpected section1 number %d\n", sec_num);
+      return (-1);
+    }
 
-  index = inext = 0;
+  *idsp = section;
 
-  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;
-      }
+  grib_len += sec_len;
+  section  += sec_len;
 
-  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;
-      }
+  /* section 2 and 3 */
+  sec_len = GRIB2_SECLEN(section);
+  sec_num = GRIB2_SECNUM(section);
+  //fprintf(stderr, "lus %d %ld\n", sec_num, sec_len);
 
-  for ( m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
+  if ( sec_num == 2 )
+    {
+      *lusp = section;
 
-  Free(fphelp);
-}
+      grib_len += sec_len;
+      section  += sec_len;
 
+      /* section 3 */
+      sec_len = GRIB2_SECLEN(section);
+      //sec_num = GRIB2_SECNUM(section);
+      //fprintf(stderr, "gds %d %ld\n", sec_num, sec_len);
 
-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;
+      *gdsp = section;
+    }
+  else if ( sec_num == 3 )
+    {
+      *gdsp = section;
+    }
+  else
+    {
+      fprintf(stderr, "Unexpected section3 number %d\n", sec_num);
+      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;
-      }
+  grib_len += sec_len;
+  section  += sec_len;
 
-  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;
-      }
+  /* section 4 */
+  sec_len = GRIB2_SECLEN(section);
+  sec_num = GRIB2_SECNUM(section);
+  //fprintf(stderr, "pds %d %ld\n", sec_num, sec_len);
 
-  for ( size_t m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
+  if ( sec_num != 4 )
+    {
+      fprintf(stderr, "Unexpected section4 number %d\n", sec_num);
+      return (-1);
+    }
 
-  Free(fphelp);
-}
+  *pdsp = section;
 
+  grib_len += sec_len;
+  section  += sec_len;
 
-void TEMPLATE(scm0,T)(T *pdl, T *pdr, T *pfl, T *pfr, int klg)
-{
-  /* System generated locals */
-  double r_1;
+  /* section 5 */
+  sec_len = GRIB2_SECLEN(section);
+  sec_num = GRIB2_SECNUM(section);
+  //fprintf(stderr, "drs %d %ld\n", sec_num, sec_len);
 
-  /* Local variables */
-  int jl;
-  double zfac, zeps, zbeta;
-  double zalpha;
+  if ( sec_num != 5 )
+    {
+      fprintf(stderr, "Unexpected section5 number %d\n", sec_num);
+      return (-1);
+    }
 
-  /* **** 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 */
+  *drsp = section;
 
-  /*  define constants */
+  grib_len += sec_len;
+  section  += sec_len;
 
-  zeps = 1.0e-12;
-  zfac = (1.0 - zeps) * 3.0;
+  /* section 6 */
+  sec_len = GRIB2_SECLEN(section);
+  sec_num = GRIB2_SECNUM(section);
+  //fprintf(stderr, "bms %d %ld\n", sec_num, sec_len);
 
-  for ( jl = 0; jl < klg; ++jl )
+  if ( sec_num != 6 )
     {
-      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] = zfac * (pfr[jl] - pfl[jl]);
-	  if ( zbeta  > zfac ) pdr[jl] = zfac * (pfr[jl] - pfl[jl]);
-	}
-      else
-	{
-	  pdl[jl] = 0.0;
-	  pdr[jl] = 0.0;
-	}
+      fprintf(stderr, "Unexpected section6 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;
+  *bmsp = section;
 
-  /* Local variables */
-  int jl, ip;
-  double zwt1, zrdi, zpos;
-  double zdo, zwt;
+  grib_len += sec_len;
+  section  += sec_len;
 
-  UNUSED(omisng);
+  /* section 7 */
+  sec_len = GRIB2_SECLEN(section);
+  sec_num = GRIB2_SECNUM(section);
+  //fprintf(stderr, "bds %d %ld\n", sec_num, sec_len);
 
-  /* Parameter adjustments */
-  --p;
-  pw_dim1 = ko + 3;
-  pw_offset = pw_dim1;
-  pw -= pw_offset;
+  if ( sec_num != 7 )
+    {
+      fprintf(stderr, "Unexpected section7 number %d\n", sec_num);
+      return (-1);
+    }
 
-  *kret = 0;
+  *bdsp = section;
 
-  if ( kcode == 1 )
+  grib_len += sec_len;
+  section  += sec_len;
+
+  /* skip multi GRIB sections */
+  msec = 1;
+  while ( !GRIB_FIN(section) )
     {
-      /*    Move input values to work array */
-      for ( jl = 1; jl <= ki; ++jl )
-	pw[jl + pw_dim1] = p[jl];
+      sec_len = GRIB2_SECLEN(section);
+      sec_num = GRIB2_SECNUM(section);
 
-      if ( operio )
-	{
-	  /* Arrange wrap-around value in work array */
-	  pw[ki + 1 + pw_dim1] = p[1];
+      if ( sec_num < 1 || sec_num > 7 ) break;
 
-	  /* 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];
+      if ( sec_num == 7 )
+	fprintf(stderr, "Skipped unsupported multi GRIB section %d!\n", ++msec);
 
-	  /* Set up constants to be used to figure out weighting for */
-	  /* values in interpolation. */
-	  zrdi = (double) (ki-1);
-	  zdo = 1.0 / (double) (ko-1);
- 	}
+      if ( (grib_len + sec_len) > gribsize ) break;
 
-      /*    Loop through the output points */
-      for ( jl = 1; jl <= ko; ++jl )
-	{
+      grib_len += sec_len;
+      section  += sec_len;
+    }
 
-	  /* Calculate weight from the start of row */
-	  zpos = (jl - 1) * zdo;
-	  zwt = zpos * zrdi;
+  /* 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);
+    }
 
-	  /* 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;
+  return (0);
+}
 
-          /* 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 )
+
+int grib_info_for_grads(off_t recpos, long recsize, unsigned char *gribbuffer,
+			int *intnum, float *fltnum, off_t *bignum)
+{
+  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;
+
+  section = gribbuffer;
+  is = gribbuffer;
+  if ( ! GRIB_START(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);
-	}
+      fprintf(stderr, "wrong indicator section >%c%c%c%c<\n",
+	      section[0], section[1], section[2], section[3]);
+      return (-1);
+    }
 
-      TEMPLATE(scm0,T)(&pw[(pw_dim1 << 1) + 1], &pw[pw_dim1 * 3 + 2],
-		       &pw[pw_dim1 + 1], &pw[pw_dim1 + 2], ki);
+  gribversion = GRIB_EDITION(section);
+  if ( GRIB1_SECLEN(section) == 24 && gribversion == 0 ) gribversion = 0;
 
-      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 ( 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
     {
-      /*    **************************************    */
-      /*    Section 3.  Invalid interpolation code .. */
-      /*    **************************************    */
-      fprintf(stderr," ROWINA3:");
-      fprintf(stderr," Invalid interpolation code = %2d\n",kcode);
-      *kret = 2;
+      gds = NULL;
     }
 
-L900:
-    return 0;
-} /* rowina3 */
+  if ( PDS_HAS_BMS )
+    {
+      bms = bufpointer;
+      bufpointer += BMS_Len;
 
+      bpos = recpos + gribsize + 6;
 
-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;
+      gribsize += BMS_Len;
+    }
+  else
+    {
+      bms = NULL;
+    }
 
-   /* Local variables */
-   int ilii, ilio, icode;
-   int iregno, iquano, j210, j220, j230, j240, j225;
-   T *ztemp = NULL;
-   T *zline = NULL;
-   T *zwork = NULL;
+  bds = bufpointer;
 
-   ztemp = (T*) Malloc((size_t)klon*(size_t)klat*sizeof(T));
+  dpos = recpos + gribsize + 11;
 
-   zline = (T*) Malloc(2*(size_t)klon*sizeof(T));
+  bdslen = BDS_Len;
+  bdslen = correct_bdslen(bdslen, recsize, bds-gribbuffer);
+  bufpointer += bdslen;
+  gribsize += bdslen;
+  gribsize += 4;
 
-   zwork = (T*) Malloc(3*(2*(size_t)klon+3)*sizeof(T));
+  if ( gribsize > recsize )
+    {
+      fprintf(stderr, "GRIB buffer size %ld too small! Min size = %ld\n", recsize, gribsize);
+      return (1);
+    }
 
-   /* Parameter adjustments */
-   --pfield;
-   --kpoint;
+  /* 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]);
+    }
 
-/* ------------------------------ */
-/* Section 1. Set initial values. */
-/* ------------------------------ */
+  {
+    int bs = BDS_BinScale;
+    if ( bs > 32767 ) bs = 32768-bs;
+    bsf = ldexpf(1.0f, bs);
+  }
 
-   *kret = 0;
+  bignum[0] = dpos;
+  bignum[1] = bms ? bpos : -999;
+  intnum[0] = BDS_NumBits;
 
-/* Check input parameters. */
+  /*  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);
+}
 
-   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. */
+void grib1PrintALL(int nrec, long offset, long recpos, long recsize, unsigned char *gribbuffer)
+{
+  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;
 
-   ilii = 0;
-   ilio = 0;
+  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;
+    }
 
-/* Establish values of loop parameters. */
+  is = gribbuffer;
 
-   if (kcode > 10) {
+  if ( gribrec_len(is[4], is[5], is[6]) > JP23SET ) llarge = 1;
 
-/*    Quasi-regular along longitude lines. */
+  long gribrecsize;
+  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;
+    }
 
-      iquano = klon;
-      iregno = klat;
-      icode = kcode - 10;
-   } else {
+  if ( gds == NULL )
+    GridType = -1;
+  else
+    GridType = GDS_GridType;
 
-/*    Quasi-regular along latitude lines. */
+  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;
 
-      iquano = klat;
-      iregno = klon;
-      icode = kcode;
-   }
+  bdslen = BDS_Len;
+  bdslen = correct_bdslen(bdslen, recsize, bds-gribbuffer);
 
-/*     -------------------------------------------------------- */
-/**    Section 2. Interpolate field from quasi to regular grid. */
-/*     -------------------------------------------------------- */
+  if ( ((BDS_Flag >> 4)&1) && (BDS_Z == 128 || BDS_Z == 130) )
+    {
+      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;
+    }
 
-   i_1 = iquano;
-   for (j230 = 1; j230 <= i_1; ++j230) {
+  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');
 
-      if (iregno != kpoint[j230]) {
+  if ( nerr > 0 ) fprintf(stdout, " <-- GRIB data corrupted!");
+  fprintf(stdout, "\n");
+}
 
-/*       Line contains less values than required,so */
-/*       extract quasi-regular grid values for a line */
 
-         i_2 = kpoint[j230];
-         for (j210 = 1; j210 <= i_2; ++j210) {
-            ++ilii;
-            zline[j210 - 1] = pfield[ilii];
-         }
+void grib2PrintALL(int nrec, long offset, long recpos, long recsize, unsigned char *gribbuffer)
+{
+  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;
 
-/*       and interpolate this line. */
+  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;
+    }
 
-         TEMPLATE(rowina3,T)(zline, iregno, kpoint[j230], zwork, icode, msval, kret, omisng, operio , oveggy);
-         if (*kret != 0) goto L900;
+  is = gribbuffer;
 
-/*       Add regular grid values for this line to the
-         temporary array. */
+  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;
+    }
 
-         i_2 = iregno;
-         for (j220 = 1; j220 <= i_2; ++j220) {
-            ++ilio;
-            ztemp[ilio - 1] = zline[j220 - 1];
-         }
+  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);
 
-      } else {
+  /*
+  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);
+}
 
-/*       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];
-         }
-      }
-   }
+void gribPrintALL(int nrec, long offset, long recpos, long recsize, unsigned char *gribbuffer)
+{
+  int gribversion;
 
-/* Copy temporary array to user array. */
+  gribversion = gribVersion(gribbuffer, (size_t)recsize);
 
-   i_1 = klon * klat;
-   for (j240 = 1; j240 <= i_1; ++j240) {
-      pfield[j240] = ztemp[j240 - 1];
-   }
+  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); 
+    }
+}
 
-/* -------------------------------------------------------- */
-/* Section 9. Return to calling routine. Format statements. */
-/* -------------------------------------------------------- */
 
-L900:
+void grib1PrintPDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
+{
+  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;
 
-   Free(zwork);
-   Free(zline);
-   Free(ztemp);
+  UNUSED(recpos);
 
-   return 0;
-} /* qu2reg3 */
+  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;
+    }
 
-#endif /* T */
+  is = gribbuffer;
 
-/*
- * Local Variables:
- * mode: c
- * End:
- */
-#include <string.h>
+  long gribrecsize;
+  nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  if ( nerr < 0 )
+    {
+      fprintf(stdout, "%5d : GRIB message error\n", nrec);
+      return;
+    }
 
+  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);
+    }
 
+  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]);
 
-int gribVersion(unsigned char *is, size_t buffersize)
-{
-  if ( buffersize < 8 )
-    Error("Buffer too small (current size %d)!", (int) buffersize);
+  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 (GRIB_EDITION(is));
+  if ( nerr > 0 ) fprintf(stdout, " <-- GRIB data corrupted!");
+  fprintf(stdout, "\n");
 }
 
-static 
-double GET_Real(unsigned char *grib)
+
+void gribPrintPDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
 {
-  int iexp, imant;
+  int gribversion;
 
-  iexp  = GET_UINT1(grib[0]);
-  imant = GET_UINT3(grib[1], grib[2], grib[3]);
+  gribversion = gribVersion(gribbuffer, (size_t)recsize);
 
-  return (decfp2(iexp, imant));
+  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 
-int decodeIS(unsigned char *is, int *isec0, int *iret)
+
+void grib1PrintGDS(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;
+  int nerr;
+  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
 
-  /*
-    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 : GDS  NV PVPL Typ : xsize ysize   Lat1   Lon1   Lat2   Lon2    dx    dy\n");
+/*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
+      header = 0;
     }
-  if ( lbudg == TRUE || ltide == TRUE )
+
+  long gribrecsize;
+  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);
-
-  grib1offset = ISEC0_GRIB_Version * 4;
+  fprintf(stdout, "%5d :", nrec);
 
-  isLen = 4 + grib1offset;
+  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");
 
-  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 gribPrintGDS(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 = 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 
-void decodePDS_DWD_local_Extension_254(unsigned char *pds, int *isec1)
+
+void grib1PrintBMS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
 {
-  long i;
-  int isvn;
+  static int header = 1;
+  int level, nerr;
+  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
 
-  isec1[36] = GET_UINT1(pds[40]); /* extension identifier */
-  for ( i = 0; i < 11; i++ ) 
-    { 
-      isec1[37+i] =  GET_UINT1(pds[41+i]);
-    } 
+  UNUSED(recpos);
 
-  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) */
+  if ( header )
+    {
+      fprintf(stdout, 
+      "  Rec : Code Level     BMS    Size\n");
+/*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
+      header = 0;
+    }
 
-}
+  long gribrecsize;
+  nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  if ( nerr < 0 )
+    {
+      fprintf(stdout, "%5d : GRIB message error\n", nrec);
+      return;
+    }
 
-static 
-void decodePDS_DWD_local_Extension_253(unsigned char *pds, int *isec1)
-{
-  long i;
-  int isvn;
+  if ( PDS_LevelType == 100 )
+    level = PDS_Level * 100;
+  else if ( PDS_LevelType == 99 )
+    level = PDS_Level;
+  else
+    level = PDS_Level1;
 
-  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 ( 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");
 }
 
-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 */
-}
 
-static 
-int decodePDS(unsigned char *pds, int *isec0, int *isec1)
+void gribPrintBMS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
 {
-  int pdsLen;
-
-  pdsLen = PDS_Len;
+  int gribversion;
 
-  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;
+  gribversion = gribVersion(gribbuffer, (size_t)recsize);
 
-  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) )
-    {
-      ISEC1_Level1 = PDS_Level1;
-      ISEC1_Level2 = PDS_Level2;
-    }
+  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 )
+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;
+
+  UNUSED(recpos);
+
+  if ( header )
     {
-      ISEC1_Year           = PDS_Year;
-      ISEC1_Century        = PDS_Century;
-      ISEC1_SubCenterID    = PDS_Subcenter;
-      ISEC1_DecScaleFactor = PDS_DecimalScale;
+      fprintf(stdout, 
+      "  Rec : Code Level     BDS Flag     Scale   RefValue Bits  CR\n");
+/*     ----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+ */
+      header = 0;
     }
-  else
+
+  long gribrecsize;
+  nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  if ( nerr < 0 )
     {
-      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, "%5d : GRIB message error\n", nrec);
+      return;
     }
 
-  if ( ISEC1_Year < 0 )
+  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 )
     {
-      ISEC1_Year    = -ISEC1_Year;
-      ISEC1_Century = -ISEC1_Century;
+      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;
     }
 
-  ISEC1_LocalFLag = 0;
-  if ( pdsLen > 28 )
-    {
-      int localextlen;
-      localextlen = pdsLen-28;
+  refval = BDS_RefValue;
 
-      if ( localextlen > 4000 )
-	{
-	  Warning("PDS larger than 4000 bytes not supported!");
-	}
-      else
-	{
-	  ISEC1_LocalFLag = 1;
+  if ( BDS_BinScale < 0 )
+    scale = 1.0/pow(2.0, (double) -BDS_BinScale);
+  else
+    scale = pow(2.0, (double) BDS_BinScale);
 
-	  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];
-		}
-	    }
-	}
+  if ( PDS_DecimalScale )
+    {
+      double decscale;
+      decscale = pow(10.0, (double)-PDS_DecimalScale);
+      refval *= decscale;
+      scale  *= decscale;
     }
 
-  return (pdsLen);
+  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 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);}
+void gribPrintBDS(int nrec, long recpos, long recsize, unsigned char *gribbuffer)
+{
+  int gribversion;
 
+  gribversion = gribVersion(gribbuffer, (size_t)recsize);
 
-#ifdef T
-#undef T
-#endif
-#define T double
-#ifdef T
+  if ( gribversion == 0 || gribversion == 1 )
+    grib1PrintBDS(nrec, recpos, recsize, gribbuffer);
+  /*
+  else if ( gribversion == 2 )
+    grib2PrintBDS(nrec, recpos, recsize, gribbuffer);
+  */
+  else
+    {
+      fprintf(stdout, "%5d :%4ld%9ld%7ld : GRIB version %d unsupported\n",
+	      nrec, 0L, recpos, recsize, gribversion); 
+    }
+}
 
-#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 gribCheck1(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 level, nerr;
+  unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
+  double cr = 1;
 
-  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;
-	}
+  UNUSED(recpos);
 
-      while ( t_bits < n_bits )
-	{
-	  tbits = (tbits * 256) + *bits++;
-	  t_bits += 8;
-	}
-      t_bits -= n_bits;
-      fpdata[i] = (float)((tbits >> t_bits) & jmask);
+  long gribrecsize;
+  nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  if ( nerr < 0 )
+    {
+      fprintf(stdout, "%5d : GRIB message error\n", nrec);
+      return;
     }
-  /* 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};
+  if ( nerr > 0 )
+    {
+      fprintf(stdout, "%5d : <-- GRIB data corrupted!\n", nrec);
+      return;
+    }
 
-  /* code from wgrib routine BDS_unpack */
-  const unsigned char *bits = igrib;
-  long i;
-  int n_bits = NumBits;
-  int c_bits, j_bits;
+  if ( PDS_LevelType == 100 )
+    level = PDS_Level * 100;
+  else if ( PDS_LevelType == 99 )
+    level = PDS_Level;
+  else
+    level = PDS_Level1;
 
-  /* older unoptimized code, not often used */
-  c_bits = 8;
-  for ( i = 0; i < jlend; i++ )
+  if ( ((BDS_Flag >> 4)&1) && BDS_Z == 128 )
     {
-      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;
-	    }
-	}
+      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;
+    }
 
-      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 ( 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);
+  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; */
 
-  if ( IS_BIGENDIAN() )
+  long gribrecsize;
+  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
+  /* recLen = gribrec_len(gbuf[4], gbuf[5], gbuf[6]); */
+  /* if ( recLen > JP23SET ) llarge = TRUE; */
 
-  long i;
-#if defined (VECTORCODE)
-  GRIBPACK *lgrib = NULL;
+  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 )
+  sourceLen = (size_t)(((((bds_len - datstart)*8-bds_ubits)/bds_nbits)*bds_nbits)/8);
+
+  if ( bds_nbits == 24 )
     {
-      for ( i = 0; i < jlend; i++ )
-	fpdata[i] = fmin;
+      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 ==  8 )
-    for ( i = 0; i < jlend; i++ )
-      {
-	T dval = (int)igrib[i];
-	fpdata[i] = fmin + zscale * dval;
-      }
-  else if ( numBits == 16 )
+}
+
+
+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;
+
+  long gribrecsize;
+  nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  if ( nerr < 0 )
     {
-      TEMPLATE(decode_array_2byte,T)((size_t) jlend, igrib, fpdata, fmin, zscale);
+      fprintf(stdout, "%5d : GRIB message error\n", nrec);
+      return;
     }
-  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 )
+
+  if ( nerr > 0 )
     {
-      TEMPLATE(decode_array_common,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
+      fprintf(stdout, "%5d : <-- GRIB data corrupted!\n", nrec);
+      return;
     }
-  else if ( numBits > 25 && numBits < 32 )
+
+  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 )
     {
-      TEMPLATE(decode_array_common2,T)(igrib, jlend, numBits, fmin, zscale, fpdata);
+      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;
     }
-  else
+
+  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) || 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
 
-#endif /* T */
+#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
+
+#  define PIXELS_PER_BLOCK    (8)
+#  define PIXELS_PER_SCANLINE (PIXELS_PER_BLOCK*128)
+
+#  define MIN_COMPRESS        (0.95)
+#  define MIN_SIZE            (256)
+#endif
+
+#define  Z_SZIP  128
+#define  Z_AEC   130
+
+
+#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      )))
 
-/*
- * Local Variables:
- * mode: c
- * End:
- */
 
-#ifdef T
-#undef T
-#endif
-#define T float
-#ifdef T
+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;
 
-#include <inttypes.h>
+  int gribversion = gribVersion(gribbuffer, (size_t)recsize);
 
-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;
+  if ( gribversion == 2 ) return (compress);
 
-  unsigned jmask = (1U << n_bits) - 1U;
-  for ( i = 0; i < jlend; i++ )
+  long gribrecsize;
+  nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  if ( nerr < 0 )
     {
-      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, "GRIB message error\n");
+      return (compress);
     }
-  /* 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};
+  if ( nerr > 0 )
+    {
+      fprintf(stdout, "GRIB data corrupted!\n");
+      return (compress);
+    }
 
-  /* code from wgrib routine BDS_unpack */
-  const unsigned char *bits = igrib;
-  long i;
-  int n_bits = NumBits;
-  int c_bits, j_bits;
+  /* 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;
 
-  /* older unoptimized code, not often used */
-  c_bits = 8;
-  for ( i = 0; i < jlend; i++ )
+  *urecsize = 0;
+  if ( lcompress )
     {
-      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 (j_bits)
+      compress = BDS_Z;
+      if ( compress == Z_SZIP || compress == Z_AEC )
 	{
-	  c_bits -= j_bits;
-	  jj = (jj * shift[j_bits]) + (double) (((unsigned)*bits >> c_bits) & mask[j_bits]);
+	  gribsize = gribrec_len(bds[14], bds[15], bds[16]);
 	}
-      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);
+  *urecsize = gribsize;
 
-  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;
-        }
-    }
+  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;
+  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;
 
-  long i;
-#if defined (VECTORCODE)
-  GRIBPACK *lgrib = NULL;
+  gribLen = gribrec_len(dbuf[4], dbuf[5], dbuf[6]);
+  if ( gribLen > JP23SET ) llarge = TRUE;
 
-  if ( numBits%8 == 0 )
-    {
-      long jlenc = jlend * numBits / 8;
-      if ( jlenc > 0 ) 
-	{
-	  lgrib = (GRIBPACK*) Malloc(jlenc*sizeof(GRIBPACK));
-	  if ( lgrib == NULL ) SysError("No Memory!");
+  rec_len = gribLen;
 
-	  (void) UNPACK_GRIB(igrib, lgrib, jlenc, -1L);
-	}
+  long gribrecsize;
+  nerr = grib1Sections(dbuf, dbufsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  if ( nerr < 0 )
+    {
+      fprintf(stdout, "GRIB message error\n");
+      return (rec_len);
     }
 
-  if ( numBits ==  0 )
+  if ( nerr > 0 )
     {
-      for ( i = 0; i < jlend; i++ )
-	fpdata[i] = fmin;
+      fprintf(stdout, "GRIB data corrupted!\n");
+      return (rec_len);
     }
-  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++ )
+
+#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 )
       {
-	T dval = (((int)lgrib[3*i  ] << 16) + ((int)lgrib[3*i+1] <<  8) +
-	  	 (int)lgrib[3*i+2]);
-	fpdata[i] = fmin + zscale * dval;
+	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);
       }
-  else if ( numBits == 32 )
-    for ( i = 0; i < jlend; i++ )
+
+#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 ( lspherc )
       {
-	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;
+	if ( lcomplex  )
+	  {
+	    int jup, ioff;
+	    jup  = bds[15];
+	    ioff = (jup+1)*(jup+2);
+	    bds_ext = 4 + 3 + 4*ioff;
+	  }
+	else
+	  {
+	    bds_ext = 4;
+	  }
       }
-  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);
+    datstart = bds_head + bds_ext;
 
-#else
-  if ( numBits ==  0 )
-    {
-      for ( i = 0; i < jlend; i++ )
-	fpdata[i] = fmin;
-    }
-  else if ( numBits ==  8 )
-    for ( i = 0; i < jlend; i++ )
+    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);
+    */
+    sourceLen = datsize;
+    destLen   = sbufsize;
+    
+    source = bds + datstart;
+    dest = sbuf;
+
+#if defined (HAVE_LIBSZ)
+    if ( bds_nbits == 24 )
       {
-	T dval = (int)igrib[i];
-	fpdata[i] = fmin + zscale * dval;
+	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;
       }
-  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++ )
+#endif
+
+#if defined (HAVE_LIBAEC)
+    strm.next_in = source;
+    strm.avail_in = sourceLen;
+    strm.next_out = dest;
+    strm.avail_out = destLen;
+
+    status = aec_buffer_encode(&strm);
+    if ( status != AEC_OK )
       {
-	T dval = (T)(((int)igrib[3*i  ] << 16) + ((int)igrib[3*i+1] <<  8) +
-                     (int)igrib[3*i+2]);
-	fpdata[i] = fmin + zscale * dval;
+       	if ( status != AEC_DATA_ERROR )
+	  Warning("AEC ERROR: %d code %3d level %3d", status, PDS_Parameter, PDS_Level2);
       }
-  else if ( numBits == 32 )
-    for ( i = 0; i < jlend; i++ )
+
+    destLen = strm.total_out;
+#else
+    status = SZ_BufftoBuffCompress(dest, &destLen, source, sourceLen, &sz_param);
+    if ( status != SZ_OK )
       {
-	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;
+	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 <= 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
-}
+    
+    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) */
 
-#endif /* T */
+	BDS_Flag -= bds_ubits;
+    
+	gribLenOld = gribLen;
 
-/*
- * Local Variables:
- * mode: c
- * End:
- */
+	if ( bds_ext )
+	  for ( 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);
+	  }
 
-#ifdef T
-#undef T
+	bdsLen = datstart + bds_zoffset + destLen;
+
+	bds[11] = 0;
+	bds[12] = 0;
+#if defined (HAVE_LIBAEC)
+	BDS_Z   = Z_AEC;
+#else
+	BDS_Z   = Z_SZIP;
 #endif
-#define T double
-#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;
-  int  locnv = 0, locnl;
-  int  jlenl;
-  int iexp, imant;
-  int ipvpl, ipl;
-  int gdsLen = 0;
-#if defined (VECTORCODE)
-  unsigned char *igrib;
-  GRIBPACK *lgrib = NULL;
-  size_t lGribLen = 0;
+	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 itemp;
+	    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;
+
+	    itemp = gribLen / (-120);
+	    itemp = JP23SET - itemp + 1;
+
+	    SetLen3(dbuf, 4, itemp);
+
+	    bdslen = gribLen - bdslen;
+
+	    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);
+    */
+  }
+
+#else
+  
+  UNUSED(sbuf);
+  UNUSED(sbufsize);
+
+  if ( libszwarn )
+    {
+      Warning("Compression disabled, szlib or libaec not available!");
+      libszwarn = 0;
+    }
 #endif
 
-  *numGridVals = 0;
+  if ( llarge )
+    while ( gribLen%120 ) dbuf[gribLen++] = 0;
+  else
+    while ( gribLen & 7 ) dbuf[gribLen++] = 0;
 
-  memset(isec2, 0, 22*sizeof(int));
+  rec_len = gribLen;
 
-  gdsLen = GDS_Len;
+  return (rec_len);
+}
 
-  ipvpl = GDS_PVPL;
-  if ( ipvpl == 0 ) ipvpl = 0xFF;
 
-  if ( ipvpl != 0xFF )
-    { /* Either vct or reduced grid */
-      if ( GDS_NV != 0 )
-	{ /* we have vct */
-	  VertCoorTab = TRUE;
-	  ipl =  4*GDS_NV + ipvpl - 1;
-	  if ( ipl < gdsLen )
-	    {
-	      ReducedGrid = TRUE;
-	    }
-	}
-      else
-	{
-	  VertCoorTab = FALSE;
-	  ReducedGrid = TRUE;
-	}
-      /*	  ReducedGrid = (gdsLen - 32 - 4*GDS_NV); */
+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;
+
+  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);
     }
- 
-  if ( ISEC0_GRIB_Version == 0 )
+
+  if ( nerr > 0 )
     {
-      if ((gdsLen - 32) > 0) VertCoorTab = TRUE;
-      else                   VertCoorTab = FALSE;
+      fprintf(stdout, "GRIB data corrupted!\n");
+      return (0);
     }
-  
-  if ( ReducedGrid )
+
+  bds_zstart = 14;
+
+  int recLen = gribrec_len(bds[bds_zstart], bds[bds_zstart+1], bds[bds_zstart+2]);
+  if ( recLen > JP23SET ) llarge = TRUE;
+
+  bds_zoffset = 12;
+  if ( llarge ) bds_zoffset += 2;
+
+  /* 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; */
+
+  if ( lspherc )
     {
-      locnl = GDS_PVPL - 1 + (VertCoorTab * 4 * GDS_NV);
-      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, ioff;
+	  jup  = bds[bds_zoffset+15];
+	  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;
+  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);
     }
+
+  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]));
 
-  /*    vertical coordinate parameters for hybrid levels.     */
-  /*    get number of vertical coordinate parameters, if any. */
+  BDS_Flag = (unsigned char)(BDS_Flag - 16);
 
-  ISEC2_NumVCP = 0;
+  size_t bdsLen = datstart + destLen;
 
-  isec2[17] = 0;
-  isec2[18] = 0;
+#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 ( VertCoorTab == TRUE )
-    {
-      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 defined (HAVE_LIBSZ)
+    if ( bds_nbits == 24 )
+      bits_per_sample    = 8;
+    else
+#endif
+      bits_per_sample    = bds_nbits;
 
-      igrib = &gds[locnv];
-      if ( ISEC2_NumVCP > 0 ) (void) UNPACK_GRIB(igrib, lgrib, lGribLen, -1L);
-      for ( int i = 0; i < ISEC2_NumVCP; i++ )
-	{
-	  iexp   = (lgrib[4*i  ]);
-	  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 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
 
-      Free(lgrib);
+    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
-      for ( int i = 0; i < ISEC2_NumVCP; i++ )
-	{
-	  iexp   = (gds[locnv+4*i  ]);
-	  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);
-	}
+    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 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 = 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;
 
-  if ( imiss ) memset((char *)fpdata, 0, (size_t)jlend*sizeof(T));
-  else
-    {
-      igrib += locnd;
+/*       Add regular grid values for this line to the
+         temporary array. */
 
-      TEMPLATE(decode_array,T)(igrib, jlend, ISEC4_NumBits, fmin, zscale, fpdata);
-    }
+         i_2 = iregno;
+         for (j220 = 1; j220 <= i_2; ++j220) {
+            ++ilio;
+            ztemp[ilio - 1] = zline[j220 - 1];
+         }
 
-  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);
-    }
+      } 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;
-	  }
+/*       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];
+         }
       }
+   }
 
-  if ( decscale )
-    {
-      T scale = (T) pow(10.0, (double)-decscale);
-      for ( int i = 0; i < ISEC4_NumValues; i++ ) fsec4[i] *= scale;
-    }
+/* Copy temporary array to user array. */
 
-  return bdsLen;
-}
+   i_1 = klon * klat;
+   for (j240 = 1; j240 <= i_1; ++j240) {
+      pfield[j240] = ztemp[j240 - 1];
+   }
 
+/* -------------------------------------------------------- */
+/* Section 9. Return to calling routine. Format statements. */
+/* -------------------------------------------------------- */
 
-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 *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;
+L900:
 
-  UNUSED(kleng);
+   Free(zline);
+   Free(zwork);
 
-  *iret = 0;
+   return 0;
+} /* qu2reg2 */
 
-  grsdef();
 
-  ISEC2_Reduced = FALSE;
 
-  /*
-    ----------------------------------------------------------------
-    IS Indicator Section (Section 0)
-    ----------------------------------------------------------------
-  */
-  is = (unsigned char *) &kgrib[0];
+#ifdef T
+#undef T
+#endif
+#define T double
+#ifdef T
 
-  isLen = decodeIS(is, isec0, iret);
+/* 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;
 
   /*
-    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);
-    }
-  /*
-    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
+  // Setup the weights
+   */
 
-                 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)
+  range = (double) (ismax - ismin +1);
 
-    Identify which GRIB code edition is being decoded.
+  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));
 
-    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.
+  for( loop = 0; loop < ismax+1; loop++ ) norms[loop] = 0.0;
+  /*
+  // Form norms for the rows which contain part of the unscaled subset.
+   */
 
-    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.
+  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.
+   */
 
-  */
-  if ( ISEC0_GRIB_Len == 24 && ISEC0_GRIB_Version == 0 )
-    {
-      /*
-	Set length of GRIB message to missing data value.
-      */
-      ISEC0_GRIB_Len = 0;
+  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 Grib Edition 1 and only length is required, go to section 9.
-  */
-  if ( dfunc == 'L' ) goto LABEL900;
+  // 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;
+  }
 
   /*
-    ----------------------------------------------------------------
-    PDS Product Definition Section (Section 1)
-    ----------------------------------------------------------------
-  */ 
-  pds = is + isLen;
+  // Do linear fit to find the slope
+   */
 
-  pdsLen = decodePDS(pds, isec0, isec1);
+  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;
 
   /*
-    ----------------------------------------------------------------
-    GDS Grid Description Section (Section 2)
-    ----------------------------------------------------------------
-  */
-  gdsIncluded = ISEC1_Sec2Or3Flag & 128;
+  // Perform a least square fit for the equation
+   */
 
-  if ( gdsIncluded )
-    {
-      gds = is + isLen + pdsLen;
+  for( loop = ismin; loop <= ismax; loop++ ) {
 
-      gdsLen = TEMPLATE(decodeGDS,T)(gds, isec0, isec2, fsec2, &numGridVals);
-    }
+    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;
 
-  /*
-    ----------------------------------------------------------------
-    BMS Bit-Map Section Section (Section 3)
-    ----------------------------------------------------------------
-  */ 
-  bmsIncluded = ISEC1_Sec2Or3Flag & 64;
+  Free(weights);
+  Free(norms);
 
-  isec3[0] = 0;
-  if ( bmsIncluded )
+  pFactor = -slope;
+  if( pFactor < -9999.9 ) pFactor = -9999.9;
+  if( pFactor > 9999.9 )  pFactor = 9999.9;
+
+  return pFactor;
+}
+
+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 )
     {
-      bms = is + isLen + pdsLen + gdsLen;
+      fprintf(stderr, " %s: Invalid power given %6d\n", __func__, pcScale);
+      return;
+   }
 
-      bmsLen = BMS_Len;
-      imaskSize = (bmsLen - 6)<<3;
-      bitmapSize = imaskSize - BMS_UnusedBits;
-      /*
-      fprintf(stderr," bitmapSize = %d %d %d\n", bitmapSize, imaskSize, BMS_UnusedBits);
-      */
-    }
+  /* Setup scaling factors = n(n+1)^^p for n = 1 to truncation */
 
-  /*
-    ----------------------------------------------------------------
-    BDS Binary Data Section (Section 4)
-    ----------------------------------------------------------------
-  */
-  bds = is + isLen + pdsLen + gdsLen + bmsLen;
+  if ( pcScale == 0 ) return;
 
-  bdsLen = ISEC0_GRIB_Len - (isLen + pdsLen + gdsLen + bmsLen);
+  power = (double) pcScale / 1000.;
+  scale[0] = 1.0;
 
-  bdsLen = TEMPLATE(decodeBDS,T)(ISEC1_DecScaleFactor, bds, isec2, isec4, 
-				 fsec4, fsec4len, dfunc, bdsLen, numGridVals, llarge, iret);
+  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 ( *iret != 0 ) return;
+  if ( inv )
+    for ( int n = 1; n <= trunc; n++ ) scale[n] = 1.0 / scale[n];
 
-  ISEC4_NumNonMissValues = ISEC4_NumValues;
+  /* Scale the values */
 
-  if ( bitmapSize > 0 )
-    {
-      if ( dfunc != 'L' && dfunc != 'J' )
-	if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo )
-	  {
-	    lmissvalinfo = 0;
-	    FSEC3_MissVal = (T)GRIB_MISSVAL;
-	    Message("Missing value = NaN is unsupported, set to %g!", GRIB_MISSVAL);
-	  }
+  size_t index = 0;
 
-      /* ISEC4_NumNonMissValues = ISEC4_NumValues; */
-      ISEC4_NumValues        = bitmapSize;
+  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 ( 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;
-	    }
-	  */
+  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]);
+      }
 
-	  GRIBPACK *imask = (GRIBPACK*) Malloc((size_t)imaskSize*sizeof(GRIBPACK));
+  Free(scale);
+}
 
-#if defined (VECTORCODE)
-	  (void) UNPACK_GRIB(BMS_Bitmap, imask, imaskSize/8, -1L);
-	  GRIBPACK *pbitmap = imask;
-#else
-	  GRIBPACK *pbitmap = BMS_Bitmap;
-#endif
 
-#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);
-	    }
+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;
 
-	  int j = 0;
-	  for ( int i = 0; i < ISEC4_NumValues; i++ )
-	    if ( imask[i] ) j++;
+  if ( fphelp == NULL ) SysError("No Memory!");
 
-	  if ( ISEC4_NumNonMissValues != j )
-	    {
-	      if ( dfunc != 'J' && ISEC4_NumBits != 0 )
-		Warning("Bitmap (%d) and data (%d) section differ, using bitmap section!",
-			j, ISEC4_NumNonMissValues);
+  index = inext = 0;
 
-	      ISEC4_NumNonMissValues = j;
-	    }
+  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 ( 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;
-	    }
+  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;
+      }
 
-	  Free(imask);
-	}
-    }
+  for ( m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
 
-  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);
+  Free(fphelp);
+}
 
-      // 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);
+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 ( 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;
+  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;
+      }
 
-	  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 ( 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;
+      }
 
+  for ( size_t m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
 
-  if ( ISEC0_GRIB_Version == 1 ) isLen = 8;
-  esLen = 4;
+  Free(fphelp);
+}
 
-  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);
+void TEMPLATE(scm0,T)(T *pdl, T *pdr, T *pfl, T *pfr, int klg)
+{
+  /* System generated locals */
+  double r_1;
 
-  ISEC0_GRIB_Len = gribLen;
+  /* Local variables */
+  int jl;
+  double zfac, zeps, zbeta;
+  double zalpha;
 
-  *kword = (int)(((size_t)gribLen + sizeof(int) - 1) / sizeof(int));
+  /* **** 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 */
 
-  /*
-    ----------------------------------------------------------------
-    Section 9 . Abort/return to calling routine.
-    ----------------------------------------------------------------
-  */
- LABEL900:;
+  /*  define constants */
 
-  if ( ldebug )
+  zeps = 1.0e-12;
+  zfac = (1.0 - zeps) * 3.0;
+
+  for ( jl = 0; jl < klg; ++jl )
     {
-      gprintf(__func__, "Section 9.");
-      gprintf(__func__, "Output values set -");
+      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 */
 
-      gribPrintSec0(isec0);
-      gribPrintSec1(isec0, isec1);
-      /*
-	Print section 2 if present.
-      */
-      if ( lsect2 ) TEMPLATE(gribPrintSec2,T)(isec0, isec2, fsec2);
+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 ( ! l_iorj )
-	{
-	  /*
-	    Print section 3 if present.
-	  */
-	  if ( lsect3 ) TEMPLATE(gribPrintSec3,T)(isec0, isec3, fsec3);
+  /* Local variables */
+  int jl, ip;
+  double zwt1, zrdi, zpos;
+  double zdo, zwt;
 
-	  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);
-	}
-    }
-}
+  UNUSED(omisng);
 
-#endif /* T */
+  /* Parameter adjustments */
+  --p;
+  pw_dim1 = ko + 3;
+  pw_offset = pw_dim1;
+  pw -= pw_offset;
 
-/*
- * Local Variables:
- * mode: c
- * End:
- */
+  *kret = 0;
 
-#ifdef T
-#undef T
-#endif
-#define T float
-#ifdef T
+  if ( kcode == 1 )
+    {
+      /*    Move input values to work array */
+      for ( jl = 1; jl <= ki; ++jl )
+	pw[jl + pw_dim1] = p[jl];
 
-static 
-int TEMPLATE(decodeGDS,T)(unsigned char  *gds, int *isec0, int *isec2, T *fsec2, int *numGridVals)
-{
-  /* int imisng = 0; */
-  int  ReducedGrid = FALSE, VertCoorTab = FALSE;
-  int  locnv = 0, locnl;
-  int  jlenl;
-  int iexp, imant;
-  int ipvpl, ipl;
-  int gdsLen = 0;
-#if defined (VECTORCODE)
-  unsigned char *igrib;
-  GRIBPACK *lgrib = NULL;
-  size_t lGribLen = 0;
-#endif
+      if ( operio )
+	{
+	  /* Arrange wrap-around value in work array */
+	  pw[ki + 1 + pw_dim1] = p[1];
 
-  *numGridVals = 0;
+	  /* 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];
 
-  memset(isec2, 0, 22*sizeof(int));
+	  /* Set up constants to be used to figure out weighting for */
+	  /* values in interpolation. */
+	  zrdi = (double) (ki-1);
+	  zdo = 1.0 / (double) (ko-1);
+ 	}
 
-  gdsLen = GDS_Len;
+      /*    Loop through the output points */
+      for ( jl = 1; jl <= ko; ++jl )
+	{
 
-  ipvpl = GDS_PVPL;
-  if ( ipvpl == 0 ) ipvpl = 0xFF;
+	  /* Calculate weight from the start of row */
+	  zpos = (jl - 1) * zdo;
+	  zwt = zpos * zrdi;
 
-  if ( ipvpl != 0xFF )
-    { /* Either vct or reduced grid */
-      if ( GDS_NV != 0 )
-	{ /* we have vct */
-	  VertCoorTab = TRUE;
-	  ipl =  4*GDS_NV + ipvpl - 1;
-	  if ( ipl < gdsLen )
+	  /* 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 '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 )
-    {
-      if ((gdsLen - 32) > 0) VertCoorTab = TRUE;
-      else                   VertCoorTab = FALSE;
     }
-  
-  if ( ReducedGrid )
+  else if ( kcode == 3 )
     {
-      locnl = GDS_PVPL - 1 + (VertCoorTab * 4 * GDS_NV);
-      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);
-    }
-
-  /*    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 )
-    {
-      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));
-
-      igrib = &gds[locnv];
-      if ( ISEC2_NumVCP > 0 ) (void) UNPACK_GRIB(igrib, lgrib, lGribLen, -1L);
-      for ( int i = 0; i < ISEC2_NumVCP; i++ )
-	{
-	  iexp   = (lgrib[4*i  ]);
-	  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++ )
-	{
-	  iexp   = (gds[locnv+4*i  ]);
-	  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
+      /*    **************************************    */
+      /*    Section 3.  Invalid interpolation code .. */
+      /*    **************************************    */
+      fprintf(stderr," ROWINA3:");
+      fprintf(stderr," Invalid interpolation code = %2d\n",kcode);
+      *kret = 2;
     }
 
-  return gdsLen;
-}
+L900:
+    return 0;
+} /* rowina3 */
 
-#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 TEMPLATE(qu2reg3,T)(T *pfield, int *kpoint, int klat, int klon,
+			T msval, int *kret, int omisng, int operio, int oveggy)
 {
-  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));
-
-  /* get length of binary data block. */
-
-  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;
-
-  /* 4 bit flag / 4 bit count of unused bits at end of block octet. */
-
-  bds_flag = BDS_Flag;
-
-  /* 0------- grid point           */
-  /* 1------- spherical harmonics  */
-
-  lspherc = bds_flag >> 7;
-
-  if ( lspherc ) isec4[2] = 128;
-  else           isec4[2] = 0;
-
-  /* -0------  simple packing */
-  /* -1------ complex packing */
-
-  lcomplex = (bds_flag >> 6)&1;
-
-  if ( lcomplex ) isec4[3] = 64;
-  else            isec4[3] =  0;
-
-  /* ---0---- No additional flags */
-  /* ---1---- No additional flags */
-
-  lcompress = (bds_flag >> 4)&1; /* compress */
-
-  if ( lcompress )
-    { isec4[5] = 16; isec4[6] = BDS_Z; zoff = 12; }
-  else
-    { isec4[5] =  0; isec4[6] = 0;     zoff =  0; }
-
-  /* ----++++ number of unused bits at end of section) */
-
-  bds_ubits = bds_flag & 0xF;
-  
-  /* scale factor (2 bytes) */;
-
-  jscale = BDS_BinScale;
-
-  /* check for missing data indicators. */
-
-  iexp  = bds[ 6];
-  imant = GET_UINT3(bds[ 7], bds[ 8], bds[ 9]);
-
-  imiss = (jscale == 0xFFFF && iexp == 0xFF && imant == 0xFFFFFF);
-
-  /* convert reference value and scale factor. */
+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 ( ! (dfunc == 'J') && imiss == 0 )
-    {
-      fmin = BDS_RefValue;
-      zscale = TEMPLATE(ldexp,T)((T)1.0, jscale);
-    }
+   /* Local variables */
+   int ilii, ilio, icode;
+   int iregno, iquano, j210, j220, j230, j240, j225;
+   T *ztemp = NULL;
+   T *zline = NULL;
+   T *zwork = NULL;
 
-  /* get number of bits in each data value. */
+   ztemp = (T*) Malloc((size_t)klon*(size_t)klat*sizeof(T));
 
-  ISEC4_NumBits = BDS_NumBits;
+   zline = (T*) Malloc(2*(size_t)klon*sizeof(T));
 
-  /* octet number of start of packed data */
-  /* calculated from start of block 4 - 1 */
+   zwork = (T*) Malloc(3*(2*(size_t)klon+3)*sizeof(T));
 
-  locnd = zoff + bds_head;
+   /* Parameter adjustments */
+   --pfield;
+   --kpoint;
 
-  /* if data is in spherical harmonic form, distinguish   */
-  /* between simple/complex packing (lcomplex = 0/1)      */
+/* ------------------------------ */
+/* Section 1. Set initial values. */
+/* ------------------------------ */
 
-  if ( lspherc )
-    {
-      if ( !lcomplex )
-	{
-	  /*    no unpacked binary data present */
+   *kret = 0;
 
-	  //jup = kup = mup = 0;
+/* Check input parameters. */
 
-	  /*    octet number of start of packed data */
-	  /*    calculated from start of block 4 - 1 */
+   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;
+   }
 
-	  ioff   = 1;
-	  locnd += 4*ioff;  /* RealCoef */
+/* Set array indices to 0. */
 
-	  /*    get real (0,0) coefficient in grib format and     */
-	  /*    convert to floating point.                        */
+   ilii = 0;
+   ilio = 0;
 
-	  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;
+/* Establish values of loop parameters. */
 
-	  /*    pentagonal resolution parameters of the */
-	  /*    unpacked section of data field          */
+   if (kcode > 10) {
 
-	  jup = bds[zoff+15];
-	  kup = bds[zoff+16];
-	  mup = bds[zoff+17];
+/*    Quasi-regular along longitude lines. */
 
-	  isec4[zoff+17] = jup;
-	  isec4[zoff+18] = kup;
-	  isec4[zoff+19] = mup;
+      iquano = klon;
+      iregno = klat;
+      icode = kcode - 10;
+   } else {
 
-	  /*    unpacked binary data */
+/*    Quasi-regular along latitude lines. */
 
-	  locnd += 4; /* 2 + power */
-	  locnd += 3; /* j, k, m   */
-	  ioff   = (jup+1)*(jup+2);
+      iquano = klat;
+      iregno = klon;
+      icode = kcode;
+   }
 
-	  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]);
+/*     -------------------------------------------------------- */
+/**    Section 2. Interpolate field from quasi to regular grid. */
+/*     -------------------------------------------------------- */
 
-		    *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;
-	}
-    }
+   i_1 = iquano;
+   for (j230 = 1; j230 <= i_1; ++j230) {
 
-  /* 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 (iregno != kpoint[j230]) {
 
-  int jlend = bdsLen - locnd;
+/*       Line contains less values than required,so */
+/*       extract quasi-regular grid values for a line */
 
-  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;
-	}
+         i_2 = kpoint[j230];
+         for (j210 = 1; j210 <= i_2; ++j210) {
+            ++ilii;
+            zline[j210 - 1] = pfield[ilii];
+         }
 
-      if ( numGridVals == 0 )
-	{
-	  *iret = 2002;
-	  gprintf(__func__, " Constant field unsupported for this grid type!");
-	  gprintf(__func__, " Return code =  %d", *iret);
-	  return 0;
-	}
+/*       and interpolate this line. */
 
-      jlend = numGridVals;
-      jlend -= ioff;
-    }
-  else
-    {
-      jlend = (jlend*8 - bds_ubits) / ISEC4_NumBits;
-    }
+         TEMPLATE(rowina3,T)(zline, iregno, kpoint[j230], zwork, icode, msval, kret, omisng, operio , oveggy);
+         if (*kret != 0) goto L900;
 
-  ISEC4_NumValues        = jlend + ioff;
-  ISEC4_NumNonMissValues = 0;
+/*       Add regular grid values for this line to the
+         temporary array. */
 
-  if ( lcompress )
-    {
-      size_t len;
+         i_2 = iregno;
+         for (j220 = 1; j220 <= i_2; ++j220) {
+            ++ilio;
+            ztemp[ilio - 1] = zline[j220 - 1];
+         }
 
-      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]));
+      } else {
 
-      ISEC4_NumValues = (int)(len*8/(size_t)ISEC4_NumBits);
+/*       Line contains the required number of values, so add */
+/*       this line to the temporary array. */
 
-      if ( lspherc )
-	{
-	  if ( lcomplex )
-	    ISEC4_NumValues += ioff;
-	  else
-	    ISEC4_NumValues++;
-	}
-    }
+         i_2 = iregno;
+         for (j225 = 1; j225 <= i_2; ++j225) {
+            ++ilio;
+            ++ilii;
+            ztemp[ilio - 1] = pfield[ilii];
+         }
+      }
+   }
 
-  if ( dfunc == 'J' ) return bdsLen;
+/* Copy temporary array to user array. */
 
-  /* 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;
-    }
+   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(zwork);
+   Free(zline);
+   Free(ztemp);
 
-  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;
+} /* qu2reg3 */
 
-  if ( decscale )
-    {
-      T scale = (T) pow(10.0, (double)-decscale);
-      for ( int i = 0; i < ISEC4_NumValues; i++ ) fsec4[i] *= scale;
-    }
+#endif /* T */
 
-  return bdsLen;
-}
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
 
+#ifdef T
+#undef T
+#endif
+#define T float
+#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;
-
-  UNUSED(kleng);
-
-  *iret = 0;
+  /*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;
 
-  grsdef();
+  /*
+  // Setup the weights
+   */
 
-  ISEC2_Reduced = FALSE;
+  range = (double) (ismax - ismin +1);
 
+  weights = (double*) Malloc(((size_t)ismax+1)*sizeof(double));
+  for( loop = ismin; loop <= ismax; loop++ )
+    weights[loop] = range / (double) (loop-ismin+1);
   /*
-    ----------------------------------------------------------------
-    IS Indicator Section (Section 0)
-    ----------------------------------------------------------------
-  */
-  is = (unsigned char *) &kgrib[0];
-
-  isLen = decodeIS(is, isec0, iret);
+  // Compute norms
+  // Handle values 2 at a time (real and imaginary parts).
+   */
+  norms = (double*) Malloc(((size_t)ismax+1)*sizeof(double));
 
+  for( loop = 0; loop < ismax+1; loop++ ) norms[loop] = 0.0;
   /*
-    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);
+  // 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;
+      }
     }
   /*
-    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)
+  // Form norms for the rows which do not contain part of the unscaled subset.
+   */
 
-    Identify which GRIB code edition is being decoded.
+  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;
+    }
 
-    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.
+  /*
+  // Ensure the norms have a value which is not too small in case of
+  // problems with math functions (e.g. LOG).
+   */
 
-    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.
+  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 ( 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;
+  // Do linear fit to find the slope
+   */
+
+  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;
 
   /*
-    ----------------------------------------------------------------
-    PDS Product Definition Section (Section 1)
-    ----------------------------------------------------------------
-  */ 
-  pds = is + isLen;
+  // Perform a least square fit for the equation
+   */
 
-  pdsLen = decodePDS(pds, isec0, isec1);
+  for( loop = ismin; loop <= ismax; loop++ ) {
 
-  /*
-    ----------------------------------------------------------------
-    GDS Grid Description Section (Section 2)
-    ----------------------------------------------------------------
-  */
-  gdsIncluded = ISEC1_Sec2Or3Flag & 128;
+    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 ( gdsIncluded )
-    {
-      gds = is + isLen + pdsLen;
+  Free(weights);
+  Free(norms);
 
-      gdsLen = TEMPLATE(decodeGDS,T)(gds, isec0, isec2, fsec2, &numGridVals);
-    }
+  pFactor = -slope;
+  if( pFactor < -9999.9 ) pFactor = -9999.9;
+  if( pFactor > 9999.9 )  pFactor = 9999.9;
 
-  /*
-    ----------------------------------------------------------------
-    BMS Bit-Map Section Section (Section 3)
-    ----------------------------------------------------------------
-  */ 
-  bmsIncluded = ISEC1_Sec2Or3Flag & 64;
+  return pFactor;
+}
 
-  isec3[0] = 0;
-  if ( bmsIncluded )
-    {
-      bms = is + isLen + pdsLen + gdsLen;
+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));
 
-      bmsLen = BMS_Len;
-      imaskSize = (bmsLen - 6)<<3;
-      bitmapSize = imaskSize - BMS_UnusedBits;
-      /*
-      fprintf(stderr," bitmapSize = %d %d %d\n", bitmapSize, imaskSize, BMS_UnusedBits);
-      */
-    }
+  if ( scale == NULL ) SysError("No Memory!");
 
-  /*
-    ----------------------------------------------------------------
-    BDS Binary Data Section (Section 4)
-    ----------------------------------------------------------------
-  */
-  bds = is + isLen + pdsLen + gdsLen + bmsLen;
+  if ( pcScale < -10000 || pcScale > 10000 )
+    {
+      fprintf(stderr, " %s: Invalid power given %6d\n", __func__, pcScale);
+      return;
+   }
 
-  bdsLen = ISEC0_GRIB_Len - (isLen + pdsLen + gdsLen + bmsLen);
+  /* Setup scaling factors = n(n+1)^^p for n = 1 to truncation */
 
-  bdsLen = TEMPLATE(decodeBDS,T)(ISEC1_DecScaleFactor, bds, isec2, isec4, 
-				 fsec4, fsec4len, dfunc, bdsLen, numGridVals, llarge, iret);
+  if ( pcScale == 0 ) return;
 
-  if ( *iret != 0 ) return;
+  power = (double) pcScale / 1000.;
+  scale[0] = 1.0;
 
-  ISEC4_NumNonMissValues = ISEC4_NumValues;
+  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 ( bitmapSize > 0 )
-    {
-      if ( dfunc != 'L' && dfunc != 'J' )
-	if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo )
-	  {
-	    lmissvalinfo = 0;
-	    FSEC3_MissVal = (T)GRIB_MISSVAL;
-	    Message("Missing value = NaN is unsupported, set to %g!", GRIB_MISSVAL);
-	  }
+  if ( inv )
+    for ( int n = 1; n <= trunc; n++ ) scale[n] = 1.0 / scale[n];
 
-      /* ISEC4_NumNonMissValues = ISEC4_NumValues; */
-      ISEC4_NumValues        = bitmapSize;
+  /* Scale the values */
 
-      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;
-	    }
-	  */
+  size_t index = 0;
 
-	  GRIBPACK *imask = (GRIBPACK*) Malloc((size_t)imaskSize*sizeof(GRIBPACK));
+  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 defined (VECTORCODE)
-	  (void) UNPACK_GRIB(BMS_Bitmap, imask, imaskSize/8, -1L);
-	  GRIBPACK *pbitmap = imask;
-#else
-	  GRIBPACK *pbitmap = BMS_Bitmap;
-#endif
+  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]);
+      }
 
-#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);
-	    }
+  Free(scale);
+}
 
-	  int j = 0;
-	  for ( int i = 0; i < ISEC4_NumValues; i++ )
-	    if ( imask[i] ) j++;
 
-	  if ( ISEC4_NumNonMissValues != j )
-	    {
-	      if ( dfunc != 'J' && ISEC4_NumBits != 0 )
-		Warning("Bitmap (%d) and data (%d) section differ, using bitmap section!",
-			j, ISEC4_NumNonMissValues);
+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 = j;
-	    }
+  if ( fphelp == NULL ) SysError("No Memory!");
 
-	  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;
-	    }
+  index = inext = 0;
 
-	  Free(imask);
-	}
-    }
+  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 ( 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);
+  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;
+      }
 
-      // int dlon = ISEC2_LastLon-ISEC2_FirstLon;
-      // if ( dlon < 0 ) dlon += 360000;
-	  
-      if ( nvalues != ISEC4_NumValues ) *iret = -801;
+  for ( m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
 
-      //printf("nlat %d  nlon %d \n", nlat, nlon);
-      //printf("nvalues %d %d\n", nvalues, ISEC4_NumValues);
+  Free(fphelp);
+}
 
-      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;
-	    }
-	}
-    }
+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;
 
+  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;
+      }
 
-  if ( ISEC0_GRIB_Version == 1 ) isLen = 8;
-  esLen = 4;
+  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;
+      }
 
-  int gribLen = isLen + pdsLen + gdsLen + bmsLen + bdsLen + esLen;
+  for ( size_t m = 0; m < nsp; m++ ) fpdata[m] = fphelp[m];
 
-  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);
+  Free(fphelp);
+}
 
-  ISEC0_GRIB_Len = gribLen;
 
-  *kword = (int)(((size_t)gribLen + sizeof(int) - 1) / sizeof(int));
+void TEMPLATE(scm0,T)(T *pdl, T *pdr, T *pfl, T *pfr, int klg)
+{
+  /* System generated locals */
+  double r_1;
 
-  /*
-    ----------------------------------------------------------------
-    Section 9 . Abort/return to calling routine.
-    ----------------------------------------------------------------
-  */
- LABEL900:;
+  /* Local variables */
+  int jl;
+  double zfac, zeps, zbeta;
+  double zalpha;
 
-  if ( ldebug )
-    {
-      gprintf(__func__, "Section 9.");
-      gprintf(__func__, "Output values set -");
+  /* **** 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 */
 
-      gribPrintSec0(isec0);
-      gribPrintSec1(isec0, isec1);
-      /*
-	Print section 2 if present.
-      */
-      if ( lsect2 ) TEMPLATE(gribPrintSec2,T)(isec0, isec2, fsec2);
+  /*  define constants */
 
-      if ( ! l_iorj )
-	{
-	  /*
-	    Print section 3 if present.
-	  */
-	  if ( lsect3 ) TEMPLATE(gribPrintSec3,T)(isec0, isec3, fsec3);
+  zeps = 1.0e-12;
+  zfac = (1.0 - zeps) * 3.0;
 
-	  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);
+  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;
 	}
     }
-}
-
-#endif /* T */
-
-/*
- * Local Variables:
- * mode: c
- * End:
- */
+} /* scm0 */
 
-/* GRIB block 0 - indicator block */
 static
-void encodeIS(GRIBPACK *lGrib, long *gribLen)
+int TEMPLATE(rowina3,T)(T *p, int ko, int ki, T *pw,
+			int kcode, T msval, int *kret, int omisng, int operio, int oveggy)
 {
-  long z;
-  // z = *gribLen;
+  /*
+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;
 
-  lGrib[0] = 'G';
-  lGrib[1] = 'R';
-  lGrib[2] = 'I';
-  lGrib[3] = 'B';
+  /* Local variables */
+  int jl, ip;
+  double zwt1, zrdi, zpos;
+  double zdo, zwt;
 
-  /* 
-   * lGrib[4]-lGrib[6] contains full length of grib record. 
-   * included before finished CODEGB
-   */
+  UNUSED(omisng);
 
-  z = 7;   
-  Put1Byte(1); /* grib version */
-  z = 8;
+  /* Parameter adjustments */
+  --p;
+  pw_dim1 = ko + 3;
+  pw_offset = pw_dim1;
+  pw -= pw_offset;
 
-  *gribLen = z;
-}
+  *kret = 0;
 
-/* GRIB block 5 - end block */
-static
-void encodeES(GRIBPACK *lGrib, long *gribLen, long bdsstart)
-{
-  long z = *gribLen;
+  if ( kcode == 1 )
+    {
+      /*    Move input values to work array */
+      for ( jl = 1; jl <= ki; ++jl )
+	pw[jl + pw_dim1] = p[jl];
 
-  lGrib[z++] = '7';
-  lGrib[z++] = '7';
-  lGrib[z++] = '7';
-  lGrib[z++] = '7';
+      if ( operio )
+	{
+	  /* Arrange wrap-around value in work array */
+	  pw[ki + 1 + pw_dim1] = p[1];
 
-  if ( z > JP23SET )
-    {
-      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;
+	  /* 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];
 
-      if ( z > JP23SET*120 )
+	  /* Set up constants to be used to figure out weighting for */
+	  /* values in interpolation. */
+	  zrdi = (double) (ki-1);
+	  zdo = 1.0 / (double) (ko-1);
+ 	}
+
+      /*    Loop through the output points */
+      for ( jl = 1; jl <= ko; ++jl )
+	{
+
+	  /* Calculate weight from the start of row */
+	  zpos = (jl - 1) * zdo;
+	  zwt = zpos * zrdi;
+
+	  /* 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 '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 )
+    {
+      /*     *******************************    */
+      /*     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];
+   }
 
-int  BitsPerInt = (int) (sizeof(int) * 8);
+/* -------------------------------------------------------- */
+/* Section 9. Return to calling routine. Format statements. */
+/* -------------------------------------------------------- */
 
+L900:
 
+   Free(zwork);
+   Free(zline);
+   Free(ztemp);
 
-#ifdef T
-#undef T
-#endif
-#define T double
-#ifdef T
+   return 0;
+} /* qu2reg3 */
+
+#endif /* T */
 
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
+#include <string.h>
+
+
+
+int gribVersion(unsigned char *is, size_t buffersize)
+{
+  if ( buffersize < 8 )
+    Error("Buffer too small (current size %d)!", (int) buffersize);
+
+  return (GRIB_EDITION(is));
+}
 
-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)
+static 
+double GET_Real(unsigned char *grib)
 {
-  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 */
+  int iexp, imant;
 
-  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);
+  iexp  = GET_UINT1(grib[0]);
+  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);
+  int isLen = 0;
+  int grib1offset;
+  int lgrib = FALSE, lbudg = FALSE, ltide = FALSE;
 
-  if ( IS_BIGENDIAN() )
+  /*
+    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 )
     {
-      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 == TRUE || ltide == TRUE )
     {
-      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;
+  /*
+    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);
+
+  grib1offset = ISEC0_GRIB_Version * 4;
+
+  isLen = 4 + grib1offset;
+
+  return (isLen);
 }
-/*
-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 
+void decodePDS_ECMWF_local_Extension_1(unsigned char *pds, int *isec1)
 {
-  size_t i, z = *gz;
-  uint16_t ui16;
-  T tmp;
+  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   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;
-    }
+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]);
+    } 
+
+  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) */
 
-  *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;
+static 
+void decodePDS_DWD_local_Extension_253(unsigned char *pds, int *isec1)
+{
+  long i;
+  int isvn;
 
-  if      ( numBits ==  8 )
-    {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(2, "pack 8 bit base");
-#endif
+  isec1[36] = GET_UINT1(pds[40]); /* extension identifier */
+  for ( 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++;
-	}
+  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           */
 
-#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
+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 */
+}
 
-#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 
+int decodePDS(unsigned char *pds, int *isec0, int *isec1)
+{
+  int pdsLen;
 
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(4);
-#endif
-    }
-  else if ( numBits == 32 )
-    {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(5, "pack 32 bit base");
-#endif
+  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_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++) 
+      ISEC1_Year           = PDS_Year;
+      ISEC1_Century        = PDS_Century;
+      ISEC1_SubCenterID    = PDS_Subcenter;
+      ISEC1_DecScaleFactor = PDS_DecimalScale;
+    }
+  else
+    {
+      int year;
+      year                 = GET_UINT1(pds[12]);
+      if ( year <= 100 )
 	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
+	  ISEC1_Year       = year;
+	  ISEC1_Century    = 1;
 	}
-      for (j = 0; j < residual; j++) 
+      else
 	{
-#ifdef _ARCH_PWR6
-	  *cgrib++ = (unsigned long) dval[j];
-#else
-	  *cgrib++ = (unsigned char) dval[j];
-#endif
+	  ISEC1_Year       = year%100;
+	  ISEC1_Century    = 1 + (year-ISEC1_Year)/100;
 	}
-      z += residual;
+      ISEC1_SubCenterID    = 0;
+      ISEC1_DecScaleFactor = 0;
+    }
 
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(2);
-#endif
+  if ( ISEC1_Year < 0 )
+    {
+      ISEC1_Year    = -ISEC1_Year;
+      ISEC1_Century = -ISEC1_Century;
     }
-  else if ( numBits == 16 )
+
+  ISEC1_LocalFLag = 0;
+  if ( pdsLen > 28 )
     {
-#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);
+      int localextlen;
+      localextlen = pdsLen-28;
 
-      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() )
+      if ( localextlen > 4000 )
 	{
-	  for (j = 0; j < residual; j++) 
-	    {
-#ifdef _ARCH_PWR6
-	      *sgrib++ = (unsigned long) dval[j];
-#else
-              *sgrib++ = (uint16_t) dval[j];
-#endif
-	    }
-	  z += 2*residual;
+	  Warning("PDS larger than 4000 bytes not supported!");
 	}
       else
 	{
-	  for (j = 0; j < residual; j++) 
+	  ISEC1_LocalFLag = 1;
+
+	  if ( ISEC1_CenterID == 78 || ISEC1_CenterID == 215 || ISEC1_CenterID == 250 )
 	    {
-              ival = (uint16_t) dval[j];
-	      lGrib[z  ] = (GRIBPACK)(ival >>  8);
-	      lGrib[z+1] = (GRIBPACK)ival;
-	      z += 2;
+	      if ( pds[40] == 254 ) 
+		{
+		  decodePDS_DWD_local_Extension_254(pds, isec1);
+		}
+	      else if ( pds[40] == 253 )
+		{ 
+		  decodePDS_DWD_local_Extension_253(pds, isec1);
+		}
 	    }
-	}
-#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 += __UNROLL_DEPTH_2 ) 
-	{
-	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
+	  else if ( (ISEC1_CenterID    == 98 && ISEC1_LocalFLag ==  1) ||
+		    (ISEC1_SubCenterID == 98 && ISEC1_LocalFLag ==  1) ||
+		    (ISEC1_CenterID    ==  7 && ISEC1_SubCenterID == 98) )
 	    {
-	      dval[j] = ((data[i+j] - zref) * factor + (T)0.5);
+	      if ( pds[40] == 1 )
+		decodePDS_ECMWF_local_Extension_1(pds, isec1);
 	    }
-	  for (j = 0; j < __UNROLL_DEPTH_2; j++) 
+	  else if ( ISEC1_CenterID    == 252 && ISEC1_LocalFLag ==  1 )
 	    {
-#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 ( 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];
+		}
 	    }
 	}
-      for (j = 0; j < residual; j++) 
+    }
+
+  return (pdsLen);
+}
+
+
+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 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)
 	{
-	  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 */
@@ -17681,1153 +15923,1142 @@ void TEMPLATE(encode_array_unrolled,T)(int numBits, size_t packStart, size_t dat
 #define T float
 #ifdef T
 
+#include <inttypes.h>
 
-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)
+static 
+void TEMPLATE(decode_array_common,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 */
+  /* 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;
 
-  cbits = 8;
-  c = 0;
-  for ( i = packStart; i < datasize; i++ )
+  unsigned jmask = (1U << n_bits) - 1U;
+  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 ) 
+      if (n_bits - t_bits > 8)
 	{
-	  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;
-	    }
+	  tbits = (tbits << 16) | ((unsigned)bits[0] << 8) | ((unsigned)bits[1]);
+	  bits += 2;
+	  t_bits += 16;
 	}
-      /* now jbits < cbits */
-      if ( jbits )
+
+      while ( t_bits < n_bits )
 	{
-	  c = (c << jbits) + (ival & mask[jbits]);
-	  cbits -= jbits;
+	  tbits = (tbits * 256) + *bits++;
+	  t_bits += 8;
 	}
+      t_bits -= n_bits;
+      fpdata[i] = (float)((tbits >> t_bits) & jmask);
     }
-  if ( cbits != 8 ) lGrib[z++] = (GRIBPACK)(c << cbits);
-
-  *gz = z;
+  /* at least this vectorizes :) */
+  for ( i = 0; i < jlend; i++ )
+    fpdata[i] = fmin + zscale*fpdata[i];
 }
 
-
 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_common2,T)(const unsigned char *restrict igrib, long jlend, int NumBits,
+				      T fmin, T zscale, T *restrict fpdata)
 {
-  U_BYTEORDER;
-  uint16_t *restrict sgrib = (uint16_t *) (lGrib+*gz);
-
-  if ( IS_BIGENDIAN() )
-    {
-      for ( size_t i = 0; i < datasize; i++ )
-        {
-          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) ((data[i] - zref) * factor + (T)0.5);
-          sgrib[i] = gribSwapByteOrder_uint16(ui16);
-        }
-    }
+  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};
 
-  *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;
+  /* code from wgrib routine BDS_unpack */
+  const unsigned char *bits = igrib;
+  long i;
+  int n_bits = NumBits;
+  int c_bits, j_bits;
 
-#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++ )
+  /* older unoptimized code, not often used */
+  c_bits = 8;
+  for ( i = 0; i < jlend; i++ )
     {
-      tmp = ((data[i] - zref) * factor + (T)0.5);
-      ui16 = (uint16_t) tmp;
-      lGrib[z  ] = ui16 >>  8;
-      lGrib[z+1] = ui16;
-      z += 2;
+      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 (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);
     }
-
-  *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)
+void TEMPLATE(decode_array_2byte,T)(size_t jlend, const unsigned char *restrict igrib,
+                                    T *fpdata, T fmin, T zscale)
 {
-#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;
+  U_BYTEORDER;
+  const uint16_t *restrict sgrib = (uint16_t *) (igrib);
 
-  if      ( numBits ==  8 )
+  if ( IS_BIGENDIAN() )
     {
-#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 = ((data[i] - zref) * factor + (T)0.5);
-	  lGrib[z  ] = (GRIBPACK)tmp;
-          z++;
-	}
-
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(2);
-#endif
+      for ( size_t i = 0; i < jlend; i++ )
+        {
+          fpdata[i] = fmin + zscale * sgrib[i];
+        }
     }
-  else if ( numBits == 16 )
+  else
     {
-#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
+      uint16_t ui16;
+      for ( size_t i = 0; i < jlend; i++ )
         {
-          TEMPLATE(encode_array_2byte,T)(datasize, lGrib, data, zref, factor, &z);
+          ui16 = gribSwapByteOrder_uint16(sgrib[i]);
+          fpdata[i] = fmin + zscale * ui16;
         }
-
-#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
+}
 
-#if   defined (CRAY)
-#pragma _CRI ivdep
-#elif defined (SX)
-#pragma vdir nodep
-#elif defined (__uxp__)
-#pragma loop novrec
-#elif defined (__ICC)
-#pragma ivdep
+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
-      for ( i = 0; i < datasize; i++ )
+
+  long i;
+#if defined (VECTORCODE)
+  GRIBPACK *lgrib = NULL;
+
+  if ( numBits%8 == 0 )
+    {
+      long jlenc = jlend * numBits / 8;
+      if ( jlenc > 0 ) 
 	{
-	  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;
+	  lgrib = (GRIBPACK*) Malloc(jlenc*sizeof(GRIBPACK));
+	  if ( lgrib == NULL ) SysError("No Memory!");
+
+	  (void) UNPACK_GRIB(igrib, lgrib, jlenc, -1L);
 	}
+    }
 
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(4);
-#endif
+  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 )
     {
-#ifdef _GET_IBM_COUNTER 
-      hpmStart(5, "pack 32 bit base");
-#endif
+      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   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;
-	}
+  if ( lgrib ) Free(lgrib);
 
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(5);
-#endif
+#else
+  if ( numBits ==  0 )
+    {
+      for ( i = 0; i < jlend; i++ )
+	fpdata[i] = fmin;
     }
-  else if ( numBits > 0 && numBits <= 32 )
+  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(encode_array_common,T)(numBits, 0, datasize, lGrib, data, zref, factor, &z);
+      TEMPLATE(decode_array_2byte,T)((size_t) jlend, igrib, fpdata, fmin, zscale);
     }
-  else if ( numBits == 0 )
+  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);
     }
-
-  *gz = z;
+#endif
 }
 
-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];
+#endif /* T */
 
-  data += packStart;
-  datasize -= packStart;
-  residual =  datasize % __UNROLL_DEPTH_2;
-  ofs = datasize - residual;
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
 
-  // reducing FP operations to single FMA is slowing down on pwr6 ...
 
-  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 += __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];
+#ifdef T
+#undef T
 #endif
-	}
-      z += residual;
+#define T double
+#ifdef T
 
-#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;
+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
-      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++) 
+  *numGridVals = 0;
+
+  memset(isec2, 0, 22*sizeof(int));
+
+  int gdsLen = GDS_Len;
+
+  int ipvpl = GDS_PVPL;
+  if ( ipvpl == 0 ) ipvpl = 0xFF;
+
+  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 )
 	    {
-#ifdef _ARCH_PWR6
-	      *sgrib++ = (unsigned long) dval[j];
-#else
-              *sgrib++ = (uint16_t) dval[j];
-#endif
+	      ReducedGrid = TRUE;
 	    }
-	  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;
-	    }
+	  VertCoorTab = FALSE;
+	  ReducedGrid = TRUE;
 	}
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(3);
-#endif
+      /*	  ReducedGrid = (gdsLen - 32 - 4*GDS_NV); */
     }
-  else if ( numBits == 24 )
+ 
+  if ( ISEC0_GRIB_Version == 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++) 
-	{
-	  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
+      VertCoorTab = (gdsLen - 32) > 0;
     }
-  else if ( numBits == 32 )
+  
+  if ( ReducedGrid )
     {
-#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() )
-	    {
-	      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;
-		}
-	    }
-	  else
+      int locnl = GDS_PVPL - 1 + (VertCoorTab * 4 * GDS_NV);
+      int jlenl = (gdsLen - locnl)  >> 1;
+      if ( jlenl == GDS_NumLat )
+	{
+	  *numGridVals = 0;
+	  ISEC2_Reduced = TRUE;
+	  for ( int i = 0; i < jlenl; i++ )
 	    {
-	      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;
-		}
+	      ISEC2_RowLon(i) = GET_UINT2(gds[locnl+2*i], gds[locnl+2*i+1]);
+	      *numGridVals += ISEC2_RowLon(i);
 	    }
 	}
-      for (j = 0; j < residual; j++) 
+      else
 	{
-	  dval[j] = ((data[ofs+j] - zref) * factor + (T)0.5);
+	  ReducedGrid = FALSE;
 	}
-      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;
-	    }
+    }
+
+  ISEC2_GridType = GDS_GridType;
+
+  /*
+     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;
 	}
-      else
+      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 )
 	{
-          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;
-	    }
+	  ISEC2_LatSP     = GDS_LatSP;
+	  ISEC2_LonSP     = GDS_LonSP;
+	  FSEC2_RotAngle  = (T)GDS_RotAngle;
 	}
-#ifdef _GET_IBM_COUNTER 
-      hpmStop(5);
-#endif
+      /*
+	if ( Lons != Longitudes || Lats != Latitudes )
+	Error("Latitude/Longitude Conflict");
+      */
     }
-  else if ( numBits > 0 && numBits <= 32 )
+  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 )
     {
-      TEMPLATE(encode_array_common,T)(numBits, 0, datasize, lGrib, data, zref, factor, &z);
+      /*
+      iret = decodeGDS_GG(gds, gdspos, isec0, isec2, imisng);
+      */
     }
-  else if ( numBits == 0 )
+  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
     {
-      Error("Unimplemented packing factor %d!", numBits);
+      ISEC2_NumLon = GDS_NumLon;
+      ISEC2_NumLat = GDS_NumLat;
+      *numGridVals  = ISEC2_NumLon*ISEC2_NumLat;
+      Message("Gridtype %d unsupported", ISEC2_GridType);
     }
 
-  *gz = z;
-#undef __UNROLL_DEPTH_2
-}
+  /*    vertical coordinate parameters for hybrid levels.     */
+  /*    get number of vertical coordinate parameters, if any. */
 
-#endif /* T */
+  ISEC2_NumVCP = 0;
 
-/*
- * Local Variables:
- * mode: c
- * End:
- */
+  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));
 
+      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));
+	}
 
-#ifdef T
-#undef T
+      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
-#define T double
-#ifdef T
+    }
+
+  return gdsLen;
+}
+
+#define ldexp_double ldexp
+#define ldexp_float ldexpf
 
-/* GRIB BLOCK 2 - GRID DESCRIPTION SECTION */
 static
-void TEMPLATE(encodeGDS,T)(GRIBPACK *lGrib, long *gribLen, int *isec2, T *fsec2)
+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)
 {
-  long z = *gribLen;
-  int exponent, mantissa;
-  long i;
-  int ival;
-  int pvoffset = 0xFF;
-  int gdslen = 32;
-  unsigned lonIncr, latIncr;
+  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;
 
-  if ( ISEC2_GridType == GRIB1_GTYPE_LCC ) gdslen += 10;
+  *iret = 0;
+  igrib = bds;
 
-  if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )  gdslen += 10;
+  memset(isec4, 0, 42*sizeof(int));
 
-  if ( ISEC2_NumVCP || ISEC2_Reduced ) pvoffset = gdslen + 1;
+  /* get length of binary data block. */
 
-  if ( ISEC2_Reduced ) gdslen += 2 * ISEC2_NumLat;
+  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;
 
-  gdslen += ISEC2_NumVCP * 4;
+  /* 4 bit flag / 4 bit count of unused bits at end of block octet. */
 
-  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 */
+  bds_flag = BDS_Flag;
 
-  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               */
+  /* 0------- grid point           */
+  /* 1------- spherical harmonics  */
 
-      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;
-      if ( ISEC2_Reduced )
-	numlon = 0xFFFF;
-      else
-	numlon = ISEC2_NumLon;
+  lspherc = bds_flag >> 7;
 
-      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                 */
+  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 */
+
+  lcompress = (bds_flag >> 4)&1; /* compress */
+
+  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));
+  bds_ubits = bds_flag & 0xF;
+  
+  /* scale factor (2 bytes) */;
 
-  *gribLen = z;
-}
+  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!");
-    }
+  iexp  = bds[ 6];
+  imant = GET_UINT3(bds[ 7], bds[ 8], bds[ 9]);
 
-  bitmapSize = ISEC4_NumValues;
-  imaskSize = ((bitmapSize+7)>>3)<<3;
-  bitmap = &lGrib[z+6];
-  fsec4size = 0;
+  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;
 
-  for ( i = 0; i < bitmapSize; i++ )
+  /* octet number of start of packed data */
+  /* calculated from start of block 4 - 1 */
+
+  locnd = zoff + bds_head;
+
+  /* if data is in spherical harmonic form, distinguish   */
+  /* between simple/complex packing (lcomplex = 0/1)      */
+
+  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 */
 
-  bmsLen = imaskSize/8 + 6;
-  bmsUnusedBits = imaskSize - bitmapSize;
+	  //jup = kup = mup = 0;
 
-  Put3Byte(bmsLen);   /*  0- 2 Length of Block 3 Byte 0 */
-  Put1Byte(bmsUnusedBits);
-  Put2Byte(0);
+	  /*    octet number of start of packed data */
+	  /*    calculated from start of block 4 - 1 */
 
-  *gribLen += bmsLen;
+	  ioff   = 1;
+	  locnd += 4*ioff;  /* RealCoef */
 
-  *datasize = fsec4size;
-}
+	  /*    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 /* complex packed spherical harmonics */
+	{
+	  isec4[15] = BDS_PackData;
+	  /*    scaling factor */
+	  isec4[16] = BDS_Power;
 
-/* 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 */
+	  /*    pentagonal resolution parameters of the */
+	  /*    unpacked section of data field          */
 
-  size_t z = (size_t)*gribLen;
-  long i;
-  int numBits;
-  int ival;
-  long PackStart = 0, Flag = 0;
-  int binscale = 0;
-  int nbpv;
-  int bds_head = 11;
-  int bds_ext = 0;
-  /* ibits = BitsPerInt; */
-  int exponent, mantissa;
-  int lspherc = FALSE, lcomplex = FALSE;
-  int isubset = 0, itemp = 0, itrunc = 0;
-  T factor = 1, fmin, fmax;
-  double zref;
-  double range;
-  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 */
+	  jup = bds[zoff+15];
+	  kup = bds[zoff+16];
+	  mup = bds[zoff+17];
 
-  if ( isec2 )
-    {
-      /* If section 2 is present, it says if data is spherical harmonic */
+	  isec4[zoff+17] = jup;
+	  isec4[zoff+18] = kup;
+	  isec4[zoff+19] = mup;
 
-      lspherc =  ( isec2[0] == 50 || isec2[0] == 60 ||
-                   isec2[0] == 70 || isec2[0] == 80 );
+	  /*    unpacked binary data */
 
-      if ( lspherc )
-	isec4[2] = 128;
-      else
-	isec4[2] = 0;
+	  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
+		  {
+		    iexp   = (bds[locnd+4*i  ]);
+		    imant  =((bds[locnd+4*i+1]) << 16) +
+		            ((bds[locnd+4*i+2]) <<  8) +
+		             (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 0;
+	}
     }
 
-  /* Complex packing supported for spherical harmonics. */
-
-  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 0;
 	}
-      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 0;
 	}
-    }
 
-  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 = (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;
-	}
+      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);
+
+      if ( lspherc )
 	{
-	  bds_ext = 4;
-	  PackStart = 1;
-	  Flag = 128;
+	  if ( lcomplex )
+	    ISEC4_NumValues += ioff;
+	  else
+	    ISEC4_NumValues++;
 	}
     }
 
-  *datstart = bds_head + bds_ext;
-
-  nbpv = numBits = ISEC4_NumBits;
+  if ( dfunc == 'J' ) return bdsLen;
 
-  if ( lspherc && lcomplex )
+  /* 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 0;
     }
 
-  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);
+    }
 
-  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;
     }
 
+  return bdsLen;
+}
 
-  long blockLength = (*datstart) + (nbpv*(datasize - PackStart) + 7)/8;
-  blockLength += blockLength & 1;
 
-  long unused_bits = blockLength*8 - (*datstart)*8 - nbpv*(datasize - PackStart);
+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 *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;
 
-  Flag += unused_bits;
+  UNUSED(kleng);
 
+  *iret = 0;
+
+  grsdef();
+
+  ISEC2_Reduced = FALSE;
 
   /*
-    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).           
+    ----------------------------------------------------------------
+    IS Indicator Section (Section 0)
+    ----------------------------------------------------------------
   */
-  range = fabs(fmax - fmin);
+  is = (unsigned char *) &kgrib[0];
+
+  isLen = decodeIS(is, isec0, iret);
 
-  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 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 ( 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 )
+  if ( ISEC0_GRIB_Len < 0 )
     {
-      binscale = 1 - nbpv;
+      if ( ldebug )
+	gprintf(__func__, "Special case, negative length multiplied by -120");
+      llarge = TRUE;
+      ISEC0_GRIB_Len *= (-120);
     }
-  else if ( range > 1.0 )
+  /*
+    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.
+
+    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.
+
+  */
+  if ( ISEC0_GRIB_Len == 24 && ISEC0_GRIB_Version == 0 )
     {
-      double rangec = range + jpepsln,
-        p2 = 2.0;
-      long 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);
-        }
+      /*
+	Set length of GRIB message to missing data value.
+      */
+      ISEC0_GRIB_Len = 0;
     }
-  else
+  /*
+    If Grib Edition 1 and only length is required, go to section 9.
+  */
+  if ( dfunc == 'L' ) goto LABEL900;
+
+  /*
+    ----------------------------------------------------------------
+    PDS Product Definition Section (Section 1)
+    ----------------------------------------------------------------
+  */ 
+  pds = is + isLen;
+
+  pdsLen = decodePDS(pds, isec0, isec1);
+
+  /*
+    ----------------------------------------------------------------
+    GDS Grid Description Section (Section 2)
+    ----------------------------------------------------------------
+  */
+  gdsIncluded = ISEC1_Sec2Or3Flag & 128;
+
+  if ( gdsIncluded )
     {
-      double rangec = range - jpepsln, p05 = 0.5;
-      long 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);
-	}
+      gds = is + isLen + pdsLen;
+
+      gdsLen = TEMPLATE(decodeGDS,T)(gds, isec0, isec2, fsec2, &numGridVals);
     }
 
-  uint64_t max_nbpv_pow2 = (uint64_t) ((1ULL << nbpv) - 1);
+  /*
+    ----------------------------------------------------------------
+    BMS Bit-Map Section Section (Section 3)
+    ----------------------------------------------------------------
+  */ 
+  bmsIncluded = ISEC1_Sec2Or3Flag & 64;
 
-  if ( binscale != 0 )
+  isec3[0] = 0;
+  if ( bmsIncluded )
     {
-      if ( binscale < 0 )
-        while ( (uint64_t)(ldexp(range, -binscale)+0.5) > max_nbpv_pow2 ) binscale++;
-      else
-        while ( (uint64_t)(ldexp(range, -binscale)+0.5) > max_nbpv_pow2 ) binscale--;
+      bms = is + isLen + pdsLen + gdsLen;
 
-      factor = intpow2(-binscale);
+      bmsLen = BMS_Len;
+      imaskSize = (bmsLen - 6)<<3;
+      bitmapSize = imaskSize - BMS_UnusedBits;
+      /*
+      fprintf(stderr," bitmapSize = %d %d %d\n", bitmapSize, imaskSize, BMS_UnusedBits);
+      */
     }
 
-  ref2ibm(&zref, BitsPerInt);
+  /*
+    ----------------------------------------------------------------
+    BDS Binary Data Section (Section 4)
+    ----------------------------------------------------------------
+  */
+  bds = is + isLen + pdsLen + gdsLen + bmsLen;
 
-  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             */
+  bdsLen = ISEC0_GRIB_Len - (isLen + pdsLen + gdsLen + bmsLen);
 
-  if ( lspherc )
+  bdsLen = TEMPLATE(decodeBDS,T)(ISEC1_DecScaleFactor, bds, isec2, isec4, 
+				 fsec4, fsec4len, dfunc, bdsLen, numGridVals, llarge, iret);
+
+  if ( *iret != 0 ) return;
+
+  ISEC4_NumNonMissValues = ISEC4_NumValues;
+
+  if ( bitmapSize > 0 )
     {
-      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
+      if ( dfunc != 'L' && dfunc != 'J' )
+	if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo )
+	  {
+	    lmissvalinfo = 0;
+	    FSEC3_MissVal = (T)GRIB_MISSVAL;
+	    Message("Missing value = NaN is unsupported, set to %g!", GRIB_MISSVAL);
+	  }
+
+      /* ISEC4_NumNonMissValues = ISEC4_NumValues; */
+      ISEC4_NumValues        = bitmapSize;
+
+      if ( dfunc != 'J' || bitmapSize == ISEC4_NumNonMissValues )
 	{
-	  Put1Real((double)(data[0]));
-	}
-    }
+	  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;
+	    }
+	  */
 
-  *datsize  = ((datasize-PackStart)*nbpv + 7)/8;
+	  GRIBPACK *imask = (GRIBPACK*) Malloc((size_t)imaskSize*sizeof(GRIBPACK));
 
-#if  defined  (_ARCH_PWR6)
-  TEMPLATE(encode_array_unrolled,T)(nbpv, (size_t)PackStart, (size_t)datasize, lGrib, data, (T)zref, factor, &z);
+#if defined (VECTORCODE)
+	  (void) UNPACK_GRIB(BMS_Bitmap, imask, imaskSize/8, -1L);
+	  GRIBPACK *pbitmap = imask;
 #else
-  TEMPLATE(encode_array,T)(nbpv, (size_t)PackStart, (size_t)datasize, lGrib, data, (T)zref, factor, &z);
+	  GRIBPACK *pbitmap = BMS_Bitmap;
 #endif
 
-  if ( unused_bits >= 8 ) Put1Byte(0);  /*  Fillbyte                     */
-
-  *gribLen = (long)z;
+#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);
+	    }
 
-  return (0);
-}
+	  int j = 0;
+	  for ( int i = 0; i < ISEC4_NumValues; i++ )
+	    if ( imask[i] ) j++;
 
+	  if ( ISEC4_NumNonMissValues != j )
+	    {
+	      if ( dfunc != 'J' && ISEC4_NumBits != 0 )
+		Warning("Bitmap (%d) and data (%d) section differ, using bitmap section!",
+			j, ISEC4_NumNonMissValues);
 
-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;
+	      ISEC4_NumNonMissValues = j;
+	    }
 
-  UNUSED(isec3);
-  UNUSED(efunc);
+	  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;
+	    }
 
-  grsdef();
+	  Free(imask);
+	}
+    }
 
-  CGrib = (unsigned char *) kgrib;
+  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);
 
-  bmsIncluded = ISEC1_Sec2Or3Flag & 64;
+      // int dlon = ISEC2_LastLon-ISEC2_FirstLon;
+      // if ( dlon < 0 ) dlon += 360000;
+	  
+      if ( nvalues != ISEC4_NumValues ) *iret = -801;
 
-  /* set max header len */
-  size_t len = 16384;
+      //printf("nlat %d  nlon %d \n", nlat, nlon);
+      //printf("nvalues %d %d\n", nvalues, ISEC4_NumValues);
 
-  /* add data len */
-  size_t numBytes = (size_t)((ISEC4_NumBits+7)>>3);
+      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;
 
-  len += numBytes*(size_t)klenp;
+	  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;
+	    }
+	}
+    }
 
-  /* add bitmap len */
-  if ( bmsIncluded ) len += (size_t)((klenp+7)>>3);
 
-#if defined (VECTORCODE)
-  lGrib = (GRIBPACK*) Malloc(len*sizeof(GRIBPACK));
-  if ( lGrib == NULL ) SysError("No Memory!");
-#else
-  lGrib = CGrib;
-#endif
+  if ( ISEC0_GRIB_Version == 1 ) isLen = 8;
+  esLen = 4;
 
-  isLen = 8;
-  encodeIS(lGrib, &gribLen);
-  lpds = &lGrib[isLen];
-  pdsLen = getPdsLen(isec1);
+  int gribLen = isLen + pdsLen + gdsLen + bmsLen + bdsLen + esLen;
 
-  encodePDS(lpds, pdsLen,  isec1);
-  gribLen += pdsLen;
-  /*
-  if ( ( isec4[3] == 64 ) && ( isec2[5] == 2 ) )
-    {
-      static int lwarn_cplx = TRUE;
+  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);
 
-      if ( lwarn_cplx )
-	Message("Complex packing of spectral data unsupported, using simple packing!");
+  ISEC0_GRIB_Len = gribLen;
 
-      isec2[5] = 1;
-      isec4[3] = 0;
+  *kword = (int)(((size_t)gribLen + sizeof(int) - 1) / sizeof(int));
 
-      lwarn_cplx = FALSE;
-    }
-  */
-  TEMPLATE(encodeGDS,T)(lGrib, &gribLen, isec2, fsec2);
   /*
     ----------------------------------------------------------------
-    BMS Bit-Map Section Section (Section 3)
+    Section 9 . Abort/return to calling routine.
     ----------------------------------------------------------------
-  */ 
-  if ( bmsIncluded )
-    {
-      TEMPLATE(encodeBMS,T)(lGrib, &gribLen, fsec3, isec4, fsec4, &fsec4size);
-    }
-  else
-    {
-      fsec4size = ISEC4_NumValues;
-    }
+  */
+ LABEL900:;
 
-  bdsstart = gribLen;
-  status = TEMPLATE(encodeBDS,T)(lGrib, &gribLen, ISEC1_DecScaleFactor, isec2,
-				 isec4, fsec4size, fsec4, &datstart, &datsize, ISEC1_Parameter);
-  if ( status )
+  if ( ldebug )
     {
-      *kret = status;
-      return;
-    }
-
-  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 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);
-
-  Free(lGrib);
-#endif
+      gprintf(__func__, "Section 9.");
+      gprintf(__func__, "Output values set -");
 
-  ISEC0_GRIB_Len     = (int)gribLen;
-  ISEC0_GRIB_Version = 1;
+      gribPrintSec0(isec0);
+      gribPrintSec1(isec0, isec1);
+      /*
+	Print section 2 if present.
+      */
+      if ( lsect2 ) TEMPLATE(gribPrintSec2,T)(isec0, isec2, fsec2);
 
-  *kword = (int)((gribLen + (long)sizeof(int) - 1) / (long)sizeof(int));
+      if ( ! l_iorj )
+	{
+	  /*
+	    Print section 3 if present.
+	  */
+	  if ( lsect3 ) TEMPLATE(gribPrintSec3,T)(isec0, isec3, fsec3);
 
-  *kret = status;
+	  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 */
@@ -18844,3552 +17075,4322 @@ 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;
-
-  if ( ISEC2_GridType == GRIB1_GTYPE_LCC ) gdslen += 10;
-
-  if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )  gdslen += 10;
+  /* int imisng = 0; */
+  int  ReducedGrid = FALSE, VertCoorTab = FALSE;
+#if defined (VECTORCODE)
+  unsigned char *igrib;
+  GRIBPACK *lgrib = NULL;
+  size_t lGribLen = 0;
+#endif
 
-  if ( ISEC2_NumVCP || ISEC2_Reduced ) pvoffset = gdslen + 1;
+  *numGridVals = 0;
 
-  if ( ISEC2_Reduced ) gdslen += 2 * ISEC2_NumLat;
+  memset(isec2, 0, 22*sizeof(int));
 
-  gdslen += ISEC2_NumVCP * 4;
+  int gdsLen = GDS_Len;
 
-  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 */
+  int ipvpl = GDS_PVPL;
+  if ( ipvpl == 0 ) ipvpl = 0xFF;
 
-  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);
+  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); */
     }
-  else if ( ISEC2_GridType == GRIB1_GTYPE_LCC )
+ 
+  if ( ISEC0_GRIB_Version == 0 )
     {
-      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 */
+      VertCoorTab = (gdsLen - 32) > 0;
     }
-  else if ( ISEC2_GridType == GRIB1_GTYPE_LATLON    ||
-	    ISEC2_GridType == GRIB1_GTYPE_GAUSSIAN  ||
-	    ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
+  
+  if ( ReducedGrid )
     {
-      int numlon;
-      if ( ISEC2_Reduced )
-	numlon = 0xFFFF;
-      else
-	numlon = 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);
-      if ( ISEC2_ResFlag == 0 )
+      int locnl = GDS_PVPL - 1 + (VertCoorTab * 4 * GDS_NV);
+      int jlenl = (gdsLen - locnl)  >> 1;
+      if ( jlenl == GDS_NumLat )
 	{
-	  lonIncr = 0xFFFF;
-	  latIncr = 0xFFFF;
+	  *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);
+	    }
 	}
       else
 	{
-	  lonIncr = (unsigned)ISEC2_LonIncr;
-	  latIncr = (unsigned)ISEC2_LatIncr;
+	  ReducedGrid = FALSE;
 	}
-      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                 */
+  ISEC2_GridType = GDS_GridType;
+
+  /*
+     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;
 
+      ISEC2_NumPar    = GDS_NumPar;
+      ISEC2_ScanFlag  = GDS_ScanFlag;
       if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
 	{
-	  Put3Int(ISEC2_LatSP);
-	  Put3Int(ISEC2_LonSP);
-	  Put1Real((double)(FSEC2_RotAngle));
+	  ISEC2_LatSP     = GDS_LatSP;
+	  ISEC2_LonSP     = GDS_LonSP;
+	  FSEC2_RotAngle  = (T)GDS_RotAngle;
 	}
+      /*
+	if ( Lons != Longitudes || Lats != Latitudes )
+	Error("Latitude/Longitude Conflict");
+      */
     }
-  else
+  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 )
     {
-      Error("Unsupported grid type %d", ISEC2_GridType);
+      /*
+      iret = decodeGDS_GG(gds, gdspos, isec0, isec2, imisng);
+      */
     }
-
-#if defined (SX)
-#pragma vdir novector     /* vectorization gives wrong results on NEC */
-#endif
-  for ( i = 0; i < ISEC2_NumVCP; ++i )
+  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 )
     {
-      Put1Real((double)(fsec2[10+i]));
+      /*
+      iret = decodeGDS_LL(gds, gdspos, isec0, isec2, imisng);
+      */
     }
-
-  if ( ISEC2_Reduced )
-    for ( i = 0; i < ISEC2_NumLat; i++ ) Put2Byte(ISEC2_RowLon(i));
-
-  *gribLen = z;
-}
-
-/* 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; */
-
-  if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo)
+  else if ( ISEC2_GridType == GRIB1_GTYPE_LCC )
     {
-      lmissvalinfo = 0;
-      Message("Missing value = NaN is unsupported!");
+      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);
     }
 
-  bitmapSize = ISEC4_NumValues;
-  imaskSize = ((bitmapSize+7)>>3)<<3;
-  bitmap = &lGrib[z+6];
-  fsec4size = 0;
+  /*    vertical coordinate parameters for hybrid levels.     */
+  /*    get number of vertical coordinate parameters, if any. */
 
-#if defined (VECTORCODE)
-  imask = (unsigned int*) Malloc(imaskSize*sizeof(unsigned int));
-  memset(imask, 0, imaskSize*sizeof(int));
+  ISEC2_NumVCP = 0;
 
-#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++ )
+  isec2[17] = 0;
+  isec2[18] = 0;
+
+  if ( VertCoorTab == TRUE )
     {
-      if ( IS_NOT_EQUAL(data[i], FSEC3_MissVal) )
+      int locnv;
+      if ( ISEC0_GRIB_Version  == 0 )
 	{
-	  data[fsec4size++] = data[i];
-	  imask[i] = 1;
+	  locnv = 32;
+	  ISEC2_NumVCP = (gdsLen - 32) >> 2;
+	}
+      else
+	{
+	  locnv = GDS_PVPL - 1;
+	  ISEC2_NumVCP = GDS_NV;
 	}
-    }
-
-#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]);
-    }
+      lGribLen = 4*ISEC2_NumVCP;	      
+      lgrib    = (GRIBPACK*) Malloc(lGribLen*sizeof(GRIBPACK));
 
-  Free(imask);
-#else
-  for ( i = 0; i < imaskSize/8; i++ ) bitmap[i] = 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));
+	}
 
-  for ( i = 0; i < bitmapSize; i++ )
-    {
-      if ( IS_NOT_EQUAL(data[i], FSEC3_MissVal) )
+      Free(lgrib);
+#else
+      for ( int i = 0; i < ISEC2_NumVCP; i++ )
 	{
-	  data[fsec4size++] = data[i];
-	  bitmap[i/8] |= (GRIBPACK)(1<<(7-(i&7)));
+	  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
+    }
+
+  return gdsLen;
+}
+
+#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)
+{
+  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));
+
+  /* get length of binary data block. */
+
+  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;
 
-  bmsLen = imaskSize/8 + 6;
-  bmsUnusedBits = imaskSize - bitmapSize;
+  /* 4 bit flag / 4 bit count of unused bits at end of block octet. */
 
-  Put3Byte(bmsLen);   /*  0- 2 Length of Block 3 Byte 0 */
-  Put1Byte(bmsUnusedBits);
-  Put2Byte(0);
+  bds_flag = BDS_Flag;
 
-  *gribLen += bmsLen;
+  /* 0------- grid point           */
+  /* 1------- spherical harmonics  */
 
-  *datasize = fsec4size;
-}
+  lspherc = bds_flag >> 7;
 
+  if ( lspherc ) isec4[2] = 128;
+  else           isec4[2] = 0;
 
-/* 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 */
+  /* -0------  simple packing */
+  /* -1------ complex packing */
 
-  size_t z = (size_t)*gribLen;
-  long i;
-  int numBits;
-  int ival;
-  long PackStart = 0, Flag = 0;
-  int binscale = 0;
-  int nbpv;
-  int bds_head = 11;
-  int bds_ext = 0;
-  /* ibits = BitsPerInt; */
-  int exponent, mantissa;
-  int lspherc = FALSE, lcomplex = FALSE;
-  int isubset = 0, itemp = 0, itrunc = 0;
-  T factor = 1, fmin, fmax;
-  double zref;
-  double range;
-  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 */
+  lcomplex = (bds_flag >> 6)&1;
 
-  if ( isec2 )
-    {
-      /* If section 2 is present, it says if data is spherical harmonic */
+  if ( lcomplex ) isec4[3] = 64;
+  else            isec4[3] =  0;
 
-      lspherc =  ( isec2[0] == 50 || isec2[0] == 60 ||
-                   isec2[0] == 70 || isec2[0] == 80 );
+  /* ---0---- No additional flags */
+  /* ---1---- No additional flags */
 
-      if ( lspherc )
-	isec4[2] = 128;
-      else
-	isec4[2] = 0;
-    }
+  lcompress = (bds_flag >> 4)&1; /* compress */
+
+  if ( lcompress )
+    { isec4[5] = 16; isec4[6] = BDS_Z; zoff = 12; }
   else
-    {
-      /* Section 4 says if it's spherical harmonic data.. */
+    { isec4[5] =  0; isec4[6] = 0;     zoff =  0; }
 
-      lspherc = ( isec4[2] == 128 );
-    }
+  /* ----++++ number of unused bits at end of section) */
 
-  /* Complex packing supported for spherical harmonics. */
+  bds_ubits = bds_flag & 0xF;
+  
+  /* scale factor (2 bytes) */;
 
-  lcomplex = ( lspherc && ( isec4[3] == 64 ) ) ||
-             ( lspherc && isec2 && ( isec2[5] == 2 ) );
+  jscale = BDS_BinScale;
 
-  /* Check input specification is consistent */
+  /* check for missing data indicators. */
 
-  if ( lcomplex && isec2 )
-    {
-      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;
-	}
-    }
+  iexp  = bds[ 6];
+  imant = GET_UINT3(bds[ 7], bds[ 8], bds[ 9]);
 
-  if ( decscale )
-    {
-      T scale = (T) pow(10.0, (double) decscale);
-      for ( i = 0; i < datasize; ++i ) data[i] *= scale;
-    }
+  imiss = (jscale == 0xFFFF && iexp == 0xFF && imant == 0xFFFFFF);
 
-  if ( lspherc )
+  /* convert reference value and scale factor. */
+
+  if ( ! (dfunc == 'J') && imiss == 0 )
     {
-      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;
-	}
+      fmin = (T)BDS_RefValue;
+      zscale = TEMPLATE(ldexp,T)((T)1.0, jscale);
     }
 
-  *datstart = bds_head + bds_ext;
+  /* get number of bits in each data value. */
 
-  nbpv = numBits = ISEC4_NumBits;
+  ISEC4_NumBits = BDS_NumBits;
 
-  if ( lspherc && lcomplex )
+  /* octet number of start of packed data */
+  /* calculated from start of block 4 - 1 */
+
+  locnd = zoff + bds_head;
+
+  /* if data is in spherical harmonic form, distinguish   */
+  /* between simple/complex packing (lcomplex = 0/1)      */
+
+  if ( lspherc )
     {
-      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 )
+	{
+	  /*    no unpacked binary data present */
 
-  fmin = fmax = data[PackStart];
+	  //jup = kup = mup = 0;
 
-  TEMPLATE(minmax_val,T)(data+PackStart, datasize-PackStart, &fmin, &fmax);
+	  /*    octet number of start of packed data */
+	  /*    calculated from start of block 4 - 1 */
 
-  zref = (double)fmin;
+	  ioff   = 1;
+	  locnd += 4*ioff;  /* RealCoef */
 
+	  /*    get real (0,0) coefficient in grib format and     */
+	  /*    convert to floating point.                        */
 
-  if ( CGRIBEX_Const && !lspherc )
-    {
-      if ( IS_EQUAL(fmin, fmax) ) nbpv = 0;
-    }
+	  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          */
 
-  long blockLength = (*datstart) + (nbpv*(datasize - PackStart) + 7)/8;
-  blockLength += blockLength & 1;
+	  jup = bds[zoff+15];
+	  kup = bds[zoff+16];
+	  mup = bds[zoff+17];
 
-  long unused_bits = blockLength*8 - (*datstart)*8 - nbpv*(datasize - PackStart);
+	  isec4[zoff+17] = jup;
+	  isec4[zoff+18] = kup;
+	  isec4[zoff+19] = mup;
 
-  Flag += unused_bits;
+	  /*    unpacked binary data */
 
+	  locnd += 4; /* 2 + power */
+	  locnd += 3; /* j, k, m   */
+	  ioff   = (jup+1)*(jup+2);
 
-  /*
-    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).           
-  */
-  range = fabs(fmax - fmin);
+	  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]);
 
-  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;
-      long 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);
-        }
+		    *fpdata++ = (T)decfp2(iexp,imant);
+		  }
+	      }
+	  
+	  locnd += 4*ioff;  /* RealCoef */
+	}
     }
   else
     {
-      double rangec = range - jpepsln, p05 = 0.5;
-      long jloop = 1;
-      while ( jloop < 127 && p05 >= rangec )
+      if ( lcomplex )
 	{
-          p05 *= 0.5;
-          jloop++;
+	  *iret = 1999;
+	  gprintf(__func__, " Second order packed grids unsupported!");
+	  gprintf(__func__, " Return code =  %d", *iret);
+	  return 0;
 	}
-      if ( jloop < 127 )
+    }
+
+  /* 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 )
 	{
-	  binscale = 1 - jloop - nbpv;
+	  *iret = 2001;
+	  gprintf(__func__, " Number of bits per data value = 0!");
+	  gprintf(__func__, " Return code =  %d", *iret);
+	  return 0;
 	}
-      else
+
+      if ( numGridVals == 0 )
 	{
-	  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);
+	  *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;
     }
 
-  uint64_t max_nbpv_pow2 = (uint64_t) ((1ULL << nbpv) - 1);
+  ISEC4_NumValues        = jlend + ioff;
+  ISEC4_NumNonMissValues = 0;
 
-  if ( binscale != 0 )
+  if ( lcompress )
     {
-      if ( binscale < 0 )
-        while ( (uint64_t)(ldexp(range, -binscale)+0.5) > max_nbpv_pow2 ) binscale++;
+      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
-        while ( (uint64_t)(ldexp(range, -binscale)+0.5) > max_nbpv_pow2 ) binscale--;
+        len = ((size_t) ((bds[17]<<16)+(bds[18]<<8)+bds[19]));
 
-      factor = intpow2(-binscale);
-    }
+      ISEC4_NumValues = (int)(len*8/(size_t)ISEC4_NumBits);
 
-  ref2ibm(&zref, BitsPerInt);
+      if ( lspherc )
+	{
+	  if ( lcomplex )
+	    ISEC4_NumValues += ioff;
+	  else
+	    ISEC4_NumValues++;
+	}
+    }
 
-  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 ( dfunc == 'J' ) return bdsLen;
 
-  if ( lspherc )
+  /* check length of output array. */
+  
+  if ( ISEC4_NumValues > fsec4len )
     {
-      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]));
-	}
+      *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;
     }
 
-  *datsize  = ((datasize-PackStart)*nbpv + 7)/8;
+  if ( imiss ) memset((char *)fpdata, 0, (size_t)jlend*sizeof(T));
+  else
+    {
+      igrib += locnd;
 
-#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
+      TEMPLATE(decode_array,T)(igrib, jlend, ISEC4_NumBits, fmin, zscale, fpdata);
+    }
 
-  if ( unused_bits >= 8 ) Put1Byte(0);  /*  Fillbyte                     */
+  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);
+    }
 
-  *gribLen = (long)z;
+  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);
+  if ( decscale )
+    {
+      T scale = (T) pow(10.0, (double)-decscale);
+      for ( int i = 0; i < ISEC4_NumValues; i++ ) fsec4[i] *= scale;
+    }
+
+  return bdsLen;
 }
 
 
-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)
+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)
 {
-  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;
+  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(isec3);
-  UNUSED(efunc);
+  UNUSED(kleng);
+
+  *iret = 0;
 
   grsdef();
 
-  CGrib = (unsigned char *) kgrib;
+  ISEC2_Reduced = FALSE;
 
-  bmsIncluded = ISEC1_Sec2Or3Flag & 64;
+  /*
+    ----------------------------------------------------------------
+    IS Indicator Section (Section 0)
+    ----------------------------------------------------------------
+  */
+  is = (unsigned char *) &kgrib[0];
 
-  /* set max header len */
-  size_t len = 16384;
+  isLen = decodeIS(is, isec0, iret);
 
-  /* add data len */
-  size_t numBytes = (size_t)((ISEC4_NumBits+7)>>3);
+  /*
+    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);
+    }
+  /*
+    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.
 
-  len += numBytes*(size_t)klenp;
+    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.
 
-  /* add bitmap len */
-  if ( bmsIncluded ) len += (size_t)((klenp+7)>>3);
+  */
+  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 defined (VECTORCODE)
-  lGrib = (GRIBPACK*) Malloc(len*sizeof(GRIBPACK));
-  if ( lGrib == NULL ) SysError("No Memory!");
-#else
-  lGrib = CGrib;
-#endif
+  /*
+    ----------------------------------------------------------------
+    PDS Product Definition Section (Section 1)
+    ----------------------------------------------------------------
+  */ 
+  pds = is + isLen;
 
-  isLen = 8;
-  encodeIS(lGrib, &gribLen);
-  lpds = &lGrib[isLen];
-  pdsLen = getPdsLen(isec1);
+  pdsLen = decodePDS(pds, isec0, isec1);
 
-  encodePDS(lpds, pdsLen,  isec1);
-  gribLen += pdsLen;
   /*
-  if ( ( isec4[3] == 64 ) && ( isec2[5] == 2 ) )
-    {
-      static int lwarn_cplx = TRUE;
-
-      if ( lwarn_cplx )
-	Message("Complex packing of spectral data unsupported, using simple packing!");
+    ----------------------------------------------------------------
+    GDS Grid Description Section (Section 2)
+    ----------------------------------------------------------------
+  */
+  gdsIncluded = ISEC1_Sec2Or3Flag & 128;
 
-      isec2[5] = 1;
-      isec4[3] = 0;
+  if ( gdsIncluded )
+    {
+      gds = is + isLen + pdsLen;
 
-      lwarn_cplx = FALSE;
+      gdsLen = TEMPLATE(decodeGDS,T)(gds, isec0, isec2, fsec2, &numGridVals);
     }
-  */
-  TEMPLATE(encodeGDS,T)(lGrib, &gribLen, isec2, fsec2);
+
   /*
     ----------------------------------------------------------------
     BMS Bit-Map Section Section (Section 3)
     ----------------------------------------------------------------
   */ 
+  bmsIncluded = ISEC1_Sec2Or3Flag & 64;
+
+  isec3[0] = 0;
   if ( bmsIncluded )
     {
-      TEMPLATE(encodeBMS,T)(lGrib, &gribLen, fsec3, isec4, fsec4, &fsec4size);
-    }
-  else
-    {
-      fsec4size = ISEC4_NumValues;
-    }
+      bms = is + isLen + pdsLen + gdsLen;
 
-  bdsstart = gribLen;
-  status = TEMPLATE(encodeBDS,T)(lGrib, &gribLen, ISEC1_DecScaleFactor, isec2,
-				 isec4, fsec4size, fsec4, &datstart, &datsize, ISEC1_Parameter);
-  if ( status )
-    {
-      *kret = status;
-      return;
+      bmsLen = BMS_Len;
+      imaskSize = (bmsLen - 6)<<3;
+      bitmapSize = imaskSize - BMS_UnusedBits;
+      /*
+      fprintf(stderr," bitmapSize = %d %d %d\n", bitmapSize, imaskSize, BMS_UnusedBits);
+      */
     }
 
-  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 defined (VECTORCODE)
-  if ( (size_t) gribLen > len )
-    Error("lGrib buffer too small! len = %d  gribLen = %d", len, gribLen);
+  /*
+    ----------------------------------------------------------------
+    BDS Binary Data Section (Section 4)
+    ----------------------------------------------------------------
+  */
+  bds = is + isLen + pdsLen + gdsLen + bmsLen;
 
-  (void) PACK_GRIB(lGrib, (unsigned char *)CGrib, gribLen, -1L);
+  bdsLen = ISEC0_GRIB_Len - (isLen + pdsLen + gdsLen + bmsLen);
 
-  Free(lGrib);
-#endif
+  bdsLen = TEMPLATE(decodeBDS,T)(ISEC1_DecScaleFactor, bds, isec2, isec4, 
+				 fsec4, fsec4len, dfunc, bdsLen, numGridVals, llarge, iret);
 
-  ISEC0_GRIB_Len     = (int)gribLen;
-  ISEC0_GRIB_Version = 1;
+  if ( *iret != 0 ) return;
 
-  *kword = (int)((gribLen + (long)sizeof(int) - 1) / (long)sizeof(int));
+  ISEC4_NumNonMissValues = ISEC4_NumValues;
 
-  *kret = status;
-}
+  if ( bitmapSize > 0 )
+    {
+      if ( dfunc != 'L' && dfunc != 'J' )
+	if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo )
+	  {
+	    lmissvalinfo = 0;
+	    FSEC3_MissVal = (T)GRIB_MISSVAL;
+	    Message("Missing value = NaN is unsupported, set to %g!", GRIB_MISSVAL);
+	  }
 
-#endif /* T */
+      /* ISEC4_NumNonMissValues = ISEC4_NumValues; */
+      ISEC4_NumValues        = bitmapSize;
 
-/*
- * Local Variables:
- * mode: c
- * End:
- */
+      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;
+	    }
+	  */
 
-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.4" " of ""Feb 19 2016"" ""11:03:41";
-const char *
-cgribexLibraryVersion(void)
-{
-  return (grb_libvers);
-}
+	  GRIBPACK *imask = (GRIBPACK*) Malloc((size_t)imaskSize*sizeof(GRIBPACK));
 
-#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)
-#pragma GCC diagnostic pop
+#if defined (VECTORCODE)
+	  (void) UNPACK_GRIB(BMS_Bitmap, imask, imaskSize/8, -1L);
+	  GRIBPACK *pbitmap = imask;
+#else
+	  GRIBPACK *pbitmap = BMS_Bitmap;
 #endif
 
-#ifdef HAVE_CONFIG_H
+#if defined (CRAY)
+#pragma _CRI ivdep
 #endif
-
-#include <inttypes.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#ifdef WORDS_BIGENDIAN
-#include <limits.h>
+#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++;
 
-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)
-{
-/*  Input arguments:
- *  const char*   b == byte sequence to checksum
- *  size_t        n == length of sequence
- */
+	  if ( ISEC4_NumNonMissValues != j )
+	    {
+	      if ( dfunc != 'J' && ISEC4_NumBits != 0 )
+		Warning("Bitmap (%d) and data (%d) section differ, using bitmap section!",
+			j, ISEC4_NumNonMissValues);
 
+	      ISEC4_NumNonMissValues = j;
+	    }
 
-  uint32_t s = 0;
+	  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;
+	    }
 
-  memcrc_r(&s, b, n);
+	  Free(imask);
+	}
+    }
 
-  /* 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];
-  }
+  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;
 
-  return ~s;
-}
+      //printf("nlat %d  nlon %d \n", nlat, nlon);
+      //printf("nvalues %d %d\n", nvalues, ISEC4_NumValues);
 
-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
- */
+      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;
+	    }
+	}
+    }
 
-  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];
-  }
+  if ( ISEC0_GRIB_Version == 1 ) isLen = 8;
+  esLen = 4;
 
-  *state = s;
-}
+  int gribLen = isLen + pdsLen + gdsLen + bmsLen + bdsLen + esLen;
 
-#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
+  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);
 
+  ISEC0_GRIB_Len = gribLen;
 
-/**
- *  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;
+  *kword = (int)(((size_t)gribLen + sizeof(int) - 1) / sizeof(int));
 
-  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
-}
+  /*
+    ----------------------------------------------------------------
+    Section 9 . Abort/return to calling routine.
+    ----------------------------------------------------------------
+  */
+ LABEL900:;
 
+  if ( ldebug )
+    {
+      gprintf(__func__, "Section 9.");
+      gprintf(__func__, "Output values set -");
 
-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;
+      gribPrintSec0(isec0);
+      gribPrintSec1(isec0, isec1);
+      /*
+	Print section 2 if present.
+      */
+      if ( lsect2 ) TEMPLATE(gribPrintSec2,T)(isec0, isec2, fsec2);
 
-  /* Extend with the length of the string. */
-  while (n != 0) {
-    c = n & 0377;
-    n >>= 8;
-    s = (s << 8) ^ crctab[(s >> 24) ^ c];
-  }
+      if ( ! l_iorj )
+	{
+	  /*
+	    Print section 3 if present.
+	  */
+	  if ( lsect3 ) TEMPLATE(gribPrintSec3,T)(isec0, isec3, fsec3);
 
-  return ~s;
+	  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 */
+
 /*
  * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
+ * mode: c
  * 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 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
+   */
+
+  z = 7;   
+  Put1Byte(1); /* grib version */
+  z = 8;
+
+  *gribLen = z;
+}
+
+/* GRIB block 5 - end block */
+static
+void encodeES(GRIBPACK *lGrib, long *gribLen, long bdsstart)
+{
+  long z = *gribLen;
+
+  lGrib[z++] = '7';
+  lGrib[z++] = '7';
+  lGrib[z++] = '7';
+  lGrib[z++] = '7';
+
+  if ( z > JP23SET )
+    {
+      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 )
+	{
+	  fprintf(stderr, "Abort: GRIB record too large (max = %d)!\n", JP23SET*120);
+	  exit(1);
+	}
 
-#if !defined(HAVE_CONFIG_H) && !defined(HAVE_MALLOC_H) && defined(SX)
-#  define  HAVE_MALLOC_H
-#endif
+      itemp = z / (-120);
+      itemp = JP23SET - itemp + 1;
 
-#if  defined(HAVE_MALLOC_H)
-#  include <malloc.h>
-#endif
+      lGrib[4] = (GRIBPACK)(itemp >> 16);
+      lGrib[5] = (GRIBPACK)(itemp >>  8);
+      lGrib[6] = (GRIBPACK)itemp;
 
+      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;
 
-enum             {MALLOC_FUNC=0, CALLOC_FUNC, REALLOC_FUNC, FREE_FUNC};
-static const char *memfunc[] = {"Malloc", "Calloc", "Realloc", "Free"};
+      while ( z%8 ) lGrib[z++] = 0;
+    }
 
-#undef   MEM_UNDEFID
-#define  MEM_UNDEFID  -1
+  *gribLen = z;
+}
 
-#define  MEM_MAXNAME  32   /* Min = 8, for  "unknown" ! */
+/* GRIB block 1 - product definition block. */
 
-static int dmemory_ExitOnError = 1;
+#define DWD_extension_253_len 38
+#define DWD_extension_254_len 26
+#define ECMWF_extension_1_len 24
+#define MPIM_extension_1_len  18
 
-typedef struct
+static
+long getLocalExtLen(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;
-
-static MemTable_t *memTable;
-static size_t  memTableSize  = 0;
-static long    memAccess     = 0;
+  long extlen = 0;
 
-static size_t  MemObjs       = 0;
-static size_t  MaxMemObjs    = 0;
-static size_t  MemUsed       = 0;
-static size_t  MaxMemUsed    = 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;
+        }
+    }
 
-static int     MEM_Debug     = 0;   /* If set to 1, debugging */
-static int     MEM_Info      = 0;   /* If set to 1, print mem table at exit */
+  return (extlen);
+}
 
 static
-const char *get_filename(const char *file)
+long getPdsLen(int *isec1)
 {
-  const char *fnptr = strrchr(file, '/');
-  if ( fnptr ) fnptr++;
-  else         fnptr = (char *) file;
+  long pdslen = 28;
 
-  return fnptr;
-}
+  pdslen += getLocalExtLen(isec1);
 
+  return (pdslen);
+}
 
-void memDebug(int debug)
+static
+void encodePDS_DWD_local_Extension_254(GRIBPACK *lGrib, long *zs, int *isec1)
 {
-  MEM_Debug = debug;
-}
+  int isvn;
+  long localextlen, i;
+  long z = *zs;
 
-/* If we're not using GNU C, elide __attribute__ */
-#if ! defined __GNUC__ && ! defined __attribute__
-#  define  __attribute__(x)  /*NOTHING*/
-#endif
+  localextlen = getLocalExtLen(isec1);
+  for ( i = 0; i < localextlen-2; i++ )
+    {
+      Put1Byte(isec1[24+i]);
+    }
 
-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));
+  isvn = isec1[49] << 15 | isec1[48]; /* DWD experiment identifier    */
+  Put2Byte(isvn);             /* DWD run type (0=main, 2=ass, 3=test) */
+
+  *zs = z;
+}
 
 static
-void memInternalProblem(const char *functionname, const char *fmt, ...)
+void encodePDS_DWD_local_Extension_253(GRIBPACK *lGrib, long *zs, int *isec1)
 {
-  va_list args;
-
-  va_start(args, fmt);
+  int isvn;
+  long localextlen, i;
+  long z = *zs;
 
-  printf("\n");
-   fprintf(stderr, "Internal problem (%s) : ", functionname);
-  vfprintf(stderr, fmt, args);
-   fprintf(stderr, "\n");
+  localextlen = DWD_extension_254_len;
+  for ( i = 0; i < localextlen-2; i++ )
+    {
+      Put1Byte(isec1[24+i]);
+    }
 
-  va_end(args);
+  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      */
 
-  exit(EXIT_FAILURE);
+  *zs = z;
 }
 
 static
-void memError(const char *functionname, const char *file, int line, size_t size)
+void encodePDS_ECMWF_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));
+  // int isvn;
+  long localextlen, i;
+  long z = *zs;
 
-  if ( errno ) perror("System error message ");
+  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                                     */
 
-  exit(EXIT_FAILURE);
+  /* 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]);
+
+  Put1Byte(isec1[41]);        /* Ensemble forecast number                   */
+  Put1Byte(isec1[42]);        /* Total number of forecasts in ensemble      */
+  Put1Byte(0);                /* (Spare)                                    */
+
+  *zs = z;
 }
 
 static
-void memListPrintEntry(int mtype, int item, size_t size, void *ptr,
-		       const char *functionname, const char *file, int line)
+void encodePDS_MPIM_local_Extension_1(GRIBPACK *lGrib, long *zs, int *isec1)
 {
-  fprintf(stderr, "[%-7s ", memfunc[mtype]);
+  // int isvn;
+  long localextlen, i;
+  long z = *zs;
 
-  fprintf(stderr, "memory item %3d ", item);
-  fprintf(stderr, "(%6zu byte) ", size);
-  fprintf(stderr, "at %p", ptr);
-  if ( file != NULL )
+  localextlen = getLocalExtLen(isec1);
+  for ( i = 0; i < localextlen-6; i++ )
     {
-      fprintf(stderr, " line %4d", line);
-      fprintf(stderr, " file %s", get_filename(file));
+      Put1Byte(isec1[24+i]);
     }
-  if ( functionname != NULL )
-    fprintf(stderr, " (%s)", functionname);
-  fprintf(stderr, "]\n");
+                              /* 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            */
+
+  *zs = z;
 }
 
+/* GRIB BLOCK 1 - PRODUCT DESCRIPTION SECTION */
 static
-void memListPrintTable(void)
+void encodePDS(GRIBPACK *lpds, long pdsLen, int *isec1)
 {
-  if ( MemObjs ) fprintf(stderr, "\nMemory table:\n");
+  GRIBPACK *lGrib = lpds;
+  long z = 0;
+  int ival, century, year;
 
-  for ( size_t memID = 0; memID < memTableSize; memID++ )
+  century = ISEC1_Century;
+  year    = ISEC1_Year;
+
+  if ( century < 0 )
     {
-      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);
+      century = -century;
+      year    = -year;
     }
 
-  if ( MemObjs )
+  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) )
     {
-      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_Level1);
+      Put1Byte(ISEC1_Level2);
+    }
+  else
+    {
+      Put2Byte(ISEC1_Level1);     /* 10 Level                    */    
     }
 
-  if ( MaxMemUsed )
+  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, "  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)));
+      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                  */
+
+  Put1Byte(ISEC1_AvgMiss);        /* 23 Missing from averages    */
+  Put1Byte(century);              /* 24 Century                  */
+  Put1Byte(ISEC1_SubCenterID);    /* 25 Subcenter                */
+  Put2Byte(ISEC1_DecScaleFactor); /* 26 Decimal scale factor     */
+
+  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
-	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);
-}
 
 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) ((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) ((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) ((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 = ((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;
-
-  /*
-    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);
+#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;
 
-      for ( size_t i = 0; i < memTableSize; i++ )
-	memTableInitEntry(i);
-    }
-  else
+  data += packStart;
+  datasize -= packStart;
+
+  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 = ((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 = ((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 = ((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
+#define __UNROLL_DEPTH_2 8
+#else
+#define __UNROLL_DEPTH_2 128
+#endif
+  size_t residual;
+  size_t ofs;
+  T dval[__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 % __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 += __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
     }
-  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 += __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 < __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;
+	    }
 	}
-      else
+      for (j = 0; j < residual; j++) 
 	{
-	  (void) strcpy(memTable[memID].filename, "unknown");
+	  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 += __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 < __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;
+	    }
 	}
-
-      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] = ((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 += __UNROLL_DEPTH_2 ) 
+ {
+	  for (j = 0; j < __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] = ((data[i+j] - zref) * factor + (T)0.5);
+	    }
+	  if ( IS_BIGENDIAN() )
+	    {
+	      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;
+		}
+	    }
+	  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;
+		}
 	    }
-
-	  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] = ((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);
+    }
+  else if ( numBits == 0 )
+    {
+    }
+  else
+    {
+      Error("Unimplemented packing factor %d!", numBits);
     }
-  memtotal = (size_t)meminfo.arena;
-#endif
 
-  return memtotal;
+  *gz = z;
+#undef __UNROLL_DEPTH_2
 }
 
+#endif /* T */
 
-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
+ * mode: c
  * 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*/
+#ifdef T
+#undef T
 #endif
+#define T float
+#ifdef T
 
-void SysError_(const char *caller, const char *fmt, ...)
-  __attribute__((noreturn));
 
-void SysError_(const char *caller, const char *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)
 {
-  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);
+  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 ( saved_errno )
+  cbits = 8;
+  c = 0;
+  for ( i = packStart; i < datasize; i++ )
     {
-      errno = saved_errno;
-      perror("System error message");
+      /* 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);
 
-  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);
-}
-
-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
-;
-
-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);
-}
-
-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);
+  *gz = z;
 }
 
-typedef void (*cdiWarningFunc)(const char * caller, const char * fmt,
-                               va_list ap);
 
-void Warning_(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);
 
-  if ( _Verbose )
+  if ( IS_BIGENDIAN() )
     {
-      cdiWarningFunc cdiWarning_p
-        = (cdiWarningFunc)namespaceSwitchGet(NSSWITCH_WARNING).func;
-      cdiWarning_p(caller, fmt, args);
+      for ( size_t i = 0; i < datasize; i++ )
+        {
+          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) ((data[i] - zref) * factor + (T)0.5);
+          sgrib[i] = gribSwapByteOrder_uint16(ui16);
+        }
     }
 
-  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);
-}
-
-
-void Message_(const char *caller, const char *fmt, ...)
-{
-  va_list args;
-
-  va_start(args, fmt);
-
-   fprintf(stdout, "%-18s : ", caller);
-  vfprintf(stdout, fmt, args);
-   fprintf(stdout, "\n");
-
-  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,
-};
-
-#endif
-#if defined (HAVE_CONFIG_H)
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <ctype.h>
-
-
-
-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;
-}
-
-
-static int EXT_Debug = 0;    /* If set to 1, debugging */
-
-
-void extDebug(int debug)
-{
-  EXT_Debug = debug;
-
-  if ( EXT_Debug )
-    Message("debug level %d", debug);
-}
-
-
 static
-void extLibInit()
+void TEMPLATE(encode_array_2byte,T)(size_t datasize, GRIBPACK *restrict lGrib,
+				    const T *restrict data, T zref, T factor, size_t *gz)
 {
-  const char *envName = "EXT_PRECISION";
+  size_t i, z = *gz;
+  uint16_t ui16;
+  T tmp;
 
-  char *envString = getenv(envName);
-  if ( envString )
+#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++ )
     {
-      int pos = 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;
-              }
-            }
-	}
+      tmp = ((data[i] - zref) * factor + (T)0.5);
+      ui16 = (uint16_t) tmp;
+      lGrib[z  ] = ui16 >>  8;
+      lGrib[z+1] = ui16;
+      z += 2;
     }
 
-  initExtLib = 1;
+  *gz = z;
 }
-
+*/
 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 *extNew(void)
+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 ( ! initExtLib ) extLibInit();
-
-  extrec_t *extp = (extrec_t *) Malloc(sizeof(extrec_t));
-
-  extInit(extp);
-
-  return (void*)extp;
-}
-
+#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;
 
-void extDelete(void *ext)
-{
-  extrec_t *extp = (extrec_t *) ext;
+  data += packStart;
+  datasize -= packStart;
 
-  if ( extp )
+  if      ( numBits ==  8 )
     {
-      if ( extp->buffer ) Free(extp->buffer);
-      Free(extp);
-    }
-}
-
+#ifdef _GET_IBM_COUNTER 
+      hpmStart(2, "pack 8 bit base");
+#endif
 
-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 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++;
+	}
 
-  if ( fileRead(fileID, buffer, 4) != 4 ) return found;
+#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);
+        }
 
-  size_t blocklen  = (size_t) get_UINT32(buffer);
-  size_t sblocklen = (size_t) get_SUINT32(buffer);
+#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
 
-  if ( EXT_Debug )
-    Message("blocklen = %d sblocklen = %d", blocklen, sblocklen);
+#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;
+	}
 
-  if ( blocklen == 16 )
-    {
-     *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);
+#ifdef _GET_IBM_COUNTER 
+      hpmStop(4);
+#endif
     }
-  else if ( blocklen == 32 )
+  else if ( numBits == 32 )
     {
-     *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);
+#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 ( sblocklen == 16 )
+  else if ( numBits > 0 && numBits <= 32 )
     {
-     *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);
+      TEMPLATE(encode_array_common,T)(numBits, 0, datasize, lGrib, data, zref, factor, &z);
     }
-  else if ( sblocklen == 32 )
+  else if ( numBits == 0 )
     {
-     *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);
     }
-
-  fileRewind(fileID);
-
-  if      ( data && dimxy*fact   == data ) found = 1;
-  else if ( data && dimxy*fact*2 == data ) found = 1;
-
-  if ( EXT_Debug )
+  else
     {
-      Message("swap = %d fact = %d", *swap, fact);
-      Message("dimxy = %lu data = %lu", dimxy, data);
+      Error("Unimplemented packing factor %d!", numBits);
     }
 
-  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 ( EXT_Debug ) Message("datasize = %lu", extp->datasize);
-
-  return 0;
+  *gz = z;
 }
 
-
-int extDefHeader(void *ext, const int *header)
+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)
 {
-  extrec_t *extp = (extrec_t *) ext;
-
-  for ( size_t i = 0; i < EXT_HEADER_LEN; i++ )
-    extp->header[i] = header[i];
-
-  extp->datasize = (size_t)header[3];
-  if ( extp->number == EXT_COMP ) extp->datasize *= 2;
-
-  if ( EXT_Debug ) Message("datasize = %lu", extp->datasize);
+  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];
 
-  return 0;
-}
+  data += packStart;
+  datasize -= packStart;
+  residual =  datasize % __UNROLL_DEPTH_2;
+  ofs = datasize - residual;
 
-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;
+  // reducing FP operations to single FMA is slowing down on pwr6 ...
 
-  switch ( rprec )
+  if      ( numBits ==  8 )
     {
-    case EXSE_SINGLE_PRECISION:
-      {
-	if ( sizeof(FLT32) == 4 )
-	  {
-	    if ( byteswap ) swap4byte(buffer, datasize);
-
-	    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);
+#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;
 
-	    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;
-      }
+#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);
 
-  return ierr;
-}
-
-
-int extInqDataSP(void *ext, float *data)
-{
-  return extInqData((extrec_t *)ext, EXSE_SINGLE_PRECISION, (void *) data);
-}
-
-
-int extInqDataDP(void *ext, double *data)
-{
-  return extInqData((extrec_t *)ext, EXSE_DOUBLE_PRECISION, (void *) data);
-}
-
-
-static int extDefData(void *ext, int prec, const void *data)
-{
-  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;
-
-  if ( buffersize != blocklen )
+      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
+    }
+  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 += __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++) 
+	{
+	  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 )
+    {
+#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() )
+	    {
+	      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;
+		}
+	    }
+	  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;
+		}
+	    }
+	}
+      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
+	      *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 )
     {
-      buffersize = blocklen;
-      buffer = extp->buffer;
-      buffer = Realloc(buffer, buffersize);
-      extp->buffer = buffer;
-      extp->buffersize = buffersize;
     }
   else
-    buffer = extp->buffer;
-
-  switch ( rprec )
     {
-    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];
-
-	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];
-
-	break;
-      }
-    default:
-      {
-	Error("unexpected data precision %d", rprec);
-        break;
-      }
+      Error("Unimplemented packing factor %d!", numBits);
     }
 
-  return 0;
+  *gz = z;
+#undef __UNROLL_DEPTH_2
 }
 
+#endif /* T */
 
-int extDefDataSP(void *ext, const float *data)
-{
-  return extDefData(ext, EXSE_SINGLE_PRECISION, (void *) data);
-}
-
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
 
-int extDefDataDP(void *ext, const double *data)
-{
-  return extDefData(ext, EXSE_DOUBLE_PRECISION, (void *) data);
-}
 
+#ifdef T
+#undef T
+#endif
+#define T double
+#ifdef T
 
-int extRead(int fileID, 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;
-  size_t i;
-  void *buffer;
-  int status;
+  long z = *gribLen;
+  int exponent, mantissa;
+  long i;
+  int ival;
+  int pvoffset = 0xFF;
+  int gdslen = 32;
+  unsigned lonIncr, latIncr;
 
-  if ( ! extp->checked )
-    {
-      status = extCheckFiletype(fileID, &extp->byteswap);
-      if ( status == 0 ) Error("Not a EXTRA file!");
-      extp->checked = 1;
-    }
+  if ( ISEC2_GridType == GRIB1_GTYPE_LCC ) gdslen += 10;
 
-  int byteswap = extp->byteswap;
+  if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )  gdslen += 10;
 
-  /* read header record */
-  size_t blocklen = binReadF77Block(fileID, byteswap);
+  if ( ISEC2_NumVCP || ISEC2_Reduced ) pvoffset = gdslen + 1;
 
-  if ( fileEOF(fileID) ) return -1;
+  if ( ISEC2_Reduced ) gdslen += 2 * ISEC2_NumLat;
 
-  if ( EXT_Debug )
-    Message("blocklen = %lu", blocklen);
+  gdslen += ISEC2_NumVCP * 4;
 
-  size_t hprec = blocklen / EXT_HEADER_LEN;
+  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 */
 
-  extp->prec = (int)hprec;
+  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               */
 
-  switch ( hprec )
+      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 )
     {
-    case EXSE_SINGLE_PRECISION:
-      {
-        INT32 tempheader[4];
-	binReadInt32(fileID, byteswap, EXT_HEADER_LEN, tempheader);
+      int numlon;
+      if ( ISEC2_Reduced )
+	numlon = 0xFFFF;
+      else
+	numlon = ISEC2_NumLon;
 
-	for ( i = 0; i < EXT_HEADER_LEN; i++ )
-          extp->header[i] = (int)tempheader[i];
+      Put2Byte(numlon);                /*  6- 7 Number of Longitudes     */
 
-	break;
-      }
-    case EXSE_DOUBLE_PRECISION:
-      {
-        INT64 tempheader[4];
-	binReadInt64(fileID, byteswap, EXT_HEADER_LEN, tempheader);
+      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  */
 
-	for ( i = 0; i < EXT_HEADER_LEN; i++ )
-          extp->header[i] = (int)tempheader[i];
+      Put1Byte(ISEC2_ScanFlag);        /* 27    Scanning mode            */
+      PutnZero(4);                     /* 28-31 reserved                 */
 
-	break;
-      }
-    default:
-      {
-	Error("Unexpected header precision %d", hprec);
-        break;
-      }
+      if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
+	{
+	  Put3Int(ISEC2_LatSP);
+	  Put3Int(ISEC2_LonSP);
+	  Put1Real((double)(FSEC2_RotAngle));
+	}
     }
-
-  size_t blocklen2 = binReadF77Block(fileID, byteswap);
-
-  if ( blocklen2 != blocklen )
+  else
     {
-      Warning("Header blocklen differ (blocklen1=%d; blocklen2=%d)!", blocklen, blocklen2);
-      if ( blocklen2 != 0 ) return -1;
+      Error("Unsupported grid type %d", ISEC2_GridType);
     }
 
-  extp->datasize = (size_t)extp->header[3];
+#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]));
+    }
 
-  if ( EXT_Debug ) Message("datasize = %lu", extp->datasize);
+  if ( ISEC2_Reduced )
+    for ( i = 0; i < ISEC2_NumLat; i++ ) Put2Byte(ISEC2_RowLon(i));
 
-  blocklen = binReadF77Block(fileID, byteswap);
+  *gribLen = z;
+}
 
-  size_t buffersize = (size_t)extp->buffersize;
+/* 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; */
 
-  if ( buffersize < blocklen )
+  if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo)
     {
-      buffersize = blocklen;
-      buffer = extp->buffer;
-      buffer = Realloc(buffer, buffersize);
-      extp->buffer = buffer;
-      extp->buffersize = buffersize;
+      lmissvalinfo = 0;
+      Message("Missing value = NaN is unsupported!");
     }
-  else
-    buffer = extp->buffer;
 
-  size_t dprec = blocklen / extp->datasize;
+  bitmapSize = ISEC4_NumValues;
+  imaskSize = ((bitmapSize+7)>>3)<<3;
+  bitmap = &lGrib[z+6];
+  fsec4size = 0;
 
-  if ( dprec == hprec )
+#if defined (VECTORCODE)
+  imask = (unsigned int*) Malloc(imaskSize*sizeof(unsigned int));
+  memset(imask, 0, imaskSize*sizeof(int));
+
+#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++ )
     {
-      extp->number = EXT_REAL;
+      if ( IS_NOT_EQUAL(data[i], FSEC3_MissVal) )
+	{
+	  data[fsec4size++] = data[i];
+	  imask[i] = 1;
+	}
     }
-  else if ( dprec == 2*hprec )
+
+#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++ )
     {
-      dprec /= 2;
-      extp->datasize *= 2;
-      extp->number = EXT_COMP;
+      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 ( dprec != EXSE_SINGLE_PRECISION && dprec != EXSE_DOUBLE_PRECISION )
+  Free(imask);
+#else
+  for ( i = 0; i < imaskSize/8; i++ ) bitmap[i] = 0;
+
+  for ( i = 0; i < bitmapSize; i++ )
     {
-      Warning("Unexpected data precision %d", dprec);
-      return -1;
+      if ( IS_NOT_EQUAL(data[i], FSEC3_MissVal) )
+	{
+	  data[fsec4size++] = data[i];
+	  bitmap[i/8] |= (GRIBPACK)(1<<(7-(i&7)));
+	}
     }
+#endif
 
-  fileRead(fileID, buffer, blocklen);
+  bmsLen = imaskSize/8 + 6;
+  bmsUnusedBits = imaskSize - bitmapSize;
 
-  blocklen2 = binReadF77Block(fileID, byteswap);
+  Put3Byte(bmsLen);   /*  0- 2 Length of Block 3 Byte 0 */
+  Put1Byte(bmsUnusedBits);
+  Put2Byte(0);
 
-  if ( blocklen2 != blocklen )
-    {
-      Warning("Data blocklen differ (blocklen1=%d; blocklen2=%d)!", blocklen, blocklen2);
-      if ( blocklen2 != 0 ) return -1;
-    }
+  *gribLen += bmsLen;
 
-  return 0;
+  *datasize = fsec4size;
 }
 
-
-int extWrite(int fileID, void *ext)
+/* 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;
-  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;
+  /* 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 */
 
-  /* write header record */
-  size_t blocklen = EXT_HEADER_LEN * (size_t)rprec;
+  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 */
 
-  binWriteF77Block(fileID, byteswap, blocklen);
+  if ( isec2 )
+    {
+      /* If section 2 is present, it says if data is spherical harmonic */
 
-  switch ( rprec )
+      lspherc =  ( isec2[0] == 50 || isec2[0] == 60 ||
+                   isec2[0] == 70 || isec2[0] == 80 );
+
+      if ( lspherc )
+	isec4[2] = 128;
+      else
+	isec4[2] = 0;
+    }
+  else
     {
-    case EXSE_SINGLE_PRECISION:
-      {
-	for ( i = 0; i < EXT_HEADER_LEN; i++ )
-          tempheader.i32[i] = (INT32) header[i];
+      /* Section 4 says if it's spherical harmonic data.. */
 
-	binWriteInt32(fileID, byteswap, EXT_HEADER_LEN, tempheader.i32);
+      lspherc = ( isec4[2] == 128 );
+    }
 
-	break;
-      }
-    case EXSE_DOUBLE_PRECISION:
-      {
-	for ( i = 0; i < EXT_HEADER_LEN; i++ )
-          tempheader.i64[i] = (INT64) header[i];
+  /* Complex packing supported for spherical harmonics. */
 
-	binWriteInt64(fileID, byteswap, EXT_HEADER_LEN, tempheader.i64);
+  int lcomplex = ( lspherc && ( isec4[3] == 64 ) ) ||
+                 ( lspherc && isec2 && ( isec2[5] == 2 ) );
 
-	break;
-      }
-    default:
-      {
-	Error("unexpected header precision %d", rprec);
-        break;
-      }
-    }
+  /* Check input specification is consistent */
 
-  binWriteF77Block(fileID, byteswap, blocklen);
+  if ( lcomplex && isec2 )
+    {
+      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;
+	}
+    }
 
-  size_t datasize = (size_t)header[3];
-  if ( number == EXT_COMP ) datasize *= 2;
-  blocklen = datasize * (size_t)rprec;
+  if ( decscale )
+    {
+      T scale = (T) pow(10.0, (double) decscale);
+      for ( i = 0; i < datasize; ++i ) data[i] *= scale;
+    }
 
-  binWriteF77Block(fileID, byteswap, blocklen);
+  if ( lspherc )
+    {
+      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;
+	}
+    }
 
-  extp->datasize = datasize;
+  *datstart = bds_head + bds_ext;
 
-  void *buffer = extp->buffer;
+  int nbpv = numBits = ISEC4_NumBits;
 
-  switch ( rprec )
+  if ( lspherc && lcomplex )
     {
-    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;
-      }
+      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);
     }
 
-  binWriteF77Block(fileID, byteswap, blocklen);
+  fmin = fmax = data[PackStart];
 
-  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
+  TEMPLATE(minmax_val,T)(data+PackStart, datasize-PackStart, &fmin, &fmax);
 
-#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()
+  double zref = (double)fmin;
 
 
+  if ( CGRIBEX_Const && !lspherc )
+    {
+      if ( IS_EQUAL(fmin, fmax) ) nbpv = 0;
+    }
 
-#if ! defined (O_BINARY)
-#define O_BINARY 0
-#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
+  long blockLength = (*datstart) + (nbpv*(datasize - PackStart) + 7)/8;
+  blockLength += blockLength & 1;
 
+  long unused_bits = blockLength*8 - (*datstart)*8 - nbpv*(datasize - PackStart);
 
-#if defined (HAVE_MMAP)
-#  include <sys/mman.h> /* mmap() is defined in this header */
-#endif
+  Flag += unused_bits;
 
 
-#if ! defined   (FALSE)
-#  define  FALSE  0
-#endif
+  /*
+    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 ! defined   (TRUE)
-#  define  TRUE   1
-#endif
+  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);
+	}
+    }
 
-/* #define  MAX_FILES  FOPEN_MAX */
-#define  MAX_FILES  4096
+  uint64_t max_nbpv_pow2 = (uint64_t) ((1ULL << nbpv) - 1);
 
-static int _file_max = MAX_FILES;
+  if ( binscale != 0 )
+    {
+      while ( (uint64_t)(ldexp(range, -binscale)+0.5) > max_nbpv_pow2 ) binscale++;
 
-static void file_initialize(void);
+      factor = (T)intpow2(-binscale);
+    }
 
-static int _file_init = FALSE;
+  ref2ibm(&zref, BitsPerInt);
 
-#if  defined  (HAVE_LIBPTHREAD)
-#include <pthread.h>
+  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             */
 
-static pthread_once_t  _file_init_thread = PTHREAD_ONCE_INIT;
-static pthread_mutex_t _file_mutex;
+  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]));
+	}
+    }
 
-#  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)
+  *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
-
-#  define FILE_LOCK()
-#  define FILE_UNLOCK()
-#  define FILE_INIT()        \
-   if ( _file_init == FALSE ) file_initialize()
-
+  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                     */
 
-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;
-
-
-enum F_I_L_E_Flags
-  {
-    FILE_READ  =  01,
-    FILE_WRITE =  02,
-    FILE_UNBUF =  04,
-    FILE_EOF   = 010,
-    FILE_ERROR = 020
-  };
-
-
-static int FileInfo  = FALSE;
+  *gribLen = (long)z;
 
+  return (0);
+}
 
-#if ! defined (MIN_BUF_SIZE)
-#  define  MIN_BUF_SIZE  131072L
-#endif
 
+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;
 
-static size_t FileBufferSizeMin = MIN_BUF_SIZE;
-static long   FileBufferSizeEnv = -1;
-static short  FileBufferTypeEnv =  0;
+  UNUSED(isec3);
+  UNUSED(efunc);
 
-static short  FileTypeRead  = FILE_TYPE_OPEN;
-static short  FileTypeWrite = FILE_TYPE_FOPEN;
-static int    FileFlagWrite = 0;
+  grsdef();
 
-static int    FILE_Debug = 0;   /* If set to 1, debugging */
+  CGrib = (unsigned char *) kgrib;
 
+  bmsIncluded = ISEC1_Sec2Or3Flag & 64;
 
-static void file_table_print(void);
+  /* set max header len */
+  size_t len = 16384;
 
-/*
- * 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__;
+  /* add data len */
+  size_t numBytes = (size_t)((ISEC4_NumBits+7)>>3);
 
-/*
-  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)
- */
+  len += numBytes*(size_t)klenp;
 
+  /* add bitmap len */
+  if ( bmsIncluded ) len += (size_t)((klenp+7)>>3);
 
-typedef struct _filePtrToIdx {
-  int idx;
-  bfile_t *ptr;
-  struct _filePtrToIdx *next;
-} filePtrToIdx;
+#if defined (VECTORCODE)
+  lGrib = (GRIBPACK*) Malloc(len*sizeof(GRIBPACK));
+  if ( lGrib == NULL ) SysError("No Memory!");
+#else
+  lGrib = CGrib;
+#endif
 
+  isLen = 8;
+  encodeIS(lGrib, &gribLen);
+  lpds = &lGrib[isLen];
+  pdsLen = getPdsLen(isec1);
 
-static filePtrToIdx *_fileList  = NULL;
-static filePtrToIdx *_fileAvail = NULL;
+  encodePDS(lpds, pdsLen,  isec1);
+  gribLen += pdsLen;
+  /*
+  if ( ( isec4[3] == 64 ) && ( isec2[5] == 2 ) )
+    {
+      static int lwarn_cplx = TRUE;
 
-static
-void file_list_new(void)
-{
-  assert(_fileList == NULL);
+      if ( lwarn_cplx )
+	Message("Complex packing of spectral data unsupported, using simple packing!");
 
-  _fileList = (filePtrToIdx *) Malloc((size_t)_file_max * sizeof (filePtrToIdx));
-}
+      isec2[5] = 1;
+      isec4[3] = 0;
 
-static
-void file_list_delete(void)
-{
-  if ( _fileList )
+      lwarn_cplx = FALSE;
+    }
+  */
+  TEMPLATE(encodeGDS,T)(lGrib, &gribLen, isec2, fsec2);
+  /*
+    ----------------------------------------------------------------
+    BMS Bit-Map Section Section (Section 3)
+    ----------------------------------------------------------------
+  */ 
+  if ( bmsIncluded )
     {
-      Free(_fileList);
-      _fileList = NULL;
+      TEMPLATE(encodeBMS,T)(lGrib, &gribLen, fsec3, isec4, fsec4, &fsec4size);
     }
-}
-
-static
-void file_init_pointer(void)
-{
-  int  i;
-
-  for ( i = 0; i < _file_max; i++ )
+  else
     {
-      _fileList[i].next = _fileList + i + 1;
-      _fileList[i].idx  = i;
-      _fileList[i].ptr  = 0;
+      fsec4size = ISEC4_NumValues;
     }
 
-  _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 )
+  bdsstart = gribLen;
+  status = TEMPLATE(encodeBDS,T)(lGrib, &gribLen, ISEC1_DecScaleFactor, isec2,
+				 isec4, fsec4size, fsec4, &datstart, &datsize, ISEC1_Parameter);
+  if ( status )
     {
-      FILE_LOCK();
-
-      fileptr = _fileList[idx].ptr;
-
-      FILE_UNLOCK();
+      *kret = status;
+      return;
     }
-  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;
+  encodeES(lGrib, &gribLen, bdsstart);
 
-  if ( ptr )
-    {
-      FILE_LOCK();
+  if ( (size_t) gribLen > (size_t)kleng*sizeof(int) )
+    Error("kgrib buffer too small! kleng = %d  gribLen = %d", kleng, gribLen);
 
-      if ( _fileAvail )
-	{
-	  newptr       = _fileAvail;
-	  _fileAvail   = _fileAvail->next;
-	  newptr->next = 0;
-	  idx	       = newptr->idx;
-	  newptr->ptr  = ptr;
+#if defined (VECTORCODE)
+  if ( (size_t) gribLen > len )
+    Error("lGrib buffer too small! len = %d  gribLen = %d", len, gribLen);
 
-	  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);
+  (void) PACK_GRIB(lGrib, (unsigned char *)CGrib, gribLen, -1L);
 
-      FILE_UNLOCK();
-    }
-  else
-    Error("Internal problem (pointer %p undefined)", ptr);
+  Free(lGrib);
+#endif
 
-  return (idx);
-}
+  ISEC0_GRIB_Len     = (int)gribLen;
+  ISEC0_GRIB_Version = 1;
 
-static
-void file_init_entry(bfile_t *fileptr)
-{
-  fileptr->self          = file_from_pointer(fileptr);
+  *kword = (int)((gribLen + (long)sizeof(int) - 1) / (long)sizeof(int));
 
-  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;
+  *kret = status;
 }
 
-static
-bfile_t *file_new_entry(void)
-{
-  bfile_t *fileptr;
-
-  fileptr = (bfile_t *) Malloc(sizeof(bfile_t));
+#endif /* T */
 
-  if ( fileptr ) file_init_entry(fileptr);
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
 
-  return (fileptr);
-}
+#ifdef T
+#undef T
+#endif
+#define T float
+#ifdef T
 
+/* GRIB BLOCK 2 - GRID DESCRIPTION SECTION */
 static
-void file_delete_entry(bfile_t *fileptr)
+void TEMPLATE(encodeGDS,T)(GRIBPACK *lGrib, long *gribLen, int *isec2, T *fsec2)
 {
-  int idx;
-
-  idx = fileptr->self;
-
-  FILE_LOCK();
+  long z = *gribLen;
+  int exponent, mantissa;
+  long i;
+  int ival;
+  int pvoffset = 0xFF;
+  int gdslen = 32;
+  unsigned lonIncr, latIncr;
 
-  Free(fileptr);
+  if ( ISEC2_GridType == GRIB1_GTYPE_LCC ) gdslen += 10;
 
-  _fileList[idx].next = _fileAvail;
-  _fileList[idx].ptr  = 0;
-  _fileAvail   	      = &_fileList[idx];
+  if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )  gdslen += 10;
 
-  FILE_UNLOCK();
+  if ( ISEC2_NumVCP || ISEC2_Reduced ) pvoffset = gdslen + 1;
 
-  if ( FILE_Debug )
-    Message("Removed idx %d from file list", idx);
-}
+  if ( ISEC2_Reduced ) gdslen += 2 * ISEC2_NumLat;
 
+  gdslen += ISEC2_NumVCP * 4;
 
-const char *fileLibraryVersion(void)
-{
-  return (file_libvers);
-}
+  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               */
 
-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
-}
+      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;
+      if ( ISEC2_Reduced )
+	numlon = 0xFFFF;
+      else
+	numlon = ISEC2_NumLon;
 
-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);
-}
+      Put2Byte(numlon);                /*  6- 7 Number of Longitudes     */
 
-void fileDebug(int debug)
-{
-  FILE_Debug = debug;
+      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  */
 
-  if ( FILE_Debug )
-    Message("Debug level %d", debug);
-}
+      Put1Byte(ISEC2_ScanFlag);        /* 27    Scanning mode            */
+      PutnZero(4);                     /* 28-31 reserved                 */
 
+      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);
+    }
 
-void *filePtr(int fileID)
-{
-  bfile_t *fileptr;
+#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]));
+    }
 
-  fileptr = file_to_pointer(fileID);
+  if ( ISEC2_Reduced )
+    for ( i = 0; i < ISEC2_NumLat; i++ ) Put2Byte(ISEC2_RowLon(i));
 
-  return (fileptr);
+  *gribLen = z;
 }
 
+/* GRIB BLOCK 3 - BIT MAP SECTION */
 static
-void file_pointer_info(const char *caller, int fileID)
+void TEMPLATE(encodeBMS,T)(GRIBPACK *lGrib, long *gribLen, T *fsec3, int *isec4, T *data, long *datasize)
 {
-  if ( FILE_Debug )
+  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; */
+
+  if ( DBL_IS_NAN(FSEC3_MissVal) && lmissvalinfo)
     {
-      fprintf(stdout, "%-18s : ", caller);
-      fprintf(stdout, "The fileID %d underlying pointer is not valid!", fileID);
-      fprintf(stdout, "\n");
+      lmissvalinfo = 0;
+      Message("Missing value = NaN is unsupported!");
     }
-}
-
 
-int fileSetBufferType(int fileID, int type)
-{
-  int ret = 0;
-  bfile_t *fileptr;
+  bitmapSize = ISEC4_NumValues;
+  imaskSize = ((bitmapSize+7)>>3)<<3;
+  bitmap = &lGrib[z+6];
+  fsec4size = 0;
 
-  fileptr = file_to_pointer(fileID);
+#if defined (VECTORCODE)
+  imask = (unsigned int*) Malloc(imaskSize*sizeof(unsigned int));
+  memset(imask, 0, imaskSize*sizeof(int));
 
-  if ( fileptr )
+#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++ )
     {
-      switch (type)
+      if ( IS_NOT_EQUAL(data[i], FSEC3_MissVal) )
 	{
-	case FILE_BUFTYPE_STD:
-	case FILE_BUFTYPE_MMAP:
-	  fileptr->bufferType = (short)type;
-	  break;
-	default:
-	  Error("File type %d not implemented!", type);
+	  data[fsec4size++] = data[i];
+	  imask[i] = 1;
 	}
     }
 
-#if ! defined (HAVE_MMAP)
-  if ( type == FILE_BUFTYPE_MMAP ) ret = 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 < 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]);
+    }
 
-  return (ret);
-}
+  Free(imask);
+#else
+  for ( i = 0; i < imaskSize/8; i++ ) bitmap[i] = 0;
 
-int fileFlush(int fileID)
-{
-  bfile_t *fileptr;
-  int retval = 0;
+  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
 
-  fileptr = file_to_pointer(fileID);
+  bmsLen = imaskSize/8 + 6;
+  bmsUnusedBits = imaskSize - bitmapSize;
 
-  if ( fileptr ) retval = fflush(fileptr->fp);
+  Put3Byte(bmsLen);   /*  0- 2 Length of Block 3 Byte 0 */
+  Put1Byte(bmsUnusedBits);
+  Put2Byte(0);
 
-  return (retval);
-}
+  *gribLen += bmsLen;
 
+  *datasize = fsec4size;
+}
 
-void fileClearerr(int fileID)
+/* 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)
 {
-  bfile_t *fileptr;
+  /* 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 */
 
-  fileptr = file_to_pointer(fileID);
+  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 ( fileptr )
+  if ( isec2 )
     {
-      if ( fileptr->mode != 'r' )
-	clearerr(fileptr->fp);
+      /* If section 2 is present, it says if data is spherical harmonic */
+
+      lspherc =  ( isec2[0] == 50 || isec2[0] == 60 ||
+                   isec2[0] == 70 || isec2[0] == 80 );
+
+      if ( lspherc )
+	isec4[2] = 128;
+      else
+	isec4[2] = 0;
     }
-}
+  else
+    {
+      /* Section 4 says if it's spherical harmonic data.. */
 
+      lspherc = ( isec4[2] == 128 );
+    }
 
-int filePtrEOF(void *vfileptr)
-{
-  bfile_t *fileptr = (bfile_t *) vfileptr;
-  int retval = 0;
+  /* Complex packing supported for spherical harmonics. */
 
-  if ( fileptr ) retval = (fileptr->flag & FILE_EOF) != 0;
+  int lcomplex = ( lspherc && ( isec4[3] == 64 ) ) ||
+                 ( lspherc && isec2 && ( isec2[5] == 2 ) );
 
-  return (retval);
-}
+  /* Check input specification is consistent */
 
+  if ( lcomplex && isec2 )
+    {
+      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 fileEOF(int fileID)
-{
-  bfile_t *fileptr;
-  int retval = 0;
+  if ( decscale )
+    {
+      T scale = (T) pow(10.0, (double) decscale);
+      for ( i = 0; i < datasize; ++i ) data[i] *= scale;
+    }
 
-  fileptr = file_to_pointer(fileID);
+  if ( lspherc )
+    {
+      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;
+	}
+    }
 
-  if ( fileptr ) retval = (fileptr->flag & FILE_EOF) != 0;
+  *datstart = bds_head + bds_ext;
 
-  return (retval);
-}
+  int nbpv = numBits = ISEC4_NumBits;
 
-void fileRewind(int fileID)
-{
-  fileSetPos(fileID, (off_t) 0, SEEK_SET);
-  fileClearerr(fileID);
-}
+  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);
+    }
 
+  fmin = fmax = data[PackStart];
 
-off_t fileGetPos(int fileID)
-{
-  off_t filepos = 0;
-  bfile_t *fileptr;
+  TEMPLATE(minmax_val,T)(data+PackStart, datasize-PackStart, &fmin, &fmax);
 
-  fileptr = file_to_pointer(fileID);
+  double zref = (double)fmin;
 
-  if ( fileptr )
+
+  if ( CGRIBEX_Const && !lspherc )
     {
-      if ( fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN )
-	filepos = fileptr->position;
-      else
-	filepos = ftell(fileptr->fp);
+      if ( IS_EQUAL(fmin, fmax) ) nbpv = 0;
     }
 
-  if ( FILE_Debug ) Message("Position %ld", filepos);
 
-  return (filepos);
-}
+  long blockLength = (*datstart) + (nbpv*(datasize - PackStart) + 7)/8;
+  blockLength += blockLength & 1;
 
+  long unused_bits = blockLength*8 - (*datstart)*8 - nbpv*(datasize - PackStart);
 
-int fileSetPos(int fileID, off_t offset, int whence)
-{
-  int status = 0;
-  bfile_t *fileptr;
+  Flag += unused_bits;
 
-  fileptr = file_to_pointer(fileID);
 
-  if ( FILE_Debug ) Message("Offset %8ld  Whence %3d", (long) offset, whence);
+  /*
+    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 ( fileptr == 0 )
+  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 )
     {
-      file_pointer_info(__func__, fileID);
-      return (1);
+      binscale = 0;
     }
-
-  switch (whence)
+  else if ( IS_NOT_EQUAL(fmin, 0.0) && (fabs(range/fmin) <= jpepsln) )
     {
-    case SEEK_SET:
-      if ( fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN )
+      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 )
 	{
-	  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();
-
-	      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;
-	    }
+          p05 *= 0.5;
+          jloop++;
 	}
-      else
+      if ( jloop < 127 )
 	{
-	  status = fseek(fileptr->fp, offset, whence);
+	  binscale = 1 - jloop - nbpv;
 	}
-      break;
-    case SEEK_CUR:
-      if ( fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN )
+      else
 	{
-	  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();
+	  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);
+	}
+    }
 
-	      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);
+  uint64_t max_nbpv_pow2 = (uint64_t) ((1ULL << nbpv) - 1);
 
-		  fileptr->bufferPos = fileptr->bufferEnd + 1;
-		}
-	      fileptr->bufferCnt -= (size_t)offset;
-	      fileptr->bufferPtr += offset;
-	    }
+  if ( binscale != 0 )
+    {
+      while ( (uint64_t)(ldexp(range, -binscale)+0.5) > max_nbpv_pow2 ) binscale++;
+
+      factor = (T)intpow2(-binscale);
+    }
+
+  ref2ibm(&zref, BitsPerInt);
+
+  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 ( 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
 	{
-	  status = fseek(fileptr->fp, offset, whence);
+	  Put1Real((double)(data[0]));
 	}
-      break;
-    default:
-      Error("Whence = %d not implemented", whence);
     }
 
-  if ( fileptr->position < fileptr->size )
-    if ( (fileptr->flag & FILE_EOF) != 0 )
-      fileptr->flag -= FILE_EOF;
+  *datsize  = ((datasize-PackStart)*nbpv + 7)/8;
 
-  return (status);
+#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);
 }
 
-static
-void file_table_print(void)
+
+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)
 {
-  int fileID;
-  int lprintHeader = 1;
-  bfile_t *fileptr;
+  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;
 
-  for ( fileID = 0; fileID < _file_max; fileID++ )
-    {
-      fileptr = file_to_pointer(fileID);
+  UNUSED(isec3);
+  UNUSED(efunc);
 
-      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;
-	    }
+  grsdef();
 
-	  fprintf(stderr, "| %3d | ", fileID);
+  CGrib = (unsigned char *) kgrib;
 
-	  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");
-	    }
+  bmsIncluded = ISEC1_Sec2Or3Flag & 64;
 
-          fprintf(stderr, " | %-51s|\n", fileptr->name);
-	}
-    }
+  /* set max header len */
+  size_t len = 16384;
+
+  /* add data len */
+  size_t numBytes = (size_t)((ISEC4_NumBits+7)>>3);
+
+  len += numBytes*(size_t)klenp;
+
+  /* add bitmap len */
+  if ( bmsIncluded ) len += (size_t)((klenp+7)>>3);
+
+#if defined (VECTORCODE)
+  lGrib = (GRIBPACK*) Malloc(len*sizeof(GRIBPACK));
+  if ( lGrib == NULL ) SysError("No Memory!");
+#else
+  lGrib = CGrib;
+#endif
+
+  isLen = 8;
+  encodeIS(lGrib, &gribLen);
+  lpds = &lGrib[isLen];
+  pdsLen = getPdsLen(isec1);
+
+  encodePDS(lpds, pdsLen,  isec1);
+  gribLen += pdsLen;
+  /*
+  if ( ( isec4[3] == 64 ) && ( isec2[5] == 2 ) )
+    {
+      static int lwarn_cplx = TRUE;
+
+      if ( lwarn_cplx )
+	Message("Complex packing of spectral data unsupported, using simple packing!");
+
+      isec2[5] = 1;
+      isec4[3] = 0;
 
-  if ( lprintHeader == 0 )
+      lwarn_cplx = FALSE;
+    }
+  */
+  TEMPLATE(encodeGDS,T)(lGrib, &gribLen, isec2, fsec2);
+  /*
+    ----------------------------------------------------------------
+    BMS Bit-Map Section Section (Section 3)
+    ----------------------------------------------------------------
+  */ 
+  if ( bmsIncluded )
     {
-      fprintf(stderr, "+-----+---------+");
-      fprintf(stderr, "----------------------------------------------------+\n");
+      TEMPLATE(encodeBMS,T)(lGrib, &gribLen, fsec3, isec4, fsec4, &fsec4size);
+    }
+  else
+    {
+      fsec4size = ISEC4_NumValues;
     }
-}
-
 
-char *fileInqName(int fileID)
-{
-  bfile_t *fileptr;
-  char *name = NULL;
+  bdsstart = gribLen;
+  status = TEMPLATE(encodeBDS,T)(lGrib, &gribLen, ISEC1_DecScaleFactor, isec2,
+				 isec4, fsec4size, fsec4, &datstart, &datsize, ISEC1_Parameter);
+  if ( status )
+    {
+      *kret = status;
+      return;
+    }
 
-  fileptr = file_to_pointer(fileID);
+  encodeES(lGrib, &gribLen, bdsstart);
 
-  if ( fileptr ) name = fileptr->name;
+  if ( (size_t) gribLen > (size_t)kleng*sizeof(int) )
+    Error("kgrib buffer too small! kleng = %d  gribLen = %d", kleng, gribLen);
 
-  return (name);
-}
+#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 fileInqMode(int fileID)
-{
-  bfile_t *fileptr;
-  int mode = 0;
+  Free(lGrib);
+#endif
 
-  fileptr = file_to_pointer(fileID);
+  ISEC0_GRIB_Len     = (int)gribLen;
+  ISEC0_GRIB_Version = 1;
 
-  if ( fileptr ) mode = fileptr->mode;
+  *kword = (int)((gribLen + (long)sizeof(int) - 1) / (long)sizeof(int));
 
-  return (mode);
+  *kret = status;
 }
 
-static
-long file_getenv(const char *envName)
-{
-  char *envString;
-  long envValue = -1;
-  long fact = 1;
-
-  envString = getenv(envName);
-
-  if ( envString )
-    {
-      int loop;
-
-      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 ( fact ) envValue = fact*atol(envString);
+#endif /* T */
 
-      if ( FILE_Debug ) Message("Set %s to %ld", envName, envValue);
-    }
+/*
+ * Local Variables:
+ * mode: c
+ * End:
+ */
 
-  return (envValue);
+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
-void file_initialize(void)
+static const char grb_libvers[] = "1.7.5" " of ""Jun  3 2016"" ""14:44:00";
+const char *
+cgribexLibraryVersion(void)
 {
-  long value;
-  char *envString;
+  return (grb_libvers);
+}
 
-#if  defined  (HAVE_LIBPTHREAD)
-  /* initialize global API mutex lock */
-  pthread_mutex_init(&_file_mutex, NULL);
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)
+#pragma GCC diagnostic pop
 #endif
 
-  value = file_getenv("FILE_DEBUG");
-  if ( value >= 0 ) FILE_Debug = (int) value;
-
-  value = file_getenv("FILE_MAX");
-  if ( value >= 0 ) _file_max = (int) value;
-
-  if ( FILE_Debug )
-    Message("FILE_MAX = %d", _file_max);
-
-  FileInfo  = (int) file_getenv("FILE_INFO");
+#ifdef HAVE_CONFIG_H
+#endif
 
-  value  = file_getenv("FILE_BUFSIZE");
-  if ( value >= 0 ) FileBufferSizeEnv = value;
-  else
-    {
-      value  = file_getenv("GRIB_API_IO_BUFFER_SIZE");
-      if ( value >= 0 ) FileBufferSizeEnv = value;
-    }
+#include <inttypes.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#ifdef WORDS_BIGENDIAN
+#include <limits.h>
+#endif
 
-  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);
-	}
-    }
 
-  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);
-	}
-    }
+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
+};
 
-#if defined (O_NONBLOCK)
-  FileFlagWrite = O_NONBLOCK;
-#endif
-  envString = getenv("FILE_FLAG_WRITE");
-  if ( envString )
-    {
-#if defined (O_NONBLOCK)
-      if ( strcmp(envString, "NONBLOCK") == 0 ) FileFlagWrite = O_NONBLOCK;
-#endif
-    }
 
-  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);
-	}
-    }
+uint32_t
+memcrc(const unsigned char *b, size_t n)
+{
+/*  Input arguments:
+ *  const char*   b == byte sequence to checksum
+ *  size_t        n == length of sequence
+ */
 
-  file_list_new();
-  atexit(file_list_delete);
 
-  FILE_LOCK();
+  uint32_t s = 0;
 
-  file_init_pointer();
+  memcrc_r(&s, b, n);
 
-  FILE_UNLOCK();
+  /* 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];
+  }
 
-  if ( FILE_Debug ) atexit(file_table_print);
 
-  _file_init = TRUE;
+  return ~s;
 }
 
-static
-void file_set_buffer(bfile_t *fileptr)
+void
+memcrc_r(uint32_t *state, const unsigned char *block, size_t block_len)
 {
-  size_t buffersize = 0;
+/*  Input arguments:
+ *  const char*   b == byte sequence to checksum
+ *  size_t        n == length of sequence
+ */
 
-  if ( fileptr->mode == 'r' )
-    {
-      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;
-	}
+  register uint32_t c, s = *state;
+  register size_t n = block_len;
+  register const unsigned char *b = block;
 
-      if ( (size_t) fileptr->size < buffersize )
-	buffersize = (size_t) fileptr->size;
+  for (; n > 0; --n) {
+    c = (uint32_t)(*b++);
+    s = (s << 8) ^ crctab[(s >> 24) ^ c];
+  }
 
-      if ( fileptr->bufferType == FILE_BUFTYPE_MMAP )
-	{
-	  size_t blocksize = (size_t) pagesize();
-	  size_t minblocksize = 4 * blocksize;
-	  buffersize = buffersize - buffersize % minblocksize;
+  *state = s;
+}
 
-	  if ( buffersize < (size_t) fileptr->size && buffersize < minblocksize )
-	    buffersize = minblocksize;
-	}
+#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
 
-      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;
-	}
-    }
+/**
+ *  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 ( 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!");
-        }
-    }
+  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
+}
 
-  if ( fileptr->type == FILE_TYPE_FOPEN )
-    if ( setvbuf(fileptr->fp, fileptr->buffer, fileptr->buffer ? _IOFBF : _IONBF, buffersize) )
-      SysError("setvbuf failed!");
 
-  fileptr->bufferSize = buffersize;
+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;
+
+  /* Extend with the length of the string. */
+  while (n != 0) {
+    c = n & 0377;
+    n >>= 8;
+    s = (s << 8) ^ crctab[(s >> 24) ^ c];
+  }
+
+  return ~s;
 }
 
-static
-int file_fill_buffer(bfile_t *fileptr)
-{
-  ssize_t nread;
-  int fd;
-  long offset = 0;
-  off_t retseek;
+/*
+ * 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 ( FILE_Debug )
-    Message("file ptr = %p  Cnt = %ld", fileptr, fileptr->bufferCnt);
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <errno.h>
 
-  if ( (fileptr->flag & FILE_EOF) != 0 ) return (EOF);
+#if !defined(HAVE_CONFIG_H) && !defined(HAVE_MALLOC_H) && defined(SX)
+#  define  HAVE_MALLOC_H
+#endif
 
-  if ( fileptr->buffer == NULL ) file_set_buffer(fileptr);
+#if  defined(HAVE_MALLOC_H)
+#  include <malloc.h>
+#endif
 
-  if ( fileptr->bufferSize == 0 ) return (EOF);
 
-  fd = fileptr->fd;
+enum             {MALLOC_FUNC=0, CALLOC_FUNC, REALLOC_FUNC, FREE_FUNC};
+static const char *memfunc[] = {"Malloc", "Calloc", "Realloc", "Free"};
 
-#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;
+#undef   MEM_UNDEFID
+#define  MEM_UNDEFID  -1
 
-	  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;
-	    }
+#define  MEM_MAXNAME  32   /* Min = 8, for  "unknown" ! */
 
-	  fileptr->mappedSize = (size_t)nread;
+static int dmemory_ExitOnError = 1;
 
-	  fileptr->buffer = (char*) mmap(NULL, (size_t) nread, PROT_READ, MAP_PRIVATE, fd, fileptr->bufferPos);
+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;
 
-	  if ( fileptr->buffer == MAP_FAILED ) SysError("mmap error for read %s", fileptr->name);
+static MemTable_t *memTable;
+static size_t  memTableSize  = 0;
+static long    memAccess     = 0;
 
-	  offset = fileptr->position - fileptr->bufferPos;
-	}
-    }
-  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);
+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
+const char *get_filename(const char *file)
+{
+  const char *fnptr = strrchr(file, '/');
+  if ( fnptr ) fnptr++;
+  else         fnptr = (char *) file;
 
-      nread = read(fd, fileptr->buffer, fileptr->bufferSize);
-    }
+  return fnptr;
+}
 
-  if ( nread <= 0 )
-    {
-      if ( nread == 0 )
-	fileptr->flag |= FILE_EOF;
-      else
-	fileptr->flag |= FILE_ERROR;
 
-      fileptr->bufferCnt = 0;
-      return (EOF);
-    }
+void memDebug(int debug)
+{
+  MEM_Debug = debug;
+}
 
-  fileptr->bufferPtr = fileptr->buffer;
-  fileptr->bufferCnt = (size_t)nread;
+/* If we're not using GNU C, elide __attribute__ */
+#if ! defined __GNUC__ && ! defined __attribute__
+#  define  __attribute__(x)  /*NOTHING*/
+#endif
 
-  fileptr->bufferStart = fileptr->bufferPos;
-  fileptr->bufferPos  += nread;
-  fileptr->bufferEnd   = fileptr->bufferPos - 1;
+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 ( 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
+void memInternalProblem(const char *functionname, const char *fmt, ...)
+{
+  va_list args;
 
-  if ( offset > 0 )
-    {
-      if ( offset > nread )
-	Error("Internal problem with buffer handling. nread = %d offset = %d", nread, offset);
+  va_start(args, fmt);
 
-      fileptr->bufferPtr += offset;
-      fileptr->bufferCnt -= (size_t)offset;
-    }
+  printf("\n");
+   fprintf(stderr, "Internal problem (%s) : ", functionname);
+  vfprintf(stderr, fmt, args);
+   fprintf(stderr, "\n");
 
-  fileptr->bufferNumFill++;
+  va_end(args);
 
-  return ((unsigned char) *fileptr->bufferPtr);
+  exit(EXIT_FAILURE);
 }
 
 static
-void file_copy_from_buffer(bfile_t *fileptr, void *ptr, size_t size)
+void memError(const char *functionname, const char *file, int line, size_t size)
 {
-  if ( FILE_Debug )
-    Message("size = %ld  Cnt = %ld", size, fileptr->bufferCnt);
+  fputs("\n", stdout);
+  fprintf(stderr, "Error (%s) : Allocation of %zu bytes failed. [ line %d file %s ]\n",
+	  functionname, size, line, get_filename(file));
 
-  if ( fileptr->bufferCnt < size )
-    Error("Buffer too small. bufferCnt = %d", fileptr->bufferCnt);
+  if ( errno ) perror("System error message ");
 
-  if ( size == 1 )
-    {
-      ((char *)ptr)[0] = fileptr->bufferPtr[0];
+  exit(EXIT_FAILURE);
+}
 
-      fileptr->bufferPtr++;
-      fileptr->bufferCnt--;
-    }
-  else
-    {
-      memcpy(ptr, fileptr->bufferPtr, size);
+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]);
 
-      fileptr->bufferPtr += size;
-      fileptr->bufferCnt -= size;
+  fprintf(stderr, "memory item %3d ", item);
+  fprintf(stderr, "(%6zu byte) ", size);
+  fprintf(stderr, "at %p", ptr);
+  if ( file != NULL )
+    {
+      fprintf(stderr, " line %4d", line);
+      fprintf(stderr, " file %s", get_filename(file));
     }
+  if ( functionname != NULL )
+    fprintf(stderr, " (%s)", functionname);
+  fprintf(stderr, "]\n");
 }
 
 static
-size_t file_read_from_buffer(bfile_t *fileptr, void *ptr, size_t size)
+void memListPrintTable(void)
 {
-  size_t nread, rsize;
-  size_t offset = 0;
-
-  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);
+  if ( MemObjs ) fprintf(stderr, "\nMemory table:\n");
 
-  rsize = size;
+  for ( size_t memID = 0; memID < memTableSize; memID++ )
+    {
+      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);
+    }
 
-  while ( fileptr->bufferCnt < rsize )
+  if ( MemObjs )
     {
-      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;
+      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
-	rsize = 0;
-
-      if ( file_fill_buffer(fileptr) == EOF ) break;
+	fprintf(stderr, " %5d Byte\n", (int)  MemUsed);
     }
 
-  nread = size - offset;
+  if ( MaxMemUsed )
+    {
+      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);
+    }
+}
 
-  if ( fileptr->bufferCnt < nread ) nread = fileptr->bufferCnt;
+static
+void memGetDebugLevel(void)
+{
+  const char *envstr;
 
-  if ( nread > (unsigned) 0 )
-    file_copy_from_buffer(fileptr, (char *)ptr+offset, nread);
+  envstr = getenv("MEMORY_INFO");
+  if ( envstr && isdigit((int) envstr[0]) ) MEM_Info = atoi(envstr);
 
-  return (nread+offset);
-}
+  envstr = getenv("MEMORY_DEBUG");
+  if ( envstr && isdigit((int) envstr[0]) ) MEM_Debug = atoi(envstr);
 
+  if ( MEM_Debug && !MEM_Info ) MEM_Info = 1;
 
-void fileSetBufferSize(int fileID, long buffersize)
-{
-  bfile_t *fileptr = file_to_pointer(fileID);
-  xassert(buffersize >= 0);
-  if ( fileptr ) fileptr->bufferSize = (size_t)buffersize;
+  if ( MEM_Info ) atexit(memListPrintTable);
 }
 
-/*
- *   Open a file. Returns file ID, or -1 on error
- */
-int fileOpen(const char *filename, const char *mode)
+static
+void memInit(void)
 {
-  int (*myFileOpen)(const char *filename, const char *mode)
-    = (int (*)(const char *, const char *))
-    namespaceSwitchGet(NSSWITCH_FILE_OPEN).func;
-  return myFileOpen(filename, mode);
+  static int initDebugLevel = 0;
+
+  if ( ! initDebugLevel )
+    {
+      memGetDebugLevel();
+      initDebugLevel = 1;
+    }
 }
 
-int fileOpen_serial(const char *filename, const char *mode)
+static
+int memListDeleteEntry(void *ptr, size_t *size)
 {
-  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();
+  int item = MEM_UNDEFID;
+  size_t memID;
 
-  fmode = tolower((int) mode[0]);
+  for ( memID = 0; memID < memTableSize; memID++ )
+    {
+      if ( memTable[memID].item == MEM_UNDEFID ) continue;
+      if ( memTable[memID].ptr == ptr ) break;
+    }
 
-  switch ( fmode )
+  if ( memID != memTableSize )
     {
-    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);
+      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 ( FILE_Debug )
-    if ( fp == NULL && fd == -1 )
-      Message("Open failed on %s mode %c errno %d", filename, fmode, errno);
+  return item;
+}
 
-  if ( fp )
+static
+void memTableInitEntry(size_t memID)
+{
+  if ( memID >= memTableSize )
+    memInternalProblem(__func__, "memID %d undefined!", memID);
+
+  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;
+}
+
+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;
+
+  /*
+    Look for a free slot in memTable.
+    (Create the table the first time through).
+  */
+  if ( memTableSize == 0 )
     {
-      if ( stat(filename, &filestat) != 0 ) return (fileID);
+      memTableSize = 8;
+      memSize  = memTableSize * sizeof(MemTable_t);
+      memTable = (MemTable_t *) malloc(memSize);
+      if( memTable == NULL ) memError(__func__, __FILE__, __LINE__, memSize);
 
-      fileptr = file_new_entry();
-      if ( fileptr )
-	{
-	  fileID = fileptr->self;
-	  fileptr->fp = fp;
-	}
+      for ( size_t i = 0; i < memTableSize; i++ )
+	memTableInitEntry(i);
     }
-  else if ( fd >= 0 )
+  else
     {
-      if ( fstat(fd, &filestat) != 0 ) return (fileID);
-
-      fileptr = file_new_entry();
-      if ( fileptr )
+      while ( memID < memTableSize )
 	{
-	  fileID = fileptr->self;
-	  fileptr->fd = fd;
+	  if ( memTable[memID].item == MEM_UNDEFID ) break;
+	  memID++;
 	}
     }
-
-  if ( fileID >= 0 )
+  /*
+    If the table overflows, double its size.
+  */
+  if ( memID == memTableSize )
     {
-      fileptr->mode = fmode;
-      fileptr->name = strdupx(filename);
-
-#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;
-
-      if ( fmode == 'r' ) fileptr->size = filestat.st_size;
-
-      if ( fileptr->type == FILE_TYPE_FOPEN ) file_set_buffer(fileptr);
+      memTableSize = 2*memTableSize;
+      memSize  = memTableSize*sizeof(MemTable_t);
+      memTable = (MemTable_t*) realloc(memTable, memSize);
+      if ( memTable == NULL ) memError(__func__, __FILE__, __LINE__, memSize);
 
-      if ( FILE_Debug )
-	Message("File %s opened with ID %d", filename, fileID);
+      for ( size_t i = memID; i < memTableSize; i++ )
+	memTableInitEntry(i);
     }
 
-  return (fileID);
-}
-
-/*
- *   Close a file.
- */
-int fileClose(int fileID)
-{
-  int (*myFileClose)(int fileID)
-    = (int (*)(int))namespaceSwitchGet(NSSWITCH_FILE_CLOSE).func;
-  return myFileClose(fileID);
-}
+  memTable[memID].item  = item;
+  memTable[memID].ptr   = ptr;
+  memTable[memID].size  = size;
+  memTable[memID].nobj  = nobj;
+  memTable[memID].mtype = mtype;
+  memTable[memID].line  = line;
 
-int fileClose_serial(int fileID)
-{
-  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;
+  if ( file )
+    {
+      const char *filename = get_filename(file);
+      size_t len = strlen(filename);
+      if ( len > MEM_MAXNAME-1 ) len = MEM_MAXNAME-1;
 
-  if ( fileptr == NULL )
+      (void) memcpy(memTable[memID].filename, filename, len);
+      memTable[memID].filename[len] = '\0';
+    }
+  else
     {
-      file_pointer_info(__func__, fileID);
-      return (1);
+      (void) strcpy(memTable[memID].filename, "unknown");
     }
 
-  name = fileptr->name;
-
-  if ( FILE_Debug )
-    Message("fileID = %d  filename = %s", fileID, name);
-
-  if ( FileInfo > 0 )
+  if ( functionname )
     {
-      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]);
+      size_t len = strlen(functionname);
+      if ( len > MEM_MAXNAME-1 ) len = MEM_MAXNAME-1;
 
-      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);
+      (void) memcpy(memTable[memID].functionname, functionname, len);
+      memTable[memID].functionname[len] = '\0';
+    }
+  else
+    {
+      (void) strcpy(memTable[memID].functionname, "unknown");
+    }
 
-      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);
-	}
+  MaxMemObjs++;
+  MemObjs++;
+  MemUsed += size*nobj;
+  if ( MemUsed > MaxMemUsed ) MaxMemUsed = MemUsed;
 
-      if ( fileptr->time_in_sec > 0 )
-        {
-          rout = (double)fileptr->byteTrans / (1024.*1024.*fileptr->time_in_sec);
-        }
+  return item++;
+}
 
-      fprintf(stderr, " wall time [s]    : %.2f\n", fileptr->time_in_sec);
-      fprintf(stderr, " data rate [MB/s] : %.1f\n", rout);
+static
+int memListChangeEntry(void *ptrold, void *ptr, size_t size,
+		       const char *functionname, const char *file, int line)
+{
+  int item = MEM_UNDEFID;
+  size_t memID = 0;
 
-      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");
+  while( memID < memTableSize )
+    {
+      if ( memTable[memID].item != MEM_UNDEFID )
+	if ( memTable[memID].ptr == ptrold ) break;
+      memID++;
     }
 
-  if ( fileptr->type == FILE_TYPE_FOPEN )
+  if ( memID == memTableSize )
     {
-      ret = fclose(fileptr->fp);
-      if ( ret == EOF )
-	SysError("EOF returned for close of %s!", name);
+      if ( ptrold != NULL )
+	memInternalProblem(__func__, "Item at %p not found.", ptrold);
     }
   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);
-    }
-
-  if ( fileptr->name )    Free((void*) fileptr->name);
-  if ( fileptr->buffer )  Free((void*) fileptr->buffer);
-
-  file_delete_entry(fileptr);
+      item = memTable[memID].item;
 
-  return (0);
-}
+      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;
 
-int filePtrGetc(void *vfileptr)
-{
-  int ivalue = EOF;
-  int fillret = 0;
-  bfile_t *fileptr = (bfile_t *) vfileptr;
+      if ( file )
+	{
+          const char *filename = get_filename(file);
+	  size_t len = strlen(filename);
+	  if ( len > MEM_MAXNAME-1 ) len = MEM_MAXNAME-1;
 
-  if ( fileptr )
-    {
-      if ( fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN )
+	  (void) memcpy(memTable[memID].filename, filename, len);
+	  memTable[memID].filename[len] = '\0';
+	}
+      else
 	{
-	  if ( fileptr->bufferCnt == 0 ) fillret = file_fill_buffer(fileptr);
+	  (void) strcpy(memTable[memID].filename, "unknown");
+	}
 
-	  if ( fillret >= 0 )
-	    {
-	      ivalue = (unsigned char) *fileptr->bufferPtr++;
-	      fileptr->bufferCnt--;
-	      fileptr->position++;
+      if ( functionname )
+	{
+	  size_t len = strlen(functionname);
+	  if ( len > MEM_MAXNAME-1 ) len = MEM_MAXNAME-1;
 
-	      fileptr->byteTrans++;
-	      fileptr->access++;
-	    }
+	  (void) memcpy(memTable[memID].functionname, functionname, len);
+	  memTable[memID].functionname[len] = '\0';
 	}
       else
 	{
-	  ivalue = fgetc(fileptr->fp);
-	  if ( ivalue >= 0 )
-	    {
-	      fileptr->byteTrans++;
-	      fileptr->access++;
-	    }
-	  else
-	    fileptr->flag |= FILE_EOF;
+	  (void) strcpy(memTable[memID].functionname, "unknown");
 	}
+
+      MemUsed -= sizeold;
+      MemUsed += size;
+      if ( MemUsed > MaxMemUsed ) MaxMemUsed = MemUsed;
     }
 
-  return (ivalue);
+  return item;
 }
 
 
-int fileGetc(int fileID)
+void *memCalloc(size_t nobjs, size_t size, const char *file, const char *functionname, int line)
 {
-  int ivalue;
-  bfile_t *fileptr;
+  void *ptr = NULL;
 
-  fileptr = file_to_pointer(fileID);
+  memInit();
 
-  ivalue = filePtrGetc((void *)fileptr);
+  if ( nobjs*size > 0 )
+    {
+      ptr = calloc(nobjs, size);
 
-  return (ivalue);
+      if ( MEM_Info )
+	{
+	  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);
+	}
+
+      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;
 }
 
 
-size_t filePtrRead(void *vfileptr, void *restrict ptr, size_t size)
+void *memMalloc(size_t size, const char *file, const char *functionname, int line)
 {
-  size_t nread = 0;
-  bfile_t *fileptr = (bfile_t *) vfileptr;
+  void *ptr = NULL;
 
-  if ( fileptr )
+  memInit();
+
+  if ( size > 0 )
     {
-      if ( fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN )
-	nread = file_read_from_buffer(fileptr, ptr, size);
-      else
+      ptr = malloc(size);
+
+      if ( MEM_Info )
 	{
-	  nread = fread(ptr, 1, size, fileptr->fp);
-	  if ( nread != size )
-	    {
-	      if ( nread == 0 )
-		fileptr->flag |= FILE_EOF;
-	      else
-		fileptr->flag |= FILE_ERROR;
-	    }
+	  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);
 	}
 
-      fileptr->position  += (off_t)nread;
-      fileptr->byteTrans += (off_t)nread;
-      fileptr->access++;
+      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);
 
-  if ( FILE_Debug ) Message("size %ld  nread %ld", size, nread);
-
-  return (nread);
+  return ptr;
 }
 
 
-size_t fileRead(int fileID, void *restrict ptr, size_t size)
+void *memRealloc(void *ptrold, size_t size, const char *file, const char *functionname, int line)
 {
-  size_t nread = 0;
-  bfile_t *fileptr;
+  void *ptr = NULL;
 
-  fileptr = file_to_pointer(fileID);
+  memInit();
 
-  if ( fileptr )
+  if ( size > 0 )
     {
-      double t_begin = 0.0;
-
-      if ( FileInfo ) t_begin = file_time();
+      ptr = realloc(ptrold, size);
 
-      if ( fileptr->type == FILE_TYPE_OPEN )
-	nread = file_read_from_buffer(fileptr, ptr, size);
-      else
+      if ( MEM_Info )
 	{
-	  nread = fread(ptr, 1, size, fileptr->fp);
-	  if ( nread != size )
+	  memAccess++;
+
+          int item = MEM_UNDEFID;
+	  if ( ptr )
 	    {
-	      if ( nread == 0 )
-		fileptr->flag |= FILE_EOF;
-	      else
-		fileptr->flag |= FILE_ERROR;
+	      item = memListChangeEntry(ptrold, ptr, size, functionname, file, line);
+
+	      if ( item == MEM_UNDEFID ) item = memListNewEntry(REALLOC_FUNC, ptr, size, 1, functionname, file, line);
 	    }
-	}
 
-      if ( FileInfo ) fileptr->time_in_sec += file_time() - t_begin;
+	  if ( MEM_Debug ) memListPrintEntry(REALLOC_FUNC, item, size, ptr, functionname, file, line);
+	}
 
-      fileptr->position  += (off_t)nread;
-      fileptr->byteTrans += (off_t)nread;
-      fileptr->access++;
+      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));
 
-  if ( FILE_Debug ) Message("size %ld  nread %ld", size, nread);
-
-  return (nread);
+  return ptr;
 }
 
 
-size_t fileWrite(int fileID, const void *restrict ptr, size_t size)
+void memFree(void *ptr, const char *file, const char *functionname, int line)
 {
-  size_t nwrite = 0;
-  bfile_t *fileptr;
-
-  fileptr = file_to_pointer(fileID);
+  memInit();
 
-  if ( fileptr )
+  if ( MEM_Info )
     {
-      double t_begin = 0.0;
+      int item;
+      size_t size;
 
-      /* if ( fileptr->buffer == NULL ) file_set_buffer(fileptr); */
+      if ( (item = memListDeleteEntry(ptr, &size)) >= 0 )
+	{
+	  if ( MEM_Debug ) memListPrintEntry(FREE_FUNC, item, size, ptr, functionname, file, line);
+	}
+      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);
+	}
+    }
 
-      if ( FileInfo ) t_begin = file_time();
+  free(ptr);
+}
 
-      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;
-            }
-          else
-            nwrite = (size_t)temp;
-        }
 
-      if ( FileInfo ) fileptr->time_in_sec += file_time() - t_begin;
+size_t memTotal(void)
+{
+  size_t memtotal = 0;
+#if  defined  (HAVE_MALLINFO)
+  struct mallinfo meminfo = mallinfo();
+  if ( MEM_Debug )
+    {
+      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);
 
-      fileptr->position  += (off_t)nwrite;
-      fileptr->byteTrans += (off_t)nwrite;
-      fileptr->access++;
+      /* malloc_stats(); */
     }
+  memtotal = (size_t)meminfo.arena;
+#endif
 
-  return (nwrite);
+  return memtotal;
+}
+
+
+void memExitOnError(void)
+{
+  dmemory_ExitOnError = 1;
 }
 /*
  * Local Variables:
@@ -22400,20 +21401,141 @@ size_t fileWrite(int fileID, const void *restrict ptr, size_t size)
  * require-trailing-newline: t
  * End:
  */
-#ifndef _GAUSSGRID_H
-#define _GAUSSGRID_H
+#if defined (HAVE_CONFIG_H)
+#endif
 
-#ifdef __cplusplus
-extern "C" {
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#if !defined (NAMESPACE_H)
 #endif
 
-void gaussaw(double *restrict pa, double *restrict pw, size_t nlat);
+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 defined (__cplusplus)
+/* 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 )
+    {
+      errno = saved_errno;
+      perror("System error message");
+    }
+
+  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);
 }
+
+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  /* _GAUSSGRID_H */
+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);
+}
+
+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);
+
+void Warning_(const char *caller, const char *fmt, ...)
+{
+  va_list args;
+
+  va_start(args, fmt);
+
+  if ( _Verbose )
+    {
+      cdiWarningFunc cdiWarning_p
+        = (cdiWarningFunc)namespaceSwitchGet(NSSWITCH_WARNING).func;
+      cdiWarning_p(caller, fmt, args);
+    }
+
+  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);
+}
+
+
+void Message_(const char *caller, const char *fmt, ...)
+{
+  va_list args;
+
+  va_start(args, fmt);
+
+   fprintf(stdout, "%-18s : ", caller);
+  vfprintf(stdout, fmt, args);
+   fprintf(stdout, "\n");
+
+  va_end(args);
+}
 /*
  * Local Variables:
  * c-file-style: "Java"
@@ -22423,678 +21545,585 @@ void gaussaw(double *restrict pa, double *restrict pw, size_t nlat);
  * require-trailing-newline: t
  * End:
  */
-#ifdef HAVE_CONFIG_H
+#ifndef EXSE_H
+#define EXSE_H
+
+enum {
+  EXSE_SINGLE_PRECISION = 4,
+  EXSE_DOUBLE_PRECISION = 8,
+};
+
+#endif
+#if defined (HAVE_CONFIG_H)
 #endif
 
-#include <math.h>
-#include <float.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
 
 
 
-#ifndef  M_PI
-#define  M_PI        3.14159265358979323846  /* pi */
-#endif
+enum {
+  EXT_HEADER_LEN = 4,
+};
 
-#ifndef  M_SQRT2
-#define  M_SQRT2     1.41421356237309504880
-#endif
+
+static int initExtLib       = 0;
+static int extDefaultPrec   = 0;
+static int extDefaultNumber = EXT_REAL;
 
 
-static
-void cpledn(size_t kn, size_t kodd, double *pfn, double pdx, int kflag, 
-            double *pw, double *pdxn, double *pxmod)
+/*
+ * 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)
 {
-  double zdlk;
-  double zdlldn;
-  double zdlx;
-  double zdlmod;
-  double zdlxn;
+  return ext_libvers;
+}
 
-  size_t ik;
 
-  /* 1.0 Newton iteration step */
+static int EXT_Debug = 0;    /* If set to 1, debugging */
 
-  zdlx = pdx;
-  zdlk = 0.0;
-  if (kodd == 0) 
-    {
-      zdlk = 0.5*pfn[0];
-    }
-  zdlxn  = 0.0;
-  zdlldn = 0.0;
 
-  ik = 1;
+void extDebug(int debug)
+{
+  EXT_Debug = debug;
 
-  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 */
-      zdlmod = -(zdlk/zdlldn);
-      zdlxn = zdlx + zdlmod;
-      *pdxn = zdlxn;
-      *pxmod = zdlmod;
-    }
+  if ( EXT_Debug )
+    Message("debug level %d", debug);
+}
 
-  /* 2.0 Compute weights */
 
-  if (kflag == 1) 
+static
+void extLibInit()
+{
+  const char *envName = "EXT_PRECISION";
+
+  char *envString = getenv(envName);
+  if ( envString )
     {
-      for(size_t jn = 2-kodd; jn <= kn; jn += 2) 
+      int pos = 0;
+
+      if ( strlen(envString) == 2  )
 	{
-	  /* normalised derivative */
-	  zdlldn = zdlldn - pfn[ik]*(double)(jn)*sin((double)(jn)*zdlx);
-	  ik++;
+	  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;
+              }
+            }
 	}
-      *pw = (double)(2*kn+1)/(zdlldn*zdlldn);
     }
 
-  return;
+  initExtLib = 1;
 }
 
 static
-void gawl(double *pfn, double *pl, double *pw, size_t kn)
+void extInit(extrec_t *extp)
 {
-  double pmod = 0;
-  int iflag;
-  int itemax;
-  double zw = 0;
-  double zdlx;
-  double zdlxn = 0;
-
-  /* 1.0 Initizialization */
-
-  iflag  =  0;
-  itemax = 20;
-
-  size_t iodd   = (kn % 2);
-
-  zdlx   =  *pl;
-
-  /* 2.0 Newton iteration */
-
-  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;
-    }
-
-  *pl = zdlxn;
-  *pw = zw;
-
-  return;
+  extp->checked    = 0;
+  extp->byteswap   = 0;
+  extp->prec       = 0;
+  extp->number     = extDefaultNumber;
+  extp->datasize   = 0;
+  extp->buffersize = 0;
+  extp->buffer     = NULL;
 }
 
-static
-void gauaw(size_t kn, double *__restrict__ pl, double *__restrict__ pw)
+
+void *extNew(void)
 {
-  /*
-   * 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;
+  if ( ! initExtLib ) extLibInit();
 
-  double z, zfnn;
+  extrec_t *extp = (extrec_t *) Malloc(sizeof(extrec_t));
 
-  zfn    = (double *) Malloc((kn+1) * (kn+1) * sizeof(double));
-  zfnlat = (double *) Malloc((kn/2+1+1)*sizeof(double));
+  extInit(extp);
 
-  zfn[0] = M_SQRT2;
-  for (size_t jn = 1; jn <= kn; jn++)
-    {
-      zfnn = zfn[0];
-      for (size_t jgl = 1; jgl <= jn; jgl++)
-	{
-	  zfnn *= sqrt(1.0-0.25/((double)(jgl*jgl))); 
-	}
+  return (void*)extp;
+}
 
-      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 extDelete(void *ext)
+{
+  extrec_t *extp = (extrec_t *) ext;
+
+  if ( extp )
+    {
+      if ( extp->buffer ) Free(extp->buffer);
+      Free(extp);
     }
+}
 
 
-  /* 2.0 Gaussian latitudes and weights */
+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;
 
-  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++;
-    } 
+  if ( fileRead(fileID, buffer, 4) != 4 ) return found;
 
-  /*
-   * 2.1 Find first approximation of the roots of the
-   *     Legendre polynomial of degree kn.
-   */
+  size_t blocklen  = (size_t) get_UINT32(buffer);
+  size_t sblocklen = (size_t) get_SUINT32(buffer);
 
-  size_t ins2 = kn/2+(kn % 2);
+  if ( EXT_Debug )
+    Message("blocklen = %d sblocklen = %d", blocklen, sblocklen);
 
-  for (size_t jgl = 1; jgl <= ins2; jgl++) 
+  if ( blocklen == 16 )
     {
-      z = ((double)(4*jgl-1))*M_PI/((double)(4*kn+2)); 
-      pl[jgl-1] = z+1.0/(tan(z)*((double)(8*kn*kn)));
+     *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);
     }
-
-  /* 2.2 Computes roots and weights for transformed theta */
-
-  for (size_t jgl = ins2; jgl >= 1 ; jgl--) 
+  else if ( blocklen == 32 )
     {
-      size_t jglm1 = jgl-1;
-      gawl(zfnlat, &(pl[jglm1]), &(pw[jglm1]), kn);
+     *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);
     }
-
-  /* convert to physical latitude */
-
-  for (size_t jgl = 0; jgl < ins2; jgl++) 
+  else if ( sblocklen == 16 )
     {
-      pl[jgl] = cos(pl[jgl]);
+     *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);
     }
-
-  for (size_t jgl = 1; jgl <= kn/2; jgl++) 
+  else if ( sblocklen == 32 )
     {
-      size_t jglm1 = jgl-1;
-      size_t isym =  kn-jgl;
-      pl[isym] =  -pl[jglm1];
-      pw[isym] =  pw[jglm1];
+     *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);
     }
 
-  Free(zfnlat);
-  Free(zfn);
+  fileRewind(fileID);
 
-  return;
+  if      ( data && dimxy*fact   == data ) found = 1;
+  else if ( data && dimxy*fact*2 == data ) found = 1;
+
+  if ( EXT_Debug )
+    {
+      Message("swap = %d fact = %d", *swap, fact);
+      Message("dimxy = %lu data = %lu", dimxy, data);
+    }
+
+  return found;
 }
 
-#if 0
-static
-void gauaw_old(double *pa, double *pw, int nlat)
-{
-  /*
-   * Compute Gaussian latitudes.  On return pa contains the
-   * sine of the latitudes starting closest to the north pole and going
-   * toward the south
-   *
-   */
 
-  const int itemax = 20;
+int extInqHeader(void *ext, int *header)
+{
+  extrec_t *extp = (extrec_t *) ext;
 
-  int isym, iter, ins2, jn, j;
-  double za, zw, zan;
-  double z, zk, zkm1, zkm2, zx, zxn, zldn, zmod;
+  for ( size_t i = 0; i < EXT_HEADER_LEN; i++ )
+    header[i] = extp->header[i];
 
-  /*
-   * Perform the Newton loop
-   * Find 0 of Legendre polynomial with Newton loop
-   */
+  if ( EXT_Debug ) Message("datasize = %lu", extp->datasize);
 
-  ins2 = nlat/2 + nlat%2;
+  return 0;
+}
 
-  for ( j = 0; j < ins2; j++ )
-    {
-      z = (double) (4*(j+1)-1)*M_PI / (double) (4*nlat+2);
-      pa[j] = cos(z + 1.0/(tan(z)*(double)(8*nlat*nlat)));
-    }
 
-  for ( j = 0; j < ins2; j++ )
-    {
+int extDefHeader(void *ext, const int *header)
+{
+  extrec_t *extp = (extrec_t *) ext;
 
-      za = pa[j];
+  for ( size_t i = 0; i < EXT_HEADER_LEN; i++ )
+    extp->header[i] = header[i];
 
-      iter = 0;
-      do
-	{
-	  iter++;
-	  zk = 0.0;
+  extp->datasize = (size_t)header[3];
+  if ( extp->number == EXT_COMP ) extp->datasize *= 2;
 
-	  /* Newton iteration step */
+  if ( EXT_Debug ) Message("datasize = %lu", extp->datasize);
 
-	  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 );
+  return 0;
+}
 
-      pa[j] = zan;
-      pw[j] = 2.0*zw;
-    }
+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 (SX)
-#pragma vdir nodep
-#endif
-  for (j = 0; j < nlat/2; j++)
+  switch ( rprec )
     {
-      isym = nlat-(j+1);
-      pa[isym] = -pa[j];
-      pw[isym] =  pw[j];
+    case EXSE_SINGLE_PRECISION:
+      {
+	if ( sizeof(FLT32) == 4 )
+	  {
+	    if ( byteswap ) swap4byte(buffer, datasize);
+
+	    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);
+
+	    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;
+  return ierr;
 }
-#endif
 
-void gaussaw(double *restrict pa, double *restrict pw, size_t nlat)
+
+int extInqDataSP(void *ext, float *data)
 {
-  //gauaw_old(pa, pw, nlat);
-  gauaw(nlat, pa, pw);
+  return extInqData((extrec_t *)ext, EXSE_SINGLE_PRECISION, (void *) data);
 }
 
-/*
-#define NGL  48
 
-int main (int rgc, char *argv[])
+int extInqDataDP(void *ext, double *data)
 {
-  int ngl = NGL;
-  double plo[NGL], pwo[NGL];
-  double pl[NGL], pw[NGL];
+  return extInqData((extrec_t *)ext, EXSE_DOUBLE_PRECISION, (void *) data);
+}
 
-  int 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;
-    }
+static int extDefData(void *ext, int prec, const void *data)
+{
+  extrec_t *extp = (extrec_t *) ext;
+  size_t i;
+  int rprec;
+  void *buffer;
 
-  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]);
-    }
+  if ( extDefaultPrec ) rprec = extDefaultPrec;
+  else                  rprec = extp->prec;
 
-  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
+  if ( ! rprec ) rprec = prec;
 
-#if  defined  (HAVE_LIBGRIB_API)
-#  include <grib_api.h>
-#endif
+  extp->prec = rprec;
 
-#include <stdio.h>
+  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;
 
-static char gribapi_libvers[64] = "";
-#if  defined  (HAVE_LIBGRIB_API)
-static int gribapi_libvers_init;
-#endif
+  extp->datasize = datasize;
 
+  size_t buffersize = extp->buffersize;
 
-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 ( buffersize != blocklen )
+    {
+      buffersize = blocklen;
+      buffer = extp->buffer;
+      buffer = Realloc(buffer, buffersize);
+      extp->buffer = buffer;
+      extp->buffersize = buffersize;
+    }
+  else
+    buffer = extp->buffer;
 
-const char *gribapiLibraryVersionString(void)
-{
-#if  defined  (HAVE_LIBGRIB_API)
-  if (!gribapi_libvers_init)
+  switch ( rprec )
     {
-      int major_version, minor_version, revision_version;
+    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];
 
-      gribapiLibraryVersion(&major_version, &minor_version, &revision_version);
+	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];
 
-      sprintf(gribapi_libvers, "%d.%d.%d", major_version, minor_version, revision_version);
-      gribapi_libvers_init = 1;
+	break;
+      }
+    default:
+      {
+	Error("unexpected data precision %d", rprec);
+        break;
+      }
     }
-#endif
 
-  return (gribapi_libvers);
+  return 0;
 }
 
 
-void gribContainersNew(stream_t * streamptr)
+int extDefDataSP(void *ext, const float *data)
 {
-  int editionNumber = 2;
+  return extDefData(ext, EXSE_SINGLE_PRECISION, (void *) data);
+}
 
-  if ( streamptr->filetype == FILETYPE_GRB ) editionNumber = 1;
-  (void)editionNumber;
-#if  defined  (HAVE_LIBCGRIBEX)
-  if ( streamptr->filetype == FILETYPE_GRB )
+
+int extDefDataDP(void *ext, const double *data)
+{
+  return extDefData(ext, EXSE_DOUBLE_PRECISION, (void *) data);
+}
+
+
+int extRead(int fileID, void *ext)
+{
+  extrec_t *extp = (extrec_t *) ext;
+  size_t i;
+  void *buffer;
+  int status;
+
+  if ( ! extp->checked )
     {
+      status = extCheckFiletype(fileID, &extp->byteswap);
+      if ( status == 0 ) Error("Not a EXTRA file!");
+      extp->checked = 1;
     }
-  else
-#endif
-    {
-      int nvars = streamptr->nvars;
-
-#if defined (GRIBCONTAINER2D)
-      gribContainer_t **gribContainers;
-      gribContainers = (gribContainer_t **) Malloc(nvars*sizeof(gribContainer_t *));
 
-      for ( int varID = 0; varID < nvars; ++varID )
-        {
-          int nlevs = streamptr->vars[varID].nlevs;
-          gribContainers[varID] = (gribContainer_t *) Malloc(nlevs*sizeof(gribContainer_t));
+  int byteswap = extp->byteswap;
 
-          for ( int levelID = 0; levelID < nlevs; ++levelID )
-            {
-              gribContainers[varID][levelID].gribHandle = gribHandleNew(editionNumber);
-              gribContainers[varID][levelID].init = FALSE;
-            }
-	}
+  /* read header record */
+  size_t blocklen = binReadF77Block(fileID, byteswap);
 
-      streamptr->gribContainers = (void **) gribContainers;
-#else
-      gribContainer_t *gribContainers
-        = (gribContainer_t *) Malloc((size_t)nvars*sizeof(gribContainer_t));
+  if ( fileEOF(fileID) ) return -1;
 
-      for ( int varID = 0; varID < nvars; ++varID )
-        {
-          gribContainers[varID].gribHandle = gribHandleNew(editionNumber);
-          gribContainers[varID].init = FALSE;
-	}
+  if ( EXT_Debug )
+    Message("blocklen = %lu", blocklen);
 
-      streamptr->gribContainers = (void *) gribContainers;
-#endif
-    }
-}
+  size_t hprec = blocklen / EXT_HEADER_LEN;
 
+  extp->prec = (int)hprec;
 
-void gribContainersDelete(stream_t * streamptr)
-{
-  if ( streamptr->gribContainers )
+  switch ( hprec )
     {
-      int nvars = streamptr->nvars;
-
-#if defined (GRIBCONTAINER2D)
-      gribContainer_t **gribContainers = (gribContainer_t **) streamptr->gribContainers;
+    case EXSE_SINGLE_PRECISION:
+      {
+        INT32 tempheader[4];
+	binReadInt32(fileID, byteswap, EXT_HEADER_LEN, tempheader);
 
-      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;
+	for ( i = 0; i < EXT_HEADER_LEN; i++ )
+          extp->header[i] = (int)tempheader[i];
 
-      for ( int varID = 0; varID < nvars; ++varID )
-	{
-          gribHandleDelete(gribContainers[varID].gribHandle);
-	}
-#endif
+	break;
+      }
+    case EXSE_DOUBLE_PRECISION:
+      {
+        INT64 tempheader[4];
+	binReadInt64(fileID, byteswap, EXT_HEADER_LEN, tempheader);
 
-      Free(gribContainers);
+	for ( i = 0; i < EXT_HEADER_LEN; i++ )
+          extp->header[i] = (int)tempheader[i];
 
-      streamptr->gribContainers = NULL;
+	break;
+      }
+    default:
+      {
+	Error("Unexpected header precision %d", hprec);
+        break;
+      }
     }
-}
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
-#ifndef _GRID_H
-#define _GRID_H
 
+  size_t blocklen2 = binReadF77Block(fileID, byteswap);
 
-typedef unsigned char mask_t;
+  if ( blocklen2 != blocklen )
+    {
+      Warning("Header blocklen differ (blocklen1=%d; blocklen2=%d)!", blocklen, blocklen2);
+      if ( blocklen2 != 0 ) return -1;
+    }
 
-typedef struct grid_t grid_t;
+  extp->datasize = (size_t)extp->header[3];
 
-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 */
-  int (*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 */
-  int (*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 ( EXT_Debug ) Message("datasize = %lu", extp->datasize);
 
-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;
-};
+  blocklen = binReadF77Block(fileID, byteswap);
 
+  size_t buffersize = (size_t)extp->buffersize;
 
-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 ( buffersize < blocklen )
+    {
+      buffersize = blocklen;
+      buffer = extp->buffer;
+      buffer = Realloc(buffer, buffersize);
+      extp->buffer = buffer;
+      extp->buffersize = buffersize;
+    }
+  else
+    buffer = extp->buffer;
 
-unsigned cdiGridCount(void);
+  size_t dprec = blocklen / extp->datasize;
 
-const double *gridInqXvalsPtr(int gridID);
-const double *gridInqYvalsPtr(int gridID);
+  if ( dprec == hprec )
+    {
+      extp->number = EXT_REAL;
+    }
+  else if ( dprec == 2*hprec )
+    {
+      dprec /= 2;
+      extp->datasize *= 2;
+      extp->number = EXT_COMP;
+    }
 
-const double *gridInqXboundsPtr(int gridID);
-const double *gridInqYboundsPtr(int gridID);
-const double *gridInqAreaPtr(int gridID);
+  if ( dprec != EXSE_SINGLE_PRECISION && dprec != EXSE_DOUBLE_PRECISION )
+    {
+      Warning("Unexpected data precision %d", dprec);
+      return -1;
+    }
 
-const char *gridInqXnamePtr(int gridID);
-const char *gridInqYnamePtr(int gridID);
+  fileRead(fileID, buffer, blocklen);
 
-const char *gridInqReferencePtr(int gridID);
+  blocklen2 = binReadF77Block(fileID, byteswap);
 
-int gridCompare(int gridID, const grid_t *grid);
-int gridGenerate(const grid_t *grid);
+  if ( blocklen2 != blocklen )
+    {
+      Warning("Data blocklen differ (blocklen1=%d; blocklen2=%d)!", blocklen, blocklen2);
+      if ( blocklen2 != 0 ) return -1;
+    }
 
-void cdiGridGetIndexList(unsigned, int * );
+  return 0;
+}
 
-void
-gridUnpack(char * unpackBuffer, int unpackBufferSize,
-           int * unpackBufferPos, int originNamespace, void *context,
-           int force_id);
 
-struct addIffNewRes
+int extWrite(int fileID, void *ext)
 {
-  int Id;
-  int isNew;
-};
+  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;
 
-struct addIffNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode);
+  /* write header record */
+  size_t blocklen = EXT_HEADER_LEN * (size_t)rprec;
 
-#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
+  binWriteF77Block(fileID, byteswap, blocklen);
 
-#ifdef HAVE_LIBGRIB_API
+  switch ( rprec )
+    {
+    case EXSE_SINGLE_PRECISION:
+      {
+	for ( i = 0; i < EXT_HEADER_LEN; i++ )
+          tempheader.i32[i] = (INT32) header[i];
 
+	binWriteInt32(fileID, byteswap, EXT_HEADER_LEN, tempheader.i32);
 
-#include <grib_api.h>
+	break;
+      }
+    case EXSE_DOUBLE_PRECISION:
+      {
+	for ( i = 0; i < EXT_HEADER_LEN; i++ )
+          tempheader.i64[i] = (INT64) header[i];
 
-#include <stdbool.h>
+	binWriteInt64(fileID, byteswap, EXT_HEADER_LEN, tempheader.i64);
 
-char* gribCopyString(grib_handle* gribHandle, const char* key);
-bool gribCheckString(grib_handle* gribHandle, const char* key, const char* expectedValue);
+	break;
+      }
+    default:
+      {
+	Error("unexpected header precision %d", rprec);
+        break;
+      }
+    }
 
-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);
+  binWriteF77Block(fileID, byteswap, blocklen);
 
-double gribGetDouble(grib_handle* gh, const char* key);
-double gribGetDoubleDefault(grib_handle* gribHandle, const char* key, double defaultValue);
+  size_t datasize = (size_t)header[3];
+  if ( number == EXT_COMP ) datasize *= 2;
+  blocklen = datasize * (size_t)rprec;
 
-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.
+  binWriteF77Block(fileID, byteswap, blocklen);
 
-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);
+  extp->datasize = datasize;
 
-#endif
+  void *buffer = extp->buffer;
 
-#endif
+  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:
  * c-file-style: "Java"
@@ -23107,8411 +22136,8317 @@ void gribapiGetGrid(grib_handle *gh, grid_t *grid);
 #if defined (HAVE_CONFIG_H)
 #endif
 
-#ifdef HAVE_LIBGRIB_API
-
-
-
 #include <assert.h>
-#include <time.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.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()
 
-#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)
 
-//A simple wrapper for grib_get_string() that returns a newly allocated string.
-char* gribCopyString(grib_handle* gribHandle, const char* key)
-{
-  char* result = NULL;
-  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;
-      }
-    }
-#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)
-    {
-      if (length <= 1024UL * 1024UL)
-        {
-          length *= 2;
-          result = Realloc(result, length);
-        }
-      else
-        break;
-    }
-  if (!rc)
-    result = Realloc(result, length);
-  else
-    {
-      Free(result);
-      result = NULL;
-    }
+#if ! defined (O_BINARY)
+#define O_BINARY 0
 #endif
-  return result;
-}
 
-//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)
-{
-  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);
+#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
-  return rc;
-}
 
-//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;
-}
 
-//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;
-}
+#if defined (HAVE_MMAP)
+#  include <sys/mman.h> /* mmap() is defined in this header */
+#endif
 
-//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;
-}
 
-//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)
-{
-  double result;
-  FAIL_ON_GRIB_ERROR(grib_get_double, gh, key, &result);
-  return result;
-}
+#if ! defined   (FALSE)
+#  define  FALSE  0
+#endif
 
-//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;
-}
+#if ! defined   (TRUE)
+#  define  TRUE   1
+#endif
 
-//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;
-}
+/* #define  MAX_FILES  FOPEN_MAX */
+#define  MAX_FILES  4096
 
-//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);
-}
+static int _file_max = MAX_FILES;
 
-//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);
-}
+static void file_initialize(void);
 
+static int _file_init = FALSE;
 
-//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  defined  (HAVE_LIBPTHREAD)
+#include <pthread.h>
 
-//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;
-}
+static pthread_once_t  _file_init_thread = PTHREAD_ONCE_INIT;
+static pthread_mutex_t _file_mutex;
 
-//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)
-{
-  if(savedTz)
-    {
-      setenv("TZ", savedTz, 1);
-      Free(savedTz);
-    }
-  else
-    {
-      unsetenv("TZ");
-    }
-}
+#  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)
 
-//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.
+#else
 
-  int result = mktime(me) == (time_t)-1;        //This does all the heavy lifting.
+#  define FILE_LOCK()
+#  define FILE_UNLOCK()
+#  define FILE_INIT()        \
+   if ( _file_init == FALSE ) file_initialize()
 
-  resetTz(savedTz);
-  return result;
-}
+#endif
 
-//Returns zero on success.
-static int addSecondsToDate(struct tm* me, long long amount)
-{
-  //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);
-}
 
-static void addMonthsToDate(struct tm* me, long long amount)
+typedef struct
 {
-  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;
+  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;
 
-//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)
-    {
-      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
-    }
-}
+enum F_I_L_E_Flags
+  {
+    FILE_READ  =  01,
+    FILE_WRITE =  02,
+    FILE_UNBUF =  04,
+    FILE_EOF   = 010,
+    FILE_ERROR = 020
+  };
 
-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)
-{
-  switch(gribGetLong(gh, "productDefinitionTemplateNumber"))
-    {
-      case 20: case 30: case 31: case 254: case 311: case 2000:
-        *outHaveForecastTime = false, *outHaveTimeRange = false;
-        return 0;
+static int FileInfo  = FALSE;
 
-      //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;
 
-      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 ! defined (MIN_BUF_SIZE)
+#  define  MIN_BUF_SIZE  131072L
+#endif
 
-      default:
-        return 1;
-    }
-}
 
-char* gribMakeTimeString(grib_handle* gh, CdiTimeType timeType)
-{
-  //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");
+static size_t FileBufferSizeMin = MIN_BUF_SIZE;
+static long   FileBufferSizeEnv = -1;
+static short  FileBufferTypeEnv =  0;
 
-  if(gribEditionNumber(gh) == 1)
-    {
-      date.tm_year = (int)gribGetLong(gh, "yearOfCentury");  //years are -1900 based both in struct tm and GRIB1
-    }
-  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");
+static short  FileTypeRead  = FILE_TYPE_OPEN;
+static short  FileTypeWrite = FILE_TYPE_FOPEN;
+static int    FileFlagWrite = 0;
 
-      //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
+static int    FILE_Debug = 0;   /* If set to 1, debugging */
 
-          //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;
-                }
-            }
-        }
-    }
 
-  //Bake the date into a string.
-  return makeDateString(&date);
-}
+static void file_table_print(void);
 
-int gribapiTimeIsFC(grib_handle *gh)
-{
-  if(gribEditionNumber(gh) <= 1) return true;
+/*
+ * 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__;
 
-  long sigofrtime;
-  FAIL_ON_GRIB_ERROR(grib_get_long, gh, "significanceOfReferenceTime", &sigofrtime);
-  return sigofrtime != 3;
-}
+/*
+  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)
+ */
 
-//Fetches the value of the "stepType" key and converts it into a constant in the TSTEP_* range.
-int gribapiGetTsteptype(grib_handle *gh)
-{
-  int tsteptype = TSTEP_INSTANT;
-  static bool lprint = true;
 
-  if ( gribapiTimeIsFC(gh) )
-    {
-      int status;
-      size_t len = 256;
-      char stepType[256];
+typedef struct _filePtrToIdx {
+  int idx;
+  bfile_t *ptr;
+  struct _filePtrToIdx *next;
+} filePtrToIdx;
 
-      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;
-            }
 
-          // printf("stepType: %s %ld %d\n", stepType, len, tsteptype);
-        }
-    }
+static filePtrToIdx *_fileList  = NULL;
+static filePtrToIdx *_fileAvail = NULL;
+
+static
+void file_list_new(void)
+{
+  assert(_fileList == NULL);
 
-  return (tsteptype);
+  _fileList = (filePtrToIdx *) Malloc((size_t)_file_max * sizeof (filePtrToIdx));
 }
 
-int gribGetDatatype(grib_handle* gribHandle)
+static
+void file_list_delete(void)
 {
-  int datatype;
-  if(gribEditionNumber(gribHandle) > 1 && gribCheckString(gribHandle, "packingType", "grid_ieee"))
-    {
-      datatype = gribCheckLong(gribHandle, "precision", 1) ? DATATYPE_FLT32 : DATATYPE_FLT64;
-    }
-  else
+  if ( _fileList )
     {
-      long bitsPerValue;
-      datatype = (!grib_get_long(gribHandle, "bitsPerValue", &bitsPerValue) && bitsPerValue > 0 && bitsPerValue <= 32) ? (int)bitsPerValue : DATATYPE_PACK;
+      Free(_fileList);
+      _fileList = NULL;
     }
-  return datatype;
 }
 
-int gribapiGetParam(grib_handle *gh)
+static
+void file_init_pointer(void)
 {
-  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  i;
+
+  for ( i = 0; i < _file_max; i++ )
     {
-      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;
+      _fileList[i].next = _fileList + i + 1;
+      _fileList[i].idx  = i;
+      _fileList[i].ptr  = 0;
     }
-  return cdiEncodeParam((int)pnum, (int)pcat, (int)pdis);
+
+  _fileList[_file_max-1].next = 0;
+
+  _fileAvail = _fileList;
 }
 
-int gribapiGetGridType(grib_handle *gh)
+static
+bfile_t *file_to_pointer(int idx)
 {
-  int gridtype = GRID_GENERIC;
-  switch (gribGetLongDefault(gh, "gridDefinitionTemplateNumber", -1))
+  bfile_t *fileptr = NULL;
+
+  FILE_INIT();
+
+  if ( idx >= 0 && idx < _file_max )
     {
-      case  GRIB2_GTYPE_LATLON:
-        gridtype = ( gribGetLong(gh, "Ni") == (long) GRIB_MISSING_LONG ) ? GRID_GENERIC : GRID_LONLAT;
-        break;
+      FILE_LOCK();
 
-      case  GRIB2_GTYPE_GAUSSIAN:
-        gridtype = ( gribGetLong(gh, "Ni") == (long) GRIB_MISSING_LONG ) ? GRID_GAUSSIAN_REDUCED : GRID_GAUSSIAN;
-        break;
+      fileptr = _fileList[idx].ptr;
 
-      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;
+      FILE_UNLOCK();
     }
+  else
+    Error("file index %d undefined!", idx);
 
-  return gridtype;
+  return (fileptr);
 }
 
+/* Create an index from a pointer */
 static
-int gribapiGetIsRotated(grib_handle *gh)
-{
-  return gribGetLongDefault(gh, "gridDefinitionTemplateNumber", -1) == GRIB2_GTYPE_LATLON_ROT;
-}
-
-//TODO: Simplify by use of the convenience functions (gribGetLong(), gribGetLongDefault(), etc.).
-void gribapiGetGrid(grib_handle *gh, grid_t *grid)
+int file_from_pointer(bfile_t *ptr)
 {
-  long editionNumber = gribEditionNumber(gh);
-  int gridtype = gribapiGetGridType(gh);
-  /*
-  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);
-
-  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);
+  int      idx = -1;
+  filePtrToIdx *newptr;
 
-  switch (gridtype)
+  if ( ptr )
     {
-    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);
-
-        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;
+      FILE_LOCK();
 
-                if ( editionNumber <= 1 )
-                  {
-                    /* correct xinc if necessary */
-                    if ( IS_EQUAL(grid->xfirst, 0) && grid->xlast > 354 )
-                      {
-                        double xinc = 360. / grid->xsize;
+      if ( _fileAvail )
+	{
+	  newptr       = _fileAvail;
+	  _fileAvail   = _fileAvail->next;
+	  newptr->next = 0;
+	  idx	       = newptr->idx;
+	  newptr->ptr  = ptr;
 
-                        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:
-      {
-        size_t dummy;
-        long *pl;
+	  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);
 
-        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->rowlon = (int *) Malloc((size_t)nlat * sizeof (int));
-        pl          = (long *) Malloc((size_t)nlat * sizeof (long));
-        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;
+      FILE_UNLOCK();
+    }
+  else
+    Error("Internal problem (pointer %p undefined)", ptr);
 
-                if ( editionNumber <= 1 )
-                  {
-                    /* correct xinc if necessary */
-                    if ( IS_EQUAL(grid->xfirst, 0) && grid->xlast > 354 )
-                      {
-                        double xinc = 360. / grid->xsize;
+  return (idx);
+}
 
-                        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;
+static
+void file_init_entry(bfile_t *fileptr)
+{
+  fileptr->self          = file_from_pointer(fileptr);
 
-        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;
+  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 ( numberOfPoints != nlon*nlat )
-          Error("numberOfPoints (%d) and gridSize (%d) differ!", (int)numberOfPoints, nlon*nlat);
+static
+bfile_t *file_new_entry(void)
+{
+  bfile_t *fileptr;
 
-        grid->size  = (int)numberOfPoints;
-        grid->xsize = nlon;
-        grid->ysize = nlat;
+  fileptr = (bfile_t *) Malloc(sizeof(bfile_t));
 
-        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 ( fileptr ) file_init_entry(fileptr);
 
-        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;
-          }
+  return (fileptr);
+}
 
-        grid->xdef   = 0;
-        grid->ydef   = 0;
+static
+void file_delete_entry(bfile_t *fileptr)
+{
+  int idx;
 
-        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;
+  idx = fileptr->self;
 
-        /* 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;
+  FILE_LOCK();
 
-        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;
+  Free(fileptr);
 
-        break;
-      }
-    case GRID_UNSTRUCTURED:
-      {
-        unsigned char uuid[CDI_UUID_SIZE];
-        /*
-        char reference_link[8192];
-        size_t len = sizeof(reference_link);
-        reference_link[0] = 0;
-        */
+  _fileList[idx].next = _fileAvail;
+  _fileList[idx].ptr  = 0;
+  _fileAvail   	      = &_fileList[idx];
 
-        /* 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;
+  FILE_UNLOCK();
 
-        /* FIXME: assert(numberOfPoints <= INT_MAX && numberOfPoints >= INT_MIN) */
-        grid->size  = (int)numberOfPoints;
+  if ( FILE_Debug )
+    Message("Removed idx %d from file list", idx);
+}
 
-        if ( nlon > 0 && nlat > 0 && nlon*nlat == grid->size )
-          {
-            grid->xsize = nlon;
-            grid->ysize = nlat;
-          }
-        else
-          {
-            grid->xsize = 0;
-            grid->ysize = 0;
-          }
 
-        break;
-      }
-    default:
-      {
-        Error("Unsupported grid type: %s", gridNamePtr(gridtype));
-        break;
-      }
-    }
+const char *fileLibraryVersion(void)
+{
+  return (file_libvers);
+}
 
-  grid->isRotated = FALSE;
-  if ( gribapiGetIsRotated(gh) )
-    {
-      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;
-    }
 
-  grid->xvals = NULL;
-  grid->yvals = NULL;
-  grid->type  = gridtype;
-}
+static
+int pagesize(void)
+{
+#if defined(_SC_PAGESIZE)
+  return ((int) sysconf(_SC_PAGESIZE));
+#else
+#ifndef POSIXIO_DEFAULT_PAGESIZE
+#define POSIXIO_DEFAULT_PAGESIZE 4096
 #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
-
-#if defined (HAVE_CONFIG_H)
+  return ((int) POSIXIO_DEFAULT_PAGESIZE);
 #endif
+}
 
+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);
+}
 
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-static inline int cdiUUIDIsNull(const unsigned char uuid[])
+void fileDebug(int debug)
 {
-  int isNull = 1;
-  for (size_t i = 0; i < CDI_UUID_SIZE; ++i)
-    isNull &= (uuid[i] == 0);
-  return isNull;
+  FILE_Debug = debug;
+
+  if ( FILE_Debug )
+    Message("Debug level %d", debug);
 }
 
-void cdiCreateUUID(unsigned char uuid[CDI_UUID_SIZE]);
 
-void cdiUUID2Str(const unsigned char uuid[], char uuidstr[]);
-int cdiStr2UUID(const char *uuidstr, unsigned char uuid[]);
+void *filePtr(int fileID)
+{
+  bfile_t *fileptr;
 
-#if defined (__cplusplus)
+  fileptr = file_to_pointer(fileID);
+
+  return (fileptr);
 }
-#endif
 
-#endif
+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");
+    }
+}
 
-/*
- * 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
 
-#ifdef HAVE_CONFIG_H
-#endif
+int fileSetBufferType(int fileID, int type)
+{
+  int ret = 0;
+  bfile_t *fileptr;
 
-enum
-{ GRID      = 1,
-  ZAXIS     = 2,
-  TAXIS     = 3,
-  INSTITUTE = 4,
-  MODEL     = 5,
-  STREAM    = 6,
-  VLIST     = 7,
-  RESH_DELETE,
-  START     = 55555555,
-  END       = 99999999
-};
+  fileptr = file_to_pointer(fileID);
 
-int reshUnpackResources(char * unpackBuffer, int unpackBufferSize,
-                        void *context);
+  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);
+	}
+    }
 
+#if ! defined (HAVE_MMAP)
+  if ( type == FILE_BUFTYPE_MMAP ) ret = 1;
 #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_H
-#define _VLIST_H
+  return (ret);
+}
 
-#ifdef HAVE_CONFIG_H
-#endif
+int fileFlush(int fileID)
+{
+  bfile_t *fileptr;
+  int retval = 0;
 
-#ifndef  _ERROR_H
-#endif
+  fileptr = file_to_pointer(fileID);
 
-#include <stddef.h>  /* size_t */
+  if ( fileptr ) retval = fflush(fileptr->fp);
 
-#ifndef _CDI_LIMITS_H
-#endif
+  return (retval);
+}
 
-#define VALIDMISS 1.e+303
 
-/*
- * 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;
+void fileClearerr(int fileID)
+{
+  bfile_t *fileptr;
 
+  fileptr = file_to_pointer(fileID);
 
-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 )
+    {
+      if ( fileptr->mode != 'r' )
+	clearerr(fileptr->fp);
+    }
+}
 
 
-typedef struct
+int filePtrEOF(void *vfileptr)
 {
-  int      flag;
-  int      index;
-  int      mlevelID;
-  int      flevelID;
+  bfile_t *fileptr = (bfile_t *) vfileptr;
+  int retval = 0;
+
+  if ( fileptr ) retval = (fileptr->flag & FILE_EOF) != 0;
+
+  return (retval);
 }
-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
+
+int fileEOF(int fileID)
 {
-  int ens_index;
-  int ens_count;
-  int forecast_init_type;
+  bfile_t *fileptr;
+  int retval = 0;
+
+  fileptr = file_to_pointer(fileID);
+
+  if ( fileptr ) retval = (fileptr->flag & FILE_EOF) != 0;
+
+  return (retval);
 }
-ensinfo_t;
 
+void fileRewind(int fileID)
+{
+  fileSetPos(fileID, (off_t) 0, SEEK_SET);
+  fileClearerr(fileID);
+}
 
 
-typedef struct
+off_t fileGetPos(int fileID)
 {
-  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;
+  off_t filepos = 0;
+  bfile_t *fileptr;
 
-  int         subtypeID;   /* subtype ID for tile-related meta-data, currently for GRIB-API only. */
+  fileptr = file_to_pointer(fileID);
 
-  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 )
+    {
+      if ( fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN )
+	filepos = fileptr->position;
+      else
+	filepos = ftell(fileptr->fp);
+    }
 
+  if ( FILE_Debug ) Message("Position %ld", filepos);
 
-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;
+  return (filepos);
 }
-vlist_t;
 
 
-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);
+int fileSetPos(int fileID, off_t offset, int whence)
+{
+  int status = 0;
+  bfile_t *fileptr;
 
-int      vlistDelAtts(int vlistID, int varID);
-int      vlistCopyVarAtts(int vlistID1, int varID_1, int vlistID2, int varID_2);
+  fileptr = file_to_pointer(fileID);
 
-void     vlistUnpack(char * buffer, int bufferSize, int * pos,
-                     int originNamespace, void *context, int force_id);
+  if ( FILE_Debug ) Message("Offset %8ld  Whence %3d", (long) offset, whence);
 
-/*      vlistDefVarValidrange: Define the valid range of a Variable */
-void    vlistDefVarValidrange(int vlistID, int varID, const double *validrange);
+  if ( fileptr == 0 )
+    {
+      file_pointer_info(__func__, fileID);
+      return (1);
+    }
 
-/*      vlistInqVarValidrange: Get the valid range of a Variable */
-int     vlistInqVarValidrange(int vlistID, int varID, double *validrange);
+  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();
 
-void vlistInqVarDimorder(int vlistID, int varID, int (*outDimorder)[3]);
+	      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();
 
-int vlist_att_compare(vlist_t *a, int varIDA, vlist_t *b, int varIDB, int attnum);
+	      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 resize_opt_grib_entries(var_t *var, int nentries);
+		  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;
 
+  return (status);
+}
 
-static inline void
-vlistAdd2GridIDs(vlist_t *vlistptr, int gridID)
+static
+void file_table_print(void)
 {
-  int index, ngrids = vlistptr->ngrids;
-  for ( index = 0; index < ngrids; index++ )
-    if (vlistptr->gridIDs[index] == gridID ) break;
-  if ( index == ngrids )
+  int fileID;
+  int lprintHeader = 1;
+  bfile_t *fileptr;
+
+  for ( fileID = 0; fileID < _file_max; fileID++ )
     {
-      if (ngrids >= MAX_GRIDS_PS)
-        Error("Internal limit exceeded: more than %d grids.", MAX_GRIDS_PS);
-      ++(vlistptr->ngrids);
-      vlistptr->gridIDs[ngrids] = gridID;
+      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;
+	    }
+
+	  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");
+	    }
+
+          fprintf(stderr, " | %-51s|\n", fileptr->name);
+	}
+    }
+
+  if ( lprintHeader == 0 )
+    {
+      fprintf(stderr, "+-----+---------+");
+      fprintf(stderr, "----------------------------------------------------+\n");
     }
 }
 
-static inline void
-vlistAdd2ZaxisIDs(vlist_t *vlistptr, int zaxisID)
+
+char *fileInqName(int fileID)
 {
-  int index, nzaxis = vlistptr->nzaxis;
-  for ( index = 0; index < nzaxis; index++ )
-    if ( zaxisID == vlistptr->zaxisIDs[index] ) break;
+  bfile_t *fileptr;
+  char *name = NULL;
 
-  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++;
-    }
+  fileptr = file_to_pointer(fileID);
+
+  if ( fileptr ) name = fileptr->name;
+
+  return (name);
 }
 
-static inline void
-vlistAdd2SubtypeIDs(vlist_t *vlistptr, int subtypeID)
+
+int fileInqMode(int fileID)
 {
-  if ( subtypeID == CDI_UNDEFID ) return;
+  bfile_t *fileptr;
+  int mode = 0;
 
-  int index, nsubs = vlistptr->nsubtypes;
-  for ( index = 0; index < nsubs; index++ )
-    if (vlistptr->subtypeIDs[index] == subtypeID ) break;
-  if ( index == nsubs )
-    {
-      if (nsubs >= MAX_SUBTYPES_PS)
-        Error("Internal limit exceeded: more than %d subs.", MAX_SUBTYPES_PS);
-      ++(vlistptr->nsubtypes);
-      vlistptr->subtypeIDs[nsubs] = subtypeID;
-    }
+  fileptr = file_to_pointer(fileID);
+
+  if ( fileptr ) mode = fileptr->mode;
+
+  return (mode);
 }
 
+static
+long file_getenv(const char *envName)
+{
+  char *envString;
+  long envValue = -1;
+  long fact = 1;
 
+  envString = getenv(envName);
 
-#if  defined  (HAVE_LIBGRIB_API)
-extern int   cdiNAdditionalGRIBKeys;
-extern char* cdiAdditionalGRIBKeys[];
-#endif
+  if ( envString )
+    {
+      int loop;
 
-extern
-#ifndef __cplusplus
-const
-#endif
-resOps vlistOps;
+      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;
+	    }
+	}
 
-#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:
- */
-#if defined (HAVE_CONFIG_H)
-#endif
+      if ( fact ) envValue = fact*atol(envString);
 
-#include <assert.h>
-#include <string.h>
-#include <float.h>  /* FLT_EPSILON */
-#include <limits.h> /* INT_MAX     */
+      if ( FILE_Debug ) Message("Set %s to %ld", envName, envValue);
+    }
+
+  return (envValue);
+}
 
+static
+void file_initialize(void)
+{
+  long value;
+  char *envString;
 
-#undef  UNDEFID
-#define UNDEFID -1
+#if  defined  (HAVE_LIBPTHREAD)
+  /* initialize global API mutex lock */
+  pthread_mutex_init(&_file_mutex, NULL);
+#endif
 
-/* 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",
-};
+  value = file_getenv("FILE_DEBUG");
+  if ( value >= 0 ) FILE_Debug = (int) value;
 
-/* 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" },
+  value = file_getenv("FILE_MAX");
+  if ( value >= 0 ) _file_max = (int) value;
 
-};
+  if ( FILE_Debug )
+    Message("FILE_MAX = %d", _file_max);
 
+  FileInfo  = (int) file_getenv("FILE_INFO");
 
+  value  = file_getenv("FILE_BUFSIZE");
+  if ( value >= 0 ) FileBufferSizeEnv = value;
+  else
+    {
+      value  = file_getenv("GRIB_API_IO_BUFFER_SIZE");
+      if ( value >= 0 ) FileBufferSizeEnv = value;
+    }
 
-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 );
+  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 const resOps gridOps = {
-  gridCompareP,
-  gridDestroyP,
-  gridPrintP,
-  gridGetPackSize,
-  gridPack,
-  gridTxCode
-};
+  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);
+	}
+    }
 
-static int  GRID_Debug = 0;   /* If set to 1, debugging */
+#if defined (O_NONBLOCK)
+  FileFlagWrite = O_NONBLOCK;
+#endif
+  envString = getenv("FILE_FLAG_WRITE");
+  if ( envString )
+    {
+#if defined (O_NONBLOCK)
+      if ( strcmp(envString, "NONBLOCK") == 0 ) FileFlagWrite = O_NONBLOCK;
+#endif
+    }
+
+  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);
+	}
+    }
+
+  file_list_new();
+  atexit(file_list_delete);
 
-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)
+  FILE_LOCK();
 
+  file_init_pointer();
 
-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;
-}
+  FILE_UNLOCK();
 
+  if ( FILE_Debug ) atexit(file_table_print);
 
-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]);
+  _file_init = TRUE;
 }
 
-void grid_free(grid_t *gridptr)
+static
+void file_set_buffer(bfile_t *fileptr)
 {
-  grid_free_components(gridptr);
-  grid_init(gridptr);
-}
+  size_t buffersize = 0;
 
-static grid_t *
-gridNewEntry(cdiResH resH)
-{
-  grid_t *gridptr = (grid_t*) Malloc(sizeof(grid_t));
-  grid_init(gridptr);
-  if (resH == CDI_UNDEFID)
-    gridptr->self = reshPut(gridptr, &gridOps);
-  else
+  if ( fileptr->mode == 'r' )
     {
-      gridptr->self = resH;
-      reshReplace(resH, gridptr, &gridOps);
-    }
-  return gridptr;
-}
+      if ( FileBufferTypeEnv )
+	fileptr->bufferType = FileBufferTypeEnv;
+      else if ( fileptr->bufferType == 0 )
+	fileptr->bufferType = FILE_BUFTYPE_STD;
 
-static
-void gridInit (void)
-{
-  static int gridInitialized = 0;
-  char *env;
+      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 ( gridInitialized ) return;
+      if ( (size_t) fileptr->size < buffersize )
+	buffersize = (size_t) fileptr->size;
 
-  gridInitialized = 1;
+      if ( fileptr->bufferType == FILE_BUFTYPE_MMAP )
+	{
+	  size_t blocksize = (size_t) pagesize();
+	  size_t minblocksize = 4 * blocksize;
+	  buffersize = buffersize - buffersize % minblocksize;
 
-  env = getenv("GRID_DEBUG");
-  if ( env ) GRID_Debug = atoi(env);
-}
+	  if ( buffersize < (size_t) fileptr->size && buffersize < minblocksize )
+	    buffersize = minblocksize;
+	}
 
-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 ( 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;
+	}
+    }
 
-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;
-}
+  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!");
+        }
+    }
 
-unsigned cdiGridCount(void)
-{
-  return reshCountType(&gridOps);
-}
+  if ( fileptr->type == FILE_TYPE_FOPEN )
+    if ( setvbuf(fileptr->fp, fileptr->buffer, fileptr->buffer ? _IOFBF : _IONBF, buffersize) )
+      SysError("setvbuf failed!");
 
-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;
+  fileptr->bufferSize = buffersize;
 }
 
-static inline
-void gridGetString(char *name, const char *gridstrname, size_t len)
+static
+int file_fill_buffer(bfile_t *fileptr)
 {
-  if ( len > CDI_MAX_NAME ) len = CDI_MAX_NAME;
-  strncpy(name, gridstrname, len);
-  name[len - 1] = 0;
-}
+  ssize_t nread;
+  int fd;
+  long offset = 0;
+  off_t retseek;
 
-static inline void
-gridSetName(char *gridstrname, const char *name)
-{
-  strncpy(gridstrname, name, CDI_MAX_NAME);
-  gridstrname[CDI_MAX_NAME - 1] = 0;
-}
+  if ( FILE_Debug )
+    Message("file ptr = %p  Cnt = %ld", fileptr, fileptr->bufferCnt);
 
-void
-cdiGridTypeInit(grid_t *gridptr, int gridtype, int size)
-{
-  gridptr->type = gridtype;
-  gridptr->size = size;
+  if ( (fileptr->flag & FILE_EOF) != 0 ) return (EOF);
 
-  switch (gridtype)
+  if ( fileptr->buffer == NULL ) file_set_buffer(fileptr);
+
+  if ( fileptr->bufferSize == 0 ) return (EOF);
+
+  fd = fileptr->fd;
+
+#if defined (HAVE_MMAP)
+  if ( fileptr->bufferType == FILE_BUFTYPE_MMAP )
     {
-    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->bufferPos >= fileptr->size )
+	{
+	  nread = 0;
+	}
+      else
+	{
+          xassert(fileptr->bufferSize <= SIZE_MAX);
+	  nread = (ssize_t)fileptr->bufferSize;
+	  if ( (nread + fileptr->bufferPos) > fileptr->size )
+	    nread = fileptr->size - fileptr->bufferPos;
 
-        /*
-        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");
-          }
+	  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;
+	    }
 
-        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:
-      {
+	  fileptr->mappedSize = (size_t)nread;
 
-        /* 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;
-      }
+	  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);
+
+	  offset = fileptr->position - fileptr->bufferPos;
+	}
     }
-}
+  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);
+    }
 
-// used also in CDO
-void gridGenXvals(int xsize, double xfirst, double xlast, double xinc, double *restrict xvals)
-{
-  if ( (! (fabs(xinc) > 0)) && xsize > 1 )
+  if ( nread <= 0 )
     {
-      if ( xfirst >= xlast )
-        {
-          while ( xfirst >= xlast ) xlast += 360;
-          xinc = (xlast-xfirst)/(xsize);
-        }
+      if ( nread == 0 )
+	fileptr->flag |= FILE_EOF;
       else
-        {
-          xinc = (xlast-xfirst)/(xsize-1);
-        }
+	fileptr->flag |= FILE_ERROR;
+
+      fileptr->bufferCnt = 0;
+      return (EOF);
     }
 
-  for ( int i = 0; i < xsize; ++i )
-    xvals[i] = xfirst + i*xinc;
-}
+  fileptr->bufferPtr = fileptr->buffer;
+  fileptr->bufferCnt = (size_t)nread;
 
-static
-void calc_gaussgrid(double *restrict yvals, int ysize, double yfirst, double ylast)
-{
-  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;
+  fileptr->bufferStart = fileptr->bufferPos;
+  fileptr->bufferPos  += nread;
+  fileptr->bufferEnd   = fileptr->bufferPos - 1;
 
-  if ( yfirst < ylast && yfirst > -90.0 && ylast < 90.0 )
+  if ( FILE_Debug )
     {
-      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;
-        }
+      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);
     }
-}
-
-// used also in CDO
-void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double yinc, double *restrict yvals)
-{
-  const double deleps = 0.002;
 
-  if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
+  if ( offset > 0 )
     {
-      if ( ysize > 2 )
-	{
-	  calc_gaussgrid(yvals, ysize, yfirst, ylast);
+      if ( offset > nread )
+	Error("Internal problem with buffer handling. nread = %d offset = %d", nread, offset);
 
-	  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;
-                    }
+      fileptr->bufferPtr += offset;
+      fileptr->bufferCnt -= (size_t)offset;
+    }
 
-		    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];
-                      }
-		  }
+  fileptr->bufferNumFill++;
 
-		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;
-		  }
+  return ((unsigned char) *fileptr->bufferPtr);
+}
 
-		if ( ytmp ) Free(ytmp);
-	      }
-	}
-      else
-        {
-          yvals[0] = yfirst;
-          yvals[ysize-1] = ylast;
-        }
+static
+void file_copy_from_buffer(bfile_t *fileptr, void *ptr, size_t size)
+{
+  if ( FILE_Debug )
+    Message("size = %ld  Cnt = %ld", size, fileptr->bufferCnt);
+
+  if ( fileptr->bufferCnt < size )
+    Error("Buffer too small. bufferCnt = %d", fileptr->bufferCnt);
+
+  if ( size == 1 )
+    {
+      ((char *)ptr)[0] = fileptr->bufferPtr[0];
+
+      fileptr->bufferPtr++;
+      fileptr->bufferCnt--;
     }
-  /*     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
-            {
-              if ( ysize%2 != 0 )
-                {
-                  yinc = 180.0/(ysize-1);
-                  yfirst = -90;
-                }
-              else
-                {
-                  yinc = 180.0/ysize;
-                  yfirst = -90 + yinc/2;
-                }
-            }
-        }
-
-      if ( yfirst > ylast && yinc > 0 ) yinc = -yinc;
+      memcpy(ptr, fileptr->bufferPtr, size);
 
-      for (int i = 0; i < ysize; i++ )
-        yvals[i] = yfirst + i*yinc;
+      fileptr->bufferPtr += size;
+      fileptr->bufferCnt -= size;
     }
-  /*
-    else
-    Error("unable to calculate values for %s grid!", gridNamePtr(gridtype));
-  */
 }
 
-/*
- at Function  gridCreate
- at Title     Create a horizontal Grid
+static
+size_t file_read_from_buffer(bfile_t *fileptr, void *ptr, size_t size)
+{
+  size_t nread, rsize;
+  size_t offset = 0;
 
- 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.
+  if ( FILE_Debug )
+    Message("size = %ld  Cnt = %ld", size, (long) fileptr->bufferCnt);
 
- at Description
-The function @func{gridCreate} creates a horizontal Grid.
+  if ( ((long)fileptr->bufferCnt) < 0L )
+    Error("Internal problem. bufferCnt = %ld", (long) fileptr->bufferCnt);
 
- at Result
- at func{gridCreate} returns an identifier to the Grid.
+  rsize = size;
 
- at Example
-Here is an example using @func{gridCreate} to create a regular lon/lat Grid:
+  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;
+      else
+	rsize = 0;
 
- 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)
-{
-  if ( CDI_Debug ) Message("gridtype=%s  size=%d", gridNamePtr(gridtype), size);
+      if ( file_fill_buffer(fileptr) == EOF ) break;
+    }
 
-  if ( size < 0 || size > INT_MAX ) Error("Grid size (%d) out of bounds (0 - %d)!", size, INT_MAX);
+  nread = size - offset;
 
-  gridInit();
+  if ( fileptr->bufferCnt < nread ) nread = fileptr->bufferCnt;
 
-  grid_t *gridptr = gridNewEntry(CDI_UNDEFID);
-  if ( ! gridptr ) Error("No memory");
+  if ( nread > (unsigned) 0 )
+    file_copy_from_buffer(fileptr, (char *)ptr+offset, nread);
 
-  int gridID = gridptr->self;
+  return (nread+offset);
+}
 
-  if ( CDI_Debug ) Message("gridID: %d", gridID);
 
-  cdiGridTypeInit(gridptr, gridtype, size);
+void fileSetBufferSize(int fileID, long buffersize)
+{
+  bfile_t *fileptr = file_to_pointer(fileID);
+  xassert(buffersize >= 0);
+  if ( fileptr ) fileptr->bufferSize = (size_t)buffersize;
+}
 
-  return (gridID);
+/*
+ *   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);
 }
 
-static
-void gridDestroyKernel( grid_t * gridptr )
+int fileOpen_serial(const char *filename, const char *mode)
 {
-  int id;
+  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;
 
-  xassert ( gridptr );
+  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);
+    }
 
-  id = gridptr->self;
+  if ( FILE_Debug )
+    if ( fp == NULL && fd == -1 )
+      Message("Open failed on %s mode %c errno %d", filename, fmode, errno);
 
-  grid_free_components(gridptr);
-  Free( gridptr );
+  if ( fp )
+    {
+      if ( stat(filename, &filestat) != 0 ) return (fileID);
 
-  reshRemove ( id, &gridOps );
-}
+      fileptr = file_new_entry();
+      if ( fileptr )
+	{
+	  fileID = fileptr->self;
+	  fileptr->fp = fp;
+	}
+    }
+  else if ( fd >= 0 )
+    {
+      if ( fstat(fd, &filestat) != 0 ) return (fileID);
 
-/*
- at Function  gridDestroy
- at Title     Destroy a horizontal Grid
+      fileptr = file_new_entry();
+      if ( fileptr )
+	{
+	  fileID = fileptr->self;
+	  fileptr->fd = fd;
+	}
+    }
 
- at Prototype void gridDestroy(int gridID)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
+  if ( fileID >= 0 )
+    {
+      fileptr->mode = fmode;
+      fileptr->name = strdupx(filename);
 
- at EndFunction
-*/
-void gridDestroy(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  gridptr->vtable->destroy(gridptr);
-}
+#if defined (HAVE_STRUCT_STAT_ST_BLKSIZE)
+      fileptr->blockSize = (size_t) filestat.st_blksize;
+#else
+      fileptr->blockSize = (size_t) 4096;
+#endif
 
-void gridDestroyP ( void * gridptr )
-{
-  ((grid_t *)gridptr)->vtable->destroy((grid_t *)gridptr);
-}
+      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;
 
-const char *gridNamePtr(int gridtype)
-{
-  int size = (int) (sizeof(Grids)/sizeof(Grids[0]));
+      if ( fileptr->type == FILE_TYPE_FOPEN ) file_set_buffer(fileptr);
 
-  const char *name = gridtype >= 0 && gridtype < size ? Grids[gridtype] : Grids[GRID_GENERIC];
+      if ( FILE_Debug )
+	Message("File %s opened with ID %d", filename, fileID);
+    }
 
-  return (name);
+  return (fileID);
 }
 
-
-void gridName(int gridtype, char *gridname)
+/*
+ *   Close a file.
+ */
+int fileClose(int fileID)
 {
-  strcpy(gridname, gridNamePtr(gridtype));
+  int (*myFileClose)(int fileID)
+    = (int (*)(int))namespaceSwitchGet(NSSWITCH_FILE_CLOSE).func;
+  return myFileClose(fileID);
 }
 
-static
-char *grid_key_to_string(grid_t *gridptr, int key)
+int fileClose_serial(int fileID)
 {
-  char *gridstring = NULL;
+  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;
 
-  switch (key)
+  if ( fileptr == NULL )
     {
-    case CDI_GRID_XDIMNAME: gridstring = gridptr->xdimname; break;
-    case CDI_GRID_YDIMNAME: gridstring = gridptr->ydimname; break;
-    case CDI_GRID_VDIMNAME: gridstring = gridptr->vdimname; break;
+      file_pointer_info(__func__, fileID);
+      return (1);
     }
 
-  return gridstring;
-}
+  name = fileptr->name;
 
-/*
- at Function  cdiGridDefString
- at Title     Define a CDI grid string value from a key
+  if ( FILE_Debug )
+    Message("fileID = %d  filename = %s", fileID, name);
 
- 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
+  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]);
 
- at Description
-The function @func{cdiGridDefString} defines a CDI grid string value from a key.
+      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);
 
- at Result
- at func{cdiGridDefString} returns 0 if OK and integer value on error.
+      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);
+	}
 
- at EndFunction
-*/
-int cdiGridDefString(int gridID, int key, int size, const char *mesg)
-{
-  if ( size < 1 || mesg == NULL || *mesg == 0 ) return -1;
+      if ( fileptr->time_in_sec > 0 )
+        {
+          rout = (double)fileptr->byteTrans / (1024.*1024.*fileptr->time_in_sec);
+        }
 
-  grid_t *gridptr = gridID2Ptr(gridID);
+      fprintf(stderr, " wall time [s]    : %.2f\n", fileptr->time_in_sec);
+      fprintf(stderr, " data rate [MB/s] : %.1f\n", rout);
 
-  char *gridstring = grid_key_to_string(gridptr, key);
-  if ( gridstring == NULL)
-    {
-      Warning("CDI grid string key %d not supported!", key);
-      return -1;
+      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");
     }
 
-  gridSetString(gridstring, mesg, (size_t)size);
-  gridMark4Update(gridID);
-
-  return 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);
+    }
 
-/*
- at Function  cdiGridInqString
- at Title     Get a CDI grid string value from a key
+  if ( fileptr->name )    Free((void*) fileptr->name);
+  if ( fileptr->buffer )  Free((void*) fileptr->buffer);
 
- 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}.
+  file_delete_entry(fileptr);
 
- at Description
-The function @func{cdiGridInqString} return a CDI grid string value from a key.
+  return (0);
+}
 
- 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)
+int filePtrGetc(void *vfileptr)
 {
-  if ( size < 1 || mesg == NULL ) return -1;
+  int ivalue = EOF;
+  int fillret = 0;
+  bfile_t *fileptr = (bfile_t *) vfileptr;
 
-  grid_t *gridptr = gridID2Ptr(gridID);
-  const char *gridstring = grid_key_to_string(gridptr, key);
-  if ( gridstring == NULL)
+  if ( fileptr )
     {
-      Warning("CDI grid string key %d not supported!", key);
-      return -1;
-    }
-
-  gridGetString(mesg, gridstring, (size_t)size);
+      if ( fileptr->mode == 'r' && fileptr->type == FILE_TYPE_OPEN )
+	{
+	  if ( fileptr->bufferCnt == 0 ) fillret = file_fill_buffer(fileptr);
 
-  return 0;
-}
+	  if ( fillret >= 0 )
+	    {
+	      ivalue = (unsigned char) *fileptr->bufferPtr++;
+	      fileptr->bufferCnt--;
+	      fileptr->position++;
 
-/*
- at Function  gridDefXname
- at Title     Define the name of a X-axis
+	      fileptr->byteTrans++;
+	      fileptr->access++;
+	    }
+	}
+      else
+	{
+	  ivalue = fgetc(fileptr->fp);
+	  if ( ivalue >= 0 )
+	    {
+	      fileptr->byteTrans++;
+	      fileptr->access++;
+	    }
+	  else
+	    fileptr->flag |= FILE_EOF;
+	}
+    }
 
- 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.
+  return (ivalue);
+}
 
- at Description
-The function @func{gridDefXname} defines the name of a X-axis.
 
- at EndFunction
-*/
-void gridDefXname(int gridID, const char *xname)
+int fileGetc(int fileID)
 {
-  if ( xname && *xname )
-    {
-      grid_t *gridptr = gridID2Ptr(gridID);
-      gridSetName(gridptr->xname, xname);
-      gridMark4Update(gridID);
-    }
-}
-
-/*
- at Function  gridDefXlongname
- at Title     Define the longname of a X-axis
+  int ivalue;
+  bfile_t *fileptr;
 
- 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.
+  fileptr = file_to_pointer(fileID);
 
- at Description
-The function @func{gridDefXlongname} defines the longname of a X-axis.
+  ivalue = filePtrGetc((void *)fileptr);
 
- at EndFunction
-*/
-void gridDefXlongname(int gridID, const char *xlongname)
-{
-  if ( xlongname )
-    {
-      grid_t *gridptr = gridID2Ptr(gridID);
-      gridSetName(gridptr->xlongname, xlongname);
-      gridMark4Update(gridID);
-    }
+  return (ivalue);
 }
 
-/*
- at Function  gridDefXunits
- at Title     Define the units of a X-axis
-
- 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.
 
- at Description
-The function @func{gridDefXunits} defines the units of a X-axis.
-
- at EndFunction
-*/
-void gridDefXunits(int gridID, const char *xunits)
+size_t filePtrRead(void *vfileptr, void *restrict ptr, size_t size)
 {
-  if ( xunits )
-    {
-      grid_t *gridptr = gridID2Ptr(gridID);
-      gridSetName(gridptr->xunits, xunits);
-      gridMark4Update(gridID);
-    }
-}
+  size_t nread = 0;
+  bfile_t *fileptr = (bfile_t *) vfileptr;
 
-/*
- at Function  gridDefYname
- at Title     Define the name of a Y-axis
+  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;
+	    }
+	}
 
- 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.
+      fileptr->position  += (off_t)nread;
+      fileptr->byteTrans += (off_t)nread;
+      fileptr->access++;
+    }
 
- at Description
-The function @func{gridDefYname} defines the name of a Y-axis.
+  if ( FILE_Debug ) Message("size %ld  nread %ld", size, nread);
 
- at EndFunction
-*/
-void gridDefYname(int gridID, const char *yname)
-{
-  if ( yname && *yname )
-    {
-      grid_t *gridptr = gridID2Ptr(gridID);
-      gridSetName(gridptr->yname, yname);
-      gridMark4Update(gridID);
-    }
+  return (nread);
 }
 
-/*
- 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.
+size_t fileRead(int fileID, void *restrict ptr, size_t size)
+{
+  size_t nread = 0;
+  bfile_t *fileptr;
 
- at Description
-The function @func{gridDefYlongname} defines the longname of a Y-axis.
+  fileptr = file_to_pointer(fileID);
 
- at EndFunction
-*/
-void gridDefYlongname(int gridID, const char *ylongname)
-{
-  if ( ylongname )
+  if ( fileptr )
     {
-      grid_t *gridptr = gridID2Ptr(gridID);
-      gridSetName(gridptr->ylongname, ylongname);
-      gridMark4Update(gridID);
-    }
-}
+      double t_begin = 0.0;
 
-/*
- at Function  gridDefYunits
- at Title     Define the units of a Y-axis
+      if ( FileInfo ) t_begin = file_time();
 
- 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.
+      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;
+	    }
+	}
 
- at Description
-The function @func{gridDefYunits} defines the units of a Y-axis.
+      if ( FileInfo ) fileptr->time_in_sec += file_time() - t_begin;
 
- at EndFunction
-*/
-void gridDefYunits(int gridID, const char *yunits)
-{
-  if ( yunits )
-    {
-      grid_t *gridptr = gridID2Ptr(gridID);
-      gridSetName(gridptr->yunits, yunits);
-      gridMark4Update(gridID);
+      fileptr->position  += (off_t)nread;
+      fileptr->byteTrans += (off_t)nread;
+      fileptr->access++;
     }
-}
-
-/*
- 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}.
+  if ( FILE_Debug ) Message("size %ld  nread %ld", size, nread);
 
- at Description
-The function @func{gridInqXname} returns the name of a X-axis.
+  return (nread);
+}
 
- 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 fileWrite(int fileID, const void *restrict ptr, size_t size)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  size_t nwrite = 0;
+  bfile_t *fileptr;
 
-  strcpy(xname, gridptr->xname);
-}
+  fileptr = file_to_pointer(fileID);
 
-const char *gridInqXnamePtr(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->xname;
-}
+  if ( fileptr )
+    {
+      double t_begin = 0.0;
 
-/*
- at Function  gridInqXlongname
- at Title     Get the longname of a X-axis
+      /* if ( fileptr->buffer == NULL ) file_set_buffer(fileptr); */
 
- 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 ( FileInfo ) t_begin = file_time();
 
- at Description
-The function @func{gridInqXlongname} returns the longname of a X-axis.
+      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;
+            }
+          else
+            nwrite = (size_t)temp;
+        }
 
- at Result
- at func{gridInqXlongname} returns the longname of the X-axis to the parameter longname.
+      if ( FileInfo ) fileptr->time_in_sec += file_time() - t_begin;
 
- at EndFunction
-*/
-void gridInqXlongname(int gridID, char *xlongname)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+      fileptr->position  += (off_t)nwrite;
+      fileptr->byteTrans += (off_t)nwrite;
+      fileptr->access++;
+    }
 
-  strcpy(xlongname, gridptr->xlongname);
+  return (nwrite);
 }
-
 /*
- at Function  gridInqXunits
- at Title     Get the units of a X-axis
-
- 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}.
-
- at Description
-The function @func{gridInqXunits} returns the units of a X-axis.
-
- 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);
+ * 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
 
-  strcpy(xunits, gridptr->xunits);
-}
+#include <stdbool.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
 
-void gridInqXstdname(int gridID, char *xstdname)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  if ( gridptr->xstdname )
-    strcpy(xstdname, gridptr->xstdname);
-  else
-    xstdname[0] = 0;
+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  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}.
+ * 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 Description
-The function @func{gridInqYname} returns the name of a Y-axis.
+#include <math.h>
+#include <float.h>
+#include <stdio.h>
+#include <stdlib.h>
 
- at Result
- at func{gridInqYname} returns the name of the Y-axis to the parameter name.
 
- at EndFunction
-*/
-void gridInqYname(int gridID, char *yname)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
 
-  strcpy(yname, gridptr->yname);
-}
 
-const char *gridInqYnamePtr(int gridID)
+static
+void cpledn(size_t kn, size_t kodd, double *pfn, double pdx, int kflag,
+            double *pw, double *pdxn, double *pxmod)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->yname;
-}
+  /* 1.0 Newton iteration step */
 
-/*
- at Function  gridInqYlongname
- at Title     Get the longname of a Y-axis
+  double zdlx = pdx;
+  double zdlk = 0.0;
+  if ( kodd == 0 ) zdlk = 0.5*pfn[0];
+  double zdlxn  = 0.0;
+  double zdlldn = 0.0;
 
- 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}.
+  size_t ik = 1;
 
- at Description
-The function @func{gridInqYlongname} returns the longname of a Y-axis.
+  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;
+    }
 
- at Result
- at func{gridInqYlongname} returns the longname of the Y-axis to the parameter longname.
+  /* 2.0 Compute weights */
 
- at EndFunction
-*/
-void gridInqYlongname(int gridID, char *ylongname)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+  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);
+    }
 
-  strcpy(ylongname, gridptr->ylongname);
+  return;
 }
 
-/*
- at Function  gridInqYunits
- at Title     Get the units of a Y-axis
+static
+void gawl(double *pfn, double *pl, double *pw, size_t kn)
+{
+  double pmod = 0;
+  double zw = 0;
+  double zdlxn = 0;
 
- 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}.
+  /* 1.0 Initizialization */
 
- at Description
-The function @func{gridInqYunits} returns the units of a Y-axis.
+  int iflag  =  0;
+  int itemax = 20;
 
- at Result
- at func{gridInqYunits} returns the units of the Y-axis to the parameter units.
+  size_t iodd   = (kn % 2);
 
- at EndFunction
-*/
-void gridInqYunits(int gridID, char *yunits)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+  double zdlx   =  *pl;
 
-  strcpy(yunits, gridptr->yunits);
-}
+  /* 2.0 Newton iteration */
 
-void gridInqYstdname(int gridID, char *ystdname)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  if ( gridptr->ystdname )
-    strcpy(ystdname, gridptr->ystdname);
-  else
-    ystdname[0] = 0;
-}
+  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 Function  gridInqType
- at Title     Get the type of a Grid
+  *pl = zdlxn;
+  *pw = zw;
 
- at Prototype int gridInqType(int gridID)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+  return;
+}
 
- at Description
-The function @func{gridInqType} returns the type of a Grid.
+static
+void gauaw(size_t kn, double *restrict pl, double *restrict pw)
+{
+  /*
+   * 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));
 
- 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}.
+  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)));
+	}
 
- at EndFunction
-*/
-int gridInqType(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+      zfn[jn*(kn+1)+jn] = zfnn;
 
-  return (gridptr->type);
-}
+      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)));
+	}
+    }
 
 
-/*
- at Function  gridInqSize
- at Title     Get the size of a Grid
+  /* 2.0 Gaussian latitudes and weights */
 
- at Prototype int gridInqSize(int gridID)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+  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++;
+    }
 
- at Description
-The function @func{gridInqSize} returns the size of a Grid.
+  /*
+   * 2.1 Find first approximation of the roots of the
+   *     Legendre polynomial of degree kn.
+   */
 
- at Result
- at func{gridInqSize} returns the number of grid points of a Grid.
+  size_t ins2 = kn/2+(kn % 2);
+  double z;
 
- at EndFunction
-*/
-int gridInqSize(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+  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)));
+    }
 
-  int size = gridptr->size;
+  /* 2.2 Computes roots and weights for transformed theta */
 
-  if ( ! size )
+  for ( size_t jgl = ins2; jgl >= 1 ; jgl-- )
     {
-      int xsize, ysize;
+      size_t jglm1 = jgl-1;
+      gawl(zfnlat, &(pl[jglm1]), &(pw[jglm1]), kn);
+    }
 
-      xsize = gridptr->xsize;
-      ysize = gridptr->ysize;
+  /* convert to physical latitude */
 
-      if ( ysize )
-        size = xsize * ysize;
-      else
-        size = xsize;
+  for ( size_t jgl = 0; jgl < ins2; jgl++ )
+    {
+      pl[jgl] = cos(pl[jgl]);
+    }
 
-      gridptr->size = size;
+  for ( size_t jgl = 1; jgl <= kn/2; jgl++ )
+    {
+      size_t jglm1 = jgl-1;
+      size_t isym =  kn-jgl;
+      pl[isym] =  -pl[jglm1];
+      pw[isym] =  pw[jglm1];
     }
 
-  return (size);
+  Free(zfnlat);
+  Free(zfn);
+
+  return;
 }
 
-static
-int nsp2trunc(int nsp)
+
+void gaussaw(double *restrict pa, double *restrict pw, size_t nlat)
 {
-  /*  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);
+  //gauaw_old(pa, pw, nlat);
+  gauaw(nlat, pa, pw);
 }
 
 
-int gridInqTrunc(int gridID)
+bool isGaussGrid(size_t ysize, double yinc, const double *yvals)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  bool lgauss = false;
 
-  if ( gridptr->trunc == 0 )
+  if ( IS_EQUAL(yinc, 0) && ysize > 2 ) /* check if gaussian */
     {
-      if ( gridptr->type == GRID_SPECTRAL )
-        gridptr->trunc = nsp2trunc(gridptr->size);
-      /*
-      else if      ( gridptr->type == GRID_GAUSSIAN )
-        gridptr->trunc = nlat2trunc(gridptr->ysize);
-      */
-    }
+      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;
 
-  return (gridptr->trunc);
-}
+      for ( i = 0; i < ysize; i++ )
+        if ( fabs(yv[i] - yvals[i]) >
+             ((yv[0] - yv[1])/500) ) break;
 
+      if ( i == ysize ) lgauss = true;
 
-void gridDefTrunc(int gridID, int trunc)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+      /* 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 (gridptr->trunc != trunc)
-    {
-      gridMark4Update(gridID);
-      gridptr->trunc = trunc;
+          if ( i == ysize ) lgauss = true;
+        }
+
+      Free(yv);
     }
+
+  return lgauss;
 }
 
 /*
- 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.
+#define NGL  48
 
- at EndFunction
-*/
-void gridDefXsize(int gridID, int xsize)
+int main (int rgc, char *argv[])
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  int gridSize = gridInqSize(gridID);
-  if ( xsize > gridSize )
-    Error("xsize %d is greater then gridsize %d", xsize, gridSize);
+  int ngl = NGL;
+  double plo[NGL], pwo[NGL];
+  double pl[NGL], pw[NGL];
 
-  int gridType = gridInqType(gridID);
-  if ( gridType == GRID_UNSTRUCTURED && xsize != gridSize )
-    Error("xsize %d must be equal to gridsize %d for gridtype: UNSTRUCTURED", xsize, gridSize);
+  int i;
 
-  if (gridptr->xsize != xsize)
+  gauaw(ngl, pl, pw);
+  for (i = 0; i < ngl; i++)
     {
-      gridMark4Update(gridID);
-      gridptr->xsize = xsize;
+      pl[i]  = asin(pl[i])/M_PI*180.0;
+      plo[i] = asin(plo[i])/M_PI*180.0;
     }
 
-  if ( gridType != GRID_UNSTRUCTURED )
+  for (i = 0; i < ngl; i++)
     {
-      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);
+      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
- 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
+#if  defined  (HAVE_LIBGRIB_API)
+#  include <grib_api.h>
+#endif
 
- at EndFunction
-*/
-void gridDefPrec(int gridID, int prec)
+#include <stdio.h>
+
+
+static char gribapi_libvers[64] = "";
+#if  defined  (HAVE_LIBGRIB_API)
+static int gribapi_libvers_init;
+#endif
+
+
+void gribapiLibraryVersion(int* major_version, int* minor_version, int* revision_version)
 {
-  grid_t *gridptr = gridID2Ptr(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
+}
 
-  if (gridptr->prec != prec)
+const char *gribapiLibraryVersionString(void)
+{
+#if  defined  (HAVE_LIBGRIB_API)
+  if (!gribapi_libvers_init)
     {
-      gridMark4Update(gridID);
-      gridptr->prec = prec;
+      int major_version, minor_version, revision_version;
+
+      gribapiLibraryVersion(&major_version, &minor_version, &revision_version);
+
+      sprintf(gribapi_libvers, "%d.%d.%d", major_version, minor_version, revision_version);
+      gribapi_libvers_init = 1;
     }
-}
+#endif
 
-/*
- at Function
- at Title
+  return (gribapi_libvers);
+}
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
 
- at EndFunction
-*/
-int gridInqPrec(int gridID)
+void gribContainersNew(stream_t * streamptr)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  int editionNumber = (streamptr->filetype == FILETYPE_GRB) ? 1 : 2;
 
-  return (gridptr->prec);
-}
+#if  defined  (HAVE_LIBCGRIBEX)
+  if ( editionNumber == 1 )
+    {
+    }
+  else
+#endif
+    {
+      int nvars = streamptr->nvars;
 
-/*
- at Function  gridInqXsize
- at Title     Get the number of values of a X-axis
+#if defined (GRIBCONTAINER2D)
+      gribContainer_t **gribContainers;
+      gribContainers = (gribContainer_t **) Malloc(nvars*sizeof(gribContainer_t *));
 
- at Prototype int gridInqXsize(int gridID)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+      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{gridInqXsize} returns the number of values of a X-axis.
+          for ( int levelID = 0; levelID < nlevs; ++levelID )
+            {
+              gribContainers[varID][levelID].gribHandle = gribHandleNew(editionNumber);
+              gribContainers[varID][levelID].init = FALSE;
+            }
+	}
 
- at Result
- at func{gridInqXsize} returns the number of values of a X-axis.
+      streamptr->gribContainers = (void **) gribContainers;
+#else
+      gribContainer_t *gribContainers
+        = (gribContainer_t *) Malloc((size_t)nvars*sizeof(gribContainer_t));
 
- at EndFunction
-*/
-int gridInqXsize(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+      for ( int varID = 0; varID < nvars; ++varID )
+        {
+          gribContainers[varID].gribHandle = gribHandleNew(editionNumber);
+          gribContainers[varID].init = FALSE;
+	}
 
-  return (gridptr->xsize);
+      streamptr->gribContainers = (void *) gribContainers;
+#endif
+    }
 }
 
-/*
- at Function  gridDefYsize
- at Title     Define the number of values of a Y-axis
-
- 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.
-
- at Description
-The function @func{gridDefYsize} defines the number of values of a Y-axis.
 
- at EndFunction
-*/
-void gridDefYsize(int gridID, int ysize)
+void gribContainersDelete(stream_t * streamptr)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  if ( streamptr->gribContainers )
+    {
+      int nvars = streamptr->nvars;
 
-  int gridSize = gridInqSize(gridID);
+#if defined (GRIBCONTAINER2D)
+      gribContainer_t **gribContainers = (gribContainer_t **) streamptr->gribContainers;
 
-  if ( ysize > gridSize )
-    Error("ysize %d is greater then gridsize %d", ysize, gridSize);
+      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;
 
-  if ( gridInqType(gridID) == GRID_UNSTRUCTURED && ysize != gridSize )
-    Error("ysize %d must be equal gridsize %d for gridtype: UNSTRUCTURED", ysize, gridSize);
+      for ( int varID = 0; varID < nvars; ++varID )
+	{
+          gribHandleDelete(gribContainers[varID].gribHandle);
+	}
+#endif
 
-  if (gridptr->ysize != ysize)
-    {
-      gridMark4Update(gridID);
-      gridptr->ysize = ysize;
-    }
+      Free(gribContainers);
 
-  if ( gridInqType(gridID) != GRID_UNSTRUCTURED )
-    {
-      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);
+      streamptr->gribContainers = NULL;
     }
 }
-
 /*
- at Function  gridInqYsize
- at Title     Get the number of values of a Y-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 int gridInqYsize(int gridID)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+#ifdef HAVE_LIBGRIB_API
 
- 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.
+#include <grib_api.h>
 
- at EndFunction
-*/
-int gridInqYsize(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+#include <stdbool.h>
+
+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);
+
+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.
+
+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
 
-  return (gridptr->ysize);
-}
+#endif
 
 /*
- at Function  gridDefNP
- at Title     Define the number of parallels between a pole and the equator
+ * 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 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.
+#ifdef HAVE_LIBGRIB_API
 
- at Description
-The function @func{gridDefNP} defines the number of parallels between a pole and the equator
-of a Gaussian grid.
 
- at EndFunction
-*/
-void gridDefNP(int gridID, int np)
+
+#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)
+
+//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);
+  char* result = NULL;
+  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);
 
-  if (gridptr->np != np)
+    else
+      {
+          Free(result);
+          result = 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)
     {
-      gridMark4Update(gridID);
-      gridptr->np = np;
+      if (length <= 1024UL * 1024UL)
+        {
+          length *= 2;
+          result = Realloc(result, length);
+        }
+      else
+        break;
+    }
+  if (!rc)
+    result = Realloc(result, length);
+  else
+    {
+      Free(result);
+      result = NULL;
     }
+#endif
+  return result;
 }
 
-/*
- at Function  gridInqNP
- at Title     Get the number of parallels between a pole and the equator
-
- 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.
-
- at Result
- at func{gridInqNP} returns the number of parallels between a pole and the equator.
-
- at EndFunction
-*/
-int gridInqNP(int gridID)
+//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);
-
-  return (gridptr->np);
+  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;
 }
 
-/*
- at Function
- at Title
-
- at Prototype
- at Parameter
-    @Item  Grid identifier
-
- at EndFunction
-*/
-void gridDefRowlon(int gridID, int nrowlon, const int rowlon[])
+//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);
-
-  gridptr->rowlon = (int *) Malloc((size_t)nrowlon * sizeof(int));
-  gridptr->nrowlon = nrowlon;
-  memcpy(gridptr->rowlon, rowlon, (size_t)nrowlon * sizeof(int));
-  gridMark4Update(gridID);
+  long value;
+  if(grib_get_long(gribHandle, key, &value)) return false;
+  return value == expectedValue;
 }
 
-/*
- at Function
- at Title
-
- at Prototype
- at Parameter
-    @Item  Grid identifier
-
- at EndFunction
-*/
-void gridInqRowlon(int gridID, int *rowlon)
+//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)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  if ( gridptr->rowlon == 0 )  Error("undefined pointer!");
+  long result;
+  FAIL_ON_GRIB_ERROR(grib_get_long, gh, key, &result);
+  return result;
+}
 
-  memcpy(rowlon, gridptr->rowlon, (size_t)gridptr->nrowlon * sizeof(int));
+//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;
 }
 
-static int
-gridInqMaskSerialGeneric(grid_t *gridptr, mask_t **internalMask,
-                        int *restrict mask)
+//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)
 {
-  long size = gridptr->size;
+  double result;
+  FAIL_ON_GRIB_ERROR(grib_get_double, gh, key, &result);
+  return result;
+}
 
-  if ( CDI_Debug && size == 0 )
-    Warning("Size undefined for gridID = %d", gridptr->self);
+//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;
+}
 
-  const mask_t *restrict mask_src = *internalMask;
-  if (mask_src)
-    {
-      if (mask && size > 0)
-        for (size_t i = 0; i < (size_t)size; ++i)
-          mask[i] = (int)mask_src[i];
-    }
-  else
-    size = 0;
+//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;
+}
 
-  return (int)size;
+//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);
 }
 
-static int
-gridInqMaskSerial(grid_t *gridptr, int *mask)
+//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)
 {
-  return gridInqMaskSerialGeneric(gridptr, &gridptr->mask, mask);
+  size_t valueCount = gribGetArraySize(gribHandle, key);
+  FAIL_ON_GRIB_ERROR(grib_get_long_array, gribHandle, key, array, &valueCount);
 }
 
 
-int gridInqMask(int gridID, int *mask)
+//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 gridptr->vtable->inqMask(gridptr, mask);
+  return gribGetLong(gh, "editionNumber");
 }
 
-static void
-gridDefMaskSerial(grid_t *gridptr, const int *mask)
+//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()
 {
-  long size = gridptr->size;
-
-  if ( size == 0 )
-    Error("Size undefined for gridID = %d", gridptr->self);
+  char* temp = getenv("TZ"), *result = NULL;
+  if(temp) result = strdup(temp);
+  setenv("TZ", "UTC", 1);
+  return result;
+}
 
-  if ( mask == NULL )
+//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)
+{
+  if(savedTz)
     {
-      if ( gridptr->mask )
-	{
-	  Free(gridptr->mask);
-	  gridptr->mask = NULL;
-	}
+      setenv("TZ", savedTz, 1);
+      Free(savedTz);
     }
   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);
+      unsetenv("TZ");
     }
 }
 
-void gridDefMask(int gridID, const int *mask)
+//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)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  gridptr->vtable->defMask(gridptr, mask);
-  gridMark4Update(gridID);
+  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;
 }
 
-static int
-gridInqMaskGMESerial(grid_t *gridptr, int *mask_gme)
+//Returns zero on success.
+static int addSecondsToDate(struct tm* me, long long amount)
 {
-  return gridInqMaskSerialGeneric(gridptr, &gridptr->mask_gme, mask_gme);
+  //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);
 }
 
-int gridInqMaskGME(int gridID, int *mask)
+static void addMonthsToDate(struct tm* me, long long amount)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqMaskGME(gridptr, mask);
+  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;
 }
 
-static void
-gridDefMaskGMESerial(grid_t *gridptr, const int *mask)
+//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)
 {
-  long size = gridptr->size;
+  switch(unit)
+    {
+      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 ( size == 0 )
-    Error("Size undefined for gridID = %d", gridptr->self);
+      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
 
-  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!");
+      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
 
-  for (long i = 0; i < size; ++i)
-    gridptr->mask_gme[i] = (mask_t)(mask[i] != 0);
+      default: return 1;        //reserved, unknown, or missing
+    }
 }
 
-void gridDefMaskGME(int gridID, const int *mask)
+static char* makeDateString(struct tm* me)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  gridptr->vtable->defMaskGME(gridptr, mask);
-  gridMark4Update(gridID);
+  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;
 }
 
-
-static int
-gridInqXValsSerial(grid_t *gridptr, double *xvals)
+//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)
 {
-  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;
+  switch(gribGetLong(gh, "productDefinitionTemplateNumber"))
+    {
+      case 20: case 30: case 31: case 254: case 311: case 2000:
+        *outHaveForecastTime = false, *outHaveTimeRange = false;
+        return 0;
 
-  if ( CDI_Debug && size == 0 )
-    Warning("size undefined for gridID = %d", gridptr->self);
+      //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;
 
-  if ( gridptr->xvals )
-    {
-      if ( size && xvals )
-        {
-          const double *gridptr_xvals = gridptr->vtable->inqXValsPtr(gridptr);
-          memcpy(xvals, gridptr_xvals, (size_t)size * sizeof (double));
-        }
+      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;
+
+      default:
+        return 1;
     }
-  else
-    size = 0;
-  return (int)size;
 }
 
-/*
- at Function  gridInqXvals
- at Title     Get all values of a X-axis
 
- 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.
+char* gribMakeTimeString(grib_handle* gh, CdiTimeType timeType)
+{
+  //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");
 
- at Description
-The function @func{gridInqXvals} returns all values of the X-axis.
+  if(gribEditionNumber(gh) == 1)
+    {
+      date.tm_year = (int)gribGetLong(gh, "yearOfCentury");  //years are -1900 based both in struct tm and GRIB1
+    }
+  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");
 
- 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.
+      //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
 
- at EndFunction
-*/
-int gridInqXvals(int gridID, double *xvals)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqXVals(gridptr, xvals);
+          //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;
+                }
+            }
+        }
+    }
+
+  //Bake the date into a string.
+  return makeDateString(&date);
 }
 
 
-static void
-gridDefXValsSerial(grid_t *gridptr, const double *xvals)
+int gribapiTimeIsFC(grib_handle *gh)
 {
-  int gridtype = gridptr->type;
-
-  long size;
-  if ( gridtype == GRID_UNSTRUCTURED || gridtype == GRID_CURVILINEAR )
-    size = gridptr->size;
-  else if ( gridtype == GRID_GAUSSIAN_REDUCED )
-    size = 2;
-  else
-    size = gridptr->xsize;
-
-  if ( size == 0 )
-    Error("Size undefined for gridID = %d", gridptr->self);
+  if (gribEditionNumber(gh) <= 1) return true;
 
-  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));
+  long sigofrtime;
+  FAIL_ON_GRIB_ERROR(grib_get_long, gh, "significanceOfReferenceTime", &sigofrtime);
+  return sigofrtime != 3;
 }
 
-/*
- at Function  gridDefXvals
- at Title     Define the values of a X-axis
+//Fetches the value of the "stepType" key and converts it into a constant in the TSTEP_* range.
+int gribapiGetTsteptype(grib_handle *gh)
+{
+  int tsteptype = TSTEP_INSTANT;
+  static bool lprint = true;
 
- 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.
+  if ( gribapiTimeIsFC(gh) )
+    {
+      int status;
+      size_t len = 256;
+      char stepType[256];
 
- at Description
-The function @func{gridDefXvals} defines all values of the X-axis.
+      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;
+            }
 
- at EndFunction
-*/
-void gridDefXvals(int gridID, const double *xvals)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  gridptr->vtable->defXVals(gridptr, xvals);
-  gridMark4Update(gridID);
+          // printf("stepType: %s %ld %d\n", stepType, len, tsteptype);
+        }
+    }
+
+  return tsteptype;
 }
 
-static int
-gridInqYValsSerial(grid_t *gridptr, double *yvals)
+
+int gribGetDatatype(grib_handle* gribHandle)
 {
-  int gridtype = gridptr->type;
-  long size
-    = (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
-    ? gridptr->size : gridptr->ysize;
+  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;
+}
 
-  if ( CDI_Debug && size == 0 )
-    Warning("size undefined for gridID = %d!", gridptr->self);
 
-  if ( gridptr->yvals )
+int gribapiGetParam(grib_handle *gh)
+{
+  long pdis, pcat, pnum;
+  if ( gribEditionNumber(gh) <= 1 )
     {
-      if ( size && yvals )
-        {
-          const double *gridptr_yvals = gridptr->vtable->inqYValsPtr(gridptr);
-          memcpy(yvals, gridptr_yvals, (size_t)size * sizeof (double));
-        }
+      pdis = 255;
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "table2Version", &pcat);
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "indicatorOfParameter", &pnum);
     }
   else
-    size = 0;
-
-  return (int)size;
+    {
+      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  gridInqYvals
- at Title     Get all values of a Y-axis
-
- 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.
 
- at Description
-The function @func{gridInqYvals} returns all values of the Y-axis.
+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 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.
+  return gridtype;
+}
 
- at EndFunction
-*/
-int gridInqYvals(int gridID, double *yvals)
+static
+int gribapiGetIsRotated(grib_handle *gh)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqYVals(gridptr, yvals);
+  return gribGetLongDefault(gh, "gridDefinitionTemplateNumber", -1) == GRIB2_GTYPE_LATLON_ROT;
 }
 
-static void
-gridDefYValsSerial(grid_t *gridptr, const double *yvals)
+//TODO: Simplify by use of the convenience functions (gribGetLong(), gribGetLongDefault(), etc.).
+void gribapiGetGrid(grib_handle *gh, grid_t *grid)
 {
-  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);
-
-  if (gridptr->yvals && CDI_Debug)
-    Warning("Values already defined!");
+  long editionNumber = gribEditionNumber(gh);
+  int gridtype = gribapiGetGridType(gh);
+  int projtype = (gridtype == GRID_PROJECTION && gribapiGetIsRotated(gh)) ? CDI_PROJ_RLL : CDI_UNDEFID;
+  /*
+  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);
 
-  gridptr->yvals = (double *)Realloc(gridptr->yvals, (size_t)size * sizeof (double));
-  memcpy(gridptr->yvals, yvals, (size_t)size * sizeof (double));
-}
+  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;
 
-/*
- at Function  gridDefYvals
- at Title     Define the values of a Y-axis
+  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);
 
- 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.
+      if ( gridtype == GRID_GAUSSIAN )
+        {
+          FAIL_ON_GRIB_ERROR(grib_get_long, gh, "numberOfParallelsBetweenAPoleAndTheEquator", &lpar);
+          grid->np = (int)lpar;
+        }
 
- at Description
-The function @func{gridDefYvals} defines all values of the Y-axis.
+      if ( numberOfPoints != nlon*nlat )
+        Error("numberOfPoints (%ld) and gridSize (%ld) differ!", numberOfPoints, nlon*nlat);
+
+      grid->size  = (int)numberOfPoints;
+      grid->x.size = (int)nlon;
+      grid->y.size = (int)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);
+
+      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 ( grid->y.inc > 0 && grid->y.first > grid->y.last ) grid->y.inc = -grid->y.inc;
+
+      /* 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 EndFunction
-*/
-void gridDefYvals(int gridID, const double *yvals)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  gridptr->vtable->defYVals(gridptr, yvals);
-  gridMark4Update(gridID);
-}
+            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;
 
-static double
-gridInqXValSerial(grid_t *gridptr, int index)
-{
-  double xval = gridptr->xvals ? gridptr->xvals[index] : 0;
-  return xval;
-}
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Nj", &lpar);
+      int nlat = (int)lpar;
 
+      grid->size   = (int)numberOfPoints;
 
-double gridInqXval(int gridID, int index)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqXVal(gridptr, index);
-}
+      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);
 
-static double
-gridInqYValSerial(grid_t *gridptr, int index)
-{
-  double yval = gridptr->yvals ? gridptr->yvals[index] : 0;
-  return yval;
-}
+      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);
 
-/*
- at Function
- at Title
+      // 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 Prototype
- at Parameter
-    @Item  Grid identifier
+      /* 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 EndFunction
-*/
-double gridInqYval(int gridID, int index)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqYVal(gridptr, index);
-}
+            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_LCC )
+    {
+      int nlon, nlat;
+      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;
 
-/*
- at Function
- at Title
+      if ( numberOfPoints != nlon*nlat )
+        Error("numberOfPoints (%d) and gridSize (%d) differ!", (int)numberOfPoints, nlon*nlat);
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
+      grid->size  = (int)numberOfPoints;
+      grid->x.size = nlon;
+      grid->y.size = nlat;
 
- at EndFunction
-*/
-double gridInqXinc(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  double xinc = gridptr->xinc;
-  const double *restrict xvals = gridptr->vtable->inqXValsPtr(gridptr);
+      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 ( (! (fabs(xinc) > 0)) && xvals )
-    {
-      int xsize = gridptr->xsize;
-      if ( xsize > 1 )
+      if ( editionNumber <= 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;
+          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;
         }
+
+      grid->x.flag = 0;
+      grid->y.flag = 0;
     }
+  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;
 
-  return xinc;
-}
+      grid->size  = (int)datasize;
 
-/*
- at Function
- at Title
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "J", &lpar);
+      grid->trunc = (int)lpar;
+    }
+  else if ( gridtype == GRID_GME )
+    {
+      grid->size  = (int)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 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  = (int)numberOfPoints;
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
+      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 )
+    {
+      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;
 
- at EndFunction
-*/
-double gridInqYinc(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  double yinc = gridptr->yinc;
-  const double *yvals = gridptr->vtable->inqYValsPtr(gridptr);
+      grid->size  = (int)numberOfPoints;
 
-  if ( (! (fabs(yinc) > 0)) && yvals )
-    {
-      int ysize = gridptr->ysize;
-      if ( ysize > 1 )
+      if ( nlon > 0 && nlat > 0 && nlon*nlat == grid->size )
         {
-          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;
-              }
-
-          gridptr->yinc = yinc;
+          grid->x.size = nlon;
+          grid->y.size = nlat;
         }
+      else
+        {
+          grid->x.size = 0;
+          grid->y.size = 0;
+        }
+    }
+  else
+    {
+      Error("Unsupported grid type: %s", gridNamePtr(gridtype));
     }
 
-  return yinc;
+  grid->type  = gridtype;
+  grid->projtype  = projtype;
 }
-
+#endif
 /*
- at Function
- at Title
-
- at Prototype
- at Parameter
-    @Item  Grid identifier
+ * 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
 
- at EndFunction
-*/
-double gridInqXpole(int gridID)
-{
-  // Xpole -> grid_north_pole_longitude
-  grid_t *gridptr = gridID2Ptr(gridID);
+#if defined (HAVE_CONFIG_H)
+#endif
 
-  return gridptr->xpole;
-}
 
-/*
- at Function
- at Title
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
+#ifdef __cplusplus
+extern "C" {
+#endif
 
- at EndFunction
-*/
-void gridDefXpole(int gridID, double xpole)
+static inline int cdiUUIDIsNull(const unsigned char uuid[])
 {
-  // Xpole -> grid_north_pole_longitude
-  grid_t *gridptr = gridID2Ptr(gridID);
+  int isNull = 1;
+  for (size_t i = 0; i < CDI_UUID_SIZE; ++i)
+    isNull &= (uuid[i] == 0);
+  return isNull;
+}
 
-  if ( gridptr->xstdname && memcmp(gridptr->xstdname, "grid", 4) != 0 )
-    gridptr->xstdname = xystdname_tab[grid_xystdname_grid_latlon][0];
+void cdiCreateUUID(unsigned char uuid[CDI_UUID_SIZE]);
 
-  if ( gridptr->isRotated != TRUE || IS_NOT_EQUAL(gridptr->xpole, xpole) )
-    {
-      gridptr->isRotated = TRUE;
-      gridptr->xpole = xpole;
-      gridMark4Update(gridID);
-    }
+void cdiUUID2Str(const unsigned char uuid[], char uuidstr[]);
+int cdiStr2UUID(const char *uuidstr, unsigned char uuid[]);
+
+#if defined (__cplusplus)
 }
+#endif
+
+#endif
 
 /*
- 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:
+ */
+#ifndef RESOURCE_UNPACK_H
+#define RESOURCE_UNPACK_H
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
+#ifdef HAVE_CONFIG_H
+#endif
 
- at EndFunction
-*/
-double gridInqYpole(int gridID)
-{
-  // Ypole -> grid_north_pole_latitude
-  grid_t *gridptr = gridID2Ptr(gridID);
+enum
+{ GRID      = 1,
+  ZAXIS     = 2,
+  TAXIS     = 3,
+  INSTITUTE = 4,
+  MODEL     = 5,
+  STREAM    = 6,
+  VLIST     = 7,
+  RESH_DELETE,
+  START     = 55555555,
+  END       = 99999999
+};
 
-  return (gridptr->ypole);
-}
+int reshUnpackResources(char * unpackBuffer, int unpackBufferSize,
+                        void *context);
+
+#endif
 
 /*
- 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:
+ */
+#ifndef _VLIST_H
+#define _VLIST_H
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
+#ifdef HAVE_CONFIG_H
+#endif
 
- at EndFunction
-*/
-void gridDefYpole(int gridID, double ypole)
-{
-  // Ypole -> grid_north_pole_latitude
-  grid_t *gridptr = gridID2Ptr(gridID);
+#ifndef  _ERROR_H
+#endif
 
-  if ( gridptr->ystdname && memcmp(gridptr->ystdname, "grid", 4) != 0 )
-    gridptr->ystdname = xystdname_tab[grid_xystdname_grid_latlon][1];
+#include <stddef.h>  /* size_t */
 
-  if ( gridptr->isRotated != TRUE || IS_NOT_EQUAL(gridptr->ypole, ypole) )
-    {
-      gridptr->isRotated = TRUE;
-      gridptr->ypole = ypole;
-      gridMark4Update(gridID);
-    }
-}
+#ifndef _CDI_LIMITS_H
+#endif
 
-/*
- at Function
- at Title
+#define VALIDMISS 1.e+303
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
 
- at EndFunction
-*/
-double gridInqAngle(int gridID)
+typedef struct
 {
-  // Angle -> north_pole_grid_longitude
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  return (gridptr->angle);
+  int      flag;
+  int      index;
+  int      mlevelID;
+  int      flevelID;
 }
+levinfo_t;
 
+#define DEFAULT_LEVINFO(levID) \
+  (levinfo_t){ 0, -1, levID, levID}
 /*
- at Function
- at Title
-
- at Prototype
- at Parameter
-    @Item  Grid identifier
-
- at EndFunction<
+#define DEFAULT_LEVINFO(levID) \
+  (levinfo_t){ .flag = 0, .index = -1, .flevelID = levID, .mlevelID = levID}
 */
-void gridDefAngle(int gridID, double angle)
+typedef struct
 {
-  // Angle -> north_pole_grid_longitude
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  if ( gridptr->isRotated != TRUE || IS_NOT_EQUAL(gridptr->angle, angle) )
-    {
-      gridptr->isRotated = TRUE;
-      gridptr->angle = angle;
-      gridMark4Update(gridID);
-    }
+  int ens_index;
+  int ens_count;
+  int forecast_init_type;
 }
+ensinfo_t;
 
-/*
- at Function
- at Title
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
 
- at EndFunction
-*/
-int gridInqGMEnd(int gridID)
+typedef struct
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  bool        isUsed;
+  int         flag;
+  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;
 
-  return (gridptr->nd);
-}
+  int         subtypeID;   /* subtype ID for tile-related meta-data, currently for GRIB-API only. */
 
-/*
- at Function
- at Title
+  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 Prototype
- at Parameter
-    @Item  Grid identifier
 
- at EndFunction
-*/
-void gridDefGMEnd(int gridID, int nd)
+typedef struct
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  if (gridptr->nd != nd)
-    {
-      gridptr->nd = nd;
-      gridMark4Update(gridID);
-    }
+  //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;
 
-/*
- at Function
- at Title
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
+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);
+
+int      cdiDelAtts(int vlistID, int varID);
+int      cdiCopyVarAtts(int vlistID1, int varID_1, int vlistID2, int varID_2);
 
- at EndFunction
-*/
-int gridInqGMEni(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+void     vlistUnpack(char * buffer, int bufferSize, int * pos,
+                     int originNamespace, void *context, int force_id);
 
-  return (gridptr->ni);
-}
+/*      vlistDefVarValidrange: Define the valid range of a Variable */
+void    vlistDefVarValidrange(int vlistID, int varID, const double *validrange);
 
-/*
- at Function
- at Title
+/*      vlistInqVarValidrange: Get the valid range of a Variable */
+int     vlistInqVarValidrange(int vlistID, int varID, double *validrange);
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
+void vlistInqVarDimorder(int vlistID, int varID, int (*outDimorder)[3]);
 
- at EndFunction
-*/
-void gridDefGMEni(int gridID, int ni)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+int cdi_att_compare(vlist_t *a, int varIDA, vlist_t *b, int varIDB, int attnum);
 
-  if (gridptr->ni != ni)
-    {
-      gridptr->ni = ni;
-      gridMark4Update(gridID);
-    }
-}
+void resize_opt_grib_entries(var_t *var, int nentries);
 
-/*
- at Function
- at Title
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
 
- at EndFunction
-*/
-int gridInqGMEni2(int gridID)
+static inline
+void vlistAdd2GridIDs(vlist_t *vlistptr, int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  int index, ngrids = vlistptr->ngrids;
+  for ( index = 0; index < ngrids; index++ )
+    {
+      if ( vlistptr->gridIDs[index] == gridID ) break;
+      //      if ( gridIsEqual(vlistptr->gridIDs[index], gridID) ) break;
+    }
 
-  return (gridptr->ni2);
+  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
-
- at Prototype
- at Parameter
-    @Item  Grid identifier
-
- at EndFunction
-*/
-void gridDefGMEni2(int gridID, int ni2)
+static inline
+void vlistAdd2ZaxisIDs(vlist_t *vlistptr, int zaxisID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  int index, nzaxis = vlistptr->nzaxis;
+  for ( index = 0; index < nzaxis; index++ )
+    if ( zaxisID == vlistptr->zaxisIDs[index] ) break;
 
-  if (gridptr->ni2 != ni2)
+  if ( index == nzaxis )
     {
-      gridptr->ni2 = ni2;
-      gridMark4Update(gridID);
+      if ( nzaxis >= MAX_ZAXES_PS )
+	Error("Internal limit exceeded: more than %d zaxis.", MAX_ZAXES_PS);
+      vlistptr->zaxisIDs[nzaxis] = zaxisID;
+      ++(vlistptr->nzaxis);
     }
 }
 
-/*
- at Function
- at Title
-
- at Prototype
- at Parameter
-    @Item  Grid identifier
-
- at EndFunction
-*/
-int gridInqGMEni3(int gridID)
+static inline
+void vlistAdd2SubtypeIDs(vlist_t *vlistptr, int subtypeID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  return (gridptr->ni3);
-}
+  if ( subtypeID == CDI_UNDEFID ) return;
 
-void gridDefGMEni3(int gridID, int ni3)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+  int index, nsubs = vlistptr->nsubtypes;
+  for ( index = 0; index < nsubs; index++ )
+    if ( vlistptr->subtypeIDs[index] == subtypeID ) break;
 
-  if (gridptr->ni3 != ni3)
+  if ( index == nsubs )
     {
-      gridptr->ni3 = ni3;
-      gridMark4Update(gridID);
+      if ( nsubs >= MAX_SUBTYPES_PS )
+        Error("Internal limit exceeded: more than %d subs.", MAX_SUBTYPES_PS);
+      vlistptr->subtypeIDs[nsubs] = subtypeID;
+      ++(vlistptr->nsubtypes);
     }
 }
 
-/*
- at Function
- at Title
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
 
- at EndFunction
-*/
-void gridChangeType(int gridID, int gridtype)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+#if  defined  (HAVE_LIBGRIB_API)
+extern int   cdiNAdditionalGRIBKeys;
+extern char* cdiAdditionalGRIBKeys[];
+#endif
 
-  if ( CDI_Debug )
-    Message("Changed grid type from %s to %s", gridNamePtr(gridptr->type), gridNamePtr(gridtype));
+extern
+#ifndef __cplusplus
+const
+#endif
+resOps vlistOps;
 
-  if (gridptr->type != gridtype)
-    {
-      gridptr->type = gridtype;
-      gridMark4Update(gridID);
-    }
-}
+#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:
+ */
+#if defined (HAVE_CONFIG_H)
+#endif
 
-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);
+#include <assert.h>
+#include <string.h>
+#include <float.h>  /* FLT_EPSILON */
+#include <limits.h> /* INT_MAX     */
 
-  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);
 
-          double x0 = 2*xvals[xsize-1]-xvals[xsize-2]-360;
+#undef  CDI_UNDEFID
+#define CDI_UNDEFID -1
 
-          if ( IS_NOT_EQUAL(xvals[0], xvals[xsize-1]) )
-            if ( fabs(x0 - xvals[0]) < 0.01*xinc ) gridptr->isCyclic = TRUE;
-        }
-    }
-  else if ( gridptr->type == GRID_CURVILINEAR )
-    {
-      if ( 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];
+/* 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",
+};
 
-              double xinc = fabs(val2-val1);
+/* 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" },
 
-	      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);
 
-              nc += fabs(x0-val1) < 0.5*xinc;
-            }
-          gridptr->isCyclic = nc > ysize/2 ? TRUE : FALSE;
-        }
 
-      if ( xbounds && xsize > 1 )
-	{
-          short 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];
+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 );
 
-		      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;
+static const resOps gridOps = {
+  gridCompareP,
+  gridDestroyP,
+  gridPrintP,
+  gridGetPackSize,
+  gridPack,
+  gridTxCode
+};
 
-		      if ( fabs(val1-val2) < 0.001 )
-                        goto foundCloseVertices;
-		    }
-		}
-              /* all vertices more than 0.001 degrees apart */
-              isCyclic = FALSE;
-              break;
-              foundCloseVertices:
-              ;
-	    }
-          gridptr->isCyclic = isCyclic;
-	}
-    }
+static int  GRID_Debug = 0;   /* If set to 1, debugging */
+
+grid_t *grid_to_pointer(int gridID)
+{
+  return (grid_t *)reshGetVal(gridID, &gridOps);
 }
+#define grid_to_pointer(gridID) (grid_t *)reshGetVal(gridID, &gridOps)
+#define gridMark4Update(gridID) reshSetStatus(gridID, &gridOps, RESH_DESYNC_IN_USE)
 
 
-int gridIsCircular(int gridID)
+void grid_init(grid_t *gridptr)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  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->y.vals        = NULL;
+  gridptr->x.bounds      = NULL;
+  gridptr->y.bounds      = NULL;
+  gridptr->area          = NULL;
+  gridptr->rowlon        = NULL;
+  gridptr->nrowlon       = 0;
 
-  if ( gridptr->isCyclic == CDI_UNDEFID ) grid_check_cyclic(gridptr);
+  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;
+
+  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->gme.nd        = 0;
+  gridptr->gme.ni        = 0;
+  gridptr->gme.ni2       = 0;
+  gridptr->gme.ni3       = 0;
+
+  gridptr->trunc         = 0;
+  gridptr->nvertex       = 0;
+  gridptr->number        = 0;
+  gridptr->position      = 0;
+  gridptr->reference     = NULL;
+  gridptr->prec          = 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;
 
-  return ( gridptr->isCyclic );
+  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;
 }
 
 
-int gridIsRotated(int gridID)
+static
+void grid_free_components(grid_t *gridptr)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  void *p2free[] = { gridptr->mask, gridptr->mask_gme,
+                     gridptr->x.vals, gridptr->y.vals,
+                     gridptr->x.bounds, gridptr->y.bounds,
+                     gridptr->rowlon, gridptr->area,
+                     gridptr->reference, gridptr->name};
 
-  return ( gridptr->isRotated );
+  for ( size_t i = 0; i < sizeof(p2free)/sizeof(p2free[0]); ++i )
+    if ( p2free[i] ) Free(p2free[i]);
 }
 
-static
-int compareXYvals(grid_t *gridRef, grid_t *gridTest)
+void grid_free(grid_t *gridptr)
 {
-  int differ = 0;
-
-  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);
+  grid_free_components(gridptr);
+  grid_init(gridptr);
+}
 
-      for ( size_t i = 0; i < (size_t)xsizeTest; ++i )
-	if ( fabs(xvalsTest[i] - xvalsRef[i]) > 1.e-10 )
-	  {
-	    differ = 1;
-	    break;
-	  }
-    }
+static
+grid_t *gridNewEntry(cdiResH resH)
+{
+  grid_t *gridptr = (grid_t*) Malloc(sizeof(grid_t));
+  grid_init(gridptr);
 
-  if ( !differ && ysizeTest > 0 && ysizeTest == gridRef->vtable->inqYVals(gridRef, NULL) )
+  if ( resH == CDI_UNDEFID )
+    gridptr->self = reshPut(gridptr, &gridOps);
+  else
     {
-      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 = 1;
-	    break;
-	  }
+      gridptr->self = resH;
+      reshReplace(resH, gridptr, &gridOps);
     }
 
-  return (differ);
+  return gridptr;
 }
 
 static
-int compareXYvals2(grid_t *gridRef, grid_t *gridTest)
+void gridInit(void)
 {
-  int gridsize = gridTest->size;
-  int 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;
-
-  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;
-
-  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;
+  static bool gridInitialized = false;
+  if ( gridInitialized ) return;
+  gridInitialized = true;
 
-  return differ;
+  const char *env = getenv("GRID_DEBUG");
+  if ( env ) GRID_Debug = atoi(env);
 }
 
-
-int gridCompare(int gridID, const grid_t *grid)
+static
+void grid_copy_base_scalar_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
 {
-  int differ = 1;
-  grid_t *gridRef = gridID2Ptr(gridID);
-
-  if ( grid->type == gridRef->type || grid->type == GRID_GENERIC )
-    {
-      if ( grid->size == gridRef->size )
-	{
-	  differ = 0;
-	  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 == grid->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 = 1;
-			    }
-			  if ( !differ && fabs(grid->xinc) > 0 &&
-			       fabs(fabs(grid->xinc) - fabs(gridRef->xinc)) > fabs(grid->xinc/1000))
-			    {
-			      differ = 1;
-			    }
-			  if ( !differ && fabs(grid->yinc) > 0 &&
-			       fabs(fabs(grid->yinc) - fabs(gridRef->yinc)) > fabs(grid->yinc/1000))
-			    {
-			      differ = 1;
-			    }
-			}
-		    }
-		  else if ( grid->xvals && grid->yvals )
-                    differ = gridRef->vtable->compareXYFull(gridRef, (grid_t *)grid);
-		}
-	      else
-		differ = 1;
-	    }
-	  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 = 1;
-	    }
-	  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 = 1;
-			  }
-		    }
-		  else if ( grid->xvals && grid->yvals )
-                    differ = gridRef->vtable->compareXYFull(gridRef, (grid_t *)grid);
-		}
-	      else
-		differ = 1;
-	    }
-	  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 );
-
-              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);
-                }
-              }
-	}
-    }
-
-  return differ;
+  memcpy(gridptrDup, gridptrOrig, sizeof(grid_t));
+  gridptrDup->self = CDI_UNDEFID;
+  if ( gridptrOrig->reference )
+    gridptrDup->reference = strdupx(gridptrOrig->reference);
 }
 
 
-int gridCompareP ( void * gridptr1, void * gridptr2 )
+static
+grid_t *grid_copy_base(grid_t *gridptrOrig)
 {
-  grid_t * g1 = ( grid_t * ) gridptr1;
-  grid_t * g2 = ( grid_t * ) gridptr2;
-  enum { equal = 0,
-         differ = -1 };
-  int i, size;
-
-  xassert ( g1 );
-  xassert ( g2 );
-
-  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;
-
-  if ( g1->rowlon )
-    {
-      for ( i = 0; i < g1->nrowlon; i++ )
-	if ( g1->rowlon[i] != g2->rowlon[i] ) return differ;
-    }
-  else if ( g2->rowlon )
-    return differ;
+  grid_t *gridptrDup = (grid_t *)Malloc(sizeof (*gridptrDup));
+  gridptrOrig->vtable->copyScalarFields(gridptrOrig, gridptrDup);
+  gridptrOrig->vtable->copyArrayFields(gridptrOrig, gridptrDup);
+  return gridptrDup;
+}
 
-  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;
+unsigned cdiGridCount(void)
+{
+  return reshCountType(&gridOps);
+}
 
-  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 );
+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 ( !g2_xvals ) return differ;
+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;
+}
 
-      for ( i = 0; i < size; i++ )
-        if ( IS_NOT_EQUAL(g1_xvals[i], g2_xvals[i]) ) return differ;
-    }
-  else if ( g2_xvals )
-    return differ;
+static inline
+void gridSetName(char *gridstrname, const char *name)
+{
+  strncpy(gridstrname, name, CDI_MAX_NAME);
+  gridstrname[CDI_MAX_NAME - 1] = 0;
+}
 
-  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 );
 
-      if ( !g2_yvals ) return differ;
+void cdiGridTypeInit(grid_t *gridptr, int gridtype, int size)
+{
+  gridptr->type = gridtype;
+  gridptr->size = size;
 
-      for ( i = 0; i < size; i++ )
-        if ( IS_NOT_EQUAL(g1_yvals[i], g2_yvals[i]) ) return differ;
-    }
-  else if ( g2_yvals )
-    return differ;
+  if      ( gridtype == GRID_CURVILINEAR  ) gridptr->nvertex = 4;
+  else if ( gridtype == GRID_UNSTRUCTURED ) gridptr->x.size = size;
 
-  const double *restrict g1_area = g1->vtable->inqAreaPtr(g1),
-    *restrict g2_area = g2->vtable->inqAreaPtr(g2);
-  if ( g1_area )
+  switch (gridtype)
     {
-      xassert ( g1->size );
-
-      if ( !g2_area ) return differ;
-
-      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;
-
-  {
-    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;
+    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] == 0 ) gridSetName(gridptr->x.name, "tlon");
+            if ( gridptr->y.name[0] == 0 ) gridSetName(gridptr->y.name, "tlat");
+          }
         else
-          size = g1->nvertex * g1->xsize;
-        xassert ( size );
+          {
+            if ( gridptr->x.name[0] == 0 ) gridSetName(gridptr->x.name, "lon");
+            if ( gridptr->y.name[0] == 0 ) gridSetName(gridptr->y.name, "lat");
+          }
 
-        if ( !(g2_xbounds = g2->vtable->inqXBoundsPtr(g2)) ) return differ;
+        gridSetName(gridptr->x.longname, "longitude");
+        gridSetName(gridptr->y.longname, "latitude");
 
-        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;
-  }
+        gridptr->x.stdname = xystdname_tab[grid_xystdname_latlon][0];
+        gridptr->y.stdname = xystdname_tab[grid_xystdname_latlon][1];
+        gridSetName(gridptr->x.units, "degrees_east");
+        gridSetName(gridptr->y.units, "degrees_north");
 
-  {
-    const double *restrict g1_ybounds, *restrict g2_ybounds;
-    if ( (g1_ybounds = g1->vtable->inqYBoundsPtr(g1)) )
+        break;
+      }
+    case GRID_GENERIC:
+    case GRID_PROJECTION:
       {
-        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 );
-
-        if ( ! (g2_ybounds = g2->vtable->inqYBoundsPtr(g2)) ) return differ;
+        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");
 
-        for ( i = 0; i < size; i++ )
-          if ( IS_NOT_EQUAL(g1->ybounds[i], g2->ybounds[i]) ) return differ;
+            gridptr->x.stdname = xystdname_tab[grid_xystdname_projection][0];
+            gridptr->y.stdname = xystdname_tab[grid_xystdname_projection][1];
+            gridSetName(gridptr->x.units, "m");
+            gridSetName(gridptr->y.units, "m");
+          }
+        break;
       }
-    else if ( g2->vtable->inqYBoundsPtr(g2) )
-      return differ;
-  }
+    }
+}
 
-  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;
 
-  if ( g1->reference )
+// used also in CDO
+void gridGenXvals(int xsize, double xfirst, double xlast, double xinc, double *restrict xvals)
+{
+  if ( (! (fabs(xinc) > 0)) && xsize > 1 )
     {
-      if ( !g2->reference ) return differ;
-      if ( strcmp(g1->reference, g2->reference) ) return differ;
+      if ( xfirst >= xlast )
+        {
+          while ( xfirst >= xlast ) xlast += 360;
+          xinc = (xlast-xfirst)/(xsize);
+        }
+      else
+        {
+          xinc = (xlast-xfirst)/(xsize-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;
+  for ( int i = 0; i < xsize; ++i )
+    xvals[i] = xfirst + i*xinc;
+}
 
-  if ( g1->mask_gme )
+static
+void calc_gaussgrid(double *restrict yvals, int ysize, double yfirst, double ylast)
+{
+  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;
+
+  if ( yfirst < ylast && yfirst > -90.0 && ylast < 90.0 )
     {
-      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;
+      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;
+        }
     }
-  else if ( g2->mask_gme )
-    return differ;
-
-  if (memcmp(g1->uuid, g2->uuid, CDI_UUID_SIZE))
-    return differ;
-
-  return equal;
 }
 
-static void gridComplete(grid_t *grid)
+// used also in CDO
+void gridGenYvals(int gridtype, int ysize, double yfirst, double ylast, double yinc, double *restrict yvals)
 {
-  int gridID = grid->self;
-  gridDefPrec(gridID, grid->prec);
+  const double deleps = 0.002;
 
-  int gridtype = grid->type;
-  switch (gridtype)
+  if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
     {
-    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);
-
-        if ( gridtype == GRID_GAUSSIAN ) gridDefNP(gridID, grid->np);
+      if ( ysize > 2 )
+	{
+	  calc_gaussgrid(yvals, ysize, yfirst, ylast);
 
-	if ( grid->nvertex > 0 )
-	  gridDefNvertex(gridID, grid->nvertex);
+	  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;
+                    }
 
-	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);
-	    */
-	  }
+		    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];
+                      }
+		  }
 
-	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);
-	    */
-	  }
+		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 ( 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);
-	  }
+		if ( ytmp ) Free(ytmp);
+	      }
+	}
+      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;
 
-        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:
+          if ( yfirst > ylast )
+            yinc = (yfirst-ylast)/(ysize-1);
+          else if ( yfirst < ylast )
+            yinc = (ylast-yfirst)/(ysize-1);
+          else
             {
-              int number = grid->number;
-              int position = grid->position >= 0 ? grid->position : 0;
-              if ( number > 0 )
+              if ( ysize%2 != 0 )
+                {
+                  yinc = 180.0/(ysize-1);
+                  yfirst = -90;
+                }
+              else
                 {
-                  gridDefNumber(gridID, number);
-                  gridDefPosition(gridID, position);
+                  yinc = 180.0/ysize;
+                  yfirst = -90 + yinc/2;
                 }
             }
-            break;
-	  }
-
-	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);
-          }
+      if ( yfirst > ylast && yinc > 0 ) yinc = -yinc;
 
-        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;
-      }
+      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
 
-  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 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.
 
-}
+ at Description
+The function @func{gridCreate} creates a horizontal Grid.
 
-#define GRID_STR_SERIALIZE(gridP) { gridP->xdimname, gridP->ydimname,  \
-    gridP->vdimname, gridP->xname, gridP->yname,  \
-    gridP->xlongname, gridP->ylongname, \
-    gridP->xunits, gridP->yunits }
+ at Result
+ at func{gridCreate} returns an identifier to the Grid.
 
-int gridGenerate(const grid_t *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)
 {
-  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);
+  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);
+
+  gridInit();
+
+  grid_t *gridptr = gridNewEntry(CDI_UNDEFID);
+  if ( ! gridptr ) Error("No memory");
+
+  int gridID = gridptr->self;
+
+  if ( CDI_Debug ) Message("gridID: %d", gridID);
+
+  cdiGridTypeInit(gridptr, gridtype, size);
+
+  return gridID;
 }
 
-static void
-grid_copy_base_array_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
+static
+void gridDestroyKernel( grid_t * gridptr )
 {
-  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));
-    }
+  xassert ( gridptr );
 
-  if ( gridptrOrig->xvals != NULL )
-    {
-      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->xsize;
+  int id = gridptr->self;
 
-      gridptrDup->xvals = (double *)Malloc(size * sizeof (double));
-      memcpy(gridptrDup->xvals, gridptrOrig->xvals, size * sizeof (double));
-    }
+  grid_free_components(gridptr);
+  Free( gridptr );
 
-  if ( gridptrOrig->yvals != NULL )
-    {
-      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->ysize;
+  reshRemove ( id, &gridOps );
+}
 
-      gridptrDup->yvals = (double *)Malloc(size * sizeof (double));
-      memcpy(gridptrDup->yvals, gridptrOrig->yvals, size * sizeof (double));
-    }
+/*
+ at Function  gridDestroy
+ at Title     Destroy a horizontal Grid
 
-  if ( gridptrOrig->xbounds != NULL )
-    {
-      size_t size  = (irregular ? gridsize : (size_t)gridptrOrig->xsize)
-        * (size_t)gridptrOrig->nvertex;
+ at Prototype void gridDestroy(int gridID)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
 
-      gridptrDup->xbounds = (double *)Malloc(size * sizeof (double));
-      memcpy(gridptrDup->xbounds, gridptrOrig->xbounds, size * sizeof (double));
-    }
+ at EndFunction
+*/
+void gridDestroy(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->vtable->destroy(gridptr);
+}
 
-  if ( gridptrOrig->ybounds != NULL )
-    {
-      size_t size = (irregular ? gridsize : (size_t)gridptrOrig->ysize)
-        * (size_t)gridptrOrig->nvertex;
 
-      gridptrDup->ybounds = (double *)Malloc(size * sizeof (double));
-      memcpy(gridptrDup->ybounds, gridptrOrig->ybounds, size * sizeof (double));
-    }
+void gridDestroyP ( void * gridptr )
+{
+  ((grid_t *)gridptr)->vtable->destroy((grid_t *)gridptr);
+}
 
-  {
-    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));
-      }
-  }
+const char *gridNamePtr(int gridtype)
+{
+  int size = (int) (sizeof(Grids)/sizeof(Grids[0]));
 
-  if ( gridptrOrig->mask != NULL )
-    {
-      size_t size = gridsize;
+  const char *name = gridtype >= 0 && gridtype < size ? Grids[gridtype] : Grids[GRID_GENERIC];
 
-      gridptrDup->mask = (mask_t *)Malloc(size * sizeof(mask_t));
-      memcpy(gridptrDup->mask, gridptrOrig->mask, size * sizeof (mask_t));
-    }
+  return name;
+}
 
-  if ( gridptrOrig->mask_gme != NULL )
-    {
-      size_t size = gridsize;
 
-      gridptrDup->mask_gme = (mask_t *)Malloc(size * sizeof (mask_t));
-      memcpy(gridptrDup->mask_gme, gridptrOrig->mask_gme, size * sizeof(mask_t));
+void gridName(int gridtype, char *gridname)
+{
+  strcpy(gridname, gridNamePtr(gridtype));
+}
+
+static
+void *grid_key_to_ptr(grid_t *gridptr, int key)
+{
+  void *keyptr = NULL;
+
+  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_MAPNAME:    keyptr = (void*)gridptr->mapname; break;
+    case CDI_KEY_MAPPING:    keyptr = (void*)gridptr->mapping; break;
     }
 
+  return keyptr;
 }
 
-
 /*
- at Function  gridDuplicate
- at Title     Duplicate a horizontal Grid
+ at Function  cdiGridDefKeyStr
+ at Title     Define a CDI grid string value from a key
 
- at Prototype int gridDuplicate(int gridID)
+ at Prototype int cdiGridDefKeyStr(int gridID, int key, int size, const char *mesg)
 @Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+    @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
 
 @Description
-The function @func{gridDuplicate} duplicates a horizontal Grid.
+The function @func{cdiGridDefKeyStr} defines a CDI grid string value from a key.
 
 @Result
- at func{gridDuplicate} returns an identifier to the duplicated Grid.
+ at func{cdiGridDefKeyStr} returns 0 if OK and integer value on error.
 
 @EndFunction
 */
-int gridDuplicate(int gridID)
+int cdiGridDefKeyStr(int gridID, int key, int size, const char *mesg)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  grid_t *gridptrnew = gridptr->vtable->copy(gridptr);
-  int gridIDnew = reshPut(gridptrnew, &gridOps);
-  gridptrnew->self = gridIDnew;
-  return (gridIDnew);
-}
-
+  if ( size < 1 || mesg == NULL || *mesg == 0 ) return -1;
 
-void gridCompress(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  int gridtype = gridInqType(gridID);
-  if ( gridtype == GRID_UNSTRUCTURED )
+  char *keyptr = (char*)grid_key_to_ptr(gridptr, key);
+  if ( keyptr == NULL )
     {
-      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);
-
-	  /* 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;
+      Warning("CDI grid string key %d not supported!", key);
+      return -1;
+    }
 
-          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));
+  gridSetString(keyptr, mesg, (size_t)size);
+  gridMark4Update(gridID);
 
-	  Free(gridptr->mask_gme);
-	  gridptr->mask_gme = NULL;
-          gridMark4Update(gridID);
-	}
-    }
-  else
-    Warning("Unsupported grid type: %s", gridNamePtr(gridtype));
+  return 0;
 }
 
-static void
-gridDefAreaSerial(grid_t *gridptr, const double *area)
-{
-  size_t size = (size_t)gridptr->size;
+/*
+ at Function  cdiGridInqKeyStr
+ at Title     Get a CDI grid string value from a key
+
+ 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}.
+
+ at Description
+The function @func{cdiGridInqKeyStr} return a CDI grid string value from a key.
 
-  if ( size == 0 )
-    Error("size undefined for gridID = %d", gridptr->self);
+ at Result
+ at func{cdiGridInqKeyStr} returns 0 if OK and integer value on error.
 
-  if ( gridptr->area == NULL )
-    gridptr->area = (double *) Malloc(size*sizeof(double));
-  else if ( CDI_Debug )
-    Warning("values already defined!");
+ at EndFunction
+*/
+int cdiGridInqKeyStr(int gridID, int key, int size, char *mesg)
+{
+  if ( size < 1 || mesg == NULL ) return -1;
 
-  memcpy(gridptr->area, area, size * sizeof(double));
-}
+  grid_t *gridptr = grid_to_pointer(gridID);
+  const char *keyptr = (const char*)grid_key_to_ptr(gridptr, key);
+  if ( keyptr == NULL)
+    {
+      Warning("CDI grid string key %d not supported!", key);
+      return -1;
+    }
 
+  gridGetString(mesg, keyptr, (size_t)size);
 
-void gridDefArea(int gridID, const double *area)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  gridptr->vtable->defArea(gridptr, area);
-  gridMark4Update(gridID);
+  return 0;
 }
 
-static void
-gridInqAreaSerial(grid_t *gridptr, double *area)
-{
-  if (gridptr->area)
-    memcpy(area, gridptr->area, (size_t)gridptr->size * sizeof (double));
-}
+/*
+ at Function  gridDefXname
+ at Title     Define the name of a X-axis
 
+ 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.
 
-void gridInqArea(int gridID, double *area)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  gridptr->vtable->inqArea(gridptr, area);
-}
+ at Description
+The function @func{gridDefXname} defines the name of a X-axis.
 
-static int
-gridHasAreaBase(grid_t *gridptr)
+ at EndFunction
+*/
+void gridDefXname(int gridID, const char *xname)
 {
-  return gridptr->area != NULL;
+  (void)cdiGridDefKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, xname);
 }
 
-int gridHasArea(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->hasArea(gridptr);
-}
+/*
+ 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.
 
-static const double *gridInqAreaPtrBase(grid_t *gridptr)
+ at EndFunction
+*/
+void gridDefXlongname(int gridID, const char *xlongname)
 {
-  return gridptr->area;
+  (void)cdiGridDefKeyStr(gridID, CDI_KEY_XLONGNAME, CDI_MAX_NAME, xlongname);
 }
 
-const double *gridInqAreaPtr(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqAreaPtr(gridptr);
-}
+/*
+ at Function  gridDefXunits
+ at Title     Define the units of a X-axis
 
+ 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.
 
-void gridDefNvertex(int gridID, int nvertex)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+ at Description
+The function @func{gridDefXunits} defines the units of a X-axis.
 
-  if (gridptr->nvertex != nvertex)
-    {
-      gridptr->nvertex = nvertex;
-      gridMark4Update(gridID);
-    }
+ at EndFunction
+*/
+void gridDefXunits(int gridID, const char *xunits)
+{
+  (void)cdiGridDefKeyStr(gridID, CDI_KEY_XUNITS, CDI_MAX_NAME, xunits);
 }
 
+/*
+ at Function  gridDefYname
+ at Title     Define the name of a Y-axis
 
-int gridInqNvertex(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+ 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.
 
-  return (gridptr->nvertex);
-}
+ at Description
+The function @func{gridDefYname} defines the name of a Y-axis.
 
-static void
-gridDefBoundsGeneric(grid_t *gridptr, const double *bounds, int regularSize,
-                     double **field)
+ at EndFunction
+*/
+void gridDefYname(int gridID, const char *yname)
 {
-  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 * (size_t)(irregular ? gridptr->size : regularSize);
-  if ( size == 0 )
-    Error("size undefined for gridID = %d", gridptr->self);
+  (void)cdiGridDefKeyStr(gridID, CDI_KEY_YNAME, CDI_MAX_NAME, yname);
+}
 
-  if (*field == NULL)
-    *field = (double *)Malloc(size * sizeof (double));
-  else if ( CDI_Debug )
-    Warning("values already defined!");
+/*
+ at Function  gridDefYlongname
+ at Title     Define the longname of a Y-axis
 
-  memcpy(*field, bounds, size * sizeof (double));
-}
+ 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.
 
+ at Description
+The function @func{gridDefYlongname} defines the longname of a Y-axis.
 
-static void
-gridDefXBoundsSerial(grid_t *gridptr, const double *xbounds)
+ at EndFunction
+*/
+void gridDefYlongname(int gridID, const char *ylongname)
 {
-  gridDefBoundsGeneric(gridptr, xbounds, gridptr->xsize, &gridptr->xbounds);
+  (void)cdiGridDefKeyStr(gridID, CDI_KEY_YLONGNAME, CDI_MAX_NAME, ylongname);
 }
 
 /*
- at Function  gridDefXbounds
- at Title     Define the bounds of a X-axis
+ at Function  gridDefYunits
+ at Title     Define the units of a Y-axis
 
- at Prototype void gridDefXbounds(int gridID, const double *xbounds)
+ at Prototype void gridDefYunits(int gridID, const char *units)
 @Parameter
     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  xbounds  X-bounds of the grid.
+    @Item  units    Units of the Y-axis.
 
 @Description
-The function @func{gridDefXbounds} defines all bounds of the X-axis.
+The function @func{gridDefYunits} defines the units of a Y-axis.
 
 @EndFunction
 */
-void gridDefXbounds(int gridID, const double *xbounds)
+void gridDefYunits(int gridID, const char *yunits)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  gridptr->vtable->defXBounds(gridptr, xbounds);
-  gridMark4Update(gridID);
+  (void)cdiGridDefKeyStr(gridID, CDI_KEY_YUNITS, CDI_MAX_NAME, yunits);
 }
 
-static int
-gridInqXBoundsSerial(grid_t *gridptr, double *xbounds)
-{
-  size_t nvertex = (size_t)gridptr->nvertex;
+/*
+ at Function  gridInqXname
+ at Title     Get the name of a X-axis
 
-  int irregular = gridptr->type == GRID_CURVILINEAR
-    || gridptr->type == GRID_UNSTRUCTURED;
-  size_t size = nvertex * (size_t)(irregular ? gridptr->size : gridptr->xsize);
+ 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}.
 
-  const double *gridptr_xbounds = gridptr->vtable->inqXBoundsPtr(gridptr);
-  if ( gridptr_xbounds )
-    {
-      if ( size && xbounds )
-        memcpy(xbounds, gridptr_xbounds, size * sizeof (double));
-    }
-  else
-    size = 0;
+ 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.
 
-  return ((int)size);
+ at EndFunction
+*/
+void gridInqXname(int gridID, char *xname)
+{
+  (void)cdiGridInqKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, xname);
 }
 
 /*
- at Function  gridInqXbounds
- at Title     Get the bounds of a X-axis
+ at Function  gridInqXlongname
+ at Title     Get the longname of a X-axis
 
- at Prototype int gridInqXbounds(int gridID, double *xbounds)
+ at Prototype void gridInqXlongname(int gridID, char *longname)
 @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.
+    @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}.
 
 @Description
-The function @func{gridInqXbounds} returns the bounds of the X-axis.
+The function @func{gridInqXlongname} returns the longname of a X-axis.
 
 @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 func{gridInqXlongname} returns the longname of the X-axis to the parameter longname.
 
 @EndFunction
 */
-int gridInqXbounds(int gridID, double *xbounds)
+void gridInqXlongname(int gridID, char *xlongname)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqXBounds(gridptr, xbounds);
+  (void)cdiGridInqKeyStr(gridID, CDI_KEY_XLONGNAME, CDI_MAX_NAME, xlongname);
 }
 
-static const double *
-gridInqXBoundsPtrSerial(grid_t *gridptr)
-{
-  return gridptr->xbounds;
-}
+/*
+ at Function  gridInqXunits
+ at Title     Get the units of a X-axis
+
+ 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}.
 
+ at Description
+The function @func{gridInqXunits} returns the units of a X-axis.
 
-const double *gridInqXboundsPtr(int gridID)
+ 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);
-  return gridptr->vtable->inqXBoundsPtr(gridptr);
+  (void)cdiGridInqKeyStr(gridID, CDI_KEY_XUNITS, CDI_MAX_NAME, xunits);
 }
 
-static void
-gridDefYBoundsSerial(grid_t *gridptr, const double *ybounds)
+
+void gridInqXstdname(int gridID, char *xstdname)
 {
-  gridDefBoundsGeneric(gridptr, ybounds, gridptr->ysize, &gridptr->ybounds);
+  grid_t *gridptr = grid_to_pointer(gridID);
+  if ( gridptr->x.stdname )
+    strcpy(xstdname, gridptr->x.stdname);
+  else
+    xstdname[0] = 0;
 }
 
 /*
- at Function  gridDefYbounds
- at Title     Define the bounds of a Y-axis
+ at Function  gridInqYname
+ at Title     Get the name of a Y-axis
 
- at Prototype void gridDefYbounds(int gridID, const double *ybounds)
+ at Prototype void gridInqYname(int gridID, char *name)
 @Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  ybounds  Y-bounds of the grid.
+    @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}.
 
 @Description
-The function @func{gridDefYbounds} defines all bounds of the Y-axis.
+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.
 
 @EndFunction
 */
-void gridDefYbounds(int gridID, const double *ybounds)
+void gridInqYname(int gridID, char *yname)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  gridptr->vtable->defYBounds(gridptr, ybounds);
-  gridMark4Update(gridID);
+  (void)cdiGridInqKeyStr(gridID, CDI_KEY_YNAME, CDI_MAX_NAME, yname);
 }
 
-static int
-gridInqYBoundsSerial(grid_t *gridptr, double *ybounds)
-{
-  size_t nvertex = (size_t)gridptr->nvertex;
+/*
+ at Function  gridInqYlongname
+ at Title     Get the longname of a Y-axis
 
-  int irregular = gridptr->type == GRID_CURVILINEAR
-    || gridptr->type == GRID_UNSTRUCTURED;
-  size_t size = nvertex * (size_t)(irregular ? gridptr->size : gridptr->ysize);
+ 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}.
 
-  const double *gridptr_ybounds = gridptr->vtable->inqYBoundsPtr(gridptr);
-  if ( gridptr_ybounds )
-    {
-      if ( size && ybounds )
-        memcpy(ybounds, gridptr_ybounds, size * sizeof (double));
-    }
-  else
-    size = 0;
+ at Description
+The function @func{gridInqYlongname} returns the longname of a Y-axis.
 
-  return ((int)size);
-}
+ 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  gridInqYbounds
- at Title     Get the bounds of a Y-axis
+ at Function  gridInqYunits
+ at Title     Get the units of a Y-axis
 
- at Prototype int gridInqYbounds(int gridID, double *ybounds)
+ at Prototype void gridInqYunits(int gridID, char *units)
 @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.
+    @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{gridInqYbounds} returns the bounds of the Y-axis.
+The function @func{gridInqYunits} returns the units 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{gridInqYunits} returns the units of the Y-axis to the parameter units.
 
 @EndFunction
 */
-int gridInqYbounds(int gridID, double *ybounds)
+void gridInqYunits(int gridID, char *yunits)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqYBounds(gridptr, ybounds);
+  (void)cdiGridInqKeyStr(gridID, CDI_KEY_YUNITS, CDI_MAX_NAME, yunits);
 }
 
-static const double *
-gridInqYBoundsPtrSerial(grid_t *gridptr)
+
+void gridInqYstdname(int gridID, char *ystdname)
 {
-  return gridptr->ybounds;
+  grid_t *gridptr = grid_to_pointer(gridID);
+  if ( gridptr->y.stdname )
+    strcpy(ystdname, gridptr->y.stdname);
+  else
+    ystdname[0] = 0;
 }
 
 
-const double *gridInqYboundsPtr(int gridID)
+void gridDefProj(int gridID, int projID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqYBoundsPtr(gridptr);
-}
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->proj = projID;
 
-static void
-printDblsPrefixAutoBrk(FILE *fp, 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 ( gridptr->type == GRID_CURVILINEAR )
     {
-      if ( nbyte > 80 )
-        {
-          fprintf(fp, "\n%*s", (int)nbyte0, "");
-          nbyte = nbyte0;
-        }
-      nbyte += (size_t)fprintf(fp, "%.9g ", vals[i]);
+      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);
     }
-  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++ )
-    {
-      if ( nbyte > 80 )
-        {
-          fprintf(fp, "\n%*s", (int)nbyte0, "");
-          nbyte = nbyte0;
-        }
-      nbyte += (size_t)fprintf(fp, "%d ", vals[i]);
-    }
-  fputs("\n", fp);
-}
 
-static void
-printBounds(FILE *fp, const char prefix[], size_t nbyte0,
-            size_t n, size_t nvertex, const double bounds[])
+int gridInqProj(int gridID)
 {
-  fputs(prefix, fp);
-  if ( n > 0 )
-    {
-      for ( size_t iv = 0; iv < nvertex; iv++ )
-        fprintf(fp, "%.9g ", 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, "%.9g ", bounds[i*nvertex+iv]);
-        }
-      fputs("\n", fp);
-    }
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->proj;
 }
 
-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 ( nbyte > 80 )
-        {
-          fprintf(fp, "\n%*s", (int)nbyte0, "");
-          nbyte = nbyte0;
-        }
-      nbyte += (size_t)fprintf(fp, "%d ", (int)mask[i]);
-    }
-  fputs("\n", fp);
-}
 
-static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
+int gridInqProjType(int gridID)
 {
-  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);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  fprintf(fp, "#\n"
-          "# gridID %d\n"
-          "#\n"
-          "gridtype  = %s\n"
-          "gridsize  = %d\n", index, gridNamePtr(type), gridsize);
+  int projtype = gridptr->projtype;
 
-  if ( type != GRID_GME )
+  if ( projtype == -1 )
     {
-      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 )
+      char mapping[CDI_MAX_NAME]; mapping[0] = 0;
+      cdiGridInqKeyStr(gridID, CDI_KEY_MAPPING, CDI_MAX_NAME, mapping);
+      if ( mapping[0] )
         {
-          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      ( 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;
+
+          gridptr->projtype = projtype;
         }
-      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;
-	  }
+  return projtype;
+}
 
-	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);
-              }
-          }
+void gridVerifyProj(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-	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", a, lon_0, lat_0);
-	  }
+  int projtype = gridInqProjType(gridID);
 
-	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",
-                    a, lon_0, lat_0, lat_1, lat_2);
-	  }
+  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");
+    }
+}
 
-	if ( gridptr->isRotated )
-	  {
-	    if ( xsize > 0 ) fprintf(fp, "xnpole    = %g\n", gridptr->xpole);
-	    if ( ysize > 0 ) fprintf(fp, "ynpole    = %g\n", gridptr->ypole);
-	    if ( IS_NOT_EQUAL(gridptr->angle, 0) ) fprintf(fp, "angle     = %g\n", gridptr->angle);
- 	  }
+/*
+ at Function  gridInqType
+ at Title     Get the type of a Grid
 
-	if ( xvals )
-	  {
-	    double xfirst = 0.0, xinc = 0.0;
+ at Prototype int gridInqType(int gridID)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
 
-	    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 Description
+The function @func{gridInqType} returns the type of a Grid.
 
-	    if ( IS_NOT_EQUAL(xinc, 0) && opt )
-	      {
-                fprintf(fp, "xfirst    = %g\n"
-                        "xinc      = %g\n", xfirst, xinc);
-	      }
-	    else
-	      {
-                static const char prefix[] = "xvals     = ";
-                printDblsPrefixAutoBrk(fp, prefix, sizeof (prefix),
-                                       (size_t)(xdim > 0 ? xdim : 0), xvals);
-	      }
-	  }
+ 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}.
 
-	if ( xbounds )
-	  {
-            static const char prefix[] = "xbounds   = ";
-            printBounds(fp, prefix, sizeof (prefix),
-                        (size_t)(xdim > 0 ? xdim : 0),
-                        (size_t)(nvertex > 0 ? nvertex : 0), xbounds);
-	  }
+ at EndFunction
+*/
+int gridInqType(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-	if ( yvals )
-	  {
-	    double yfirst = 0.0, yinc = 0.0;
+  return gridptr->type;
+}
 
-	    if ( type == GRID_LONLAT || type == GRID_GENERIC || type == GRID_LCC2 ||
-		 type == GRID_SINUSOIDAL || type == GRID_LAEA )
-	      {
-		yfirst = gridInqYval(gridID, 0);
-		yinc   = gridInqYinc(gridID);
-	      }
 
-	    if ( IS_NOT_EQUAL(yinc, 0) && opt )
-	      {
-	  	fprintf(fp, "yfirst    = %g\n"
-                        "yinc      = %g\n", yfirst, yinc);
-	      }
-	    else
-	      {
-                static const char prefix[] = "yvals     = ";
-                printDblsPrefixAutoBrk(fp, prefix, sizeof (prefix),
-                                       (size_t)(ydim > 0 ? ydim : 0), yvals);
-	      }
-	  }
+/*
+ at Function  gridInqSize
+ at Title     Get the size of a Grid
 
-	if ( ybounds )
-	  {
-            static const char prefix[] = "ybounds   = ";
-            printBounds(fp, prefix, sizeof (prefix),
-                        (size_t)(ydim > 0 ? ydim : 0),
-                        (size_t)(nvertex > 0 ? nvertex : 0), ybounds);
-	  }
+ at Prototype int gridInqSize(int gridID)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
 
-	if ( area )
-	  {
-            static const char prefix[] = "area      = ";
-            printDblsPrefixAutoBrk(fp, prefix, sizeof (prefix),
-                                   (size_t)(gridsize > 0 ? gridsize : 0), area);
-	  }
+ at Description
+The function @func{gridInqSize} returns the size of a Grid.
 
-        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),
-                                   (size_t)(ysize > 0 ? ysize : 0), rowlon);
-            Free(rowlon);
-          }
+ at Result
+ at func{gridInqSize} returns the number of grid points of a Grid.
 
-	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);
+ at EndFunction
+*/
+int gridInqSize(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-	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, originLon, originLat, lonParY, lat1, lat2,
-                xincm, 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;
-      }
-    }
+  int size = gridptr->size;
 
-  gridInqUUID(gridID, uuidOfHGrid);
-  if ( !cdiUUIDIsNull(uuidOfHGrid) )
+  if ( size == 0 )
     {
-      char uuidOfHGridStr[37];
-      cdiUUID2Str(uuidOfHGrid, uuidOfHGridStr);
-      if ( uuidOfHGridStr[0] != 0 && strlen(uuidOfHGridStr) == 36 )
-        fprintf(fp, "uuid      = %s\n", uuidOfHGridStr);
+      int xsize = gridptr->x.size;
+      int ysize = gridptr->y.size;
+
+      if ( ysize )
+        size = xsize * ysize;
+      else
+        size = xsize;
+
+      gridptr->size = size;
     }
 
-  if ( gridptr->mask )
+  return size;
+}
+
+static
+int nsp2trunc(int nsp)
+{
+  /*  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;
+}
+
+
+int gridInqTrunc(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+
+  if ( gridptr->trunc == 0 )
     {
-      static const char prefix[] = "mask      = ";
-      printMask(fp, prefix, sizeof (prefix),
-                (size_t)(gridsize > 0 ? gridsize : 0), gridptr->mask);
+      if ( gridptr->type == GRID_SPECTRAL )
+        gridptr->trunc = nsp2trunc(gridptr->size);
+      /*
+      else if      ( gridptr->type == GRID_GAUSSIAN )
+        gridptr->trunc = nlat2trunc(gridptr->y.size);
+      */
     }
+
+  return gridptr->trunc;
 }
 
-void gridPrint ( int gridID, int index, int opt )
+
+void gridDefTrunc(int gridID, int trunc)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  gridPrintKernel ( gridptr, index, opt, stdout );
+  if ( gridptr->trunc != trunc )
+    {
+      gridMark4Update(gridID);
+      gridptr->trunc = trunc;
+    }
 }
 
+/*
+ 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.
 
-void gridPrintP ( void * voidptr, FILE * fp )
-{
-  grid_t * gridptr = ( grid_t * ) voidptr;
+ at Description
+The function @func{gridDefXsize} defines the number of values of a X-axis.
 
-  xassert ( gridptr );
+ at EndFunction
+*/
+void gridDefXsize(int gridID, int xsize)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  gridPrintKernel ( gridptr , gridptr->self, 0, fp );
+  int gridSize = gridInqSize(gridID);
+  if ( xsize > gridSize )
+    Error("xsize %d is greater then gridsize %d", xsize, gridSize);
 
-  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 );
+  int gridType = gridInqType(gridID);
+  if ( gridType == GRID_UNSTRUCTURED && xsize != gridSize )
+    Error("xsize %d must be equal to gridsize %d for gridtype: UNSTRUCTURED", xsize, gridSize);
 
-  if ( gridptr->rowlon )
+  if ( gridptr->x.size != xsize )
     {
-      static const char prefix[] = "rowlon    = ";
-      printIntsPrefixAutoBrk(fp, prefix, sizeof (prefix),
-                             (size_t)(gridptr->nrowlon > 0
-                                      ? gridptr->nrowlon : 0), gridptr->rowlon);
+      gridMark4Update(gridID);
+      gridptr->x.size = xsize;
     }
 
-  if ( gridptr->mask_gme )
+  if ( gridType != GRID_UNSTRUCTURED && gridType != GRID_PROJECTION )
     {
-      static const char prefix[] = "mask_gme  = ";
-      printMask(fp, prefix, sizeof (prefix),
-                (size_t)(gridptr->size > 0 ? gridptr->size : 0),
-                gridptr->mask_gme);
+      long axisproduct = gridptr->x.size*gridptr->y.size;
+      if ( axisproduct > 0 && axisproduct != gridSize )
+        Error("Inconsistent grid declaration! (xsize=%d ysize=%d gridsize=%d)",
+              gridptr->x.size, gridptr->y.size, gridSize);
     }
 }
 
-static const double *gridInqXValsPtrSerial(grid_t *gridptr)
-{
-  return gridptr->xvals;
-}
+/*
+ at Function
+ at Title
 
-const double *gridInqXvalsPtr(int gridID)
+ at Prototype
+ at Parameter
+    @Item  Grid identifier
+
+ at EndFunction
+*/
+void gridDefPrec(int gridID, int prec)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqXValsPtr(gridptr);
+  grid_t *gridptr = grid_to_pointer(gridID);
+
+  if ( gridptr->prec != prec )
+    {
+      gridMark4Update(gridID);
+      gridptr->prec = prec;
+    }
 }
 
+/*
+ at Function
+ at Title
 
-static const double *gridInqYValsPtrSerial(grid_t *gridptr)
+ at Prototype
+ at Parameter
+    @Item  Grid identifier
+
+ at EndFunction
+*/
+int gridInqPrec(int gridID)
 {
-  return gridptr->yvals;
+  grid_t *gridptr = grid_to_pointer(gridID);
+
+  return gridptr->prec;
 }
 
-const double *gridInqYvalsPtr(int gridID)
+/*
+ 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.
+
+ at Result
+ at func{gridInqXsize} returns the number of values of a X-axis.
+
+ at EndFunction
+*/
+int gridInqXsize(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->vtable->inqYValsPtr(gridptr);
+  grid_t *gridptr = grid_to_pointer(gridID);
+
+  return gridptr->x.size;
 }
 
 /*
- at Function  gridDefLCC
- at Title     Define the parameter of a Lambert Conformal Conic grid
+ at Function  gridDefYsize
+ at Title     Define the number of values of a Y-axis
 
- 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 Prototype void gridDefYsize(int gridID, int ysize)
 @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.
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
+    @Item  ysize    Number of values of a Y-axis.
 
 @Description
-The function @func{gridDefLCC} defines the parameter of a Lambert Conformal Conic grid.
+The function @func{gridDefYsize} defines the number of values of a Y-axis.
 
 @EndFunction
 */
-void gridDefLCC(int gridID, double originLon, double originLat, double lonParY,
-                double lat1, double lat2, double xinc, double yinc,
-                int projflag, int scanflag)
+void gridDefYsize(int gridID, int ysize)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  if ( gridptr->type != GRID_LCC )
-    Warning("Definition of LCC grid for %s grid not allowed!",
-	    gridNamePtr(gridptr->type));
-  else
+  int gridSize = gridInqSize(gridID);
+
+  if ( ysize > gridSize )
+    Error("ysize %d is greater then gridsize %d", 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);
+
+  if ( gridptr->y.size != ysize )
     {
-      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);
+      gridptr->y.size = ysize;
+    }
+
+  if ( gridType != GRID_UNSTRUCTURED && gridType != GRID_PROJECTION )
+    {
+      long axisproduct = gridptr->x.size*gridptr->y.size;
+      if ( axisproduct > 0 && axisproduct != gridSize )
+        Error("Inconsistent grid declaration! (xsize=%d ysize=%d gridsize=%d)",
+              gridptr->x.size, gridptr->y.size, gridSize);
     }
 }
 
 /*
- at Function  gridInqLCC
- at Title     Get the parameter of a Lambert Conformal Conic grid
+ at Function  gridInqYsize
+ at Title     Get the number of values of a Y-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 int gridInqYsize(int gridID)
 @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}.
+
 @Description
-The function @func{gridInqLCC} returns the parameter of a Lambert Conformal Conic grid.
+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.
 
 @EndFunction
 */
-void gridInqLCC(int gridID, double *originLon, double *originLat, double *lonParY,
-                double *lat1, double *lat2, double *xinc, double *yinc,
-                int *projflag, int *scanflag)
+int gridInqYsize(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(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);
-    }
+  return gridptr->y.size;
 }
 
-void gridDefLcc2(int gridID, double earth_radius, double lon_0, double lat_0, double lat_1, double lat_2)
+/*
+ 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.
+
+ at Description
+The function @func{gridDefNP} defines the number of parallels between a pole and the equator
+of a Gaussian grid.
+
+ at EndFunction
+*/
+void gridDefNP(int gridID, int np)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  if ( gridptr->type != GRID_LCC2 )
-    Warning("Definition of LCC2 grid for %s grid not allowed!",
-	    gridNamePtr(gridptr->type));
-  else
+  if ( gridptr->np != np )
     {
-      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);
+      gridptr->np = np;
     }
 }
 
+/*
+ at Function  gridInqNP
+ at Title     Get the number of parallels between a pole and the equator
+
+ 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.
+
+ at Result
+ at func{gridInqNP} returns the number of parallels between a pole and the equator.
 
-void gridInqLcc2(int gridID, double *earth_radius, double *lon_0, double *lat_0, double *lat_1, double *lat_2)
+ at EndFunction
+*/
+int gridInqNP(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  if ( gridptr->type != GRID_LCC2 )
-    Warning("Inquire of LCC2 grid definition for %s grid not allowed!",
-	    gridNamePtr(gridptr->type));
-  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);
-    }
+  return gridptr->np;
 }
 
-void gridDefLaea(int gridID, double earth_radius, double lon_0, double lat_0)
+/*
+ at Function
+ at Title
+
+ at Prototype
+ at Parameter
+    @Item  Grid identifier
+
+ at EndFunction
+*/
+void gridDefRowlon(int gridID, int nrowlon, const int rowlon[])
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  if ( gridptr->type != GRID_LAEA )
-    Warning("Definition of LAEA grid for %s grid not allowed!",
-            gridNamePtr(gridptr->type));
-  else
-    {
-      gridptr->laea_a       = earth_radius;
-      gridptr->laea_lon_0   = lon_0;
-      gridptr->laea_lat_0   = lat_0;
-      gridptr->laea_defined = TRUE;
-      gridMark4Update(gridID);
-    }
+  gridptr->rowlon = (int *) Malloc((size_t)nrowlon * sizeof(int));
+  gridptr->nrowlon = nrowlon;
+  memcpy(gridptr->rowlon, rowlon, (size_t)nrowlon * sizeof(int));
+  gridMark4Update(gridID);
 }
 
+/*
+ at Function
+ at Title
+
+ at Prototype
+ at Parameter
+    @Item  Grid identifier
 
-void gridInqLaea(int gridID, double *earth_radius, double *lon_0, double *lat_0)
+ at EndFunction
+*/
+void gridInqRowlon(int gridID, int *rowlon)
 {
-  grid_t* gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  if ( gridptr->type != GRID_LAEA )
-    Warning("Inquire of LAEA grid definition for %s grid not allowed!",
-            gridNamePtr(gridptr->type));
-  else
-    {
-      if ( gridptr->laea_defined )
-        {
-          *earth_radius = gridptr->laea_a;
-          *lon_0        = gridptr->laea_lon_0;
-          *lat_0        = gridptr->laea_lat_0;
-        }
-      else
-        Warning("LAEA grid undefined (gridID = %d)", gridID);
-    }
-}
+  if ( gridptr->rowlon == 0 )  Error("undefined pointer!");
 
+  memcpy(rowlon, gridptr->rowlon, (size_t)gridptr->nrowlon * sizeof(int));
+}
 
-void gridDefComplexPacking(int gridID, int lcomplex)
+static int
+gridInqMaskSerialGeneric(grid_t *gridptr, mask_t **internalMask,
+                        int *restrict mask)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  long size = gridptr->size;
 
+  if ( CDI_Debug && size == 0 )
+    Warning("Size undefined for gridID = %d", gridptr->self);
 
-  if (gridptr->lcomplex != lcomplex)
+  const mask_t *restrict mask_src = *internalMask;
+  if ( mask_src )
     {
-      gridptr->lcomplex = (short)(lcomplex != 0);
-      gridMark4Update(gridID);
+      if (mask && size > 0)
+        for (size_t i = 0; i < (size_t)size; ++i)
+          mask[i] = (int)mask_src[i];
     }
-}
+  else
+    size = 0;
 
+  return (int)size;
+}
 
-int gridInqComplexPacking(int gridID)
+static int
+gridInqMaskSerial(grid_t *gridptr, int *mask)
 {
-  grid_t* gridptr = gridID2Ptr(gridID);
-
-  return (gridptr->lcomplex);
+  return gridInqMaskSerialGeneric(gridptr, &gridptr->mask, mask);
 }
 
 
-void gridDefHasDims(int gridID, int hasdims)
+int gridInqMask(int gridID, int *mask)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqMask(gridptr, mask);
+}
+
+static void
+gridDefMaskSerial(grid_t *gridptr, const int *mask)
 {
-  grid_t* gridptr = gridID2Ptr(gridID);
+  long size = gridptr->size;
 
-  if (gridptr->hasdims != (hasdims != 0))
+  if ( size == 0 )
+    Error("Size undefined for gridID = %d", gridptr->self);
+
+  if ( mask == NULL )
     {
-      gridptr->hasdims = hasdims != 0;
-      gridMark4Update(gridID);
+      if ( gridptr->mask )
+	{
+	  Free(gridptr->mask);
+	  gridptr->mask = NULL;
+	}
+    }
+  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);
     }
 }
 
+void gridDefMask(int gridID, const int *mask)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->vtable->defMask(gridptr, mask);
+  gridMark4Update(gridID);
+}
 
-int gridInqHasDims(int gridID)
+static int
+gridInqMaskGMESerial(grid_t *gridptr, int *mask_gme)
 {
-  grid_t* gridptr = gridID2Ptr(gridID);
+  return gridInqMaskSerialGeneric(gridptr, &gridptr->mask_gme, mask_gme);
+}
 
-  return (gridptr->hasdims);
+int gridInqMaskGME(int gridID, int *mask)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqMaskGME(gridptr, mask);
 }
 
-/*
- at Function  gridDefNumber
- at Title     Define the reference number for an unstructured grid
+static void
+gridDefMaskGMESerial(grid_t *gridptr, const int *mask)
+{
+  long size = gridptr->size;
 
- 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 ( size == 0 )
+    Error("Size undefined for gridID = %d", gridptr->self);
 
- at Description
-The function @func{gridDefNumber} defines the reference number for an unstructured grid.
+  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!");
 
- at EndFunction
-*/
-void gridDefNumber(int gridID, const int number)
+  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 = grid_to_pointer(gridID);
+  gridptr->vtable->defMaskGME(gridptr, mask);
+  gridMark4Update(gridID);
+}
+
+
+static
+int gridInqXValsSerial(grid_t *gridptr, double *xvals)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  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->x.size;
+
+  if ( CDI_Debug && size == 0 )
+    Warning("size undefined for gridID = %d", gridptr->self);
 
-  if (gridptr->number != number)
+  if ( gridptr->x.vals )
     {
-      gridptr->number = number;
-      gridMark4Update(gridID);
+      if ( size && xvals )
+        {
+          const double *gridptr_xvals = gridptr->vtable->inqXValsPtr(gridptr);
+          memcpy(xvals, gridptr_xvals, (size_t)size * sizeof (double));
+        }
     }
+  else
+    size = 0;
+
+  return (int)size;
 }
 
 /*
- at Function  gridInqNumber
- at Title     Get the reference number to an unstructured grid
+ at Function  gridInqXvals
+ at Title     Get all values of a X-axis
 
- at Prototype int gridInqNumber(int gridID)
+ at Prototype int 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.
+                    The caller must allocate space for the returned values.
 
 @Description
-The function @func{gridInqNumber} returns the reference number to an unstructured grid.
+The function @func{gridInqXvals} returns all values of the X-axis.
 
 @Result
- at func{gridInqNumber} returns the reference number to an unstructured grid.
+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
 */
-int gridInqNumber(int gridID)
+int gridInqXvals(int gridID, double *xvals)
 {
-  grid_t* gridptr = gridID2Ptr(gridID);
-  return gridptr->number;
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqXVals(gridptr, xvals);
 }
 
-/*
- at Function  gridDefPosition
- at Title     Define the position of grid in the reference file
 
- 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.
+static
+void gridDefXValsSerial(grid_t *gridptr, const double *xvals)
+{
+  int gridtype = gridptr->type;
 
- at Description
-The function @func{gridDefPosition} defines the position of grid in the reference file.
+  long size;
+  if ( gridtype == GRID_UNSTRUCTURED || gridtype == GRID_CURVILINEAR )
+    size = gridptr->size;
+  else if ( gridtype == GRID_GAUSSIAN_REDUCED )
+    size = 2;
+  else
+    size = gridptr->x.size;
 
- at EndFunction
-*/
-void gridDefPosition(int gridID, int position)
-{
-  grid_t* gridptr = gridID2Ptr(gridID);
+  if ( size == 0 )
+    Error("Size undefined for gridID = %d", gridptr->self);
 
-  if (gridptr->position != position)
-    {
-      gridptr->position = position;
-      gridMark4Update(gridID);
-    }
+  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));
 }
 
 /*
- at Function  gridInqPosition
- at Title     Get the position of grid in the reference file
+ at Function  gridDefXvals
+ at Title     Define the values of a X-axis
 
- at Prototype int gridInqPosition(int gridID)
+ at Prototype void gridDefXvals(int gridID, const double *xvals)
 @Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
+    @Item  xvals    X-values of the grid.
 
 @Description
-The function @func{gridInqPosition} returns the position of grid in the reference file.
+The function @func{gridDefXvals} defines all values of the X-axis.
 
- at Result
- at func{gridInqPosition} returns the position of grid in the reference file.
 @EndFunction
 */
-int gridInqPosition(int gridID)
+void gridDefXvals(int gridID, const double *xvals)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  return (gridptr->position);
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->vtable->defXVals(gridptr, xvals);
+  gridMark4Update(gridID);
 }
 
-/*
- at Function  gridDefReference
- at Title     Define the reference URI for an unstructured grid
-
- 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.
-
- at Description
-The function @func{gridDefReference} defines the reference URI for an unstructured grid.
-
- at EndFunction
-*/
-void gridDefReference(int gridID, const char *reference)
+static
+int gridInqYValsSerial(grid_t *gridptr, double *yvals)
 {
-  grid_t* gridptr = gridID2Ptr(gridID);
+  int gridtype = gridptr->type;
+  long size = (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
+            ? gridptr->size : gridptr->y.size;
 
-  if ( reference )
+  if ( CDI_Debug && size == 0 )
+    Warning("size undefined for gridID = %d!", gridptr->self);
+
+  if ( gridptr->y.vals )
     {
-      if ( gridptr->reference )
+      if ( size && yvals )
         {
-          Free(gridptr->reference);
-          gridptr->reference = NULL;
+          const double *gridptr_yvals = gridptr->vtable->inqYValsPtr(gridptr);
+          memcpy(yvals, gridptr_yvals, (size_t)size * sizeof (double));
         }
-
-      gridptr->reference = strdupx(reference);
-      gridMark4Update(gridID);
     }
+  else
+    size = 0;
+
+  return (int)size;
 }
 
 /*
- at Function  gridInqReference
- at Title     Get the reference URI to an unstructured grid
+ at Function  gridInqYvals
+ at Title     Get all values of a Y-axis
 
- at Prototype char *gridInqReference(int gridID, char *reference)
+ at Prototype int 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.
+                    The caller must allocate space for the returned values.
 
 @Description
-The function @func{gridInqReference} returns the reference URI to an unstructured grid.
+The function @func{gridInqYvals} returns all values of the Y-axis.
 
 @Result
- at func{gridInqReference} returns the reference URI to an unstructured grid.
+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.
+
 @EndFunction
 */
-int gridInqReference(int gridID, char *reference)
+int gridInqYvals(int gridID, double *yvals)
 {
-  size_t len = 0;
-  grid_t* gridptr = gridID2Ptr(gridID);
-
-  if ( gridptr->reference )
-    {
-      len = strlen(gridptr->reference);
-      if ( reference )
-        strcpy(reference, gridptr->reference);
-    }
-
-  return (int)len;
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqYVals(gridptr, yvals);
 }
 
-const char *gridInqReferencePtr(int gridID)
+static
+void gridDefYValsSerial(grid_t *gridptr, const double *yvals)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->reference;
+  int gridtype = gridptr->type;
+  long 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!");
+
+  gridptr->y.vals = (double *)Realloc(gridptr->y.vals, (size_t)size * sizeof (double));
+  memcpy(gridptr->y.vals, yvals, (size_t)size * sizeof (double));
 }
 
+
 /*
- at Function  gridDefUUID
- at Title     Define the UUID for an unstructured grid
+ at Function  gridDefYvals
+ at Title     Define the values of a Y-axis
 
- at Prototype void gridDefUUID(int gridID, const char *uuid)
+ at Prototype void gridDefYvals(int gridID, const double *yvals)
 @Parameter
     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
-    @Item  uuid     UUID for an unstructured grid.
+    @Item  yvals    Y-values of the grid.
 
 @Description
-The function @func{gridDefUUID} defines the UUID for an unstructured grid.
+The function @func{gridDefYvals} defines all values of the Y-axis.
 
 @EndFunction
 */
-void gridDefUUID(int gridID, const unsigned char uuid[CDI_UUID_SIZE])
+void gridDefYvals(int gridID, const double *yvals)
 {
-  grid_t* gridptr = gridID2Ptr(gridID);
-
-  memcpy(gridptr->uuid, uuid, CDI_UUID_SIZE);
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->vtable->defYVals(gridptr, yvals);
   gridMark4Update(gridID);
 }
 
-/*
- at Function  gridInqUUID
- at Title     Get the UUID to an unstructured grid
-
- at Prototype void gridInqUUID(int gridID, char *uuid)
- at Parameter
-    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
-
- at Description
-The function @func{gridInqUUID} returns the UUID to an unstructured grid.
-
- 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])
+static double
+gridInqXValSerial(grid_t *gridptr, int index)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  memcpy(uuid, gridptr->uuid, CDI_UUID_SIZE);
+  double xval = gridptr->x.vals ? gridptr->x.vals[index] : 0;
+  return xval;
 }
 
 
-void cdiGridGetIndexList(unsigned ngrids, int * gridIndexList)
+double gridInqXval(int gridID, int index)
 {
-  reshGetResHListOfType(ngrids, gridIndexList, &gridOps);
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqXVal(gridptr, index);
 }
 
-
-static int
-gridTxCode ()
+static double
+gridInqYValSerial(grid_t *gridptr, int index)
 {
-  return GRID;
+  double yval = gridptr->y.vals ? gridptr->y.vals[index] : 0;
+  return yval;
 }
 
-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,
-};
+/*
+ at Function
+ at Title
 
+ at Prototype
+ at Parameter
+    @Item  Grid identifier
 
-static int gridGetComponentFlags(const grid_t * gridP)
+ at EndFunction
+*/
+double gridInqYval(int gridID, int index)
 {
-  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;
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqYVal(gridptr, index);
 }
 
-static int
-gridGetPackSize(void * voidP, void *context)
-{
-  grid_t * gridP = ( grid_t * ) voidP;
-  int packBuffSize = 0, count;
-
-  packBuffSize += serializeGetSize(gridNint, DATATYPE_INT, context)
-    + serializeGetSize(1, DATATYPE_UINT32, context);
+/*
+ at Function
+ at Title
 
-  if (gridP->rowlon)
-    {
-      xassert(gridP->nrowlon);
-      packBuffSize += serializeGetSize(gridP->nrowlon, DATATYPE_INT, context)
-        + serializeGetSize( 1, DATATYPE_UINT32, context);
-    }
+ at Prototype
+ at Parameter
+    @Item  Grid identifier
 
-  packBuffSize += serializeGetSize(gridNdouble, DATATYPE_FLT64, context);
+ at EndFunction
+*/
+double gridInqXinc(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  double xinc = gridptr->x.inc;
+  const double *restrict xvals = gridptr->vtable->inqXValsPtr(gridptr);
 
-  if (gridP->vtable->inqXValsPtr(gridP))
+  if ( (! (fabs(xinc) > 0)) && xvals )
     {
-      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);
-    }
+      int xsize = gridptr->x.size;
+      if ( xsize > 1 )
+        {
+          xinc = fabs(xvals[xsize-1] - xvals[0])/(xsize-1);
+          for ( int i = 2; i < xsize; i++ )
+            if ( fabs(fabs(xvals[i-1] - xvals[i]) - xinc) > 0.01*xinc )
+              {
+                xinc = 0;
+                break;
+              }
 
-  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);
+          gridptr->x.inc = xinc;
+        }
     }
 
-  if (gridP->vtable->inqAreaPtr(gridP))
-    {
-      xassert(gridP->size);
-      packBuffSize +=
-        serializeGetSize(gridP->size, DATATYPE_FLT64, context)
-        + serializeGetSize(1, DATATYPE_UINT32, context);
-    }
+  return xinc;
+}
 
-  if (gridP->xbounds)
-    {
-      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));
-    }
+/*
+ at Function
+ at Title
 
-  if (gridP->ybounds)
-    {
-      xassert(gridP->nvertex);
-      if (gridP->type == GRID_CURVILINEAR || gridP->type == GRID_UNSTRUCTURED)
-	count = gridP->size;
-      else
-	count = gridP->ysize;
-      xassert(count);
-      packBuffSize
-        += (serializeGetSize(gridP->nvertex * count, DATATYPE_FLT64, context)
-            + serializeGetSize(1, DATATYPE_UINT32, context));
-    }
+ at Prototype
+ at Parameter
+    @Item  Grid identifier
 
-  {
-    const char *strTab[] = GRID_STR_SERIALIZE(gridP);
-    int numStr = (int)(sizeof (strTab) / sizeof (strTab[0]));
-    packBuffSize
-      += serializeStrTabGetPackSize(strTab, numStr, context);
-  }
+ 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 (gridP->reference)
+  if ( (! (fabs(yinc) > 0)) && yvals )
     {
-      size_t len = strlen(gridP->reference);
-      packBuffSize += serializeGetSize(1, DATATYPE_INT, context)
-        + serializeGetSize((int)len + 1, DATATYPE_TXT, context)
-        + serializeGetSize(1, DATATYPE_UINT32, context);
-    }
+      int 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++ )
+            if ( fabs(fabs(yvals[i] - yvals[i-1]) - abs_yinc) > (0.01*abs_yinc) )
+              {
+                yinc = 0;
+                break;
+              }
 
-  if (gridP->mask)
-    {
-      xassert(gridP->size);
-      packBuffSize
-        += serializeGetSize(gridP->size, DATATYPE_UCHAR, context)
-        + serializeGetSize(1, DATATYPE_UINT32, context);
+          gridptr->y.inc = yinc;
+        }
     }
 
-  if (gridP->mask_gme)
-    {
-      xassert(gridP->size);
-      packBuffSize += serializeGetSize(gridP->size, DATATYPE_UCHAR, context)
-        + serializeGetSize(1, DATATYPE_UINT32, context);
-    }
+  return yinc;
+}
 
-  if (!cdiUUIDIsNull(gridP->uuid))
-    packBuffSize += serializeGetSize(CDI_UUID_SIZE, DATATYPE_UCHAR, context);
+/*
+ at Function
+ at Title
 
-  return packBuffSize;
-}
+ at Prototype
+ at Parameter
+    @Item  Grid identifier
 
-void
-gridUnpack(char * unpackBuffer, int unpackBufferSize,
-           int * unpackBufferPos, int originNamespace, void *context,
-           int force_id)
+ at EndFunction
+*/
+void gridInqParamRLL(int gridID, double *xpole, double *ypole, double *angle)
 {
-  grid_t * gridP;
-  uint32_t d;
-  int memberMask, size;
+  *xpole = 0; *ypole = 0; *angle = 0;
 
-  gridInit();
-
-  {
-    int intBuffer[gridNint];
-    serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                    intBuffer, gridNint, DATATYPE_INT, context);
-    serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                    &d, 1, DATATYPE_UINT32, context);
+  const char *projection = "rotated_latitude_longitude";
+  char mapping[CDI_MAX_NAME]; mapping[0] = 0;
+  cdiGridInqKeyStr(gridID, CDI_KEY_MAPPING, CDI_MAX_NAME, mapping);
+  if ( mapping[0] && strcmp(mapping, projection) == 0 )
+    {
+      int atttype, attlen;
+      char attname[CDI_MAX_NAME+1];
 
-    xassert(cdiCheckSum(DATATYPE_INT, gridNint, intBuffer) == d);
-    int targetID = namespaceAdaptKey(intBuffer[0], originNamespace);
-    gridP = gridNewEntry(force_id?targetID:CDI_UNDEFID);
+      int natts;
+      cdiInqNatts(gridID, CDI_GLOBAL, &natts);
 
-    xassert(!force_id || targetID == gridP->self);
+      for ( int iatt = 0; iatt < natts; ++iatt )
+        {
+          cdiInqAtt(gridID, CDI_GLOBAL, iatt, attname, &atttype, &attlen);
 
-    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];
-  }
+          if ( attlen != 1 ) continue;
 
-  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);
+          if ( atttype == DATATYPE_FLT32 || atttype == DATATYPE_FLT64 )
+            {
+              double attflt;
+              cdiInqAttFlt(gridID, CDI_GLOBAL, 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);
+}
 
-  {
-    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));
+/*
+ at Function
+ at Title
 
-    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];
-  }
+ at Prototype
+ at Parameter
+    @Item  Grid identifier
 
-  int irregular = gridP->type == GRID_UNSTRUCTURED
-    || gridP->type == GRID_CURVILINEAR;
-  if (memberMask & gridHasXValsFlag)
-    {
-      size = irregular ? gridP->size : gridP->xsize;
+ at EndFunction
+*/
+void gridDefParamRLL(int gridID, double xpole, double ypole, double angle)
+{
+  cdiGridDefKeyStr(gridID, CDI_KEY_MAPNAME, CDI_MAX_NAME, "rotated_pole");
 
-      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 );
-    }
+  const char *mapping = "rotated_latitude_longitude";
+  cdiGridDefKeyStr(gridID, CDI_KEY_MAPPING, CDI_MAX_NAME, mapping);
+  cdiDefAttTxt(gridID, CDI_GLOBAL, "grid_mapping_name", strlen(mapping), mapping);
+  cdiDefAttFlt(gridID, CDI_GLOBAL, "grid_north_pole_longitude", DATATYPE_FLT64, 1, &xpole);
+  cdiDefAttFlt(gridID, CDI_GLOBAL, "grid_north_pole_latitude", DATATYPE_FLT64, 1, &ypole);
+  if ( IS_NOT_EQUAL(angle, 0) ) cdiDefAttFlt(gridID, CDI_GLOBAL, "north_pole_grid_longitude", DATATYPE_FLT64, 1, &angle);
 
-  if (memberMask & gridHasYValsFlag)
-    {
-      size = irregular ? gridP->size : gridP->ysize;
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->projtype = CDI_PROJ_RLL;
 
-      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);
-    }
+  gridVerifyProj(gridID);
+}
 
-  if (memberMask & gridHasAreaFlag)
-    {
-      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);
-    }
+/*
+ at Function
+ at Title
 
-  if (memberMask & gridHasXBoundsFlag)
-    {
-      size = gridP->nvertex * (irregular ? gridP->size : gridP->xsize);
-      xassert(size);
+ at Prototype
+ at Parameter
+    @Item  Grid identifier
 
-      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);
-    }
+ at EndFunction
+*/
+void gridInqParamGME(int gridID, int *nd, int *ni, int *ni2, int *ni3)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  if (memberMask & gridHasYBoundsFlag)
-    {
-      size = gridP->nvertex * (irregular ? gridP->size : gridP->ysize);
-      xassert(size);
+  *nd  = gridptr->gme.nd;
+  *ni  = gridptr->gme.ni;
+  *ni2 = gridptr->gme.ni2;
+  *ni3 = gridptr->gme.ni3;
+}
 
-      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);
-    }
+/*
+ at Function
+ at Title
 
-  {
-    char *strTab[] = GRID_STR_SERIALIZE(gridP);
-    int numStr = sizeof (strTab) / sizeof (strTab[0]);
-    serializeStrTabUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                          strTab, numStr, context);
-  }
+ at Prototype
+ at Parameter
+    @Item  Grid identifier
 
-  if (memberMask & gridHasReferenceFlag)
+ at EndFunction
+*/
+void gridDefParamGME(int gridID, int nd, int ni, int ni2, int ni3)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+
+  if ( gridptr->gme.nd != nd )
     {
-      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);
+      gridptr->gme.nd  = nd;
+      gridptr->gme.ni  = ni;
+      gridptr->gme.ni2 = ni2;
+      gridptr->gme.ni3 = ni3;
+      gridMark4Update(gridID);
     }
+}
+
+/*
+ at Function
+ at Title
+
+ at Prototype
+ at Parameter
+    @Item  Grid identifier
+
+ at EndFunction
+*/
+void gridChangeType(int gridID, int gridtype)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  if (memberMask & gridHasMaskFlag)
+  if ( CDI_Debug )
+    Message("Changed grid type from %s to %s", gridNamePtr(gridptr->type), gridNamePtr(gridtype));
+
+  if (gridptr->type != gridtype)
     {
-      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);
+      gridptr->type = gridtype;
+      gridMark4Update(gridID);
     }
+}
 
-  if (memberMask & gridHasGMEMaskFlag)
+static
+void grid_check_cyclic(grid_t *gridptr)
+{
+  gridptr->isCyclic = FALSE;
+  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;
+  const double *xvals = gridptr->vtable->inqXValsPtr(gridptr),
+    (*xbounds)[numVertices]
+    = (const double (*)[numVertices])gridptr->vtable->inqXBoundsPtr(gridptr);
+
+  if ( gridptr->type == GRID_GAUSSIAN || gridptr->type == GRID_LONLAT )
     {
-      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 ( xvals && xsize > 1 )
+        {
+          double xinc = xvals[1] - xvals[0];
+          if ( IS_EQUAL(xinc, 0) )
+            xinc = (xvals[xsize-1] - xvals[0])/(double)(xsize-1);
+
+          double x0 = 2*xvals[xsize-1]-xvals[xsize-2]-360;
+
+          if ( IS_NOT_EQUAL(xvals[0], xvals[xsize-1]) )
+            if ( fabs(x0 - xvals[0]) < 0.01*xinc ) gridptr->isCyclic = TRUE;
+        }
     }
-  if (memberMask & gridHasUUIDFlag)
+  else if ( gridptr->type == GRID_CURVILINEAR )
     {
-      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      gridP->uuid, CDI_UUID_SIZE, DATATYPE_UCHAR, context);
-    }
+      if ( 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];
 
-  reshSetStatus(gridP->self, &gridOps,
-                reshGetStatus(gridP->self, &gridOps) & ~RESH_SYNC_BIT);
-}
+              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;
 
-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;
+              double x0 = valn + copysign(xinc, val1 - valn);
 
-  {
-    int intBuffer[gridNint];
+              nc += fabs(x0-val1) < 0.5*xinc;
+            }
+          gridptr->isCyclic = nc > ysize/2 ? TRUE : FALSE;
+        }
 
-    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]);
+      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];
 
-    serializePack(intBuffer, gridNint, DATATYPE_INT,
-                  packBuffer, packBufferSize, packBufferPos, context);
-    d = cdiCheckSum(DATATYPE_INT, gridNint, intBuffer);
-    serializePack(&d, 1, DATATYPE_UINT32,
-                  packBuffer, packBufferSize, packBufferPos, context);
-  }
+		      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 (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 ( fabs(val1-val2) < 0.001 )
+                        goto foundCloseVertices;
+		    }
+		}
+              /* all vertices more than 0.001 degrees apart */
+              isCyclic = false;
+              break;
+              foundCloseVertices:
+              ;
+	    }
+          gridptr->isCyclic = (int) isCyclic;
+	}
     }
+}
 
-  {
-    double doubleBuffer[gridNdouble];
 
-    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;
+int gridIsCircular(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-    serializePack(doubleBuffer, gridNdouble, DATATYPE_FLT64,
-                  packBuffer, packBufferSize, packBufferPos, context);
-    d = cdiCheckSum(DATATYPE_FLT, gridNdouble, doubleBuffer);
-    serializePack(&d, 1, DATATYPE_UINT32,
-                  packBuffer, packBufferSize, packBufferPos, context);
-  }
+  if ( gridptr->isCyclic == CDI_UNDEFID ) grid_check_cyclic(gridptr);
 
-  if (memberMask & gridHasXValsFlag)
-    {
-      if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR)
-	size = gridP->size;
-      else
-	size = gridP->xsize;
-      xassert(size);
+  return gridptr->isCyclic;
+}
 
-      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);
-    }
+static
+bool compareXYvals(grid_t *gridRef, grid_t *gridTest)
+{
+  bool differ = false;
 
-  if (memberMask & gridHasYValsFlag)
+  int xsizeTest = gridTest->x.size, ysizeTest = gridTest->y.size;
+  if ( !differ && xsizeTest > 0 && xsizeTest == gridRef->vtable->inqXVals(gridRef, 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);
+      const double *restrict xvalsRef = gridRef->vtable->inqXValsPtr(gridRef),
+        *restrict xvalsTest = gridTest->vtable->inqXValsPtr(gridTest);
+
+      for ( size_t i = 0; i < (size_t)xsizeTest; ++i )
+	if ( fabs(xvalsTest[i] - xvalsRef[i]) > 1.e-10 )
+	  {
+	    differ = true;
+	    break;
+	  }
     }
 
-  if (memberMask & gridHasAreaFlag)
+  if ( !differ && ysizeTest > 0 && ysizeTest == gridRef->vtable->inqYVals(gridRef, NULL) )
     {
-      xassert(gridP->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);
+      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;
+	  }
     }
 
-  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->xsize;
-      xassert ( size );
+  return differ;
+}
 
-      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);
-    }
+static
+bool compareXYvals2(grid_t *gridRef, grid_t *gridTest)
+{
+  int gridsize = gridTest->size;
+  bool differ
+    = ((gridTest->x.vals == NULL) ^ (gridRef->x.vals == NULL))
+    || ((gridTest->y.vals == NULL) ^ (gridRef->y.vals == NULL));
 
-  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->ysize;
-      xassert ( size );
+  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;
 
-      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);
-    }
+  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;
 
-  {
-    const char *strTab[] = GRID_STR_SERIALIZE(gridP);
-    int numStr = sizeof (strTab) / sizeof (strTab[0]);
-    serializeStrTabPack(strTab, numStr,
-                        packBuffer, packBufferSize, packBufferPos, 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 (memberMask & gridHasReferenceFlag)
-    {
-      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);
-    }
+  return differ;
+}
 
-  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);
-    }
+static
+bool gridCompare(int gridID, const grid_t *grid, bool coord_compare)
+{
+  bool differ = true;
+  const grid_t *gridRef = grid_to_pointer(gridID);
 
-  if (memberMask & gridHasGMEMaskFlag)
+  if ( grid->type == gridRef->type || grid->type == GRID_GENERIC )
     {
-      xassert((size = gridP->size));
+      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  %d\n", grid->x.size);
+	      printf("grid.ysize  %d\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 );
 
-      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);
+                  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 (memberMask & gridHasUUIDFlag)
-    serializePack(gridP->uuid, CDI_UUID_SIZE, DATATYPE_UCHAR,
-                  packBuffer, packBufferSize, packBufferPos, context);
+  return differ;
 }
 
-#undef GRID_STR_SERIALIZE
-
-
-struct gridCompareSearchState
+/*
+int gridIsEqual(int gridID1, int gridID2)
 {
-  int resIDValue;
-  const grid_t *queryKey;
-};
+  const grid_t *grid2 = grid_to_pointer(gridID2);
 
-static enum cdiApplyRet
-gridCompareSearch(int id, void *res, void *data)
-{
-  struct gridCompareSearchState *state = (struct gridCompareSearchState*)data;
-  (void)res;
-  if (gridCompare(id, state->queryKey) == 0)
-    {
-      state->resIDValue = id;
-      return CDI_APPLY_STOP;
-    }
-  else
-    return CDI_APPLY_GO_ON;
+  int grid_is_equal = gridCompare(gridID1, grid2, true) == false;
+
+  return grid_is_equal;
 }
+*/
 
-/* Add grid (which must be Malloc'ed to vlist if not already found */
-struct addIffNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode)
+int gridCompareP(void *gridptr1, void *gridptr2)
 {
-  /*
-    mode: 0 search in vlist and grid table
-          1 search in grid table
-   */
-  int gridglobdefined = FALSE;
-  int griddefined = FALSE;
-  int gridID = CDI_UNDEFID;
-  vlist_t *vlistptr = vlist_to_pointer(vlistID);
+  grid_t *g1 = ( grid_t * ) gridptr1;
+  grid_t *g2 = ( grid_t * ) gridptr2;
+  enum { equal = 0,
+         differ = -1 };
+  int i, size;
 
-  unsigned ngrids = (unsigned)vlistptr->ngrids;
+  xassert ( g1 );
+  xassert ( g2 );
 
-  if ( mode == 0 )
-    for (unsigned index = 0; index < ngrids; index++ )
-      {
-	if ( (gridID = vlistptr->gridIDs[index]) != UNDEFID )
-          {
-            if ( gridCompare(gridID, grid) == 0 )
-              {
-                griddefined = TRUE;
-                break;
-              }
-          }
-        else
-          Error("Internal problem: undefined gridID in vlist "
-                "%d, position %u!", vlistID, index);
+  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->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 ( 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->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 ( ! griddefined )
+  const double *restrict g1_xvals = g1->vtable->inqXValsPtr(g1),
+               *restrict g2_xvals = g2->vtable->inqXValsPtr(g2);
+  if ( g1_xvals )
     {
-      struct gridCompareSearchState query;
-      query.queryKey = grid;// = { .queryKey = grid };
-      if ((gridglobdefined
-           = (cdiResHFilterApply(&gridOps, gridCompareSearch, &query)
-              == CDI_APPLY_STOP)))
-        gridID = query.resIDValue;
+      if ( g1->type == GRID_UNSTRUCTURED || g1->type == GRID_CURVILINEAR )
+        size = g1->size;
+      else
+        size = g1->x.size;
+      xassert ( size );
 
-      if ( mode == 1 && gridglobdefined)
-	for (unsigned index = 0; index < ngrids; index++ )
-	  if ( vlistptr->gridIDs[index] == gridID )
-	    {
-	      gridglobdefined = FALSE;
-	      break;
-	    }
+      if ( !g2_xvals ) return differ;
+
+      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 ( ! griddefined )
+  const double *restrict g1_yvals = g1->vtable->inqYValsPtr(g1),
+               *restrict g2_yvals = g2->vtable->inqYValsPtr(g2);
+  if ( g1_yvals )
     {
-      if ( ! gridglobdefined )
-        {
-          grid->self = gridID = reshPut(grid, &gridOps);
-          gridComplete(grid);
-        }
-      vlistptr->gridIDs[ngrids] = gridID;
-      vlistptr->ngrids++;
-    }
+      if ( g1->type == GRID_UNSTRUCTURED || g1->type == GRID_CURVILINEAR )
+	size = g1->size;
+      else
+	size = g1->y.size;
+      xassert ( size );
 
-  return (struct addIffNewRes){ .Id = gridID,
-      .isNew = !griddefined && !gridglobdefined };
-}
+      if ( !g2_yvals ) return differ;
 
-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,
-};
+      for ( i = 0; i < size; i++ )
+        if ( IS_NOT_EQUAL(g1_yvals[i], g2_yvals[i]) ) return differ;
+    }
+  else if ( g2_yvals )
+    return differ;
 
-/*
- * 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
+  const double *restrict g1_area = g1->vtable->inqAreaPtr(g1),
+               *restrict g2_area = g2->vtable->inqAreaPtr(g2);
+  if ( g1_area )
+    {
+      xassert ( g1->size );
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <ctype.h>
+      if ( !g2_area ) return differ;
 
+      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;
 
+  {
+    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 );
 
-static int initIegLib      = 0;
-static int iegDefaultDprec = 0;
+        if ( !(g2_xbounds = g2->vtable->inqXBoundsPtr(g2)) ) return differ;
 
+        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;
+  }
 
-/*
- * 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 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 );
 
-const char *iegLibraryVersion(void)
-{
-  return ieg_libvers;
-}
+        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;
+  }
 
-static int IEG_Debug = 0;    /* If set to 1, debugging */
+  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;
 
-static
-void iegLibInit(void)
-{
-  const char *envName = "IEG_PRECISION";
+  if (strcmp(g1->mapping, g2->mapping)) return differ;
 
-  char *envString = getenv(envName);
-  if ( envString )
+  if ( g1->reference )
     {
-      int pos;
-      int nrun;
-      if ( strlen(envString) == 2 ) nrun = 1;
-      else                          nrun = 2;
-
-      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;
-	}
+      if ( !g2->reference ) return differ;
+      if ( strcmp(g1->reference, g2->reference) ) return differ;
     }
+  else if ( g2->reference )
+    return differ;
 
-  initIegLib = 1;
-}
+  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;
 
+  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;
 
-void iegDebug(int debug)
-{
-  IEG_Debug = debug;
+  if ( memcmp(g1->uuid, g2->uuid, CDI_UUID_SIZE) )
+    return differ;
 
-  if ( IEG_Debug )
-    Message("debug level %d", debug);
+  return equal;
 }
 
 static
-void iegInit(iegrec_t *iegp)
+void gridComplete(grid_t *grid)
 {
-  iegp->checked    = 0;
-  iegp->byteswap   = 0;
-  iegp->dprec      = 0;
-  iegp->refval     = 0;
-  iegp->datasize   = 0;
-  iegp->buffersize = 0;
-  iegp->buffer     = NULL;
-}
+  int gridID = grid->self;
+  gridDefPrec(gridID, grid->prec);
 
+  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_PROJECTION:
+      {
+	if ( grid->x.size > 0 ) gridDefXsize(gridID, grid->x.size);
+	if ( grid->y.size > 0 ) gridDefYsize(gridID, grid->y.size);
 
-void iegInitMem(void *ieg)
-{
-  iegrec_t *iegp = (iegrec_t *) ieg;
+        if ( gridtype == GRID_GAUSSIAN ) gridDefNP(gridID, grid->np);
 
-  memset(iegp->ipdb, 0, sizeof(iegp->ipdb));
-  memset(iegp->igdb, 0, sizeof(iegp->igdb));
-  memset(iegp->vct,  0, sizeof(iegp->vct));
-}
+	if ( grid->nvertex > 0 )
+	  gridDefNvertex(gridID, grid->nvertex);
 
+	if ( grid->x.flag == 2 )
+	  {
+            assert(gridtype != GRID_UNSTRUCTURED && gridtype != GRID_CURVILINEAR);
+	    double *xvals = (double *) Malloc((size_t)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);
+	    */
+	  }
 
-void *iegNew(void)
-{
-  if ( ! initIegLib ) iegLibInit();
+	if ( grid->y.flag == 2 )
+	  {
+            assert(gridtype != GRID_UNSTRUCTURED && gridtype != GRID_CURVILINEAR);
+	    double *yvals = (double *) Malloc((size_t)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);
+	    */
+	  }
 
-  iegrec_t *iegp = (iegrec_t *) Malloc(sizeof(iegrec_t));
+	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");
+	  }
 
-  iegInit(iegp);
-  iegInitMem(iegp);
+        switch (gridtype)
+          {
+          case GRID_LCC:
+            gridDefParamLCC(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;
+	  }
 
-  return (void*)iegp;
+	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 ( grid->y.flag == 2 )
+	  {
+	    double *yvals = (double *) Malloc((size_t)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;
+      }
+    }
+
+  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;
 }
 
+#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 }
 
-void iegDelete(void *ieg)
+int gridGenerate(const grid_t *grid)
 {
-  iegrec_t *iegp = (iegrec_t *) ieg;
-
-  if ( iegp )
+  int gridtype = grid->type;
+  int gridID = gridCreate(gridtype, grid->size);
+  grid_t *restrict gridptr = grid_to_pointer(gridID);
+  gridptr->prec = grid->prec;
+  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_LCC, 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 ( iegp->buffer ) Free(iegp->buffer);
-      Free(iegp);
+      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->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->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);
 
+  return gridID;
+}
 
-int iegCheckFiletype(int fileID, int *swap)
+static void
+grid_copy_base_array_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
 {
-  size_t data = 0;
-  size_t dimx = 0, dimy = 0;
-  size_t fact = 0;
-  unsigned char buffer[1048], *pbuf;
-
-  if ( fileRead(fileID, buffer, 4) != 4 ) return 0;
-
-  size_t blocklen  = get_UINT32(buffer);
-  size_t sblocklen = get_SUINT32(buffer);
-
-  if ( IEG_Debug )
-    Message("blocklen = %d sblocklen = %d", blocklen, sblocklen);
+  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 ( blocklen == 636 || blocklen == 640 )
+  if ( gridptrOrig->x.vals != 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);
+      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->x.size;
+
+      gridptrDup->x.vals = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->x.vals, gridptrOrig->x.vals, size * sizeof (double));
     }
-  else if ( blocklen == 1040 || blocklen == 1036 )
+
+  if ( gridptrOrig->y.vals != 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);
+      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->y.size;
+
+      gridptrDup->y.vals = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->y.vals, gridptrOrig->y.vals, size * sizeof (double));
     }
-  else if ( sblocklen == 636 || sblocklen == 640 )
+
+  if ( gridptrOrig->x.bounds != NULL )
     {
-     *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);
+      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));
     }
-  else if ( sblocklen == 1040 || sblocklen == 1036 )
+
+  if ( gridptrOrig->y.bounds != NULL )
     {
-     *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);
+      size_t size = (irregular ? gridsize : (size_t)gridptrOrig->y.size)
+        * (size_t)gridptrOrig->nvertex;
+
+      gridptrDup->y.bounds = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->y.bounds, gridptrOrig->y.bounds, size * sizeof (double));
     }
 
-  fileRewind(fileID);
+  {
+    const double *gridptrOrig_area
+      = gridptrOrig->vtable->inqAreaPtr(gridptrOrig);
+    if ( gridptrOrig_area != NULL )
+      {
+        size_t size = gridsize;
 
-  int found = data && (dimx*dimy*fact == data || dimx*dimy*8 == data);
+        gridptrDup->area = (double *)Malloc(size * sizeof (double));
+        memcpy(gridptrDup->area, gridptrOrig_area, size * sizeof (double));
+      }
+  }
 
-  if ( IEG_Debug )
+  if ( gridptrOrig->mask != NULL )
     {
-      Message("swap = %d fact = %d", *swap, fact);
-      Message("dimx = %lu dimy = %lu data = %lu", dimx, dimy, data);
+      size_t size = gridsize;
+
+      gridptrDup->mask = (mask_t *)Malloc(size * sizeof(mask_t));
+      memcpy(gridptrDup->mask, gridptrOrig->mask, size * sizeof (mask_t));
     }
 
-  return found;
+  if ( gridptrOrig->mask_gme != NULL )
+    {
+      size_t size = gridsize;
+
+      gridptrDup->mask_gme = (mask_t *)Malloc(size * sizeof (mask_t));
+      memcpy(gridptrDup->mask_gme, gridptrOrig->mask_gme, size * sizeof(mask_t));
+    }
 }
 
 
-void iegCopyMeta(void *dieg, void *sieg)
-{
-  iegrec_t *diegp = (iegrec_t *) dieg;
-  iegrec_t *siegp = (iegrec_t *) sieg;
+/*
+ at Function  gridDuplicate
+ at Title     Duplicate a horizontal Grid
 
-  /*  diegp->byteswap = siegp->byteswap; */
-  diegp->dprec    = siegp->dprec;
-  diegp->refval   = siegp->refval;
+ at Prototype int gridDuplicate(int gridID)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
 
-  memcpy(diegp->ipdb, siegp->ipdb, sizeof(siegp->ipdb));
-  memcpy(diegp->igdb, siegp->igdb, sizeof(siegp->igdb));
-  memcpy(diegp->vct,  siegp->vct,  sizeof(siegp->vct));
+ 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)
+{
+  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
-int iegInqData(void *ieg, int prec, void *data)
+
+void gridCompress(int gridID)
 {
-  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;
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  switch ( dprec )
+  int gridtype = gridInqType(gridID);
+  if ( gridtype == GRID_UNSTRUCTURED )
     {
-    case EXSE_SINGLE_PRECISION:
-      {
-	if ( sizeof(FLT32) == 4 )
-	  {
-	    if ( byteswap ) swap4byte(buffer, datasize);
+      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);
 
-	    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);
+	  /* 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;
 
-	    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;
-      }
+          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
+    Warning("Unsupported grid type: %s", gridNamePtr(gridtype));
+}
+
+static void
+gridDefAreaSerial(grid_t *gridptr, const double *area)
+{
+  size_t size = (size_t)gridptr->size;
+
+  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!");
+
+  memcpy(gridptr->area, area, size * sizeof(double));
+}
+
+
+void gridDefArea(int gridID, const double *area)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->vtable->defArea(gridptr, area);
+  gridMark4Update(gridID);
+}
+
+static void
+gridInqAreaSerial(grid_t *gridptr, double *area)
+{
+  if (gridptr->area)
+    memcpy(area, gridptr->area, (size_t)gridptr->size * sizeof (double));
+}
 
-  return ierr;
+
+void gridInqArea(int gridID, double *area)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->vtable->inqArea(gridptr, area);
 }
 
+static int
+gridHasAreaBase(grid_t *gridptr)
+{
+  return gridptr->area != NULL;
+}
 
-int iegInqDataSP(void *ieg, float *data)
+int gridHasArea(int gridID)
 {
-  return iegInqData(ieg, EXSE_SINGLE_PRECISION, (void *) data);
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->hasArea(gridptr);
 }
 
 
-int iegInqDataDP(void *ieg, double *data)
+static const double *gridInqAreaPtrBase(grid_t *gridptr)
 {
-  return iegInqData(ieg, EXSE_DOUBLE_PRECISION, (void *) data);
+  return gridptr->area;
+}
+
+const double *gridInqAreaPtr(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqAreaPtr(gridptr);
 }
 
 
-static int
-iegDefData(iegrec_t *iegp, int prec, const void *data)
+void gridDefNvertex(int gridID, int nvertex)
 {
-  int dprec = iegDefaultDprec ? iegDefaultDprec : iegp->dprec;
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  iegp->dprec = dprec = dprec ? dprec : prec;
+  if (gridptr->nvertex != nvertex)
+    {
+      gridptr->nvertex = nvertex;
+      gridMark4Update(gridID);
+    }
+}
 
-  size_t datasize = (size_t)IEG_G_NumLon(iegp->igdb) * (size_t)IEG_G_NumLat(iegp->igdb);
-  size_t blocklen = datasize * (size_t)dprec;
 
-  iegp->datasize = datasize;
+int gridInqNvertex(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  size_t buffersize = iegp->buffersize;
+  return gridptr->nvertex;
+}
 
-  void *buffer = iegp->buffer;
-  if ( buffersize != blocklen )
+static void
+gridDefBoundsGeneric(grid_t *gridptr, const double *bounds, int regularSize,
+                     double **field)
+{
+  int irregular = gridptr->type == GRID_CURVILINEAR
+    || gridptr->type == GRID_UNSTRUCTURED;
+  size_t nvertex = (size_t)gridptr->nvertex;
+  if ( nvertex == 0 )
     {
-      buffersize = blocklen;
-      buffer = Realloc(buffer, buffersize);
-      iegp->buffer = buffer;
-      iegp->buffersize = buffersize;
+      Warning("nvertex undefined for gridID = %d. Cannot define bounds!",
+              gridptr->self);
+      return;
     }
+  size_t size = nvertex * (size_t)(irregular ? gridptr->size : regularSize);
+  if ( size == 0 )
+    Error("size undefined for gridID = %d", gridptr->self);
 
-  switch ( dprec )
+  if (*field == NULL)
+    *field = (double *)Malloc(size * sizeof (double));
+  else if ( CDI_Debug )
+    Warning("values already defined!");
+
+  memcpy(*field, bounds, size * sizeof (double));
+}
+
+
+static void
+gridDefXBoundsSerial(grid_t *gridptr, const double *xbounds)
+{
+  gridDefBoundsGeneric(gridptr, xbounds, gridptr->x.size, &gridptr->x.bounds);
+}
+
+/*
+ at Function  gridDefXbounds
+ at Title     Define the bounds of a X-axis
+
+ 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.
+
+ at Description
+The function @func{gridDefXbounds} defines all bounds of the X-axis.
+
+ at EndFunction
+*/
+void gridDefXbounds(int gridID, const double *xbounds)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->vtable->defXBounds(gridptr, xbounds);
+  gridMark4Update(gridID);
+}
+
+static int
+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);
+
+  const double *gridptr_xbounds = gridptr->vtable->inqXBoundsPtr(gridptr);
+  if ( gridptr_xbounds )
     {
-    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;
-      }
+      if ( size && xbounds )
+        memcpy(xbounds, gridptr_xbounds, size * sizeof (double));
     }
+  else
+    size = 0;
 
-  return 0;
+  return (int)size;
 }
 
+/*
+ at Function  gridInqXbounds
+ at Title     Get the bounds of a X-axis
 
-int iegDefDataSP(void *ieg, const float *data)
+ at Prototype int 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.
+
+ 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.
+
+ at EndFunction
+*/
+int gridInqXbounds(int gridID, double *xbounds)
 {
-  return iegDefData((iegrec_t *)ieg, EXSE_SINGLE_PRECISION, (void *) data);
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqXBounds(gridptr, xbounds);
+}
+
+static const double *
+gridInqXBoundsPtrSerial(grid_t *gridptr)
+{
+  return gridptr->x.bounds;
 }
 
 
-int iegDefDataDP(void *ieg, const double *data)
+const double *gridInqXboundsPtr(int gridID)
 {
-  return iegDefData((iegrec_t *)ieg, EXSE_DOUBLE_PRECISION, (void *) data);
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqXBoundsPtr(gridptr);
 }
 
+static void
+gridDefYBoundsSerial(grid_t *gridptr, const double *ybounds)
+{
+  gridDefBoundsGeneric(gridptr, ybounds, gridptr->y.size, &gridptr->y.bounds);
+}
 
-int iegRead(int fileID, void *ieg)
+/*
+ at Function  gridDefYbounds
+ at Title     Define the bounds of a Y-axis
+
+ 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.
+
+ at Description
+The function @func{gridDefYbounds} defines all bounds of the Y-axis.
+
+ at EndFunction
+*/
+void gridDefYbounds(int gridID, const double *ybounds)
 {
-  iegrec_t *iegp = (iegrec_t *) ieg;
-  union { double d[200]; float f[200]; int32_t i32[200]; } buf;
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->vtable->defYBounds(gridptr, ybounds);
+  gridMark4Update(gridID);
+}
 
-  if ( ! iegp->checked )
+static int
+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);
+
+  const double *gridptr_ybounds = gridptr->vtable->inqYBoundsPtr(gridptr);
+  if ( gridptr_ybounds )
     {
-      int status = iegCheckFiletype(fileID, &iegp->byteswap);
-      if ( status == 0 ) Error("Not a IEG file!");
-      iegp->checked = 1;
+      if ( size && ybounds )
+        memcpy(ybounds, gridptr_ybounds, size * sizeof (double));
     }
+  else
+    size = 0;
 
-  int byteswap = iegp->byteswap;
+  return (int)size;
+}
 
-  /* read header record */
-  size_t blocklen = binReadF77Block(fileID, byteswap);
 
-  if ( fileEOF(fileID) ) return -1;
+/*
+ at Function  gridInqYbounds
+ at Title     Get the bounds of a Y-axis
 
-  if ( IEG_Debug )
-    Message("blocklen = %lu", blocklen);
+ at Prototype int 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.
 
-  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 Description
+The function @func{gridInqYbounds} returns the bounds of the Y-axis.
 
-  iegp->dprec = dprec;
+ 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.
 
-  binReadInt32(fileID, byteswap, 37, buf.i32);
-  for ( size_t i = 0; i < 37; i++ ) iegp->ipdb[i] = (int)buf.i32[i];
+ at EndFunction
+*/
+int gridInqYbounds(int gridID, double *ybounds)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqYBounds(gridptr, ybounds);
+}
 
-  binReadInt32(fileID, byteswap, 18, buf.i32);
-  for ( size_t i = 0; i < 18; i++ ) iegp->igdb[i] = (int)buf.i32[i];
+static const double *
+gridInqYBoundsPtrSerial(grid_t *gridptr)
+{
+  return gridptr->y.bounds;
+}
 
-  if ( blocklen == 636 || blocklen == 1036 )
+
+const double *gridInqYboundsPtr(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(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++ )
     {
-      fileRead(fileID, buf.f, 4);
-      if ( byteswap ) swap4byte(buf.f, 1);
-      iegp->refval = (double)buf.f[0];
+      if ( nbyte > 80 )
+        {
+          fprintf(fp, "\n%*s", (int)nbyte0, "");
+          nbyte = nbyte0;
+        }
+      nbyte += (size_t)fprintf(fp, "%.*g ", dig, vals[i]);
     }
-  else
+  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++ )
     {
-      fileRead(fileID, buf.d, 8);
-      if ( byteswap ) swap8byte(buf.d, 1);
-      iegp->refval = (double)buf.d[0];
+      if ( nbyte > 80 )
+        {
+          fprintf(fp, "\n%*s", (int)nbyte0, "");
+          nbyte = nbyte0;
+        }
+      nbyte += (size_t)fprintf(fp, "%d ", vals[i]);
     }
+  fputs("\n", fp);
+}
 
-  binReadInt32(fileID, byteswap, 3, buf.i32);
-  for ( size_t i = 0; i < 3; i++ ) iegp->igdb[18+i] = (int)buf.i32[i];
-
-  if ( dprec == EXSE_SINGLE_PRECISION )
+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 )
     {
-      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];
+      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);
     }
-  else
+}
+
+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++ )
     {
-      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];
+      if ( nbyte > 80 )
+        {
+          fprintf(fp, "\n%*s", (int)nbyte0, "");
+          nbyte = nbyte0;
+        }
+      nbyte += (size_t)fprintf(fp, "%d ", (int)mask[i]);
     }
+  fputs("\n", fp);
+}
 
-  /*
-  fprintf(stderr, "refval %g\n", iegp->refval);
+static inline
+void *resizeBuffer(void **buf, size_t *bufSize, size_t reqSize)
+{
+  if (reqSize > *bufSize)
+    {
+      *buf = Realloc(*buf, reqSize);
+      *bufSize = reqSize;
+    }
+  return *buf;
+}
 
-  for ( size_t i = 0; i < 100; i++ )
-    fprintf(stderr, "%3d %g\n", i, iegp->vct[i]);
+static
+void gridPrintAttributes(FILE *fp, int gridID)
+{
+  int cdiID = gridID;
+  int varID = CDI_GLOBAL;
+  int atttype, attlen;
+  char attname[CDI_MAX_NAME+1];
+  void *attBuf = NULL;
+  size_t attBufSize = 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);
+  int natts;
+  cdiInqNatts(cdiID, varID, &natts);
 
-  if ( blocklen2 != blocklen )
+  for ( int iatt = 0; iatt < natts; ++iatt )
     {
-      Warning("header blocklen differ!");
-      return -1;
-    }
+      cdiInqAtt(cdiID, varID, iatt, attname, &atttype, &attlen);
 
-  size_t datasize = iegp->datasize
-    = (size_t)IEG_G_NumLon(iegp->igdb) * (size_t)IEG_G_NumLat(iegp->igdb);
+      if ( attlen == 0 ) continue;
 
-  if ( IEG_Debug )
-    Message("datasize = %lu", iegp->datasize);
+      if ( atttype == 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 == DATATYPE_INT8  || atttype == DATATYPE_UINT8  ||
+                atttype == DATATYPE_INT16 || atttype == DATATYPE_UINT16 ||
+                atttype == DATATYPE_INT32 || atttype == 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 == DATATYPE_FLT32 || atttype == DATATYPE_FLT64 )
+        {
+          size_t attSize = (size_t)attlen * sizeof(double);
+          double *attflt = (double *)resizeBuffer(&attBuf, &attBufSize, attSize);
+          int dig = (atttype == 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");
+        }
+    }
 
-  blocklen = binReadF77Block(fileID, byteswap);
+  Free(attBuf);
+}
 
+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);
 
-  void *buffer = iegp->buffer;
-  if ( iegp->buffersize < blocklen )
-    {
-      iegp->buffer = buffer = Realloc(buffer, blocklen);
-      iegp->buffersize = blocklen;
-    }
+  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);
 
-  if ( dprec != (int) (blocklen/datasize) )
-    {
-      Warning("data precision differ! (h = %d; d = %d)",
-	      (int) dprec, (int) (blocklen/datasize));
-      return -1;
-    }
+  int dig = (prec == DATATYPE_FLT64) ? 15 : 7;
 
-  fileRead(fileID, buffer, blocklen);
+  struct gridaxis_t *xaxis = &gridptr->x;
+  struct gridaxis_t *yaxis = &gridptr->y;
 
-  blocklen2 = binReadF77Block(fileID, byteswap);
+  fprintf(fp, "#\n"
+          "# gridID %d\n"
+          "#\n"
+          "gridtype  = %s\n"
+          "gridsize  = %d\n", index, gridNamePtr(type), gridsize);
 
-  if ( blocklen2 != blocklen )
+  if ( type != GRID_GME )
     {
-      Warning("data blocklen differ!");
-      return -1;
-    }
+      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);
+        }
 
-  return 0;
-}
+      if ( xvals )
+        {
+          if ( xaxis->name[0]     )  fprintf(fp, "xname     = %s\n", xaxis->name);
+          if ( xaxis->longname[0] )  fprintf(fp, "xlongname = %s\n", xaxis->longname);
+          if ( xaxis->units[0]    )  fprintf(fp, "xunits    = %s\n", xaxis->units);
+          if ( xaxis->dimname[0] && strcmp(xaxis->name, xaxis->dimname) )
+            fprintf(fp, "xdimname  = %s\n", xaxis->dimname);
+        }
+      if ( yvals )
+        {
+          if ( yaxis->name[0]     )  fprintf(fp, "yname     = %s\n", yaxis->name);
+          if ( yaxis->longname[0] )  fprintf(fp, "ylongname = %s\n", yaxis->longname);
+          if ( yaxis->units[0]    )  fprintf(fp, "yunits    = %s\n", yaxis->units);
+          if ( yaxis->dimname[0] && strcmp(yaxis->name, yaxis->dimname) )
+            fprintf(fp, "ydimname  = %s\n", yaxis->dimname);
+        }
 
+      if ( type == GRID_UNSTRUCTURED || type == GRID_CURVILINEAR )
+        if ( gridptr->vdimname[0] ) fprintf(fp, "vdimname  = %s\n", gridptr->vdimname);
+      if ( type == GRID_UNSTRUCTURED && nvertex > 0 ) fprintf(fp, "nvertex   = %d\n", nvertex);
+    }
 
-int iegWrite(int fileID, void *ieg)
-{
-  iegrec_t *iegp = (iegrec_t *) ieg;
-  union { INT32 i32[200]; float fvct[100]; } buf;
-  int dprec  = iegp->dprec;
-  int byteswap = iegp->byteswap;
+  switch (type)
+    {
+    case GRID_LONLAT:
+    case GRID_GAUSSIAN:
+    case GRID_GAUSSIAN_REDUCED:
+    case GRID_GENERIC:
+    case GRID_PROJECTION:
+    case GRID_CURVILINEAR:
+    case GRID_UNSTRUCTURED:
+      {
+        if ( type == GRID_GAUSSIAN || type == GRID_GAUSSIAN_REDUCED ) fprintf(fp, "np        = %d\n", gridptr->np);
 
-  /* write header record */
-  size_t blocklen = ( dprec == EXSE_SINGLE_PRECISION ) ? 636 : 1040;
+	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 )
+          {
+            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);
+              }
+          }
 
-  binWriteF77Block(fileID, byteswap, blocklen);
+	if ( xvals )
+	  {
+	    double xfirst = 0.0, xinc = 0.0;
 
-  for ( size_t i = 0; i < 37; i++ ) buf.i32[i] = (INT32) iegp->ipdb[i];
-  binWriteInt32(fileID, byteswap, 37, buf.i32);
+	    if ( type == GRID_LONLAT     || type == GRID_GAUSSIAN ||
+		 type == GRID_PROJECTION || type == GRID_GENERIC )
+	      {
+		xfirst = gridInqXval(gridID, 0);
+		xinc   = gridInqXinc(gridID);
+	      }
 
-  for ( size_t i = 0; i < 18; i++ ) buf.i32[i] = (INT32) iegp->igdb[i];
-  binWriteInt32(fileID, byteswap, 18, buf.i32);
+	    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);
+	      }
+	  }
 
-  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);
+	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);
+	  }
 
-  for ( size_t i = 0; i < 3; i++ ) buf.i32[i] = (INT32) iegp->igdb[18+i];
-  binWriteInt32(fileID, byteswap, 3, buf.i32);
+	if ( yvals )
+	  {
+	    double yfirst = 0.0, yinc = 0.0;
 
-  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
-    {
-      binWriteFlt64(fileID, byteswap, 100, iegp->vct);
-    }
+	    if ( type == GRID_LONLAT || type == GRID_GENERIC ||
+                 type == GRID_PROJECTION || type == GRID_GENERIC )
+	      {
+		yfirst = gridInqYval(gridID, 0);
+		yinc   = gridInqYinc(gridID);
+	      }
 
-  binWriteF77Block(fileID, byteswap, blocklen);
+	    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);
+	      }
+	  }
 
-  size_t datasize = (size_t)iegp->igdb[4] * (size_t)iegp->igdb[5];
-  blocklen = datasize * (size_t)dprec;
+	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);
+	  }
 
-  binWriteF77Block(fileID, byteswap, blocklen);
+	if ( area )
+	  {
+            static const char prefix[] = "area      = ";
+            printDblsPrefixAutoBrk(fp, dig, prefix, sizeof(prefix)-1,
+                                   (size_t)(gridsize > 0 ? gridsize : 0), area);
+	  }
 
-  iegp->datasize = datasize;
+        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);
+          }
 
-  void *buffer = iegp->buffer;
+        if ( type == GRID_PROJECTION ) gridPrintAttributes(fp, gridID);
 
-  switch ( dprec )
-    {
-    case EXSE_SINGLE_PRECISION:
+	break;
+      }
+    case GRID_LCC:
       {
-	binWriteFlt32(fileID, byteswap, datasize, (FLT32 *) buffer);
+	double originLon = 0, originLat = 0, lonParY = 0, lat1 = 0, lat2 = 0, xincm = 0, yincm = 0;
+	int projflag = 0, scanflag = 0;
+	gridInqParamLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
+		   &projflag, &scanflag);
+
+	fprintf(fp,
+                "originLon = %.*g\n"
+                "originLat = %.*g\n"
+                "lonParY   = %.*g\n"
+                "lat1      = %.*g\n"
+                "lat2      = %.*g\n"
+                "xinc      = %.*g\n"
+                "yinc      = %.*g\n"
+                "projection = %s\n",
+                dig, originLon, dig, originLat, dig, lonParY,
+                dig, lat1, dig, lat2, dig, xincm, dig, yincm,
+                (projflag & 128) == 0 ? "northpole" : "southpole");
 	break;
       }
-    case EXSE_DOUBLE_PRECISION:
+    case GRID_SPECTRAL:
       {
-	binWriteFlt64(fileID, byteswap, datasize, (FLT64 *) buffer);
+        fprintf(fp, "truncation = %d\n"
+                "complexpacking = %d\n", trunc, gridptr->lcomplex );
+        break;
+      }
+    case GRID_FOURIER:
+      {
+	fprintf(fp, "truncation = %d\n", trunc);
 	break;
       }
-    default:
+    case GRID_GME:
       {
-	Error("unexpected data precision %d", dprec);
+        fprintf(fp, "ni        = %d\n", gridptr->gme.ni );
+        break;
+      }
+   default:
+      {
+	fprintf(stderr, "Unsupported grid type: %s\n", gridNamePtr(type));
         break;
       }
     }
 
-  binWriteF77Block(fileID, byteswap, blocklen);
+  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);
+    }
 
-  return 0;
+  if ( gridptr->mask )
+    {
+      static const char prefix[] = "mask      = ";
+      printMask(fp, prefix, sizeof(prefix)-1,
+                (size_t)(gridsize > 0 ? gridsize : 0), gridptr->mask);
+    }
 }
-/*
- * 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
-
-
-#include <sys/types.h>
-#include <stdlib.h>
-
-/*
-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().
-
->>> Warning <<<
-This code is currently not thread-safe.
-
-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.
-
-  //private:    //Subclasses may read it to determine whether there is only one reference, though.
-    size_t refCount;
-};
-
-void cdiRefObject_construct(CdiReferencedObject* me);
-void cdiRefObject_retain(CdiReferencedObject* me);
-void cdiRefObject_release(CdiReferencedObject* me);
-void cdiRefObject_destruct(CdiReferencedObject* me);
-
-#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
-
-
-/*
-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;
-
-  //private:
-    char* path;
-    int fileDescriptor;
-} CdiInputFile;
-
-//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.
-
-#endif
 
-/*
- * 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
+void gridPrint ( int gridID, int index, int opt )
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
 
+  gridPrintKernel ( gridptr, index, opt, stdout );
+}
 
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <string.h>
-#include <unistd.h>
 
-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)
+void gridPrintP ( void * voidptr, FILE * fp )
 {
-  #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;
-
-// ^        constructor code       ^
-// |                               |
-// v destructor/error-cleanup code v
+  grid_t * gridptr = ( grid_t * ) voidptr;
 
-destruct:
-  close(me->fileDescriptor);
-freePath:
-  Free(me->path);
-destructSuper:
-  cdiRefObject_destruct(super());
-  me = NULL;
+  xassert ( gridptr );
 
-success:
-  return me;
-  #undef super
-}
+  gridPrintKernel ( gridptr , gridptr->self, 0, fp );
 
-static CdiInputFile **openFileList = NULL;
-static size_t openFileCount = 0, openFileListSize = 0;
-static pthread_mutex_t openFileListLock = PTHREAD_MUTEX_INITIALIZER;
+  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->gme.nd, gridptr->gme.ni, gridptr->gme.ni2,
+          gridptr->gme.ni3, gridptr->number, gridptr->position, gridptr->trunc,
+          gridptr->lcomplex, gridptr->nrowlon );
 
-//This either returns a new object, or retains and returns a preexisting open file.
-CdiInputFile* cdiInputFile_make(const char* path)
-{
-  CdiInputFile* result = NULL;
-  xassert(path);
-  int error = pthread_mutex_lock(&openFileListLock);
-  xassert(!error);
+  if ( gridptr->rowlon )
     {
-      //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;
-            }
-        }
+      static const char prefix[] = "rowlon    = ";
+      printIntsPrefixAutoBrk(fp, prefix, sizeof(prefix)-1,
+                             (size_t)(gridptr->nrowlon > 0
+                                      ? gridptr->nrowlon : 0), gridptr->rowlon);
     }
-  error = pthread_mutex_unlock(&openFileListLock);
-  xassert(!error);
-  return result;
-}
 
-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)
+  if ( gridptr->mask_gme )
     {
-      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;
+      static const char prefix[] = "mask_gme  = ";
+      printMask(fp, prefix, sizeof(prefix)-1,
+                (size_t)(gridptr->size > 0 ? gridptr->size : 0),
+                gridptr->mask_gme);
     }
-  return CDI_NOERR;
 }
 
-const char* cdiInputFile_getPath(const CdiInputFile* me)
+static const double *gridInqXValsPtrSerial(grid_t *gridptr)
 {
-  return me->path;
+  return gridptr->x.vals;
 }
 
-void cdiInputFile_destruct(CdiInputFile* me)
+const double *gridInqXvalsPtr(int gridID)
 {
-  int error = pthread_mutex_lock(&openFileListLock);
-  xassert(!error);
-    {
-      //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);
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqXValsPtr(gridptr);
 }
 
-/*
- * 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
-
-/*
- * 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 <assert.h>
-#include <limits.h>
-
-
-#undef  UNDEFID
-#define UNDEFID  -1
 
-static int ECMWF  = UNDEFID,
-  MPIMET = UNDEFID,
-  MCH    = UNDEFID;
-
-typedef struct
+static const double *gridInqYValsPtrSerial(grid_t *gridptr)
 {
-  int    self;
-  int    used;
-  int    center;
-  int    subcenter;
-  char  *name;
-  char  *longname;
+  return gridptr->y.vals;
 }
-institute_t;
 
+const double *gridInqYvalsPtr(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->vtable->inqYValsPtr(gridptr);
+}
 
-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 );
+/*
+ at Function  gridDefParamLCC
+ at Title     Define the parameter of a Lambert Conformal Conic grid
 
-static const resOps instituteOps = {
-  (int (*)(void *, void *))instituteCompareKernel,
-  (void (*)(void *))instituteDestroyP,
-  (void (*)(void *, FILE *))institutePrintP,
-  (int (*)(void *, void *))instituteGetPackSize,
-  institutePackP,
-  instituteTxCode
-};
+ at Prototype void gridDefParamLCC(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.
 
-static
-void instituteDefaultValue ( institute_t * instituteptr )
-{
-  instituteptr->self       = UNDEFID;
-  instituteptr->used       = 0;
-  instituteptr->center     = UNDEFID;
-  instituteptr->subcenter  = UNDEFID;
-  instituteptr->name       = NULL;
-  instituteptr->longname   = NULL;
-}
+ at Description
+The function @func{gridDefParamLCC} defines the parameter of a Lambert Conformal Conic grid.
 
-void instituteDefaultEntries ( void )
+ at EndFunction
+*/
+void gridDefParamLCC(int gridID, double originLon, double originLat, double lonParY,
+                double lat1, double lat2, double xinc, double yinc,
+                int projflag, int scanflag)
 {
-  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)"); */
-
-  size_t n = sizeof(resH)/sizeof(*resH);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  for (size_t i = 0; i < n ; i++ )
-    reshSetStatus(resH[i], &instituteOps, RESH_IN_USE);
+  if ( gridptr->type != GRID_LCC )
+    Warning("Definition of LCC grid for %s grid not allowed!",
+	    gridNamePtr(gridptr->type));
+  else
+    {
+      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);
+    }
 }
 
+/*
+ at Function  gridInqParamLCC
+ at Title     Get the parameter of a Lambert Conformal Conic grid
+
+ at Prototype void gridInqParamLCC(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} 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.
+ 
+ at Description
+The function @func{gridInqParamLCC} returns the parameter of a Lambert Conformal Conic grid.
 
-static int
-instituteCompareKernel(institute_t *  ip1, institute_t * ip2)
+ at EndFunction
+*/
+void gridInqParamLCC(int gridID, double *originLon, double *originLat, double *lonParY,
+                double *lat1, double *lat2, double *xinc, double *yinc,
+                int *projflag, int *scanflag)
 {
-  int differ = 0;
-  size_t len1, len2;
-
-  if ( ip1->name )
-    {
-      if ( ip1->center    > 0 && ip2->center    != ip1->center )    differ = 1;
-      if ( ip1->subcenter > 0 && ip2->subcenter != ip1->subcenter ) differ = 1;
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-      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 ( gridptr->type != GRID_LCC )
+    Warning("Inquire of LCC grid definition for %s grid not allowed!",
+	    gridNamePtr(gridptr->type));
+  else
     {
-      if ( ip2->longname )
+      if ( gridptr->lcc.defined )
         {
-          len1 = strlen(ip1->longname);
-          len2 = strlen(ip2->longname);
-          if ( (len1 < len2) || memcmp(ip2->longname, ip1->longname, len2) ) differ = 1;
+          *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);
     }
-  else
+}
+
+
+void gridDefComplexPacking(int gridID, int lcomplex)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+
+  if (gridptr->lcomplex != lcomplex)
     {
-      if ( !( ip2->center    == ip1->center &&
-              ip2->subcenter == ip1->subcenter )) differ = 1;
+      gridptr->lcomplex = lcomplex != 0;
+      gridMark4Update(gridID);
     }
-
-  return differ;
 }
 
 
-struct instLoc
+int gridInqComplexPacking(int gridID)
 {
-  institute_t *ip;
-  int id;
-};
+  grid_t* gridptr = grid_to_pointer(gridID);
 
-static enum cdiApplyRet
-findInstitute(int id, void *res, void *data)
+  return (int)gridptr->lcomplex;
+}
+
+
+void gridDefHasDims(int gridID, int hasdims)
 {
-  institute_t * ip1 = ((struct instLoc *)data)->ip;
-  institute_t * ip2 = (institute_t*) res;
-  if (ip2->used && !instituteCompareKernel(ip1, ip2))
+  grid_t* gridptr = grid_to_pointer(gridID);
+
+  if ( gridptr->hasdims != (hasdims != 0) )
     {
-      ((struct instLoc *)data)->id = id;
-      return CDI_APPLY_STOP;
+      gridptr->hasdims = hasdims != 0;
+      gridMark4Update(gridID);
     }
-  else
-    return CDI_APPLY_GO_ON;
 }
 
 
-int institutInq(int center, int subcenter, const char *name, const char *longname)
+int gridInqHasDims(int gridID)
 {
-  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* gridptr = grid_to_pointer(gridID);
 
-  struct instLoc state = { .ip = ip_ref, .id = UNDEFID };
-  cdiResHFilterApply(&instituteOps, findInstitute, &state);
+  return (int)gridptr->hasdims;
+}
 
-  Free(ip_ref);
+/*
+ at Function  gridDefNumber
+ at Title     Define the reference number for an unstructured grid
 
-  return state.id;
-}
+ 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.
 
-static
-institute_t *instituteNewEntry(cdiResH resH, int center, int subcenter,
-                               const char *name, const char *longname)
+ at Description
+The function @func{gridDefNumber} defines the reference number for an unstructured grid.
+
+ at EndFunction
+*/
+void gridDefNumber(int gridID, const int number)
 {
-  institute_t *instituteptr = (institute_t*) Malloc(sizeof(institute_t));
-  instituteDefaultValue(instituteptr);
-  if (resH == CDI_UNDEFID)
-    instituteptr->self = reshPut(instituteptr, &instituteOps);
-  else
+  grid_t *gridptr = grid_to_pointer(gridID);
+
+  if ( gridptr->number != number )
     {
-      instituteptr->self = resH;
-      reshReplace(resH, instituteptr, &instituteOps);
+      gridptr->number = number;
+      gridMark4Update(gridID);
     }
-  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;
 }
 
+/*
+ at Function  gridInqNumber
+ at Title     Get the reference number to an unstructured grid
 
-int institutDef(int center, int subcenter, const char *name, const char *longname)
+ at Prototype int gridInqNumber(int gridID)
+ at Parameter
+    @Item  gridID   Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
+
+ at Description
+The function @func{gridInqNumber} returns the reference number to an unstructured grid.
+
+ at Result
+ at func{gridInqNumber} returns the reference number to an unstructured grid.
+ at EndFunction
+*/
+int gridInqNumber(int gridID)
 {
-  institute_t * instituteptr
-    = instituteNewEntry(CDI_UNDEFID, center, subcenter, name, longname);
-  return instituteptr->self;
+  grid_t* gridptr = grid_to_pointer(gridID);
+  return gridptr->number;
 }
 
+/*
+ at Function  gridDefPosition
+ at Title     Define the position of grid in the reference file
 
-int institutInqCenter(int instID)
-{
-  institute_t * instituteptr = NULL;
+ 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.
 
-  if ( instID != UNDEFID )
-    instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
+ at Description
+The function @func{gridDefPosition} defines the position of grid in the reference file.
+
+ at EndFunction
+*/
+void gridDefPosition(int gridID, int position)
+{
+  grid_t* gridptr = grid_to_pointer(gridID);
 
-  return  instituteptr ? instituteptr->center : UNDEFID;
+  if ( gridptr->position != position )
+    {
+      gridptr->position = position;
+      gridMark4Update(gridID);
+    }
 }
 
+/*
+ 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}.
 
-int institutInqSubcenter(int instID)
-{
-  institute_t * instituteptr = NULL;
+ at Description
+The function @func{gridInqPosition} returns the position of grid in the reference file.
 
-  if ( instID != UNDEFID )
-    instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
+ 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 instituteptr ? instituteptr->subcenter: UNDEFID;
+  return gridptr->position;
 }
 
+/*
+ at Function  gridDefReference
+ at Title     Define the reference URI for an unstructured grid
 
-const char *institutInqNamePtr(int instID)
+ 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.
+
+ at Description
+The function @func{gridDefReference} defines the reference URI for an unstructured grid.
+
+ at EndFunction
+*/
+void gridDefReference(int gridID, const char *reference)
 {
-  institute_t * instituteptr = NULL;
+  grid_t* gridptr = grid_to_pointer(gridID);
 
-  if ( instID != UNDEFID )
-    instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
+  if ( reference )
+    {
+      if ( gridptr->reference )
+        {
+          Free(gridptr->reference);
+          gridptr->reference = NULL;
+        }
 
-  return instituteptr ? instituteptr->name : NULL;
+      gridptr->reference = strdupx(reference);
+      gridMark4Update(gridID);
+    }
 }
 
+/*
+ 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}.
+
+ at Description
+The function @func{gridInqReference} returns the reference URI to an unstructured grid.
 
-const char *institutInqLongnamePtr(int instID)
+ at Result
+ at func{gridInqReference} returns the reference URI to an unstructured grid.
+ at EndFunction
+*/
+int gridInqReference(int gridID, char *reference)
 {
-  institute_t * instituteptr = NULL;
+  size_t len = 0;
+  grid_t* gridptr = grid_to_pointer(gridID);
 
-  if ( instID != UNDEFID )
-    instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
+  if ( gridptr->reference )
+    {
+      len = strlen(gridptr->reference);
+      if ( reference )
+        strcpy(reference, gridptr->reference);
+    }
 
-  return instituteptr ? instituteptr->longname : NULL;
+  return (int)len;
 }
 
-static enum cdiApplyRet
-activeInstitutes(int id, void *res, void *data)
+const char *gridInqReferencePtr(int gridID)
 {
-  (void)id;
-  if (res && ((institute_t *)res)->used)
-    ++(*(int *)data);
-  return CDI_APPLY_GO_ON;
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->reference;
 }
 
-int institutInqNumber(void)
+/*
+ at Function  gridDefUUID
+ at Title     Define the UUID for an unstructured grid
+
+ 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.
+
+ at Description
+The function @func{gridDefUUID} defines the UUID for an unstructured grid.
+
+ at EndFunction
+*/
+void gridDefUUID(int gridID, const unsigned char uuid[CDI_UUID_SIZE])
 {
-  int instNum = 0;
+  grid_t* gridptr = grid_to_pointer(gridID);
 
-  cdiResHFilterApply(&instituteOps, activeInstitutes, &instNum);
-  return instNum;
+  memcpy(gridptr->uuid, uuid, CDI_UUID_SIZE);
+  gridMark4Update(gridID);
 }
 
+/*
+ at Function  gridInqUUID
+ at Title     Get the UUID to an unstructured grid
+
+ 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 void
-instituteDestroyP(institute_t *instituteptr)
+ at Description
+The function @func{gridInqUUID} returns the UUID to an unstructured grid.
+
+ 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])
 {
-  xassert(instituteptr);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  int instituteID = instituteptr->self;
-  Free(instituteptr->name);
-  Free(instituteptr->longname);
-  reshRemove(instituteID, &instituteOps);
-  Free(instituteptr);
+  memcpy(uuid, gridptr->uuid, CDI_UUID_SIZE);
 }
 
 
-static void institutePrintP(institute_t *ip, FILE * fp )
+void cdiGridGetIndexList(unsigned ngrids, int * gridIndexList)
 {
-  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");
+  reshGetResHListOfType(ngrids, gridIndexList, &gridOps);
 }
 
 
 static int
-instituteTxCode ( void )
+gridTxCode ()
 {
-  return INSTITUTE;
+  return GRID;
 }
 
-enum {
-  institute_nints = 5,
+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 int instituteGetPackSize(institute_t *ip, void *context)
+
+static int gridGetComponentFlags(const grid_t * gridP)
 {
-  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 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;
 }
 
-static void institutePackP(void * instituteptr, void *buf, int size, int *position, void *context)
+static int
+gridGetPackSize(void * voidP, void *context)
 {
-  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);
+  grid_t * gridP = ( grid_t * ) voidP;
+  int packBuffSize = 0, count;
+
+  packBuffSize += serializeGetSize(gridNint, DATATYPE_INT, context)
+    + serializeGetSize(1, DATATYPE_UINT32, context);
+
+  if (gridP->rowlon)
+    {
+      xassert(gridP->nrowlon);
+      packBuffSize += serializeGetSize(gridP->nrowlon, DATATYPE_INT, context)
+        + serializeGetSize( 1, DATATYPE_UINT32, context);
+    }
+
+  packBuffSize += serializeGetSize(gridNdouble, DATATYPE_FLT64, context);
+
+  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, DATATYPE_FLT64, context)
+        + serializeGetSize(1, DATATYPE_UINT32, context);
+    }
+
+  if (gridP->vtable->inqYValsPtr(gridP))
+    {
+      if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR)
+	count = gridP->size;
+      else
+	count = gridP->y.size;
+      xassert(count);
+      packBuffSize += serializeGetSize(count, DATATYPE_FLT64, context)
+        + serializeGetSize(1, DATATYPE_UINT32, context);
+    }
+
+  if (gridP->vtable->inqAreaPtr(gridP))
+    {
+      xassert(gridP->size);
+      packBuffSize +=
+        serializeGetSize(gridP->size, DATATYPE_FLT64, context)
+        + serializeGetSize(1, DATATYPE_UINT32, context);
+    }
+
+  if (gridP->x.bounds)
+    {
+      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, DATATYPE_FLT64, context)
+            + serializeGetSize(1, DATATYPE_UINT32, context));
+    }
+
+  if (gridP->y.bounds)
+    {
+      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, DATATYPE_FLT64, context)
+            + serializeGetSize(1, DATATYPE_UINT32, context));
+    }
+
+  {
+    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, DATATYPE_INT, context)
+        + serializeGetSize((int)len + 1, DATATYPE_TXT, context)
+        + serializeGetSize(1, DATATYPE_UINT32, context);
+    }
+
+  if (gridP->mask)
+    {
+      xassert(gridP->size);
+      packBuffSize
+        += serializeGetSize(gridP->size, DATATYPE_UCHAR, context)
+        + serializeGetSize(1, DATATYPE_UINT32, context);
+    }
+
+  if (gridP->mask_gme)
+    {
+      xassert(gridP->size);
+      packBuffSize += serializeGetSize(gridP->size, DATATYPE_UCHAR, context)
+        + serializeGetSize(1, DATATYPE_UINT32, context);
+    }
+
+  if (!cdiUUIDIsNull(gridP->uuid))
+    packBuffSize += serializeGetSize(CDI_UUID_SIZE, DATATYPE_UCHAR, context);
+
+  return packBuffSize;
 }
 
-int instituteUnpack(void *buf, int size, int *position, int originNamespace,
-                    void *context, int force_id)
+void
+gridUnpack(char * unpackBuffer, int unpackBufferSize,
+           int * unpackBufferPos, int originNamespace, void *context,
+           int force_id)
 {
-  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;
-}
+  grid_t * gridP;
+  uint32_t d;
+  int memberMask, size;
 
-/*
- * 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.
- */
+  gridInit();
+
+  {
+    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);
+
+    xassert(!force_id || targetID == gridP->self);
+
+    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->isCyclic      =   (short)intBuffer[8];
+    gridP->x.flag        =   (short)intBuffer[10];
+    gridP->y.flag        =   (short)intBuffer[11];
+    gridP->gme.nd        =   intBuffer[12];
+    gridP->gme.ni        =   intBuffer[13];
+    gridP->gme.ni2       =   intBuffer[14];
+    gridP->gme.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->x.size        =   intBuffer[22];
+    gridP->y.size        =   intBuffer[23];
+    gridP->lcomplex      =   (bool)intBuffer[24];
+    memberMask           =   intBuffer[25];
+    gridP->x.stdname     =   xystdname_tab[intBuffer[26]][0];
+    gridP->y.stdname     =   xystdname_tab[intBuffer[27]][1];
+  }
 
-#ifndef INCLUDE_GUARD_CDI_ITERATOR_INT_H
-#define INCLUDE_GUARD_CDI_ITERATOR_INT_H
+  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));
 
-#include <stdbool.h>
+    gridP->x.first = doubleBuffer[0];
+    gridP->y.first = doubleBuffer[1];
+    gridP->x.last = doubleBuffer[2];
+    gridP->y.last = doubleBuffer[3];
+    gridP->x.inc = doubleBuffer[4];
+    gridP->y.inc = 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];
+  }
 
-/*
-class CdiIterator
+  int irregular = gridP->type == GRID_UNSTRUCTURED
+    || gridP->type == GRID_CURVILINEAR;
+  if (memberMask & gridHasXValsFlag)
+    {
+      size = irregular ? gridP->size : gridP->x.size;
 
-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.
+      gridP->x.vals = (double *) Malloc((size_t)size * sizeof (double));
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      gridP->x.vals, size, DATATYPE_FLT64, context);
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      &d, 1, DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(DATATYPE_FLT, size, gridP->x.vals) == d );
+    }
 
-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 (memberMask & gridHasYValsFlag)
+    {
+      size = irregular ? gridP->size : gridP->y.size;
 
-    CdiIterator <|--+-- CdiFallbackIterator
-                    |
-                    +-- CdiGribIterator
+      gridP->y.vals = (double *) Malloc((size_t)size * sizeof (double));
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      gridP->y.vals, size, DATATYPE_FLT64, context);
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      &d, 1, DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(DATATYPE_FLT, size, gridP->y.vals) == d);
+    }
 
-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 (memberMask & gridHasAreaFlag)
+    {
+      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);
+    }
 
-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?)
+  if (memberMask & gridHasXBoundsFlag)
+    {
+      size = gridP->nvertex * (irregular ? gridP->size : gridP->x.size);
+      xassert(size);
 
-  //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;
+      gridP->x.bounds = (double *) Malloc((size_t)size * sizeof (double));
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      gridP->x.bounds, size, DATATYPE_FLT64, context);
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      &d, 1, DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(DATATYPE_FLT, size, gridP->x.bounds) == d);
+    }
 
-  //The status information for reading/advancing is added in the subclasses.
-};
+  if (memberMask & gridHasYBoundsFlag)
+    {
+      size = gridP->nvertex * (irregular ? gridP->size : gridP->y.size);
+      xassert(size);
 
-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);
+      gridP->y.bounds = (double *) Malloc((size_t)size * sizeof (double));
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+			  gridP->y.bounds, size, DATATYPE_FLT64, context);
+      serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                      &d, 1, DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(DATATYPE_FLT, size, gridP->y.bounds) == d);
+    }
 
-#endif
+  {
+    char *strTab[] = GRID_STR_SERIALIZE(gridP);
+    int numStr = sizeof (strTab) / sizeof (strTab[0]);
+    serializeStrTabUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
+                          strTab, numStr, context);
+  }
 
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * 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.
- */
+  if (memberMask & gridHasReferenceFlag)
+    {
+      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);
+    }
 
-#ifndef INCLUDE_GUARD_CDI_ITERATOR_FALLBACK_H
-#define INCLUDE_GUARD_CDI_ITERATOR_FALLBACK_H
+  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 (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);
+    }
 
-typedef struct CdiFallbackIterator CdiFallbackIterator;
+  reshSetStatus(gridP->self, &gridOps,
+                reshGetStatus(gridP->self, &gridOps) & ~RESH_SYNC_BIT);
+}
 
-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);
 
-int cdiFallbackIterator_nextField(CdiIterator *me);
+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;
 
-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);
+  {
+    int intBuffer[gridNint];
 
-void cdiFallbackIterator_readField(CdiIterator *me, double *buffer, size_t *nmiss);
-void cdiFallbackIterator_readFieldF(CdiIterator *me, float *buffer, size_t *nmiss);
+    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[8]  = gridP->isCyclic;
+    intBuffer[10] = gridP->x.flag;
+    intBuffer[11] = gridP->y.flag;
+    intBuffer[12] = gridP->gme.nd;
+    intBuffer[13] = gridP->gme.ni;
+    intBuffer[14] = gridP->gme.ni2;
+    intBuffer[15] = gridP->gme.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->x.size;
+    intBuffer[23] = gridP->y.size;
+    intBuffer[24] = gridP->lcomplex;
+    intBuffer[25] = memberMask = gridGetComponentFlags(gridP);
+    intBuffer[26] = (int)((const char (*)[2][24])gridP->x.stdname
+                          - xystdname_tab);
+    intBuffer[27] = (int)((const char (*)[2][24])gridP->y.stdname
+                          - (const char (*)[2][24])xystdname_tab[0][1]);
 
-void cdiFallbackIterator_delete(CdiIterator *super);
+    serializePack(intBuffer, gridNint, DATATYPE_INT,
+                  packBuffer, packBufferSize, packBufferPos, context);
+    d = cdiCheckSum(DATATYPE_INT, gridNint, intBuffer);
+    serializePack(&d, 1, DATATYPE_UINT32,
+                  packBuffer, packBufferSize, packBufferPos, context);
+  }
 
-#endif
+  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);
+    }
 
-/*
- * 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.
- */
+  {
+    double doubleBuffer[gridNdouble];
 
-#ifndef INCLUDE_GUARD_CDI_ITERATOR_GRIB_H
-#define INCLUDE_GUARD_CDI_ITERATOR_GRIB_H
+    doubleBuffer[0]  = gridP->x.first;
+    doubleBuffer[1]  = gridP->y.first;
+    doubleBuffer[2]  = gridP->x.last;
+    doubleBuffer[3]  = gridP->y.last;
+    doubleBuffer[4]  = gridP->x.inc;
+    doubleBuffer[5]  = gridP->y.inc;
+    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;
 
+    serializePack(doubleBuffer, gridNdouble, DATATYPE_FLT64,
+                  packBuffer, packBufferSize, packBufferPos, context);
+    d = cdiCheckSum(DATATYPE_FLT, gridNdouble, doubleBuffer);
+    serializePack(&d, 1, DATATYPE_UINT32,
+                  packBuffer, packBufferSize, packBufferPos, context);
+  }
 
-#ifdef HAVE_LIBGRIB_API
-#include <grib_api.h>
-#endif
+  if (memberMask & gridHasXValsFlag)
+    {
+      if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR)
+	size = gridP->size;
+      else
+	size = gridP->x.size;
+      xassert(size);
 
-typedef struct recordList recordList;
+      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);
+    }
 
-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);
+  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, DATATYPE_FLT64,
+                    packBuffer, packBufferSize, packBufferPos, context);
+      d = cdiCheckSum(DATATYPE_FLT, size, gridP_yvals);
+      serializePack(&d, 1, DATATYPE_UINT32,
+                    packBuffer, packBufferSize, packBufferPos, context);
+    }
 
-int cdiGribIterator_nextField(CdiIterator *me);
+  if (memberMask & gridHasAreaFlag)
+    {
+      xassert(gridP->size);
 
-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);
+      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);
+    }
 
-void cdiGribIterator_readField(CdiIterator *me, double *buffer, size_t *nmiss);
-void cdiGribIterator_readFieldF(CdiIterator *me, float *buffer, size_t *nmiss);
+  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 );
 
-#endif
+      serializePack(gridP->x.bounds, size, DATATYPE_FLT64,
+                    packBuffer, packBufferSize, packBufferPos, context);
+      d = cdiCheckSum(DATATYPE_FLT, size, gridP->x.bounds);
+      serializePack(&d, 1, DATATYPE_UINT32,
+                    packBuffer, packBufferSize, packBufferPos, context);
+    }
 
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
+  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 );
 
-#include <assert.h>
-#include <ctype.h>
+      serializePack(gridP->y.bounds, size, DATATYPE_FLT64,
+                    packBuffer, packBufferSize, packBufferPos, context);
+      d = cdiCheckSum(DATATYPE_FLT, size, gridP->y.bounds);
+      serializePack(&d, 1, DATATYPE_UINT32,
+                    packBuffer, packBufferSize, packBufferPos, context);
+    }
 
-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";
+  {
+    const char *strTab[] = GRID_STR_SERIALIZE(gridP);
+    int numStr = sizeof (strTab) / sizeof (strTab[0]);
+    serializeStrTabPack(strTab, numStr,
+                        packBuffer, packBufferSize, packBufferPos, context);
+  }
 
-//Returns a static string.
-static const char* fileType2String(int fileType)
-{
-  switch(fileType)
+  if (memberMask & gridHasReferenceFlag)
     {
-#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
+      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);
+    }
 
-      default: return NULL;
+  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);
     }
-}
 
-static int string2FileType(const char* fileType, const char **outRestString)
-{
-  //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 (memberMask & gridHasGMEMaskFlag)
+    {
+      xassert((size = gridP->size));
 
-  //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;
-}
+      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);
+    }
 
-/*
- at Function cdiIterator_new
- at Title Create an iterator for an input file
+  if (memberMask & gridHasUUIDFlag)
+    serializePack(gridP->uuid, CDI_UUID_SIZE, DATATYPE_UCHAR,
+                  packBuffer, packBufferSize, packBufferPos, context);
+}
 
- at Prototype CdiIterator* cdiIterator_new(const char* path)
- at Parameter
-    @item path Path to the file that is to be read.
+#undef GRID_STR_SERIALIZE
 
- at Result An iterator for the given file.
 
- at Description
-    Combined allocator and constructor for CdiIterator.
+struct gridCompareSearchState
+{
+  int resIDValue;
+  const grid_t *queryKey;
+};
 
-    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)
+static enum cdiApplyRet
+gridCompareSearch(int id, void *res, void *data)
 {
-  int trash;
-  int filetype = cdiGetFiletype(path, &trash);
-  switch(filetype)
+  struct gridCompareSearchState *state = (struct gridCompareSearchState*)data;
+  (void)res;
+  if ( gridCompare(id, state->queryKey, false) == false )
     {
-      case FILETYPE_UNDEF:
-        Warning("Can't open file \"%s\": unknown format\n", path);
-        return NULL;
-
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          return cdiGribIterator_new(path, filetype);
-#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_new(path, filetype);
-
-      default:
-        Warning("the file \"%s\" is of type %s, but support for this format is not compiled in!", path, strfiletype(filetype));
-        return NULL;
+      state->resIDValue = id;
+      return CDI_APPLY_STOP;
     }
+  else
+    return CDI_APPLY_GO_ON;
 }
 
-void baseIterConstruct(CdiIterator* me, int filetype)
+/* Add grid (which must be Malloc'ed to vlist if not already found) */
+struct addIfNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode)
 {
-  me->filetype = filetype;
-  me->isAdvanced = false;
-}
+  /*
+    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);
 
-const char* baseIter_constructFromString(CdiIterator* me, const char* description)
-{
-  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))
+  unsigned ngrids = (unsigned)vlistptr->ngrids;
+
+  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);
+      }
+
+  if ( ! griddefined )
     {
-      me->isAdvanced = false;
-      result += sizeof (kUnadvancedString) - 1;
+      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;
+	    }
     }
-  else
+
+  if ( ! griddefined )
     {
-      Error("Invalid iterator description string \"%s\". Please check the origin of this string.", description);
-      return NULL;
+      if ( ! gridglobdefined )
+        {
+          grid->self = gridID = reshPut(grid, &gridOps);
+          gridComplete(grid);
+        }
+      if ( mode < 2 )
+        {
+          vlistptr->gridIDs[ngrids] = gridID;
+          vlistptr->ngrids++;
+        }
     }
-  return result;
+
+  return (struct addIfNewRes){ .Id = gridID, .isNew = !griddefined && !gridglobdefined };
 }
 
-#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
+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,
+};
 
- at Prototype CdiIterator* cdiIterator_clone(CdiIterator* me)
- at Parameter
-    @item iterator The iterator to copy.
+/*
+ * 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 Result The clone.
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
 
- at Description
-    Clones the given iterator. Make sure to call cdiIterator_delete() on both
-    the copy and the original.
 
-    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 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));
+static int initIegLib      = 0;
+static int iegDefaultDprec = 0;
 
-      default:
-        Error(kUnexpectedFileTypeMessage);
-        return NULL;
-    }
-}
 
 /*
- at Function cdiGribIterator_clone
- at Title Gain access to GRIB specific functionality
+ * 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__;
 
- at Prototype CdiGribIterator* cdiGribIterator_clone(CdiIterator* me)
- at Parameter
-    @item iterator The iterator to operate on.
+const char *iegLibraryVersion(void)
+{
+  return ieg_libvers;
+}
 
- 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.
+static int IEG_Debug = 0;    /* If set to 1, debugging */
 
-    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)
+static
+void iegLibInit(void)
 {
-  sanityCheck(me);
-  switch(me->filetype)
+  const char *envName = "IEG_PRECISION";
+
+  char *envString = getenv(envName);
+  if ( envString )
     {
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          return cdiGribIterator_makeClone(me);
-#endif
+      int pos;
+      int nrun;
+      if ( strlen(envString) == 2 ) nrun = 1;
+      else                          nrun = 2;
 
-      default:
-        return NULL;
+      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;
+	}
     }
+
+  initIegLib = 1;
 }
 
-/*
- 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.
+void iegDebug(int debug)
+{
+  IEG_Debug = debug;
 
- at Result A malloc'ed string that contains the full description of the iterator.
+  if ( IEG_Debug )
+    Message("debug level %d", debug);
+}
 
- at Description
-    Make sure to call Free() on the resulting string.
-*/
-char* cdiIterator_serialize(CdiIterator* me)
+static
+void iegInit(iegrec_t *iegp)
 {
-  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)
-    {
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          subclassDescription = cdiGribIterator_serialize(me);
-          break;
-#endif
+  iegp->checked    = 0;
+  iegp->byteswap   = 0;
+  iegp->dprec      = 0;
+  iegp->refval     = 0;
+  iegp->datasize   = 0;
+  iegp->buffersize = 0;
+  iegp->buffer     = NULL;
+}
 
-#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;
-    }
+void iegInitMem(void *ieg)
+{
+  iegrec_t *iegp = (iegrec_t *) ieg;
 
-  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;
+  memset(iegp->ipdb, 0, sizeof(iegp->ipdb));
+  memset(iegp->igdb, 0, sizeof(iegp->igdb));
+  memset(iegp->vct,  0, sizeof(iegp->vct));
 }
 
-/*
- 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 *iegNew(void)
+{
+  if ( ! initIegLib ) iegLibInit();
 
- at Result A clone of the original iterator.
+  iegrec_t *iegp = (iegrec_t *) Malloc(sizeof(iegrec_t));
 
- at Description
-    A pair of cdiIterator_serialize() and cdiIterator_deserialize() is functionally equivalent to a call to cdiIterator_clone()
+  iegInit(iegp);
+  iegInitMem(iegp);
 
-    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)
-{
-  switch(string2FileType(description, NULL))
-    {
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          return cdiGribIterator_getSuper(cdiGribIterator_deserialize(description));
-#endif
+  return (void*)iegp;
+}
 
-#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));
 
-      default:
-        Error(kUnexpectedFileTypeMessage);
-        return NULL;
+void iegDelete(void *ieg)
+{
+  iegrec_t *iegp = (iegrec_t *) ieg;
+
+  if ( iegp )
+    {
+      if ( iegp->buffer ) Free(iegp->buffer);
+      Free(iegp);
     }
 }
 
 
-/*
- at Function cdiIterator_print
- at Title Print a textual description of the iterator to a stream
+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 void cdiIterator_print(CdiIterator* iterator, FILE* stream);
- at Parameter
-    @item iterator The iterator to print.
-    @item stream The stream to print to.
+  if ( fileRead(fileID, buffer, 4) != 4 ) return 0;
 
- at Description
-    Use for debugging output.
-*/
-void cdiIterator_print(CdiIterator* me, FILE* stream)
-{
-  char* description = cdiIterator_serialize(me);
-  fprintf(stream, "%s\n", description);
-  Free(description);
-}
+  size_t blocklen  = get_UINT32(buffer);
+  size_t sblocklen = get_SUINT32(buffer);
 
+  if ( IEG_Debug )
+    Message("blocklen = %d sblocklen = %d", blocklen, sblocklen);
 
-/*
- at Function cdiIterator_nextField
- at Title Advance an iterator to the next field in the file
+  if ( blocklen == 636 || blocklen == 640 )
+    {
+     *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);
+    }
+  else if ( blocklen == 1040 || blocklen == 1036 )
+    {
+     *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 Prototype int cdiIterator_nextField(CdiIterator* iterator)
- at Parameter
-    @item iterator The iterator to operate on.
+  fileRewind(fileID);
 
- 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.
+  int found = data && (dimx*dimy*fact == data || dimx*dimy*8 == data);
 
- 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)
+  if ( IEG_Debug )
     {
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          return cdiGribIterator_nextField(me);
-#endif
+      Message("swap = %d fact = %d", *swap, fact);
+      Message("dimx = %lu dimy = %lu data = %lu", dimx, dimy, data);
+    }
 
-#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);
+  return found;
+}
 
-      default:
-        Error(kUnexpectedFileTypeMessage);
-        return CDI_EINVAL;
-    }
+
+void iegCopyMeta(void *dieg, void *sieg)
+{
+  iegrec_t *diegp = (iegrec_t *) dieg;
+  iegrec_t *siegp = (iegrec_t *) sieg;
+
+  /*  diegp->byteswap = siegp->byteswap; */
+  diegp->dprec    = siegp->dprec;
+  diegp->refval   = siegp->refval;
+
+  memcpy(diegp->ipdb, siegp->ipdb, sizeof(siegp->ipdb));
+  memcpy(diegp->igdb, siegp->igdb, sizeof(siegp->igdb));
+  memcpy(diegp->vct,  siegp->vct,  sizeof(siegp->vct));
 }
 
-static char* cdiIterator_inqTime(CdiIterator* me, CdiTimeType timeType)
+static
+int iegInqData(void *ieg, int prec, void *data)
 {
-  sanityCheck(me);
-  switch(me->filetype)
+  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_inqTime(me, timeType);
-#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_inqTime(me, timeType);
+	    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;
+      }
     }
-}
-
-/*
- 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.
+  return ierr;
+}
 
- 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).
+int iegInqDataSP(void *ieg, float *data)
+{
+  return iegInqData(ieg, EXSE_SINGLE_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_inqStartTime(CdiIterator* me)
+int iegInqDataDP(void *ieg, double *data)
 {
-  return cdiIterator_inqTime(me, kCdiTimeType_startTime);
+  return iegInqData(ieg, EXSE_DOUBLE_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.
+static int
+iegDefData(iegrec_t *iegp, int prec, const void *data)
+{
+  int dprec = iegDefaultDprec ? iegDefaultDprec : iegp->dprec;
 
- at Description
-The returned time is the end time of an integration period if such a time exists (statistical fields).
-Otherwise, NULL is returned.
+  iegp->dprec = dprec = dprec ? dprec : prec;
 
-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.
+  size_t datasize = (size_t)IEG_G_NumLon(iegp->igdb) * (size_t)IEG_G_NumLat(iegp->igdb);
+  size_t blocklen = datasize * (size_t)dprec;
 
-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)
-{
-  return cdiIterator_inqTime(me, kCdiTimeType_endTime);
-}
+  iegp->datasize = datasize;
 
-/*
- at Function cdiIterator_inqRTime
- at Title Get the validity time of the current field
+  size_t buffersize = iegp->buffersize;
 
- at Prototype char* cdiIterator_inqRTime(CdiIterator* me)
- at Parameter
-    @item iterator The iterator to operate on.
+  void *buffer = iegp->buffer;
+  if ( buffersize != blocklen )
+    {
+      buffersize = blocklen;
+      buffer = Realloc(buffer, buffersize);
+      iegp->buffer = buffer;
+      iegp->buffersize = buffersize;
+    }
 
- at Result A malloc'ed string containing the validity time of the current field in the format "YYYY-MM-DDTHH:MM:SS.mmm".
+  switch ( dprec )
+    {
+    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 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.
+  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_inqRTime(CdiIterator* me)
+int iegDefDataSP(void *ieg, const float *data)
 {
-  return cdiIterator_inqTime(me, kCdiTimeType_referenceTime);
+  return iegDefData((iegrec_t *)ieg, EXSE_SINGLE_PRECISION, (void *) data);
 }
 
-/*
- at Function cdiIterator_inqVTime
- at Title Get the validity time of the current field
-
- at Prototype char* cdiIterator_inqVTime(CdiIterator* me)
- at Parameter
-    @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".
 
- 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.
+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_inqVTime(CdiIterator* me)
+int iegRead(int fileID, void *ieg)
 {
-  char* result = cdiIterator_inqEndTime(me);
-  return (result) ? result : cdiIterator_inqStartTime(me);
-}
+  iegrec_t *iegp = (iegrec_t *) ieg;
+  union { double d[200]; float f[200]; int32_t i32[200]; } buf;
 
-/*
- at Function cdiIterator_inqLevelType
- at Title Get the type of a level
+  if ( ! iegp->checked )
+    {
+      int status = iegCheckFiletype(fileID, &iegp->byteswap);
+      if ( status == 0 ) Error("Not a IEG file!");
+      iegp->checked = 1;
+    }
 
- 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.
+  int byteswap = iegp->byteswap;
 
- at Result An integer indicating the type of the level.
+  /* read header record */
+  size_t blocklen = 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)
-    {
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          return cdiGribIterator_levelType(me, levelSelector, outName, outLongName, outStdName, outUnit);
-#endif
+  if ( fileEOF(fileID) ) 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);
+  if ( IEG_Debug )
+    Message("blocklen = %lu", blocklen);
 
-      default:
-        Error(kUnexpectedFileTypeMessage);
-        return CDI_UNDEFID;
+  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_inqLevel
- at Title Get the value of the z-coordinate
+  iegp->dprec = dprec;
 
- 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.
+  binReadInt32(fileID, byteswap, 37, buf.i32);
+  for ( size_t i = 0; i < 37; i++ ) iegp->ipdb[i] = (int)buf.i32[i];
 
- at Result An error code.
+  binReadInt32(fileID, byteswap, 18, buf.i32);
+  for ( size_t i = 0; i < 18; i++ ) iegp->igdb[i] = (int)buf.i32[i];
 
- 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 ( blocklen == 636 || blocklen == 1036 )
     {
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          return cdiGribIterator_level(me, levelSelector, outValue1, outValue2);
-#endif
+      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];
+    }
 
-#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);
+  binReadInt32(fileID, byteswap, 3, buf.i32);
+  for ( size_t i = 0; i < 3; i++ ) iegp->igdb[18+i] = (int)buf.i32[i];
 
-      default:
-        Error(kUnexpectedFileTypeMessage);
-        return CDI_EINVAL;
+  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_inqLevelUuid
- at Title Get the UUID of the z-axis used by this field
+  /*
+  fprintf(stderr, "refval %g\n", iegp->refval);
 
- 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.
+  for ( size_t i = 0; i < 100; i++ )
+    fprintf(stderr, "%3d %g\n", i, iegp->vct[i]);
 
- at Result An error code.
+  {
+    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
-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])
-{
-  sanityCheck(me);
-  switch(me->filetype)
+  if ( blocklen2 != blocklen )
     {
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          return cdiGribIterator_zaxisUuid(me, outVgridNumber, outLevelCount, outUuid);
-#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_zaxisUuid(me, outVgridNumber, outLevelCount, outUuid);
+  size_t datasize = iegp->datasize
+    = (size_t)IEG_G_NumLon(iegp->igdb) * (size_t)IEG_G_NumLat(iegp->igdb);
 
-      default:
-        Error(kUnexpectedFileTypeMessage);
-        return CDI_ELIBNAVAIL;
-    }
-}
+  if ( IEG_Debug )
+    Message("datasize = %lu", iegp->datasize);
 
-/*
- at Function cdiIterator_inqTile
- at Title Inquire the tile information for the current field
+  blocklen = binReadF77Block(fileID, byteswap);
 
- 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.
 
- at Result An error code. CDI_EINVAL if there is no tile information associated with the current field.
+  void *buffer = iegp->buffer;
+  if ( iegp->buffersize < blocklen )
+    {
+      iegp->buffer = buffer = Realloc(buffer, blocklen);
+      iegp->buffersize = blocklen;
+    }
 
- 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)
+  if ( dprec != (int) (blocklen/datasize) )
     {
-      #ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          return cdiGribIterator_inqTile(me, outTileIndex, outTileAttribute);
-      #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_inqTile(me, outTileIndex, outTileAttribute);
+  fileRead(fileID, buffer, blocklen);
 
-      default:
-        Error(kUnexpectedFileTypeMessage);
-        return CDI_ELIBNAVAIL;
+  blocklen2 = binReadF77Block(fileID, byteswap);
+
+  if ( blocklen2 != blocklen )
+    {
+      Warning("data blocklen differ!");
+      return -1;
     }
+
+  return 0;
 }
 
-/**
- 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.
+int iegWrite(int fileID, void *ieg)
+{
+  iegrec_t *iegp = (iegrec_t *) ieg;
+  union { INT32 i32[200]; float fvct[100]; } buf;
+  int dprec  = iegp->dprec;
+  int byteswap = iegp->byteswap;
 
- at Result An error code. CDI_EINVAL if there is no tile information associated with the current field.
+  /* write header record */
+  size_t blocklen = ( dprec == EXSE_SINGLE_PRECISION ) ? 636 : 1040;
 
- 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)
-    {
-      #ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          return cdiGribIterator_inqTileCount(me, outTileCount, outTileAttributeCount);
-      #endif
+  binWriteF77Block(fileID, byteswap, blocklen);
 
-      #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);
+  for ( size_t i = 0; i < 37; i++ ) buf.i32[i] = (INT32) iegp->ipdb[i];
+  binWriteInt32(fileID, byteswap, 37, buf.i32);
 
-      default:
-        Error(kUnexpectedFileTypeMessage);
-        return CDI_ELIBNAVAIL;
+  for ( size_t i = 0; i < 18; i++ ) buf.i32[i] = (INT32) iegp->igdb[i];
+  binWriteInt32(fileID, byteswap, 18, buf.i32);
+
+  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);
+
+  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 )
+    {
+      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);
     }
-}
 
-/*
- at Function cdiIterator_inqParam
- at Title Get discipline, category, and number
+  binWriteF77Block(fileID, byteswap, blocklen);
 
- at Prototype CdiParam cdiIterator_inqParam(CdiIterator* iterator)
- at Parameter
-    @item iterator The iterator to operate on.
+  size_t datasize = (size_t)iegp->igdb[4] * (size_t)iegp->igdb[5];
+  blocklen = datasize * (size_t)dprec;
 
- at Result A struct containing the requested information.
+  binWriteF77Block(fileID, byteswap, blocklen);
 
- at Description
-    Simple metadata inspection function.
-*/
-CdiParam cdiIterator_inqParam(CdiIterator* me)
-{
-  sanityCheck(me);
-  return me->param;
-}
+  iegp->datasize = datasize;
 
-/*
- at Function cdiIterator_inqParamParts
- at Title Get discipline, category, and number
+  void *buffer = iegp->buffer;
 
- 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.
+  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 Description
-    Simple metadata inspection function.
+  binWriteF77Block(fileID, byteswap, blocklen);
 
-    Some FORTRAN compilers produce wrong code for the cdiIterator_inqParam()-wrapper,
-    rendering it unusable from FORTRAN. This function is the workaround.
-*/
-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;
+  return 0;
 }
-
 /*
- at Function cdiIterator_inqDatatype
- at Title Get the datatype of the current field
-
- at Prototype int cdiIterator_inqDatatype(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 The datatype that is used to store this field on disk.
 
- at Description
-    Simple metadata inspection function.
-*/
-int cdiIterator_inqDatatype(CdiIterator* me)
-{
-  sanityCheck(me);
-  return me->datatype;
-}
+#include <sys/types.h>
+#include <stdlib.h>
 
 /*
- at Function cdiIterator_inqTsteptype
- at Title Get the timestep type
-
- at Prototype int cdiIterator_inqTsteptype(CdiIterator* iterator)
- at Parameter
-    @item iterator The iterator to operate on.
+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 Result The timestep type.
+>>> Warning <<<
+This code is currently not thread-safe.
 
- at Description
-    Simple metadata inspection function.
+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.
 */
-int cdiIterator_inqTsteptype(CdiIterator* me)
-{
-  sanityCheck(me);
-  return me->timesteptype;
-}
-
-/*
- at Function cdiIterator_inqVariableName
- at Title Get the variable name of the current field
+typedef struct CdiReferencedObject CdiReferencedObject;
+struct CdiReferencedObject {
+  //protected:
+    void (*destructor)(CdiReferencedObject* me);  //Subclass constructors should set this to their own destructor.
 
- at Prototype char* cdiIterator_inqVariableName(CdiIterator* iterator)
- at Parameter
-    @item iterator The iterator to operate on.
+  //private:    //Subclasses may read it to determine whether there is only one reference, though.
+    size_t refCount;
+};
 
- 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.
+void cdiRefObject_construct(CdiReferencedObject* me);
+void cdiRefObject_retain(CdiReferencedObject* me);
+void cdiRefObject_release(CdiReferencedObject* me);
+void cdiRefObject_destruct(CdiReferencedObject* me);
 
- 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)
-{
-  sanityCheck(me);
-  switch(me->filetype)
-    {
-#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);
+/*
+ * 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
 
-      default:
-        Error(kUnexpectedFileTypeMessage);
-        return NULL;
-    }
-}
 
 /*
- at Function cdiIterator_inqGridId
- at Title Get the ID of the current grid
+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_inqGridId(CdiIterator* iterator)
- at Parameter
-    @item iterator The iterator to operate on.
+  //private:
+    char* path;
+    int fileDescriptor;
+} CdiInputFile;
 
- at Result A gridId that can be used for further introspection.
+//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
-    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;
-}
+#endif
 
 /*
- at Function cdiIterator_readField
- at Title Read the whole field into a double buffer
+ * 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 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.
 
- 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)
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <string.h>
+#include <unistd.h>
+
+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);
-  if(!buffer) xabort("NULL was passed in a buffer. Please provide a suitable buffer.");
-  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:
-          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);
+      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;
 
-/*
- at Function cdiIterator_readFieldF
- at Title Read the whole field into a double buffer
+// ^        constructor code       ^
+// |                               |
+// v destructor/error-cleanup code v
 
- 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.
+destruct:
+  close(me->fileDescriptor);
+freePath:
+  Free(me->path);
+destructSuper:
+  cdiRefObject_destruct(super());
+  me = NULL;
 
- 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)
+success:
+  return me;
+  #undef super
+}
+
+static CdiInputFile **openFileList = NULL;
+static size_t openFileCount = 0, openFileListSize = 0;
+static pthread_mutex_t openFileListLock = PTHREAD_MUTEX_INITIALIZER;
+
+//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_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);
+      //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_delete
- at Title Destroy an iterator
-
- at Prototype void cdiIterator_delete(CdiIterator* iterator)
- at Parameter
-    @item iterator The iterator to operate on.
-
- at Description
-    Combined destructor & deallocator.
-*/
-void cdiIterator_delete(CdiIterator* me)
+int cdiInputFile_read(const CdiInputFile* me, off_t readPosition, size_t readSize, size_t* outActualReadSize, void* buffer)
 {
-  if(!me) xabort("NULL was passed in as an iterator. Please check the return value of cdiIterator_new().");
-  switch(me->filetype)
+  char* byteBuffer = (char *)buffer;
+  size_t trash;
+  if(!outActualReadSize) outActualReadSize = &trash;
+  *outActualReadSize = 0;
+  while(readSize)
     {
-#ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
-          cdiGribIterator_delete((CdiGribIterator*)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
-          cdiFallbackIterator_delete(me);
-          break;
-
-      default:
-        Error(kUnexpectedFileTypeMessage);
+      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;
 }
 
-void baseIterDestruct(CdiIterator* me)
+const char* cdiInputFile_getPath(const CdiInputFile* me)
 {
-  /*currently empty, but that's no reason not to call it*/
-  (void)me;
+  return me->path;
+}
+
+void cdiInputFile_destruct(CdiInputFile* me)
+{
+  int error = pthread_mutex_lock(&openFileListLock);
+  xassert(!error);
+    {
+      //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);
 }
 
 /*
@@ -31523,394 +30458,363 @@ void baseIterDestruct(CdiIterator* me)
  * 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);
 
-#include <assert.h>
-#include <limits.h>
-#include <stdlib.h>
-
-struct CdiFallbackIterator {
-  CdiIterator super;
-  int streamId, vlistId, subtypeId;
-  char *path;   //needed for clone() & serialize()
+void instituteDefaultEntries(void);
 
-  int variableCount, curVariable;
-  int curLevelCount, curLevel;
-  int curSubtypeCount, curSubtype;
-  int curTimestep;
-};
+#endif
 
-CdiIterator *cdiFallbackIterator_getSuper(CdiFallbackIterator *me)
-{
-  return &me->super;
-}
+/*
+ * 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 <assert.h>
+#include <limits.h>
 
-//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;
 
-  me = (CdiFallbackIterator *) Malloc(sizeof(*me));
-  baseIterConstruct(&me->super, filetype);
+#undef  CDI_UNDEFID
+#define CDI_UNDEFID  -1
 
-  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 ECMWF  = CDI_UNDEFID,
+  MPIMET = CDI_UNDEFID,
+  MCH    = CDI_UNDEFID;
 
-  //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;
+typedef struct
+{
+  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);
+  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)"); */
 
-  //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);
+  size_t n = sizeof(resH)/sizeof(*resH);
+
+  for (size_t i = 0; i < n ; i++ )
+    reshSetStatus(resH[i], &instituteOps, RESH_IN_USE);
 }
 
-CdiFallbackIterator *cdiFallbackIterator_clone(CdiIterator *super)
-{
-  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
 
-  //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;
+static int
+instituteCompareKernel(institute_t *  ip1, institute_t * ip2)
+{
+  int differ = 0;
+  size_t len1, len2;
 
-  //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;
+  if ( ip1->name )
+    {
+      if ( ip1->center    > 0 && ip2->center    != ip1->center )    differ = 1;
+      if ( ip1->subcenter > 0 && ip2->subcenter != ip1->subcenter ) differ = 1;
 
-  clone->super.isAdvanced = super->isAdvanced;
-  if(super->isAdvanced) fetchVariableInfo(clone);
+      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;
+    }
 
-  return clone;
+  return differ;
 }
 
-char *cdiFallbackIterator_serialize(CdiIterator *super)
-{
-  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
-
-  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;
-}
 
-CdiFallbackIterator *cdiFallbackIterator_deserialize(const char *description)
+struct instLoc
 {
-  CdiFallbackIterator *me = (CdiFallbackIterator *) Malloc(sizeof(*me));
-  if(!me) goto fail;
-
-  description = baseIter_constructFromString(&me->super, description);
+  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, 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;
+}
+
+static void institutePackP(void * instituteptr, void *buf, int size, int *position, void *context)
+{
+  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);
 }
 
-void cdiFallbackIterator_delete(CdiIterator *super)
+int instituteUnpack(void *buf, int size, int *position, int originNamespace,
+                    void *context, int force_id)
 {
-  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
-  cdiFallbackIterator_condestruct(me, NULL, 0);
+  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;
 }
 
 /*
@@ -31922,33 +30826,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>
 
-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);
+/*
+class CdiIterator
 
-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);
+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.
 
-int   grib1ltypeToZaxisType(int grib_ltype);
-int   grib2ltypeToZaxisType(int grib_ltype);
+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   zaxisTypeToGrib1ltype(int zaxistype);
-int   zaxisTypeToGrib2ltype(int zaxistype);
+    CdiIterator <|--+-- CdiFallbackIterator
+                    |
+                    +-- CdiGribIterator
+
+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"
@@ -31958,25 +30883,39 @@ 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);
 
-void cdiZaxisGetIndexList(unsigned numIDs, int *IDs);
+typedef struct CdiFallbackIterator CdiFallbackIterator;
 
-void
-zaxisUnpack(char * unpackBuffer, int unpackBufferSize,
-            int * unpackBufferPos, int originNamespace, void *context,
-            int force_id);
+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);
 
-void zaxisDefLtype2(int zaxisID, int ltype2);
+int cdiFallbackIterator_nextField(CdiIterator *me);
 
-const resOps *getZaxisOps(void);
+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);
 
-const char *zaxisInqNamePtr(int zaxisID);
+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
 
@@ -31989,989 +30928,1174 @@ const char *zaxisInqNamePtr(int zaxisID);
  * 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
 
-#include <assert.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-
-
-#ifdef HAVE_LIBGRIB_API
-
-struct CdiGribIterator {
-  CdiIterator super;
 
-  CdiInputFile *file;
-  off_t fileOffset;
-  unsigned char *gribBuffer;
-  size_t bufferSize, curRecordSize;
 #ifdef HAVE_LIBGRIB_API
-  grib_handle *gribHandle;
-#else
-  void *gribHandle;
+#include <grib_api.h>
 #endif
-};
-
-CdiIterator *cdiGribIterator_getSuper(CdiGribIterator *me)
-{
-  return &me->super;
-}
-
-//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)
-{
-#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;
+typedef struct recordList recordList;
 
-  goto success;
+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);
 
-// ^        constructor code        ^
-// |                                |
-// v destructor/error-cleanup code  v
+int cdiGribIterator_nextField(CdiIterator *me);
 
-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;
+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);
 
-success:
-  return me;
-#undef super
-}
+void cdiGribIterator_readField(CdiIterator *me, double *buffer, size_t *nmiss);
+void cdiGribIterator_readFieldF(CdiIterator *me, float *buffer, size_t *nmiss);
 
-CdiIterator *cdiGribIterator_new(const char *path, int filetype)
-{
-  return &cdiGribIterator_condestruct(NULL, path, filetype)->super;
-}
+#endif
 
-CdiGribIterator *cdiGribIterator_makeClone(CdiIterator *super)
-{
-  CdiGribIterator *me = (CdiGribIterator*)super;
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
 
-  //Allocate memory and copy data. (operations that may fail)
-  CdiGribIterator *result = (struct CdiGribIterator *) Malloc(sizeof(*result));
-  if(!result) goto fail;
+#include <assert.h>
+#include <ctype.h>
 
-  result->file = me->file;
-  result->fileOffset = me->fileOffset;
-  result->gribBuffer = NULL;
-  result->bufferSize = me->bufferSize;
-  result->curRecordSize = me->curRecordSize;
-  result->gribHandle = NULL;
+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";
 
-  if(me->gribBuffer)
-    {
-      result->gribBuffer = (unsigned char *) Malloc(me->bufferSize);
-      if(!result->gribBuffer) goto freeResult;
-      memcpy(result->gribBuffer, me->gribBuffer, me->curRecordSize);
-    }
-  if(me->gribHandle)
-    {
-      result->gribHandle = grib_handle_new_from_message(NULL, result->gribBuffer, result->curRecordSize);
-      if(!result->gribHandle) goto freeBuffer;
-    }
-  if(super->gridId != CDI_UNDEFID)
+//Returns a static string.
+static const char* fileType2String(int fileType)
+{
+  switch(fileType)
     {
-      result->super.gridId = gridDuplicate(super->gridId);
-      if(result->super.gridId == CDI_UNDEFID) goto deleteGribHandle;
-    }
-
-  //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;
+#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
 
-  //Error handling.
-deleteGribHandle:
-  if(result->gribHandle) grib_handle_delete(result->gribHandle);
-freeBuffer:
-  Free(result->gribBuffer);
-freeResult:
-  Free(result);
-fail:
-  return NULL;
+      default: return NULL;
+    }
 }
 
-char *cdiGribIterator_serialize(CdiIterator *super)
+static int string2FileType(const char* fileType, const char **outRestString)
 {
-  CdiGribIterator *me = (CdiGribIterator*)super;
+  //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
 
-  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;
+  //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;
 }
 
+/*
+ at Function cdiIterator_new
+ at Title Create an iterator for an input file
 
-CdiGribIterator *cdiGribIterator_deserialize(const char *description)
-{
-  char *path;
-  CdiGribIterator *me = (CdiGribIterator *) Malloc(sizeof(*me));
-  if(!me) goto fail;
-
-  description = baseIter_constructFromString(&me->super, description);
-
-  while(*description == ' ') description++;
-  path = cdiUnescapeSpaces(description, &description);
-  if(!path) goto destructSuper;
+ at Prototype CdiIterator* cdiIterator_new(const char* path)
+ at Parameter
+    @item path Path to the file that is to be read.
 
-  me->file = cdiInputFile_make(path);
-  Free(path);
-  if(!me->file) goto destructSuper;
+ at Result An iterator for the given file.
 
-  {
-    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;
-  }
+ at Description
+    Combined allocator and constructor for CdiIterator.
 
-  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;
+    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)
+{
+  int trash;
+  int filetype = cdiGetFiletype(path, &trash);
+  switch(filetype)
+    {
+      case FILETYPE_UNDEF:
+        Warning("Can't open file \"%s\": unknown format\n", path);
+        return NULL;
 
-  return me;
+#ifdef HAVE_LIBGRIB_API
+        case FILETYPE_GRB:
+        case FILETYPE_GRB2:
+          return cdiGribIterator_new(path, filetype);
+#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_new(path, filetype);
 
-closeFile:
-  cdiRefObject_release(&me->file->super);
-destructSuper:
-  baseIterDestruct(&me->super);
-  Free(me);
-fail:
-  return NULL;
+      default:
+        Warning("the file \"%s\" is of type %s, but support for this format is not compiled in!", path, strfiletype(filetype));
+        return NULL;
+    }
 }
 
-static void cdiGribIterator_ensureBuffer(CdiGribIterator *me, size_t requiredSize)
+void baseIterConstruct(CdiIterator* me, int filetype)
 {
-  if(me->bufferSize < requiredSize)
-    {
-      me->bufferSize *= 2;
-      if(me->bufferSize < requiredSize) me->bufferSize = requiredSize;
-      me->gribBuffer = (unsigned char *) Realloc(me->gribBuffer, me->bufferSize);
-    }
+  me->filetype = filetype;
+  me->isAdvanced = false;
 }
 
-static bool isGrib1DualLevel(int levelType)
+const char* baseIter_constructFromString(CdiIterator* me, const char* description)
 {
-  switch(levelType)
+  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))
     {
-      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;
+      me->isAdvanced = true;
+      result += sizeof (kAdvancedString) - 1;
     }
-}
-
-static const unsigned char *positionOfGribMarker(const unsigned char *data, size_t size)
-{
-  for(const unsigned char *currentPosition = data, *end = data + size; currentPosition < end; currentPosition++)
+  else if(result == strstr(result, kUnadvancedString))
     {
-      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;
+      me->isAdvanced = false;
+      result += sizeof (kUnadvancedString) - 1;
     }
-  return NULL;
+  else
+    {
+      Error("Invalid iterator description string \"%s\". Please check the origin of this string.", description);
+      return NULL;
+    }
+  return result;
 }
 
-//This clobbers the contents of the gribBuffer!
-//Returns the file offset of the next 'GRIB' marker.
-static ssize_t scanToGribMarker(CdiGribIterator *me)
+#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
+
+ at Prototype CdiIterator* cdiIterator_clone(CdiIterator* me)
+ at Parameter
+    @item iterator The iterator to copy.
+
+ at Result The clone.
+
+ at Description
+    Clones the given iterator. Make sure to call cdiIterator_delete() on both
+    the copy and the original.
+
+    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)
 {
-  cdiGribIterator_ensureBuffer(me, 8*1024);
-  const size_t kMaxScanSize = 16*1024*1024;
-  for(size_t scannedBytes = 0, scanSize; scannedBytes < kMaxScanSize; scannedBytes += scanSize)
+  sanityCheck(me);
+  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 FILETYPE_GRB:
+        case FILETYPE_GRB2:
+          return cdiGribIterator_getSuper(cdiGribIterator_clone(me));
+#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 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));
 
-      //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];
-}
+/*
+ at Function cdiGribIterator_clone
+ at Title Gain access to GRIB specific functionality
 
-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];
-  return result;
-}
+ at Prototype CdiGribIterator* cdiGribIterator_clone(CdiIterator* me)
+ at Parameter
+    @item iterator The iterator to operate on.
 
-//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)
+ 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)
 {
-  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])
+  sanityCheck(me);
+  switch(me->filetype)
     {
-      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;
-
-      case 2:
-        *outRecordSize =  decode64(&buffer[8]);
-        return CDI_NOERR;
+#ifdef HAVE_LIBGRIB_API
+        case FILETYPE_GRB:
+        case FILETYPE_GRB2:
+          return cdiGribIterator_makeClone(me);
+#endif
 
       default:
-        return CDI_EUFTYPE;
+        return NULL;
     }
 }
 
-#if 0
-static void hexdump(void *data, size_t size)
+/*
+ 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.
+
+ 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)
 {
-  unsigned char *charData = data;
-  for(size_t offset = 0; offset < size; )
+  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)
     {
-      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 FILETYPE_GRB:
+        case FILETYPE_GRB2:
+          subclassDescription = cdiGribIterator_serialize(me);
+          break;
 #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;
+#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;
 
-  return CDI_NOERR;
+      default:
+        Error(kUnexpectedFileTypeMessage);
+        return NULL;
+    }
 
-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.
+  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;
 }
 
-int cdiGribIterator_nextField(CdiIterator *super)
-{
-  CdiGribIterator *me = (CdiGribIterator*)super;
+/*
+ at Function cdiIterator_deserialize
+ at Title Recreate an iterator from its textual description
 
-  if(super->gridId != CDI_UNDEFID) gridDestroy(super->gridId), super->gridId = CDI_UNDEFID;
+ at Prototype CdiIterator* cdiIterator_deserialize(const char* description)
+ at Parameter
+    @item description The result of a call to cdiIterator_serialize().
 
-  //Get the next GRIB message into our buffer.
-  int result = readMessage(me);
-  if(result) return result;
+ at Result A clone of the original iterator.
 
-  //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 Description
+    A pair of cdiIterator_serialize() and cdiIterator_deserialize() is functionally equivalent to a call to cdiIterator_clone()
 
-  return CDI_NOERR;
+    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)
+{
+  switch(string2FileType(description, NULL))
+    {
+#ifdef HAVE_LIBGRIB_API
+        case FILETYPE_GRB:
+        case FILETYPE_GRB2:
+          return cdiGribIterator_getSuper(cdiGribIterator_deserialize(description));
+#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_deserialize(description));
+
+      default:
+        Error(kUnexpectedFileTypeMessage);
+        return NULL;
+    }
 }
 
-char *cdiGribIterator_inqTime(CdiIterator *super, CdiTimeType timeType)
+
+/*
+ at Function cdiIterator_print
+ at Title Print a textual description of the iterator to a stream
+
+ 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)
 {
-  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 FILETYPE_GRB:
+        case FILETYPE_GRB2:
+          return cdiGribIterator_nextField(me);
+#endif
 
-      case 255:
-        return 0;
+#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);
 
       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 FILETYPE_GRB:
+        case 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 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:
-        {
-          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)
+ 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.
+
+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)
 {
-  CdiGribIterator *me = (CdiGribIterator*)super;
-  int trash;
-  if(!outTileCount) outTileCount = &trash;
-  if(!outTileAttributeCount) outTileAttributeCount = &trash;
+  return cdiIterator_inqTime(me, kCdiTimeType_endTime);
+}
 
-  //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 Function cdiIterator_inqRTime
+ at Title Get the validity time of the current field
+
+ at Prototype char* cdiIterator_inqRTime(CdiIterator* me)
+ at Parameter
+    @item iterator The iterator to operate on.
 
-  //Ensure defined return values in case of failure.
-  if(error) *outTileCount = *outTileAttributeCount = 0;
-  return error;
-}
+ at Result A malloc'ed string containing the validity time of the current field in the format "YYYY-MM-DDTHH:MM:SS.mmm".
 
-char *cdiGribIterator_copyVariableName(CdiIterator *super)
+ 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)
 {
-  CdiGribIterator *me = (CdiGribIterator*)super;
-  return gribCopyString(me->gribHandle, "shortName");
+  return cdiIterator_inqTime(me, kCdiTimeType_referenceTime);
 }
 
-void cdiGribIterator_readField(CdiIterator *super, double *buffer, size_t *nmiss)
-{
-  CdiGribIterator *me = (CdiGribIterator*)super;
+/*
+ at Function cdiIterator_inqVTime
+ 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_inqVTime(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_inqVTime(CdiIterator* me)
+{
+  char* result = cdiIterator_inqEndTime(me);
+  return (result) ? result : cdiIterator_inqStartTime(me);
 }
-#endif
 
 /*
- at Function cdiGribIterator_delete
- at Title Dispose off a CdiGribIterator instance.
+ at Function cdiIterator_inqLevelType
+ at Title Get the type of a level
 
- at Prototype void cdiGribIterator_delete(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 delete.
+    @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 An integer indicating the type of the level.
 
 @Description
-    Combined destructor and deallocator. Make sure to match every call to cdiGribIterator_clone() with a call to this function.
+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.
 */
-void cdiGribIterator_delete(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
-  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");
+        case FILETYPE_GRB:
+        case FILETYPE_GRB2:
+          return cdiGribIterator_levelType(me, levelSelector, outName, outLongName, outStdName, outUnit);
 #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_levelType(me, levelSelector, outName, outLongName, outStdName, outUnit);
 
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// callthroughs to provide direct access to the grib keys //////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////////////////////////
+      default:
+        Error(kUnexpectedFileTypeMessage);
+        return CDI_UNDEFID;
+    }
+}
 
 /*
- at Function cdiGribIterator_inqEdition
- at Title Get the version of the GRIB standard that is used
+ at Function cdiIterator_inqLevel
+ at Title Get the value of the z-coordinate
 
- at Prototype int cdiGribIterator_inqEdition(CdiGribIterator *me)
+ at Prototype void cdiIterator_inqLevel(CdiIterator* me, int levelSelector, double* outValue1, double* outValue2 = 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 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 The GRIB version.
+ at Result An error code.
 
 @Description
-    Returns the version of the file format.
+Returns the value of the z-coordinate, whatever that may be.
 */
-int cdiGribIterator_inqEdition(CdiGribIterator *me)
+int cdiIterator_inqLevel(CdiIterator* me, int levelSelector, double* outValue1, double* outValue2)
 {
+  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 FILETYPE_GRB:
+        case FILETYPE_GRB2:
+          return cdiGribIterator_level(me, levelSelector, outValue1, outValue2);
+#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_level(me, levelSelector, outValue1, outValue2);
+
+      default:
+        Error(kUnexpectedFileTypeMessage);
+        return CDI_EINVAL;
+    }
 }
 
 /*
- at Function cdiGribIterator_getLong
- at Title Access to grib_get_long()
+ at Function cdiIterator_inqLevelUuid
+ at Title Get the UUID of the z-axis used by this field
 
- at Prototype int cdiGribIterator_getLong(CdiGribIterator *me, const char *key, long *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_long().
+Returns identifying information for the external z-axis description. May only be called for generalized levels.
 */
-int cdiGribIterator_getLong(CdiGribIterator *me, const char *key, long *result)
+int cdiIterator_inqLevelUuid(CdiIterator* me, int* outVgridNumber, int* outLevelCount, unsigned char outUuid[CDI_UUID_SIZE])
 {
+  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 FILETYPE_GRB:
+        case FILETYPE_GRB2:
+          return cdiGribIterator_zaxisUuid(me, outVgridNumber, outLevelCount, outUuid);
+#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_zaxisUuid(me, outVgridNumber, outLevelCount, outUuid);
+
+      default:
+        Error(kUnexpectedFileTypeMessage);
+        return CDI_ELIBNAVAIL;
+    }
 }
 
 /*
- at Function cdiGribIterator_getLength
- at Title Access to grib_get_length()
+ at Function cdiIterator_inqTile
+ at Title Inquire the tile information for the current field
 
- at Prototype int cdiGribIterator_getLength(CdiGribIterator *me, const char *key, size_t *result)
+ 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.
+ at Result An error code. CDI_EINVAL if there is no tile information associated with the current field.
 
 @Description
-    Callthrough to grib_get_length().
+Inquire the tile index and attribute for the current field.
 */
-int cdiGribIterator_getLength(CdiGribIterator *me, const char *key, size_t *result)
+int cdiIterator_inqTile(CdiIterator* me, int* outTileIndex, int* outTileAttribute)
 {
-#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");
-#endif
+  sanityCheck(me);
+  switch(me->filetype)
+    {
+      #ifdef HAVE_LIBGRIB_API
+        case FILETYPE_GRB:
+        case FILETYPE_GRB2:
+          return cdiGribIterator_inqTile(me, outTileIndex, outTileAttribute);
+      #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_inqTile(me, outTileIndex, outTileAttribute);
+
+      default:
+        Error(kUnexpectedFileTypeMessage);
+        return CDI_ELIBNAVAIL;
+    }
 }
 
-/*
- at Function cdiGribIterator_getString
- at Title Access to grib_get_string()
+/**
+ at Function cdiIterator_inqTileCount
+ at Title Inquire the tile count and tile attribute counts for the current field
 
- at Prototype int cdiGribIterator_getString(CdiGribIterator *me, const char *key, char *result, size_t *length)
+ at Prototype int cdiIterator_inqTileCount(CdiIterator* me, int* outTileCount, int* outTileAttributeCount)
 @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 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 FILETYPE_GRB:
+        case FILETYPE_GRB2:
+          return cdiGribIterator_inqTileCount(me, outTileCount, outTileAttributeCount);
+      #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_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 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;
+    }
 }
 
 /*
- 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 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);
+    }
 }
 
 /*
- 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 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);
+    }
 }
 
 /*
- 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 FILETYPE_GRB:
+        case 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 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;
 
-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"
@@ -32981,345 +32105,394 @@ void modelDefaultEntries(void);
  * require-trailing-newline: t
  * End:
  */
-#if defined (HAVE_CONFIG_H)
-#endif
 
-#include <limits.h>
 
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
 
-#undef  UNDEFID
-#define UNDEFID -1
+struct CdiFallbackIterator {
+  CdiIterator super;
+  int streamId, vlistId, subtypeId;
+  char *path;   //needed for clone() & serialize()
 
-static int ECHAM4 = UNDEFID,
-  ECHAM5 = UNDEFID,
-  COSMO  = UNDEFID;
+  int variableCount, curVariable;
+  int curLevelCount, curLevel;
+  int curSubtypeCount, curSubtype;
+  int curTimestep;
+};
 
-typedef struct
+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 = strdup(path);
+  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;
+  return &cdiFallbackIterator_condestruct(NULL, path, filetype)->super;
+}
 
-  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);
+//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)
+{
+  //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);
 
-  return (modelptr);
+  //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);
 }
 
-void modelDefaultEntries ( void )
+CdiFallbackIterator *cdiFallbackIterator_clone(CdiIterator *super)
 {
-  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);
+  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
 
-  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");
+  //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( 98, 255, "MPIMET", NULL);
-  resH[4] = modelDef(instID,  60, "ECHAM5.0");
-  resH[5] = ECHAM4  = modelDef(instID,  50, "ECHAM4");
-  resH[6] = modelDef(instID, 110, "MPIOM1");
+  //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,   0, "DWD", NULL);
-  resH[7] = modelDef(instID, 149, "GME");
+  clone->super.isAdvanced = super->isAdvanced;
+  if(super->isAdvanced) fetchVariableInfo(clone);
 
-  instID  = institutInq(  0,   0, "MCH", NULL);
-  //(void)  = modelDef(instID, 137, "COSMO");
-  resH[8] = COSMO   = modelDef(instID, 255, "COSMO");
+  return clone;
+}
 
-  instID  = institutInq(  0,   1, "NCEP", NULL);
-  resH[9] = modelDef(instID,  80, "T62L28MRF");
+char *cdiFallbackIterator_serialize(CdiIterator *super)
+{
+  CdiFallbackIterator *me = (CdiFallbackIterator*)(void *)super;
 
-  /* pre-defined models are not synchronized */
-  for ( i = 0; i < nDefModels ; i++ )
-    reshSetStatus(resH[i], &modelOps, RESH_IN_USE);
+  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;
 }
 
-static
-void modelInit(void)
+CdiFallbackIterator *cdiFallbackIterator_deserialize(const char *description)
 {
-  static int modelInitialized = 0;
+  CdiFallbackIterator *me = (CdiFallbackIterator *) Malloc(sizeof(*me));
+  if(!me) goto fail;
 
-  if (modelInitialized) return;
+  description = baseIter_constructFromString(&me->super, description);
 
-  modelInitialized = 1;
-  char *env = getenv("MODEL_DEBUG");
-  if ( env ) MODEL_Debug = atoi(env);
-}
+  while(*description == ' ') description++;
+  me->path = cdiUnescapeSpaces(description, &description);
+  if(!me->path) goto destructSuper;
 
-struct modelLoc
-{
-  const char *name;
-  int instID, modelgribID, resID;
-};
+  me->streamId = streamOpenRead(me->path);
+  if(me->streamId == CDI_UNDEFID) goto freePath;
+  me->vlistId = streamInqVlist(me->streamId);
+  if(me->vlistId == CDI_UNDEFID) goto closeStream;
 
-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;
+  //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;
+  int 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;
+  int 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);
 }
 
 /*
@@ -33331,1248 +32504,1439 @@ 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
+int   grbBitsPerValue(int datatype);
 
-#include <limits.h>
-#include <stdlib.h>
-#include <stdio.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);
 
-static unsigned nNamespaces = 1;
-static int activeNamespace = 0;
+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);
 
-#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_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);
 
-#else
-#define CDI_NETCDF_SWITCHES
-#endif
+int   grib1ltypeToZaxisType(int grib_ltype);
+int   grib2ltypeToZaxisType(int grib_ltype);
 
-#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   zaxisTypeToGrib1ltype(int zaxistype);
+int   zaxisTypeToGrib2ltype(int zaxistype);
 
-#if defined (SX) || defined (__cplusplus)
-static const union namespaceSwitchValue
-  defaultSwitches_[NUM_NAMESPACE_SWITCH] = defaultSwitches;
-#endif
+#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
 
-enum namespaceStatus {
-  NAMESPACE_STATUS_INUSE,
-  NAMESPACE_STATUS_UNUSED,
-};
+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];
+  cdi_atts_t atts;
+}
+zaxis_t;
 
-static struct Namespace
-{
-  enum namespaceStatus resStage;
-  union namespaceSwitchValue switches[NUM_NAMESPACE_SWITCH];
-} initialNamespace = {
-  .resStage = NAMESPACE_STATUS_INUSE,
-  .switches = defaultSwitches
-};
 
-static struct Namespace *namespaces = &initialNamespace;
+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.
 
-static unsigned namespacesSize = 1;
+unsigned cdiZaxisCount(void);
 
-#if  defined  (HAVE_LIBPTHREAD)
-#  include <pthread.h>
+zaxis_t *zaxis_to_pointer(int zaxisID);
 
-static pthread_once_t  namespaceOnce = PTHREAD_ONCE_INIT;
-static pthread_mutex_t namespaceMutex;
+void cdiZaxisGetIndexList(unsigned numIDs, int *IDs);
 
-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
+zaxisUnpack(char * unpackBuffer, int unpackBufferSize,
+            int * unpackBufferPos, int originNamespace, void *context,
+            int force_id);
 
-#  define NAMESPACE_LOCK()         pthread_mutex_lock(&namespaceMutex)
-#  define NAMESPACE_UNLOCK()       pthread_mutex_unlock(&namespaceMutex)
-#  define NAMESPACE_INIT()         pthread_once(&namespaceOnce, \
-                                                namespaceInitialize)
+void zaxisDefLtype2(int zaxisID, int ltype2);
 
+const resOps *getZaxisOps(void);
 
-#else
+const char *zaxisInqNamePtr(int zaxisID);
 
-#  define NAMESPACE_INIT() do { } while (0)
-#  define NAMESPACE_LOCK()
-#  define NAMESPACE_UNLOCK()
+const double *zaxisInqLevelsPtr(int zaxisID);
 
 #endif
 
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
+
 
-enum {
-  intbits = sizeof(int) * CHAR_BIT,
-  nspbits = 4,
-  idxbits = intbits - nspbits,
-  nspmask = (int)((( (unsigned)1 << nspbits ) - 1) << idxbits),
-  idxmask = ( 1 << idxbits ) - 1,
-};
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
 
-enum {
-  NUM_NAMESPACES = 1 << nspbits,
-  NUM_IDX = 1 << idxbits,
-};
 
+#ifdef HAVE_LIBGRIB_API
 
-int namespaceIdxEncode ( namespaceTuple_t tin )
-{
-  xassert ( tin.nsp < NUM_NAMESPACES && tin.idx < NUM_IDX);
-  return ( tin.nsp << idxbits ) + tin.idx;
-}
+struct CdiGribIterator {
+  CdiIterator super;
 
-int namespaceIdxEncode2 ( int nsp, int idx )
+  CdiInputFile *file;
+  off_t fileOffset;
+  unsigned char *gribBuffer;
+  size_t bufferSize, curRecordSize;
+#ifdef HAVE_LIBGRIB_API
+  grib_handle *gribHandle;
+#else
+  void *gribHandle;
+#endif
+};
+
+CdiIterator *cdiGribIterator_getSuper(CdiGribIterator *me)
 {
-  xassert(nsp < NUM_NAMESPACES && idx < NUM_IDX);
-  return ( nsp << idxbits ) + idx;
+  return &me->super;
 }
 
-
-namespaceTuple_t namespaceResHDecode ( int resH )
+//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)
 {
-  namespaceTuple_t tin;
+#define super() (&me->super)
+  if(me) goto destruct;
+  me = (CdiGribIterator *) Malloc(sizeof(*me));
+  baseIterConstruct(super(), filetype);
 
-  tin.idx = resH & idxmask;
-  tin.nsp = (int)(((unsigned)( resH & nspmask )) >> idxbits);
+  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;
 
-  return tin;
-}
+  goto success;
 
-int
-namespaceNew()
-{
-  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)
-    {
-      /* 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;
+// ^        constructor code        ^
+// |                                |
+// v destructor/error-cleanup code  v
+
+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;
+
+success:
+  return me;
+#undef super
 }
 
-void
-namespaceDelete(int namespaceID)
+CdiIterator *cdiGribIterator_new(const char *path, int filetype)
 {
-  NAMESPACE_INIT();
-  NAMESPACE_LOCK();
-  xassert(namespaceID >= 0 && (unsigned)namespaceID < namespacesSize
-          && nNamespaces);
-  reshListDestruct(namespaceID);
-  namespaces[namespaceID].resStage = NAMESPACE_STATUS_UNUSED;
-  --nNamespaces;
-  NAMESPACE_UNLOCK();
+  return &cdiGribIterator_condestruct(NULL, path, filetype)->super;
 }
 
-int namespaceGetNumber ()
+CdiGribIterator *cdiGribIterator_makeClone(CdiIterator *super)
 {
-  return (int)nNamespaces;
-}
+  CdiGribIterator *me = (CdiGribIterator*)super;
 
+  //Allocate memory and copy data. (operations that may fail)
+  CdiGribIterator *result = (struct CdiGribIterator *) Malloc(sizeof(*result));
+  if(!result) goto fail;
 
-void namespaceSetActive ( int nId )
-{
-  xassert((unsigned)nId < namespacesSize
-          && namespaces[nId].resStage != NAMESPACE_STATUS_UNUSED);
-  activeNamespace = nId;
-}
+  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)
+    {
+      result->gribBuffer = (unsigned char *) Malloc(me->bufferSize);
+      if(!result->gribBuffer) goto freeResult;
+      memcpy(result->gribBuffer, me->gribBuffer, me->curRecordSize);
+    }
+  if(me->gribHandle)
+    {
+      result->gribHandle = grib_handle_new_from_message(NULL, result->gribBuffer, result->curRecordSize);
+      if(!result->gribHandle) goto freeBuffer;
+    }
+  if(super->gridId != CDI_UNDEFID)
+    {
+      result->super.gridId = gridDuplicate(super->gridId);
+      if(result->super.gridId == CDI_UNDEFID) goto deleteGribHandle;
+    }
 
-int namespaceGetActive ()
-{
-  return activeNamespace;
+  //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;
 }
 
-int namespaceAdaptKey ( int originResH, int originNamespace )
+char *cdiGribIterator_serialize(CdiIterator *super)
 {
-  namespaceTuple_t tin;
-  int nsp;
+  CdiGribIterator *me = (CdiGribIterator*)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;
+    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;
+  }
 
-  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:
- */
+//This clobbers the contents of the gribBuffer!
+//Returns the file offset of the next 'GRIB' marker.
+static ssize_t scanToGribMarker(CdiGribIterator *me)
+{
+  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;
 
+      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_construct(CdiReferencedObject* 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;
+}
+
+static unsigned decode24(void *beData)
 {
-  me->destructor = cdiRefObject_destruct;
-  me->refCount = 1;
+  unsigned char *bytes = (unsigned char *)beData;
+  return ((unsigned)bytes[0] << 16) + ((unsigned)bytes[1] << 8) + (unsigned)bytes[2];
 }
 
-void cdiRefObject_retain(CdiReferencedObject* me)
+static uint64_t decode64(void *beData)
 {
-  size_t oldCount = me->refCount++;
-  xassert(oldCount && "A reference counted object was used after it was destructed.");
+  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;
 }
 
-void cdiRefObject_release(CdiReferencedObject* me)
+//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)
 {
-  size_t oldCount = me->refCount--;
-  xassert(oldCount && "A reference counted object was released too often.");
-  if(oldCount == 1)
+  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])
     {
-      me->destructor(me);
-      Free(me);
+      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;
+
+      case 2:
+        *outRecordSize =  decode64(&buffer[8]);
+        return CDI_NOERR;
+
+      default:
+        return CDI_EUFTYPE;
     }
 }
 
-void cdiRefObject_destruct(CdiReferencedObject* me)
+#if 0
+static void hexdump(void *data, size_t size)
 {
-  (void)me;
-  /* Empty for now, but that's no reason not to call it! */
+  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");
+    }
 }
-
-/*
- * 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()
+//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)
 {
-#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
-}
+  //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;
 
-enum { MIN_LIST_SIZE = 128 };
+  //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;
 
-static void listInitialize(void);
+  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;
+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;
+}
 
-struct resHList_t
+int cdiGribIterator_nextField(CdiIterator *super)
 {
-  int size, freeHead, hasDefaultRes;
-  listElem_t *resources;
-};
-
-static struct resHList_t *resHList;
-
-static int resHListSize = 0;
-
-#if  defined  (HAVE_LIBPTHREAD)
-#  include <pthread.h>
-
-static pthread_once_t  listInitThread = PTHREAD_ONCE_INIT;
-static pthread_mutex_t listMutex;
-
-#  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)
-
-
+  CdiGribIterator *me = (CdiGribIterator*)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*)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*)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;
+      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;
     }
-  listInitResources(namespaceID);
-  LIST_UNLOCK();
 }
 
+//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)
+{
+  assert(levelTypeKey && powerKey && valueKey && outValue1 && outValue2);
+
+  long levelType = gribGetLongDefault(gribHandle, levelTypeKey, 255);   //1 byte
+  switch(levelType)
+    {
+      case 255: break;
 
-/**************************************************************/
+      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;
+        }
 
-void
-reshListDestruct(int namespaceID)
-{
-  LIST_LOCK();
-  xassert(resHList && namespaceID >= 0 && namespaceID < resHListSize);
-  int callerNamespaceID = namespaceGetActive();
-  namespaceSetActive(namespaceID);
-  if (resHList[namespaceID].resources)
-    {
-      for ( int j = 0; j < resHList[namespaceID].size; j++ )
+      default:
         {
-          listElem_t *listElem = resHList[namespaceID].resources + j;
-          if (listElem->status & RESH_IN_USE_BIT)
-            listElem->res.v.ops->valDestroy(listElem->res.v.val);
+          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*)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;
-
-  resHList[nsp].resources = (listElem_t*) Realloc(resHList[nsp].resources,
-                                                   newListSize * sizeof(listElem_t));
+  CdiGribIterator *me = (CdiGribIterator*)super;
 
-  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;
-}
-
-/**************************************************************/
-
-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;
+  return CDI_NOERR;
 }
 
-int reshPut ( void *p, const resOps *ops )
+int cdiGribIterator_inqTile(CdiIterator *super, int *outTileIndex, int *outTileAttribute)
 {
-  xassert ( p && ops );
-
-  LIST_INIT(1);
+  CdiGribIterator *me = (CdiGribIterator*)super;
+  int trash;
+  if(!outTileIndex) outTileIndex = &trash;
+  if(!outTileAttribute) outTileAttribute = &trash;
 
-  LIST_LOCK();
+  //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;
 
-  int nsp = namespaceGetActive ();
+  //Ensure defined return values in case of failure.
+  if(error) *outTileIndex = *outTileAttribute = -1;
+  return error;
+}
 
-  if ( resHList[nsp].freeHead == -1) listSizeExtend();
-  int entry = resHList[nsp].freeHead;
-  cdiResH resH = namespaceIdxEncode2(nsp, entry);
-  reshPut_(nsp, entry, p, ops);
+int cdiGribIterator_inqTileCount(CdiIterator *super, int *outTileCount, int *outTileAttributeCount)
+{
+  CdiGribIterator *me = (CdiGribIterator*)super;
+  int trash;
+  if(!outTileCount) outTileCount = &trash;
+  if(!outTileAttributeCount) outTileAttributeCount = &trash;
 
-  LIST_UNLOCK();
+  //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;
 
-  return resH;
+  //Ensure defined return values in case of failure.
+  if(error) *outTileCount = *outTileAttributeCount = 0;
+  return error;
 }
 
-/**************************************************************/
-
-static void
-reshRemove_(int nsp, int idx)
+char *cdiGribIterator_copyVariableName(CdiIterator *super)
 {
-  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*)super;
+  return gribCopyString(me->gribHandle, "shortName");
 }
 
-void reshDestroy(cdiResH resH)
+void cdiGribIterator_readField(CdiIterator *super, double *buffer, size_t *nmiss)
 {
-  int nsp;
-  namespaceTuple_t nspT;
-
-  LIST_LOCK();
-
-  nsp = namespaceGetActive ();
-
-  nspT = namespaceResHDecode ( resH );
+  CdiGribIterator *me = (CdiGribIterator*)super;
 
-  xassert ( nspT.nsp == nsp
-            && nspT.idx >= 0
-            && nspT.idx < resHList[nsp].size
-            && resHList[nsp].resources[nspT.idx].res.v.ops);
+  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.
+    }
+}
 
-  if (resHList[nsp].resources[nspT.idx].status & RESH_IN_USE_BIT)
-    reshRemove_(nsp, nspT.idx);
+void cdiGribIterator_readFieldF(CdiIterator *super, float *buffer, size_t *nmiss)
+{
+  CdiGribIterator *me = (CdiGribIterator*)super;
 
-  LIST_UNLOCK();
+  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 reshRemove ( cdiResH resH, const resOps * ops )
-{
-  int nsp;
-  namespaceTuple_t nspT;
+/*
+ at Function cdiGribIterator_delete
+ at Title Dispose off a CdiGribIterator instance.
 
-  LIST_LOCK();
+ at Prototype void cdiGribIterator_delete(CdiGribIterator *me)
+ at Parameter
+    @item me The iterator to delete.
 
-  nsp = namespaceGetActive ();
+ 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)
+{
+#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
+}
 
-  nspT = namespaceResHDecode ( resH );
 
-  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 );
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// callthroughs to provide direct access to the grib keys //////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////
 
-  reshRemove_(nsp, nspT.idx);
+/*
+ at Function cdiGribIterator_inqEdition
+ at Title Get the version of the GRIB standard that is used
 
-  LIST_UNLOCK();
-}
+ at Prototype int cdiGribIterator_inqEdition(CdiGribIterator *me)
+ at Parameter
+    @item me The iterator to operate on.
 
-/**************************************************************/
+ at Result The GRIB version.
 
-void reshReplace(cdiResH resH, void *p, const resOps *ops)
+ at Description
+    Returns the version of the file format.
+*/
+int cdiGribIterator_inqEdition(CdiGribIterator *me)
 {
-  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 (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");
+#endif
 }
 
+/*
+ at Function cdiGribIterator_getLong
+ at Title Access to grib_get_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 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.
 
-  LIST_INIT(1);
+ at Result An error code.
 
-  LIST_LOCK();
+ at Description
+    Callthrough to grib_get_long().
+*/
+int cdiGribIterator_getLong(CdiGribIterator *me, const char *key, long *result)
+{
+#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");
+#endif
+}
 
-  nsp = namespaceGetActive ();
+/*
+ at Function cdiGribIterator_getLength
+ at Title Access to grib_get_length()
 
-  nspT = namespaceResHDecode ( resH );
-  assert(nspT.idx >= 0);
+ 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.
 
-  if (nspT.nsp == nsp &&
-      nspT.idx < resHList[nsp].size)
-    {
-      listElem = resHList[nsp].resources + nspT.idx;
-      LIST_UNLOCK();
-    }
-  else
-    {
-      LIST_UNLOCK();
-      show_stackframe();
+ at Result An error code.
 
-      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
+    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");
+#endif
+}
 
-  if ( !(listElem && listElem->res.v.ops == ops) )
-    {
-      show_stackframe();
+/*
+ at Function cdiGribIterator_getString
+ at Title Access to grib_get_string()
 
-      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 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.
 
-  return listElem;
-}
+ at Result An error code.
 
-void *reshGetValue(const char * caller, const char* expressionString, cdiResH resH, const resOps * ops)
+ at Description
+    Callthrough to grib_get_string().
+*/
+int cdiGribIterator_getString(CdiGribIterator *me, const char *key, char *result, size_t *length)
 {
-  return reshGetElem(caller, expressionString, resH, ops)->res.v.val;
+#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
 }
 
-/**************************************************************/
-
-void reshGetResHListOfType(unsigned numIDs, int resHs[], const resOps *ops)
-{
-  xassert ( resHs && ops );
-
-  LIST_INIT(1);
+/*
+ at Function cdiGribIterator_inqLongValue
+ at Title Get the value of a GRIB-API key as a long
 
-  LIST_LOCK();
+ 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.
 
-  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 The value of the key.
 
-  LIST_UNLOCK();
+ 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");
+#endif
 }
 
-enum cdiApplyRet
-cdiResHApply(enum cdiApplyRet (*func)(int id, void *res, const resOps *p,
-                                      void *data), void *data)
-{
-  xassert(func);
+/*
+ at Function cdiGribIterator_inqLongDefaultValue
+ at Title Get the value of a GRIB-API key as a long
 
-  LIST_INIT(1);
+ 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.
 
-  LIST_LOCK();
+ at Result The value of the key or the given default value.
 
-  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
+    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");
+#endif
 }
 
+/*
+ at Function cdiGribIterator_inqStringValue
+ at Title Safely retrieve a GRIB-API key with a string value
 
-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 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.
 
-  LIST_LOCK();
+ at Result A malloc'ed string or NULL.
 
-  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
+    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)
+{
+#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
 }
 
+/*
+ at Function cdiGribIterator_getDouble
+ at Title Access to grib_get_double()
 
+ 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.
 
+ at Result An error code.
 
-/**************************************************************/
-
-unsigned reshCountType(const resOps *ops)
+ at Description
+    Callthrough to grib_get_double().
+*/
+int cdiGribIterator_getDouble(CdiGribIterator *me, const char *key, double *result)
 {
-  unsigned countType = 0;
-
-  xassert(ops);
-
-  LIST_INIT(1);
-
-  LIST_LOCK();
+#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
+}
 
-  int nsp = namespaceGetActive ();
+/*
+ at Function cdiGribIterator_getSize
+ at Title Access to grib_get_size()
 
-  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 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_UNLOCK();
+ at Result An error code.
 
-  return countType;
+ 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");
+#endif
 }
 
-/**************************************************************/
+/*
+ at Function cdiGribIterator_getLongArray
+ at Title Access to grib_get_long_array()
 
-int
-reshResourceGetPackSize_intern(int resH, const resOps *ops, void *context, const char* caller, const char* expressionString)
-{
-  listElem_t *curr = reshGetElem(caller, expressionString, resH, ops);
-  return curr->res.v.ops->valGetPackSize(curr->res.v.val, context);
-}
+ 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.
 
-void
-reshPackResource_intern(int resH, const resOps *ops, void *buf, int buf_size, int *position, void *context,
-                        const char* caller, const char* expressionString)
+ at Result An error code.
+
+ at Description
+    Callthrough to grib_get_long_array().
+*/
+int cdiGribIterator_getLongArray(CdiGribIterator *me, const char *key, long *result, size_t *size)
 {
-  listElem_t *curr = reshGetElem(caller, expressionString, resH, ops);
-  curr->res.v.ops->valPack(curr->res.v.val, buf, buf_size, position, context);
+#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
 }
 
-enum {
-  resHPackHeaderNInt = 2,
-  resHDeleteNInt = 2,
-};
+/*
+ at Function cdiGribIterator_getDoubleArray
+ at Title Access to grib_get_double_array()
 
-static int getPackBufferSize(void *context)
-{
-  int intpacksize, packBufferSize = 0;
+ 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.
 
-  int nsp = namespaceGetActive ();
+ at Result An error code.
 
-  /* pack start marker, namespace and sererator marker */
-  packBufferSize += resHPackHeaderNInt * (intpacksize = serializeGetSize(1, DATATYPE_INT, context));
+ at Description
+    Callthrough to grib_get_double_array().
+*/
+int cdiGribIterator_getDoubleArray(CdiGribIterator *me, const char *key, double *result, size_t *size)
+{
+#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");
+#endif
+}
 
-  /* 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;
+/*
+ at Function cdiGribIterator_inqDoubleValue
+ at Title Get the value of a GRIB-API key as a double
 
-  return packBufferSize;
-}
+ 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.
 
-/**************************************************************/
+ at Result The value of the key.
 
-void reshPackBufferDestroy ( char ** buffer )
+ 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)
 {
-  if ( buffer ) free ( *buffer );
+#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");
+#endif
 }
 
-/**************************************************************/
+/*
+ at Function cdiGribIterator_inqDoubleDefaultValue
+ at Title Get the value of a GRIB-API key as a double
 
-int reshPackBufferCreate(char **packBuffer, int *packBufferSize, void *context)
-{
-  int i, packBufferPos = 0;
-  int end = END;
+ 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.
 
-  xassert ( packBuffer );
+ at Result The value of the key or the given default value.
 
-  LIST_LOCK();
+ 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)
+{
+#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");
+#endif
+}
 
-  int nsp = namespaceGetActive ();
+/*
+ * 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
 
-  int pBSize = *packBufferSize = getPackBufferSize(context);
-  char *pB = *packBuffer = (char *) Malloc((size_t)pBSize);
+int
+modelUnpack(void *buf, int size, int *position,
+            int originNamespace, void *context, int force_id);
 
-  {
-    int header[resHPackHeaderNInt] = { START, nsp };
-    serializePack(header, resHPackHeaderNInt,  DATATYPE_INT, pB, pBSize, &packBufferPos, context);
-  }
+void modelDefaultEntries(void);
 
-  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;
-      }
+#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
 
-  LIST_UNLOCK();
+#include <limits.h>
 
-  serializePack(&end, 1,  DATATYPE_INT, pB, pBSize, &packBufferPos, context);
-  return packBufferPos;
-}
 
-/**************************************************************/
+#undef  CDI_UNDEFID
+#define CDI_UNDEFID -1
 
-/* for thread safety this feature would have to be integrated in reshPut */
+static int ECHAM4 = CDI_UNDEFID,
+  ECHAM5 = CDI_UNDEFID,
+  COSMO  = CDI_UNDEFID;
 
-void reshSetStatus ( cdiResH resH, const resOps * ops, int status )
+typedef struct
 {
-  int nsp;
-  namespaceTuple_t nspT;
-  listElem_t * listElem;
+  int      self;
+  int      used;
+  int      instID;
+  int      modelgribID;
+  char    *name;
+}
+model_t;
 
-  xassert((ops != NULL) ^ !(status & RESH_IN_USE_BIT));
 
-  LIST_INIT(1);
+static int  MODEL_Debug = 0;   /* If set to 1, debugging */
 
-  LIST_LOCK();
+static void modelInit(void);
 
-  nsp = namespaceGetActive ();
 
-  nspT = namespaceResHDecode ( resH );
+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 );
 
-  xassert ( nspT.nsp == nsp &&
-            nspT.idx >= 0 &&
-            nspT.idx < resHList[nsp].size );
+static const resOps modelOps = {
+  modelCompareP,
+  modelDestroyP,
+  modelPrintP,
+  modelGetSizeP,
+  modelPackP,
+  modelTxCode
+};
 
-  xassert ( resHList[nsp].resources );
-  listElem = resHList[nsp].resources + nspT.idx;
+static
+void modelDefaultValue ( model_t *modelptr )
+{
+  modelptr->self        = CDI_UNDEFID;
+  modelptr->used        = 0;
+  modelptr->instID      = CDI_UNDEFID;
+  modelptr->modelgribID = CDI_UNDEFID;
+  modelptr->name        = NULL;
+}
 
-  xassert((!ops || (listElem->res.v.ops == ops))
-          && (listElem->status & RESH_IN_USE_BIT) == (status & RESH_IN_USE_BIT));
+static model_t *
+modelNewEntry(cdiResH resH, int instID, int modelgribID, const char *name)
+{
+  model_t *modelptr;
 
-  listElem->status = status;
+  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);
 
-  LIST_UNLOCK();
+  return (modelptr);
 }
 
-/**************************************************************/
-
-int reshGetStatus ( cdiResH resH, const resOps * ops )
+void modelDefaultEntries ( void )
 {
-  int nsp;
-  namespaceTuple_t nspT;
+  int instID, i;
+  enum { nDefModels = 10 };
+  cdiResH resH[nDefModels];
 
-  LIST_INIT(1);
+  instID  = institutInq(  0,   0, "ECMWF", NULL);
+  /* (void)    modelDef(instID, 131, "ERA15"); */
+  /* (void)    modelDef(instID, 199, "ERA40"); */
+  instID  = institutInq(  0,   0, "MPIMET", NULL);
 
-  LIST_LOCK();
+  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");
 
-  nsp = namespaceGetActive ();
+  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");
 
-  nspT = namespaceResHDecode ( resH );
+  instID  = institutInq(  0,   0, "DWD", NULL);
+  resH[7] = modelDef(instID, 149, "GME");
 
-  xassert ( nspT.nsp == nsp &&
-            nspT.idx >= 0 &&
-            nspT.idx < resHList[nsp].size );
+  instID  = institutInq(  0,   0, "MCH", NULL);
+  //(void)  = modelDef(instID, 137, "COSMO");
+  resH[8] = COSMO   = modelDef(instID, 255, "COSMO");
 
-  listElem_t *listElem = resHList[nsp].resources + nspT.idx;
+  instID  = institutInq(  0,   1, "NCEP", NULL);
+  resH[9] = modelDef(instID,  80, "T62L28MRF");
 
-  const resOps *elemOps = listElem->res.v.ops;
+  /* pre-defined models are not synchronized */
+  for ( i = 0; i < nDefModels ; i++ )
+    reshSetStatus(resH[i], &modelOps, RESH_IN_USE);
+}
 
-  LIST_UNLOCK();
+static
+void modelInit(void)
+{
+  static int modelInitialized = 0;
 
-  xassert(listElem && (!(listElem->status & RESH_IN_USE_BIT) || elemOps == ops));
+  if (modelInitialized) return;
 
-  return listElem->status;
+  modelInitialized = 1;
+  char *env = getenv("MODEL_DEBUG");
+  if ( env ) MODEL_Debug = atoi(env);
 }
 
-/**************************************************************/
-
-void reshLock ()
+struct modelLoc
 {
-  LIST_LOCK();
-}
-
-/**************************************************************/
+  const char *name;
+  int instID, modelgribID, resID;
+};
 
-void reshUnlock ()
+static enum cdiApplyRet
+findModelByID(int resID, void *res, void *data)
 {
-  LIST_UNLOCK();
+  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;
 }
 
-/**************************************************************/
-
-int reshListCompare ( int nsp0, int nsp1 )
+static enum cdiApplyRet
+findModelByName(int resID, void *res, void *data)
 {
-  LIST_INIT(1);
-  LIST_LOCK();
-
-  xassert(resHListSize > nsp0 && resHListSize > nsp1 &&
-          nsp0 >= 0 && nsp1 >= 0);
-
-  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++)
+  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)
     {
-      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)
+      const char *p = name, *q = modelptr->name;
+      while (*p != '\0' && *p == *q)
+        ++p, ++q;
+      if (*p == '\0' || *q == '\0')
         {
-          /* 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);
-            }
+          ret->resID = resID;
+          return CDI_APPLY_STOP;
         }
     }
-  /* 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);
+  return CDI_APPLY_GO_ON;
+}
+
+int modelInq(int instID, int modelgribID, const char *name)
+{
+  modelInit ();
 
-  LIST_UNLOCK();
+  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;
+}
 
-  return valCompare;
+
+int modelDef(int instID, int modelgribID, const char *name)
+{
+  model_t *modelptr;
+
+  modelInit ();
+
+  modelptr = modelNewEntry(CDI_UNDEFID, instID, modelgribID, name);
+
+  return modelptr->self;
 }
 
-/**************************************************************/
 
-void reshListPrint(FILE *fp)
+int modelInqInstitut(int modelID)
 {
-  int i, j, temp;
-  listElem_t * curr;
+  model_t *modelptr = NULL;
 
-  LIST_INIT(1);
+  modelInit ();
 
+  if ( modelID != CDI_UNDEFID )
+    modelptr = ( model_t * ) reshGetVal ( modelID, &modelOps );
 
-  temp = namespaceGetActive ();
+  return modelptr ? modelptr->instID : CDI_UNDEFID;
+}
 
-  fprintf ( fp, "\n\n##########################################\n#\n#  print " \
-            "global resource list \n#\n" );
 
-  for ( i = 0; i < namespaceGetNumber (); i++ )
-    {
-      namespaceSetActive ( i );
+int modelInqGribID(int modelID)
+{
+  model_t *modelptr = NULL;
 
-      fprintf ( fp, "\n" );
-      fprintf ( fp, "##################################\n" );
-      fprintf ( fp, "#\n" );
-      fprintf ( fp, "# namespace=%d\n", i );
-      fprintf ( fp, "#\n" );
-      fprintf ( fp, "##################################\n\n" );
+  modelInit ();
 
-      fprintf ( fp, "resHList[%d].size=%d\n", i, resHList[i].size );
+  if ( modelID != CDI_UNDEFID )
+    modelptr = ( model_t * ) reshGetVal ( modelID, &modelOps );
 
-      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" );
+  return modelptr ? modelptr->modelgribID : CDI_UNDEFID;
+}
 
-  namespaceSetActive ( temp );
+
+const char *modelInqNamePtr(int modelID)
+{
+  model_t *modelptr = NULL;
+
+  modelInit ();
+
+  if ( modelID != CDI_UNDEFID )
+    modelptr = ( model_t * ) reshGetVal ( modelID, &modelOps );
+
+  return modelptr ? modelptr->name : NULL;
 }
 
 
-/*
- * 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>
+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;
+}
 
 
-int
-serializeGetSize(int count, int datatype, void *context)
+void modelDestroyP ( void * modelptr )
 {
-  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);
+  model_t *mp = (model_t*) modelptr;
+  if (mp->name)
+    Free(mp->name);
+  Free(mp);
 }
 
-void serializePack(const void *data, int count, int datatype,
-                   void *buf, int buf_size, int *position, void *context)
+
+void modelPrintP   ( void * modelptr, FILE * fp )
 {
-  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);
+  model_t *mp = (model_t*) modelptr;
+
+  if ( !mp ) return;
+
+  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 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, DATATYPE_INT, context)
+    + (size_t)serializeGetSize(p->name?(int)strlen(p->name) + 1:0, 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, DATATYPE_INT, buf, size, position, context);
+  if (p->name)
+    serializePack(p->name, tempbuf[3], 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, 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;
 }
 
 /*
@@ -34587,3064 +33951,3217 @@ void serializeUnpackInCore(const void *buf, int buf_size, int *position,
 #if defined (HAVE_CONFIG_H)
 #endif
 
-#include <stdio.h>
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 600 /* PTHREAD_MUTEX_RECURSIVE */
+#endif
+
+#include <limits.h>
 #include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <ctype.h>
+#include <stdio.h>
 
 
+static unsigned nNamespaces = 1;
+static int activeNamespace = 0;
 
-enum {
-  SRV_HEADER_LEN = 8,
+#ifdef HAVE_LIBNETCDF
+#define CDI_NETCDF_SWITCHES                     \
+  { .func = (void (*)()) nc__create },          \
+  { .func = (void (*)()) cdf_def_var_serial },  \
+  { .func = (void (*)()) cdfDefTimestep },      \
+  { .func = (void (*)()) cdfDefVars }
+
+#else
+#define CDI_NETCDF_SWITCHES
+#endif
+
+#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                        \
+    }
+
+#if defined (SX) || defined (__cplusplus)
+static const union namespaceSwitchValue
+  defaultSwitches_[NUM_NAMESPACE_SWITCH] = defaultSwitches;
+#endif
+
+enum namespaceStatus {
+  NAMESPACE_STATUS_INUSE,
+  NAMESPACE_STATUS_UNUSED,
 };
 
+static struct Namespace
+{
+  enum namespaceStatus resStage;
+  union namespaceSwitchValue switches[NUM_NAMESPACE_SWITCH];
+} initialNamespace = {
+  .resStage = NAMESPACE_STATUS_INUSE,
+  .switches = defaultSwitches
+};
 
-static int initSrvLib      = 0;
-static int srvDefaultHprec = 0;
-static int srvDefaultDprec = 0;
+static struct Namespace *namespaces = &initialNamespace;
 
+static unsigned namespacesSize = 1;
 
-/*
- * 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__;
+#if  defined  (HAVE_LIBPTHREAD)
+#  include <pthread.h>
 
-const char *srvLibraryVersion(void)
+static pthread_once_t  namespaceOnce = PTHREAD_ONCE_INIT;
+static pthread_mutex_t namespaceMutex;
+
+static void
+namespaceInitialize(void)
 {
-  return srv_libvers;
+  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)
 
-static int SRV_Debug = 0;    /* If set to 1, debugging */
 
+#else
 
-void srvDebug(int debug)
+#  define NAMESPACE_INIT() do { } while (0)
+#  define NAMESPACE_LOCK()
+#  define NAMESPACE_UNLOCK()
+
+#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,
+};
+
+
+int namespaceIdxEncode ( namespaceTuple_t tin )
 {
-  SRV_Debug = debug;
+  xassert ( tin.nsp < NUM_NAMESPACES && tin.idx < NUM_IDX);
+  return ( tin.nsp << idxbits ) + tin.idx;
+}
 
-  if ( SRV_Debug )
-    Message("debug level %d", debug);
+int namespaceIdxEncode2 ( int nsp, int idx )
+{
+  xassert(nsp < NUM_NAMESPACES && idx < NUM_IDX);
+  return ( nsp << idxbits ) + idx;
 }
 
-static
-void srvLibInit()
+
+namespaceTuple_t namespaceResHDecode ( int resH )
 {
-  const char *envName = "SRV_PRECISION";
+  namespaceTuple_t tin;
 
-  char *envString = getenv(envName);
-  if ( envString )
-    {
-      int nrun;
-      if ( strlen(envString) == 2 ) nrun = 1;
-      else                          nrun = 2;
+  tin.idx = resH & idxmask;
+  tin.nsp = (int)(((unsigned)( resH & nspmask )) >> idxbits);
 
-      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;
-	}
+  return tin;
+}
+
+int
+namespaceNew()
+{
+  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)
+    {
+      /* 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;
+}
 
-  initSrvLib = 1;
+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();
 }
 
-static
-void srvInit(srvrec_t *srvp)
+int namespaceGetNumber ()
 {
-  srvp->checked    = 0;
-  srvp->byteswap   = 0;
-  srvp->hprec      = 0;
-  srvp->dprec      = 0;
-  srvp->datasize   = 0;
-  srvp->buffersize = 0;
-  srvp->buffer     = NULL;
+  return (int)nNamespaces;
 }
 
 
-void *srvNew(void)
+void namespaceSetActive ( int nId )
 {
-  if ( ! initSrvLib ) srvLibInit();
+  xassert((unsigned)nId < namespacesSize
+          && namespaces[nId].resStage != NAMESPACE_STATUS_UNUSED);
+  activeNamespace = nId;
+}
 
-  srvrec_t *srvp = (srvrec_t *) Malloc(sizeof(srvrec_t));
 
-  srvInit(srvp);
+int namespaceGetActive ()
+{
+  return activeNamespace;
+}
+
+int namespaceAdaptKey ( int originResH, int originNamespace )
+{
+  namespaceTuple_t tin;
+  int nsp;
+
+  if ( originResH == CDI_UNDEFID ) return CDI_UNDEFID;
 
-  return (void*)srvp;
-}
+  tin.idx = originResH & idxmask;
+  tin.nsp = (int)(((unsigned)( originResH & nspmask )) >> idxbits);
 
+  xassert ( tin.nsp == originNamespace );
 
-void srvDelete(void *srv)
-{
-  srvrec_t *srvp = (srvrec_t *) srv;
+  nsp = namespaceGetActive ();
 
-  if ( srvp )
-    {
-      if ( srvp->buffer ) Free(srvp->buffer);
-      Free(srvp);
-    }
+  return namespaceIdxEncode2 ( nsp, tin.idx );
 }
 
 
-int srvCheckFiletype(int fileID, int *swap)
+int namespaceAdaptKey2 ( int originResH )
 {
-  size_t data = 0;
-  size_t dimx = 0, dimy = 0;
-  size_t fact = 0;
-  int found = 0;
-  unsigned char buffer[72], *pbuf;
+  namespaceTuple_t tin;
+  int nsp;
 
-  if ( fileRead(fileID, buffer, 4) != 4 ) return found;
+  if ( originResH == CDI_UNDEFID ) return CDI_UNDEFID;
 
-  size_t blocklen  = (size_t) get_UINT32(buffer);
-  size_t sblocklen = (size_t) get_SUINT32(buffer);
+  tin.idx = originResH & idxmask;
+  tin.nsp = (int)(((unsigned)( originResH & nspmask )) >> idxbits);
 
-  if ( SRV_Debug )
-    Message("blocklen = %d sblocklen = %d", blocklen, sblocklen);
+  nsp = namespaceGetActive ();
 
-  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);
-    }
+  return namespaceIdxEncode2 ( nsp, tin.idx );
+}
 
-  fileRewind(fileID);
+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;
+}
 
-  if      ( data && dimx*dimy*fact == data ) found = 1;
-  else if ( data && dimx*dimy*8    == data ) found = 1;
+union namespaceSwitchValue namespaceSwitchGet(enum namespaceSwitch sw)
+{
+  xassert(sw > NSSWITCH_NO_SUCH_SWITCH && sw < NUM_NAMESPACE_SWITCH);
+  int nsp = namespaceGetActive();
+  return namespaces[nsp].switches[sw];
+}
 
-  if ( SRV_Debug )
+void cdiReset(void)
+{
+  NAMESPACE_INIT();
+  NAMESPACE_LOCK();
+  for (unsigned namespaceID = 0; namespaceID < namespacesSize; ++namespaceID)
+    if (namespaces[namespaceID].resStage != NAMESPACE_STATUS_UNUSED)
+      namespaceDelete((int)namespaceID);
+  if (namespaces != &initialNamespace)
     {
-      Message("swap = %d fact = %d", *swap, fact);
-      Message("dimx = %lu dimy = %lu data = %lu", dimx, dimy, data);
+      Free(namespaces);
+      namespaces = &initialNamespace;
+      namespaces[0].resStage = NAMESPACE_STATUS_UNUSED;
     }
-
-  return found;
+  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 srvInqHeader(void *srv, int *header)
-{
-  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);
+void cdiRefObject_construct(CdiReferencedObject* me)
+{
+  me->destructor = cdiRefObject_destruct;
+  me->refCount = 1;
+}
 
-  return 0;
+void cdiRefObject_retain(CdiReferencedObject* me)
+{
+  size_t oldCount = me->refCount++;
+  xassert(oldCount && "A reference counted object was used after it was destructed.");
 }
 
+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);
+    }
+}
 
-int srvDefHeader(void *srv, const int *header)
+void cdiRefObject_destruct(CdiReferencedObject* me)
 {
-  srvrec_t *srvp = (srvrec_t *) srv;
+  (void)me;
+  /* Empty for now, but that's no reason not to call it! */
+}
 
-  for ( size_t i = 0; i < SRV_HEADER_LEN; i++ )
-    srvp->header[i] = header[i];
+/*
+ * 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
 
-  srvp->datasize = (size_t)(header[4] * header[5]);
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 600 /* PTHREAD_MUTEX_RECURSIVE */
+#endif
 
-  if ( SRV_Debug )
-    Message("datasize = %lu", srvp->datasize);
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
 
-  return 0;
-}
+#if defined (HAVE_EXECINFO_H)
+#include <execinfo.h>
+#endif
 
 static
-int srvInqData(srvrec_t *srvp, int prec, void *data)
+void show_stackframe()
 {
-  size_t i;
-  int ierr = 0;
-  int byteswap = srvp->byteswap;
-  size_t datasize = srvp->datasize;
-  void *buffer = srvp->buffer;
-  int dprec = srvp->dprec;
+#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 ( dprec )
-    {
-    case EXSE_SINGLE_PRECISION:
-      {
-	if ( sizeof(FLT32) == 4 )
-	  {
-	    if ( byteswap ) swap4byte(buffer, datasize);
+  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
+}
 
-	    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;
-      }
-    }
+enum { MIN_LIST_SIZE = 128 };
 
-  return ierr;
-}
+static void listInitialize(void);
 
+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;
 
-int srvInqDataSP(void *srv, float *data)
+struct resHList_t
 {
-  return srvInqData((srvrec_t *)srv, EXSE_SINGLE_PRECISION, (void *) data);
-}
-
+  int size, freeHead, hasDefaultRes;
+  listElem_t *resources;
+};
 
-int srvInqDataDP(void *srv, double *data)
-{
-  return srvInqData((srvrec_t *)srv, EXSE_DOUBLE_PRECISION, (void *) data);
-}
+static struct resHList_t *resHList;
 
+static int resHListSize = 0;
 
-static int
-srvDefData(void *srv, int prec, const void *data)
-{
-  srvrec_t *srvp = (srvrec_t *) srv;
-  size_t i;
-  int dprec, hprec;
-  void *buffer;
+#if  defined  (HAVE_LIBPTHREAD)
+#  include <pthread.h>
 
-  if ( srvDefaultDprec ) dprec = srvDefaultDprec;
-  else                   dprec = srvp->dprec;
+static pthread_once_t  listInitThread = PTHREAD_ONCE_INIT;
+static pthread_mutex_t listMutex;
 
-  if ( ! dprec ) dprec = prec;
+#  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)
 
-  srvp->dprec = dprec;
 
-  if ( srvDefaultHprec ) hprec = srvDefaultHprec;
-  else                   hprec = srvp->hprec;
 
-  if ( ! hprec ) hprec = dprec;
+#else
 
-  srvp->hprec = hprec;
+static int listInit = 0;
 
-  int *header = srvp->header;
+#  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)
 
-  size_t datasize = (size_t)(header[4] * header[5]);
-  size_t blocklen = datasize * (size_t)dprec;
+#endif
 
-  srvp->datasize = datasize;
+/**************************************************************/
 
-  size_t buffersize = srvp->buffersize;
+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;
 
-  if ( buffersize != blocklen )
+  for (int i = 0; i < size; i++ )
     {
-      buffersize = blocklen;
-      buffer = srvp->buffer;
-      buffer = Realloc(buffer, buffersize);
-      srvp->buffer = buffer;
-      srvp->buffersize = buffersize;
+      p[i].res.free.next = i + 1;
+      p[i].res.free.prev = i - 1;
+      p[i].status = RESH_UNUSED;
     }
-  else
-    buffer = srvp->buffer;
 
-  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];
+  p[size-1].res.free.next = -1;
+  resHList[nsp].freeHead = 0;
+  int oldNsp = namespaceGetActive();
+  namespaceSetActive(nsp);
+  instituteDefaultEntries();
+  modelDefaultEntries();
+  namespaceSetActive(oldNsp);
+}
 
-	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];
+static inline void
+reshListClearEntry(int i)
+{
+  resHList[i].size = 0;
+  resHList[i].resources = NULL;
+  resHList[i].freeHead = -1;
+}
 
-	break;
-      }
-    default:
-      {
-	Error("unexpected data precision %d", dprec);
-        break;
-      }
+void
+reshListCreate(int namespaceID)
+{
+  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();
+}
 
-  return 0;
+
+/**************************************************************/
+
+void
+reshListDestruct(int namespaceID)
+{
+  LIST_LOCK();
+  xassert(resHList && namespaceID >= 0 && namespaceID < resHListSize);
+  int callerNamespaceID = namespaceGetActive();
+  namespaceSetActive(namespaceID);
+  if (resHList[namespaceID].resources)
+    {
+      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();
 }
 
 
-int srvDefDataSP(void *srv, const float *data)
+static void listDestroy ( void )
 {
-  return srvDefData(srv, EXSE_SINGLE_PRECISION, (void *) data);
+  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();
 }
 
+/**************************************************************/
 
-int srvDefDataDP(void *srv, const double *data)
+static
+void listInitialize ( void )
 {
-  return srvDefData(srv, EXSE_DOUBLE_PRECISION, (void *) data);
+#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 );
 }
 
+/**************************************************************/
 
-int srvRead(int fileID, void *srv)
+static
+void listSizeExtend()
 {
-  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;
+  int nsp = namespaceGetActive ();
+  int oldSize = resHList[nsp].size;
+  size_t newListSize = (size_t)oldSize + MIN_LIST_SIZE;
 
-  if ( ! srvp->checked )
+  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)
     {
-      status = srvCheckFiletype(fileID, &srvp->byteswap);
-      if ( status == 0 ) Error("Not a SERVICE file!");
-      srvp->checked = 1;
+      r[i].res.free.next = (int)i + 1;
+      r[i].res.free.prev = (int)i - 1;
+      r[i].status = RESH_UNUSED;
     }
 
-  int byteswap = srvp->byteswap;
+  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;
+}
+
+/**************************************************************/
+
+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 reshPut ( void *p, const resOps *ops )
+{
+  xassert ( p && ops );
 
-  /* read header record */
-  size_t blocklen = binReadF77Block(fileID, byteswap);
+  LIST_INIT(1);
 
-  if ( fileEOF(fileID) ) return -1;
+  LIST_LOCK();
 
-  if ( SRV_Debug )
-    Message("blocklen = %lu", blocklen);
+  int nsp = namespaceGetActive ();
 
-  size_t hprec = blocklen / SRV_HEADER_LEN;
+  if ( resHList[nsp].freeHead == -1) listSizeExtend();
+  int entry = resHList[nsp].freeHead;
+  cdiResH resH = namespaceIdxEncode2(nsp, entry);
+  reshPut_(nsp, entry, p, ops);
 
-  srvp->hprec = (int)hprec;
+  LIST_UNLOCK();
 
-  switch ( hprec )
-    {
-    case EXSE_SINGLE_PRECISION:
-      {
-	binReadInt32(fileID, byteswap, SRV_HEADER_LEN, tempheader.i32);
+  return resH;
+}
 
-	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);
+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;
+}
 
-	for ( i = 0; i < SRV_HEADER_LEN; i++ )
-          srvp->header[i] = (int)tempheader.i64[i];
+void reshDestroy(cdiResH resH)
+{
+  int nsp;
+  namespaceTuple_t nspT;
 
-	break;
-      }
-    default:
-      {
-	Error("Unexpected header precision %d", hprec);
-        break;
-      }
-    }
+  LIST_LOCK();
 
-  size_t blocklen2 = binReadF77Block(fileID, byteswap);
+  nsp = namespaceGetActive ();
 
-  if ( blocklen2 != blocklen )
-    {
-      Warning("Header blocklen differ (blocklen1=%d; blocklen2=%d)!", blocklen, blocklen2);
-      if ( blocklen2 != 0 ) return -1;
-    }
+  nspT = namespaceResHDecode ( resH );
 
-  srvp->datasize = (size_t)(srvp->header[4] * srvp->header[5]);
+  xassert ( nspT.nsp == nsp
+            && nspT.idx >= 0
+            && nspT.idx < resHList[nsp].size
+            && resHList[nsp].resources[nspT.idx].res.v.ops);
 
-  if ( SRV_Debug )
-    Message("datasize = %lu", srvp->datasize);
+  if (resHList[nsp].resources[nspT.idx].status & RESH_IN_USE_BIT)
+    reshRemove_(nsp, nspT.idx);
 
-  blocklen = binReadF77Block(fileID, byteswap);
+  LIST_UNLOCK();
+}
 
-  size_t buffersize = srvp->buffersize;
+void reshRemove ( cdiResH resH, const resOps * ops )
+{
+  int nsp;
+  namespaceTuple_t nspT;
 
-  if ( buffersize < blocklen )
-    {
-      buffersize = blocklen;
-      buffer = srvp->buffer;
-      buffer = Realloc(buffer, buffersize);
-      srvp->buffer = buffer;
-      srvp->buffersize = buffersize;
-    }
-  else
-    buffer = srvp->buffer;
+  LIST_LOCK();
 
-  size_t datasize = srvp->datasize;
+  nsp = namespaceGetActive ();
 
-  size_t dprec = blocklen / datasize;
+  nspT = namespaceResHDecode ( resH );
 
-  srvp->dprec = (int)dprec;
+  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 );
 
-  if ( dprec != EXSE_SINGLE_PRECISION && dprec != EXSE_DOUBLE_PRECISION )
-    {
-      Warning("Unexpected data precision %d", dprec);
-      return -1;
-    }
+  reshRemove_(nsp, nspT.idx);
 
-  fileRead(fileID, buffer, blocklen);
+  LIST_UNLOCK();
+}
 
-  blocklen2 = binReadF77Block(fileID, byteswap);
+/**************************************************************/
 
-  if ( blocklen2 != blocklen )
+void reshReplace(cdiResH resH, void *p, const resOps *ops)
+{
+  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)
     {
-      Warning("Data blocklen differ (blocklen1=%d; blocklen2=%d)!", blocklen, blocklen2);
-      if ( blocklen2 != 0 ) return -1;
+      q->res.v.ops->valDestroy(q->res.v.val);
+      reshRemove_(nsp, nspT.idx);
     }
-
-  return 0;
+  reshPut_(nsp, nspT.idx, p, ops);
+  LIST_UNLOCK();
 }
 
 
-void srvWrite(int fileID, void *srv)
+static listElem_t *
+reshGetElem(const char *caller, const char* expressionString, cdiResH resH, const resOps *ops)
 {
-  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);
+  listElem_t *listElem;
+  xassert ( ops );
 
-  switch ( hprec )
-    {
-    case EXSE_SINGLE_PRECISION:
-      {
-	for (i = 0; i < SRV_HEADER_LEN; i++)
-          tempheader.i32[i] = (INT32) header[i];
+  LIST_INIT(1);
 
-	binWriteInt32(fileID, byteswap, SRV_HEADER_LEN, tempheader.i32);
+  LIST_LOCK();
 
-	break;
-      }
-    case EXSE_DOUBLE_PRECISION:
-      {
-	for (i = 0; i < SRV_HEADER_LEN; i++)
-          tempheader.i64[i] = (INT64) header[i];
+  int nsp = namespaceGetActive ();
 
-	binWriteInt64(fileID, byteswap, SRV_HEADER_LEN, tempheader.i64);
+  namespaceTuple_t nspT = namespaceResHDecode ( resH );
+  assert(nspT.idx >= 0);
 
-	break;
-      }
-    default:
-      {
-	Error("unexpected header precision %d", hprec);
-        break;
-      }
+  if (nspT.nsp == nsp &&
+      nspT.idx < resHList[nsp].size)
+    {
+      listElem = resHList[nsp].resources + nspT.idx;
+      LIST_UNLOCK();
     }
+  else
+    {
+      LIST_UNLOCK();
+      show_stackframe();
 
-  binWriteF77Block(fileID, byteswap, blocklen);
-
-  size_t datasize = (size_t)(header[4] * header[5]);
-  blocklen = datasize * (size_t)dprec;
-
-  binWriteF77Block(fileID, byteswap, blocklen);
-
-  srvp->datasize = datasize;
-
-  void *buffer = srvp->buffer;
+      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);
+        }
+    }
 
-  switch ( dprec )
+  if ( !(listElem && listElem->res.v.ops == ops) )
     {
-    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;
-      }
+      show_stackframe();
+
+      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);
     }
 
-  binWriteF77Block(fileID, byteswap, blocklen);
+  return listElem;
 }
-/*
- * 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);
-
-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);
 
-void   srvReadVarDP (stream_t *streamptr, int varID,       double *data, int *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   srvWriteVarSliceDP(stream_t *streamptr, int varID, int levelID, const double *data);
-
-#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
-
-#ifndef _EXTRA_H
-#endif
+void *reshGetValue(const char * caller, const char* expressionString, cdiResH resH, const resOps * ops)
+{
+  return reshGetElem(caller, expressionString, resH, ops)->res.v.val;
+}
 
-int    extInqContents(stream_t *streamptr);
-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   extWriteRecord(stream_t *streamptr, const double *data);
+void reshGetResHListOfType(unsigned numIDs, int resHs[], const resOps *ops)
+{
+  xassert ( resHs && ops );
 
-void   extReadVarDP (stream_t *streamptr, int varID,       double *data, int *nmiss);
-void   extWriteVarDP(stream_t *streamptr, int varID, const double *data);
+  LIST_INIT(1);
 
-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);
+  LIST_LOCK();
 
-#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
+  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);
 
-#ifndef _IEG_H
-#endif
+  LIST_UNLOCK();
+}
 
-int    iegInqContents(stream_t *streamptr);
-int    iegInqTimestep(stream_t *streamptr, int tsID);
+enum cdiApplyRet
+cdiResHApply(enum cdiApplyRet (*func)(int id, void *res, const resOps *p,
+                                      void *data), void *data)
+{
+  xassert(func);
 
-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);
+  LIST_INIT(1);
 
-void   iegReadVarDP (stream_t *streamptr, int varID,       double *data, int *nmiss);
-void   iegWriteVarDP(stream_t *streamptr, int varID, const double *data);
+  LIST_LOCK();
 
-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);
+  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;
+}
 
-#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
 
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 600
-#endif
+enum cdiApplyRet
+cdiResHFilterApply(const resOps *p,
+                   enum cdiApplyRet (*func)(int id, void *res, void *data),
+                   void *data)
+{
+  xassert(p && func);
 
-#include <ctype.h>
+  LIST_INIT(1);
 
+  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;
+}
 
-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);
 
-const resOps streamOps = {
-  streamCompareP,
-  streamDestroyP,
-  streamPrintP,
-  streamGetPackSize,
-  streamPack,
-  streamTxCode
-};
 
 
+/**************************************************************/
 
-static
-int getByteorder(int byteswap)
+unsigned reshCountType(const resOps *ops)
 {
-  int byteorder = -1;
+  unsigned countType = 0;
 
-  switch (HOST_ENDIANNESS)
-    {
-    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");
-    }
-  return byteorder;
-}
+  xassert(ops);
 
-// used also in CDO
-int cdiGetFiletype(const char *filename, int *byteorder)
-{
-  int filetype = CDI_EUFTYPE;
-  int swap = 0;
-  int version;
-  long recpos;
-  char buffer[8];
+  LIST_INIT(1);
 
-  int fileID = fileOpen(filename, "r");
+  LIST_LOCK();
 
-  if ( fileID == CDI_UNDEFID )
-    {
-      if ( strncmp(filename, "http:", 5) == 0 || strncmp(filename, "https:", 6) == 0 )
-	return (FILETYPE_NC);
-      else
-	return (CDI_ESYSTEM);
-    }
+  int nsp = namespaceGetActive ();
 
-  if ( fileRead(fileID, buffer, 8) != 8 ) return (CDI_EUFTYPE);
+  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);
 
-  fileRewind(fileID);
+  LIST_UNLOCK();
 
-  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) )
-    {
-      filetype = FILETYPE_EXT;
-      if ( CDI_Debug ) Message("found EXT file = %s", filename);
-    }
-#endif
-#if  defined  (HAVE_LIBIEG)
-  else if ( iegCheckFiletype(fileID, &swap) )
-    {
-      filetype = FILETYPE_IEG;
-      if ( CDI_Debug ) Message("found IEG file = %s", filename);
-    }
-#endif
-#if  defined  (HAVE_LIBCGRIBEX)
-  else if ( gribCheckSeek(fileID, &recpos, &version) == 0 )
-    {
-      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
+  return countType;
+}
 
-  fileClose(fileID);
+/**************************************************************/
 
-  *byteorder = getByteorder(swap);
+int
+reshResourceGetPackSize_intern(int resH, const resOps *ops, void *context, const char* caller, const char* expressionString)
+{
+  listElem_t *curr = reshGetElem(caller, expressionString, resH, ops);
+  return curr->res.v.ops->valGetPackSize(curr->res.v.val, context);
+}
 
-  return (filetype);
+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);
 }
 
-/*
- at Function  streamInqFiletype
- at Title     Get the filetype
+enum {
+  resHPackHeaderNInt = 2,
+  resHDeleteNInt = 2,
+};
 
- at Prototype int streamInqFiletype(int streamID)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
+static int getPackBufferSize(void *context)
+{
+  int intpacksize, packBufferSize = 0;
 
- at Description
-The function @func{streamInqFiletype} returns the filetype of a stream.
+  int nsp = namespaceGetActive ();
 
- 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}.
+  /* pack start marker, namespace and sererator marker */
+  packBufferSize += resHPackHeaderNInt * (intpacksize = serializeGetSize(1, DATATYPE_INT, context));
 
- at EndFunction
-*/
-int streamInqFiletype(int streamID)
+  /* 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;
+}
+
+/**************************************************************/
+
+void reshPackBufferDestroy ( char ** buffer )
 {
-  stream_t *streamptr = stream_to_pointer(streamID);
-  return (streamptr->filetype);
+  if ( buffer ) free ( *buffer );
 }
 
+/**************************************************************/
 
-int getByteswap(int byteorder)
+int reshGetTxCode(cdiResH resH)
 {
-  int byteswap = -1;
+  int type = 0;
 
-  switch (byteorder)
+  LIST_LOCK();
+
+  int nsp = namespaceGetActive ();
+
+  namespaceTuple_t nspT = namespaceResHDecode ( resH );
+  assert(nspT.idx >= 0);
+
+  if (nspT.nsp == nsp &&
+      nspT.idx < resHList[nsp].size)
     {
-    case CDI_BIGENDIAN:
-    case CDI_LITTLEENDIAN:
-    case CDI_PDPENDIAN:
-      byteswap = (HOST_ENDIANNESS != byteorder);
-      break;
-    case -1:
-      break;
-    default:
-      Error("unexpected byteorder %d query!", byteorder);
+      listElem_t *listElem = resHList[nsp].resources + nspT.idx;
+      xassert ( listElem->res.v.ops );
+      type = listElem->res.v.ops->valTxCode();
     }
 
-  return (byteswap);
+  LIST_UNLOCK();
+
+  return type;
 }
 
-/*
- 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}.
+int reshPackBufferCreate(char **packBuffer, int *packBufferSize, void *context)
+{
+  int packBufferPos = 0;
+  int end = END;
 
- 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}.
+  xassert ( packBuffer );
 
- at EndFunction
-*/
-void streamDefByteorder(int streamID, int byteorder)
-{
-  stream_t *streamptr = stream_to_pointer(streamID);
-  streamptr->byteorder = byteorder;
-  int filetype = streamptr->filetype;
+  LIST_LOCK();
 
-  switch (filetype)
-    {
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      {
-	srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
-	srvp->byteswap = getByteswap(byteorder);
+  int nsp = namespaceGetActive ();
 
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      {
-	extrec_t *extp = (extrec_t*) streamptr->record->exsep;
-	extp->byteswap = getByteswap(byteorder);
+  int pBSize = *packBufferSize = getPackBufferSize(context);
+  char *pB = *packBuffer = (char *) Malloc((size_t)pBSize);
 
-	break;
-      }
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      {
-	iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
-	iegp->byteswap = getByteswap(byteorder);
+  {
+    int header[resHPackHeaderNInt] = { START, nsp };
+    serializePack(header, resHPackHeaderNInt,  DATATYPE_INT, pB, pBSize, &packBufferPos, context);
+  }
 
-	break;
+  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)
+          {
+            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;
       }
-#endif
-    }
-  reshSetStatus(streamID, &streamOps, RESH_DESYNC_IN_USE);
-}
 
-/*
- at Function  streamInqByteorder
- at Title     Get the byte order
+  LIST_UNLOCK();
 
- at Prototype int streamInqByteorder(int streamID)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
+  serializePack(&end, 1,  DATATYPE_INT, pB, pBSize, &packBufferPos, context);
 
- 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 packBufferPos;
+}
 
- 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)
+/* for thread safety this feature would have to be integrated in reshPut */
+
+void reshSetStatus ( cdiResH resH, const resOps * ops, int status )
 {
-  stream_t *streamptr = stream_to_pointer(streamID);
-  return (streamptr->byteorder);
-}
+  int nsp;
+  namespaceTuple_t nspT;
+  listElem_t * listElem;
 
+  xassert((ops != NULL) ^ !(status & RESH_IN_USE_BIT));
 
-const char *streamFilesuffix(int filetype)
-{
-  // 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]));
+  LIST_INIT(1);
 
-  if ( filetype > 0 && filetype < size )
-    return (fileSuffix[filetype]);
-  else
-    return (fileSuffix[0]);
-}
+  LIST_LOCK();
 
+  nsp = namespaceGetActive ();
 
-const char *streamFilename(int streamID)
-{
-  stream_t *streamptr = stream_to_pointer(streamID);
-  return (streamptr->filename);
-}
+  nspT = namespaceResHDecode ( resH );
 
-static
-long cdiInqTimeSize(int streamID)
-{
-  int tsID = 0, nrecs;
-  stream_t *streamptr = stream_to_pointer(streamID);
-  long ntsteps = streamptr->ntsteps;
+  xassert ( nspT.nsp == nsp &&
+            nspT.idx >= 0 &&
+            nspT.idx < resHList[nsp].size );
 
-  if ( ntsteps == (long)CDI_UNDEFID )
-    while ( (nrecs = streamInqTimestep(streamID, tsID++)) )
-      ntsteps = streamptr->ntsteps;
+  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;
 
-  return (ntsteps);
+  LIST_UNLOCK();
 }
 
-static
-int cdiInqContents(stream_t * streamptr)
+/**************************************************************/
+
+int reshGetStatus ( cdiResH resH, const resOps * ops )
 {
-  int status = 0;
+  int nsp;
+  namespaceTuple_t nspT;
 
-  int filetype = streamptr->filetype;
+  LIST_INIT(1);
 
-  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));
+  LIST_LOCK();
 
-	status = CDI_ELIBNAVAIL;
-        break;
-      }
-    }
+  nsp = namespaceGetActive ();
 
-  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);
-        }
-    }
+  nspT = namespaceResHDecode ( resH );
 
-  return (status);
+  xassert ( nspT.nsp == nsp &&
+            nspT.idx >= 0 &&
+            nspT.idx < resHList[nsp].size );
+
+  listElem_t *listElem = resHList[nsp].resources + nspT.idx;
+
+  const resOps *elemOps = listElem->res.v.ops;
+
+  LIST_UNLOCK();
+
+  xassert(listElem && (!(listElem->status & RESH_IN_USE_BIT) || elemOps == ops));
+
+  return listElem->status;
 }
 
-int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
-                                 int filetype, stream_t *streamptr,
-                                 int recordBufIsToBeCreated)
-{
-  int fileID;
-  switch (filetype)
-    {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-      {
-#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
-#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)
-          {
-            streamptr->record = (Record *) Malloc(sizeof(Record));
-            streamptr->record->buffer = NULL;
-            streamptr->record->exsep  = srvNew();
-          }
-        break;
-      }
-#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);
-      }
-    }
+void reshLock ()
+{
+  LIST_LOCK();
+}
 
-  streamptr->filetype = filetype;
+/**************************************************************/
 
-  return fileID;
+void reshUnlock ()
+{
+  LIST_UNLOCK();
 }
 
+/**************************************************************/
 
-int streamOpenID(const char *filename, char filemode, int filetype, int resH)
+int reshListCompare ( int nsp0, int nsp1 )
 {
-  int fileID = CDI_UNDEFID;
-  int status;
+  LIST_INIT(1);
+  LIST_LOCK();
+
+  xassert(resHListSize > nsp0 && resHListSize > nsp1 &&
+          nsp0 >= 0 && nsp1 >= 0);
+
+  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);
+
+  LIST_UNLOCK();
+
+  return valCompare;
+}
+
+/**************************************************************/
 
-  if ( CDI_Debug )
-    Message("Open %s mode %c file %s", strfiletype(filetype), filemode,
-            filename?filename:"(NUL)");
+void reshListPrint(FILE *fp)
+{
+  int i, j, temp;
+  listElem_t * curr;
 
-  if ( ! filename || filetype < 0 ) return (CDI_EINVAL);
+  LIST_INIT(1);
 
-  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;
+  temp = namespaceGetActive ();
 
-    fileID = streamOpenDelegate(filename, filemode, filetype, streamptr, 1);
-  }
+  fprintf ( fp, "\n\n##########################################\n#\n#  print " \
+            "global resource list \n#\n" );
 
-  if ( fileID < 0 )
-    {
-      streamID = fileID;
-    }
-  else
+  for ( i = 0; i < namespaceGetNumber (); i++ )
     {
-      streamID = streamptr->self;
+      namespaceSetActive ( i );
 
-      if ( streamID < 0 ) return CDI_ELIMIT;
+      fprintf ( fp, "\n" );
+      fprintf ( fp, "##################################\n" );
+      fprintf ( fp, "#\n" );
+      fprintf ( fp, "# namespace=%d\n", i );
+      fprintf ( fp, "#\n" );
+      fprintf ( fp, "##################################\n\n" );
 
-      streamptr->filemode = filemode;
-      streamptr->filename = strdupx(filename);
-      streamptr->fileID   = fileID;
+      fprintf ( fp, "resHList[%d].size=%d\n", i, resHList[i].size );
 
-      if ( filemode == 'r' )
+      for ( j = 0; j < resHList[i].size; j++ )
         {
-          int vlistID = vlistCreate();
-          if ( vlistID < 0 ) return(CDI_ELIMIT);
-
-          cdiVlistMakeInternal(vlistID);
-          streamptr->vlistID = vlistID;
-          /* cdiReadByteorder(streamID); */
-          status = cdiInqContents(streamptr);
-          if ( status < 0 )
-            {
-              streamID = status;
-            }
-          else
+          curr = resHList[i].resources + j;
+          if (!(curr->status & RESH_IN_USE_BIT))
             {
-              vlist_t *vlistptr = vlist_to_pointer(streamptr->vlistID);
-              vlistptr->ntsteps = streamptr->ntsteps;
-              cdiVlistMakeImmutable(vlistID);
+              curr->res.v.ops->valPrint(curr->res.v.val, fp);
+              fprintf ( fp, "\n" );
             }
         }
     }
+  fprintf ( fp, "#\n#  end global resource list" \
+            "\n#\n##########################################\n\n" );
 
-  if ( streamID < 0 )
-    {
-      Free(streamptr->record);
-      stream_delete_entry(streamptr);
-    }
+  namespaceSetActive ( temp );
+}
 
-  return streamID;
+
+/*
+ * 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>
+
+
+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);
 }
 
-static int streamOpen(const char *filename, const char *filemode, int filetype)
+void serializePack(const void *data, int count, int datatype,
+                   void *buf, int buf_size, int *position, void *context)
 {
-  if (!filemode || strlen(filemode) != 1) return CDI_EINVAL;
-  return streamOpenID(filename, (char)tolower(filemode[0]),
-                      filetype, CDI_UNDEFID);
+  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);
 }
 
-static int streamOpenA(const char *filename, const char *filemode, int filetype)
+void serializeUnpack(const void *buf, int buf_size, int *position,
+                     void *data, int count, int datatype, void *context)
 {
-  int fileID = CDI_UNDEFID;
-  int streamID = CDI_ESYSTEM;
-  int status;
-  stream_t *streamptr = stream_new_entry(CDI_UNDEFID);
-  vlist_t *vlistptr;
+  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);
+}
 
-  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
+serializeGetSizeInCore(int count, int datatype, void *context)
+{
+  int elemSize;
+  (void)context;
+  switch (datatype)
   {
-    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);
+  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;
+}
 
-  if ( fileID == CDI_UNDEFID || fileID == CDI_ELIBNAVAIL || fileID == CDI_ESYSTEM ) return (fileID);
+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;
+}
 
-  streamID = streamptr->self;
+void serializeUnpackInCore(const void *buf, int buf_size, int *position,
+                           void *data, int count, int datatype, void *context)
+{
+  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;
+}
 
-  streamptr->filemode = tolower(*filemode);
-  streamptr->filename = strdupx(filename);
-  streamptr->fileID   = fileID;
+/*
+ * 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
 
-  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);
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
 
-  {
-    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:
-      {
-        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);
-      }
-    }
+enum {
+  SRV_HEADER_LEN = 8,
+};
 
-  if ( fileID == CDI_UNDEFID )
-    streamID = CDI_UNDEFID;
-  else
-    streamptr->fileID = fileID;
 
-  return (streamID);
-}
+static int initSrvLib      = 0;
+static int srvDefaultHprec = 0;
+static int srvDefaultDprec = 0;
 
-/*
- at Function  streamOpenRead
- at Title     Open a dataset for reading
 
- at Prototype int streamOpenRead(const char *path)
- at Parameter
-    @Item  path  The name of the dataset to be read.
+/*
+ * 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 Description
-The function @func{streamOpenRead} opens an existing dataset for reading.
+const char *srvLibraryVersion(void)
+{
+  return srv_libvers;
+}
 
- 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
+static int SRV_Debug = 0;    /* If set to 1, debugging */
 
- 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
- at EndFunction
-*/
-int streamOpenRead(const char *filename)
+void srvDebug(int debug)
 {
-  cdiInitialize();
-
-  int byteorder = 0;
-  int filetype = cdiGetFiletype(filename, &byteorder);
+  SRV_Debug = debug;
 
-  if ( filetype < 0 ) return (filetype);
+  if ( SRV_Debug )
+    Message("debug level %d", debug);
+}
 
-  int streamID = streamOpen(filename, "r", filetype);
+static
+void srvLibInit()
+{
+  const char *envName = "SRV_PRECISION";
 
-  if ( streamID >= 0 )
+  char *envString = getenv(envName);
+  if ( envString )
     {
-      stream_t *streamptr = stream_to_pointer(streamID);
-      streamptr->byteorder = byteorder;
+      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;
+	}
     }
 
-  return (streamID);
+  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;
+}
 
-int streamOpenAppend(const char *filename)
+
+void *srvNew(void)
 {
-  cdiInitialize();
+  if ( ! initSrvLib ) srvLibInit();
 
-  int byteorder = 0;
-  int filetype = cdiGetFiletype(filename, &byteorder);
+  srvrec_t *srvp = (srvrec_t *) Malloc(sizeof(srvrec_t));
+
+  srvInit(srvp);
 
-  if ( filetype < 0 ) return (filetype);
+  return (void*)srvp;
+}
 
-  int streamID = streamOpenA(filename, "a", filetype);
 
-  if ( streamID >= 0 )
+void srvDelete(void *srv)
+{
+  srvrec_t *srvp = (srvrec_t *) srv;
+
+  if ( srvp )
     {
-      stream_t *streamptr = stream_to_pointer(streamID);
-      streamptr->byteorder = byteorder;
+      if ( srvp->buffer ) Free(srvp->buffer);
+      Free(srvp);
     }
-
-  return (streamID);
 }
 
-/*
- at Function  streamOpenWrite
- at Title     Create a new dataset
 
- 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}.
+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;
 
- 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.
+  if ( fileRead(fileID, buffer, 4) != 4 ) return found;
 
- 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
+  size_t blocklen  = (size_t) get_UINT32(buffer);
+  size_t sblocklen = (size_t) get_SUINT32(buffer);
 
- at Example
-Here is an example using @func{streamOpenWrite} to create a new NetCDF file named @func{foo.nc} for writing:
+  if ( SRV_Debug )
+    Message("blocklen = %d sblocklen = %d", blocklen, sblocklen);
 
- 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)
+  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);
+
+  if      ( data && dimx*dimy*fact == data ) found = 1;
+  else if ( data && dimx*dimy*8    == data ) found = 1;
+
+  if ( SRV_Debug )
+    {
+      Message("swap = %d fact = %d", *swap, fact);
+      Message("dimx = %lu dimy = %lu data = %lu", dimx, dimy, data);
+    }
+
+  return found;
+}
+
+
+int srvInqHeader(void *srv, int *header)
 {
-  cdiInitialize();
+  srvrec_t *srvp = (srvrec_t *) srv;
+
+  for ( size_t i = 0; i < SRV_HEADER_LEN; i++ )
+    header[i] = srvp->header[i];
 
-  return (streamOpen(filename, "w", filetype));
+  if ( SRV_Debug )
+    Message("datasize = %lu", srvp->datasize);
+
+  return 0;
 }
 
-static
-void streamDefaultValue ( stream_t * streamptr )
+
+int srvDefHeader(void *srv, const int *header)
 {
-  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;
+  srvrec_t *srvp = (srvrec_t *) srv;
 
-  basetimeInit(&streamptr->basetime);
+  for ( size_t i = 0; i < SRV_HEADER_LEN; i++ )
+    srvp->header[i] = header[i];
 
-  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;
+  srvp->datasize = (size_t)(header[4] * header[5]);
 
-  streamptr->gribContainers    = NULL;
-}
+  if ( SRV_Debug )
+    Message("datasize = %lu", srvp->datasize);
 
+  return 0;
+}
 
-static stream_t *stream_new_entry(int resH)
+static
+int srvInqData(srvrec_t *srvp, int prec, void *data)
 {
-  stream_t *streamptr;
-
-  cdiInitialize(); /* ***************** make MT version !!! */
+  size_t i;
+  int ierr = 0;
+  int byteswap = srvp->byteswap;
+  size_t datasize = srvp->datasize;
+  void *buffer = srvp->buffer;
+  int dprec = srvp->dprec;
 
-  streamptr = (stream_t *) Malloc(sizeof(stream_t));
-  streamDefaultValue ( streamptr );
-  if (resH == CDI_UNDEFID)
-    streamptr->self = reshPut(streamptr, &streamOps);
-  else
+  switch ( dprec )
     {
-      streamptr->self = resH;
-      reshReplace(resH, streamptr, &streamOps);
+    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 streamptr;
+  return ierr;
 }
 
 
-void
-cdiStreamCloseDefaultDelegate(stream_t *streamptr, int recordBufIsToBeDeleted)
+int srvInqDataSP(void *srv, float *data)
 {
-  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;
-        }
-      }
+  return srvInqData((srvrec_t *)srv, EXSE_SINGLE_PRECISION, (void *) data);
 }
 
 
-static void deallocate_sleveltable_t(sleveltable_t *entry)
+int srvInqDataDP(void *srv, double *data)
 {
-  if (entry->recordID) Free(entry->recordID);
-  if (entry->lindex)   Free(entry->lindex);
-  entry->recordID = NULL;
-  entry->lindex   = NULL;
+  return srvInqData((srvrec_t *)srv, EXSE_DOUBLE_PRECISION, (void *) data);
 }
 
 
-/*
- at Function  streamClose
- at Title     Close an open dataset
+static int
+srvDefData(void *srv, int prec, const void *data)
+{
+  srvrec_t *srvp = (srvrec_t *) srv;
+  size_t i;
+  int dprec, hprec;
+  void *buffer;
 
- at Prototype  void streamClose(int streamID)
- at Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
+  if ( srvDefaultDprec ) dprec = srvDefaultDprec;
+  else                   dprec = srvp->dprec;
 
- at Description
-The function @func{streamClose} closes an open dataset.
+  if ( ! dprec ) dprec = prec;
 
- at EndFunction
-*/
-void streamClose(int streamID)
-{
-  int index;
-  stream_t *streamptr = stream_to_pointer(streamID);
+  srvp->dprec = dprec;
 
-  if ( CDI_Debug )
-    Message("streamID = %d filename = %s", streamID, streamptr->filename);
+  if ( srvDefaultHprec ) hprec = srvDefaultHprec;
+  else                   hprec = srvp->hprec;
 
-  int vlistID  = streamptr->vlistID;
+  if ( ! hprec ) hprec = dprec;
 
-  void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
-    = (void (*)(stream_t *, int))
-    namespaceSwitchGet(NSSWITCH_STREAM_CLOSE_BACKEND).func;
+  srvp->hprec = hprec;
 
-  if ( streamptr->filetype != -1 ) streamCloseDelegate(streamptr, 1);
+  int *header = srvp->header;
 
-  if ( streamptr->record )
-    {
-      if ( streamptr->record->buffer )
-        Free(streamptr->record->buffer);
+  size_t datasize = (size_t)(header[4] * header[5]);
+  size_t blocklen = datasize * (size_t)dprec;
 
-      Free(streamptr->record);
-    }
+  srvp->datasize = datasize;
 
-  streamptr->filetype = 0;
-  if ( streamptr->filename ) Free(streamptr->filename);
+  size_t buffersize = srvp->buffersize;
 
-  for ( index = 0; index < streamptr->nvars; index++ )
+  if ( buffersize != blocklen )
     {
-      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);
+      buffersize = blocklen;
+      buffer = srvp->buffer;
+      buffer = Realloc(buffer, buffersize);
+      srvp->buffer = buffer;
+      srvp->buffersize = buffersize;
     }
-  Free(streamptr->vars);
-  streamptr->vars = NULL;
+  else
+    buffer = srvp->buffer;
 
-  for ( index = 0; index < streamptr->ntsteps; ++index )
+  switch ( dprec )
     {
-      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);
+    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];
 
-  if ( vlistID != -1 )
-    {
-      if ( streamptr->filemode != 'w' )
-	if ( vlistInqTaxis(vlistID) != -1 )
-	  {
-	    taxisDestroy(vlistInqTaxis(vlistID));
-	  }
+	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];
 
-      cdiVlistDestroy_(vlistID);
+	break;
+      }
+    default:
+      {
+	Error("unexpected data precision %d", dprec);
+        break;
+      }
     }
 
-  stream_delete_entry(streamptr);
+  return 0;
 }
 
-static void stream_delete_entry(stream_t *streamptr)
-{
-  int idx;
-
-  xassert ( streamptr );
-
-  idx = streamptr->self;
-  Free( streamptr );
-  reshRemove ( idx, &streamOps );
 
-  if ( CDI_Debug )
-    Message("Removed idx %d from stream list", idx);
+int srvDefDataSP(void *srv, const float *data)
+{
+  return srvDefData(srv, EXSE_SINGLE_PRECISION, (void *) data);
 }
 
 
-void cdiStreamSync_(stream_t *streamptr)
+int srvDefDataDP(void *srv, const double *data)
 {
-  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
-    {
-      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;
-	      }
-	    }
-	}
-    }
+  return srvDefData(srv, EXSE_DOUBLE_PRECISION, (void *) data);
 }
 
-/*
- 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.
 
- at EndFunction
-*/
-void streamSync(int streamID)
+int srvRead(int fileID, void *srv)
 {
-  stream_t *streamptr = stream_to_pointer(streamID);
+  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;
 
-  void (*myStreamSync_)(stream_t *streamptr)
-    = (void (*)(stream_t *))namespaceSwitchGet(NSSWITCH_STREAM_SYNC).func;
-  myStreamSync_(streamptr);
-}
+  if ( ! srvp->checked )
+    {
+      status = srvCheckFiletype(fileID, &srvp->byteswap);
+      if ( status == 0 ) Error("Not a SERVICE file!");
+      srvp->checked = 1;
+    }
 
+  int byteswap = srvp->byteswap;
 
-int cdiStreamDefTimestep_(stream_t *streamptr, int tsID)
-{
-  int taxisID = 0;
+  /* read header record */
+  size_t blocklen = binReadF77Block(fileID, byteswap);
 
-  stream_check_ptr(__func__, streamptr);
+  if ( fileEOF(fileID) ) return -1;
 
-  if ( CDI_Debug )
-    Message("streamID = %d  tsID = %d", streamptr->self, tsID);
+  if ( SRV_Debug )
+    Message("blocklen = %lu", blocklen);
 
-  int vlistID = streamptr->vlistID;
+  size_t hprec = blocklen / SRV_HEADER_LEN;
 
-  int time_is_varying = vlistHasTime(vlistID);
+  srvp->hprec = (int)hprec;
 
-  if ( time_is_varying )
+  switch ( hprec )
     {
-      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);
-        }
-    }
+    case EXSE_SINGLE_PRECISION:
+      {
+	binReadInt32(fileID, byteswap, SRV_HEADER_LEN, tempheader.i32);
 
-  int newtsID = tstepsNewEntry(streamptr);
+	for ( i = 0; i < SRV_HEADER_LEN; i++ )
+          srvp->header[i] = (int)tempheader.i32[i];
 
-  if ( tsID != newtsID )
-    Error("Internal problem: tsID = %d newtsID = %d", tsID, newtsID);
+	break;
+      }
+    case EXSE_DOUBLE_PRECISION:
+      {
+	binReadInt64(fileID, byteswap, SRV_HEADER_LEN, tempheader.i64);
 
-  streamptr->curTsID = tsID;
+	for ( i = 0; i < SRV_HEADER_LEN; i++ )
+          srvp->header[i] = (int)tempheader.i64[i];
 
-  if ( time_is_varying )
-    {
-      taxis_t *taxisptr1 = taxisPtr(taxisID);
-      taxis_t *taxisptr2 = &streamptr->tsteps[tsID].taxis;
-      ptaxisCopy(taxisptr2, taxisptr1);
+	break;
+      }
+    default:
+      {
+	Error("Unexpected header precision %d", hprec);
+        break;
+      }
     }
 
-  streamptr->ntsteps = tsID + 1;
+  size_t blocklen2 = binReadF77Block(fileID, byteswap);
 
-#ifdef HAVE_LIBNETCDF
-  if ((streamptr->filetype == FILETYPE_NC  ||
-       streamptr->filetype == FILETYPE_NC2 ||
-       streamptr->filetype == FILETYPE_NC4 ||
-       streamptr->filetype == FILETYPE_NC4C)
-      && time_is_varying)
+  if ( blocklen2 != blocklen )
     {
-      void (*myCdfDefTimestep)(stream_t *streamptr, int tsID)
-        = (void (*)(stream_t *, int))
-        namespaceSwitchGet(NSSWITCH_CDF_DEF_TIMESTEP).func;
-      myCdfDefTimestep(streamptr, tsID);
+      Warning("Header blocklen differ (blocklen1=%d; blocklen2=%d)!", blocklen, blocklen2);
+      if ( blocklen2 != 0 ) return -1;
     }
-#endif
-
-  cdi_create_records(streamptr, tsID);
-
-  return (int)streamptr->ntsteps;
-}
-
-/*
- at Function  streamDefTimestep
- at Title     Define time step
-
- 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.
 
- at Description
-The function @func{streamDefTimestep} defines the time step of a stream.
-
- at Result
- at func{streamDefTimestep} returns the number of records of the time step.
-
- at EndFunction
-*/
-int streamDefTimestep(int streamID, int tsID)
-{
-  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);
-}
+  srvp->datasize = (size_t)(srvp->header[4] * srvp->header[5]);
 
-int streamInqCurTimestepID(int streamID)
-{
-  stream_t *streamptr = stream_to_pointer(streamID);
-  return streamptr->curTsID;
-}
+  if ( SRV_Debug )
+    Message("datasize = %lu", srvp->datasize);
 
+  blocklen = binReadF77Block(fileID, byteswap);
 
-/*
- at Function  streamInqTimestep
- at Title     Get time step
+  size_t buffersize = srvp->buffersize;
 
- 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.
+  if ( buffersize < blocklen )
+    {
+      buffersize = blocklen;
+      buffer = srvp->buffer;
+      buffer = Realloc(buffer, buffersize);
+      srvp->buffer = buffer;
+      srvp->buffersize = buffersize;
+    }
+  else
+    buffer = srvp->buffer;
 
- at Description
-The function @func{streamInqTimestep} returns the time step of a stream.
+  size_t datasize = srvp->datasize;
 
- at Result
- at func{streamInqTimestep} returns the number of records of the time step.
+  size_t dprec = blocklen / datasize;
 
- at EndFunction
-*/
-int streamInqTimestep(int streamID, int tsID)
-{
-  int nrecs = 0;
-  int taxisID;
-  stream_t *streamptr = stream_to_pointer(streamID);
-  int vlistID = streamptr->vlistID;
+  srvp->dprec = (int)dprec;
 
-  if ( tsID < streamptr->rtsteps )
+  if ( dprec != EXSE_SINGLE_PRECISION && dprec != EXSE_DOUBLE_PRECISION )
     {
-      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);
+      Warning("Unexpected data precision %d", dprec);
+      return -1;
+    }
+
+  fileRead(fileID, buffer, blocklen);
 
-      return (nrecs);
-    }
+  blocklen2 = binReadF77Block(fileID, byteswap);
 
-  if ( tsID >= streamptr->ntsteps && streamptr->ntsteps != CDI_UNDEFID )
+  if ( blocklen2 != blocklen )
     {
-      return (0);
+      Warning("Data blocklen differ (blocklen1=%d; blocklen2=%d)!", blocklen, blocklen2);
+      if ( blocklen2 != 0 ) return -1;
     }
 
-  int filetype = streamptr->filetype;
+  return 0;
+}
 
-  if ( CDI_Debug )
-    Message("streamID = %d  tsID = %d  filetype = %d", streamID, tsID, filetype);
 
-  switch (filetype)
+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 )
     {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
+    case EXSE_SINGLE_PRECISION:
       {
-        nrecs = grbInqTimestep(streamptr, tsID);
+	for (i = 0; i < SRV_HEADER_LEN; i++)
+          tempheader.i32[i] = (INT32) header[i];
+
+	binWriteInt32(fileID, byteswap, SRV_HEADER_LEN, tempheader.i32);
+
 	break;
       }
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
+    case EXSE_DOUBLE_PRECISION:
       {
-        nrecs = srvInqTimestep(streamptr, tsID);
+	for (i = 0; i < SRV_HEADER_LEN; i++)
+          tempheader.i64[i] = (INT64) header[i];
+
+	binWriteInt64(fileID, byteswap, SRV_HEADER_LEN, tempheader.i64);
+
 	break;
       }
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
+    default:
       {
-        nrecs = extInqTimestep(streamptr, tsID);
-	break;
+	Error("unexpected header precision %d", hprec);
+        break;
       }
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
+    }
+
+  binWriteF77Block(fileID, byteswap, blocklen);
+
+  size_t datasize = (size_t)(header[4] * header[5]);
+  blocklen = datasize * (size_t)dprec;
+
+  binWriteF77Block(fileID, byteswap, blocklen);
+
+  srvp->datasize = datasize;
+
+  void *buffer = srvp->buffer;
+
+  switch ( dprec )
+    {
+    case EXSE_SINGLE_PRECISION:
       {
-        nrecs = iegInqTimestep(streamptr, tsID);
+	binWriteFlt32(fileID, byteswap, datasize, (FLT32 *) buffer);
 	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);
+	binWriteFlt64(fileID, byteswap, datasize, (FLT64 *) buffer);
 	break;
       }
-#endif
     default:
       {
-	Error("%s support not compiled in!", strfiletype(filetype));
-	break;
+	Error("unexpected data precision %d", dprec);
+        break;
       }
     }
 
-  taxisID = vlistInqTaxis(vlistID);
-  if ( taxisID == -1 )
-    Error("Timestep undefined for fileID = %d", streamID);
+  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
 
-  ptaxisCopy(taxisPtr(taxisID), &streamptr->tsteps[tsID].taxis);
+#ifndef _SERVICE_H
+#endif
 
-  return (nrecs);
-}
+int    srvInqContents(stream_t *streamptr);
+int    srvInqTimestep(stream_t *streamptr, int tsID);
 
-#if 0
-void streamWriteContents(int streamID, char *cname)
-{
-  stream_t *streamptr = stream_to_pointer(streamID);
+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 vlistID = streamptr->vlistID;
+void   srvReadVarDP (stream_t *streamptr, int varID,       double *data, int *nmiss);
+void   srvWriteVarDP(stream_t *streamptr, int varID, const double *data);
 
-  FILE *cnp = fopen(cname, "w");
+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);
 
-  if ( cnp == NULL ) SysError(cname);
+#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
 
-  fprintf(cnp, "#CDI library version %s\n", cdiLibraryVersion());
-  fprintf(cnp, "#\n");
+#ifndef _EXTRA_H
+#endif
 
-  fprintf(cnp, "filename: %s\n", streamptr->filename);
-  int filetype = streamptr->filetype;
-  fprintf(cnp, "filetype: %s\n", strfiletype(filetype));
+int    extInqContents(stream_t *streamptr);
+int    extInqTimestep(stream_t *streamptr, int tsID);
 
-  fprintf(cnp, "#\n");
-  fprintf(cnp, "#grids:\n");
+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);
 
-  int ngrids = vlistNgrids(vlistID);
-  for ( int i = 0; i < ngrids; i++ )
-    {
-      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);
-    }
+void   extReadVarDP (stream_t *streamptr, int varID,       double *data, int *nmiss);
+void   extWriteVarDP(stream_t *streamptr, int varID, const double *data);
 
-  fprintf(cnp, "#\n");
+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);
 
-  fprintf(cnp, "varID:code:gridID:zaxisID:tsteptype:datatype\n");
+#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
 
-  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);
-    }
+#ifndef _IEG_H
+#endif
 
-  fprintf(cnp, "#\n");
+int    iegInqContents(stream_t *streamptr);
+int    iegInqTimestep(stream_t *streamptr, int tsID);
 
-  fprintf(cnp, "tsID:nrecs:date:time\n");
+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);
 
-  int tsID = 0;
-  while (1)
+void   iegReadVarDP (stream_t *streamptr, int varID,       double *data, int *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   iegWriteVarSliceDP(stream_t *streamptr, int varID, int levelID, const double *data);
+
+#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
+
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 600
+#endif
+
+#include <ctype.h>
+
+
+
+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);
+
+const resOps streamOps = {
+  streamCompareP,
+  streamDestroyP,
+  streamPrintP,
+  streamGetPackSize,
+  streamPack,
+  streamTxCode
+};
+
+
+
+static
+int getByteorder(int byteswap)
+{
+  int byteorder = -1;
+
+  switch (HOST_ENDIANNESS)
     {
-      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 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");
+    }
+  return byteorder;
+}
 
-      fprintf(cnp, "%4d:%4d:%4d:%4d:%ld\n",
-	      tsID, nrecs, date, time, (long) position);
+// used also in CDO
+int cdiGetFiletype(const char *filename, int *byteorder)
+{
+  int filetype = CDI_EUFTYPE;
+  int swap = 0;
+  int version;
+  long recpos;
+  char buffer[8];
 
-      if ( streamptr->tsteps[tsID].next )
-	tsID++;
+  int fileID = fileOpen(filename, "r");
+
+  if ( fileID == CDI_UNDEFID )
+    {
+      if ( strncmp(filename, "http:", 5) == 0 || strncmp(filename, "https:", 6) == 0 )
+	return FILETYPE_NC;
       else
-	break;
+	return CDI_ESYSTEM;
     }
 
-  fprintf(cnp, "#\n");
+  if ( fileRead(fileID, buffer, 8) != 8 ) return CDI_EUFTYPE;
 
-  fprintf(cnp, "tsID:recID:varID:levID:size:pos\n");
+  fileRewind(fileID);
 
-  tsID = 0;
-  while (1)
+  if ( memcmp(buffer, "GRIB", 4) == 0 )
     {
-      int nrecs = streamptr->tsteps[tsID].nallrecs;
-      for ( int recID = 0; recID < nrecs; recID++ )
+      version = buffer[7];
+      if ( version <= 1 )
 	{
-	  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);
+	  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) )
+    {
+      filetype = FILETYPE_EXT;
+      if ( CDI_Debug ) Message("found EXT file = %s", filename);
+    }
+#endif
+#if  defined  (HAVE_LIBIEG)
+  else if ( iegCheckFiletype(fileID, &swap) )
+    {
+      filetype = FILETYPE_IEG;
+      if ( CDI_Debug ) Message("found IEG file = %s", filename);
+    }
+#endif
+#if  defined  (HAVE_LIBCGRIBEX)
+  else if ( gribCheckSeek(fileID, &recpos, &version) == 0 )
+    {
+      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);
 	}
-
-      if ( streamptr->tsteps[tsID].next )
-	tsID++;
-      else
-	break;
     }
-
-  fclose(cnp);
-}
 #endif
 
-// This function is used in CDO!
-off_t streamNvals(int streamID)
-{
-  stream_t *streamptr = stream_to_pointer(streamID);
+  fileClose(fileID);
+
+  *byteorder = getByteorder(swap);
 
-  return (streamptr->numvals);
+  return filetype;
 }
 
 /*
- at Function  streamDefVlist
- at Title     Define the variable list
+ at Function  streamInqFiletype
+ at Title     Get the filetype
 
- at Prototype void streamDefVlist(int streamID, int vlistID)
+ at Prototype int streamInqFiletype(int streamID)
 @Parameter
-    @Item  streamID Stream ID, from a previous call to @fref{streamOpenWrite}.
-    @Item  vlistID  Variable list ID, from a previous call to @fref{vlistCreate}.
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
 
 @Description
-The function @func{streamDefVlist} defines the variable list of a stream.
+The function @func{streamInqFiletype} returns the filetype of a stream.
 
-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().
+ 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}.
 
 @EndFunction
 */
-void streamDefVlist(int streamID, int vlistID)
+int streamInqFiletype(int streamID)
 {
-  void (*myStreamDefVlist)(int streamID, int vlistID)
-    = (void (*)(int, int))namespaceSwitchGet(NSSWITCH_STREAM_DEF_VLIST_).func;
-  myStreamDefVlist(streamID, vlistID);
+  stream_t *streamptr = stream_to_pointer(streamID);
+  return streamptr->filetype;
 }
 
-/* the single image implementation of streamDefVlist */
-void
-cdiStreamDefVlist_(int streamID, int vlistID)
+
+int getByteswap(int byteorder)
 {
-  stream_t *streamptr = stream_to_pointer(streamID);
+  int byteswap = -1;
 
-  if ( streamptr->vlistID == CDI_UNDEFID )
+  switch (byteorder)
     {
-      int vlistCopy = vlistDuplicate(vlistID);
-      cdiVlistMakeInternal(vlistCopy);
-      cdiVlistMakeImmutable(vlistID);
-      cdiStreamSetupVlist(streamptr, vlistCopy);
+    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
-    Warning("vlist already defined for %s!", streamptr->filename);
+
+  return byteswap;
 }
 
 /*
- at Function  streamInqVlist
- at Title     Get the variable list
+ at Function  streamDefByteorder
+ at Title     Define the byte order
 
- at Prototype int streamInqVlist(int streamID)
+ at Prototype void streamDefByteorder(int streamID, int byteorder)
 @Parameter
-    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
+    @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}.
 
 @Description
-The function @func{streamInqVlist} returns the variable list of a stream.
-
- at Result
- at func{streamInqVlist} returns an identifier to the variable list.
+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}.
 
 @EndFunction
 */
-int streamInqVlist(int streamID)
+void streamDefByteorder(int streamID, int byteorder)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
-  return (streamptr->vlistID);
-}
-
+  streamptr->byteorder = byteorder;
+  int filetype = streamptr->filetype;
 
-void streamDefCompType(int streamID, int comptype)
-{
-  stream_t *streamptr = stream_to_pointer(streamID);
-  if (streamptr->comptype != comptype)
+  switch (filetype)
     {
-      streamptr->comptype = comptype;
-      reshSetStatus(streamID, &streamOps, RESH_DESYNC_IN_USE);
+#if  defined  (HAVE_LIBSERVICE)
+    case FILETYPE_SRV:
+      {
+	srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
+	srvp->byteswap = getByteswap(byteorder);
+
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case FILETYPE_EXT:
+      {
+	extrec_t *extp = (extrec_t*) streamptr->record->exsep;
+	extp->byteswap = getByteswap(byteorder);
+
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case FILETYPE_IEG:
+      {
+	iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
+	iegp->byteswap = getByteswap(byteorder);
+
+	break;
+      }
+#endif
     }
+  reshSetStatus(streamID, &streamOps, RESH_DESYNC_IN_USE);
 }
 
+/*
+ at Function  streamInqByteorder
+ at Title     Get the byte order
+
+ at Prototype int streamInqByteorder(int streamID)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
 
-void streamDefCompLevel(int streamID, int complevel)
+ 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}.
+
+ 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)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
-  if (streamptr->complevel != complevel)
-    {
-      streamptr->complevel = complevel;
-      reshSetStatus(streamID, &streamOps, RESH_DESYNC_IN_USE);
-    }
+  return streamptr->byteorder;
 }
 
 
-int streamInqCompType(int streamID)
+const char *streamFilesuffix(int filetype)
 {
-  stream_t *streamptr = stream_to_pointer(streamID);
-  return (streamptr->comptype);
+  // 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];
 }
 
 
-int streamInqCompLevel(int streamID)
+const char *streamFilename(int streamID)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
-  return (streamptr->complevel);
+  return streamptr->filename;
 }
 
-int streamInqFileID(int streamID)
+static
+long cdiInqTimeSize(int streamID)
 {
-  stream_t *streamptr;
+  int tsID = 0, nrecs;
+  stream_t *streamptr = stream_to_pointer(streamID);
+  long ntsteps = streamptr->ntsteps;
 
-  streamptr = ( stream_t *) reshGetVal ( streamID, &streamOps );
+  if ( ntsteps == (long)CDI_UNDEFID )
+    while ( (nrecs = streamInqTimestep(streamID, tsID++)) )
+      ntsteps = streamptr->ntsteps;
 
-  return (streamptr->fileID);
+  return ntsteps;
 }
 
-
-void cdiDefAccesstype(int streamID, int type)
+static
+int cdiInqContents(stream_t *streamptr)
 {
-  stream_t *streamptr = (stream_t *)reshGetVal(streamID, &streamOps);
+  int status = 0;
+  int filetype = streamptr->filetype;
 
-  if ( streamptr->accesstype == CDI_UNDEFID )
+  switch (filetype)
     {
-      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");
-}
-
-
-int cdiInqAccesstype(int streamID)
-{
-  stream_t *streamptr = (stream_t *) reshGetVal ( streamID, &streamOps );
+#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));
 
-  return (streamptr->accesstype);
-}
+	status = CDI_ELIBNAVAIL;
+        break;
+      }
+    }
 
-static
-int streamTxCode(void)
-{
-  return STREAM;
-}
+  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);
+        }
+    }
 
-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);
+  return status;
 }
 
-void
-cdiStreamSetupVlist_(stream_t *streamptr, int vlistID)
+int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
+                                 int filetype, stream_t *streamptr,
+                                 int recordBufIsToBeCreated)
 {
-  int nvars = vlistNvars(vlistID);
-  streamptr->vlistID = vlistID;
-  for (int varID = 0; varID < nvars; varID++ )
+  int fileID;
+  switch (filetype)
     {
-      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  defined  (HAVE_LIBGRIB)
+    case FILETYPE_GRB:
+#if  defined  (HAVE_LIBGRIB_API)
+    case 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
+#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)
+          {
+            streamptr->record = (Record *) Malloc(sizeof(Record));
+            streamptr->record->buffer = NULL;
+            streamptr->record->exsep  = srvNew();
+          }
+        break;
+      }
+#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 (streamptr->filemode == 'w')
-    switch (streamptr->filetype)
+        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:
       {
-#ifdef HAVE_LIBNETCDF
-      case FILETYPE_NC:
-      case FILETYPE_NC2:
-      case FILETYPE_NC4:
-      case FILETYPE_NC4C:
-        {
-          void (*myCdfDefVars)(stream_t *streamptr)
-            = (void (*)(stream_t *))
-            namespaceSwitchGet(NSSWITCH_CDF_STREAM_SETUP).func;
-          myCdfDefVars(streamptr);
-        }
+#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
-#ifdef HAVE_LIBGRIB
-      case FILETYPE_GRB:
-      case FILETYPE_GRB2:
-        gribContainersNew(streamptr);
         break;
+      }
+    case FILETYPE_NC2:
+      {
+#ifndef __cplusplus
+        fileID = cdfOpen64(filename, (char [2]){filemode, 0});
+#else
+        char temp[2] = { filemode, 0 };
+        fileID = cdfOpen64(filename, temp);
 #endif
-      default:
-        ;
+        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;
+      }
+    }
 
-void cdiStreamGetIndexList(unsigned numIDs, int *IDs)
-{
-  reshGetResHListOfType(numIDs, IDs, &streamOps);
-}
+  streamptr->filetype = filetype;
 
-int streamInqNvars ( int streamID )
-{
-  stream_t *streamptr = (stream_t *)reshGetVal(streamID, &streamOps);
-  return streamptr->nvars;
+  return fileID;
 }
 
 
-static int streamCompareP(void * streamptr1, void * streamptr2)
+int streamOpenID(const char *filename, char filemode, int filetype, int resH)
 {
-  stream_t * s1 = ( stream_t * ) streamptr1;
-  stream_t * s2 = ( stream_t * ) streamptr2;
-  enum {
-    differ = -1,
-    equal  = 0,
-  };
+  if ( CDI_Debug )
+    Message("Open %s mode %c file %s", strfiletype(filetype), filemode,
+            filename?filename:"(NUL)");
 
-  xassert ( s1 );
-  xassert ( s2 );
+  if ( ! filename || filetype < 0 ) return CDI_EINVAL;
 
-  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;
+  stream_t *streamptr = stream_new_entry(resH);
+  int streamID = CDI_ESYSTEM;
 
-  if ( s1->filename )
+  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 )
     {
-      if (strcmp(s1->filename, s2->filename))
-	return differ;
+      streamID = fileID;
     }
-  else if ( s2->filename )
-    return differ;
-
-  return equal;
-}
-
-
-void streamDestroyP ( void * streamptr )
-{
-  stream_t * sp = ( stream_t * ) streamptr;
-
-  xassert ( sp );
-
-  int id = sp->self;
-  streamClose ( id );
-}
-
+  else
+    {
+      streamID = streamptr->self;
+      if ( streamID < 0 ) return CDI_ELIMIT;
 
-void streamPrintP   ( void * streamptr, FILE * fp )
-{
-  stream_t * sp = ( stream_t * ) streamptr;
+      streamptr->filemode = filemode;
+      streamptr->filename = strdupx(filename);
+      streamptr->fileID   = fileID;
 
-  if ( !sp ) return;
+      if ( filemode == 'r' )
+        {
+          int vlistID = vlistCreate();
+          if ( vlistID < 0 ) return CDI_ELIMIT;
 
-  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);
-}
+          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);
+            }
+        }
+    }
 
-enum {
-  streamNint = 10,
-};
+  if ( streamID < 0 )
+    {
+      Free(streamptr->record);
+      stream_delete_entry(streamptr);
+    }
 
-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;
+  return streamID;
 }
 
-
-static void
-streamPack(void * streamptr, void * packBuffer, int packBufferSize,
-           int * packBufferPos, void *context)
+static
+int streamOpen(const char *filename, const char *filemode, int filetype)
 {
-  stream_t * streamP = ( stream_t * ) streamptr;
-  int intBuffer[streamNint];
-
-  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;
-
-  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);
-
-  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);
+  if ( !filemode || strlen(filemode) != 1 ) return CDI_EINVAL;
+  return streamOpenID(filename, (char)tolower(filemode[0]), filetype, CDI_UNDEFID);
 }
 
-struct streamAssoc
-streamUnpack(char * unpackBuffer, int unpackBufferSize,
-             int * unpackBufferPos, int originNamespace, void *context)
+static
+int streamOpenA(const char *filename, const char *filemode, int filetype)
 {
-  int intBuffer[streamNint];
-  uint32_t d;
-  char filename[CDI_MAX_NAME];
-
-  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 ( 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"
 
-  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]);
-  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 ( ! filename || ! filemode || filetype < 0 ) return CDI_EINVAL;
 
-/*
- * 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
+  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);
+  }
 
-/* the single image implementation */
-int cdiStreamWriteVar_(int streamID, int varID, 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;
+  if ( fileID == CDI_UNDEFID || fileID == CDI_ELIBNAVAIL || fileID == CDI_ESYSTEM ) return fileID;
 
-  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
+  int streamID = streamptr->self;
 
-  check_parg(data);
+  streamptr->filemode = tolower(*filemode);
+  streamptr->filename = strdupx(filename);
+  streamptr->fileID   = fileID;
 
-  stream_t *streamptr = stream_to_pointer(streamID);
-  if (subtypeInqActiveIndex(streamptr->vars[varID].subtypeID) != 0)
-    Error("Writing of non-trivial subtypes not yet implemented!");
+  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);
+  if(!strcmp(filemode, "r")) cdiVlistMakeImmutable(streamptr->vlistID);
 
-  // check taxis
-  if ( streamptr->curTsID == CDI_UNDEFID ) streamDefTimestep(streamID, 0);
+  {
+    void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
+      = (void (*)(stream_t *, int))
+      namespaceSwitchGet(NSSWITCH_STREAM_CLOSE_BACKEND).func;
 
-  int filetype = streamptr->filetype;
+    streamCloseDelegate(streamptr, 0);
+  }
 
   switch (filetype)
     {
 #if  defined  (HAVE_LIBGRIB)
     case FILETYPE_GRB:
+#if  defined  (HAVE_LIBGRIB_API)
     case FILETYPE_GRB2:
+#endif
       {
-        grb_write_var(streamptr, varID, memtype, data, nmiss);
+        fileID = gribOpen(filename, filemode);
+        if ( fileID != CDI_UNDEFID ) gribContainersNew(streamptr);
 	break;
       }
 #endif
 #if  defined  (HAVE_LIBSERVICE)
     case FILETYPE_SRV:
       {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        srvWriteVarDP(streamptr, varID, (double *)data);
+        fileID = fileOpen(filename, filemode);
 	break;
       }
 #endif
 #if  defined  (HAVE_LIBEXTRA)
     case FILETYPE_EXT:
       {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        extWriteVarDP(streamptr, varID, (double *)data);
+        fileID = fileOpen(filename, filemode);
 	break;
       }
 #endif
 #if  defined  (HAVE_LIBIEG)
     case FILETYPE_IEG:
       {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        iegWriteVarDP(streamptr, varID, (double *)data);
+        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:
       {
-        cdf_write_var(streamptr, varID, memtype, data, nmiss);
+	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  streamWriteVar
- at Title     Write a variable
+ at Function  streamOpenRead
+ at Title     Open a dataset for reading
 
- at Prototype void streamWriteVar(int streamID, int varID, 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  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 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.
+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 streamWriteVar(int streamID, int varID, const double *data, int nmiss)
+int streamOpenRead(const char *filename)
 {
-  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;
+  cdiInitialize();
 
-  myCdiStreamWriteVar_(streamID, varID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
+  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  streamWriteVarF
- at Title     Write a variable
+ at Function  streamOpenWrite
+ at Title     Create a new dataset
 
- at Prototype void streamWriteVarF(int streamID, int varID, 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  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{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}.
 
 @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.
+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", FILETYPE_NC);
+if ( streamID < 0 ) handle_error(streamID);
+   ...
+ at EndSource
 @EndFunction
 */
-void streamWriteVarF(int streamID, int varID, const float *data, int nmiss)
+int streamOpenWrite(const char *filename, int filetype)
 {
-  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) )
-    {
-      // 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);
-    }
+  cdiInitialize();
+
+  return streamOpen(filename, "w", filetype);
 }
 
 static
-int cdiStreamWriteVarSlice(int streamID, int varID, int levelID, int memtype, const void *data, int nmiss)
+void streamDefaultValue ( 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;
+  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->unreduced         = cdiDataUnreduced;
+  streamptr->sortname          = cdiSortName;
+  streamptr->have_missval      = cdiHaveMissval;
+  streamptr->comptype          = CDI_COMPRESS_NONE;
+  streamptr->complevel         = 0;
 
-  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
+  basetimeInit(&streamptr->basetime);
 
-  check_parg(data);
+#ifdef HAVE_LIBNETCDF
+  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;
 
-  stream_t *streamptr = stream_to_pointer(streamID);
-  if (subtypeInqActiveIndex(streamptr->vars[varID].subtypeID) != 0)
-    Error("Writing of non-trivial subtypes not yet implemented!");
+  streamptr->ncgrid            = NULL;
 
-  // check taxis
-  if ( streamptr->curTsID == CDI_UNDEFID ) streamDefTimestep(streamID, 0);
+  streamptr->vct.ilev          = 0;
+  streamptr->vct.mlev          = 0;
+  streamptr->vct.ilevID        = CDI_UNDEFID;
+  streamptr->vct.mlevID        = CDI_UNDEFID;
+#endif
 
-  int filetype = streamptr->filetype;
+  streamptr->gribContainers    = NULL;
+}
 
-  switch (filetype)
+static
+stream_t *stream_new_entry(int resH)
+{
+  cdiInitialize(); /* ***************** make MT version !!! */
+
+  stream_t *streamptr = (stream_t *) Malloc(sizeof(stream_t));
+  streamDefaultValue ( streamptr );
+
+  if (resH == CDI_UNDEFID)
+    streamptr->self = reshPut(streamptr, &streamOps);
+  else
     {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
+      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)
       {
-        grb_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
-	break;
-      }
+#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:
-      {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        srvWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
-	break;
-      }
+      case 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;
-        extWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
-	break;
-      }
+      case 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;
-        iegWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
-	break;
-      }
+      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:
-      cdf_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
-      break;
+      case FILETYPE_NC:
+      case FILETYPE_NC2:
+      case FILETYPE_NC4:
+      case FILETYPE_NC4C:
+        {
+          cdfClose(fileID);
+          if ( streamptr->ncgrid ) { Free(streamptr->ncgrid); streamptr->ncgrid = NULL; }
+          break;
+        }
 #endif
-    default:
-      {
-	Error("%s support not compiled in!", strfiletype(filetype));
-	break;
+      default:
+        {
+          Error("%s support not compiled in (fileID = %d)!", strfiletype(filetype), fileID);
+          break;
+        }
       }
-    }
-
-  return status;
 }
 
-/*
- at Function  streamWriteVarSlice
- at Title     Write a horizontal slice of a variable
-
- at Prototype void streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, int 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.
 
- 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 streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, int nmiss)
+static
+void deallocate_sleveltable_t(sleveltable_t *entry)
 {
-  cdiStreamWriteVarSlice(streamID, varID, levelID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
+  if (entry->recordID) Free(entry->recordID);
+  if (entry->lindex)   Free(entry->lindex);
+  entry->recordID = NULL;
+  entry->lindex   = NULL;
 }
 
+
 /*
- at Function  streamWriteVarSliceF
- at Title     Write a horizontal slice of a variable
+ at Function  streamClose
+ at Title     Close an open dataset
 
- at Prototype void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, int nmiss)
+ at Prototype  void streamClose(int streamID)
 @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  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
 
 @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{streamClose} closes an open dataset.
+
 @EndFunction
 */
-void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, int nmiss)
+void streamClose(int streamID)
 {
-  if ( cdiStreamWriteVarSlice(streamID, varID, levelID, MEMTYPE_FLOAT, (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 )
     {
-      // 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);
-    }
-}
+      if ( streamptr->record->buffer )
+        Free(streamptr->record->buffer);
 
+      Free(streamptr->record);
+    }
 
-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);
-}
+  streamptr->filetype = 0;
+  if ( streamptr->filename ) Free(streamptr->filename);
 
-/* single image implementation */
-void
-cdiStreamWriteVarChunk_(int streamID, int varID, int memtype,
-                        const int rect[][2], const void *data, int nmiss)
-{
-  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
+  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;
 
-  stream_t *streamptr = stream_to_pointer(streamID);
+  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);
+    }
 
-  // streamDefineTaxis(streamID);
+  if ( streamptr->tsteps ) Free(streamptr->tsteps);
 
-  int filetype = streamptr->filetype;
+  if ( streamptr->basetime.timevar_cache ) Free(streamptr->basetime.timevar_cache);
 
-  switch (filetype)
+  if ( vlistID != -1 )
     {
-#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;
+      if ( streamptr->filemode != 'w' && vlistInqTaxis(vlistID) != -1 )
+        taxisDestroy(vlistInqTaxis(vlistID));
+
+      cdiVlistDestroy_(vlistID);
     }
+
+  stream_delete_entry(streamptr);
 }
 
 static
-int stream_write_record(int streamID, int memtype, const void *data, int nmiss)
+void stream_delete_entry(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;
+  xassert ( streamptr );
 
-  check_parg(data);
+  int idx = streamptr->self;
+  Free(streamptr);
+  reshRemove ( idx, &streamOps );
 
-  stream_t *streamptr = stream_to_pointer(streamID);
+  if ( CDI_Debug )
+    Message("Removed idx %d from stream list", idx);
+}
 
-  switch (streamptr->filetype)
+
+void cdiStreamSync_(stream_t *streamptr)
+{
+  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
     {
-#if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
-      grb_write_record(streamptr, memtype, data, nmiss);
-      break;
-#endif
-#if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
-      if ( memtype == MEMTYPE_FLOAT ) return 1;
-      srvWriteRecord(streamptr, (const double *)data);
-      break;
-#endif
-#if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
-      if ( memtype == MEMTYPE_FLOAT ) return 1;
-      extWriteRecord(streamptr, (const double *)data);
-      break;
-#endif
-#if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
-      if ( memtype == MEMTYPE_FLOAT ) return 1;
-      iegWriteRecord(streamptr, (const double *)data);
-      break;
-#endif
+      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:
-      {
-	cdf_write_record(streamptr, memtype, data, nmiss);
-	break;
-      }
+	    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:
-      {
-	Error("%s support not compiled in!", strfiletype(streamptr->filetype));
-	break;
-      }
+	    default:
+	      {
+		fileFlush(fileID);
+		break;
+	      }
+	    }
+	}
     }
-
-  return status;
 }
 
 /*
- at Function  streamWriteRecord
- at Title     Write a horizontal slice of a variable
+ at Function  streamSync
+ at Title     Synchronize an Open Dataset to Disk
 
- at Prototype void streamWriteRecord(int streamID, const double *data, int nmiss)
+ at Prototype  void streamSync(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.
 
 @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{streamSync} offers a way to synchronize the disk copy of a dataset with in-memory buffers.
+
 @EndFunction
 */
-void streamWriteRecord(int streamID, const double *data, int nmiss)
+void streamSync(int streamID)
 {
-  stream_write_record(streamID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
+  stream_t *streamptr = stream_to_pointer(streamID);
+
+  void (*myStreamSync_)(stream_t *streamptr)
+    = (void (*)(stream_t *))namespaceSwitchGet(NSSWITCH_STREAM_SYNC).func;
+  myStreamSync_(streamptr);
 }
 
 
-void streamWriteRecordF(int streamID, const float *data, int nmiss)
+int cdiStreamDefTimestep_(stream_t *streamptr, int tsID)
 {
-  if ( stream_write_record(streamID, 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.
-      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);
-    }
-}
+  int taxisID = 0;
 
-#ifdef HAVE_CONFIG_H
-#endif
+  stream_check_ptr(__func__, streamptr);
 
+  if ( CDI_Debug ) Message("streamID = %d  tsID = %d", streamptr->self, tsID);
 
+  int vlistID = streamptr->vlistID;
 
-/* the single image implementation */
-static
-int cdiStreamReadVar(int streamID, int varID, 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;
+  int time_is_varying = vlistHasTime(vlistID);
 
-  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamID, varID);
+  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);
+        }
+    }
 
-  check_parg(data);
-  check_parg(nmiss);
+  int newtsID = tstepsNewEntry(streamptr);
 
-  stream_t *streamptr = stream_to_pointer(streamID);
-  int filetype = streamptr->filetype;
+  if ( tsID != newtsID )
+    Error("Internal problem: tsID = %d newtsID = %d", tsID, newtsID);
 
-  *nmiss = 0;
+  streamptr->curTsID = tsID;
 
-  switch (filetype)
+  if ( 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;
-      }
+      taxis_t *taxisptr1 = taxisPtr(taxisID);
+      taxis_t *taxisptr2 = &streamptr->tsteps[tsID].taxis;
+      ptaxisCopy(taxisptr2, taxisptr1);
     }
 
-  return status;
+  streamptr->ntsteps = tsID + 1;
+
+#ifdef HAVE_LIBNETCDF
+  if ((streamptr->filetype == FILETYPE_NC  ||
+       streamptr->filetype == FILETYPE_NC2 ||
+       streamptr->filetype == FILETYPE_NC4 ||
+       streamptr->filetype == FILETYPE_NC4C)
+      && time_is_varying)
+    {
+      void (*myCdfDefTimestep)(stream_t *streamptr, int tsID)
+        = (void (*)(stream_t *, int))
+        namespaceSwitchGet(NSSWITCH_CDF_DEF_TIMESTEP).func;
+      myCdfDefTimestep(streamptr, tsID);
+    }
+#endif
+
+  cdi_create_records(streamptr, tsID);
+
+  return (int)streamptr->ntsteps;
 }
 
 /*
- at Function  streamReadVar
- at Title     Read a variable
+ at Function  streamDefTimestep
+ at Title     Define time step
 
- 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 the time step of a stream.
+
+ at Result
+ at func{streamDefTimestep} returns the number of records of the time step.
+
 @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 time step
 
- 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} returns the time step of a stream.
+
+ at Result
+ at func{streamInqTimestep} returns the number of records of the time step.
+
 @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)
     {
@@ -37652,31 +37169,28 @@ int cdiStreamReadVarSlice(int streamID, int varID, int levelID, int memtype, voi
     case FILETYPE_GRB:
     case 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:
       {
-        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:
       {
-        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:
       {
-        if ( memtype == MEMTYPE_FLOAT ) return 1;
-        iegReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
+        nrecs = iegInqTimestep(streamptr, tsID);
 	break;
       }
 #endif
@@ -37686,7373 +37200,7421 @@ int cdiStreamReadVarSlice(int streamID, int varID, int levelID, int memtype, voi
     case FILETYPE_NC4:
     case FILETYPE_NC4C:
       {
-        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;
-}
+  taxisID = vlistInqTaxis(vlistID);
+  if ( taxisID == -1 )
+    Error("Timestep undefined for fileID = %d", streamID);
 
-/*
- at Function  streamReadVarSlice
- at Title     Read a horizontal slice of a variable
+  ptaxisCopy(taxisPtr(taxisID), &streamptr->tsteps[tsID].taxis);
 
- 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.
+  return nrecs;
+}
 
- 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 0
+void streamWriteContents(int streamID, char *cname)
 {
-  if ( cdiStreamReadVarSlice(streamID, varID, levelID, MEMTYPE_DOUBLE, data, nmiss) )
+  stream_t *streamptr = stream_to_pointer(streamID);
+
+  int vlistID = streamptr->vlistID;
+
+  FILE *cnp = fopen(cname, "w");
+
+  if ( cnp == NULL ) SysError(cname);
+
+  fprintf(cnp, "#CDI library version %s\n", cdiLibraryVersion());
+  fprintf(cnp, "#\n");
+
+  fprintf(cnp, "filename: %s\n", streamptr->filename);
+  int filetype = streamptr->filetype;
+  fprintf(cnp, "filetype: %s\n", strfiletype(filetype));
+
+  fprintf(cnp, "#\n");
+  fprintf(cnp, "#grids:\n");
+
+  int ngrids = vlistNgrids(vlistID);
+  for ( int i = 0; i < ngrids; i++ )
     {
-      Warning("Unexpected error returned from cdiStreamReadVarSlice()!");
-      size_t elementCount = (size_t)gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
-      memset(data, 0, elementCount * sizeof(*data));
+      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);
     }
-}
 
-/*
- at Function  streamReadVarSliceF
- at Title     Read a horizontal slice of a variable
+  fprintf(cnp, "#\n");
 
- 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.
+  fprintf(cnp, "varID:code:gridID:zaxisID:tsteptype:datatype\n");
 
- 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) )
+  int nvars = vlistNvars(vlistID);
+  for ( int varID = 0; varID < nvars; varID++ )
     {
-      // 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);
+      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);
     }
-}
 
-static
-int stream_read_record(int streamID, 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;
+  fprintf(cnp, "#\n");
 
-  check_parg(data);
-  check_parg(nmiss);
+  fprintf(cnp, "tsID:nrecs:date:time\n");
 
-  stream_t *streamptr = stream_to_pointer(streamID);
+  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;
 
-  *nmiss = 0;
+      fprintf(cnp, "%4d:%4d:%4d:%4d:%ld\n",
+	      tsID, nrecs, date, time, (long) position);
 
-  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));
+      if ( streamptr->tsteps[tsID].next )
+	tsID++;
+      else
 	break;
-      }
     }
 
-  return status;
-}
-
-
-void streamReadRecord(int streamID, double *data, int *nmiss)
-{
-  stream_read_record(streamID, MEMTYPE_DOUBLE, (void *) data, nmiss);
-}
+  fprintf(cnp, "#\n");
 
+  fprintf(cnp, "tsID:recID:varID:levID:size:pos\n");
 
-void streamReadRecordF(int streamID, float *data, int *nmiss)
-{
-  if ( stream_read_record(streamID, MEMTYPE_FLOAT, (void *) data, nmiss) )
+  tsID = 0;
+  while (1)
     {
-      // 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 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);
+	}
+
+      if ( streamptr->tsteps[tsID].next )
+	tsID++;
+      else
+	break;
     }
-}
-#ifndef _VARSCAN_H
-#define _VARSCAN_H
 
-#ifndef _GRID_H
+  fclose(cnp);
+}
 #endif
 
+// This function is used in CDO!
+off_t streamNvals(int streamID)
+{
+  stream_t *streamptr = stream_to_pointer(streamID);
+  return streamptr->numvals;
+}
 
-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);
+/*
+ at Function  streamDefVlist
+ at Title     Define the variable list
 
-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);
+ 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 varDefTypeOfGeneratingProcess(int varID, int typeOfGeneratingProcess);
-void varDefProductDefinitionTemplate(int varID, int productDefinitionTemplate);
+ at Description
+The function @func{streamDefVlist} defines the variable list of a stream.
 
+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().
 
-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);
+ 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  zaxisCompare(int zaxisID, int zaxistype, int nlevels, int lbounds, const double *levels, const char *longname, const char *units, int ltype);
+/* the single image implementation of streamDefVlist */
+void cdiStreamDefVlist_(int streamID, int vlistID)
+{
+  stream_t *streamptr = stream_to_pointer(streamID);
 
-#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
+  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);
+}
 
-#ifdef HAVE_LIBNETCDF
+/*
+ at Function  streamInqVlist
+ at Title     Get the variable list
 
-//#define TEST_GROUPS 1
+ at Prototype int streamInqVlist(int streamID)
+ at Parameter
+    @Item  streamID  Stream ID, from a previous call to @fref{streamOpenRead} or @fref{streamOpenWrite}.
 
-#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>
-#endif
+ at Description
+The function @func{streamInqVlist} returns the variable list of a stream.
 
-#include <netcdf.h>
+ at Result
+ at func{streamInqVlist} returns an identifier to the variable list.
 
+ at EndFunction
+*/
+int streamInqVlist(int streamID)
+{
+  stream_t *streamptr = stream_to_pointer(streamID);
+  return streamptr->vlistID;
+}
 
-//#define PROJECTION_TEST
 
-#undef  UNDEFID
-#define UNDEFID  CDI_UNDEFID
+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);
+    }
+}
 
-static const char bndsName[] = "bnds";
 
-#define  X_AXIS  1
-#define  Y_AXIS  2
-#define  Z_AXIS  3
-#define  T_AXIS  4
+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);
+    }
+}
 
-#define  POSITIVE_UP    1
-#define  POSITIVE_DOWN  2
 
-typedef struct {
-  int     ncvarid;
-  int     dimtype;
-  size_t  len;
-  char    name[CDI_MAX_NAME];
+int streamInqCompType(int streamID)
+{
+  stream_t *streamptr = stream_to_pointer(streamID);
+  return streamptr->comptype;
 }
-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 */
+
+int streamInqCompLevel(int streamID)
+{
+  stream_t *streamptr = stream_to_pointer(streamID);
+  return streamptr->complevel;
 }
-ncvar_t;
 
-static
-void strtolower(char *str)
+int streamInqFileID(int streamID)
 {
-  if ( str )
-    for (size_t i = 0; str[i]; ++i)
-      str[i] = (char)tolower((int)str[i]);
+  stream_t *streamptr = ( stream_t *) reshGetVal ( streamID, &streamOps );
+  return streamptr->fileID;
 }
 
-static
-int get_timeunit(size_t len, const char *ptu)
+
+void cdiDefAccesstype(int streamID, int type)
 {
-  int timeunit = -1;
+  stream_t *streamptr = (stream_t *)reshGetVal(streamID, &streamOps);
 
-  if ( len > 2 )
-    {
-      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;
-    }
-  else if ( len == 1 )
+  if ( streamptr->accesstype == CDI_UNDEFID )
     {
-      if ( ptu[0] == 's' ) timeunit = TUNIT_SECOND;
+      streamptr->accesstype = type;
     }
-
-  return timeunit;
+  else if ( streamptr->accesstype != type )
+    Error("Changing access type from %s not allowed!",
+          streamptr->accesstype == TYPE_REC ? "REC to VAR" : "VAR to REC");
 }
 
-static
-bool isTimeUnits(const char *timeunits)
+
+int cdiInqAccesstype(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_t *) reshGetVal ( streamID, &streamOps );
+  return streamptr->accesstype;
 }
 
 static
-bool isTimeAxisUnits(const char *timeunits)
+int streamTxCode(void)
 {
-  bool status = false;
+  return STREAM;
+}
 
-  size_t len = strlen(timeunits);
-  char *tu = (char *) Malloc((len+1)*sizeof(char));
-  memcpy(tu, timeunits, (len+1) * sizeof(char));
-  char *ptu = tu;
+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);
+}
 
-  for (size_t i = 0; i < len; i++ ) ptu[i] = (char)tolower((int)ptu[i]);
 
-  int timeunit = get_timeunit(len, ptu);
-  if ( timeunit != -1 )
+void cdiStreamSetupVlist_(stream_t *streamptr, int vlistID)
+{
+  streamptr->vlistID = vlistID;
+  int nvars = vlistNvars(vlistID);
+  for ( int varID = 0; varID < nvars; varID++ )
     {
+      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));
+    }
 
-      while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
-      if ( *ptu )
+  if (streamptr->filemode == 'w')
+    switch (streamptr->filetype)
+      {
+#ifdef HAVE_LIBNETCDF
+      case FILETYPE_NC:
+      case FILETYPE_NC2:
+      case FILETYPE_NC4:
+      case FILETYPE_NC4C:
         {
-          while ( isspace(*ptu) ) ptu++;
-
-          int timetype = memcmp(ptu, "as", 2) == 0 ? TAXIS_ABSOLUTE :
-            memcmp(ptu, "since", 5) == 0 ? TAXIS_RELATIVE : -1;
-
-          status = timetype != -1;
+          void (*myCdfDefVars)(stream_t *streamptr)
+            = (void (*)(stream_t *)) namespaceSwitchGet(NSSWITCH_CDF_STREAM_SETUP).func;
+          myCdfDefVars(streamptr);
         }
-    }
+        break;
+#endif
+#ifdef HAVE_LIBGRIB
+      case FILETYPE_GRB:
+      case FILETYPE_GRB2:
+        gribContainersNew(streamptr);
+        break;
+#endif
+      default:
+        ;
+      }
+}
 
-  Free(tu);
 
-  return status;
+void cdiStreamGetIndexList(unsigned numIDs, int *IDs)
+{
+  reshGetResHListOfType(numIDs, IDs, &streamOps);
 }
 
-static
-void scanTimeString(const char *ptu, int *rdate, int *rtime)
+int streamInqNvars ( int streamID )
 {
-  int year = 1, month = 1, day = 1;
-  int hour = 0, minute = 0, second = 0;
-  int v1 = 1, v2 = 1, v3 = 1;
+  stream_t *streamptr = (stream_t *)reshGetVal(streamID, &streamOps);
+  return streamptr->nvars;
+}
 
-  *rdate = 0;
-  *rtime = 0;
 
-  if ( *ptu )
-    {
-      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++;
-            }
-        }
-    }
+static int streamCompareP(void * streamptr1, void * streamptr2)
+{
+  stream_t * s1 = ( stream_t * ) streamptr1;
+  stream_t * s2 = ( stream_t * ) streamptr2;
+  enum {
+    differ = -1,
+    equal  = 0,
+  };
 
-  if ( v3 > 999 && v1 < 32 )
-    { year = v3; month = v2; day = v1; }
-  else
-    { year = v1; month = v2; day = v3; }
+  xassert ( s1 );
+  xassert ( s2 );
 
-  while ( isspace((int) *ptu) ) ptu++;
+  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;
 
-  if ( *ptu )
+  if ( s1->filename )
     {
-      while ( ! isdigit((int) *ptu) ) ptu++;
-
-      hour = atoi(ptu);
-      while ( isdigit((int) *ptu) ) ptu++;
-      if ( *ptu == ':' )
-        {
-          ptu++;
-          minute = atoi(ptu);
-          while ( isdigit((int) *ptu) ) ptu++;
-          if ( *ptu == ':' )
-            {
-              ptu++;
-              second = atoi(ptu);
-            }
-        }
+      if (strcmp(s1->filename, s2->filename))
+	return differ;
     }
+  else if ( s2->filename )
+    return differ;
 
-  *rdate = cdiEncodeDate(year, month, day);
-  *rtime = cdiEncodeTime(hour, minute, second);
+  return equal;
 }
 
-static
-int scanTimeUnit(const char *unitstr)
+
+void streamDestroyP ( void * streamptr )
 {
-  size_t len = strlen(unitstr);
-  int timeunit = get_timeunit(len, unitstr);
-  if ( timeunit == -1 )
-    Message("Unsupported TIMEUNIT: %s!", unitstr);
+  stream_t *sp = ( stream_t * ) streamptr;
 
-  return timeunit;
+  xassert ( sp );
+
+  int id = sp->self;
+  streamClose ( id );
 }
 
-static
-void setForecastTime(const char *timestr, taxis_t *taxis)
-{
-  (*taxis).fdate = 0;
-  (*taxis).ftime = 0;
 
-  int len = (int) strlen(timestr);
-  if ( len == 0 ) return;
+void streamPrintP   ( void * streamptr, FILE * fp )
+{
+  stream_t * sp = ( stream_t * ) streamptr;
 
-  int fdate = 0, ftime = 0;
-  scanTimeString(timestr, &fdate, &ftime);
+  if ( !sp ) return;
 
-  (*taxis).fdate = fdate;
-  (*taxis).ftime = ftime;
+  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
-int setBaseTime(const char *timeunits, taxis_t *taxis)
+enum {
+  streamNint = 10,
+};
+
+static int
+streamGetPackSize(void * voidP, void *context)
 {
-  int timetype = TAXIS_ABSOLUTE;
-  int rdate = -1, rtime = -1;
+  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;
+}
 
-  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]);
+static void
+streamPack(void * streamptr, void * packBuffer, int packBufferSize,
+           int * packBufferPos, void *context)
+{
+  stream_t * streamP = ( stream_t * ) streamptr;
+  int intBuffer[streamNint];
 
-  int timeunit = get_timeunit(len, ptu);
-  if ( timeunit == -1 )
-    {
-      Message("Unsupported TIMEUNIT: %s!", timeunits);
-      return (1);
-    }
+  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;
 
-  while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
-  if ( *ptu )
-    {
-      while ( isspace(*ptu) ) ptu++;
+  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);
 
-      if ( memcmp(ptu, "as", 2) == 0 )
-        timetype = TAXIS_ABSOLUTE;
-      else if ( memcmp(ptu, "since", 5) == 0 )
-        timetype = TAXIS_RELATIVE;
+  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);
+}
 
-      while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
-      if ( *ptu )
-        {
-          while ( isspace(*ptu) ) ptu++;
+struct streamAssoc
+streamUnpack(char * unpackBuffer, int unpackBufferSize,
+             int * unpackBufferPos, int originNamespace, void *context)
+{
+  int intBuffer[streamNint];
+  uint32_t d;
+  char filename[CDI_MAX_NAME];
 
-          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);
+  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);
+
+  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]);
+  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;
+}
 
-              (*taxis).rdate = rdate;
-              (*taxis).rtime = rtime;
+/*
+ * 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
 
-              if ( CDI_Debug )
-                Message("rdate = %d  rtime = %d", rdate, rtime);
-            }
-        }
-    }
 
-  (*taxis).type = timetype;
-  (*taxis).unit = timeunit;
 
-  Free(tu);
+/* the single image implementation */
+int cdiStreamWriteVar_(int streamID, int varID, 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;
 
-  if ( CDI_Debug )
-    Message("timetype = %d  unit = %d", timetype, timeunit);
+  if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
 
-  return 0;
-}
+  check_parg(data);
 
-static
-void cdfGetAttInt(int fileID, int ncvarid, const char *attname, int attlen, int *attint)
-{
-  nc_type atttype;
-  size_t nc_attlen;
+  stream_t *streamptr = stream_to_pointer(streamID);
+  if (subtypeInqActiveIndex(streamptr->vars[varID].subtypeID) != 0)
+    Error("Writing of non-trivial subtypes not yet implemented!");
 
-  *attint = 0;
+  // check taxis
+  if ( streamptr->curTsID == CDI_UNDEFID ) streamDefTimestep(streamID, 0);
 
-  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
-  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
+  int filetype = streamptr->filetype;
 
-  if ( atttype != NC_CHAR )
+  switch (filetype)
     {
-      int *pintatt = (int)nc_attlen > attlen
-        ? (int *)(Malloc(nc_attlen * sizeof (int))) : attint;
-
-      cdf_get_att_int(fileID, ncvarid, attname, pintatt);
-
-      if ( (int)nc_attlen > attlen )
-        {
-          memcpy(attint, pintatt, (size_t)attlen * sizeof (int));
-          Free(pintatt);
-        }
+#if  defined  (HAVE_LIBGRIB)
+    case FILETYPE_GRB:
+    case FILETYPE_GRB2:
+      {
+        grb_write_var(streamptr, varID, memtype, data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBSERVICE)
+    case FILETYPE_SRV:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        srvWriteVarDP(streamptr, varID, (double *)data);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case FILETYPE_EXT:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        extWriteVarDP(streamptr, varID, (double *)data);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case FILETYPE_IEG:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        iegWriteVarDP(streamptr, varID, (double *)data);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case FILETYPE_NC:
+    case FILETYPE_NC2:
+    case FILETYPE_NC4:
+    case FILETYPE_NC4C:
+      {
+        cdf_write_var(streamptr, varID, memtype, data, nmiss);
+	break;
+      }
+#endif
+    default:
+      {
+	Error("%s support not compiled in!", strfiletype(filetype));
+	break;
+      }
     }
+
+  return status;
 }
 
-static
-void cdfGetAttDouble(int fileID, int ncvarid, char *attname, int attlen, double *attdouble)
-{
-  nc_type atttype;
-  size_t nc_attlen;
+/*
+ at Function  streamWriteVar
+ at Title     Write a variable
 
-  *attdouble = 0;
+ 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.
 
-  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
-  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
+ 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;
 
-  if ( atttype != NC_CHAR )
-    {
-      double *pdoubleatt = NULL;
+  myCdiStreamWriteVar_(streamID, varID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
+}
 
-      if ( (int)nc_attlen > attlen )
-        pdoubleatt = (double *) Malloc(nc_attlen * sizeof (double));
-      else
-        pdoubleatt = attdouble;
+/*
+ at Function  streamWriteVarF
+ at Title     Write a variable
 
-      cdf_get_att_double(fileID, ncvarid, attname, pdoubleatt);
+ 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.
 
-      if ( (int)nc_attlen > attlen )
-        {
-          memcpy(attdouble, pdoubleatt, (size_t)attlen * sizeof (double));
-          Free(pdoubleatt);
-        }
+ 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 (*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) )
+    {
+      // 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);
     }
 }
 
 static
-void cdfGetAttText(int fileID, int ncvarid,const char *attname, int attlen, char *atttext)
+int cdiStreamWriteVarSlice(int streamID, int varID, int levelID, int memtype, const void *data, int 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 FILETYPE_GRB:
+    case FILETYPE_GRB2:
+      {
+        grb_write_var_slice(streamptr, varID, levelID, 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 FILETYPE_SRV:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        srvWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case FILETYPE_EXT:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        extWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
+	break;
+      }
 #endif
+#if  defined  (HAVE_LIBIEG)
+    case FILETYPE_IEG:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        iegWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
+	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;
+#endif
+    default:
+      {
+	Error("%s support not compiled in!", strfiletype(filetype));
+	break;
+      }
+    }
 
-  return isText;
+  return status;
 }
 
-static
-int xtypeIsFloat(int xtype)
-{
-  int isFloat = xtype == NC_FLOAT || xtype == NC_DOUBLE;
-  return isFloat;
-}
+/*
+ at Function  streamWriteVarSlice
+ at Title     Write a horizontal slice of a variable
 
-static
-int cdfInqDatatype(int xtype, int lunsigned)
+ at Prototype void streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, int 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.
+
+ 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 streamWriteVarSlice(int streamID, int varID, int levelID, const double *data, int nmiss)
 {
-  int datatype = -1;
+  cdiStreamWriteVarSlice(streamID, varID, levelID, MEMTYPE_DOUBLE, (const void *) data, nmiss);
+}
 
-#if  defined  (HAVE_NETCDF4)
-  if ( xtype == NC_BYTE && lunsigned ) xtype = NC_UBYTE;
-#endif
+/*
+ at Function  streamWriteVarSliceF
+ at Title     Write a horizontal slice of a variable
 
-  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 Prototype void streamWriteVarSliceF(int streamID, int varID, int levelID, const float *data, int 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.
 
-  return datatype;
+ 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, int 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));
+      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);
+    }
 }
 
 
-void cdfCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
+void streamWriteVarChunk(int streamID, int varID,
+                         const int rect[][2], const double *data, int 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;
+  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);
+}
 
-  void *data
-    = Malloc((size_t)datasize
-             * (memtype == MEMTYPE_DOUBLE ? sizeof(double) : sizeof(float)));
+/* single image implementation */
+void cdiStreamWriteVarChunk_(int streamID, int varID, int memtype,
+                             const int rect[][2], const void *data, int nmiss)
+{
+  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);
+  stream_t *streamptr = stream_to_pointer(streamID);
 
-  Free(data);
+  // streamDefineTaxis(streamID);
+
+  int filetype = streamptr->filetype;
+
+  switch (filetype)
+    {
+#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;
+    }
 }
 
-/* not used
-int cdfInqRecord(stream_t *streamptr, int *varID, int *levelID)
+static
+int stream_write_record(int streamID, int memtype, const void *data, int nmiss)
 {
-  int tsID, recID;
+  // 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;
 
-  recID = streamptr->tsteps[0].curRecID++;
-  printf("cdfInqRecord recID %d %d\n", recID, streamptr->tsteps[0].curRecID);
-  printf("cdfInqRecord tsID %d\n", streamptr->curTsID);
+  check_parg(data);
 
-  if ( streamptr->tsteps[0].curRecID >= streamptr->tsteps[0].nrecs )
+  stream_t *streamptr = stream_to_pointer(streamID);
+
+  switch (streamptr->filetype)
     {
-      streamptr->tsteps[0].curRecID = 0;
+#if  defined  (HAVE_LIBGRIB)
+    case FILETYPE_GRB:
+    case FILETYPE_GRB2:
+      grb_write_record(streamptr, memtype, data, nmiss);
+      break;
+#endif
+#if  defined  (HAVE_LIBSERVICE)
+    case FILETYPE_SRV:
+      if ( memtype == MEMTYPE_FLOAT ) return 1;
+      srvWriteRecord(streamptr, (const double *)data);
+      break;
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case FILETYPE_EXT:
+      if ( memtype == MEMTYPE_FLOAT ) return 1;
+      extWriteRecord(streamptr, (const double *)data);
+      break;
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case FILETYPE_IEG:
+      if ( memtype == MEMTYPE_FLOAT ) return 1;
+      iegWriteRecord(streamptr, (const double *)data);
+      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;
+      }
+#endif
+    default:
+      {
+	Error("%s support not compiled in!", strfiletype(streamptr->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  streamWriteRecord
+ 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 streamWriteRecord(int streamID, const double *data, int 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.
 
-  return (recID+1);
-}
+ 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 cdfDefRecord(stream_t *streamptr)
+void streamWriteRecord(int streamID, const double *data, int nmiss)
 {
-  (void)streamptr;
+  stream_write_record(streamID, 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)))
+void streamWriteRecordF(int streamID, const float *data, int nmiss)
+{
+  if ( stream_write_record(streamID, MEMTYPE_FLOAT, (const void *) data, nmiss) )
     {
-      if ( retval == NC_EINVAL )
-        {
-          static int lwarn = TRUE;
-
-          if ( lwarn )
-            {
-              lwarn = FALSE;
-              Warning("NetCDF4/Szip compression not compiled in!");
-            }
-        }
-      else
-        Error("nc_def_var_szip failed, status = %d", retval);
+      // 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);
     }
 }
+
+#ifdef HAVE_CONFIG_H
 #endif
 
+
+
+/* the single image implementation */
 static
-void cdfDefTimeValue(stream_t *streamptr, int tsID)
+int cdiStreamReadVar(int streamID, int varID, int memtype, void *data, int *nmiss)
 {
-  int fileID = streamptr->fileID;
+  // 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 ( CDI_Debug )
-    Message("streamID = %d, fileID = %d", streamptr->self, fileID);
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamID, varID);
 
-  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
+  check_parg(data);
+  check_parg(nmiss);
 
-  if ( streamptr->ncmode == 1 )
+  stream_t *streamptr = stream_to_pointer(streamID);
+  int filetype = streamptr->filetype;
+
+  *nmiss = 0;
+
+  switch (filetype)
     {
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
+#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;
+      }
     }
 
-  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);
+  return status;
+}
 
-  int ncvarid = streamptr->basetime.ncvarid;
-  cdf_put_var1_double(fileID, ncvarid, &index, &timevalue);
+/*
+ at Function  streamReadVar
+ at Title     Read a variable
 
-  if ( taxis->has_bounds )
-    {
-      size_t start[2], count[2];
+ at Prototype void streamReadVar(int streamID, int varID, double *data, int *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.
 
-      ncvarid = streamptr->basetime.ncvarboundsid;
+ 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, int *nmiss)
+{
+  cdiStreamReadVar(streamID, varID, MEMTYPE_DOUBLE, data, nmiss);
+}
 
-      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);
+/*
+ at Function  streamReadVarF
+ at Title     Read a variable
 
-      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);
-    }
+ at Prototype void streamReadVar(int streamID, int varID, float *data, int *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.
 
-  ncvarid = streamptr->basetime.leadtimeid;
-  if ( taxis->type == TAXIS_FORECAST && ncvarid != UNDEFID )
+ 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, int *nmiss)
+{
+  if ( cdiStreamReadVar(streamID, varID, MEMTYPE_FLOAT, data, nmiss) )
     {
-      timevalue = taxis->fc_period;
-      cdf_put_var1_double(fileID, ncvarid, &index, &timevalue);
+      // 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);
     }
-
-  /*
-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 cdiStreamReadVarSlice(int streamID, int varID, int levelID, int memtype, void *data, int *nmiss)
 {
-  int time_bndsid = -1;
-  int dims[2];
+  // 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;
 
-  dims[0] = nctimedimid;
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamID, varID);
 
-  /* fprintf(stderr, "time has bounds\n"); */
+  check_parg(data);
+  check_parg(nmiss);
 
-  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);
+  int filetype = streamptr->filetype;
 
-  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
+  *nmiss = 0;
+
+  switch (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 FILETYPE_GRB:
+    case FILETYPE_GRB2:
+      {
+        grb_read_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBSERVICE)
+    case FILETYPE_SRV:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        srvReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBEXTRA)
+    case FILETYPE_EXT:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        extReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBIEG)
+    case FILETYPE_IEG:
+      {
+        if ( memtype == MEMTYPE_FLOAT ) return 1;
+        iegReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
+	break;
+      }
+#endif
+#if  defined  (HAVE_LIBNETCDF)
+    case FILETYPE_NC:
+    case FILETYPE_NC2:
+    case FILETYPE_NC4:
+    case FILETYPE_NC4C:
+      {
+        cdf_read_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
+        break;
+      }
+#endif
+    default:
+      {
+	Error("%s support not compiled in!", strfiletype(filetype));
+        status = 2;
+	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)
-{
-  unitstr[0] = 0;
+/*
+ at Function  streamReadVarSlice
+ at Title     Read a horizontal slice of a variable
 
-  if ( taxis0->type == TAXIS_ABSOLUTE )
+ 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) )
     {
-      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");
+      Warning("Unexpected error returned from cdiStreamReadVarSlice()!");
+      size_t elementCount = (size_t)gridInqSize(vlistInqVarGrid(streamInqVlist(streamID), varID));
+      memset(data, 0, elementCount * sizeof(*data));
     }
-  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);
+/*
+ at Function  streamReadVarSliceF
+ at Title     Read a horizontal slice of a variable
 
-      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;
+ 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.
 
-      sprintf(unitstr, "%s since %d-%d-%d %02d:%02d:%02d",
-              tunitNamePtr(timeunit), year, month, day, hour, minute, second);
+ 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);
     }
 }
 
 static
-void cdfDefForecastTimeUnits(char *unitstr, int timeunit)
+int stream_read_record(int streamID, int memtype, void *data, int *nmiss)
 {
-  unitstr[0] = 0;
-
-  if ( timeunit == -1 ) timeunit = TUNIT_HOUR;
+  // 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 == 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);
 
-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 (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:
       {
-        const char *calstr = calTab[i].calStr;
-        size_t len = strlen(calstr);
-        cdf_put_att_text(fileID, ncvarid, "calendar", len, calstr);
-        break;
+	Error("%s support not compiled in!", strfiletype(streamptr->filetype));
+	break;
       }
+    }
+
+  return status;
 }
 
 
-void cdfDefTime(stream_t* streamptr)
+void streamReadRecord(int streamID, double *data, int *nmiss)
 {
-  int time_varid;
-  int time_dimid;
-  int time_bndsid = -1;
-  static const char default_name[] = "time";
-
-  if ( streamptr->basetime.ncvarid != UNDEFID ) return;
-
-  int fileID = streamptr->fileID;
-
-  if ( streamptr->ncmode == 0 ) streamptr->ncmode = 1;
-  if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+  stream_read_record(streamID, MEMTYPE_DOUBLE, (void *) data, nmiss);
+}
 
-  taxis_t *taxis = &streamptr->tsteps[0].taxis;
 
-  const char *taxis_name = (taxis->name && taxis->name[0]) ? taxis->name : default_name ;
+void streamReadRecordF(int streamID, float *data, int *nmiss)
+{
+  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 = (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);
+    }
+}
+#ifndef _VARSCAN_H
+#define _VARSCAN_H
 
-  cdf_def_dim(fileID, taxis_name, NC_UNLIMITED, &time_dimid);
-  streamptr->basetime.ncdimid = time_dimid;
+#ifndef _GRID_H
+#endif
 
-  cdf_def_var(fileID, taxis_name, NC_DOUBLE, 1, &time_dimid, &time_varid);
 
-  streamptr->basetime.ncvarid = time_varid;
+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);
 
-  {
-    static const char timeStr[] = "time";
-    cdf_put_att_text(fileID, time_varid, "standard_name", sizeof(timeStr) - 1, timeStr);
-  }
+void varDefVCT(size_t vctsize, double *vctptr);
+void varDefZAxisReference(int nlev, int nvgrid, unsigned char uuid[CDI_UUID_SIZE]);
 
-  if ( taxis->longname && taxis->longname[0] )
-    cdf_put_att_text(fileID, time_varid, "long_name", strlen(taxis->longname), taxis->longname);
+int  varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, 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 ( taxis->has_bounds )
-    {
-      time_bndsid = cdfDefTimeBounds(fileID, time_varid, time_dimid, taxis_name, taxis);
-      streamptr->basetime.ncvarboundsid = time_bndsid;
-    }
+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);
 
-  {
-    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 varDefTypeOfGeneratingProcess(int varID, int typeOfGeneratingProcess);
+void varDefProductDefinitionTemplate(int varID, int productDefinitionTemplate);
 
-  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;
+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);
 
-      cdf_def_var(fileID, "leadtime", NC_DOUBLE, 1, &time_dimid, &leadtimeid);
+bool zaxisCompare(int zaxisID, int zaxistype, int nlevels, bool lbounds, const double *levels, const char *longname, const char *units, int ltype);
 
-      streamptr->basetime.leadtimeid = leadtimeid;
+#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 const char stdname[] = "forecast_period";
-        cdf_put_att_text(fileID, leadtimeid, "standard_name", sizeof(stdname) - 1, stdname);
-      }
+#ifdef HAVE_LIBNETCDF
 
-      {
-        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 TEST_GROUPS 1
 
-      {
-          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);
-      }
-    }
+#include <ctype.h>
 
-  cdf_put_att_text(fileID, time_varid, "axis", 1, "T");
 
-  if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
-}
+#undef  CDI_UNDEFID
+#define CDI_UNDEFID  CDI_UNDEFID
 
+#define  X_AXIS  1
+#define  Y_AXIS  2
+#define  Z_AXIS  3
+#define  T_AXIS  4
 
-void cdfDefTimestep(stream_t *streamptr, int tsID)
-{
-  int vlistID = streamptr->vlistID;
+#define  POSITIVE_UP    1
+#define  POSITIVE_DOWN  2
 
-  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
+typedef struct {
+  int     ncvarid;
+  int     dimtype;
+  size_t  len;
+  char    name[CDI_MAX_NAME];
+}
+ncdim_t;
+#define  MAX_COORDVARS  4
+#define  MAX_AUXVARS    4
 
-  cdfDefTimeValue(streamptr, tsID);
+typedef struct {
+  int      ncid;
+  int      isvar;
+  bool     ignore;
+  bool     isx;
+  bool     isy;
+  bool     islon;
+  bool     islat;
+  bool     islev;
+  bool     istime;
+  bool     warn;
+  bool     climatology;
+  bool     lformulaterms;
+  int      tsteptype;
+  int      param;
+  int      code;
+  int      tabnum;
+  int      bounds;
+  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;
+  bool     defmissval;
+  bool     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;
+  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 cdfDefComplex(stream_t *streamptr, int gridID)
+void scanTimeString(const char *ptu, int *rdate, int *rtime)
 {
-  static const char axisname[] = "nc2";
-  int dimID = UNDEFID;
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
+  int year = 1, month = 1, day = 1;
+  int hour = 0, minute = 0, second = 0;
+  int v1 = 1, v2 = 1, v3 = 1;
 
-  int ngrids = vlistNgrids(vlistID);
+  *rdate = 0;
+  *rtime = 0;
 
-  for ( int index = 0; index < ngrids; index++ )
+  if ( *ptu )
     {
-      if ( streamptr->xdimID[index] != UNDEFID )
+      v1 = atoi(ptu);
+      if ( v1 < 0 ) ptu++;
+      while ( isdigit((int) *ptu) ) ptu++;
+      if ( *ptu )
         {
-          int gridID0 = vlistGrid(vlistID, index);
-          int gridtype0 = gridInqType(gridID0);
-          if ( gridtype0 == GRID_SPECTRAL || gridtype0 == GRID_FOURIER )
+          v2 = atoi(++ptu);
+          while ( isdigit((int) *ptu) ) ptu++;
+          if ( *ptu )
             {
-              dimID = streamptr->xdimID[index];
-              break;
+              v3 = atoi(++ptu);
+              while ( isdigit((int) *ptu) ) ptu++;
             }
         }
     }
 
-  if ( dimID == UNDEFID )
-    {
-      size_t dimlen = 2;
+  if ( v3 > 999 && v1 < 32 )
+    { year = v3; month = v2; day = v1; }
+  else
+    { year = v1; month = v2; day = v3; }
 
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+  while ( isspace((int) *ptu) ) ptu++;
 
-      cdf_def_dim(fileID, axisname, dimlen, &dimID);
+  if ( *ptu )
+    {
+      while ( ! isdigit((int) *ptu) ) ptu++;
 
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
+      hour = atoi(ptu);
+      while ( isdigit((int) *ptu) ) ptu++;
+      if ( *ptu == ':' )
+        {
+          ptu++;
+          minute = atoi(ptu);
+          while ( isdigit((int) *ptu) ) ptu++;
+          if ( *ptu == ':' )
+            {
+              ptu++;
+              second = atoi(ptu);
+            }
+        }
     }
 
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  streamptr->xdimID[gridindex] = dimID;
+  *rdate = cdiEncodeDate(year, month, day);
+  *rtime = cdiEncodeTime(hour, minute, second);
 }
 
-static void
-cdfDefSPorFC(stream_t *streamptr, int gridID,
-             char *restrict axisname, int gridRefType)
+static
+int scanTimeUnit(const char *unitstr)
 {
-  int index, iz = 0;
-  int dimID = UNDEFID;
+  size_t len = strlen(unitstr);
+  int timeunit = get_timeunit(len, unitstr);
+  if ( timeunit == -1 )
+    Message("Unsupported TIMEUNIT: %s!", unitstr);
 
-  int vlistID = streamptr->vlistID;
+  return timeunit;
+}
 
-  int ngrids = vlistNgrids(vlistID);
+static
+void setForecastTime(const char *timestr, taxis_t *taxis)
+{
+  (*taxis).fdate = 0;
+  (*taxis).ftime = 0;
 
-  size_t dimlen = (size_t)gridInqSize(gridID)/2;
+  int len = (int) strlen(timestr);
+  if ( len == 0 ) return;
 
-  for ( index = 0; index < ngrids; index++ )
+  int fdate = 0, ftime = 0;
+  scanTimeString(timestr, &fdate, &ftime);
+
+  (*taxis).fdate = fdate;
+  (*taxis).ftime = ftime;
+}
+
+static
+int setBaseTime(const char *timeunits, taxis_t *taxis)
+{
+  int timetype = TAXIS_ABSOLUTE;
+  int rdate = -1, rtime = -1;
+
+  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 )
+    {
+      Message("Unsupported TIMEUNIT: %s!", timeunits);
+      return 1;
+    }
+
+  while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
+  if ( *ptu )
     {
-      if ( streamptr->ydimID[index] != UNDEFID )
+      while ( isspace(*ptu) ) ptu++;
+
+      if ( str_is_equal(ptu, "as") )
+        timetype = TAXIS_ABSOLUTE;
+      else if ( str_is_equal(ptu, "since") )
+        timetype = TAXIS_RELATIVE;
+
+      while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
+      if ( *ptu )
         {
-          int gridID0 = vlistGrid(vlistID, index);
-          int gridtype0 = gridInqType(gridID0);
-          if ( gridtype0 == gridRefType )
+          while ( isspace(*ptu) ) ptu++;
+
+          if ( timetype == TAXIS_ABSOLUTE )
             {
-              size_t dimlen0 = (size_t)gridInqSize(gridID0)/2;
-              if ( dimlen == dimlen0 )
+              if ( !str_is_equal(ptu, "%y%m%d.%f") && timeunit == TUNIT_DAY )
                 {
-                  dimID = streamptr->ydimID[index];
-                  break;
+                  Message("Unsupported format %s for TIMEUNIT day!", ptu);
+                  timeunit = -1;
                 }
-              else
-                iz++;
+              else if ( !str_is_equal(ptu, "%y%m.%f") && timeunit == TUNIT_MONTH )
+                {
+                  Message("Unsupported format %s for TIMEUNIT month!", ptu);
+                  timeunit = -1;
+                }
+            }
+          else if ( timetype == TAXIS_RELATIVE )
+            {
+              scanTimeString(ptu, &rdate, &rtime);
+
+              (*taxis).rdate = rdate;
+              (*taxis).rtime = rtime;
+
+              if ( CDI_Debug )
+                Message("rdate = %d  rtime = %d", rdate, rtime);
             }
         }
     }
 
-  if ( dimID == UNDEFID )
-    {
-      int fileID  = streamptr->fileID;
-      if ( iz == 0 ) axisname[3] = '\0';
-      else           sprintf(&axisname[3], "%1d", iz+1);
-
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+  (*taxis).type = timetype;
+  (*taxis).unit = timeunit;
 
-      cdf_def_dim(fileID, axisname, dimlen, &dimID);
+  Free(tu);
 
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
-    }
+  if ( CDI_Debug )
+    Message("timetype = %d  unit = %d", timetype, timeunit);
 
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  streamptr->ydimID[gridindex] = dimID;
+  return 0;
 }
 
 static
-void cdfDefSP(stream_t *streamptr, int gridID)
+void cdfGetAttInt(int fileID, int ncvarid, const char *attname, int attlen, int *attint)
 {
-  /*
-  char longname[] = "Spherical harmonic coefficient";
-  */
-  char axisname[5] = "nspX";
-  cdfDefSPorFC(streamptr, gridID, axisname, GRID_SPECTRAL);
-}
+  nc_type atttype;
+  size_t nc_attlen;
 
+  *attint = 0;
 
-static
-void cdfDefFC(stream_t *streamptr, int gridID)
-{
-  char axisname[5] = "nfcX";
-  cdfDefSPorFC(streamptr, gridID, axisname, GRID_FOURIER);
-}
+  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
+  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
 
-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,
-};
+  if ( atttype != NC_CHAR )
+    {
+      int *pintatt = (int)nc_attlen > attlen
+        ? (int *)(Malloc(nc_attlen * sizeof (int))) : attint;
 
-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);
-  }
+      cdf_get_att_int(fileID, ncvarid, attname, pintatt);
+
+      if ( (int)nc_attlen > attlen )
+        {
+          memcpy(attint, pintatt, (size_t)attlen * sizeof (int));
+          Free(pintatt);
+        }
+    }
 }
 
-static void
-cdfDefTrajLatLon(stream_t *streamptr, int gridID,
-                 const struct cdfDefGridAxisInqs *inqs,
-                 int *dimID, const char *sizeName)
+static
+void cdfGetAttDouble(int fileID, int ncvarid, char *attname, int attlen, double *attdouble)
 {
-  nc_type xtype = gridInqPrec(gridID) == DATATYPE_FLT32 ? NC_FLOAT : NC_DOUBLE;
+  nc_type atttype;
+  size_t nc_attlen;
 
-  int vlistID = streamptr->vlistID;
-  int dimlen = inqs->axisSize(gridID);
-  if ( dimlen != 1 )
-    Error("%s isn't 1 for %s grid!", sizeName, gridNamePtr(gridInqType(gridID)));
+  *attdouble = 0;
 
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  int ncvarid = dimID[gridindex];
+  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
+  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
 
-  if ( ncvarid == UNDEFID )
+  if ( atttype != NC_CHAR )
     {
-      int dimNcID = streamptr->basetime.ncvarid;
-      int fileID  = streamptr->fileID;
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+      double *pdoubleatt = NULL;
 
-      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;
-    }
+      if ( (int)nc_attlen > attlen )
+        pdoubleatt = (double *) Malloc(nc_attlen * sizeof (double));
+      else
+        pdoubleatt = attdouble;
+
+      cdf_get_att_double(fileID, ncvarid, attname, pdoubleatt);
 
-  dimID[gridindex] = ncvarid; /* var ID for trajectory !!! */
+      if ( (int)nc_attlen > attlen )
+        {
+          memcpy(attdouble, pdoubleatt, (size_t)attlen * sizeof (double));
+          Free(pdoubleatt);
+        }
+    }
 }
 
 static
-void cdfDefTrajLon(stream_t *streamptr, int gridID)
+bool cdfCheckAttText(int fileID, int ncvarid, const char *attname)
 {
-  cdfDefTrajLatLon(streamptr, gridID, &gridInqsX, streamptr->xdimID, "Xsize");
-}
+  bool status = false;
+  nc_type atttype;
 
+  int status_nc = nc_inq_atttype(fileID, ncvarid, attname, &atttype);
 
-static
-void cdfDefTrajLat(stream_t *streamptr, int gridID)
-{
-  cdfDefTrajLatLon(streamptr, gridID, &gridInqsY, streamptr->ydimID, "Ysize");
+  if ( status_nc == NC_NOERR
+       && (atttype == NC_CHAR
+#if  defined  (HAVE_NETCDF4)
+           || atttype == NC_STRING
+#endif
+           ) )
+    {
+      status = true;
+    }
+
+  return status;
 }
 
 static
-int checkDimName(int fileID, size_t dimlen, char *dimname)
+void cdfGetAttText(int fileID, int ncvarid, const char *attname, size_t attlen, char *atttext)
 {
-  /* check whether the dimenion name is already defined with the same length */
-  unsigned iz = 0;
-  int dimid = UNDEFID;
-  char name[CDI_MAX_NAME];
+  nc_type atttype;
+  size_t nc_attlen;
 
-  size_t len = strlen(dimname);
-  memcpy(name, dimname, len + 1);
+  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
+  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
 
-  do
+  if ( atttype == NC_CHAR )
     {
-      if ( iz ) sprintf(name + len, "_%u", iz+1);
+      char attbuf[65636];
+      if ( nc_attlen < sizeof(attbuf) )
+        {
+          cdf_get_att_text(fileID, ncvarid, attname, attbuf);
 
-      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 )
+          if ( nc_attlen > (attlen-1) ) nc_attlen = (attlen-1);
+
+          attbuf[nc_attlen++] = 0;
+          memcpy(atttext, attbuf, nc_attlen);
+        }
+      else
         {
-          dimid = dimid0;
-          break;
+          atttext[0] = 0;
         }
-      iz++;
     }
-  while ( iz <= 99 );
-
+#if  defined  (HAVE_NETCDF4)
+  else if ( atttype == NC_STRING )
+    {
+      if ( nc_attlen == 1 )
+        {
+          char *attbuf = NULL;
+          cdf_get_att_string(fileID, ncvarid, attname, &attbuf);
 
-  if ( iz ) sprintf(dimname + len, "_%u", iz+1);
+          size_t ssize = strlen(attbuf) + 1;
 
-  return dimid;
+          if ( ssize > attlen ) ssize = attlen;
+          memcpy(atttext, attbuf, ssize);
+          atttext[ssize - 1] = 0;
+          Free(attbuf);
+        }
+      else
+        {
+          atttext[0] = 0;
+        }
+    }
+#endif
 }
 
 static
-void checkGridName(char *axisname, int fileID, int vlistID, int gridID, int ngrids, int mode)
+bool xtypeIsText(nc_type xtype)
 {
-  int ncdimid;
-  char axisname2[CDI_MAX_NAME];
+  bool isText = false;
 
-  /* check that the name is not already defined */
-  unsigned iz = 0;
+  if      ( xtype == NC_CHAR ) isText = true;
+#if  defined  (HAVE_NETCDF4)
+  else if ( xtype == NC_STRING ) isText = true;
+#endif
 
-  size_t axisnameLen = strlen(axisname);
-  memcpy(axisname2, axisname, axisnameLen + 1);
-  do
-    {
-      if ( iz ) sprintf(axisname2 + axisnameLen, "_%u", iz+1);
+  return isText;
+}
 
-      int status = nc_inq_varid(fileID, axisname2, &ncdimid);
+static
+bool xtypeIsFloat(nc_type xtype)
+{
+  bool isFloat = xtype == NC_FLOAT || xtype == NC_DOUBLE;
 
-      if ( status != NC_NOERR )
-        {
-          if ( iz )
-            {
-              /* 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;
-                    }
-                }
-            }
-          break;
-        }
-      nextSuffix:
-      ++iz;
-    }
-  while ( iz <= 99 );
+  return isFloat;
+}
 
+static
+bool xtypeIsInt(nc_type xtype)
+{
+  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
+             ;
 
-  if ( iz ) sprintf(axisname + axisnameLen, "_%u", iz+1);
+  return isInt;
 }
 
 static
-int checkZaxisName(char *axisname, int fileID, int vlistID, int zaxisID, int nzaxis)
+int cdfInqDatatype(int xtype, bool lunsigned)
 {
-  char axisname2[CDI_MAX_NAME];
+  int datatype = -1;
 
-  /* check that the name is not already defined */
-  unsigned iz = 0;
+#if  defined  (HAVE_NETCDF4)
+  if ( xtype == NC_BYTE && lunsigned ) xtype = NC_UBYTE;
+#endif
 
-  size_t axisnameLen = strlen(axisname);
-  memcpy(axisname2, axisname, axisnameLen + 1);
-  do
-    {
-      if ( iz ) sprintf(axisname2 + axisnameLen, "_%u", iz+1);
+  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
 
-      int ncdimid, status = nc_inq_varid(fileID, axisname2, &ncdimid);
+  return datatype;
+}
 
-      if ( status != NC_NOERR )
-        {
-          if ( iz )
-            {
-              /* 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;
+
+/* not used
+int cdfInqRecord(stream_t *streamptr, int *varID, int *levelID)
+{
+  int tsID, recID;
+
+  recID = streamptr->tsteps[0].curRecID++;
+  printf("cdfInqRecord recID %d %d\n", recID, streamptr->tsteps[0].curRecID);
+  printf("cdfInqRecord tsID %d\n", streamptr->curTsID);
+
+  if ( streamptr->tsteps[0].curRecID >= streamptr->tsteps[0].nrecs )
+    {
+      streamptr->tsteps[0].curRecID = 0;
     }
-  while (iz <= 99);
 
+  *varID   = streamptr->tsteps[0].records[recID].varID;
+  *levelID = streamptr->tsteps[0].records[recID].levelID;
+
+  streamptr->record->varID   = *varID;
+  streamptr->record->levelID = *levelID;
 
-  if ( iz ) sprintf(axisname + axisnameLen, "_%u", iz+1);
+  if ( CDI_Debug )
+    Message("recID = %d  varID = %d  levelID = %d", recID, *varID, *levelID);
 
-  return (int)iz;
+  return (recID+1);
 }
+*/
 
-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;
+void cdf_scale_add(size_t size, double *data, double addoffset, double scalefactor)
+{
+  int laddoffset   = IS_NOT_EQUAL(addoffset, 0);
+  int lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
 
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
+  if ( laddoffset || lscalefactor )
+    {
+      for ( size_t i = 0; i < size; ++i )
+        {
+          if ( lscalefactor ) data[i] *= scalefactor;
+          if ( laddoffset )   data[i] += addoffset;
+        }
+    }
+}
+
+static
+void cdfCreateRecords(stream_t *streamptr, int tsID)
+{
+  if ( tsID < 0 || (tsID >= streamptr->ntsteps && tsID > 0) ) return;
 
-  if ( ndims ) ngrids = vlistNgrids(vlistID);
+  if ( streamptr->tsteps[tsID].nallrecs > 0 ) return;
 
-  size_t dimlen = (size_t)gridAxisInq->axisSize(gridID);
-  int gridindex = vlistGridIndex(vlistID, gridID);
+  int vlistID  = streamptr->vlistID;
 
-  const char *axisname = gridAxisInq->axisNamePtr(gridID);
-  size_t axisnameLen = strlen(axisname);
+  tsteps_t* sourceTstep = streamptr->tsteps;
+  tsteps_t* destTstep = sourceTstep + tsID;
 
-  if ( axisname[0] == 0 ) Error("axis name undefined!");
+  int nvars = vlistNvars(vlistID);
+  int nrecs = vlistNrecs(vlistID);
+
+  if ( nrecs <= 0 ) return;
 
-  for ( int index = 0; index < ngrids; index++ )
+  if ( tsID == 0 )
     {
-      if ( axisDimIDs[index] != UNDEFID )
+      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;
+
+      for ( int varID = 0, recID = 0; varID < nvars; varID++ )
         {
-          int gridID0 = vlistGrid(vlistID, index);
-          int gridtype0 = gridInqType(gridID0);
-          if ( gridtype0 == GRID_GAUSSIAN    ||
-               gridtype0 == GRID_LONLAT      ||
-               gridtype0 == GRID_CURVILINEAR ||
-               gridtype0 == GRID_GENERIC )
+          int zaxisID = vlistInqVarZaxis(vlistID, varID);
+          int nlev    = zaxisInqSize(zaxisID);
+          for ( int levelID = 0; levelID < nlev; levelID++ )
             {
-              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;
-                  }
-                }
+              recordInitEntry(&records[recID]);
+              records[recID].varID   = (short)varID;
+              records[recID].levelID = (short)levelID;
+              recID++;
             }
         }
     }
-
-  if ( dimID == UNDEFID )
+  else if ( tsID == 1 )
     {
-      const double *pvals = gridAxisInq->axisValsPtr(gridID);
-
-      /* 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);
-
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-
-      if ( ndims )
+      int nvrecs = 0;
+      for ( int varID = 0; varID < nvars; varID++ )
         {
-          char dimname[CDI_MAX_NAME+3];
-          dimname[0] = 0;
-
-          if ( pvals == NULL )
-            cdiGridInqString(gridID, dimKey, CDI_MAX_NAME, dimname);
-
-          if ( dimname[0] == 0 ) strcpy(dimname, extendedAxisname);
-          dimID = checkDimName(fileID, dimlen, dimname);
-
-          if ( dimID == UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID);
+          if ( vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT )
+            {
+              int zaxisID = vlistInqVarZaxis(vlistID, varID);
+              nvrecs += zaxisInqSize(zaxisID);
+            }
         }
 
-      bool gen_bounds = false;
-      int grid_is_cyclic = gridIsCircular(gridID);
-      double *pbounds = NULL;
-      if ( pvals )
-        {
-          cdf_def_var(fileID, extendedAxisname, xtype, ndims, &dimID, &ncvarid);
+      streamptr->nrecs += nvrecs;
 
-          cdfPutGridStdAtts(fileID, ncvarid, gridID, gridAxisInq);
-          {
-            char axisStr[2] = { axisLetter, '\0' };
-            cdf_put_att_text(fileID, ncvarid, "axis", 1, axisStr);
-          }
+      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
+      destTstep->nrecs      = nvrecs;
+      destTstep->nallrecs   = nrecs;
+      destTstep->recordSize = nrecs;
+      destTstep->curRecID   = CDI_UNDEFID;
 
-          pbounds = (double *)gridAxisInq->axisBoundsPtr(gridID);
+      memcpy(destTstep->records, sourceTstep->records, (size_t)nrecs*sizeof(record_t));
 
-          if ( CDI_cmor_mode && grid_is_cyclic && !pbounds )
+      if ( nvrecs )
+        {
+          destTstep->recIDs = (int *) Malloc((size_t)nvrecs * sizeof (int));
+          for ( int recID = 0, vrecID = 0; recID < nrecs; recID++ )
             {
-              gen_bounds = true;
-              pbounds = (double*) Malloc(2*dimlen*sizeof(double));
-              for ( size_t i = 0; i < dimlen-1; ++i )
+              int varID = destTstep->records[recID].varID;
+              if ( vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT )
                 {
-                  pbounds[i*2+1]   = (pvals[i] + pvals[i+1])/2;
-                  pbounds[(i+1)*2] = (pvals[i] + pvals[i+1])/2;
+                  destTstep->recIDs[vrecID++] = recID;
                 }
-              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 )
-            {
-              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);
             }
         }
+    }
+  else
+    {
+      if ( streamptr->tsteps[1].records == 0 ) cdfCreateRecords(streamptr, 1);
 
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
+      int nvrecs = streamptr->tsteps[1].nrecs;
 
-      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);
+      streamptr->nrecs += nvrecs;
 
-      if ( ndims == 0 ) ncAxisVarIDs[gridindex] = ncvarid;
-    }
+      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
+      destTstep->nrecs      = nvrecs;
+      destTstep->nallrecs   = nrecs;
+      destTstep->recordSize = nrecs;
+      destTstep->curRecID   = CDI_UNDEFID;
 
-  axisDimIDs[gridindex] = dimID;
-}
+      memcpy(destTstep->records, sourceTstep->records, (size_t)nrecs*sizeof(record_t));
 
-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;
+      destTstep->recIDs     = (int *) Malloc((size_t)nvrecs * sizeof(int));
+
+      memcpy(destTstep->recIDs, streamptr->tsteps[1].recIDs, (size_t)nvrecs*sizeof(int));
+    }
 }
 
 static
-void cdfDefXaxis(stream_t *streamptr, int gridID, int ndims)
+int cdf_time_dimid(int fileID, int ndims, int nvars)
 {
-  cdfDefAxisCommon(streamptr, gridID, ndims, &gridInqsX, streamptr->xdimID,
-                   CDI_GRID_XDIMNAME, 'X', finishCyclicXBounds,
-                   streamptr->ncxvarID);
-}
+  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;
+    }
 
-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 varid = 0; varid < nvars; ++varid )
+    {
+      nc_type xtype;
+      int nvdims, nvatts, dimids[9];
+      cdf_inq_var(fileID, varid, NULL, &xtype, &nvdims, dimids, &nvatts);
+      if ( nvdims == 1 )
+        {
+          char sbuf[CDI_MAX_NAME];
+          for ( int iatt = 0; iatt < nvatts; ++iatt )
+            {
+              sbuf[0] = 0;
+              cdf_inq_attname(fileID, varid, iatt, sbuf);
+              if ( strncmp(sbuf, "units", 5) == 0 )
+                {
+                  cdfGetAttText(fileID, varid, "units", sizeof(sbuf), sbuf);
+                  str_tolower(sbuf);
+
+                  if ( is_time_units(sbuf) ) return dimids[0];
+                }
+            }
+        }
+    }
+
+  return CDI_UNDEFID;
 }
 
 static
-void cdfDefYaxis(stream_t *streamptr, int gridID, int ndims)
+void init_ncdims(long ndims, ncdim_t *ncdims)
 {
-  cdfDefAxisCommon(streamptr, gridID, ndims, &gridInqsY, streamptr->ydimID,
-                   CDI_GRID_YDIMNAME, 'Y', finishCyclicYBounds,
-                   streamptr->ncyvarID);
+  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 cdfGridCompress(int fileID, int ncvarid, int gridsize, int filetype, int comptype)
+void init_ncvars(long nvars, ncvar_t *ncvars)
 {
-#if  defined  (HAVE_NETCDF4)
-  if ( gridsize > 1 && comptype == COMPRESS_ZIP && (filetype == FILETYPE_NC4 || filetype == FILETYPE_NC4C) )
+  for ( long ncvarid = 0; ncvarid < nvars; ++ncvarid )
     {
-      nc_def_var_chunking(fileID, ncvarid, NC_CHUNKED, NULL);
-      cdfDefVarDeflate(fileID, ncvarid, 1);
+      ncvars[ncvarid].ncid            = CDI_UNDEFID;
+      ncvars[ncvarid].isvar           = CDI_UNDEFID;
+      ncvars[ncvarid].ignore          = false;
+      ncvars[ncvarid].isx             = false;
+      ncvars[ncvarid].isy             = false;
+      ncvars[ncvarid].islon           = false;
+      ncvars[ncvarid].islat           = false;
+      ncvars[ncvarid].islev           = false;
+      ncvars[ncvarid].istime          = false;
+      ncvars[ncvarid].warn            = false;
+      ncvars[ncvarid].climatology     = false;
+      ncvars[ncvarid].lformulaterms   = false;
+      ncvars[ncvarid].tsteptype       = TSTEP_CONSTANT;
+      ncvars[ncvarid].param           = CDI_UNDEFID;
+      ncvars[ncvarid].code            = CDI_UNDEFID;
+      ncvars[ncvarid].tabnum          = 0;
+      ncvars[ncvarid].calendar        = FALSE;
+      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 )
+        ncvars[ncvarid].coordvarids[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);
     }
-#endif
 }
 
 static
-void cdfDefCurvilinear(stream_t *streamptr, int gridID)
+void cdf_set_var(ncvar_t *ncvars, int ncvarid, short isvar)
 {
-  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;
-
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
+  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);
 
-  int ngrids = vlistNgrids(vlistID);
+      ncvars[ncvarid].warn = true;
+      isvar = FALSE;
+    }
 
-  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);
+  ncvars[ncvarid].isvar = isvar;
+}
 
-  for ( int index = 0; index < ngrids; index++ )
+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 )
     {
-      if ( streamptr->xdimID[index] != UNDEFID )
-        {
-          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;
-                  }
-            }
-        }
+      Warning("Inconsistent dimension definition for %s! dimid = %d;  type = %d;  newtype = %d",
+              ncvars[ncvarid].name, dimid, ncvars[ncvarid].dimtype[dimid], dimtype);
     }
 
-  if ( xdimID == UNDEFID || ydimID == 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 ) { 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);
-      }
+  ncvars[ncvarid].dimtype[dimid] = dimtype;
+}
 
-      int nvdimID = UNDEFID;
-      int dimIDs[3];
-      if ( gridInqXboundsPtr(gridID) || gridInqYboundsPtr(gridID) )
+static
+int scan_hybrid_formulaterms(int ncid, int ncfvarid, int *apvarid, int *bvarid, int *psvarid, int *avarid, int *p0varid)
+{
+  int status = 1;
+  *apvarid = -1;
+  *bvarid  = -1;
+  *psvarid = -1;
+  *avarid  = -1;
+  *p0varid = -1;
+  char attstring[1024];
+
+  bool lstop = false;
+  int dimvarid;
+  cdfGetAttText(ncid, ncfvarid, "formula_terms", sizeof(attstring), attstring);
+  char *pstring = attstring;
+
+  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;
+
+      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 )
         {
-          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);
+          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, "p0:") == 0 ) *p0varid = dimvarid;
         }
-
-      dimIDs[0] = ydimID;
-      dimIDs[1] = xdimID;
-      dimIDs[2] = nvdimID;
-
-      if ( gridInqXvalsPtr(gridID) )
+      else if ( strcmp(tagname, "ps:") != 0 )
         {
-          char xaxisname[CDI_MAX_NAME];
-          gridInqXname(gridID, xaxisname);
-          checkGridName(xaxisname, fileID, vlistID, gridID, ngrids, 'X');
-
-          cdf_def_var(fileID, xaxisname, xtype, 2, dimIDs, &ncxvarid);
-          cdfGridCompress(fileID, ncxvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
-
-          cdfPutGridStdAtts(fileID, ncxvarid, gridID, &gridInqsX);
-
-          /* attribute for Panoply */
-          cdf_put_att_text(fileID, ncxvarid, "_CoordinateAxisType", 3, "Lon");
-
-          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);
-
-              cdf_put_att_text(fileID, ncxvarid, "bounds", xaxisnameLen + sizeof (bndsName), xaxisname);
-            }
+          Warning("%s - %s", nc_strerror(status_nc), varname);
         }
 
-      if ( gridInqYvalsPtr(gridID) )
-        {
-          char yaxisname[CDI_MAX_NAME];
-          gridInqYname(gridID, yaxisname);
-          checkGridName(yaxisname, fileID, vlistID, gridID, ngrids, 'Y');
+      if ( lstop ) break;
+    }
 
-          cdf_def_var(fileID, yaxisname, xtype, 2, dimIDs, &ncyvarid);
-          cdfGridCompress(fileID, ncyvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
+  return status;
+}
 
-          cdfPutGridStdAtts(fileID, ncyvarid, gridID, &gridInqsY);
+static
+bool isHybridSigmaPressureCoordinate(int ncid, int ncvarid, ncvar_t *ncvars, const ncdim_t *ncdims)
+{
+  bool status = false;
+  ncvar_t *ncvar = &ncvars[ncvarid];
 
-          /* attribute for Panoply */
-          cdf_put_att_text(fileID, ncyvarid, "_CoordinateAxisType", 3, "Lat");
+  if ( strcmp(ncvar->stdname, "atmosphere_hybrid_sigma_pressure_coordinate") == 0 )
+    {
+      cdiConvention = CDI_CONVENTION_CF;
 
-          if ( gridInqYboundsPtr(gridID) && nvdimID != UNDEFID )
-            {
-              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);
+      status = true;
+      ncvar->zaxistype = ZAXIS_HYBRID;
+      int dimid = ncvar->dimids[0];
+      size_t dimlen = ncdims[dimid].len;
 
-              cdf_put_att_text(fileID, ncyvarid, "bounds", yaxisnameLen + sizeof (bndsName), yaxisname);
-            }
-        }
+      int ret = 0;
+      int apvarid1 = -1, bvarid1 = -1, psvarid1 = -1, avarid1 = -1, p0varid1 = -1;
+      int ncfvarid = ncvarid;
+      if ( ncvars[ncfvarid].lformulaterms )
+        ret = scan_hybrid_formulaterms(ncid, ncfvarid, &apvarid1, &bvarid1, &psvarid1, &avarid1, &p0varid1);
+      // printf("ret %d apvarid1, bvarid1, psvarid1, avarid1, p0varid1 %d %d %d %d %d\n", ret, 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;
 
-      if ( gridInqAreaPtr(gridID) )
+      if ( ncvar->bounds != CDI_UNDEFID && ncvars[ncvar->bounds].lformulaterms )
         {
-          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";
+          ncfvarid = ncvar->bounds;
+          int apvarid2 = -1, bvarid2 = -1, psvarid2 = -1, avarid2 = -1, p0varid2 = -1;
+          ret = 0;
+          if ( ncvars[ncfvarid].lformulaterms )
+            ret = scan_hybrid_formulaterms(ncid, ncfvarid, &apvarid2, &bvarid2, &psvarid2, &avarid2, &p0varid2);
+          // printf("ret %d apvarid2, bvarid2, psvarid2, avarid2, p0varid2 %d %d %d %d %d\n", ret, apvarid2, bvarid2, psvarid2, avarid2, p0varid2);
+          if ( ret == 1 ) avarid2 = apvarid2;
+          if ( avarid2 != -1 && bvarid2 != -1 )
+            {
+              ncvars[avarid2].isvar = FALSE;
+              ncvars[bvarid2].isvar = FALSE;
 
-          cdf_def_var(fileID, yaxisname_, xtype, 2, dimIDs, &ncavarid);
+              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);
 
-          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);
-        }
+                  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];
 
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
+                  if ( ret == 2 && IS_NOT_EQUAL(px, 1) )
+                    for ( size_t i = 0; i < dimlen+1; ++i ) vct[i] *= px;
 
-      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));
+                  ncvar->vct = vct;
+                  ncvar->vctsize = vctsize;
+                }
+            }
+        }
     }
 
-  streamptr->xdimID[gridindex] = xdimID;
-  streamptr->ydimID[gridindex] = ydimID;
-  streamptr->ncxvarID[gridindex] = ncxvarid;
-  streamptr->ncyvarID[gridindex] = ncyvarid;
-  streamptr->ncavarID[gridindex] = ncavarid;
+  return status;
 }
 
 static
-void cdfDefRgrid(stream_t *streamptr, int gridID)
+void cdf_set_cdi_attr(int ncid, int ncvarid, int attnum, int cdiID, int varID)
 {
-  int dimID = UNDEFID;
-
-  int vlistID = streamptr->vlistID;
-  int ngrids = vlistNgrids(vlistID);
+  nc_type atttype;
+  size_t attlen;
+  char attname[CDI_MAX_NAME];
 
-  size_t dimlen = (size_t)gridInqSize(gridID);
+  cdf_inq_attname(ncid, ncvarid, attnum, attname);
+  cdf_inq_attlen(ncid, ncvarid, attname, &attlen);
+  cdf_inq_atttype(ncid, ncvarid, attname, &atttype);
 
-  int iz = 0;
-  for ( int index = 0; index < ngrids; index++ )
+  if ( xtypeIsInt(atttype) )
     {
-      if ( streamptr->xdimID[index] != UNDEFID )
-        {
-          int gridID0 = vlistGrid(vlistID, index);
-          int gridtype0 = gridInqType(gridID0);
-          if ( gridtype0 == GRID_GAUSSIAN_REDUCED )
-            {
-              size_t dimlen0 = (size_t)gridInqSize(gridID0);
-
-              if ( dimlen == dimlen0 )
-                {
-                  dimID = streamptr->xdimID[index];
-                  break;
-                }
-              iz++;
-            }
-        }
+      int attint[attlen];
+      cdfGetAttInt(ncid, ncvarid, attname, (int)attlen, attint);
+      int datatype = (atttype == NC_SHORT)  ? DATATYPE_INT16 :
+                     (atttype == NC_BYTE)   ? DATATYPE_INT8 :
+#if  defined  (HAVE_NETCDF4)
+                     (atttype == NC_UBYTE)  ? DATATYPE_UINT8 :
+                     (atttype == NC_USHORT) ? DATATYPE_UINT16 :
+                     (atttype == NC_UINT)   ? DATATYPE_UINT32 :
+#endif
+                     DATATYPE_INT32;
+      cdiDefAttInt(cdiID, varID, attname, datatype, (int)attlen, attint);
     }
-
-  if ( dimID == UNDEFID )
+  else if ( xtypeIsFloat(atttype) )
     {
-      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;
-        }
-
-      char axisname[7] = "rgridX";
-      if ( iz == 0 ) axisname[5] = '\0';
-      else           sprintf(&axisname[5], "%1d", iz+1);
-
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-
-      cdf_def_dim(fileID, axisname, dimlen, &dimID);
-
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
+      double attflt[attlen];
+      cdfGetAttDouble(ncid, ncvarid, attname, (int)attlen, attflt);
+      int datatype = (atttype == NC_FLOAT) ? DATATYPE_FLT32 : 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);
     }
-
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  streamptr->xdimID[gridindex] = dimID;
 }
 
 static
-void cdfDefGdim(stream_t *streamptr, int gridID)
+void cdf_print_vars(const ncvar_t *ncvars, int nvars, const char *oname)
 {
-  int iz = 0;
-  int dimID = UNDEFID;
-
-  int vlistID = streamptr->vlistID;
-  int ngrids = vlistNgrids(vlistID);
-
-  size_t dimlen = (size_t)gridInqSize(gridID);
-
-  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++;
-              }
-          }
-      }
+  char axis[7];
+  static const char iaxis[] = {'t', 'z', 'y', 'x'};
 
-  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++;
-              }
-          }
-      }
+  fprintf(stderr, "%s:\n", oname);
 
-  if ( dimID == UNDEFID )
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
     {
-      int fileID  = streamptr->fileID;
-      char dimname[CDI_MAX_NAME];
-      strcpy(dimname, "gsize");
-
-      dimID = checkDimName(fileID, dimlen, dimname);
-
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+      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 ( dimID == UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID);
+      axis[ndim++] = 0;
 
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
+      fprintf(stderr, "%3d %3d  %-6s %s\n", ncvarid, ndim-3, axis, ncvars[ncvarid].name);
     }
-
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  streamptr->xdimID[gridindex] = dimID;
 }
 
 static
-void cdfDefGridReference(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)
 {
-  int fileID  = streamptr->fileID;
-  int number = gridInqNumber(gridID);
-
-  if ( number > 0 )
+  int i;
+  for ( i = 0; i < (int)attlen; ++i )
     {
-      cdf_put_att_int(fileID, NC_GLOBAL, "number_of_grid_used", NC_INT, 1, &number);
+      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;
+        }
     }
 
-  const char *gridfile = gridInqReferencePtr(gridID);
-  if ( gridfile && gridfile[0] != 0 )
-    cdf_put_att_text(fileID, NC_GLOBAL, "grid_file_uri", strlen(gridfile), gridfile);
-}
-
-static
-void cdfDefGridUUID(stream_t *streamptr, int gridID)
-{
-  unsigned char uuidOfHGrid[CDI_UUID_SIZE];
-
-  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];
+
+  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;
 
-  if ( gridInqPrec(gridID) == DATATYPE_FLT32 ) xtype = NC_FLOAT;
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      int ncid    = ncvars[ncvarid].ncid;
+      int *dimidsp = ncvars[ncvarid].dimids;
 
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
+      cdf_inq_var(ncid, ncvarid, name, &xtype, &nvdims, dimidsp, &nvatts);
+      strcpy(ncvars[ncvarid].name, name);
 
-  int ngrids = vlistNgrids(vlistID);
+      for ( ncdimid = 0; ncdimid < nvdims; ncdimid++ )
+        ncvars[ncvarid].dimtype[ncdimid] = -1;
 
-  size_t dimlen = (size_t)gridInqSize(gridID);
-  int gridindex = vlistGridIndex(vlistID, gridID);
+      ncvars[ncvarid].xtype = xtype;
+      ncvars[ncvarid].ndims = nvdims;
 
-  for ( int index = 0; index < ngrids; index++ )
-    {
-      if ( streamptr->xdimID[index] != UNDEFID )
+#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;
+
+          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] = (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;
+                  }
+                }
             }
         }
-    }
-
-  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].tsteptype = TSTEP_INSTANT;
+              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);
+          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 ( !isText && strcmp(attname, "code") == 0 )
+            {
+              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].code);
+              cdf_set_var(ncvars, ncvarid, TRUE);
+            }
+          else if ( !isText && 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 ( !isText && strcmp(attname, "trunc_count") == 0 )
+            {
+              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].truncation);
+            }
+          else if ( !isText && strcmp(attname, "truncation") == 0 )
+            {
+              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].truncation);
+            }
+          else if ( !isText && strcmp(attname, "number_of_grid_in_reference") == 0 )
+            {
+              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].position);
+            }
+          else if ( !isText && 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 ( !isText && 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;
+                  *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 == 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;
 
-      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 == FALSE )
+                        {
+                          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 ( !isText && strcmp(attname, "_FillValue") == 0 )
+            {
+	      cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].fillval);
+	      ncvars[ncvarid].deffillval = true;
+	      /* cdf_set_var(ncvars, ncvarid, TRUE); */
+            }
+          else if ( !isText && 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 ( strcmp(attname, "valid_range") == 0 && attlen == 2 )
+            {
+              if ( ncvars[ncvarid].lvalidrange == false )
+                {
+                  extern int cdiIgnoreValidRange;
+                  bool 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;
+                      /* cdf_set_var(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;
+                  bool 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 ( ncvars[ncvarid].lvalidrange == false )
+                {
+                  extern int cdiIgnoreValidRange;
+                  bool 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 ( 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 ( ( 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;
-        }
-
-      int fileID = streamptr->fileID;
+      if ( ncvars[ncvarid].isvar == TRUE )
+	{
+	  int ndims = ncvars[ncvarid].ndims;
+	  for ( int i = 0; i < ndims; i++ )
+	    {
+	      int ncdimid = ncvars[ncvarid].dimids[i];
+	      if      ( ncdims[ncdimid].dimtype == X_AXIS ) cdf_set_dim(ncvars, ncvarid, i, X_AXIS);
+	      else if ( ncdims[ncdimid].dimtype == Y_AXIS ) cdf_set_dim(ncvars, ncvarid, i, Y_AXIS);
+	      else if ( ncdims[ncdimid].dimtype == Z_AXIS ) cdf_set_dim(ncvars, ncvarid, i, Z_AXIS);
+	      else if ( ncdims[ncdimid].dimtype == T_AXIS ) cdf_set_dim(ncvars, ncvarid, i, T_AXIS);
+	    }
 
-      if ( streamptr->ncmode == 2 ) cdf_redef(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");
+	    }
+          }
+      }
 
-      int dimIDs[2];
-      dimIDs[0] = nclevID;
-      dimIDs[1] = ncbndsID;
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      if ( ncvars[ncvarid].isvar == TRUE )
+	{
+	  bool lxdim = false, lydim = false, lzdim = false/* , ltdim = false */;
+	  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].dimtype[i] == T_AXIS ) ltdim = true; */
+	    }
 
-      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 )
+                      {
+                        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;
-
-      const double *vctptr = zaxisInqVctPtr(zaxisID);
-      double tarray[ilev*2];
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      if ( ncvars[ncvarid].isvar == TRUE )
+	{
+	  bool lxdim = false, lydim = false, lzdim = false/* , ltdim = false */;
+	  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].dimtype[i] == T_AXIS ) ltdim = true; */
+	    }
 
-      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 )
+                      {
+                        cdf_set_dim(ncvars, ncvarid, i, X_AXIS);
+                        lxdim = true;
+                      }
+                    else if ( !lydim && ncvars[ncvarid].gridtype != GRID_UNSTRUCTURED )
+                      {
+                        cdf_set_dim(ncvars, ncvarid, i, Y_AXIS);
+                        lydim = true;
+                      }
+                    else if ( !lzdim )
+                      {
+                        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 ( 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) )
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
     {
-      size_t nvertex = 2;
-      if ( nc_inq_dimid(fileID, bndsName, &nvdimID) != NC_NOERR )
-        cdf_def_dim(fileID, bndsName, nvertex, &nvdimID);
+      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 ( 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;
+		}
+            }
 
-      if ( nvdimID != 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",
-              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);
-          }
-        }
+	  /* 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;
+		}
+	    }
+	}
     }
+}
 
-  cdf_enddef(fileID);
-  streamptr->ncmode = 2;
-
-  cdf_put_var_double(fileID, ncvarid, levels);
-
-  if ( ncbvarid != UNDEFID )
+static
+void grid_set_chunktype(grid_t *grid, ncvar_t *ncvar)
+{
+  if ( ncvar->chunked )
     {
-      double zbounds[2*dimlen];
-      for ( size_t i = 0; i < dimlen; ++i )
+      int ndims = ncvar->ndims;
+
+      if ( grid->type == GRID_UNSTRUCTURED )
         {
-          zbounds[2*i  ] = lbounds[i];
-          zbounds[2*i+1] = ubounds[i];
+          if ( ncvar->chunks[ndims-1] == grid->size )
+            ncvar->chunktype = CDI_CHUNK_GRID;
+          else
+            ncvar->chunktype = CDI_CHUNK_AUTO;
+        }
+      else
+        {
+          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_bounds(size_t size, ncvar_t *ncvar, double **gridbounds, struct cdfLazyGridIds *cellBoundsGet)
 {
-  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);
+  if ( CDI_netcdf_lazy_grid_load )
+    {
+      cellBoundsGet->datasetNCId = ncvar->ncid;
+      cellBoundsGet->varNCId  = ncvar->bounds;
+      *gridbounds = cdfPendingLoad;
+    }
   else
-    cdf_def_zaxis_hybrid_cf(streamptr, type, ncvarid, zaxisID, zaxisindex, xtype, dimlen, dimID, axisname);
+    {
+      *gridbounds = (double*) Malloc(size*sizeof(double));
+      cdf_get_var_double(ncvar->ncid, ncvar->bounds, *gridbounds);
+    }
 }
 
 static
-void cdfDefZaxis(stream_t *streamptr, int zaxisID)
+void cdf_load_cellarea(size_t size, ncvar_t *ncvar, double **gridarea, struct cdfLazyGridIds *cellAreaGet)
 {
-  /*  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);
-        }
+      cellAreaGet->datasetNCId = ncvar->ncid;
+      cellAreaGet->varNCId = ncvar->cellarea;
+      *gridarea = 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);
+      *gridarea = (double*) Malloc(size*sizeof(double));
+      cdf_get_var_double(ncvar->ncid, ncvar->cellarea, *gridarea);
+    }
+}
 
-      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);
+static
+void cdf_copy_axis_attr(ncvar_t *ncvar, struct gridaxis_t *gridaxis)
+{
+  strcpy(gridaxis->name, ncvar->name);
+  strcpy(gridaxis->longname, ncvar->longname);
+  strcpy(gridaxis->units, ncvar->units);
+}
 
-      if ( type == ZAXIS_REFERENCE ) cdfDefZaxisUUID(streamptr, zaxisID);
+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};
 
-      if ( type == ZAXIS_HYBRID || type == ZAXIS_HYBRID_HALF )
+  for ( int i = 0; i < ndims; i++ )
+    {
+      if ( dimtype[i] == X_AXIS && nxdims < 2 )
         {
-          cdf_def_zaxis_hybrid(streamptr, type, ncvarid, zaxisID, zaxisindex, xtype, dimlen, &dimID, axisname);
+          xdimids[nxdims] = dimids[i];
+          nxdims++;
         }
-      else
+      else if ( dimtype[i] == Y_AXIS && nydims < 2 )
         {
-          dimID = checkDimName(fileID, dimlen, dimname);
-
-          if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-
-          if ( ndims && dimID == UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID);
+          ydimids[nydims] = dimids[i];
+          nydims++;
+        }
+    }
 
-          cdf_def_var(fileID, axisname, (nc_type) xtype, ndims, &dimID, &ncvarid);
+  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];
+    }
 
-          cdfPutGridStdAtts(fileID, ncvarid, zaxisID, &gridInqsZ);
+  return nydims;
+}
 
-          {
-            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 )
+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 && (int) 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) )
               {
-                size_t select = positive == POSITIVE_DOWN;
-                cdf_put_att_text(fileID, ncvarid, "positive",
-                                 tab[select].txtLen, tab[select].txt);
+                yinc = 0;
+                break;
               }
-          }
-          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);
-	    }
-
-          if ( ndims == 0 ) streamptr->nczvarID[zaxisindex] = ncvarid;
         }
+      if ( ysize < 10000 && isGaussGrid(ysize, yinc, grid->y.vals) )
+        {
+          *gridtype = GRID_GAUSSIAN;
+          grid->np = (int)(ysize/2);
+        }
+      else
+        *gridtype = GRID_LONLAT;
     }
-
-  if ( dimID != UNDEFID )
-    streamptr->zaxisID[zaxisindex] = dimID;
+  else if ( islon && !islat && ysize == 0 )
+    {
+      *gridtype = GRID_LONLAT;
+    }
+  else
+    *gridtype = GRID_GENERIC;
 }
 
 static
-void cdfDefPole(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;
-  static const char varname[] = "rotated_pole";
-  static const char mapname[] = "rotated_latitude_longitude";
+  grid_t *grid = &lazyGrid->base;
+  bool skipvar = true;
+  *islon = axisvar->islon;
+  int ndims = axisvar->ndims;
+  size_t size = 0;
+  if ( (ndims - ntdims) == 2 )
+    {
+      ncvar->gridtype = GRID_CURVILINEAR;
+      size = (*xsize)*ysize;
+      /* 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;
+      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;
+    }
 
-  int fileID  = streamptr->fileID;
+  if ( skipvar )
+    {
+      Warning("Unsupported array structure, skipped variable %s!", ncvar->name);
+      ncvar->isvar = -1;
+      return true;
+    }
 
-  double ypole = gridInqYpole(gridID);
-  double xpole = gridInqXpole(gridID);
-  double angle = gridInqAngle(gridID);
+  if ( axisvar->xtype == NC_FLOAT ) grid->prec = DATATYPE_FLT32;
 
-  cdf_redef(fileID);
+  cdf_load_vals(size, ndims, xvarid, axisvar, &grid->x.vals, &lazyGrid->xValsGet, ntdims, start, count);
 
-  int ncerrcode = nc_def_var(fileID, varname, (nc_type) NC_CHAR, 0, NULL, &ncvarid);
-  if ( ncerrcode == NC_NOERR )
-    {
-      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);
-    }
+  cdf_copy_axis_attr(axisvar, &grid->x);
 
-  cdf_enddef(fileID);
+  return false;
 }
 
-
 static
-void cdfDefMapping(stream_t *streamptr, int gridID)
+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)
 {
-  int ncvarid = UNDEFID;
-  int fileID  = streamptr->fileID;
-
-  if ( gridInqType(gridID) == GRID_SINUSOIDAL )
+  grid_t *grid = &lazyGrid->base;
+  bool skipvar = true;
+  *islat = axisvar->islat;
+  int ndims = axisvar->ndims;
+  size_t size = 0;
+  if ( (ndims - ntdims) == 2 )
     {
-      static const char varname[] = "sinusoidal";
-      static const char mapname[] = "sinusoidal";
-
-      cdf_redef(fileID);
-
-      int ncerrcode = nc_def_var(fileID, varname, (nc_type) NC_CHAR, 0, NULL, &ncvarid);
-      if ( ncerrcode == NC_NOERR )
-        {
-          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);
-          */
-        }
-
-      cdf_enddef(fileID);
+      ncvar->gridtype = GRID_CURVILINEAR;
+      size = xsize*(*ysize);
+      /* 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;
+      skipvar = dimsize1*dimsize2 != size;
     }
-  else if ( gridInqType(gridID) == GRID_LAEA )
+  else if ( (ndims - ntdims) == 1 )
     {
-      static const char varname[] = "laea";
-      static const char mapname[] = "lambert_azimuthal_equal_area";
-
-      cdf_redef(fileID);
-
-      int ncerrcode = nc_def_var(fileID, varname, (nc_type) NC_CHAR, 0, NULL, &ncvarid);
-      if ( ncerrcode == NC_NOERR )
-        {
-          double a, lon_0, lat_0;
+      if ( (int) *ysize == 0 ) size = xsize;
+      else                    size = *ysize;
 
-          gridInqLaea(gridID, &a, &lon_0, &lat_0);
-
-          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);
-        }
-
-      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 ( axisvar->xtype == NC_FLOAT ) grid->prec = DATATYPE_FLT32;
 
-          gridInqLcc2(gridID, &radius, &lon_0, &lat_0, &lat_1, &lat_2);
+  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->prec = 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 )
             {
-              /* 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      ( (int) ysize == 0 ) size = xsize;
+      else if ( (int) 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  = (int)size;
+        grid->x.size = (int)xsize;
+        grid->y.size = (int)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(grid->size*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(grid->size*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 = (int)size;
+        grid->lcomplex = 1;
+        grid->trunc = ncvar->truncation;
+        break;
+      }
+    case GRID_FOURIER:
+      {
+        grid->size = (int)size;
+        grid->trunc = ncvar->truncation;
+        break;
+      }
+    case GRID_TRAJECTORY:
+      {
+        grid->size = 1;
+        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 == 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("Variable %s has an unsupported grid, skipped!", 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_MAPPING, (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;
 
-  laddoffset   = IS_NOT_EQUAL(addoffset, 0);
-  lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
+      for ( int i = 0; i < ndims2; i++ )
+        {
+          int *dimtype2 = ncvar2->dimtype;
+          int *dimids2 = ncvar2->dimids;
+          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]; }
+        }
 
-  if ( laddoffset || lscalefactor )
-    {
-      for (size_t i = 0; i < size; ++i )
+      if ( ncvar2->gridtype == CDI_UNDEFID && gridtype == GRID_UNSTRUCTURED )
         {
-          if ( lscalefactor ) data[i] *= scalefactor;
-          if ( laddoffset )   data[i] += addoffset;
+          if ( xdimid == xdimid2 && ydimid2 != CDI_UNDEFID && zdimid2 == CDI_UNDEFID )
+            {
+              ncvar2->dimtype[ydimidx] = Z_AXIS;
+              ydimid2 = CDI_UNDEFID;
+            }
+
+          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)) )
+        {
+          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)
+void cdf_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)
 {
-  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 gmapvarid = ncvar->gmapid;
+          bool lproj = gmapvarid != CDI_UNDEFID;
+          bool lgrid = !(lproj && ncvar->xvarid == 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;
+          bool lunstructured = xdimid != CDI_UNDEFID && xdimid == ydimid && nydims == 0;
+	  if ( (ncvar->gridtype == CDI_UNDEFID || ncvar->gridtype == GRID_GENERIC) && lunstructured )
+            ncvar->gridtype = GRID_UNSTRUCTURED;
 
-  int vlistID  = streamptr->vlistID;
+          struct cdfLazyGrid *restrict lazyGrid = NULL, *restrict lazyProj = NULL;
 
-  tsteps_t* sourceTstep = streamptr->tsteps;
-  tsteps_t* destTstep = sourceTstep + tsID;
+          {
+            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;
 
-  int nvars = vlistNvars(vlistID);
-  int nrecs = vlistNrecs(vlistID);
+          xaxisid = (xdimid != CDI_UNDEFID) ? ncdims[xdimid].ncvarid : CDI_UNDEFID;
+          yaxisid = (ydimid != CDI_UNDEFID) ? ncdims[ydimid].ncvarid : CDI_UNDEFID;
 
-  if ( nrecs <= 0 ) return;
 
-  if ( tsID == 0 )
-    {
-      int nvrecs = nrecs; /* use all records at first timestep */
+          if ( cdf_read_coordinates(lazyGrid, ncvar, ncvars, ncdims,
+                                    timedimid, xvarid, yvarid, xsize, ysize, &vdimid) )
+            continue;
 
-      streamptr->nrecs += nrecs;
+	  if ( number_of_grid_used != CDI_UNDEFID && (grid->type == CDI_UNDEFID || grid->type == GRID_GENERIC) )
+            grid->type = GRID_UNSTRUCTURED;
 
-      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;
+          if ( grid->type == GRID_UNSTRUCTURED )
+            if ( cdf_set_unstructured_par(ncvar, grid, xdimid, ydimid, number_of_grid_used, uuidOfHGrid) )
+              continue;
 
-      record_t *records = destTstep->records;
+          if ( lproj && lgrid )
+            {
+              int dumid;
+              cdf_read_coordinates(lazyProj, ncvar, ncvars, ncdims, timedimid,
+                                   xaxisid, yaxisid, xsize, ysize, &dumid);
+	    }
 
-      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 ( CDI_Debug )
+	    {
+	      Message("grid: type = %d, size = %d, nx = %d, ny %d",
+		      grid->type, grid->size, grid->x.size, grid->y.size);
+              if ( proj )
+                Message("proj: type = %d, size = %d, nx = %d, ny %d",
+                        proj->type, proj->size, proj->x.size, proj->y.size);
+	    }
+
+
+          if ( lgrid && lproj )
             {
-              recordInitEntry(&records[recID]);
-              records[recID].varID   = (short)varID;
-              records[recID].levelID = (short)levelID;
-              recID++;
+              projAdded = cdiVlistAddGridIfNew(vlistID, proj, 2);
+              grid->proj = projAdded.Id;
             }
-        }
+
+          gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 1);
+          ncvar->gridID = gridAdded.Id;
+
+          int gridID = ncvar->gridID;
+
+          if ( lproj )
+            {
+              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_MAPNAME, (int)(strlen(gmapname)+1), gmapname);
+              gridVerifyProj(projID);
+            }
+
+          if ( grid->type == GRID_UNSTRUCTURED && gridfile[0] != 0 )
+            gridDefReference(gridID, gridfile);
+
+          if ( ncvar->chunked ) grid_set_chunktype(grid, ncvar);
+
+	  int gridindex = vlistGridIndex(vlistID, gridID);
+	  streamptr->xdimID[gridindex] = xdimid;
+	  streamptr->ydimID[gridindex] = ydimid;
+          if ( xdimid == CDI_UNDEFID && ydimid == CDI_UNDEFID && grid->size == 1 )
+            gridDefHasDims(gridID, FALSE);
+
+          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);
+
+	  if ( CDI_Debug ) Message("gridID %d %d %s", gridID, ncvarid, ncvar->name);
+
+	  for ( int ncvarid2 = ncvarid+1; ncvarid2 < nvars; ncvarid2++ )
+            cdf_set_grid_to_similar_vars(ncvar, &ncvars[ncvarid2], grid->type, xdimid, ydimid);
+
+          if ( gridAdded.isNew ) lazyGrid = NULL;
+          if ( projAdded.isNew ) lazyProj = NULL;
+
+          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); }
+            }
+	}
     }
-  else if ( tsID == 1 )
+}
+
+/* define all input zaxes */
+static
+void 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)
+{
+  char *pname, *plongname, *punits;
+  size_t vctsize = vctsize_echam;
+  double *vct = vct_echam;
+
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
     {
-      int nvrecs = 0;
-      for ( int varID = 0; varID < nvars; varID++ )
-        {
-          if ( vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT )
+      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;
+	  int zsize = 1;
+          int psvarid = -1;
+	  double *lbounds = NULL;
+	  double *ubounds = NULL;
+
+          int positive = 0;
+	  int ndims = ncvar->ndims;
+
+          if ( ncvar->zvarid != -1 && ncvars[ncvar->zvarid].ndims == 0 )
             {
-              int zaxisID = vlistInqVarZaxis(vlistID, varID);
-              nvrecs += zaxisInqSize(zaxisID);
+              zvarid = ncvar->zvarid;
+              is_scalar = true;
             }
-        }
+          else
+            {
+              for ( int i = 0; i < ndims; i++ )
+                {
+                  if ( ncvar->dimtype[i] == Z_AXIS )
+                    zdimid = ncvar->dimids[i];
+                }
 
-      streamptr->nrecs += nvrecs;
+              if ( zdimid != CDI_UNDEFID )
+                {
+                  zvarid = ncdims[zdimid].ncvarid;
+                  zsize  = (int)ncdims[zdimid].len;
+                }
+            }
+
+	  if ( CDI_Debug ) Message("nlevs = %d", zsize);
+
+	  double *zvar = (double *) Malloc((size_t)zsize * sizeof (double));
+
+	  int zaxisType = CDI_UNDEFID;
+	  if ( zvarid != CDI_UNDEFID ) zaxisType = ncvars[zvarid].zaxistype;
+	  if ( zaxisType == CDI_UNDEFID ) zaxisType = ZAXIS_GENERIC;
+
+	  int zprec = DATATYPE_FLT64;
+
+	  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 ) 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;
+	      */
+              if ( zaxisType == ZAXIS_HYBRID && ncvars[zvarid].vct )
+                {
+                  vct = ncvars[zvarid].vct;
+                  vctsize = ncvars[zvarid].vctsize;
 
-      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
-      destTstep->nrecs      = nvrecs;
-      destTstep->nallrecs   = nrecs;
-      destTstep->recordSize = nrecs;
-      destTstep->curRecID   = UNDEFID;
+                  if ( ncvars[zvarid].psvarid != -1 ) psvarid = ncvars[zvarid].psvarid;
+                }
 
-      memcpy(destTstep->records, sourceTstep->records, (size_t)nrecs*sizeof(record_t));
+	      cdf_get_var_double(ncvars[zvarid].ncid, zvarid, zvar);
 
-      if ( nvrecs )
-        {
-          destTstep->recIDs = (int *) Malloc((size_t)nvrecs * sizeof (int));
-          for ( int recID = 0, vrecID = 0; recID < nrecs; recID++ )
-            {
-              int varID = destTstep->records[recID].varID;
-              if ( vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT )
-                {
-                  destTstep->recIDs[vrecID++] = recID;
-                }
-            }
-        }
-    }
-  else
-    {
-      if ( streamptr->tsteps[1].records == 0 ) cdfCreateRecords(streamptr, 1);
+	      if ( ncvars[zvarid].bounds != CDI_UNDEFID )
+		{
+		  int nbdims = ncvars[ncvars[zvarid].bounds].ndims;
+		  if ( nbdims == 2 )
+		    {
+		      int nlevel  = (int)ncdims[ncvars[ncvars[zvarid].bounds].dimids[0]].len;
+		      int 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 ( int i = 0; i < nlevel; ++i )
+			    {
+			      lbounds[i] = zbounds[i*2];
+			      ubounds[i] = zbounds[i*2+1];
+			    }
+			}
+		    }
+		}
+	    }
+	  else
+	    {
+	      pname     = NULL;
+	      plongname = NULL;
+	      punits    = NULL;
 
-      int nvrecs = streamptr->tsteps[1].nrecs;
+	      if ( zsize == 1 )
+		{
+                  if ( ncvar->zaxistype != CDI_UNDEFID )
+                    zaxisType = ncvar->zaxistype;
+                  else
+                    zaxisType = ZAXIS_SURFACE;
 
-      streamptr->nrecs += nvrecs;
+		  zvar[0] = 0;
+		  /*
+		  if ( zdimid == CDI_UNDEFID )
+		    zvar[0] = 9999;
+		  else
+		    zvar[0] = 0;
+		  */
+		}
+	      else
+		{
+		  for ( int ilev = 0; ilev < zsize; ilev++ ) zvar[ilev] = ilev + 1;
+		}
+	    }
 
-      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
-      destTstep->nrecs      = nvrecs;
-      destTstep->nallrecs   = nrecs;
-      destTstep->recordSize = nrecs;
-      destTstep->curRecID   = UNDEFID;
+      	  ncvar->zaxisID = varDefZaxis(vlistID, zaxisType, (int) zsize, zvar, with_bounds, lbounds, ubounds,
+                                       (int)vctsize, vct, pname, plongname, punits, zprec, 1, 0);
 
-      memcpy(destTstep->records, sourceTstep->records, (size_t)nrecs*sizeof(record_t));
+          int zaxisID = ncvar->zaxisID;
 
-      destTstep->recIDs     = (int *) Malloc((size_t)nvrecs * sizeof(int));
+          if ( CDI_cmor_mode && zsize == 1 && zaxisType != ZAXIS_HYBRID ) zaxisDefScalar(zaxisID);
 
-      memcpy(destTstep->recIDs, streamptr->tsteps[1].recIDs, (size_t)nvrecs*sizeof(int));
-    }
-}
+          if ( uuidOfVGrid[0] != 0 )
+            {
+              // printf("uuidOfVGrid: defined\n");
+              zaxisDefUUID(zaxisID, uuidOfVGrid);
+            }
 
+          if ( zaxisType == ZAXIS_HYBRID && psvarid != -1 )
+            cdiZaxisDefKeyStr(zaxisID, CDI_KEY_PSNAME, strlen(ncvars[psvarid].name)+1, ncvars[psvarid].name);
 
-static
-int cdfTimeDimID(int fileID, int ndims, int nvars)
-{
-  for ( int dimid = 0; dimid < ndims; dimid++ )
-    {
-      char dimname[80];
-      cdf_inq_dimname(fileID, dimid, dimname);
-      if ( memcmp(dimname, "time", 4) == 0 )
-        return dimid;
-    }
+          if ( positive > 0 ) zaxisDefPositive(zaxisID, positive);
+          if ( is_scalar ) zaxisDefScalar(zaxisID);
 
+          if ( zdimid != -1 )
+            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);
+          */
+	  Free(zvar);
+	  Free(lbounds);
+	  Free(ubounds);
 
-  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 ( zvarid != CDI_UNDEFID )
             {
-              char sbuf[CDI_MAX_NAME];
-              cdf_inq_attname(fileID, varid, iatt, sbuf);
-              if ( strncmp(sbuf, "units", 5) == 0 )
+              int ncid = ncvars[zvarid].ncid;
+              int nvatts = ncvars[zvarid].natts;
+              for ( int iatt = 0; iatt < nvatts; ++iatt )
                 {
-                  cdfGetAttText(fileID, varid, "units", sizeof(sbuf), sbuf);
-                  strtolower(sbuf);
-
-                  if ( isTimeUnits(sbuf) )
-                    return dimids[0];
+                  int attnum = ncvars[zvarid].atts[iatt];
+                  cdf_set_cdi_attr(ncid, zvarid, attnum, zaxisID, CDI_GLOBAL);
                 }
             }
-        }
-    }
 
-  return UNDEFID;
-}
+          int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
+	  streamptr->zaxisID[zaxisindex] = zdimid;
 
-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;
-    }
-}
+	  if ( CDI_Debug )
+	    Message("zaxisID %d %d %s", zaxisID, ncvarid, ncvar->name);
 
-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;
-    }
-}
+	  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;
 
-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 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];
+		  }
 
-      ncvars[ncvarid].warn = TRUE;
-      isvar = FALSE;
+		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].isvar = isvar;
 }
 
-static
-void cdfSetDim(ncvar_t *ncvars, int ncvarid, int dimid, int dimtype)
+struct varinfo
 {
-  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);
-    }
-
-  ncvars[ncvarid].dimtype[dimid] = dimtype;
-}
+  int      ncvarid;
+  const char *name;
+};
 
 static
-bool isLonAxis(const char *units, const char *stdname)
+int cmpvarname(const void *s1, const void *s2)
 {
-  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;
-    }
-
-  return status;
+  const struct varinfo *x = (const struct varinfo *)s1,
+                       *y = (const struct 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 varinfo *varInfo
+        = (struct varinfo *) Malloc((size_t)nvars * sizeof (struct varinfo));
+
+      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 )
+        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].tsteptype);
 
-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->xdimID[gridindex];
+      int ydimid = streamptr->ydimID[gridindex];
 
-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;
+      int ipow10[4] = {1, 10, 100, 1000};
 
-  return status;
-}
+      if ( ncvars[ncvarid].tsteptype != TSTEP_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;
+      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;
+      int ncvarid = varids[varID];
+      int ncid = ncvars[ncvarid].ncid;
 
-      status = true;
-      ncvar->zaxistype = ZAXIS_HYBRID;
-      int dimid = ncvar->dimids[0];
-      size_t dimlen = ncdims[dimid].len;
+      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);
+        }
 
-      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;
+      if ( ncvars[ncvarid].atts )
+        {
+          Free(ncvars[ncvarid].atts);
+          ncvars[ncvarid].atts = NULL;
+        }
 
-      if ( ncvar->bounds != UNDEFID && ncvars[ncvar->bounds].lformula && ncvars[ncvar->bounds].lformulaterms )
+      if ( ncvars[ncvarid].vct )
         {
-          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].vct);
+          ncvars[ncvarid].vct = 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);
+  /* release mem of not freed attributes */
+  for ( int ncvarid = 0; ncvarid < num_ncvars; ncvarid++ )
+    if ( ncvars[ncvarid].atts ) Free(ncvars[ncvarid].atts);
 
-                  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];
+  if ( varids ) Free(varids);
 
-                  if ( ret == 2 && IS_NOT_EQUAL(px, 1) )
-                    for ( size_t i = 0; i < dimlen+1; ++i ) vct[i] *= px;
+  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 ( str_is_equal(pname, "var") )
+		{
+		  vlistDefVarCode(vlistID, varID, atoi(pname+3));
+                  // vlistDestroyVarName(vlistID, varID);
+		}
+	    }
+	  else if ( len > 4 && isdigit((int) pname[4]) )
+	    {
+	      if ( str_is_equal(pname, "code") )
+		{
+		  vlistDefVarCode(vlistID, varID, atoi(pname+4));
+		  // vlistDestroyVarName(vlistID, varID);
+		}
+	    }
+	  else if ( len > 5 && isdigit((int) pname[5]) )
+	    {
+	      if ( str_is_equal(pname, "param") )
+		{
+		  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);
+		}
+	    }
+	}
+    }
+
+  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 )
+	{
+	  if ( tableInqParNamePtr(cdiDefaultTableID, code) )
+	    {
+	      vlistDestroyVarName(vlistID, varID);
+	      vlistDestroyVarLongname(vlistID, varID);
+	      vlistDestroyVarUnits(vlistID, varID);
+
+	      if ( varTableID != CDI_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;
+		}
+	    }
 
-                  ncvar->vct = vct;
-                  ncvar->vctsize = vctsize;
-                }
-            }
-        }
+	  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);
     }
-
-  return status;
 }
 
-
 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, (int)attlen, attint);
+              int datatype = (xtype == NC_SHORT) ? DATATYPE_INT16 : 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, (int)attlen, attflt);
+          int datatype = (xtype == NC_FLOAT) ? DATATYPE_FLT32 : 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
+      if ( ncvars[ncvarid].stdname[0] && strcmp(ncvars[ncvarid].stdname, "forecast_period") == 0 )
         {
-          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++] = '?';
+          leadtime_id = ncvarid;
+          break;
         }
-
-      axis[ndim++] = 0;
-
-      fprintf(stderr, "%3d %3d  %-6s %s\n", ncvarid, ndim-3, axis, ncvars[ncvarid].name);
     }
+
+  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;
+      char timeunits[CDI_MAX_NAME];
 
-#if  defined  (HAVE_NETCDF4)
-      if ( format == NC_FORMAT_NETCDF4_CLASSIC || format == NC_FORMAT_NETCDF4 )
+      for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
         {
-          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 ( ncvars[ncvarid].ndims == 0 && strcmp(ncvars[ncvarid].name, "time") == 0 )
             {
-              if ( storage_in == NC_CHUNKED )
+              if ( ncvars[ncvarid].units[0] )
                 {
-                  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
+                  strcpy(timeunits, ncvars[ncvarid].units);
+                  str_tolower(timeunits);
 
-      if ( nvdims > 0 )
-        {
-          if ( timedimid == dimidsp[0] )
-            {
-              ncvars[ncvarid].tsteptype = TSTEP_INSTANT;
-              cdfSetDim(ncvars, ncvarid, 0, T_AXIS);
-            }
-          else
-            {
-              for ( ncdimid = 1; ncdimid < nvdims; ncdimid++ )
-                {
-                  if ( timedimid == dimidsp[ncdimid] )
+                  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);
-
-          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) )
-            {
-              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);
-                }
-              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) )
-            {
-              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
-                {
-                  static int warn = TRUE;
-                  if ( warn )
-                    {
-                      warn = FALSE;
-                      Warning("NetCDF attribute level_type='%s' unsupported!", attstring);
-                    }
-                }
-
-              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 )
-                {
-                  ncvars[ncvarid].climatology = TRUE;
-                  ncvars[ncvarid].bounds = ncboundsid;
-                  cdfSetVar(ncvars, ncvars[ncvarid].bounds, FALSE);
-                  cdfSetVar(ncvars, ncvarid, 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 )
-                {
-                  ncvars[ncvarid].bounds = ncboundsid;
-                  cdfSetVar(ncvars, ncvars[ncvarid].bounds, FALSE);
-                  cdfSetVar(ncvars, ncvarid, FALSE);
-                }
-              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 )
-            {
-              ncvars[ncvarid].lformula = TRUE;
-            }
-          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;
-
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              pstring = attstring;
-
-              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;
-
-              cdf_inq_varid(ncid, xvarname, &ncvars[ncvarid].xvarid);
-              cdf_inq_varid(ncid, yvarname, &ncvars[ncvarid].yvarid);
-
-              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;
-
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              char *pstring = attstring;
-
-              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;
-
-                  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 ( k == nchecked_vars )
-                        {
-                          if ( nchecked_vars < max_check_vars ) checked_vars[nchecked_vars++] = strdup(varname);
-                          Warning("%s - %s", nc_strerror(status), varname);
-                        }
-                    }
-
-                  if ( lstop ) break;
-                }
-
-              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;
+          streamptr->basetime.ncvarid = ncdims[timedimid].ncvarid;
+          ltimevar = true;
+        }
 
-              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;
+      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;
 
-                  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);
+            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 ( lstop ) break;
-                }
+      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;
+              }
+        }
 
-              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);
+      /* time varID */
+      ncvarid = streamptr->basetime.ncvarid;
 
-              cdfSetVar(ncvars, ncvarid, TRUE);
-            }
-          else if ( strcmp(attname, "positive") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              strtolower(attstring);
+      if ( ncvarid == CDI_UNDEFID )
+        {
+          Warning("Time variable >%s< not found!", ncdims[timedimid].name);
+        }
+    }
 
-              if    ( memcmp(attstring, "down", 4) == 0 ) ncvars[ncvarid].positive = POSITIVE_DOWN;
-              else if ( memcmp(attstring, "up", 2) == 0 ) ncvars[ncvarid].positive = POSITIVE_UP;
+  /* time varID */
+  ncvarid = streamptr->basetime.ncvarid;
 
-              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 ( 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 )
             {
-              if ( ncvars[ncvarid].lvalidrange == FALSE )
+              int len = (int) ncdims[ncvars[ncvars[ncvarid].bounds].dimids[nbdims-1]].len;
+              if ( len == 2 && timedimid == ncvars[ncvars[ncvarid].bounds].dimids[0] )
                 {
-                  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);
-                    }
+                  *time_has_bounds = true;
+                  streamptr->basetime.ncvarboundsid = ncvars[ncvarid].bounds;
+                  if ( ncvars[ncvarid].climatology ) *time_climatology = true;
                 }
             }
-          else if ( strcmp(attname, "valid_max") == 0 && attlen == 1 )
+        }
+    }
+}
+
+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' )
             {
-              if ( ncvars[ncvarid].lvalidrange == FALSE )
+              if ( ncvars[ncvarid].name[2] == 'a' && ncvars[ncvarid].name[3] == 'i' ) // hyai
                 {
-                  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);
-                    }
+                  vcta_id = ncvarid;
+                  nvcth_id = ncvars[ncvarid].dimids[0];
+                  ncvars[ncvarid].isvar = FALSE;
                 }
-            }
-          else if ( strcmp(attname, "_Unsigned") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              strtolower(attstring);
-
-              if ( memcmp(attstring, "true", 4) == 0 )
+              else if ( ncvars[ncvarid].name[2] == 'b' && ncvars[ncvarid].name[3] == 'i' ) //hybi
                 {
-                  ncvars[ncvarid].lunsigned = TRUE;
-                  /*
-                  ncvars[ncvarid].lvalidrange = TRUE;
-                  ncvars[ncvarid].validrange[0] = 0;
-                  ncvars[ncvarid].validrange[1] = 255;
-                  */
+                  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
                 }
-	      /* cdfSetVar(ncvars, ncvarid, TRUE); */
             }
-          else if ( strcmp(attname, "cdi") == 0 && xtypeIsText(atttype) )
-            {
-	      cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-	      strtolower(attstring);
+	}
+    }
 
-	      if ( memcmp(attstring, "ignore", 6) == 0 )
-		{
-		  ncvars[ncvarid].ignore = TRUE;
-		  cdfSetVar(ncvars, ncvarid, FALSE);
-		}
-            }
-          else if ( strcmp(attname, "axis") == 0 && xtypeIsText(atttype) )
+  /* 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' )
             {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-	      attlen = strlen(attstring);
+              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;
+            }
+        }
+    }
+}
 
-	      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;
-			}
-		    }
+static
+int cdf_check_vars(int nvars, ncvar_t *ncvars, int 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);
 
-		  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].isvar == -1 && ncvars[ncvarid].ndims == 0 )
+	cdf_set_var(ncvars, ncvarid, FALSE);
 
-	      if( ncvars[ncvarid].ensdata == NULL )
-		ncvars[ncvarid].ensdata = (ensinfo_t *) Malloc( sizeof( ensinfo_t ) );
+      //if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims > 1 )
+      if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims >= 1 )
+	cdf_set_var(ncvars, ncvarid, TRUE);
 
-	      cdfGetAttInt(ncid, ncvarid, attname, 1, &temp);
+      if ( ncvars[ncvarid].isvar == -1 )
+	{
+	  ncvars[ncvarid].isvar = 0;
+	  Warning("Variable %s has an unknown type, skipped!", ncvars[ncvarid].name);
+	  continue;
+	}
 
-	      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;
+      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;
+	}
 
-	      cdfSetVar(ncvars, ncvarid, TRUE);
-	    }
-	  else
-	    {
-	      if ( ncvars[ncvarid].natts == 0 )
-		ncvars[ncvarid].atts
-                  = (int *) Malloc((size_t)nvatts * sizeof (int));
+      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;
+	}
 
-	      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) )
-		{
-		  cdfGetAttDouble(ncid, ncvarid, attname, 1, &attrflt);
-		  printf("flt: %s.%s = %g\n", ncvars[ncvarid].name, attname, attrflt);
-		}
-	      else if ( attrtype == NC_CHAR )
-		{
-		  cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-		  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);
-	      */
+      if ( xtypeIsText(ncvars[ncvarid].xtype) )
+	{
+	  ncvars[ncvarid].isvar = 0;
+	  continue;
+	}
+
+      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;
+	}
+
+      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;
 	    }
 	}
     }
 
-  for ( int i = 0; i < max_check_vars; ++i ) if ( checked_vars[i] ) Free(checked_vars[i]);
+  return timedimid;
 }
 
-static
-void setDimType(int nvars, ncvar_t *ncvars, ncdim_t *ncdims)
+
+int cdfInqContents(stream_t *streamptr)
 {
-  int ndims;
-  int ncvarid, ncdimid;
-  int i;
+  int ndims, nvars, ngatts, unlimdimid;
+  int ncvarid;
+  int ncdimid;
+  int timedimid = -1;
+  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 taxisID;
+  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 ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+  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 vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
+
+  if ( CDI_Debug ) Message("streamID = %d, fileID = %d", streamptr->self, fileID);
+
+#if  defined  (HAVE_NETCDF4)
+  nc_inq_format(fileID, &format);
+#endif
+
+  cdf_inq(fileID, &ndims , &nvars, &ngatts, &unlimdimid);
+
+  if ( CDI_Debug )
+    Message("root: ndims %d, nvars %d, ngatts %d", ndims, nvars, ngatts);
+
+  if ( ndims == 0 )
     {
-      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);
-	    }
+      Warning("No dimensions found!");
+      return CDI_EUFSTRUCT;
+    }
 
-	  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");
-	    }
+  /* alloc ncdims */
+  ncdim_t *ncdims = (ncdim_t *) Malloc((size_t)ndims * sizeof (ncdim_t));
+  init_ncdims(ndims, ncdims);
 
-	  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; */
-	    }
+#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 ( lxdim == FALSE && ncvars[ncvarid].xvarid != UNDEFID )
-            {
-              if (  ncvars[ncvars[ncvarid].xvarid].ndims == 0 ) lxdim = TRUE;
-            }
+          if ( CDI_Debug )
+            Message("%s: ndims %d, nvars %d, ngatts %d", name1, gndims, gnvars, gngatts);
 
-          if ( lydim == FALSE && ncvars[ncvarid].yvarid != UNDEFID )
+          if ( gndims == 0 )
             {
-              if (  ncvars[ncvars[ncvarid].yvarid].ndims == 0 ) lydim = TRUE;
             }
+        }
+    }
+#endif
+#endif
 
-          //   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 ( nvars == 0 )
+    {
+      Warning("No arrays found!");
+      return CDI_EUFSTRUCT;
     }
-}
 
-/* 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;
+  /* alloc ncvars */
+  ncvar_t *ncvars = (ncvar_t *) Malloc((size_t)nvars * sizeof (ncvar_t));
+  init_ncvars(nvars, ncvars);
+
+  for ( ncvarid = 0; ncvarid < nvars; ++ncvarid ) ncvars[ncvarid].ncid = fileID;
+
+
+  /* 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 */
+  if ( unlimdimid >= 0 )
+    timedimid = unlimdimid;
+  else
+    timedimid = 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 ( CDI_Debug ) Message("Number of timesteps = %d", ntsteps);
+  if ( CDI_Debug ) Message("Time dimid = %d", streamptr->basetime.ncdimid);
 
+  /* read ncdims */
   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;
-	    }
+      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 ( isHybridSigmaPressureCoordinate(ncid, ncvarid, ncvars, ncdims) ) continue;
+  if ( CDI_Debug ) cdf_print_vars(ncvars, nvars, "cdf_scan_var_attr");
+
+  /* scan attributes of all variables */
+  cdf_scan_var_attr(nvars, ncvars, ncdims, timedimid, modelID, format);
 
-	  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 ( CDI_Debug ) cdf_print_vars(ncvars, nvars, "find coordinate vars");
+
+  /* find coordinate vars */
+  for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
+    {
+      for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+	{
+	  if ( ncvars[ncvarid].ndims == 1 )
 	    {
-	      if ( memcmp(ncvars[ncvarid].longname+1, "ongitude", 8) == 0 )
+	      if ( timedimid != CDI_UNDEFID && timedimid == ncvars[ncvarid].dimids[0] )
 		{
-		  ncvars[ncvarid].islon = TRUE;
-		  cdfSetVar(ncvars, ncvarid, FALSE);
-		  cdfSetDim(ncvars, ncvarid, 0, X_AXIS);
-		  ncdims[ncdimid].dimtype = X_AXIS;
-		  continue;
+		  if ( ncvars[ncvarid].isvar != FALSE ) cdf_set_var(ncvars, ncvarid, TRUE);
 		}
-	      else if ( memcmp(ncvars[ncvarid].longname+1, "atitude", 7) == 0 )
+	      else
 		{
-		  ncvars[ncvarid].islat = TRUE;
-		  cdfSetVar(ncvars, ncvarid, FALSE);
-		  cdfSetDim(ncvars, ncvarid, 0, Y_AXIS);
-		  ncdims[ncdimid].dimtype = Y_AXIS;
-		  continue;
+                  //  if ( ncvars[ncvarid].isvar != TRUE ) cdf_set_var(ncvars, ncvarid, FALSE);
 		}
-	    }
+	      // if ( ncvars[ncvarid].isvar != TRUE ) cdf_set_var(ncvars, ncvarid, FALSE);
 
-	  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 ( 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;
+		  }
 	    }
 	}
     }
-}
 
-/* verify coordinate vars - second scan (all other variables) */
-static
-void verify_coordinate_vars_2(int nvars, ncvar_t *ncvars)
-{
-  int ncvarid;
+  /* find time vars */
+  find_time_vars(nvars, ncvars, ncdims, timedimid, streamptr, &time_has_units, &time_has_bounds, &time_climatology);
 
-  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+  leadtime_id = find_leadtime(nvars, ncvars);
+  if ( leadtime_id != CDI_UNDEFID ) ncvars[leadtime_id].isvar = FALSE;
+
+  /* check ncvars */
+  timedimid = cdf_check_vars(nvars, ncvars, ntsteps, timedimid);
+
+  /* verify coordinate vars - first scan (dimname == varname) */
+  bool lhybrid_cf = false;
+  verify_coordinate_vars_1(fileID, ndims, ncdims, ncvars, timedimid, &lhybrid_cf);
+
+  /* verify coordinate vars - second scan (all other variables) */
+  verify_coordinate_vars_2(nvars, ncvars);
+
+  if ( CDI_Debug ) cdf_print_vars(ncvars, nvars, "verify_coordinate_vars");
+
+  if ( ucla_les ) cdf_set_ucla_dimtype(ndims, ncdims, ncvars);
+
+  /*
+  for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
     {
-      if ( ncvars[ncvarid].isvar == 0 )
+      ncvarid = ncdims[ncdimid].ncvarid;
+      if ( ncvarid != -1 )
 	{
-	  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;
-		}
-            }
+	  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);
 
-	  /* 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 )
+	  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);
+	}
+    }
+  */
+
+  /* Set coordinate varids (att: associate)  */
+  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      ncvar_t *ncvar = &ncvars[ncvarid];
+      if ( ncvar->isvar == TRUE && ncvar->ncoordvars )
+	{
+	  int ndims = ncvar->ncoordvars;
+	  for ( int i = 0; i < ndims; 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];
 	    }
 	}
     }
-}
 
-#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);
+
+  /* read ECHAM VCT if present */
+  size_t vctsize = 0;
+  double *vct = NULL;
+  if ( !lhybrid_cf ) read_vct_echam(fileID, nvars, ncvars, ncdims, &vct, &vctsize);
+
+
+  if ( CDI_Debug ) cdf_print_vars(ncvars, nvars, "cdf_define_all_grids");
+
+  /* define all grids */
+  cdf_define_all_grids(streamptr, vlistID, ncdims, nvars, ncvars, timedimid, uuidOfHGrid, gridfile, number_of_grid_used);
+
+
+  /* define all zaxes */
+  cdf_define_all_zaxes(streamptr, vlistID, ncdims, nvars, ncvars, vctsize, vct, uuidOfVGrid);
+  if ( vct ) Free(vct);
+
+
+  /* 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 = %d", ntsteps);
+  if ( CDI_Debug ) Message("nvars_data = %d", nvars_data);
+
+
+  if ( nvars_data == 0 )
+    {
+      streamptr->ntsteps = 0;
+      return CDI_EUFSTRUCT;
+    }
+
+  if ( ntsteps == 0 && streamptr->basetime.ncdimid == CDI_UNDEFID && streamptr->basetime.ncvarid != CDI_UNDEFID )
+    ntsteps = 1;
 
-  cdf_inq_varnatts(ncfileID, ncvarID, &nvatts);
+  streamptr->ntsteps = (long)ntsteps;
 
-  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);
+  /* define all data variables */
+  cdf_define_all_vars(streamptr, vlistID, instID, modelID, varids, nvars_data, nvars, ncvars);
 
-      //  printf("%s %d\n", attname, (int)attlen);
-    }
 
-}
-#endif
+  cdiCreateTimesteps(streamptr);
 
-static
-void grid_set_chunktype(grid_t *grid, ncvar_t *ncvar)
-{
-  if ( ncvar->chunked )
+  /* 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);
+      if ( ncvars[nctimevarid].longname[0] )
+        ptaxisDefLongname(taxis, ncvars[nctimevarid].longname);
+    }
 
-#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 ( 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);
+      }
 
-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);
-}
+  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;
+	}
+    }
 
-static void cdfLazyGridDelete(grid_t *grid)
-{
-  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
-  void (*baseDestroy)(grid_t *grid) = cdfGrid->baseVtable->destroy;
-  cdfLazyGridDestroy(cdfGrid);
-  baseDestroy(grid);
-}
 
-static void cdfLazyGridDestroyOnce(void)
-{
-  /*
-#ifdef HAVE_MMAP
-  size_t pgSize = cdiGetPageSize(false);
-  munmap(cdfPendingLoad, pgSize);
+  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
-cdfLazyGridDefArea(grid_t *grid, const double *area)
-{
-  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);
-}
+  vlistDefTaxis(vlistID, taxisID);
 
+  streamptr->curTsID = 0;
+  streamptr->rtsteps = 1;
 
-static const double *
-cdfLazyGridInqAreaPtr(grid_t *grid)
-{
-  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
-  lock_lazy_load(lazyGrid);
-  if (grid->area == cdfPendingLoad)
-    {
-      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);
-}
+  (void) cdfInqTimestep(streamptr, 0);
 
-static void
-cdfLazyGridInqArea(grid_t *grid, double *area)
-{
-  grid->vtable->inqAreaPtr(grid);
-  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
-  lazyGrid->baseVtable->inqArea(grid, area);
-}
+  cdfCreateRecords(streamptr, 0);
 
+  /* free ncdims */
+  Free(ncdims);
 
-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);
-  scale_add(valsGet->size, grid_vals, valsGet->addoffset, valsGet->scalefactor);
-}
+  /* free ncvars */
+  Free(ncvars);
 
-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 0;
 }
 
-static const double *
-cdfLazyGridInqYValsPtr(grid_t *grid)
+static
+void wrf_read_timestep(int fileID, int nctimevarid, int tsID, taxis_t *taxis)
 {
-  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);
+  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 double
-cdfLazyGridInqXYVal(grid_t *grid, size_t index,
-                    const struct xyValGet *valsGet, double *vals,
-                    const double *(*inqValsPtr)(grid_t *gridptr))
+static
+double get_timevalue(int fileID, int nctimevarid, int tsID, timecache_t *tcache)
 {
-  size_t size = valsGet->size;
-  double v;
-  if ( vals == cdfPendingLoad )
+  double timevalue = 0;
+
+  if ( tcache )
     {
-      /* prevent full load if only first/last values get inspected */
-      if ( index == 0 || index == size - 1 )
+      if ( tcache->size == 0 || (tsID < tcache->startid || tsID > (tcache->startid+tcache->size-1)) )
         {
-          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)
+          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 )
             {
-              indexND[0] = index / (size_t)grid->xsize;
-              indexND[1] = index % (size_t)grid->xsize;
+              cdf_get_var1_double(fileID, nctimevarid, &index, &timevalue);
+              if ( timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE ) timevalue = 0;
+              tcache->cache[ival] = timevalue;
+              index++;
             }
-          else
-            indexND[0] = index;
-          cdf_get_var1_double(valsGet->datasetNCId, valsGet->varNCId,
-                              indexND, &v);
-        }
-      else
-        {
-          const double *grid_vals = inqValsPtr(grid);
-          v = grid_vals[index];
         }
+
+      timevalue = tcache->cache[tsID%MAX_TIMECACHE_SIZE];
     }
-  else if ( vals )
-    v = vals[index];
   else
-    v = 0.0;
-  return v;
-}
+    {
+      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;
+    }
 
-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);
+  return timevalue;
 }
 
-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);
-}
 
-static double
-cdfLazyGridInqXVal(grid_t *grid, int index)
+int cdfInqTimestep(stream_t * streamptr, int tsID)
 {
-  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;
-}
+  if ( CDI_Debug ) Message("streamID = %d  tsID = %d", streamptr->self, tsID);
 
-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;
-}
+  if ( tsID < 0 ) Error("unexpected tsID = %d", tsID);
 
-static int
-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;
-}
+  if ( tsID < streamptr->ntsteps && streamptr->ntsteps > 0 )
+    {
+      cdfCreateRecords(streamptr, tsID);
 
-static int
-cdfLazyCompareXYFull(grid_t *gridRef, grid_t *gridTest)
-{
-  int 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;
-}
+      taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
+      if ( tsID > 0 )
+	ptaxisCopy(taxis, &streamptr->tsteps[0].taxis);
 
-static int
-cdfLazyCompareXYAO(grid_t *gridRef, grid_t *gridTest)
-{
-  int 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;
-}
+      double timevalue = tsID;
 
+      int nctimevarid = streamptr->basetime.ncvarid;
+      if ( nctimevarid != CDI_UNDEFID )
+	{
+	  int fileID = streamptr->fileID;
+	  size_t index  = (size_t)tsID;
 
-static const double *
-cdfLazyGridInqXBoundsPtr(grid_t *grid)
-{
-  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
-  lock_lazy_load(lazyGrid);
-  if (grid->xbounds == cdfPendingLoad)
-    {
-      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);
-    }
-  unlock_lazy_load(lazyGrid);
-  return lazyGrid->baseVtable->inqXBoundsPtr(grid);
-}
+	  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);
+	    }
 
-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);
-}
+	  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;
 
-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);
-}
+	      cdiDecodeTimeval(timevalue, taxis, &taxis->vdate_lb, &taxis->vtime_lb);
 
-static const double *
-cdfLazyGridInqYBoundsPtr(grid_t *grid)
-{
-  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
-  lock_lazy_load(lazyGrid);
-  if (grid->ybounds == cdfPendingLoad)
-    {
-      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);
+              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->inqYBoundsPtr(grid);
-}
 
-static void
-cdfLazyGridCopyScalarFields(grid_t *gridptrOrig, grid_t *gridptrDup)
-{
-  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);
+  streamptr->curTsID = tsID;
+  long nrecs = streamptr->tsteps[tsID].nrecs;
+
+  return (int) nrecs;
 }
 
-static void
-cdfLazyGridCopyArrayFields(grid_t *gridptrOrig, grid_t *gridptrDup)
+
+int cdfInqHistorySize(stream_t *streamptr)
 {
-  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));
-    }
+  size_t size = 0;
+  int ncid = streamptr->fileID;
+  if ( streamptr->historyID != CDI_UNDEFID )
+    cdf_inq_attlen(ncid, NC_GLOBAL, "history", &size);
 
-  if ( gridptrOrig->xvals != NULL && gridptrOrig->xvals != cdfPendingLoad )
-    {
-      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->xsize;
+  return (int) size;
+}
 
-      gridptrDup->xvals = (double *)Malloc(size * sizeof (double));
-      memcpy(gridptrDup->xvals, gridptrOrig->xvals, size * sizeof (double));
-    }
 
-  if ( gridptrOrig->yvals != NULL && gridptrOrig->yvals != cdfPendingLoad )
+void cdfInqHistoryString(stream_t *streamptr, char *history)
+{
+  int ncid = streamptr->fileID;
+  if ( streamptr->historyID != CDI_UNDEFID )
     {
-      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->ysize;
+      nc_type atttype;
+      cdf_inq_atttype(ncid, NC_GLOBAL, "history", &atttype);
 
-      gridptrDup->yvals = (double *)Malloc(size * sizeof (double));
-      memcpy(gridptrDup->yvals, gridptrOrig->yvals, size * sizeof (double));
+      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
     }
+}
 
-  if ( gridptrOrig->xbounds != NULL && gridptrOrig->xbounds != cdfPendingLoad )
-    {
-      size_t size  = (irregular ? gridsize : (size_t)gridptrOrig->xsize)
-        * (size_t)gridptrOrig->nvertex;
-
-      gridptrDup->xbounds = (double *)Malloc(size * sizeof (double));
-      memcpy(gridptrDup->xbounds, gridptrOrig->xbounds, size * sizeof (double));
-    }
+#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
 
-  if ( gridptrOrig->ybounds != NULL && gridptrOrig->ybounds != cdfPendingLoad )
-    {
-      size_t size = (irregular ? gridsize : (size_t)gridptrOrig->ysize)
-        * (size_t)gridptrOrig->nvertex;
+#ifdef HAVE_LIBNETCDF
 
-      gridptrDup->ybounds = (double *)Malloc(size * sizeof (double));
-      memcpy(gridptrDup->ybounds, gridptrOrig->ybounds, size * sizeof (double));
-    }
 
-  {
-    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));
-      }
-  }
+#undef  CDI_UNDEFID
+#define CDI_UNDEFID  CDI_UNDEFID
 
-  if ( gridptrOrig->mask != NULL )
-    {
-      size_t size = gridsize;
+#define  POSITIVE_UP    1
+#define  POSITIVE_DOWN  2
 
-      gridptrDup->mask = (mask_t *)Malloc(size * sizeof(mask_t));
-      memcpy(gridptrDup->mask, gridptrOrig->mask, size * sizeof (mask_t));
-    }
 
-  if ( gridptrOrig->mask_gme != NULL )
-    {
-      size_t size = gridsize;
+static const char bndsName[] = "bnds";
 
-      gridptrDup->mask_gme = (mask_t *)Malloc(size * sizeof (mask_t));
-      memcpy(gridptrDup->mask_gme, gridptrOrig->mask_gme, size * sizeof(mask_t));
-    }
-}
 
-static grid_t *
-cdfLazyGridCopy(grid_t *gridptrOrig)
+void cdfCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
 {
-  struct cdfLazyGrid *lazyGridDup
-    = (struct cdfLazyGrid *)Malloc(sizeof (*lazyGridDup));
-  gridptrOrig->vtable->copyScalarFields(gridptrOrig, &lazyGridDup->base);
-  gridptrOrig->vtable->copyArrayFields(gridptrOrig, &lazyGridDup->base);
-  return &lazyGridDup->base;
-}
+  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;
 
-static void
-cdfLazyGridInitOnce(void)
-{
-  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
-}
+  void *data = Malloc((size_t)datasize
+             * (memtype == MEMTYPE_DOUBLE ? sizeof(double) : sizeof(float)));
 
-static void
-cdfBaseGridInit(grid_t *grid, int gridtype)
-{
-  grid_init(grid);
-  cdiGridTypeInit(grid, gridtype, 0);
-}
+  int nmiss;
+  cdf_read_record(streamptr1, memtype, data, &nmiss);
+  cdf_write_record(streamptr2, memtype, data, nmiss);
 
-static void
-cdfLazyGridInit(struct cdfLazyGrid *grid, int gridtype)
-{
-#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);
+  Free(data);
 }
 
-static void
-cdfLazyGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype)
-{
-  struct cdfLazyGrid *restrict grid = *gridpptr;
-  if (!grid)
-    *gridpptr = grid = (struct cdfLazyGrid *)Malloc(sizeof (*grid));
-  cdfLazyGridInit(grid, gridtype);
-}
 
-static void
-cdfBaseGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype)
+void cdfDefRecord(stream_t *streamptr)
 {
-  struct cdfLazyGrid *restrict grid = *gridpptr;
-  if (!grid)
-    *gridpptr = grid = (struct cdfLazyGrid *)Malloc(sizeof (grid_t));
-  cdfBaseGridInit((grid_t*)grid, gridtype);
+  (void)streamptr;
 }
 
-
-/* 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 cdfDefTimeValue(stream_t *streamptr, int tsID)
 {
-  int ltwarn = TRUE;
-  struct cdfLazyGrid *restrict lazyGrid = NULL, *restrict lazyProj = NULL;
-#define grid (&lazyGrid->base)
-#define proj (&lazyProj->base)
+  int fileID = streamptr->fileID;
 
-  for ( int ncvarid = 0; ncvarid < nvars; ++ncvarid )
+  if ( CDI_Debug )
+    Message("streamID = %d, fileID = %d", streamptr->self, fileID);
+
+  taxis_t *taxis = &streamptr->tsteps[tsID].taxis;
+
+  if ( streamptr->ncmode == 1 )
     {
-      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 };
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
+    }
 
-	  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++;
-		}
-	    }
+  size_t index = (size_t)tsID;
 
-	  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];
-	    }
+  double timevalue = cdiEncodeTimeval(taxis->vdate, taxis->vtime, &streamptr->tsteps[0].taxis);
+  if ( CDI_Debug ) Message("tsID = %d  timevalue = %f", tsID, timevalue);
 
-	  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);
+  int ncvarid = streamptr->basetime.ncvarid;
+  cdf_put_var1_double(fileID, ncvarid, &index, &timevalue);
 
-	  /*
-	  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;
-	  */
+  if ( taxis->has_bounds )
+    {
+      size_t start[2], count[2];
 
-	  if ( xdimid != UNDEFID ) xsize = ncdims[xdimid].len;
-	  if ( ydimid != UNDEFID ) ysize = ncdims[ydimid].len;
+      ncvarid = streamptr->basetime.ncvarboundsid;
 
-	  if ( ydimid == UNDEFID && yvarid != UNDEFID )
-	    {
-	      if ( ncvars[yvarid].ndims == 1 )
-		{
-		  ydimid = ncvars[yvarid].dimids[0];
-		  ysize  = ncdims[ydimid].len;
-		}
-	    }
+      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);
 
-	  if ( ncvars[ncvarid].gridtype == UNDEFID || ncvars[ncvarid].gridtype == GRID_GENERIC )
-	    if ( xdimid != UNDEFID && xdimid == ydimid && nydims == 0 ) ncvars[ncvarid].gridtype = GRID_UNSTRUCTURED;
+      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);
+    }
 
-          if (CDI_netcdf_lazy_grid_load)
-            {
-              cdfLazyGridRenew(&lazyGrid, ncvars[ncvarid].gridtype);
-              cdfLazyGridRenew(&lazyProj, GRID_PROJECTION);
-            }
-          else
-            {
-              cdfBaseGridRenew(&lazyGrid, ncvars[ncvarid].gridtype);
-              cdfBaseGridRenew(&lazyProj, GRID_PROJECTION);
-            }
+  ncvarid = streamptr->basetime.leadtimeid;
+  if ( taxis->type == TAXIS_FORECAST && ncvarid != CDI_UNDEFID )
+    {
+      timevalue = taxis->fc_period;
+      cdf_put_var1_double(fileID, ncvarid, &index, &timevalue);
+    }
 
-	  grid->prec  = DATATYPE_FLT64;
-	  grid->trunc = ncvars[ncvarid].truncation;
+  /*
+printf("fileID = %d %d %d %f\n", fileID, time_varid, index, timevalue);
+  */
+}
 
-	  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;
+static
+int cdfDefTimeBounds(int fileID, int nctimevarid, int nctimedimid, const char *taxis_name, taxis_t* taxis)
+{
+  int time_bndsid = -1;
+  int dims[2];
 
-	      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;
-		    }
+  dims[0] = nctimedimid;
 
-		  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;
-			}
-		    }
-		}
+  /* fprintf(stderr, "time has bounds\n"); */
 
-              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;
-                    }
-                }
+  if ( nc_inq_dimid(fileID, bndsName, &dims[1]) != NC_NOERR )
+    cdf_def_dim(fileID, bndsName, 2, &dims[1]);
 
-              if ( yvarid != UNDEFID )
-                {
-                  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;
-                    }
-                }
+  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
+    {
+      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);
 
-              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;
-		    }
+  return time_bndsid;
+}
 
-                  if ( skipvar )
-                    {
-                      Warning("Unsupported array structure, skipped variable %s!", ncvars[ncvarid].name);
-                      ncvars[ncvarid].isvar = -1;
-                      continue;
-                    }
+static
+void cdfDefTimeUnits(char *unitstr, taxis_t* taxis0, taxis_t* taxis)
+{
+  unitstr[0] = 0;
 
-		  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 ( taxis0->type == TAXIS_ABSOLUTE )
+    {
+      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");
+    }
+  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;
+        }
 
-	      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;
-		    }
+      int year, month, day, hour, minute, second;
+      cdiDecodeDate(rdate, &year, &month, &day);
+      cdiDecodeTime(rtime, &hour, &minute, &second);
 
-                  if ( skipvar )
-                    {
-                      Warning("Unsupported array structure, skipped variable %s!", ncvars[ncvarid].name);
-                      ncvars[ncvarid].isvar = -1;
-                      continue;
-                    }
+      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;
 
-		  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);
-		}
+      sprintf(unitstr, "%s since %d-%d-%d %02d:%02d:%02d",
+              tunitNamePtr(timeunit), year, month, day, hour, minute, second);
+    }
+}
 
-	      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;
-	    }
+static
+void cdfDefForecastTimeUnits(char *unitstr, int timeunit)
+{
+  unitstr[0] = 0;
 
-	  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;
-	    }
+  if ( timeunit == -1 ) timeunit = TUNIT_HOUR;
 
-	  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 ( 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;
 
-		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);
-                      }
-                  }
+  strcpy(unitstr, tunitNamePtr(timeunit));
+}
 
-		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;
-	      }
-	    }
+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] };
 
-          if ( grid->type != ncvars[ncvarid].gridtype )
-            {
-              int gridtype = ncvars[ncvarid].gridtype;
-              grid->type = gridtype;
-              cdiGridTypeInit(grid, gridtype, grid->size);
-            }
+  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 ( 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;
-		}
-	    }
 
-	  if ( number_of_grid_used != UNDEFID && (grid->type == UNDEFID || grid->type == GRID_GENERIC) )
-            grid->type   = GRID_UNSTRUCTURED;
+void cdfDefTime(stream_t* streamptr)
+{
+  int time_varid;
+  int time_dimid;
+  int time_bndsid = -1;
+  static const char default_name[] = "time";
 
-	  if ( number_of_grid_used != UNDEFID && grid->type == GRID_UNSTRUCTURED )
-            grid->number = number_of_grid_used;
+  if ( streamptr->basetime.ncvarid != CDI_UNDEFID ) return;
 
-	  if ( ncvars[ncvarid].gmapid >= 0 && ncvars[ncvarid].gridtype != GRID_CURVILINEAR )
-	    {
-              int nvatts;
-	      cdf_inq_varnatts(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, &nvatts);
+  int fileID = streamptr->fileID;
 
-	      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);
+  if ( streamptr->ncmode == 0 ) streamptr->ncmode = 1;
+  if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-		  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);
-		    }
-		}
-	    }
+  taxis_t *taxis = &streamptr->tsteps[0].taxis;
 
-          if ( grid->type == GRID_UNSTRUCTURED )
-            {
-              int zdimid = UNDEFID;
-              int xdimidx = -1, ydimidx = -1;
+  const char *taxis_name = (taxis->name && taxis->name[0]) ? taxis->name : default_name ;
 
-              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];
-                }
+  cdf_def_dim(fileID, taxis_name, NC_UNLIMITED, &time_dimid);
+  streamptr->basetime.ncdimid = time_dimid;
 
-              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;
-                    }
-                }
+  cdf_def_var(fileID, taxis_name, NC_DOUBLE, 1, &time_dimid, &time_varid);
 
-              if ( grid->size != grid->xsize )
-                {
-                  Warning("Unsupported array structure, skipped variable %s!", ncvars[ncvarid].name);
-                  ncvars[ncvarid].isvar = -1;
-                  continue;
-                }
+  streamptr->basetime.ncvarid = time_varid;
 
-              if ( ncvars[ncvarid].position > 0 ) grid->position = ncvars[ncvarid].position;
-              if ( uuidOfHGrid[0] != 0 ) memcpy(grid->uuid, uuidOfHGrid, 16);
-            }
+  {
+    static const char timeStr[] = "time";
+    cdf_put_att_text(fileID, time_varid, "standard_name", sizeof(timeStr) - 1, timeStr);
+  }
 
-#if defined (PROJECTION_TEST)
-	  if ( proj->type == GRID_PROJECTION )
-	    {
-	      if ( grid->type == GRID_GENERIC )
-		{
-		  grid->type = GRID_CURVILINEAR;
-		}
+  if ( taxis->longname && taxis->longname[0] )
+    cdf_put_att_text(fileID, time_varid, "long_name", strlen(taxis->longname), taxis->longname);
 
-	      if ( grid->type == GRID_CURVILINEAR )
-		{
-                  proj->size  = grid->size;
-                  proj->xsize = grid->xsize;
-                  proj->ysize = grid->ysize;
-		}
+  if ( taxis->has_bounds )
+    {
+      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);
+        */
+      }
+  }
+
+  if ( taxis->calendar != -1 )
+    {
+      cdfDefCalendar(fileID, time_varid, taxis->calendar);
+      /*
+      if ( taxis->has_bounds )
+        cdfDefCalendar(fileID, time_bndsid, taxis->calendar);
+      */
+    }
 
-	      //  grid->proj = gridGenerate(proj);
-	    }
-#endif
+  if ( taxis->type == TAXIS_FORECAST )
+    {
+      int leadtimeid;
 
-	  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);
-	    }
+      cdf_def_var(fileID, "leadtime", NC_DOUBLE, 1, &time_dimid, &leadtimeid);
 
-#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;
-            }
+      streamptr->basetime.leadtimeid = leadtimeid;
 
-          if ( grid->type == GRID_UNSTRUCTURED )
-            {
-              if ( gridfile[0] != 0 ) gridDefReference(ncvars[ncvarid].gridID, gridfile);
-            }
+      {
+        static const char stdname[] = "forecast_period";
+        cdf_put_att_text(fileID, leadtimeid, "standard_name", sizeof(stdname) - 1, stdname);
+      }
 
-          if ( ncvars[ncvarid].chunked ) grid_set_chunktype(grid, &ncvars[ncvarid]);
+      {
+        static const char lname[] = "Time elapsed since the start of the forecast";
+        cdf_put_att_text(fileID, leadtimeid, "long_name", sizeof(lname) - 1, lname);
+      }
 
-	  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);
+      {
+          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);
+      }
+    }
 
-          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);
+  cdf_put_att_text(fileID, time_varid, "axis", 1, "T");
 
-	  if ( CDI_Debug )
-	    Message("gridID %d %d %s", ncvars[ncvarid].gridID, ncvarid, ncvars[ncvarid].name);
+  if ( streamptr->ncmode == 2 ) cdf_enddef(fileID);
+}
 
-	  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;
 
-		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]; }
-		  }
+void cdfDefTimestep(stream_t *streamptr, int tsID)
+{
+  int vlistID = streamptr->vlistID;
 
-                if ( ncvars[ncvarid2].gridtype == UNDEFID && grid->type == GRID_UNSTRUCTURED )
-                  {
-                    if ( xdimid == xdimid2 && ydimid2 != UNDEFID && zdimid2 == UNDEFID )
-                      {
-                        ncvars[ncvarid2].dimtype[ydimidx] = Z_AXIS;
-                        ydimid2 = UNDEFID;
-                      }
+  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
 
-                    if ( xdimid == ydimid2 && xdimid2 != UNDEFID && zdimid2 == UNDEFID )
-                      {
-                        ncvars[ncvarid2].dimtype[xdimidx] = Z_AXIS;
-                        xdimid2 = ydimid2;
-                        ydimid2 = UNDEFID;
-                      }
-                  }
+  cdfDefTimeValue(streamptr, tsID);
+}
 
-                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;
-		      }
-		  }
-	      }
+static
+void cdfDefComplex(stream_t *streamptr, int gridID, int gridindex)
+{
+  int dimID = CDI_UNDEFID;
+  int fileID  = streamptr->fileID;
+  ncgrid_t *ncgrid = streamptr->ncgrid;
 
-          if (gridAdded.isNew)
-            lazyGrid = NULL;
-          if (projAdded.isNew)
-            lazyProj = NULL;
-	}
-    }
-  if (lazyGrid)
+  for ( int index = 0; index < gridindex; ++index )
     {
-      if (CDI_netcdf_lazy_grid_load) cdfLazyGridDestroy(lazyGrid);
-      grid_free(grid);
-      Free(grid);
+      if ( ncgrid[index].xdimID != CDI_UNDEFID )
+        {
+          int gridID0 = ncgrid[index].gridID;
+          int gridtype0 = gridInqType(gridID0);
+          if ( gridtype0 == GRID_SPECTRAL || gridtype0 == GRID_FOURIER )
+            {
+              dimID = ncgrid[index].xdimID;
+              break;
+            }
+        }
     }
-  if (lazyProj)
+
+  if ( dimID == CDI_UNDEFID )
     {
-      if (CDI_netcdf_lazy_grid_load) cdfLazyGridDestroy(lazyProj);
-      grid_free(proj);
-      Free(proj);
+      static const char axisname[] = "nc2";
+      size_t dimlen = 2;
+
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+      cdf_def_dim(fileID, axisname, dimlen, &dimID);
+      cdf_enddef(fileID);
+
+      streamptr->ncmode = 2;
     }
-#undef proj
-#undef grid
-}
 
-/* 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;
+  ncgrid[gridindex].gridID = gridID;
+  ncgrid[gridindex].xdimID = dimID;
+}
 
-  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;
+static void
+cdfDefSPorFC(stream_t *streamptr, int gridID, int gridindex,
+             char *restrict axisname, int gridRefType)
+{
+  int iz = 0;
+  int dimID = CDI_UNDEFID;
+  ncgrid_t *ncgrid = streamptr->ncgrid;
 
-          int positive = 0;
-	  int ndims = ncvars[ncvarid].ndims;
+  size_t dimlen = (size_t)gridInqSize(gridID)/2;
 
-          if ( ncvars[ncvarid].zvarid != -1 && ncvars[ncvars[ncvarid].zvarid].ndims == 0 )
-            {
-              zvarid = ncvars[ncvarid].zvarid;
-              is_scalar = TRUE;
-            }
-          else
+  for ( int index = 0; index < gridindex; index++ )
+    {
+      if ( ncgrid[index].ydimID != CDI_UNDEFID )
+        {
+          int gridID0 = ncgrid[index].gridID;
+          int gridtype0 = gridInqType(gridID0);
+          if ( gridtype0 == gridRefType )
             {
-              for ( i = 0; i < ndims; i++ )
-                {
-                  if ( ncvars[ncvarid].dimtype[i] == Z_AXIS )
-                    zdimid = ncvars[ncvarid].dimids[i];
-                }
-
-              if ( zdimid != UNDEFID )
+              size_t dimlen0 = (size_t)gridInqSize(gridID0)/2;
+              if ( dimlen == dimlen0 )
                 {
-                  zvarid = ncdims[zdimid].ncvarid;
-                  zsize  = (int)ncdims[zdimid].len;
+                  dimID = ncgrid[index].ydimID;
+                  break;
                 }
+              else
+                iz++;
             }
+        }
+    }
 
-	  if ( CDI_Debug ) Message("nlevs = %d", zsize);
-
-	  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;
+  if ( dimID == CDI_UNDEFID )
+    {
+      int fileID  = streamptr->fileID;
+      if ( iz == 0 ) axisname[3] = '\0';
+      else           sprintf(&axisname[3], "%1d", iz+1);
 
-	  int zprec = DATATYPE_FLT64;
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-	  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;
+      cdf_def_dim(fileID, axisname, dimlen, &dimID);
 
-                  if ( ncvars[zvarid].psvarid != -1 ) psvarid = ncvars[zvarid].psvarid;
-                }
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
+    }
 
-	      cdf_get_var_double(ncvars[zvarid].ncid, zvarid, zvar);
+  ncgrid[gridindex].gridID = gridID;
+  ncgrid[gridindex].ydimID = dimID;
+}
 
-	      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;
+static
+void cdfDefSP(stream_t *streamptr, int gridID, int gridindex)
+{
+  /*
+  char longname[] = "Spherical harmonic coefficient";
+  */
+  char axisname[5] = "nspX";
+  cdfDefSPorFC(streamptr, gridID, gridindex, axisname, GRID_SPECTRAL);
+}
 
-	      if ( zsize == 1 )
-		{
-                  if ( ncvars[ncvarid].zaxistype != UNDEFID )
-                    zaxisType = ncvars[ncvarid].zaxistype;
-                  else
-                    zaxisType = ZAXIS_SURFACE;
 
-		  zvar[0] = 0;
-		  /*
-		  if ( zdimid == UNDEFID )
-		    zvar[0] = 9999;
-		  else
-		    zvar[0] = 0;
-		  */
-		}
-	      else
-		{
-		  for ( ilev = 0; ilev < zsize; ilev++ ) zvar[ilev] = ilev + 1;
-		}
-	    }
+static
+void cdfDefFC(stream_t *streamptr, int gridID, int gridindex)
+{
+  char axisname[5] = "nfcX";
+  cdfDefSPorFC(streamptr, gridID, gridindex, axisname, GRID_FOURIER);
+}
 
-      	  ncvars[ncvarid].zaxisID = varDefZaxis(vlistID, zaxisType, (int) zsize, zvar, with_bounds, lbounds, ubounds,
-						(int)vctsize, vct, pname, plongname, punits, zprec, 1, 0);
+static const struct cdfDefGridAxisInqs {
+  int (*axisSize)(int gridID);
+  int (*axisName)(int cdiID, int key, int size, char *mesg);
+  void (*axisStdname)(int cdiID, char *dimstdname);
+  int (*axisLongname)(int cdiID, int key, int size, char *mesg);
+  void (*axisUnits)(int cdiID, char *dimunits);
+  double (*axisVal)(int gridID, int index);
+  const double *(*axisValsPtr)(int gridID);
+  const double *(*axisBoundsPtr)(int gridID);
+} gridInqsX = {
+  .axisSize = gridInqXsize,
+  .axisName = cdiGridInqKeyStr,
+  .axisStdname = gridInqXstdname,
+  .axisLongname = cdiGridInqKeyStr,
+  .axisUnits = gridInqXunits,
+  .axisVal = gridInqXval,
+  .axisValsPtr = gridInqXvalsPtr,
+  .axisBoundsPtr = gridInqXboundsPtr,
+}, gridInqsY = {
+  .axisSize = gridInqYsize,
+  .axisName = cdiGridInqKeyStr,
+  .axisStdname = gridInqYstdname,
+  .axisLongname = cdiGridInqKeyStr,
+  .axisUnits = gridInqYunits,
+  .axisVal = gridInqYval,
+  .axisValsPtr = gridInqYvalsPtr,
+  .axisBoundsPtr = gridInqYboundsPtr,
+}, gridInqsZ = {
+  .axisStdname = zaxisInqStdname,
+  .axisLongname = cdiZaxisInqKeyStr,
+  .axisUnits = zaxisInqUnits,
+};
 
-	  if ( uuidOfVGrid[0] != 0 )
-            {
-              // printf("uuidOfVGrid: defined\n");
-              zaxisDefUUID(ncvars[ncvarid].zaxisID, uuidOfVGrid);
-            }
+static
+void cdfPutGridStdAtts(int fileID, int ncvarid, int gridID, int dimtype, const struct cdfDefGridAxisInqs *inqs)
+{
+  size_t len;
 
-          if ( zaxisType == ZAXIS_HYBRID && psvarid != -1 ) zaxisDefPsName(ncvars[ncvarid].zaxisID, ncvars[psvarid].name);
+  char stdname[CDI_MAX_NAME];
+  inqs->axisStdname(gridID, stdname);
+  if ( (len = strlen(stdname)) )
+    cdf_put_att_text(fileID, ncvarid, "standard_name", len, stdname);
 
-          if ( positive > 0 ) zaxisDefPositive(ncvars[ncvarid].zaxisID, positive);
-          if ( is_scalar ) zaxisDefScalar(ncvars[ncvarid].zaxisID);
+  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 ( (len = strlen(longname)) )
+    cdf_put_att_text(fileID, ncvarid, "long_name", len, longname);
 
-          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);
+  char units[CDI_MAX_NAME];
+  inqs->axisUnits(gridID, units);
+  if ( (len = strlen(units)) )
+    cdf_put_att_text(fileID, ncvarid, "units", len, units);
+}
 
-	  zaxisindex = vlistZaxisIndex(vlistID, ncvars[ncvarid].zaxisID);
-	  streamptr->zaxisID[zaxisindex]  = zdimid;
+static void
+cdfDefTrajLatLon(stream_t *streamptr, int gridID, int gridindex,
+                 const struct cdfDefGridAxisInqs *inqs, int dimtype)
+{
+  nc_type xtype = (gridInqPrec(gridID) == DATATYPE_FLT32) ? NC_FLOAT : NC_DOUBLE;
+  ncgrid_t *ncgrid = streamptr->ncgrid;
 
-	  if ( CDI_Debug )
-	    Message("zaxisID %d %d %s", ncvars[ncvarid].zaxisID, ncvarid, ncvars[ncvarid].name);
+  int dimlen = inqs->axisSize(gridID);
+  if ( dimlen != 1 )
+    Error("%c size isn't 1 for %s grid!", dimtype, gridNamePtr(gridInqType(gridID)));
 
-	  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;
+  int ncvarid = CDI_UNDEFID;
+  if ( dimtype == 'X' )
+    ncvarid = ncgrid[gridindex].xdimID;
+  else
+    ncvarid = ncgrid[gridindex].ydimID;
 
-		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];
-		  }
+  if ( ncvarid == CDI_UNDEFID )
+    {
+      int dimNcID = streamptr->basetime.ncvarid;
+      int fileID  = streamptr->fileID;
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-		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;
-                      }
-                  }
-	      }
-	}
+      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;
+  if ( dimtype == 'X' )
+    ncgrid[gridindex].xdimID = ncvarid; /* var ID for trajectory !!! */
+  else
+    ncgrid[gridindex].ydimID = ncvarid; /* var ID for trajectory !!! */
 }
 
-struct varinfo
+static
+void cdfDefTrajLon(stream_t *streamptr, int gridID, int gridindex)
 {
-  int      ncvarid;
-  const char *name;
-};
+  cdfDefTrajLatLon(streamptr, gridID, gridindex, &gridInqsX, 'X');
+}
+
 
 static
-int cmpvarname(const void *s1, const void *s2)
+void cdfDefTrajLat(stream_t *streamptr, int gridID, int gridindex)
 {
-  const struct varinfo *x = (const struct varinfo *)s1,
-    *y = (const struct varinfo *)s2;
-  return (strcmp(x->name, y->name));
+  cdfDefTrajLatLon(streamptr, gridID, gridindex, &gridInqsY, 'Y');
 }
 
-/* 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)
+int checkDimName(int fileID, size_t dimlen, char *dimname)
 {
-  if ( CDI_Debug )
-    {
-      for(int i = 0; i < nvars; i++) Message("varids[%d] = %d", i, varids[i]);
-    }
-  if ( streamptr->sortname )
+  /* 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
     {
-      struct varinfo *varInfo
-        = (struct varinfo *) Malloc((size_t)nvars * sizeof (struct varinfo));
+      if ( iz ) sprintf(name + len, "_%u", iz+1);
 
-      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 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 )
         {
-          for(int i = 0; i < nvars; i++) Message("sorted varids[%d] = %d", i, varids[i]);
+          dimid = dimid0;
+          break;
         }
+      iz++;
     }
+  while ( iz <= 99 );
 
-  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;
 
-      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 ( iz ) sprintf(dimname + len, "_%u", iz+1);
 
-      if ( ncvars[ncvarid].lvalidrange )
-        vlistDefVarValidrange(vlistID, varID, ncvars[ncvarid].validrange);
+  return dimid;
+}
 
-      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
+void checkGridName(char *axisname, int fileID)
+{
+  int ncdimid;
+  char axisname2[CDI_MAX_NAME];
 
-      vlistDefVarDatatype(vlistID, varID, cdfInqDatatype(ncvars[ncvarid].xtype, ncvars[ncvarid].lunsigned));
+  /* check that the name is not already defined */
+  unsigned iz = 0;
 
-      vlistDefVarInstitut(vlistID, varID, instID);
-      vlistDefVarModel(vlistID, varID, modelID);
-      if ( ncvars[ncvarid].tableID != UNDEFID )
-	vlistDefVarTable(vlistID, varID, ncvars[ncvarid].tableID);
+  size_t axisnameLen = strlen(axisname);
+  memcpy(axisname2, axisname, axisnameLen + 1);
+  do
+    {
+      if ( iz ) sprintf(axisname2 + axisnameLen, "_%u", iz+1);
 
-      if ( ncvars[ncvarid].deffillval == FALSE && ncvars[ncvarid].defmissval == TRUE )
-        {
-          ncvars[ncvarid].deffillval = TRUE;
-          ncvars[ncvarid].fillval    = ncvars[ncvarid].missval;
-        }
+      int status = nc_inq_varid(fileID, axisname2, &ncdimid);
+      if ( status != NC_NOERR ) break;
 
-      if ( ncvars[ncvarid].deffillval == TRUE )
-        vlistDefVarMissval(vlistID, varID, ncvars[ncvarid].fillval);
+      ++iz;
+    }
+  while ( iz <= 99 );
 
-      if ( CDI_Debug )
-	Message("varID = %d  gridID = %d  zaxisID = %d", varID,
-		vlistInqVarGrid(vlistID, varID), vlistInqVarZaxis(vlistID, varID));
+  if ( iz ) sprintf(axisname + axisnameLen, "_%u", iz+1);
+}
 
-      int gridindex = vlistGridIndex(vlistID, gridID);
-      int xdimid = streamptr->xdimID[gridindex];
-      int ydimid = streamptr->ydimID[gridindex];
+static
+int checkZaxisName(char *axisname, int fileID, int vlistID, int zaxisID, int nzaxis)
+{
+  char axisname2[CDI_MAX_NAME];
 
-      int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
-      int zdimid = streamptr->zaxisID[zaxisindex];
+  /* check that the name is not already defined */
+  unsigned iz = 0;
 
-      int ndims = ncvars[ncvarid].ndims;
-      int iodim = 0;
-      int ixyz = 0;
-      int ipow10[4] = {1, 10, 100, 1000};
+  size_t axisnameLen = strlen(axisname);
+  memcpy(axisname2, axisname, axisnameLen + 1);
+  do
+    {
+      if ( iz ) sprintf(axisname2 + axisnameLen, "_%u", iz+1);
 
-      if ( ncvars[ncvarid].tsteptype != TSTEP_CONSTANT ) iodim++;
+      int ncdimid, status = nc_inq_varid(fileID, axisname2, &ncdimid);
 
-      if ( gridInqType(gridID) == GRID_UNSTRUCTURED && ndims-iodim <= 2 && ydimid == xdimid )
-        {
-          if ( xdimid == ncvars[ncvarid].dimids[ndims-1] )
-            {
-              ixyz = 321;
-            }
-          else
-            {
-              ixyz = 213;
-            }
-        }
-      else
+      if ( status != NC_NOERR )
         {
-          for ( int idim = iodim; idim < ndims; idim++ )
+          if ( iz )
             {
-              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];
+              /* 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;
         }
-
-      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;
-        }
-
-      if ( ncvars[ncvarid].extra[0] != 0 )
-        {
-          vlistDefVarExtra(vlistID, varID, ncvars[ncvarid].extra);
-        }
-    }
-
-  for ( int varID = 0; varID < nvars; varID++ )
-    {
-      int ncvarid = varids[varID];
-      int ncid = ncvars[ncvarid].ncid;
-
-      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);
-
-	      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 (ncvars[ncvarid].vct) Free(ncvars[ncvarid].vct);
-	  if (ncvars[ncvarid].atts) Free(ncvars[ncvarid].atts);
-          ncvars[ncvarid].vct = NULL;
-          ncvars[ncvarid].atts = NULL;
-	}
-    }
-
-  /* release mem of not freed attributes */
-  for ( int ncvarid = 0; ncvarid < num_ncvars; ncvarid++ )
-    if ( ncvars[ncvarid].atts ) Free(ncvars[ncvarid].atts);
-
-  if ( varids ) Free(varids);
-
-  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);
-		}
-	    }
-	}
+      nextSuffix:
+      ++iz;
     }
+  while (iz <= 99);
 
-  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);
 
-	      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;
-		}
-	    }
+  if ( iz ) sprintf(axisname + axisnameLen, "_%u", iz+1);
 
-	  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);
-    }
+  return (int)iz;
 }
 
-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)
+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))
 {
-  nc_type xtype;
-  size_t attlen;
-  char attname[CDI_MAX_NAME];
-  enum { attstringlen = 65636 };
-  char attstring[attstringlen];
-  int iatt;
+  int dimID = CDI_UNDEFID;
+  int ncvarid = CDI_UNDEFID, ncbvarid = CDI_UNDEFID;
+  int nvdimID = CDI_UNDEFID;
+  int fileID  = streamptr->fileID;
+  size_t dimlen = (size_t)gridAxisInq->axisSize(gridID);
+  nc_type xtype = (gridInqPrec(gridID) == DATATYPE_FLT32) ? NC_FLOAT : NC_DOUBLE;
+  ncgrid_t *ncgrid = streamptr->ncgrid;
+
+  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 = (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)) )
+                {
+                  if ( dimKey == CDI_KEY_XDIMNAME )
+                    dimID = ncgrid[index].xdimID;
+                  else
+                    dimID = ncgrid[index].ydimID;
+                  break;
+                }
+            }
+        }
+    }
 
-  for ( iatt = 0; iatt < ngatts; iatt++ )
+  if ( dimID == CDI_UNDEFID )
     {
-      cdf_inq_attname(fileID, NC_GLOBAL, iatt, attname);
-      cdf_inq_atttype(fileID, NC_GLOBAL, attname, &xtype);
-      cdf_inq_attlen(fileID, NC_GLOBAL, attname, &attlen);
+      const double *pvals = gridAxisInq->axisValsPtr(gridID);
 
-      if ( xtypeIsText(xtype) )
-	{
-	  cdfGetAttText(fileID, NC_GLOBAL, attname, attstringlen, attstring);
+      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);
 
-          size_t attstrlen = strlen(attstring);
+      /* 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 ( 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);
-                    }
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-		  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
+      if ( ndims )
+        {
+          char dimname[CDI_MAX_NAME+3]; dimname[0] = 0;
+
+          if ( pvals == NULL )
+            cdiGridInqKeyStr(gridID, dimKey, CDI_MAX_NAME, dimname);
+
+          if ( dimname[0] == 0 ) strcpy(dimname, extendedAxisname);
+          dimID = checkDimName(fileID, dimlen, dimname);
+
+          if ( dimID == CDI_UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID);
+        }
+
+      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);
+
+          cdfPutGridStdAtts(fileID, ncvarid, gridID, axisLetter, gridAxisInq);
+          {
+            char axisStr[2] = { axisLetter, '\0' };
+            cdf_put_att_text(fileID, ncvarid, "axis", 1, axisStr);
+          }
+
+          pbounds = (double *)gridAxisInq->axisBoundsPtr(gridID);
+
+          if ( CDI_cmor_mode && grid_is_cyclic && !pbounds )
             {
-              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);
+              gen_bounds = true;
+              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 )
+            {
+              size_t nvertex = 2;
+              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);
             }
         }
-      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);
-	}
+
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
+
+      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 ( ndims == 0 )
+        {
+          if ( dimKey == CDI_KEY_XDIMNAME )
+            ncgrid[gridindex].xvarID = ncvarid;
+          else
+            ncgrid[gridindex].yvarID = ncvarid;
+        }
     }
+
+  ncgrid[gridindex].gridID = gridID;
+  if ( dimKey == CDI_KEY_XDIMNAME )
+    ncgrid[gridindex].xdimID = dimID;
+  else
+    ncgrid[gridindex].ydimID = dimID;
 }
 
 static
-int find_leadtime(int nvars, ncvar_t *ncvars)
+void finishCyclicXBounds(double *pbounds, size_t dimlen, const double *pvals)
 {
-  int leadtime_id = UNDEFID;
+  pbounds[0] = (pvals[0] + pvals[dimlen-1]-360)*0.5;
+  pbounds[2*dimlen-1] = (pvals[dimlen-1] + pvals[0]+360)*0.5;
+}
 
-  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
-    {
-      if ( ncvars[ncvarid].stdname[0] )
-        {
-          if ( strcmp(ncvars[ncvarid].stdname, "forecast_period") == 0 )
-            {
-              leadtime_id = ncvarid;
-              break;
-            }
-        }
-    }
+static
+void cdfDefXaxis(stream_t *streamptr, int gridID, int gridindex, int ndims)
+{
+  cdfDefAxisCommon(streamptr, gridID, gridindex, ndims, &gridInqsX,
+                   CDI_KEY_XDIMNAME, 'X', finishCyclicXBounds);
+}
 
-  return (leadtime_id);
+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]);
 }
 
 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 cdfDefYaxis(stream_t *streamptr, int gridID, int gridindex, int ndims)
 {
-  int ncvarid;
+  cdfDefAxisCommon(streamptr, gridID, gridindex, ndims, &gridInqsY,
+                   CDI_KEY_YDIMNAME, 'Y', finishCyclicYBounds);
+}
 
-  if ( timedimid == UNDEFID )
+static
+void cdfGridCompress(int fileID, int ncvarid, int gridsize, int filetype, int comptype)
+{
+#if  defined  (HAVE_NETCDF4)
+  if ( gridsize > 1 && comptype == CDI_COMPRESS_ZIP && (filetype == FILETYPE_NC4 || filetype == FILETYPE_NC4C) )
     {
-      char timeunits[CDI_MAX_NAME];
+      nc_def_var_chunking(fileID, ncvarid, NC_CHUNKED, NULL);
+      cdfDefVarDeflate(fileID, ncvarid, 1);
+    }
+#endif
+}
 
-      for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+static
+void cdfDefCurvilinear(stream_t *streamptr, int gridID, int gridindex)
+{
+  int xdimID = CDI_UNDEFID;
+  int ydimID = CDI_UNDEFID;
+  int ncxvarid = CDI_UNDEFID, ncyvarid = CDI_UNDEFID;
+  int ncbxvarid = CDI_UNDEFID, ncbyvarid = CDI_UNDEFID, ncavarid = CDI_UNDEFID;
+  nc_type xtype = (gridInqPrec(gridID) == DATATYPE_FLT32) ? NC_FLOAT : NC_DOUBLE;
+  ncgrid_t *ncgrid = streamptr->ncgrid;
+
+  int fileID  = streamptr->fileID;
+
+  size_t dimlen = (size_t)gridInqSize(gridID);
+  size_t xdimlen = (size_t)gridInqXsize(gridID);
+  size_t ydimlen = (size_t)gridInqYsize(gridID);
+
+  for ( int index = 0; index < gridindex; index++ )
+    {
+      if ( ncgrid[index].xdimID != CDI_UNDEFID )
         {
-          if ( ncvars[ncvarid].ndims == 0 && strcmp(ncvars[ncvarid].name, "time") == 0 )
+          int gridID0 = ncgrid[index].gridID;
+          int gridtype0 = gridInqType(gridID0);
+          if ( gridtype0 == GRID_CURVILINEAR )
             {
-              if ( ncvars[ncvarid].units[0] )
-                {
-                  strcpy(timeunits, ncvars[ncvarid].units);
-                  strtolower(timeunits);
-
-                  if ( isTimeUnits(timeunits) )
-                    {
-                      streamptr->basetime.ncvarid = ncvarid;
-                      break;
-                    }
-                }
+              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 = ncgrid[index].xdimID;
+                    ydimID = ncgrid[index].ydimID;
+                    ncxvarid = ncgrid[index].xvarID;
+                    ncyvarid = ncgrid[index].yvarID;
+                    break;
+                  }
             }
         }
     }
-  else
+
+  if ( xdimID == CDI_UNDEFID || ydimID == CDI_UNDEFID )
     {
-      int ltimevar = FALSE;
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+      {
+        char xdimname[CDI_MAX_NAME+3];
+        xdimname[0] = 0;
+        cdiGridInqKeyStr(gridID, CDI_KEY_XDIMNAME, CDI_MAX_NAME, xdimname);
+        if ( xdimname[0] == 0 ) { xdimname[0] = 'x'; xdimname[1] = 0; }
+        xdimID = checkDimName(fileID, xdimlen, xdimname);
+        if ( xdimID == CDI_UNDEFID ) cdf_def_dim(fileID, xdimname, xdimlen, &xdimID);
+      }
+      {
+        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 ( ncdims[timedimid].ncvarid != UNDEFID )
+      int nvdimID = CDI_UNDEFID;
+      int dimIDs[3];
+      if ( gridInqXboundsPtr(gridID) || gridInqYboundsPtr(gridID) )
         {
-          streamptr->basetime.ncvarid = ncdims[timedimid].ncvarid;
-          ltimevar = TRUE;
+          char vdimname[CDI_MAX_NAME+3]; vdimname[0] = 0;
+          cdiGridInqKeyStr(gridID, CDI_KEY_VDIMNAME, CDI_MAX_NAME, vdimname);
+          if ( vdimname[0] == 0 ) strcpy(vdimname, "nv4");
+          size_t nvertex = 4;
+          nvdimID = checkDimName(fileID, nvertex, vdimname);
+          if ( nvdimID == CDI_UNDEFID ) cdf_def_dim(fileID, vdimname, nvertex, &nvdimID);
         }
 
-      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;
-
-            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);
-              }
-          }
+      dimIDs[0] = ydimID;
+      dimIDs[1] = xdimID;
+      dimIDs[2] = nvdimID;
 
-      if ( ltimevar == FALSE ) /* search for WRF time description */
+      if ( gridInqXvalsPtr(gridID) )
         {
-          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;
-              }
-        }
+          char xaxisname[CDI_MAX_NAME]; xaxisname[0] = 0;
+          cdiGridInqKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, xaxisname);
+          checkGridName(xaxisname, fileID);
 
-      /* time varID */
-      ncvarid = streamptr->basetime.ncvarid;
+          cdf_def_var(fileID, xaxisname, xtype, 2, dimIDs, &ncxvarid);
+          cdfGridCompress(fileID, ncxvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
 
-      if ( ncvarid == UNDEFID )
-        {
-          Warning("Time variable >%s< not found!", ncdims[timedimid].name);
-        }
-    }
+          cdfPutGridStdAtts(fileID, ncxvarid, gridID, 'X', &gridInqsX);
 
-  /* time varID */
-  ncvarid = streamptr->basetime.ncvarid;
+          /* attribute for Panoply */
+          cdf_put_att_text(fileID, ncxvarid, "_CoordinateAxisType", 3, "Lon");
 
-  if ( ncvarid != UNDEFID && streamptr->basetime.lwrf == FALSE )
-    {
-      if ( ncvars[ncvarid].units[0] != 0 ) *time_has_units = TRUE;
+          if ( 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, 3, dimIDs, &ncbxvarid);
+              cdfGridCompress(fileID, ncbxvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
+
+              cdf_put_att_text(fileID, ncxvarid, "bounds", xaxisnameLen + sizeof (bndsName), xaxisname);
+            }
+        }
 
-      if ( ncvars[ncvarid].bounds != UNDEFID )
+      if ( gridInqYvalsPtr(gridID) )
         {
-          int nbdims = ncvars[ncvars[ncvarid].bounds].ndims;
-          if ( nbdims == 2 )
+          char yaxisname[CDI_MAX_NAME];
+          gridInqYname(gridID, yaxisname);
+          checkGridName(yaxisname, fileID);
+
+          cdf_def_var(fileID, yaxisname, xtype, 2, dimIDs, &ncyvarid);
+          cdfGridCompress(fileID, ncyvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
+
+          cdfPutGridStdAtts(fileID, ncyvarid, gridID, 'Y', &gridInqsY);
+
+          /* attribute for Panoply */
+          cdf_put_att_text(fileID, ncyvarid, "_CoordinateAxisType", 3, "Lat");
+
+          if ( gridInqYboundsPtr(gridID) && nvdimID != CDI_UNDEFID )
             {
-              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;
-                }
+              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);
             }
         }
+
+      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";
+
+          cdf_def_var(fileID, yaxisname_, xtype, 2, 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);
+        }
+
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
+
+      if ( ncxvarid  != CDI_UNDEFID ) cdf_put_var_double(fileID, ncxvarid,  gridInqXvalsPtr(gridID));
+      if ( ncbxvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncbxvarid, gridInqXboundsPtr(gridID));
+      if ( ncyvarid  != CDI_UNDEFID ) cdf_put_var_double(fileID, ncyvarid,  gridInqYvalsPtr(gridID));
+      if ( ncbyvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncbyvarid, gridInqYboundsPtr(gridID));
+      if ( ncavarid  != CDI_UNDEFID ) cdf_put_var_double(fileID, ncavarid,  gridInqAreaPtr(gridID));
     }
+
+  ncgrid[gridindex].gridID = gridID;
+  ncgrid[gridindex].xdimID = xdimID;
+  ncgrid[gridindex].ydimID = ydimID;
+  ncgrid[gridindex].xvarID = ncxvarid;
+  ncgrid[gridindex].yvarID = ncyvarid;
+  ncgrid[gridindex].avarID = ncavarid;
 }
 
 static
-void read_vct_echam(int fileID, int nvars, ncvar_t *ncvars, ncdim_t *ncdims, double **vct, size_t *pvctsize)
+void cdfDefRgrid(stream_t *streamptr, int gridID, int gridindex)
 {
-  /* find ECHAM VCT */
-  int nvcth_id = UNDEFID, vcta_id = UNDEFID, vctb_id = UNDEFID;
+  ncgrid_t *ncgrid = streamptr->ncgrid;
+  int dimID = CDI_UNDEFID;
 
-  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+  size_t dimlen = (size_t)gridInqSize(gridID);
+
+  int iz = 0;
+  for ( int index = 0; index < gridindex; index++ )
     {
-      if ( ncvars[ncvarid].ndims == 1 )
+      if ( ncgrid[index].xdimID != CDI_UNDEFID )
         {
-          size_t len = strlen(ncvars[ncvarid].name);
-          if ( len == 4 && ncvars[ncvarid].name[0] == 'h' && ncvars[ncvarid].name[1] == 'y' )
+          int gridID0 = ncgrid[index].gridID;
+          int gridtype0 = gridInqType(gridID0);
+          if ( gridtype0 == GRID_GAUSSIAN_REDUCED )
             {
-              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' )
+              size_t dimlen0 = (size_t)gridInqSize(gridID0);
+
+              if ( dimlen == dimlen0 )
                 {
-                  ncvars[ncvarid].isvar = FALSE; // hyam or hybm
+                  dimID = ncgrid[index].xdimID;
+                  break;
                 }
+              iz++;
             }
-	}
+        }
     }
 
-  /* read VCT */
-  if ( nvcth_id != UNDEFID && vcta_id != UNDEFID && vctb_id != UNDEFID )
+  if ( dimID == 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;
+      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;
+        }
+
+      char axisname[7] = "rgridX";
+      if ( iz == 0 ) axisname[5] = '\0';
+      else           sprintf(&axisname[5], "%1d", iz+1);
+
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+
+      cdf_def_dim(fileID, axisname, dimlen, &dimID);
+
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
     }
-}
 
+  ncgrid[gridindex].gridID = gridID;
+  ncgrid[gridindex].xdimID = dimID;
+}
 
-int cdfInqContents(stream_t *streamptr)
+static
+void cdfDefGdim(stream_t *streamptr, int gridID, int gridindex)
 {
-  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;
+  ncgrid_t *ncgrid = streamptr->ncgrid;
+  int iz = 0;
+  int dimID = CDI_UNDEFID;
 
-  memset(uuidOfHGrid, 0, CDI_UUID_SIZE);
-  memset(uuidOfVGrid, 0, CDI_UUID_SIZE);
-  gridfile[0] = 0;
-  fcreftime[0] = 0;
+  size_t dimlen = (size_t)gridInqSize(gridID);
 
-  int vlistID = streamptr->vlistID;
+  if ( gridInqYsize(gridID) == 0 )
+    for ( int index = 0; index < gridindex; index++ )
+      {
+        if ( ncgrid[index].xdimID != CDI_UNDEFID )
+          {
+            int gridID0 = ncgrid[index].gridID;
+            int gridtype0 = gridInqType(gridID0);
+            if ( gridtype0 == GRID_GENERIC )
+              {
+                size_t dimlen0 = (size_t)gridInqSize(gridID0);
+                if ( dimlen == dimlen0 )
+                  {
+                    dimID = ncgrid[index].xdimID;
+                    break;
+                  }
+                else
+                  iz++;
+              }
+          }
+      }
+
+  if ( gridInqXsize(gridID) == 0 )
+    for ( int index = 0; index < gridindex; index++ )
+      {
+        if ( ncgrid[index].ydimID != CDI_UNDEFID )
+          {
+            int gridID0 = ncgrid[index].gridID;
+            int gridtype0 = gridInqType(gridID0);
+            if ( gridtype0 == GRID_GENERIC )
+              {
+                size_t dimlen0 = (size_t)gridInqSize(gridID0);
+                if ( dimlen == dimlen0 )
+                  {
+                    dimID = ncgrid[index].ydimID;
+                    break;
+                  }
+                else
+                  iz++;
+              }
+          }
+      }
+
+  if ( dimID == CDI_UNDEFID )
+    {
+      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;
+    }
+
+  ncgrid[gridindex].gridID = gridID;
+  ncgrid[gridindex].xdimID = dimID;
+}
+
+static
+void cdfDefGridReference(stream_t *streamptr, int gridID)
+{
   int fileID  = streamptr->fileID;
+  int number = gridInqNumber(gridID);
+  if ( number > 0 )
+    cdf_put_att_int(fileID, NC_GLOBAL, "number_of_grid_used", NC_INT, 1, &number);
 
-  if ( CDI_Debug ) Message("streamID = %d, fileID = %d", streamptr->self, fileID);
+  const char *gridfile = gridInqReferencePtr(gridID);
+  if ( gridfile && gridfile[0] != 0 )
+    cdf_put_att_text(fileID, NC_GLOBAL, "grid_file_uri", strlen(gridfile), gridfile);
+}
 
-#if  defined  (HAVE_NETCDF4)
-  nc_inq_format(fileID, &format);
-#endif
+static
+void cdfDefGridUUID(stream_t *streamptr, int gridID)
+{
+  unsigned char uuidOfHGrid[CDI_UUID_SIZE];
 
-  cdf_inq(fileID, &ndims , &nvars, &ngatts, &unlimdimid);
+  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 ( CDI_Debug )
-    Message("root: ndims %d, nvars %d, ngatts %d", ndims, nvars, ngatts);
+static
+void cdfDefZaxisUUID(stream_t *streamptr, int zaxisID)
+{
+  unsigned char uuidOfVGrid[CDI_UUID_SIZE];
+  zaxisInqUUID(zaxisID, uuidOfVGrid);
 
-  if ( ndims == 0 )
+  if ( uuidOfVGrid[0] != 0 )
     {
-      Warning("ndims = %d", ndims);
-      return (CDI_EUFSTRUCT);
+      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);
+        }
     }
+}
 
-  /* alloc ncdims */
-  ncdims = (ncdim_t *) Malloc((size_t)ndims * sizeof (ncdim_t));
-  init_ncdims(ndims, ncdims);
+static
+void cdfDefUnstructured(stream_t *streamptr, int gridID, int gridindex)
+{
+  int dimID = CDI_UNDEFID;
+  int ncxvarid = CDI_UNDEFID, ncyvarid = CDI_UNDEFID;
+  int ncbxvarid = CDI_UNDEFID, ncbyvarid = CDI_UNDEFID, ncavarid = CDI_UNDEFID;
+  int nvdimID = CDI_UNDEFID;
+  nc_type xtype = (gridInqPrec(gridID) == DATATYPE_FLT32) ? NC_FLOAT : NC_DOUBLE;
+  ncgrid_t *ncgrid = streamptr->ncgrid;
 
-  if ( nvars > 0 )
-    {
-      /* alloc ncvars */
-      ncvars = (ncvar_t *) Malloc((size_t)nvars * sizeof (ncvar_t));
-      init_ncvars(nvars, ncvars);
+  int fileID  = streamptr->fileID;
 
-      for ( ncvarid = 0; ncvarid < nvars; ++ncvarid )
-        ncvars[ncvarid].ncid = fileID;
-    }
+  size_t dimlen = (size_t)gridInqSize(gridID);
 
-#if  defined  (TEST_GROUPS)
-#if  defined  (HAVE_NETCDF4)
-  if ( format == NC_FORMAT_NETCDF4 )
+  for ( int index = 0; index < gridindex; index++ )
     {
-      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 )
+      if ( ncgrid[index].xdimID != CDI_UNDEFID )
         {
-          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 )
+          int gridID0 = ncgrid[index].gridID;
+          int gridtype0 = gridInqType(gridID0);
+          if ( gridtype0 == GRID_UNSTRUCTURED )
             {
+              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 = ncgrid[index].xdimID;
+                    ncxvarid = ncgrid[index].xvarID;
+                    ncyvarid = ncgrid[index].yvarID;
+                    ncavarid = ncgrid[index].avarID;
+		    break;
+		  }
             }
         }
     }
-#endif
-#endif
 
-  if ( nvars == 0 )
+  if ( dimID == CDI_UNDEFID )
     {
-      Warning("nvars = %d", nvars);
-      return (CDI_EUFSTRUCT);
-    }
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+      {
+        char xdimname[CDI_MAX_NAME+3];
+        xdimname[0] = 0;
+        cdiGridInqKeyStr(gridID, CDI_KEY_XDIMNAME, CDI_MAX_NAME, xdimname);
+        if ( xdimname[0] == 0 ) strcpy(xdimname, "ncells");
+        dimID = checkDimName(fileID, dimlen, xdimname);
+        if ( dimID == CDI_UNDEFID ) cdf_def_dim(fileID, xdimname, dimlen, &dimID);
+      }
 
-  /* scan global attributes */
-  scan_global_attributes(fileID, vlistID, streamptr, ngatts, &instID, &modelID, &ucla_les,
-                         uuidOfHGrid, uuidOfVGrid, gridfile, &number_of_grid_used);
+      size_t nvertex = (size_t)gridInqNvertex(gridID);
+      if ( nvertex > 0 )
+        {
+          char vdimname[CDI_MAX_NAME+3];
+          vdimname[0] = 0;
+          cdiGridInqKeyStr(gridID, CDI_KEY_VDIMNAME, CDI_MAX_NAME, vdimname);
+          if ( vdimname[0] == 0 ) strcpy(vdimname, "vertices");
+          nvdimID = checkDimName(fileID, nvertex, vdimname);
+          if ( nvdimID == CDI_UNDEFID ) cdf_def_dim(fileID, vdimname, nvertex, &nvdimID);
+        }
 
-  /* find time dim */
-  if ( unlimdimid >= 0 )
-    timedimid = unlimdimid;
-  else
-    timedimid = cdfTimeDimID(fileID, ndims, nvars);
+      cdfDefGridReference(streamptr, gridID);
 
-  streamptr->basetime.ncdimid = timedimid;
+      cdfDefGridUUID(streamptr, gridID);
 
-  if ( timedimid != UNDEFID )
-    cdf_inq_dimlen(fileID, timedimid, &ntsteps);
-  else
-    ntsteps = 0;
+      if ( gridInqXvalsPtr(gridID) )
+        {
+          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, 1, &dimID, &ncxvarid);
+          cdfGridCompress(fileID, ncxvarid, (int)dimlen, streamptr->filetype, streamptr->comptype);
 
-  if ( CDI_Debug ) Message("Number of timesteps = %d", ntsteps);
-  if ( CDI_Debug ) Message("Time dimid = %d", streamptr->basetime.ncdimid);
+          cdfPutGridStdAtts(fileID, ncxvarid, gridID, 'X', &gridInqsX);
 
-  /* 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 ( gridInqXboundsPtr(gridID) && nvdimID != CDI_UNDEFID )
+            {
+              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);
 
-  if ( CDI_Debug ) printNCvars(ncvars, nvars, "cdfScanVarAttributes");
+              cdf_put_att_text(fileID, ncxvarid, "bounds", xaxisnameLen + sizeof (bndsName), xaxisname);
+            }
+        }
 
-  /* scan attributes of all variables */
-  cdfScanVarAttributes(nvars, ncvars, ncdims, timedimid, modelID, format);
+      if ( gridInqYvalsPtr(gridID) )
+        {
+          char yaxisname[CDI_MAX_NAME];
+          gridInqYname(gridID, yaxisname);
+          checkGridName(yaxisname, fileID);
+          cdf_def_var(fileID, yaxisname, xtype, 1, &dimID, &ncyvarid);
+          cdfGridCompress(fileID, ncyvarid, (int)dimlen, streamptr->filetype, streamptr->comptype);
 
+          cdfPutGridStdAtts(fileID, ncyvarid, gridID, 'Y', &gridInqsY);
 
-  if ( CDI_Debug ) printNCvars(ncvars, nvars, "find coordinate vars");
+          if ( gridInqYboundsPtr(gridID) && nvdimID != CDI_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);
 
-  /* 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_att_text(fileID, ncyvarid, "bounds", yaxisnameLen + sizeof (bndsName), yaxisname);
+            }
+        }
 
-	      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 ( 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";
+
+          cdf_def_var(fileID, yaxisname_, xtype, 1, &dimID, &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);
+        }
+
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
+
+      if ( ncxvarid  != CDI_UNDEFID ) cdf_put_var_double(fileID, ncxvarid,  gridInqXvalsPtr(gridID));
+      if ( ncbxvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncbxvarid, gridInqXboundsPtr(gridID));
+      if ( ncyvarid  != CDI_UNDEFID ) cdf_put_var_double(fileID, ncyvarid,  gridInqYvalsPtr(gridID));
+      if ( ncbyvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncbyvarid, gridInqYboundsPtr(gridID));
+      if ( ncavarid  != CDI_UNDEFID ) cdf_put_var_double(fileID, ncavarid,  gridInqAreaPtr(gridID));
     }
 
-  /* find time vars */
-  find_time_vars(nvars, ncvars, ncdims, timedimid, streamptr, &time_has_units, &time_has_bounds, &time_climatology);
+  ncgrid[gridindex].gridID = gridID;
+  ncgrid[gridindex].xdimID = dimID;
+  ncgrid[gridindex].xvarID = ncxvarid;
+  ncgrid[gridindex].yvarID = ncyvarid;
+  ncgrid[gridindex].avarID = ncavarid;
+}
 
-  leadtime_id = find_leadtime(nvars, ncvars);
-  if ( leadtime_id != UNDEFID ) ncvars[leadtime_id].isvar = FALSE;
+struct attTxtTab2
+{
+  const char *attName, *attVal;
+  size_t valLen;
+};
 
-  /* check ncvars */
-  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+static
+void cdf_def_vct_echam(stream_t *streamptr, int zaxisID)
+{
+  int type = zaxisInqType(zaxisID);
+
+  if ( type == ZAXIS_HYBRID || type == ZAXIS_HYBRID_HALF )
     {
-      if ( timedimid != UNDEFID )
-	if ( ncvars[ncvarid].isvar == -1 &&
-	     ncvars[ncvarid].ndims > 1   &&
-	     timedimid == ncvars[ncvarid].dimids[0] )
-	  cdfSetVar(ncvars, ncvarid, TRUE);
+      int ilev = zaxisInqVctSize(zaxisID)/2;
+      if ( ilev == 0 ) return;
 
-      if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims == 0 )
-	cdfSetVar(ncvars, ncvarid, FALSE);
+      int mlev = ilev - 1;
 
-      //if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims > 1 )
-      if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims >= 1 )
-	cdfSetVar(ncvars, ncvarid, TRUE);
+      if ( streamptr->vct.ilev > 0 )
+        {
+          if ( streamptr->vct.ilev != ilev )
+            Error("More than one VCT for each file unsupported!");
+          return;
+        }
 
-      if ( ncvars[ncvarid].isvar == -1 )
-	{
-	  ncvars[ncvarid].isvar = 0;
-	  Warning("Variable %s has an unknown type, skipped!", ncvars[ncvarid].name);
-	  continue;
-	}
+      int fileID = streamptr->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 ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-      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;
-	}
+      int ncdimid, ncdimid2;
+      cdf_def_dim(fileID, "nhym", (size_t)mlev, &ncdimid);
+      cdf_def_dim(fileID, "nhyi", (size_t)ilev, &ncdimid2);
 
-      if ( xtypeIsText(ncvars[ncvarid].xtype) )
-	{
-	  ncvars[ncvarid].isvar = 0;
-	  continue;
-	}
+      streamptr->vct.mlev   = mlev;
+      streamptr->vct.ilev   = ilev;
+      streamptr->vct.mlevID = ncdimid;
+      streamptr->vct.ilevID = ncdimid2;
 
-      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;
-	}
+      int hyaiid, hybiid, hyamid, hybmid;
+      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 ( 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;
-	    }
-	}
-    }
+      {
+        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);
+      }
 
-  /* verify coordinate vars - first scan (dimname == varname) */
-  verify_coordinate_vars_1(fileID, ndims, ncdims, ncvars, timedimid);
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
 
-  /* verify coordinate vars - second scan (all other variables) */
-  verify_coordinate_vars_2(nvars, ncvars);
+      const double *vctptr = zaxisInqVctPtr(zaxisID);
 
-  if ( CDI_Debug ) printNCvars(ncvars, nvars, "verify_coordinate_vars");
+      cdf_put_var_double(fileID, hyaiid, vctptr);
+      cdf_put_var_double(fileID, hybiid, vctptr+ilev);
 
-  if ( ucla_les == TRUE )
-    {
-      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;
-		}
-	    }
-	}
+      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);
+        }
     }
-  /*
-  for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
-    {
-      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);
+}
 
-	  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);
-	}
-    }
-  */
+static
+void cdf_def_vct_cf(stream_t *streamptr, int zaxisID, int nclevID, int ncbndsID)
+{
+  int type = zaxisInqType(zaxisID);
 
-  /* Set coordinate varids (att: associate)  */
-  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+  if ( type == ZAXIS_HYBRID || type == ZAXIS_HYBRID_HALF )
     {
-      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];
-	    }
-	}
-    }
+      int ilev = zaxisInqVctSize(zaxisID)/2;
+      if ( ilev == 0 ) return;
 
-  /* set dim type */
-  setDimType(nvars, ncvars, ncdims);
+      int mlev = ilev - 1;
+      int hyaiid = 0, hybiid = 0, hyamid, hybmid;
 
-  /* read ECHAM VCT if present */
-  size_t vctsize = 0;
-  double *vct = NULL;
-  read_vct_echam(fileID, nvars, ncvars, ncdims, &vct, &vctsize);
+      if ( streamptr->vct.ilev > 0 )
+        {
+          if ( streamptr->vct.ilev != ilev )
+            Error("more than one VCT for each file unsupported!");
+          return;
+        }
+
+      int fileID = streamptr->fileID;
 
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-  if ( CDI_Debug ) printNCvars(ncvars, nvars, "define_all_grids");
+      int dimIDs[2];
+      dimIDs[0] = nclevID;
+      dimIDs[1] = ncbndsID;
 
-  /* define all grids */
-  define_all_grids(streamptr, vlistID, ncdims, nvars, ncvars, timedimid, uuidOfHGrid, gridfile, number_of_grid_used);
+      streamptr->vct.mlev   = mlev;
+      streamptr->vct.ilev   = ilev;
+      streamptr->vct.mlevID = nclevID;
+      streamptr->vct.ilevID = nclevID;
 
+      cdf_def_var(fileID, "ap", NC_DOUBLE, 1, dimIDs,  &hyamid);
+      cdf_def_var(fileID, "b",  NC_DOUBLE, 1, dimIDs,  &hybmid);
 
-  /* define all zaxes */
-  define_all_zaxes(streamptr, vlistID, ncdims, nvars, ncvars, vctsize, vct, uuidOfVGrid);
-  if ( vct ) Free(vct);
+      {
+        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 ( ncbndsID != -1 )
+        {
+          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);
+          }
+        }
 
-  /* 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;
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
 
-  nvars_data = nvarids;
+      const double *vctptr = zaxisInqVctPtr(zaxisID);
+      double tarray[ilev*2];
 
-  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 ( ncbndsID != -1 )
+        {
+          for ( int i = 0; i < mlev; ++i )
+            {
+              tarray[2*i  ] = vctptr[i];
+              tarray[2*i+1] = vctptr[i+1];
+            }
+          cdf_put_var_double(fileID, hyaiid, tarray);
 
+          for ( int i = 0; i < mlev; ++i )
+            {
+              tarray[2*i  ] = vctptr[ilev+i];
+              tarray[2*i+1] = vctptr[ilev+i+1];
+            }
+          cdf_put_var_double(fileID, hybiid, tarray);
+        }
 
-  if ( nvars_data == 0 )
-    {
-      streamptr->ntsteps = 0;
-      return (CDI_EUFSTRUCT);
+      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 ( ntsteps == 0 && streamptr->basetime.ncdimid == UNDEFID && streamptr->basetime.ncvarid != UNDEFID )
-    ntsteps = 1;
+struct attTxtTab { const char *txt; size_t txtLen; };
+
+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 ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+
+  int ncvarid;
+  cdf_def_dim(fileID, axisname, dimlen, dimID);
+  cdf_def_var(fileID, axisname, (nc_type) xtype, 1, dimID,  &ncvarid);
+  *ncvaridp = 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 }
+      }
+    };
 
-  streamptr->ntsteps = (long)ntsteps;
+    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);
+  }
 
-  /* define all data variables */
-  define_all_vars(streamptr, vlistID, instID, modelID, varids, nvars_data, nvars, ncvars);
+  {
+    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);
+  }
 
+  cdf_enddef(fileID);
+  streamptr->ncmode = 2;
 
-  cdiCreateTimesteps(streamptr);
+  cdf_put_var_double(fileID, ncvarid, zaxisInqLevelsPtr(zaxisID));
 
-  /* time varID */
-  int nctimevarid = streamptr->basetime.ncvarid;
+  cdf_def_vct_echam(streamptr, zaxisID);
 
-  if ( time_has_units )
+  if ( *dimID == CDI_UNDEFID )
     {
-      taxis_t *taxis = &streamptr->tsteps[0].taxis;
+      if ( type == ZAXIS_HYBRID )
+        streamptr->zaxisID[zaxisindex] = streamptr->vct.mlevID;
+      else
+        streamptr->zaxisID[zaxisindex] = streamptr->vct.ilevID;
+    }
+}
 
-      if ( setBaseTime(ncvars[nctimevarid].units, taxis) == 1 )
-        {
-          nctimevarid = UNDEFID;
-          streamptr->basetime.ncvarid = UNDEFID;
-        }
+static
+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)
+{
+  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 ( leadtime_id != UNDEFID && taxis->type == TAXIS_RELATIVE )
-        {
-          streamptr->basetime.leadtimeid = leadtime_id;
-          taxis->type = TAXIS_FORECAST;
+  int fileID = streamptr->fileID;
+  if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-          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;
+  strcpy(axisname, "lev");
 
-          setForecastTime(fcreftime, taxis);
-        }
-    }
+  int ncvarid;
+  cdf_def_dim(fileID, axisname, dimlen, dimID);
+  cdf_def_var(fileID, axisname, (nc_type) xtype, 1, dimID,  &ncvarid);
+  *ncvaridp = ncvarid;
 
-  if ( time_has_bounds )
-    {
-      streamptr->tsteps[0].taxis.has_bounds = TRUE;
-      if ( time_climatology ) streamptr->tsteps[0].taxis.climatology = TRUE;
-    }
+  {
+    static const char sname[] = "standard_name",
+      sname_v[] = "atmosphere_hybrid_sigma_pressure_coordinate",
+      lname[] = "long_name",
+      lname_v[] = "hybrid sigma pressure coordinate",
+      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 },
+      { 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);
+  }
+  {
+    char txt[CDI_MAX_NAME];
+    size_t len = (size_t)(sprintf(txt, "%s%s", "ap: ap b: b ps: ", psname));
+    cdf_put_att_text(fileID, ncvarid, "formula_terms", len, txt);
+  }
 
-  if ( nctimevarid != UNDEFID )
-    {
-      taxis_t *taxis = &streamptr->tsteps[0].taxis;
-      ptaxisDefName(taxis, ncvars[nctimevarid].name);
-      if ( ncvars[nctimevarid].longname[0] )
-        ptaxisDefLongname(taxis, ncvars[nctimevarid].longname);
-    }
+  int ncbvarid = CDI_UNDEFID;
+  int nvdimID = CDI_UNDEFID;
 
-  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);
-      }
+  double lbounds[dimlen], ubounds[dimlen], levels[dimlen];
 
-  if ( streamptr->tsteps[0].taxis.type == TAXIS_FORECAST )
-    {
-      taxisID = taxisCreate(TAXIS_FORECAST);
-    }
-  else if ( streamptr->tsteps[0].taxis.type == TAXIS_RELATIVE )
+  zaxisInqLevels(zaxisID, levels);
+
+  if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
     {
-      taxisID = taxisCreate(TAXIS_RELATIVE);
+      zaxisInqLbounds(zaxisID, lbounds);
+      zaxisInqUbounds(zaxisID, ubounds);
     }
   else
     {
-      taxisID = taxisCreate(TAXIS_ABSOLUTE);
-      if ( !time_has_units )
-	{
-	  taxisDefTunit(taxisID, TUNIT_DAY);
-	  streamptr->tsteps[0].taxis.unit = TUNIT_DAY;
-	}
+      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 ( calendar == UNDEFID && streamptr->tsteps[0].taxis.type != TAXIS_ABSOLUTE )
+  //if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
     {
-      calendar = CALENDAR_STANDARD;
-    }
+      size_t nvertex = 2;
+      if ( nc_inq_dimid(fileID, bndsName, &nvdimID) != NC_NOERR )
+        cdf_def_dim(fileID, bndsName, nvertex, &nvdimID);
 
-#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic warning "-Wstrict-overflow"
-#endif
-  if ( calendar != UNDEFID )
-    {
-      taxis_t *taxis = &streamptr->tsteps[0].taxis;
-      taxis->calendar = calendar;
-      taxisDefCalendar(taxisID, calendar);
+      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",
+              units[] = "units",
+              units_v[] = "1";
+            struct attTxtTab2 tab[] = {
+              { sname, sname_v, sizeof (sname_v) - 1 },
+              { units, units_v, sizeof (units_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);
+          }
+        }
     }
-#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)
-#pragma GCC diagnostic pop
-#endif
-
-  vlistDefTaxis(vlistID, taxisID);
-
-  streamptr->curTsID = 0;
-  streamptr->rtsteps = 1;
 
-  (void) cdfInqTimestep(streamptr, 0);
+  cdf_enddef(fileID);
+  streamptr->ncmode = 2;
 
-  cdfCreateRecords(streamptr, 0);
+  cdf_put_var_double(fileID, ncvarid, levels);
 
-  /* free ncdims */
-  Free(ncdims);
+  if ( ncbvarid != CDI_UNDEFID )
+    {
+      double zbounds[2*dimlen];
+      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);
+    }
 
-  /* free ncvars */
-  Free(ncvars);
+  cdf_def_vct_cf(streamptr, zaxisID, *dimID, nvdimID);
 
-  return (0);
+  if ( *dimID == CDI_UNDEFID )
+    {
+      if ( type == ZAXIS_HYBRID )
+        streamptr->zaxisID[zaxisindex] = streamptr->vct.mlevID;
+      else
+        streamptr->zaxisID[zaxisindex] = streamptr->vct.ilevID;
+    }
 }
 
 static
-void wrf_read_timestep(int fileID, int nctimevarid, int tsID, taxis_t *taxis)
+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)
 {
-  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;
-  }
+  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);
 }
 
 static
-double get_timevalue(int fileID, int nctimevarid, int tsID, timecache_t *tcache)
+void cdfDefZaxis(stream_t *streamptr, int zaxisID)
 {
-  double timevalue = 0;
-  size_t index = (size_t) tsID;
+  /*  char zaxisname0[CDI_MAX_NAME]; */
+  char axisname[CDI_MAX_NAME];
+  int dimID = CDI_UNDEFID;
+  int dimIDs[2];
+  int ncvarid = CDI_UNDEFID, ncbvarid = CDI_UNDEFID;
+  int nvdimID = CDI_UNDEFID;
+  int xtype = NC_DOUBLE;
 
-  if ( tcache )
+  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 ( tcache->size == 0 || (tsID < tcache->startid || tsID > (tcache->startid+tcache->size-1)) )
+      is_scalar = zaxisInqScalar(zaxisID);
+      if ( !is_scalar && CDI_cmor_mode )
         {
-          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++;
-            }
+          is_scalar = TRUE;
+          zaxisDefScalar(zaxisID);
         }
-
-      timevalue = tcache->cache[tsID%MAX_TIMECACHE_SIZE];
     }
-  else
+
+  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 == CDI_UNDEFID )
     {
-      cdf_get_var1_double(fileID, nctimevarid, &index, &timevalue);
-      if ( timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE ) timevalue = 0;
-    }
+      checkZaxisName(axisname, fileID, vlistID, zaxisID, nzaxis);
 
-  return timevalue;
-}
+      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 ( type == ZAXIS_REFERENCE ) cdfDefZaxisUUID(streamptr, zaxisID);
 
-int cdfInqTimestep(stream_t * streamptr, int tsID)
-{
-  long nrecs = 0;
-  double timevalue;
-  int fileID;
-  taxis_t *taxis;
+      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 ( CDI_Debug ) Message("streamID = %d  tsID = %d", streamptr->self, tsID);
+          if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-  if ( tsID < 0 ) Error("unexpected tsID = %d", tsID);
+          if ( ndims && dimID == CDI_UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID);
 
-  if ( tsID < streamptr->ntsteps && streamptr->ntsteps > 0 )
-    {
-      cdfCreateRecords(streamptr, tsID);
+          cdf_def_var(fileID, axisname, (nc_type) xtype, ndims, &dimID, &ncvarid);
 
-      taxis = &streamptr->tsteps[tsID].taxis;
-      if ( tsID > 0 )
-	ptaxisCopy(taxis, &streamptr->tsteps[0].taxis);
+          cdfPutGridStdAtts(fileID, ncvarid, zaxisID, 'Z', &gridInqsZ);
 
-      timevalue = tsID;
+          {
+            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");
 
-      int nctimevarid = streamptr->basetime.ncvarid;
-      if ( nctimevarid != UNDEFID )
-	{
-	  fileID = streamptr->fileID;
-	  size_t index  = (size_t)tsID;
+	  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 ( streamptr->basetime.lwrf )
-	    {
-              wrf_read_timestep(fileID, nctimevarid, tsID, taxis);
+	      if ( nvdimID != CDI_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);
+		}
 	    }
-	  else
+
+          cdf_enddef(fileID);
+          streamptr->ncmode = 2;
+
+          cdf_put_var_double(fileID, ncvarid, zaxisInqLevelsPtr(zaxisID));
+
+          if ( ncbvarid != CDI_UNDEFID )
 	    {
-#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);
+              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);
 	    }
 
-	  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;
+          if ( ndims == 0 ) streamptr->nczvarID[zaxisindex] = ncvarid;
+        }
 
-	      cdiDecodeTimeval(timevalue, taxis, &taxis->vdate_lb, &taxis->vtime_lb);
+      {
+        int natts;
+        cdiInqNatts(zaxisID, CDI_GLOBAL, &natts);
 
-              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;
+        if ( natts > 0 && streamptr->ncmode == 2 ) cdf_redef(fileID);
 
-	      cdiDecodeTimeval(timevalue, taxis, &taxis->vdate_ub, &taxis->vtime_ub);
-	    }
+        cdfDefineAttributes(zaxisID, CDI_GLOBAL, fileID, ncvarid);
 
-          int leadtimeid = streamptr->basetime.leadtimeid;
-          if ( leadtimeid != UNDEFID )
-            {
-              timevalue = get_timevalue(fileID, leadtimeid, tsID, NULL);
-              cdiSetForecastPeriod(timevalue, taxis);
-            }
-	}
+        if ( natts > 0 && streamptr->ncmode == 2 ) cdf_enddef(fileID);
+      }
     }
 
-  streamptr->curTsID = tsID;
-  nrecs = streamptr->tsteps[tsID].nrecs;
-
-  return ((int) nrecs);
+  if ( dimID != CDI_UNDEFID )
+    streamptr->zaxisID[zaxisindex] = dimID;
 }
 
-
-void cdfDefHistory(stream_t *streamptr, int size, const char *history)
+static
+void cdf_def_mapping(stream_t *streamptr, int gridID)
 {
-  int ncid = streamptr->fileID;
-  cdf_put_att_text(ncid, NC_GLOBAL, "history", (size_t) size, history);
-}
+  char mapping[CDI_MAX_NAME]; mapping[0] = 0;
+  cdiGridInqKeyStr(gridID, CDI_KEY_MAPPING, CDI_MAX_NAME, mapping);
+  if ( mapping[0] )
+    {
+      char gmapvarname[CDI_MAX_NAME]; gmapvarname[0] = 0;
+      cdiGridInqKeyStr(gridID, CDI_KEY_MAPNAME, CDI_MAX_NAME, gmapvarname);
 
+      int fileID = streamptr->fileID;
+      cdf_redef(fileID);
 
-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);
+      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);
 
-  return ((int) size);
-}
+      cdf_enddef(fileID);
 
+      if ( ncerrcode == NC_NOERR )
+        {
+          int dummy = 1;
+          cdf_put_var_int(fileID, ncvarid, &dummy);
+        }
+    }
+}
 
-void cdfInqHistoryString(stream_t *streamptr, char *history)
+static
+void cdfDefGrid(stream_t *streamptr, int gridID, int gridindex)
 {
-  int ncid = streamptr->fileID;
-  if ( streamptr->historyID != UNDEFID )
-    {
-      nc_type atttype;
-      cdf_inq_atttype(ncid, NC_GLOBAL, "history", &atttype);
+  if ( streamptr->ncgrid[gridindex].xdimID != CDI_UNDEFID ) return;
 
-      if ( atttype == NC_CHAR )
+  int gridtype = gridInqType(gridID);
+  int size     = gridInqSize(gridID);
+
+  if ( CDI_Debug )
+    Message("gridtype = %d  size = %d", gridtype, size);
+
+  if ( gridtype == GRID_GAUSSIAN    ||
+       gridtype == GRID_LONLAT      ||
+       gridtype == GRID_PROJECTION  ||
+       gridtype == GRID_GENERIC )
+    {
+      if ( gridtype == GRID_GENERIC )
         {
-          cdf_get_att_text(ncid, NC_GLOBAL, "history", history);
+          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 ( gridInqYsize(gridID) > 0 /*&& gridInqYvals(gridID, NULL) > 0*/ )
+                {
+                  cdfDefYaxis(streamptr, gridID, gridindex, 1);
+                  ly = true;
+                }
+
+              if ( !lx && !ly ) cdfDefGdim(streamptr, gridID, gridindex);
+            }
         }
-#if  defined  (HAVE_NETCDF4)
-      else if ( atttype == NC_STRING )
+      else
         {
-          // ToDo
-          Warning("History attribute with type NC_STRING unsupported!");
+          int ndims = 1;
+          if ( gridtype == GRID_LONLAT && size == 1 && gridInqHasDims(gridID) == FALSE )
+            ndims = 0;
+
+          if ( gridInqXsize(gridID) > 0 ) cdfDefXaxis(streamptr, gridID, gridindex, ndims);
+          if ( gridInqYsize(gridID) > 0 ) cdfDefYaxis(streamptr, gridID, gridindex, ndims);
+
+          cdf_def_mapping(streamptr, gridID);
         }
-#endif
     }
+  else if ( gridtype == GRID_CURVILINEAR )
+    {
+      cdfDefCurvilinear(streamptr, gridID, gridindex);
+    }
+  else if ( gridtype == GRID_UNSTRUCTURED )
+    {
+      cdfDefUnstructured(streamptr, gridID, gridindex);
+    }
+  else if ( gridtype == GRID_GAUSSIAN_REDUCED )
+    {
+      cdfDefRgrid(streamptr, gridID, gridindex);
+    }
+  else if ( gridtype == GRID_SPECTRAL )
+    {
+      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_LCC )
+    {
+      cdfDefLcc(streamptr, gridID);
+    }
+  */
+  else
+    {
+      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 index = 0;
   int vlistID = streamptr->vlistID;
-  if ( vlistID == UNDEFID )
+  if ( vlistID == CDI_UNDEFID )
     Error("Internal problem! vlist undefined for streamptr %p", streamptr);
 
   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);
-      }
+  streamptr->ncgrid = (ncgrid_t*) Malloc(2*ngrids*sizeof(ncgrid_t));
+  for ( index = 0; index < 2*ngrids; ++index )
+    {
+      streamptr->ncgrid[index].gridID = CDI_UNDEFID;
+      streamptr->ncgrid[index].xdimID = CDI_UNDEFID;
+      streamptr->ncgrid[index].ydimID = CDI_UNDEFID;
+      streamptr->ncgrid[index].xvarID = CDI_UNDEFID;
+      streamptr->ncgrid[index].yvarID = CDI_UNDEFID;
+      streamptr->ncgrid[index].avarID = CDI_UNDEFID;
+    }
 
-  if ( nzaxis > 0 )
-    for ( int index = 0; index < nzaxis; index++ )
-      {
-        int zaxisID = vlistZaxis(vlistID, index);
-        if ( streamptr->zaxisID[index] == UNDEFID ) cdfDefZaxis(streamptr, zaxisID);
-      }
+  for ( index = 0; index < ngrids; ++index )
+    {
+      int gridID = vlistGrid(vlistID, index);
+      cdfDefGrid(streamptr, gridID, index);
+    }
+  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);
+    }
 
-  /* define time first!!!
-    int nvars  = vlistNvars(vlistID);
-  for ( int varID = 0; varID < nvars; varID++ )
+  int nzaxis = vlistNzaxis(vlistID);
+  for ( int index = 0; index < nzaxis; ++index )
     {
-      int ncvarid = cdfDefVar(streamptr, varID);
+      int zaxisID = vlistZaxis(vlistID, index);
+      if ( streamptr->zaxisID[index] == CDI_UNDEFID ) cdfDefZaxis(streamptr, zaxisID);
     }
-  */
 }
+
 #endif
+
 /*
  * Local Variables:
  * c-file-style: "Java"
@@ -45141,33 +44703,26 @@ 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_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:   { 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_SPECTRAL:   { gridtype = GRID_SPECTRAL;   break; }
+    case  GRIB1_GTYPE_GME:        { gridtype = GRID_GME;        break; }
     }
 
-  return (gridtype);
+  return gridtype;
 }
 
 static
-int cgribexGetIsRotated(int *isec2)
+bool cgribexGetIsRotated(int *isec2)
 {
-  int isRotated = 0;
-
-  if ( ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT )
-    {
-      isRotated = 1;
-    }
-
-  return (isRotated);
+  return (ISEC2_GridType == GRIB1_GTYPE_LATLON_ROT);
 }
 
 static
@@ -45186,14 +44741,14 @@ int cgribexGetZaxisHasBounds(int grb_ltype)
       }
     }
 
-  return (lbounds);
+  return lbounds;
 }
 
 static
 int cgribexGetTimeUnit(int *isec1)
 {
   int timeunit = TUNIT_HOUR;
-  static int lprint = TRUE;
+  static bool lprint = true;
 
   switch ( ISEC1_TimeUnit )
     {
@@ -45209,30 +44764,27 @@ int cgribexGetTimeUnit(int *isec1)
       if ( lprint )
 	{
 	  Message("GRIB time unit %d unsupported!", ISEC1_TimeUnit);
-	  lprint = FALSE;
+	  lprint = false;
 	}
       break;
     }
 
-  return (timeunit);
+  return timeunit;
 }
 
 static
-int cgribexTimeIsFC(int *isec1)
+bool cgribexTimeIsFC(int *isec1)
 {
-  int isFC = TRUE;
+  bool isFC = (ISEC1_TimeRange == 10 && ISEC1_TimePeriod1 == 0 && ISEC1_TimePeriod2 == 0) ? false : true;
 
-  if ( ISEC1_TimeRange == 10 && ISEC1_TimePeriod1 == 0 && ISEC1_TimePeriod2 == 0 )
-    isFC = FALSE;
-
-  return (isFC);
+  return isFC;
 }
 
 static
 int cgribexGetTsteptype(int timerange)
 {
   int tsteptype = TSTEP_INSTANT;
-  static int lprint = TRUE;
+  static bool lprint = true;
 
   switch ( timerange )
     {
@@ -45247,19 +44799,20 @@ int cgribexGetTsteptype(int timerange)
       if ( lprint )
 	{
 	  Message("Time range indicator %d unsupported, set to 0!", timerange);
-	  lprint = FALSE;
+	  lprint = false;
 	}
       break;
     }
 
-  return (tsteptype);
+  return tsteptype;
 }
 
 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)
 {
-  int compyinc = TRUE;
+  bool compyinc = true;
   int gridtype = cgribexGetGridType(isec2);
+  int projtype = (gridtype == GRID_PROJECTION && cgribexGetIsRotated(isec2)) ? CDI_PROJ_RLL : CDI_UNDEFID;
 
   if ( streamptr->unreduced && gridtype == GRID_GAUSSIAN_REDUCED && iret != -801 )
     {
@@ -45269,196 +44822,174 @@ void cgribexGetGrid(stream_t *streamptr, int *isec2, double *fsec2, int *isec4,
       gridtype = GRID_GAUSSIAN;
       ISEC2_NumLon = nlon;
       ISEC4_NumValues = nlon*ISEC2_NumLat;
-      compyinc = FALSE;
+      compyinc = false;
     }
 
   grid_init(grid);
   cdiGridTypeInit(grid, gridtype, 0);
-  switch (gridtype)
-    {
-    case GRID_LONLAT:
-    case GRID_GAUSSIAN:
+
+  if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN || projtype == CDI_PROJ_RLL )
+    {
+      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;
+      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 ( 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 )
-	      {
-                int recompinc = TRUE;
+        if ( grid->x.size > 1 )
+          {
+            bool recompinc = true;
 
-                if ( ISEC2_LastLon < ISEC2_FirstLon && ISEC2_LastLon < 0 ) ISEC2_LastLon += 360000;
+            if ( ISEC2_LastLon < ISEC2_FirstLon && ISEC2_LastLon < 0 ) ISEC2_LastLon += 360000;
 
-		if ( ISEC2_ResFlag && ISEC2_LonIncr > 0 )
+            if ( ISEC2_ResFlag && ISEC2_LonIncr > 0 )
+              {
+                if ( abs(ISEC2_LastLon - (ISEC2_FirstLon+ISEC2_LonIncr*(grid->x.size-1))) <= 2 )
                   {
-                    if ( abs(ISEC2_LastLon - (ISEC2_FirstLon+ISEC2_LonIncr*(grid->xsize-1))) <= 2 )
-                      {
-                        recompinc = FALSE;
-                        grid->xinc = ISEC2_LonIncr * 0.001;
-                      }
+                    recompinc = false;
+                    grid->x.inc = ISEC2_LonIncr * 0.001;
                   }
+              }
 
-		/* recompute xinc if necessary */
-                if ( recompinc ) grid->xinc = (ISEC2_LastLon - ISEC2_FirstLon) * 0.001 / (grid->xsize-1);
-
-		/* correct xinc if necessary */
-		if ( ISEC2_FirstLon == 0 && ISEC2_LastLon > 354000 && ISEC2_LastLon < 360000 )
-		  {
-		    double xinc = 360. / grid->xsize;
+            /* recompute xinc if necessary */
+            if ( recompinc ) grid->x.inc = (ISEC2_LastLon - ISEC2_FirstLon) * 0.001 / (grid->x.size-1);
 
-		    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 )
-	      {
-                int recompinc = TRUE;
-		if ( ISEC2_ResFlag && ISEC2_LatIncr > 0 )
+            /* 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 )
                   {
-                    if ( abs(ISEC2_LastLat - (ISEC2_FirstLat+ISEC2_LatIncr*(grid->ysize-1))) <= 2 )
-                      {
-                        recompinc = FALSE;
-                        grid->yinc = ISEC2_LatIncr * 0.001;
-                      }
+                    grid->x.inc = xinc;
+                    if ( CDI_Debug ) Message("set xinc to %g", grid->x.inc);
                   }
-
-		/* 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->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;
-
-		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;
+              }
+          }
+        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 ( ISEC2_ResFlag && 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 )
+    {
+      grid->np      = ISEC2_NumPar;
+      grid->size    = ISEC4_NumValues;
+      grid->rowlon  = ISEC2_RowLonPtr;
+      grid->nrowlon = ISEC2_NumLat;
+      grid->y.size  = 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 ( ISEC2_ResFlag && 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 ( ISEC2_ResFlag && 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 ( gridtype == GRID_LCC )
+    {
+      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;
 
-  grid->isRotated = FALSE;
-  if ( cgribexGetIsRotated(isec2) )
+      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->x.flag = 0;
+      grid->y.flag = 0;
+    }
+  else if ( gridtype == GRID_SPECTRAL )
+    {
+      grid->size  = ISEC4_NumValues;
+      grid->trunc = ISEC2_PentaJ;
+      if ( ISEC2_RepMode == 2 )
+        grid->lcomplex = 1;
+      else
+        grid->lcomplex = 0;
+    }
+  else if ( gridtype == GRID_GME )
+    {
+      grid->size  = 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  = 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
@@ -45467,12 +44998,11 @@ void cgribexAddRecord(stream_t * streamptr, int param, int *isec1, int *isec2, d
 {
   int varID;
   int levelID = 0;
-  grid_t *grid = (grid_t *)Malloc(sizeof (*grid));
 
   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 = cgribexGetTsteptype(ISEC1_TimeRange);
   int numavg    = ISEC1_AvgNum;
@@ -45490,11 +45020,30 @@ void cgribexAddRecord(stream_t * streamptr, int param, int *isec1, int *isec2, d
   record->ltype     = ISEC1_LevelType;
   record->tsteptype = (short)tsteptype;
 
-  cgribexGetGrid(streamptr, isec2, fsec2, isec4, grid, iret);
+  grid_t *gridptr = (grid_t*) Malloc(sizeof(*gridptr));
+  cgribexGetGrid(streamptr, isec2, isec4, gridptr, iret);
 
-  struct addIffNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 0);
+  struct addIfNewRes gridAdded = cdiVlistAddGridIfNew(vlistID, gridptr, 0);
   int gridID = gridAdded.Id;
-  if (!gridAdded.isNew) Free(grid);
+  if ( gridAdded.isNew )
+    {
+      if ( gridptr->nrowlon )
+        {
+          size_t nrowlon = (size_t) gridptr->nrowlon;
+          int *rowlon = gridptr->rowlon;
+          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
+    Free(gridptr);
 
   int zaxistype = grib1ltypeToZaxisType(ISEC1_LevelType);
 
@@ -45626,7 +45175,7 @@ compvar_t cgribexVarSet(int param, int level1, int level2, int leveltype, int tr
   compVar.ltype     = leveltype;
   compVar.tsteptype = tsteptype;
 
-  return (compVar);
+  return compVar;
 }
 
 static inline int
@@ -45642,7 +45191,7 @@ cgribexVarCompare(compvar_t compVar, record_t record, int flag)
     |           (compVar.level2 != record.ilevel2)
     |           (compVar.ltype != record.ltype)
     |           tstepDiff;
-  return (rstatus);
+  return rstatus;
 }
 #endif
 
@@ -45699,10 +45248,11 @@ int cgribexScanTimestep1(stream_t * streamptr)
   int nrecs_scanned = 0;
   int datatype;
   long recsize = 0;
-  int warn_time = TRUE;
-  int warn_numavg = TRUE;
+  bool warn_time = true;
+  bool warn_numavg = true;
   int taxisID = -1;
-  int rdate = 0, rtime = 0, tunit = 0, fcast = 0;
+  int rdate = 0, rtime = 0, tunit = 0;
+  bool fcast = false;
   int vlistID;
   int comptype;
   long unzipsize;
@@ -45759,10 +45309,10 @@ int cgribexScanTimestep1(stream_t * streamptr)
       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 )
 	    {
@@ -45816,7 +45366,7 @@ int cgribexScanTimestep1(stream_t * streamptr)
 		if ( datetimeCmp(datetime, datetime0) != 0 )
 		  {
                     gribWarning("Inconsistent verification time!", nrecs_scanned, tsID+1, paramstr, level1, level2);
-		    warn_time = FALSE;
+		    warn_time = false;
 		  }
 	    }
 	  else
@@ -45836,7 +45386,7 @@ int cgribexScanTimestep1(stream_t * streamptr)
 	  if (  taxis->numavg && warn_numavg && (taxis->numavg != ISEC1_AvgNum) )
 	    {
 	      Warning("Changing numavg from %d to %d not supported!", taxis->numavg, ISEC1_AvgNum);
-	      warn_numavg = FALSE;
+	      warn_numavg = false;
 	    }
 	  else
 	    {
@@ -45855,7 +45405,7 @@ int cgribexScanTimestep1(stream_t * streamptr)
 
   streamptr->rtsteps = 1;
 
-  if ( nrecs == 0 ) return (CDI_EUFSTRUCT);
+  if ( nrecs == 0 ) return CDI_EUFSTRUCT;
 
   cdi_generate_vars(streamptr);
 
@@ -45899,7 +45449,7 @@ int cgribexScanTimestep1(stream_t * streamptr)
   cgribexScanTsFixNtsteps(streamptr, recpos);
   cgribexScanTsConstAdjust(streamptr, taxis);
 
-  return (0);
+  return 0;
 }
 
 
@@ -45916,7 +45466,7 @@ int cgribexScanTimestep2(stream_t * streamptr)
   size_t readsize;
   int nrecs, recID;
   long recsize = 0;
-  int warn_numavg = TRUE;
+  bool warn_numavg = true;
   int tsteptype;
   long unzipsize;
   char paramstr[32];
@@ -46037,7 +45587,7 @@ int cgribexScanTimestep2(stream_t * streamptr)
 	  /*
 	      Warning("Changing numavg from %d to %d not supported!", taxis->numavg, ISEC1_AvgNum);
 	  */
-	      warn_numavg = FALSE;
+	      warn_numavg = false;
 	    }
 	  else
 	    {
@@ -46058,7 +45608,7 @@ int cgribexScanTimestep2(stream_t * streamptr)
       if ( recID == nrecords )
 	{
 	  gribWarning("Parameter not defined at timestep 1!", nrecs_scanned, tsID+1, paramstr, level1, level2);
-	  return (CDI_EUFSTRUCT);
+	  return CDI_EUFSTRUCT;
 	}
 
       if ( cdiInventoryMode == 1 )
@@ -46100,7 +45650,7 @@ int cgribexScanTimestep2(stream_t * streamptr)
 		  tsID, recID,
 		  streamptr->tsteps[tsID].records[recID].param, param,
 		  streamptr->tsteps[tsID].records[recID].ilevel, level1);
-	  return (CDI_EUFSTRUCT);
+	  return CDI_EUFSTRUCT;
 	}
 
       streamptr->tsteps[1].records[recID].position = recpos;
@@ -46141,7 +45691,7 @@ int cgribexScanTimestep2(stream_t * streamptr)
   streamptr->record->buffer     = gribbuffer;
   streamptr->record->buffersize = buffersize;
 
-  return (rstatus);
+  return rstatus;
 }
 #endif
 
@@ -46161,7 +45711,7 @@ int cgribexScanTimestep(stream_t * streamptr)
   int level1 = 0, level2 = 0, vdate = 0, vtime = 0;
   DateTime datetime, datetime0 = { LONG_MIN, LONG_MIN };
   int vrecID, recID;
-  int warn_numavg = TRUE;
+  bool warn_numavg = true;
   size_t readsize;
   int taxisID = -1;
   int rindex, nrecs = 0;
@@ -46292,7 +45842,7 @@ int cgribexScanTimestep(stream_t * streamptr)
 	      /*
 	          Warning("Changing numavg from %d to %d not supported!", streamptr->tsteps[tsID].taxis.numavg, ISEC1_AvgNum);
 	      */
-		  warn_numavg = FALSE;
+		  warn_numavg = false;
 		}
 	      else
 		{
@@ -46316,7 +45866,7 @@ int cgribexScanTimestep(stream_t * streamptr)
 	      gribWarning("Parameter not defined at timestep 1!", nrecs_scanned, tsID+1, paramstr, level1, level2);
 
 	      if ( cdiInventoryMode == 1 )
-		return (CDI_EUFSTRUCT);
+		return CDI_EUFSTRUCT;
 	      else
 		continue;
 	    }
@@ -46376,7 +45926,7 @@ int cgribexScanTimestep(stream_t * streamptr)
 	  cdiParamToString(streamptr->tsteps[tsID].records[recID].param, paramstr, sizeof(paramstr));
 	  gribWarning("Paramameter not found!", nrecs_scanned, tsID+1, paramstr,
                       streamptr->tsteps[tsID].records[recID].ilevel, streamptr->tsteps[tsID].records[recID].ilevel2);
-	  return (CDI_EUFSTRUCT);
+	  return CDI_EUFSTRUCT;
 	}
 
       streamptr->rtsteps++;
@@ -46406,7 +45956,7 @@ int cgribexScanTimestep(stream_t * streamptr)
 
   rstatus = (int)streamptr->ntsteps;
 
-  return (rstatus);
+  return rstatus;
 }
 #endif
 
@@ -46631,7 +46181,7 @@ int cgribexDefDateTime(int *isec1, int timeunit, int date, int time)
     default:              factor =  3600; ISEC1_TimeUnit = ISEC1_TABLE4_HOUR;      break;
     }
 
-  return (factor);
+  return factor;
 }
 
 static
@@ -46716,8 +46266,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));
 
@@ -46729,11 +46279,9 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
 
   if ( gridtype == GRID_GENERIC )
     {
-      int xsize, ysize, gridsize;
-
-      gridsize = gridInqSize(gridID);
-      xsize = gridInqXsize(gridID);
-      ysize = gridInqYsize(gridID);
+      int gridsize = gridInqSize(gridID);
+      int xsize = gridInqXsize(gridID);
+      int ysize = gridInqYsize(gridID);
 
       if ( (ysize ==  32 || ysize ==  48 || ysize ==  64 ||
 	    ysize ==  96 || ysize == 160 || ysize == 192 ||
@@ -46757,15 +46305,22 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
     }
   else if ( gridtype == GRID_CURVILINEAR )
     {
+      static bool lwarning = true;
       if ( lwarning && gridInqSize(gridID) > 1 )
 	{
 	  lwarning = false;
-	  Warning("Curvilinear grids are unsupported in GRIB1! Created wrong GDS!");
+	  Warning("Curvilinear grids are unsupported in GRIB1! Created wrong Grid Description Section!");
 	}
       gridtype = GRID_LONLAT;
       lcurvi = true;
     }
 
+  if ( gridtype == GRID_PROJECTION && gridInqProjType(gridID) == CDI_PROJ_RLL )
+    {
+      gridtype = GRID_LONLAT;
+      lrotated = true;
+    }
+
   ISEC2_Reduced  = FALSE;
   ISEC2_ScanFlag = 0;
 
@@ -46776,20 +46331,18 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
     case GRID_GAUSSIAN_REDUCED:
     case GRID_TRAJECTORY:
       {
-	int nlon = 0, nlat;
 	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;
 
-	nlon = gridInqXsize(gridID);
-	nlat = gridInqYsize(gridID);
+	int nlon = gridInqXsize(gridID);
+	int nlat = gridInqYsize(gridID);
 
 	if ( gridtype == GRID_GAUSSIAN_REDUCED )
 	  {
@@ -46799,25 +46352,19 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
 	  }
 	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);
 	      }
 	  }
 
-	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));
 	  }
@@ -46859,14 +46406,16 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
 
         ISEC2_ResFlag = ( ISEC2_LatIncr == 0 || ISEC2_LonIncr == 0 ) ? 0 : 128;
 
-	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;
@@ -46885,7 +46434,7 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
 	int xsize = gridInqXsize(gridID),
           ysize = gridInqYsize(gridID);
 
-	gridInqLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
+	gridInqParamLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
 		   &projflag, &scanflag);
 
 	ISEC2_GridType = GRIB1_GTYPE_LCC;
@@ -46932,10 +46481,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;
@@ -46953,20 +46504,27 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
 }
 
 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)
 {
-  double level;
-  int ilevel, zaxistype, ltype;
+  char units[CDI_MAX_NAME];
   static bool lwarning_vct = true;
+  double level;
 
-  zaxistype = zaxisInqType(zaxisID);
-  ltype = zaxisInqLtype(zaxisID);
+  int zaxistype = zaxisInqType(zaxisID);
+  int ltype = zaxisInqLtype(zaxisID);
 
   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");
@@ -46974,83 +46532,39 @@ void cgribexDefLevel(int *isec1, int *isec2, double *fsec2, int zaxisID, int lev
 
   ISEC2_NumVCP = 0;
 
+  int grib_ltype = zaxisTypeToGrib1ltype(zaxistype);
+
   switch (zaxistype)
     {
     case ZAXIS_SURFACE:
+    case ZAXIS_MEANSEA:
+    case ZAXIS_ALTITUDE:
+    case ZAXIS_DEPTH_BELOW_SEA:
+    case ZAXIS_ISENTROPIC:
       {
-	ISEC1_LevelType = GRIB1_LTYPE_SURFACE;
-	ISEC1_Level1    = (int)(zaxisInqLevel(zaxisID, levelID));
-	ISEC1_Level2    = 0;
+        isec1DefLevel(isec1, grib_ltype, (int) zaxisInqLevel(zaxisID, levelID), 0);
 	break;
       }
     case ZAXIS_CLOUD_BASE:
-      {
-	ISEC1_LevelType = GRIB1_LTYPE_CLOUD_BASE;
-	ISEC1_Level1    = 0;
-	ISEC1_Level2    = 0;
-	break;
-      }
     case ZAXIS_CLOUD_TOP:
-      {
-	ISEC1_LevelType = GRIB1_LTYPE_CLOUD_TOP;
-	ISEC1_Level1    = 0;
-	ISEC1_Level2    = 0;
-	break;
-      }
     case ZAXIS_ISOTHERM_ZERO:
-      {
-	ISEC1_LevelType = GRIB1_LTYPE_ISOTHERM0;
-	ISEC1_Level1    = 0;
-	ISEC1_Level2    = 0;
-	break;
-      }
     case ZAXIS_TOA:
-      {
-	ISEC1_LevelType = GRIB1_LTYPE_TOA;
-	ISEC1_Level1    = 0;
-	ISEC1_Level2    = 0;
-	break;
-      }
     case ZAXIS_SEA_BOTTOM:
-      {
-	ISEC1_LevelType = GRIB1_LTYPE_SEA_BOTTOM;
-	ISEC1_Level1    = 0;
-	ISEC1_Level2    = 0;
-	break;
-      }
     case ZAXIS_ATMOSPHERE:
       {
-	ISEC1_LevelType = GRIB1_LTYPE_ATMOSPHERE;
-	ISEC1_Level1    = 0;
-	ISEC1_Level2    = 0;
-	break;
-      }
-    case ZAXIS_MEANSEA:
-      {
-	ISEC1_LevelType = GRIB1_LTYPE_MEANSEA;
-	ISEC1_Level1    = (int)(zaxisInqLevel(zaxisID, levelID));
-	ISEC1_Level2    = 0;
+        isec1DefLevel(isec1, grib_ltype, 0, 0);
 	break;
       }
     case ZAXIS_HYBRID:
     case ZAXIS_HYBRID_HALF:
       {
-	int vctsize;
-
 	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);
 
-	vctsize = zaxisInqVctSize(zaxisID);
+	int vctsize = zaxisInqVctSize(zaxisID);
 	if ( vctsize > 255 )
 	  {
 	    ISEC2_NumVCP = 0;
@@ -47069,36 +46583,25 @@ void cgribexDefLevel(int *isec1, int *isec2, double *fsec2, int zaxisID, int lev
       }
     case ZAXIS_PRESSURE:
       {
-	double dum;
-	char units[128];
-
 	level = zaxisInqLevel(zaxisID, levelID);
-	if ( level < 0 )
-	  Warning("Pressure level of %f Pa is below zero!", level);
+	if ( level < 0 ) Warning("Pressure level of %f Pa is below zero!", level);
 
 	zaxisInqUnits(zaxisID, units);
 	if ( (units[0] != 'P') | (units[1] != 'a') ) level *= 100;
 
-	ilevel = (int) level;
+	double dum;
 	if ( level < 32768 && (level < 100 || modf(level/100, &dum) > 0) )
-	  {
-	    ISEC1_LevelType = GRIB1_LTYPE_99;
-	    ISEC1_Level1    = ilevel;
-	    ISEC1_Level2    = 0;
-	  }
+          grib_ltype = GRIB1_LTYPE_99;
 	else
-	  {
-	    ISEC1_LevelType = GRIB1_LTYPE_ISOBARIC;
-	    ISEC1_Level1    = ilevel/100;
-	    ISEC1_Level2    = 0;
-	  }
+          level = level/100;
+
+        isec1DefLevel(isec1, grib_ltype, (int) level, 0);
 	break;
       }
     case ZAXIS_HEIGHT:
       {
 	level = zaxisInqLevel(zaxisID, levelID);
 
-	char units[128];
 	zaxisInqUnits(zaxisID, units);
         if ( units[1] == 'm' && !units[2] )
           {
@@ -47107,108 +46610,40 @@ void cgribexDefLevel(int *isec1, int *isec2, double *fsec2, int zaxisID, int lev
             else if ( units[0] == 'k' ) level *= 1000;
           }
 
-	ilevel = (int) level;
-	ISEC1_LevelType = GRIB1_LTYPE_HEIGHT;
-	ISEC1_Level1    = ilevel;
-	ISEC1_Level2    = 0;
-
-	break;
-      }
-    case ZAXIS_ALTITUDE:
-      {
-	level = zaxisInqLevel(zaxisID, levelID);
-
-	ilevel = (int) level;
-	ISEC1_LevelType = GRIB1_LTYPE_ALTITUDE;
-	ISEC1_Level1    = ilevel;
-	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
-	  {
-            level = zaxisInqLevel(zaxisID, levelID);
-
-            ilevel = (int) level;
-            ISEC1_LevelType = GRIB1_LTYPE_SIGMA;
-            ISEC1_Level1    = ilevel;
-            ISEC1_Level2    = 0;
-          }
+          isec1DefLevel(isec1, GRIB1_LTYPE_SIGMA, (int) zaxisInqLevel(zaxisID, levelID), 0);
 
 	break;
       }
     case ZAXIS_DEPTH_BELOW_LAND:
       {
-	char units[128];
-	double factor;
-
 	zaxisInqUnits(zaxisID, units);
 
+	double factor;
         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) )
-	  {
-            double level1, level2;
-            level1 = zaxisInqLbound(zaxisID, levelID);
-            level2 = zaxisInqUbound(zaxisID, levelID);
-	    ISEC1_LevelType = GRIB1_LTYPE_LANDDEPTH_LAYER;
-	    ISEC1_Level1    = (int) (level1*factor);
-	    ISEC1_Level2    = (int) (level2*factor);
-	  }
+          isec1DefLevel(isec1, GRIB1_LTYPE_LANDDEPTH_LAYER, (int) (factor*zaxisInqLbound(zaxisID, levelID)),
+                        (int) (factor*zaxisInqUbound(zaxisID, levelID)));
 	else
-	  {
-	    level = zaxisInqLevel(zaxisID, levelID);
-
-	    ilevel = (int) (level*factor);
-	    ISEC1_LevelType = GRIB1_LTYPE_LANDDEPTH;
-	    ISEC1_Level1    = ilevel;
-	    ISEC1_Level2    = 0;
-	  }
-
-	break;
-      }
-    case ZAXIS_DEPTH_BELOW_SEA:
-      {
-	level = zaxisInqLevel(zaxisID, levelID);
-
-	ilevel = (int) level;
-	ISEC1_LevelType = GRIB1_LTYPE_SEADEPTH;
-	ISEC1_Level1    = ilevel;
-	ISEC1_Level2    = 0;
-
-	break;
-      }
-    case ZAXIS_ISENTROPIC:
-      {
-	level = zaxisInqLevel(zaxisID, levelID);
-
-	ilevel = (int) level;
-	ISEC1_LevelType = GRIB1_LTYPE_ISENTROPIC;
-	ISEC1_Level1    = ilevel;
-	ISEC1_Level2    = 0;
+          isec1DefLevel(isec1, GRIB1_LTYPE_LANDDEPTH, (int) (factor*zaxisInqLevel(zaxisID, levelID)), 0);
 
 	break;
       }
     case ZAXIS_GENERIC:
       {
-	level = zaxisInqLevel(zaxisID, levelID);
-
-	ilevel = (int) level;
-	ISEC1_LevelType = ltype;
-	ISEC1_Level1    = ilevel;
-	ISEC1_Level2    = 0;
-
+        isec1DefLevel(isec1, ltype, (int) zaxisInqLevel(zaxisID, levelID), 0);
 	break;
       }
     default:
@@ -47355,25 +46790,6 @@ size_t cgribexEncode(int memtype, int varID, int levelID, int vlistID, int gridI
  * 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);
-
-#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
 
@@ -47384,11 +46800,9 @@ void streamFCopyRecord(stream_t *streamptr2, stream_t *streamptr1,
 
 
 
-#undef  UNDEFID
-#define UNDEFID  CDI_UNDEFID
+#undef  CDI_UNDEFID
+#define CDI_UNDEFID  CDI_UNDEFID
 
-#define SINGLE_PRECISION  4
-#define DOUBLE_PRECISION  8
 
 #if defined (HAVE_LIBEXTRA)
 
@@ -47404,17 +46818,11 @@ 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) ? DATATYPE_CPX64 : DATATYPE_CPX32;
   else
-    {
-      if ( prec == DOUBLE_PRECISION ) datatype = DATATYPE_FLT64;
-      else                            datatype = DATATYPE_FLT32;
-    }
+    datatype = (prec == EXSE_DOUBLE_PRECISION) ? DATATYPE_FLT64 : DATATYPE_FLT32;
 
-  return (datatype);
+  return datatype;
 }
 
 static
@@ -47425,15 +46833,9 @@ void extDefDatatype(int datatype, int *prec, int *number)
        datatype != DATATYPE_CPX32 && datatype != DATATYPE_CPX64 )
     datatype = DATATYPE_FLT32;
 
-  if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
-    *number = 2;
-  else
-    *number = 1;
+  *number = (datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64) ? 2 : 1;
 
-  if ( datatype == DATATYPE_FLT64 || datatype == DATATYPE_CPX64 )
-    *prec = DOUBLE_PRECISION;
-  else 
-    *prec = SINGLE_PRECISION;
+  *prec = (datatype == DATATYPE_FLT64 || datatype == DATATYPE_CPX64) ? EXSE_DOUBLE_PRECISION : EXSE_SINGLE_PRECISION;
 }
 
 /* not used
@@ -47454,7 +46856,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);
 
@@ -47463,55 +46865,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)
 {
-  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);
+  int size    = gridInqSize(gridID);
 
   streamptr->numvals += size;
 
   *nmiss = 0;
   if ( vlistInqVarNumber(vlistID, varID) == CDI_REAL )
     {
-      for ( i = 0; i < size; i++ )
+      for ( int i = 0; i < size; i++ )
 	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
 	  {
 	    data[i] = missval;
@@ -47520,7 +46913,7 @@ void extReadRecord(stream_t *streamptr, double *data, int *nmiss)
     }
   else
     {
-      for ( i = 0; i < 2*size; i+=2 )
+      for ( int i = 0; i < 2*size; i+=2 )
 	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
 	  {
 	    data[i] = missval;
@@ -47538,21 +46931,18 @@ 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;
+  int gridID = streamptr->record->gridID;
   header[3] = gridInqSize(gridID);
 
+  extrec_t *extp = (extrec_t*) streamptr->record->exsep;
   extDefDatatype(streamptr->record->prec, &extp->prec, &extp->number);
-
   extDefHeader(extp, header);
 }
 
@@ -47583,11 +46973,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);
   /*
@@ -47607,46 +46995,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;
+  int nrecs = 0;
   while ( TRUE )
     {
       recpos = fileGetPos(fileID);
-      status = extRead(fileID, extp);
+      int status = extRead(fileID, extp);
       if ( status != 0 )
 	{
 	  streamptr->ntsteps = 1;
@@ -47656,13 +47034,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 )
 	{
@@ -47698,17 +47076,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;
@@ -47748,43 +47126,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 =
@@ -47793,10 +47161,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;
@@ -47806,13 +47174,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 )
 	{
@@ -47823,7 +47191,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;
@@ -47833,7 +47202,7 @@ int extScanTimestep2(stream_t *streamptr)
 	    {
 	      if ( streamptr->tsteps[tsID].records[recID].used )
 		{
-		  nextstep = TRUE;
+		  nextstep = true;
 		}
 	      else
 		{
@@ -47846,7 +47215,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;
@@ -47865,14 +47234,14 @@ 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 )
 	{
@@ -47898,40 +47267,32 @@ int extScanTimestep2(stream_t *streamptr)
       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;
   /*
@@ -47958,14 +47319,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;
@@ -47975,13 +47336,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;
@@ -48037,131 +47398,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);
-}
-
-
-void extReadVarDP(stream_t *streamptr, int varID, double *data, int *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)++;
-	  }
-    }
+  return nrecs;
 }
 
 
 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;
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d  levID = %d", streamptr->self, varID, levID);
+
   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);
+  int 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);
 
@@ -48170,7 +47454,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 ( int i = 0; i < gridsize; i++ )
 	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
 	  {
 	    data[i] = missval;
@@ -48179,7 +47463,7 @@ void extReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data,
     }
   else
     {
-      for ( i = 0; i < 2*gridsize; i+=2 )
+      for ( int i = 0; i < 2*gridsize; i+=2 )
 	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
 	  {
 	    data[i] = missval;
@@ -48189,126 +47473,59 @@ 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, int *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 = (size_t) 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);
+  header[3] = gridInqSize(vlistInqVarGrid(vlistID, varID));
 
+  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 = (size_t) 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, levID, &data[levID*gridsize]);
 }
 
+#endif /* HAVE_LIBEXTRA */
+
 /*
  * Local Variables:
  * c-file-style: "Java"
@@ -48429,23 +47646,31 @@ int zaxisTypeToGrib1ltype(int zaxistype)
   switch (zaxistype)
     {
     case ZAXIS_SURFACE:               grib_ltype = GRIB1_LTYPE_SURFACE;            break;
-    case ZAXIS_MEANSEA:               grib_ltype = GRIB1_LTYPE_MEANSEA;            break;
+    case ZAXIS_GENERIC:               grib_ltype = -1;                             break;
+    case ZAXIS_HYBRID:                grib_ltype = -1;                             break;
+    case ZAXIS_HYBRID_HALF:           grib_ltype = -1;                             break;
+    case ZAXIS_PRESSURE:              grib_ltype = GRIB1_LTYPE_ISOBARIC;           break;
     case ZAXIS_HEIGHT:                grib_ltype = GRIB1_LTYPE_HEIGHT;             break;
-    case ZAXIS_ALTITUDE:              grib_ltype = GRIB1_LTYPE_ALTITUDE;           break;
-    case ZAXIS_SIGMA:                 grib_ltype = GRIB1_LTYPE_SIGMA;              break;
     case ZAXIS_DEPTH_BELOW_SEA:       grib_ltype = GRIB1_LTYPE_SEADEPTH;           break;
+    case ZAXIS_DEPTH_BELOW_LAND:      grib_ltype = GRIB1_LTYPE_LANDDEPTH;          break;
     case ZAXIS_ISENTROPIC:            grib_ltype = GRIB1_LTYPE_ISENTROPIC;         break;
+    case ZAXIS_TRAJECTORY:            grib_ltype = -1;                             break;
+    case ZAXIS_ALTITUDE:              grib_ltype = GRIB1_LTYPE_ALTITUDE;           break;
+    case ZAXIS_SIGMA:                 grib_ltype = GRIB1_LTYPE_SIGMA;              break;
+    case ZAXIS_MEANSEA:               grib_ltype = GRIB1_LTYPE_MEANSEA;            break;
+    case ZAXIS_TOA:                   grib_ltype = GRIB1_LTYPE_TOA;                break;
+    case ZAXIS_SEA_BOTTOM:            grib_ltype = GRIB1_LTYPE_SEA_BOTTOM;         break;
+    case ZAXIS_ATMOSPHERE:            grib_ltype = GRIB1_LTYPE_ATMOSPHERE;         break;
     case ZAXIS_CLOUD_BASE:            grib_ltype = GRIB1_LTYPE_CLOUD_BASE;         break;
     case ZAXIS_CLOUD_TOP:             grib_ltype = GRIB1_LTYPE_CLOUD_TOP;          break;
     case ZAXIS_ISOTHERM_ZERO:         grib_ltype = GRIB1_LTYPE_ISOTHERM0;          break;
-    case ZAXIS_TOA:                   grib_ltype = GRIB1_LTYPE_TOA;                break;
-    case ZAXIS_SEA_BOTTOM:            grib_ltype = GRIB1_LTYPE_SEA_BOTTOM;         break;
+    case ZAXIS_SNOW:                  grib_ltype = -1;                             break;
     case ZAXIS_LAKE_BOTTOM:           grib_ltype = GRIB1_LTYPE_LAKE_BOTTOM;        break;
     case ZAXIS_SEDIMENT_BOTTOM:       grib_ltype = GRIB1_LTYPE_SEDIMENT_BOTTOM;    break;
     case ZAXIS_SEDIMENT_BOTTOM_TA:    grib_ltype = GRIB1_LTYPE_SEDIMENT_BOTTOM_TA; break;
     case ZAXIS_SEDIMENT_BOTTOM_TW:    grib_ltype = GRIB1_LTYPE_SEDIMENT_BOTTOM_TW; break;
     case ZAXIS_MIX_LAYER:             grib_ltype = GRIB1_LTYPE_MIX_LAYER;          break;
-    case ZAXIS_ATMOSPHERE:            grib_ltype = GRIB1_LTYPE_ATMOSPHERE;         break;
+    case ZAXIS_REFERENCE:             grib_ltype = -1;                             break;
     }
 
   return grib_ltype;
@@ -48459,23 +47684,31 @@ int zaxisTypeToGrib2ltype(int zaxistype)
   switch (zaxistype)
     {
     case ZAXIS_SURFACE:               grib_ltype = GRIB2_LTYPE_SURFACE;            break;
-    case ZAXIS_MEANSEA:               grib_ltype = GRIB2_LTYPE_MEANSEA;            break;
+    case ZAXIS_GENERIC:               grib_ltype = -1;                             break;
+    case ZAXIS_HYBRID:                grib_ltype = GRIB2_LTYPE_HYBRID;             break;
+    case ZAXIS_HYBRID_HALF:           grib_ltype = GRIB2_LTYPE_HYBRID;             break;
+    case ZAXIS_PRESSURE:              grib_ltype = GRIB2_LTYPE_ISOBARIC;           break;
     case ZAXIS_HEIGHT:                grib_ltype = GRIB2_LTYPE_HEIGHT;             break;
-    case ZAXIS_ALTITUDE:              grib_ltype = GRIB2_LTYPE_ALTITUDE;           break;
-    case ZAXIS_SIGMA:                 grib_ltype = GRIB2_LTYPE_SIGMA;              break;
     case ZAXIS_DEPTH_BELOW_SEA:       grib_ltype = GRIB2_LTYPE_SEADEPTH;           break;
+    case ZAXIS_DEPTH_BELOW_LAND:      grib_ltype = GRIB2_LTYPE_LANDDEPTH;          break;
     case ZAXIS_ISENTROPIC:            grib_ltype = GRIB2_LTYPE_ISENTROPIC;         break;
+    case ZAXIS_TRAJECTORY:            grib_ltype = -1;                             break;
+    case ZAXIS_ALTITUDE:              grib_ltype = GRIB2_LTYPE_ALTITUDE;           break;
+    case ZAXIS_SIGMA:                 grib_ltype = GRIB2_LTYPE_SIGMA;              break;
+    case ZAXIS_MEANSEA:               grib_ltype = GRIB2_LTYPE_MEANSEA;            break;
+    case ZAXIS_TOA:                   grib_ltype = GRIB2_LTYPE_TOA;                break;
+    case ZAXIS_SEA_BOTTOM:            grib_ltype = GRIB2_LTYPE_SEA_BOTTOM;         break;
+    case ZAXIS_ATMOSPHERE:            grib_ltype = GRIB2_LTYPE_ATMOSPHERE;         break;
     case ZAXIS_CLOUD_BASE:            grib_ltype = GRIB2_LTYPE_CLOUD_BASE;         break;
     case ZAXIS_CLOUD_TOP:             grib_ltype = GRIB2_LTYPE_CLOUD_TOP;          break;
     case ZAXIS_ISOTHERM_ZERO:         grib_ltype = GRIB2_LTYPE_ISOTHERM0;          break;
-    case ZAXIS_TOA:                   grib_ltype = GRIB2_LTYPE_TOA;                break;
-    case ZAXIS_SEA_BOTTOM:            grib_ltype = GRIB2_LTYPE_SEA_BOTTOM;         break;
+    case ZAXIS_SNOW:                  grib_ltype = GRIB2_LTYPE_SNOW;               break;
     case ZAXIS_LAKE_BOTTOM:           grib_ltype = GRIB2_LTYPE_LAKE_BOTTOM;        break;
     case ZAXIS_SEDIMENT_BOTTOM:       grib_ltype = GRIB2_LTYPE_SEDIMENT_BOTTOM;    break;
     case ZAXIS_SEDIMENT_BOTTOM_TA:    grib_ltype = GRIB2_LTYPE_SEDIMENT_BOTTOM_TA; break;
     case ZAXIS_SEDIMENT_BOTTOM_TW:    grib_ltype = GRIB2_LTYPE_SEDIMENT_BOTTOM_TW; break;
     case ZAXIS_MIX_LAYER:             grib_ltype = GRIB2_LTYPE_MIX_LAYER;          break;
-    case ZAXIS_ATMOSPHERE:            grib_ltype = GRIB2_LTYPE_ATMOSPHERE;         break;
+    case ZAXIS_REFERENCE:             grib_ltype = GRIB2_LTYPE_REFERENCE;          break;
     }
 
   return grib_ltype;
@@ -49020,7 +48253,7 @@ void grib1GetLevel(grib_handle *gh, int *leveltype, int *lbounds, int *level1, i
   *level2    = 0;
 
   long lpar;
-  if(!grib_get_long(gh, "indicatorOfTypeOfLevel", &lpar))       //1 byte
+  if ( !grib_get_long(gh, "indicatorOfTypeOfLevel", &lpar) )       //1 byte
     {
       *leveltype = (int) lpar;
 
@@ -49226,12 +48459,24 @@ 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 =  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);
+    }
 
   int zaxistype = gribapiGetZaxisType(gribEditionNumber(gh), leveltype1);
 
@@ -49449,7 +48694,7 @@ 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)
 {
-  int lieee = FALSE;
+  bool lieee = false;
 
   grib_handle *gh = grib_handle_new_from_message(NULL, *gribbuffer, recsize);
   if(gribEditionNumber(gh) > 1)
@@ -49460,21 +48705,21 @@ 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;
-          else if ( strncmp(typeOfPacking, "grid_ieee", len) == 0 ) lieee = TRUE;
+          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;
+          *outCompressionType = CDI_COMPRESS_SZIP;
           ensureBufferSize((size_t)*outUnzipsize + 100, buffersize, gribbuffer);
         }
       else
         {
-          *outCompressionType = COMPRESS_NONE;
+          *outCompressionType = CDI_COMPRESS_NONE;
         }
     }
 
@@ -50204,11 +49449,11 @@ int gribapiDecode(void *gribbuffer, int gribsize, double *data, long gridsize,
 
   if ( unreduced )
     {
-      static int lwarn = 1;
+      static bool lwarn = true;
 
       if ( lwarn )
 	{
-	  lwarn = 0;
+	  lwarn = false;
 	  Warning("Conversion of gaussian reduced grids unsupported!");
 	}
     }
@@ -50430,7 +49675,7 @@ 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
         {
@@ -50604,17 +49849,18 @@ struct gribApiMsg {
 };
 
 static struct gribApiMsg
-getGribApiCompTypeMsg(grib_handle *gh, int comptype, int gridsize)
+getGribApiCompTypeMsg(int comptype, int 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;
@@ -50626,17 +49872,17 @@ getGribApiCompTypeMsg(grib_handle *gh, int comptype, int gridsize)
       len = sizeof (mesg_simple) - 1;
       mesg = mesg_simple;
     }
+
   return (struct gribApiMsg){ .msgLen = len, .msg = mesg };
 }
 
 
 static
-void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype, int lieee, int datatype, int nmiss, int gcinit)
+void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype, bool lieee, int datatype, int nmiss, int gcinit)
 {
-  int status;
-  static short lwarn = TRUE;
-
   UNUSED(nmiss);
+  bool lrotated = false;
+  bool lcurvi = false;
 
   int gridtype = gridInqType(gridID);
   int gridsize = gridInqSize(gridID);
@@ -50672,12 +49918,20 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
     }
   else if ( gridtype == GRID_CURVILINEAR )
     {
-      if ( lwarn && gridsize > 1 )
+      static bool lwarning = true;
+      if ( lwarning && gridsize > 1 )
 	{
-	  lwarn = FALSE;
-	  Warning("Curvilinear grids are unsupported in GRIB format! Created wrong GDS!");
+	  lwarning = false;
+	  Warning("Curvilinear grids are unsupported in GRIB format! Created wrong Grid Description Section!");
 	}
       gridtype = GRID_LONLAT;
+      lcurvi = true;
+    }
+
+  if ( gridtype == GRID_PROJECTION && gridInqProjType(gridID) == CDI_PROJ_RLL )
+    {
+      gridtype = GRID_LONLAT;
+      lrotated = true;
     }
 
   if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN )
@@ -50686,8 +49940,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);
@@ -50707,98 +49960,89 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
 	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);
 
-	int nlon = gridInqXsize(gridID);
-	int nlat = gridInqYsize(gridID);
+	long nlon = gridInqXsize(gridID);
+	long nlat = gridInqYsize(gridID);
 
 	if ( gridtype == GRID_GAUSSIAN_REDUCED )
 	  {
-	    int *rowlon, i;
-	    long *pl = NULL;
-
 	    nlon = 0;
 
-	    rowlon = (int *) Malloc((size_t)nlat*sizeof(int));
-	    pl     = (long *) Malloc((size_t)nlat*sizeof(long));
+	    int *rowlon = (int *) Malloc((size_t)nlat*sizeof(int));
+	    long *pl    = (long *) Malloc((size_t)nlat*sizeof(long));
 	    gridInqRowlon(gridID, rowlon);
-	    for ( i = 0; i < nlat; ++i ) pl[i] = rowlon[i];
+	    for ( int i = 0; i < nlat; ++i ) pl[i] = rowlon[i];
 
-	    // GRIB_CHECK(my_grib_set_long_array(gh, "pl", pl, nlat), 0);
+            GRIB_CHECK(grib_set_long_array(gh, "pl", pl, nlat), 0);
 
 	    Free(pl);
 	    Free(rowlon);
+
+	    xfirst = 0;
+	    xlast  = 360.-360./(nlat*2);
+	    xinc   = 360./(nlat*2);
 	  }
 	else
 	  {
-	    if ( nlon == 0 )
-	      {
-		nlon = 1;
-	      }
+	    if ( nlon == 0 ) nlon = 1;
 	    else
 	      {
-		xfirst = gridInqXval(gridID,      0);
-		xlast  = gridInqXval(gridID, nlon-1);
+		xfirst = gridInqXval(gridID, 0);
+                xlast  = gridInqXval(gridID, (lcurvi ? nlon*nlat : nlon) - 1);
 		xinc   = gridInqXinc(gridID);
 	      }
 	  }
 
-	if ( nlat == 0 )
-	  {
-	    nlat = 1;
-	  }
+	if ( nlat == 0 ) nlat = 1;
 	else
 	  {
-	    yfirst = gridInqYval(gridID,      0);
-	    ylast  = gridInqYval(gridID, nlat-1);
+	    yfirst = gridInqYval(gridID, 0);
+            ylast  = gridInqYval(gridID, (lcurvi ? nlon*nlat : nlat) - 1);
 	    yinc   = gridInqYinc(gridID);
 	  }
 
-	GRIB_CHECK(my_grib_set_long(gh, "Ni", nlon), 0);
-	GRIB_CHECK(my_grib_set_long(gh, "Nj", nlat), 0);
+	if ( gridtype != GRID_GAUSSIAN_REDUCED ) GRIB_CHECK(my_grib_set_long(gh, "Ni", nlon), 0);
 	GRIB_CHECK(my_grib_set_double(gh, "longitudeOfFirstGridPointInDegrees", xfirst), 0);
 	GRIB_CHECK(my_grib_set_double(gh, "longitudeOfLastGridPointInDegrees",  xlast), 0);
+	GRIB_CHECK(my_grib_set_double(gh, "iDirectionIncrementInDegrees", xinc), 0);
+
+	GRIB_CHECK(my_grib_set_long(gh, "Nj", nlat), 0);
 	GRIB_CHECK(my_grib_set_double(gh, "latitudeOfFirstGridPointInDegrees",  yfirst), 0);
 	GRIB_CHECK(my_grib_set_double(gh, "latitudeOfLastGridPointInDegrees",   ylast), 0);
-	GRIB_CHECK(my_grib_set_double(gh, "iDirectionIncrementInDegrees", xinc), 0);
 
         {
           long jscan = 0;
           if ( yfirst < ylast ) jscan = 1;
           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);
@@ -50810,67 +50054,38 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
 	    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;
-	    */
 	  }
-	/*
-	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;
-
-	/* South -> North */
-	//if ( ISEC2_LastLat > ISEC2_FirstLat ) ISEC2_ScanFlag += 64;
+            double xpole = 0, ypole = 0, angle = 0;
+            gridInqParamRLL(gridID, &xpole, &ypole, &angle);
 
-        if ( editionNumber != 2 ) { lieee = 0; comptype = 0; }
+            xpole =  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);
+          }
 
-        {
-          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 ( editionNumber != 2 ) { lieee = false; comptype = 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 == DATATYPE_FLT64 ? 2 : 1), 0);
 
 	break;
       }
@@ -50882,8 +50097,8 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
 	int xsize = gridInqXsize(gridID);
 	int ysize = gridInqYsize(gridID);
 
-	gridInqLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
-		   &projflag, &scanflag);
+	gridInqParamLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
+                        &projflag, &scanflag);
 
         static const char mesg[] = "lambert";
         size_t len = sizeof (mesg) -1;
@@ -50912,12 +50127,11 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
       }
     case GRID_SPECTRAL:
       {
-	int trunc = gridInqTrunc(gridID);
-
         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);
@@ -50956,17 +50170,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);
 
-        if ( comptype == COMPRESS_SZIP )
+        if ( comptype == CDI_COMPRESS_SZIP )
           {
             static const char mesg[] = "grid_ccsds";
             size_t len = sizeof (mesg) -1;
@@ -50977,12 +50193,12 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
       }
     case GRID_UNSTRUCTURED:
       {
-	static int warning = 1;
+	static bool warning = true;
 
-	status = my_grib_set_long(gh, "gridDefinitionTemplateNumber", GRIB2_GTYPE_UNSTRUCTURED);
+	int status = my_grib_set_long(gh, "gridDefinitionTemplateNumber", GRIB2_GTYPE_UNSTRUCTURED);
 	if ( status != 0 && warning )
 	  {
-	    warning = 0;
+	    warning = false;
 	    Warning("Can't write reference grid!");
 	    Warning("gridDefinitionTemplateNumber %d not found (grib2/template.3.%d.def)!",
 		    GRIB2_GTYPE_UNSTRUCTURED, GRIB2_GTYPE_UNSTRUCTURED);
@@ -51002,7 +50218,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;
@@ -51042,20 +50258,40 @@ void getLevelFactor(double level, long *factor, long *out_scaled_value)
 static
 void gribapiDefLevelType(grib_handle *gh, int gcinit, const char *keyname, long leveltype)
 {
-  if ( !gcinit ) GRIB_CHECK(my_grib_set_long(gh, keyname, leveltype), 0);
+  bool lset = false;
+  if ( (leveltype == 99 || leveltype == 100) && gribEditionNumber(gh) == 1 )
+    {
+      if ( gribGetLong(gh, "indicatorOfTypeOfLevel") != leveltype ) lset = true;
+    }
+
+  if ( !gcinit || lset ) GRIB_CHECK(my_grib_set_long(gh, keyname, leveltype), 0);
 }
 
 static
-void grib2DefLevel(grib_handle *gh, int gcinit, long leveltype1, long leveltype2, int lbounds, double level, double dlevel1, double dlevel2)
+void grib1DefLevel(grib_handle *gh, int gcinit, long leveltype, bool lbounds, double level, double dlevel1, double dlevel2)
 {
-  long scaled_level;
-  long factor;
+  gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", leveltype);
+
+  if ( lbounds )
+    {
+      GRIB_CHECK(my_grib_set_long(gh, "topLevel", lround(dlevel1)), 0);
+      GRIB_CHECK(my_grib_set_long(gh, "bottomLevel", lround(dlevel2)), 0);
+    }
+  else
+    {
+      GRIB_CHECK(my_grib_set_long(gh, "level", lround(level)), 0);
+    }
+}
 
+static
+void grib2DefLevel(grib_handle *gh, int gcinit, long leveltype1, long leveltype2, bool lbounds, double level, double dlevel1, double dlevel2)
+{
   gribapiDefLevelType(gh, gcinit, "typeOfFirstFixedSurface", leveltype1);
   if ( lbounds ) gribapiDefLevelType(gh, gcinit, "typeOfSecondFixedSurface", leveltype2);
 
   if ( !lbounds ) dlevel1 = level;
 
+  long scaled_level, factor;
   getLevelFactor(dlevel1, &factor, &scaled_level);
   GRIB_CHECK(my_grib_set_long(gh, "scaleFactorOfFirstFixedSurface", factor), 0);
   GRIB_CHECK(my_grib_set_long(gh, "scaledValueOfFirstFixedSurface", scaled_level), 0);
@@ -51068,20 +50304,39 @@ 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)
 {
-  int lbounds = 0;
+  char units[CDI_MAX_NAME];
+  bool lbounds = false;
   double dlevel1 = 0, dlevel2 = 0;
 
   int zaxistype = zaxisInqType(zaxisID);
-  int ltype = zaxisInqLtype(zaxisID);
-  int ltype2 = zaxisInqLtype2(zaxisID);
+  long ltype = zaxisInqLtype(zaxisID);
+  long ltype2 = zaxisInqLtype2(zaxisID);
   double level = zaxisInqLevel(zaxisID, levelID);
 
   if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
     {
-      lbounds = 1;
+      lbounds = true;
       dlevel1 = zaxisInqLbound(zaxisID, levelID);
       dlevel2 = zaxisInqUbound(zaxisID, levelID);
     }
@@ -51099,7 +50354,11 @@ void gribapiDefLevel(int editionNumber, grib_handle *gh, int param, int zaxisID,
       zaxisDefUnits(zaxisID, "Pa");
     }
 
-  int grib2ltype = zaxisTypeToGrib2ltype(zaxistype);
+  long grib_ltype = -1;
+  if ( editionNumber <= 1 )
+    grib_ltype = zaxisTypeToGrib1ltype(zaxistype);
+  else
+    grib_ltype = zaxisTypeToGrib2ltype(zaxistype);
 
   switch (zaxistype)
     {
@@ -51114,7 +50373,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] )
               {
@@ -51132,8 +50390,7 @@ void gribapiDefLevel(int editionNumber, grib_handle *gh, int param, int zaxisID,
 
         if ( editionNumber <= 1 )
           {
-            gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", zaxisTypeToGrib1ltype(zaxistype));
-            GRIB_CHECK(my_grib_set_long(gh, "level", (long)level), 0);
+            grib1DefLevel(gh, gcinit, grib_ltype, lbounds, level, dlevel1, dlevel2);
           }
         else
           {
@@ -51145,7 +50402,7 @@ void gribapiDefLevel(int editionNumber, grib_handle *gh, int param, int zaxisID,
                The key/value pairs that are set in "grib2DefLevel" do not exist for this template.
             */
             if ( proddef_template_num != 32 )
-              grib2DefLevel(gh, gcinit, grib2ltype, grib2ltype, lbounds, level, dlevel1, dlevel2);
+              grib2DefLevel(gh, gcinit, grib_ltype, grib_ltype, lbounds, level, dlevel1, dlevel2);
           }
 
 	break;
@@ -51163,22 +50420,9 @@ void gribapiDefLevel(int editionNumber, grib_handle *gh, int param, int zaxisID,
     case ZAXIS_ATMOSPHERE:
       {
         if ( editionNumber <= 1 )
-          {
-            gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", zaxisTypeToGrib1ltype(zaxistype));
-            if ( lbounds )
-              {
-                GRIB_CHECK(my_grib_set_long(gh, "topLevel", (long) dlevel1), 0);
-                GRIB_CHECK(my_grib_set_long(gh, "bottomLevel", (long) dlevel2), 0);
-              }
-            else
-              {
-                GRIB_CHECK(my_grib_set_long(gh, "level", (long) level), 0);
-              }
-          }
+          grib1DefLevel(gh, gcinit, grib_ltype, lbounds, level, dlevel1, dlevel2);
         else
-          {
-            grib2DefLevel(gh, gcinit, grib2ltype, grib2ltype, lbounds, level, dlevel1, dlevel2);
-          }
+          grib2DefLevel(gh, gcinit, grib_ltype, grib_ltype, lbounds, level, dlevel1, dlevel2);
 
         break;
       }
@@ -51187,21 +50431,12 @@ void gribapiDefLevel(int editionNumber, grib_handle *gh, int param, int zaxisID,
       {
         if ( editionNumber <= 1 )
           {
-            if ( lbounds )
-              {
-                gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", GRIB1_LTYPE_HYBRID_LAYER);
-                GRIB_CHECK(my_grib_set_long(gh, "topLevel", (long) dlevel1), 0);
-                GRIB_CHECK(my_grib_set_long(gh, "bottomLevel", (long) dlevel2), 0);
-              }
-            else
-              {
-                gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", GRIB1_LTYPE_HYBRID);
-                GRIB_CHECK(my_grib_set_long(gh, "level", (long) level), 0);
-              }
+            grib_ltype = lbounds ? GRIB1_LTYPE_HYBRID_LAYER : GRIB1_LTYPE_HYBRID;
+            grib1DefLevel(gh, gcinit, grib_ltype, lbounds, level, dlevel1, dlevel2);
           }
         else
           {
-            grib2DefLevel(gh, gcinit, GRIB2_LTYPE_HYBRID, GRIB2_LTYPE_HYBRID, lbounds, level, dlevel1, dlevel2);
+            grib2DefLevel(gh, gcinit, grib_ltype, grib_ltype, lbounds, level, dlevel1, dlevel2);
           }
 
         if ( !gcinit )
@@ -51218,9 +50453,6 @@ void gribapiDefLevel(int editionNumber, grib_handle *gh, int param, int zaxisID,
       }
     case ZAXIS_PRESSURE:
       {
-	double dum;
-	char units[128];
-
 	if ( level < 0 ) Warning("Pressure level of %f Pa is below zero!", level);
 
 	zaxisInqUnits(zaxisID, units);
@@ -51233,15 +50465,13 @@ void gribapiDefLevel(int editionNumber, grib_handle *gh, int param, int zaxisID,
 
         if ( editionNumber <= 1 )
           {
-            long leveltype = GRIB1_LTYPE_ISOBARIC;
-
+            double dum;
             if ( level < 32768 && (level < 100 || modf(level/100, &dum) > 0) )
-              leveltype = GRIB1_LTYPE_99;
+              grib_ltype = GRIB1_LTYPE_99;
             else
               level /= 100;
 
-            gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", leveltype);
-            GRIB_CHECK(my_grib_set_double(gh, "level", level), 0);
+            grib1DefLevel(gh, gcinit, grib_ltype, lbounds, level, dlevel1, dlevel2);
 	  }
 	else
 	  {
@@ -51257,95 +50487,65 @@ void gribapiDefLevel(int editionNumber, grib_handle *gh, int param, int zaxisID,
           ; // not available
 	else
           {
-            grib2DefLevel(gh, gcinit, GRIB2_LTYPE_SNOW, GRIB2_LTYPE_SNOW, lbounds, level, dlevel1, dlevel2);
+            grib2DefLevel(gh, gcinit, grib_ltype, grib_ltype, lbounds, level, dlevel1, dlevel2);
           }
 
 	break;
       }
     case ZAXIS_DEPTH_BELOW_LAND:
       {
-	char units[128];
-
 	zaxisInqUnits(zaxisID, units);
+        double sf; //scalefactor
 
 	if ( editionNumber <= 1 )
 	  {
-            double scalefactor;
-	    if      ( memcmp(units, "mm", 2) == 0 ) scalefactor =   0.1;
-	    else if ( memcmp(units, "cm", 2) == 0 ) scalefactor =   1; // cm
-	    else if ( memcmp(units, "dm", 2) == 0 ) scalefactor =  10;
-	    else                                    scalefactor = 100;
-
-	    gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", GRIB1_LTYPE_LANDDEPTH);
-	    GRIB_CHECK(my_grib_set_double(gh, "level", level*scalefactor), 0);
+	    if      ( memcmp(units, "mm", 2) == 0 ) sf =   0.1;
+	    else if ( memcmp(units, "cm", 2) == 0 ) sf =   1; // cm
+	    else if ( memcmp(units, "dm", 2) == 0 ) sf =  10;
+	    else                                    sf = 100;
+
+            grib1DefLevel(gh, gcinit, grib_ltype, lbounds, level*sf, dlevel1*sf, dlevel2*sf);
 	  }
 	else
 	  {
-            double scalefactor;
-	    if      ( memcmp(units, "mm", 2) == 0 ) scalefactor = 0.001;
-	    else if ( memcmp(units, "cm", 2) == 0 ) scalefactor = 0.01;
-	    else if ( memcmp(units, "dm", 2) == 0 ) scalefactor = 0.1;
-	    else                                    scalefactor = 1; // meter
+	    if      ( memcmp(units, "mm", 2) == 0 ) sf = 0.001;
+	    else if ( memcmp(units, "cm", 2) == 0 ) sf = 0.01;
+	    else if ( memcmp(units, "dm", 2) == 0 ) sf = 0.1;
+	    else                                    sf = 1; // meter
 
-            level   *= scalefactor;
-            dlevel1 *= scalefactor;
-            dlevel2 *= scalefactor;
-
-            grib2DefLevel(gh, gcinit, GRIB2_LTYPE_LANDDEPTH, GRIB2_LTYPE_LANDDEPTH, lbounds, level, dlevel1, dlevel2);
+            grib2DefLevel(gh, gcinit, grib_ltype, grib_ltype, lbounds, level*sf, dlevel1*sf, dlevel2*sf);
 	  }
 
 	break;
       }
     case ZAXIS_REFERENCE:
       {
-        unsigned char uuid[CDI_UUID_SIZE];
-
-        if ( !gcinit )
-          {
-            GRIB_CHECK(my_grib_set_long(gh, "genVertHeightCoords", 1), 0);
-          }
+        if ( !gcinit ) GRIB_CHECK(my_grib_set_long(gh, "genVertHeightCoords", 1), 0);
 
-        if ( lbounds )
+        if ( editionNumber <= 1 )
+          ; // not available
+        else
           {
-            if ( editionNumber <= 1 )
-              ; // not available
-            else
+            if ( lbounds )
               {
-                int number = zaxisInqNumber(zaxisID);
-                gribapiDefLevelType(gh, gcinit, "typeOfFirstFixedSurface", GRIB2_LTYPE_REFERENCE);
-                gribapiDefLevelType(gh, gcinit, "typeOfSecondFixedSurface", GRIB2_LTYPE_REFERENCE);
-                GRIB_CHECK(my_grib_set_long(gh, "NV", 6), 0);
-                GRIB_CHECK(my_grib_set_long(gh, "nlev", zaxisInqNlevRef(zaxisID)), 0);
-                GRIB_CHECK(my_grib_set_long(gh, "numberOfVGridUsed", number), 0);
-                size_t len = CDI_UUID_SIZE;
-                zaxisInqUUID(zaxisID, uuid);
-                if (grib_set_bytes(gh, "uuidOfVGrid", uuid, &len) != 0)
-                  {
-                    Warning("Can't write UUID!");
-                  }
+                gribapiDefLevelType(gh, gcinit, "typeOfFirstFixedSurface", grib_ltype);
+                gribapiDefLevelType(gh, gcinit, "typeOfSecondFixedSurface", grib_ltype);
                 GRIB_CHECK(my_grib_set_long(gh, "topLevel", (long) dlevel1), 0);
                 GRIB_CHECK(my_grib_set_long(gh, "bottomLevel", (long) dlevel2), 0);
               }
-          }
-        else
-          {
-            if ( editionNumber <= 1 )
-              ; // not available
             else
               {
-                int number = zaxisInqNumber(zaxisID);
-                gribapiDefLevelType(gh, gcinit, "typeOfFirstFixedSurface", GRIB2_LTYPE_REFERENCE);
-                GRIB_CHECK(my_grib_set_long(gh, "NV", 6), 0);
-                GRIB_CHECK(my_grib_set_long(gh, "nlev", zaxisInqNlevRef(zaxisID)), 0);
-                GRIB_CHECK(my_grib_set_long(gh, "numberOfVGridUsed", number), 0);
-                size_t len = CDI_UUID_SIZE;
-                zaxisInqUUID(zaxisID, uuid);
-                if (grib_set_bytes(gh, "uuidOfVGrid", uuid, &len) != 0)
-                  {
-                    Warning("Can't write UUID!");
-                  }
-                GRIB_CHECK(my_grib_set_double(gh, "level", level), 0);
+                grib2DefLevel(gh, gcinit, GRIB2_LTYPE_REFERENCE, GRIB2_LTYPE_REFERENCE, lbounds, level, dlevel1, dlevel2);
               }
+
+            int number = zaxisInqNumber(zaxisID);
+            unsigned char uuid[CDI_UUID_SIZE];
+            GRIB_CHECK(my_grib_set_long(gh, "NV", 6), 0);
+            GRIB_CHECK(my_grib_set_long(gh, "nlev", zaxisInqNlevRef(zaxisID)), 0);
+            GRIB_CHECK(my_grib_set_long(gh, "numberOfVGridUsed", number), 0);
+            size_t len = CDI_UUID_SIZE;
+            zaxisInqUUID(zaxisID, uuid);
+            if ( grib_set_bytes(gh, "uuidOfVGrid", uuid, &len) != 0 ) Warning("Can't write UUID!");
           }
 
         break;
@@ -51353,11 +50553,13 @@ void gribapiDefLevel(int editionNumber, grib_handle *gh, int param, int zaxisID,
     case ZAXIS_GENERIC:
       {
 	if ( editionNumber <= 1 )
-          gribapiDefLevelType(gh, gcinit, "indicatorOfTypeOfLevel", ltype);
+          {
+            grib1DefLevel(gh, gcinit, ltype, lbounds, level, dlevel1, dlevel2);
+          }
         else
-          gribapiDefLevelType(gh, gcinit, "typeOfFirstFixedSurface", ltype);
-
-	GRIB_CHECK(my_grib_set_double(gh, "level", level), 0);
+          {
+            grib2DefLevel(gh, gcinit, ltype, ltype, lbounds, level, dlevel1, dlevel2);
+          }
 
 	break;
       }
@@ -51378,7 +50580,7 @@ size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisI
 {
   size_t recsize = 0;
   void *dummy = NULL;
-  int lieee = FALSE;
+  bool lieee = false;
   /*  int ensID, ensCount, forecast_type; *//* Ensemble Data */
   int typeOfGeneratingProcess;
   int productDefinitionTemplate;
@@ -51386,7 +50588,7 @@ 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[];
 
   int param    = vlistInqVarParam(vlistID, varID);
@@ -51400,8 +50602,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 )
@@ -51426,10 +50631,10 @@ size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisI
 
   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 == DATATYPE_FLT32 || datatype == DATATYPE_FLT64) ) lieee = true;
 
   /* bitsPerValue have to be defined before call to DefGrid (complex packing) */
-  //  if ( lieee == FALSE )
+  //  if ( lieee == false )
     {
       bitsPerValue = grbBitsPerValue(datatype);
       GRIB_CHECK(my_grib_set_long(gh, "bitsPerValue", bitsPerValue), 0);
@@ -51437,7 +50642,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)
@@ -51610,11 +50815,9 @@ void streamInqHistoryString(int streamID, char *history)
 
 
 
-#undef  UNDEFID
-#define UNDEFID  CDI_UNDEFID
+#undef  CDI_UNDEFID
+#define CDI_UNDEFID  CDI_UNDEFID
 
-#define SINGLE_PRECISION  4
-#define DOUBLE_PRECISION  8
 
 #if defined (HAVE_LIBIEG)
 
@@ -51622,34 +50825,25 @@ void streamInqHistoryString(int streamID, char *history)
 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) ? DATATYPE_FLT64 : DATATYPE_FLT32;
 }
 
-
-static int iegDefDatatype(int datatype)
+static
+int iegDefDatatype(int datatype)
 {
-  int prec;
-
   if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
     Error("CDI/IEG library does not support complex numbers!");
 
   if ( datatype != DATATYPE_FLT32 && datatype != DATATYPE_FLT64 )
     datatype = DATATYPE_FLT32;
 
-  if ( datatype == DATATYPE_FLT64 ) prec = DOUBLE_PRECISION;
-  else                              prec = SINGLE_PRECISION;
-
-  return (prec);
+  return (datatype == DATATYPE_FLT64) ? EXSE_DOUBLE_PRECISION : EXSE_SINGLE_PRECISION;
 }
 
 /* not used
@@ -51669,7 +50863,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 )
@@ -51679,51 +50873,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)
 {
-  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);
+  int size    = gridInqSize(gridID);
 
   streamptr->numvals += size;
 
   *nmiss = 0;
-  for ( i = 0; i < size; i++ )
+  for ( int i = 0; i < size; i++ )
     if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
       {
 	data[i] = missval;
@@ -51783,19 +50969,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);
 
@@ -51846,21 +51031,25 @@ 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);
+  int xsize = gridInqXsize(gridID);
+  int ysize = gridInqYsize(gridID);
 
+  if ( gridtype == GRID_GENERIC )
+    {
       if ( (ysize == 32  || ysize == 48 || ysize == 64 ||
 	    ysize == 96  || ysize == 160) &&
 	   (xsize == 2*ysize || xsize == 1) )
@@ -51884,39 +51073,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;
@@ -51927,8 +51109,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)   = xsize;
+      IEG_G_NumLat(gdb)   = 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);
@@ -51938,7 +51120,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) = ysize/2;
       else
 	{
 	  IEG_G_LatIncr(gdb) = (int)lround(yinc*resfac);
@@ -51954,15 +51136,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
@@ -51979,19 +51161,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");
@@ -52003,36 +51191,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
@@ -52046,11 +51224,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 )
@@ -52058,81 +51235,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:
@@ -52152,68 +51291,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;
-
-  fileID = streamptr->fileID;
-  gridID = streamptr->record->gridID;
+  Record *record = streamptr->record;
+  iegrec_t *iegp = (iegrec_t*) record->exsep;
 
-  gridsize = gridInqSize(gridID);
+  int fileID = streamptr->fileID;
+  int gridsize = gridInqSize(record->gridID);
 
-  refval = data[0];
-  for ( i = 1; i < gridsize; i++ )
+  double refval = data[0];
+  for ( int i = 1; i < gridsize; i++ )
     if ( data[i] < refval ) refval = data[i];
 
   iegp->refval = refval;
 
   iegDefDataDP(iegp, data);
-
   iegWrite(fileID, iegp);
 }
 
@@ -52221,7 +51347,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);
@@ -52247,18 +51372,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;
+  int xsize = IEG_G_NumLon(gdb);
+  int ysize = 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;
@@ -52266,78 +51393,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);
     }
@@ -52347,6 +51461,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);
@@ -52358,8 +51473,7 @@ 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
@@ -52369,9 +51483,8 @@ void iegCmpRecord(stream_t *streamptr, int tsID, int recID, off_t position, int
 {
   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");
@@ -52391,17 +51504,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);
-
-  rmonth  = IEG_P_Month(pdb);
-  rday    = IEG_P_Day(pdb);
+  int ryear   = IEG_P_Year(pdb);
+  int rmonth  = IEG_P_Month(pdb);
+  int 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;
 
@@ -52412,51 +51523,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;
+  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
@@ -52464,6 +51563,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 )
@@ -52475,12 +51575,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};
@@ -52500,17 +51601,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;
@@ -52521,7 +51622,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 )
@@ -52539,7 +51640,7 @@ void iegScanTimestep1(stream_t *streamptr)
       if ( taxis->vdate == 0 && taxis->vtime == 0 )
 	{
 	  streamptr->ntsteps = 0;
-	  for ( varID = 0; varID < streamptr->nvars; varID++ )
+	  for ( int varID = 0; varID < streamptr->nvars; varID++ )
 	    {
 	      vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
 	    }
@@ -52550,67 +51651,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
@@ -52618,6 +51707,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 )
@@ -52629,17 +51719,18 @@ 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
 		{
@@ -52654,7 +51745,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;
@@ -52667,24 +51758,24 @@ 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;
+	  int varID = streamptr->tsteps[tsID].records[recID].varID;
           vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
 	}
       else
@@ -52706,43 +51797,31 @@ int iegScanTimestep2(stream_t *streamptr)
       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 )
@@ -52756,9 +51835,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);
@@ -52768,28 +51848,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
@@ -52797,11 +51878,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 )
 	    {
@@ -52815,7 +51897,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,
@@ -52835,7 +51917,7 @@ long iegScanTimestep(stream_t *streamptr)
 
       if ( streamptr->ntsteps != streamptr->rtsteps )
 	{
-	  tsID = tstepsNewEntry(streamptr);
+	  int tsID = tstepsNewEntry(streamptr);
 	  if ( tsID != streamptr->rtsteps )
 	    Error("Internal error. tsID = %d", tsID);
 
@@ -52853,113 +51935,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);
-}
-
-
-void iegReadVarDP(stream_t *streamptr, int varID, double *data, int *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)++;
-      }
+  return nrecs;
 }
 
 
 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;
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d  levID = %d", streamptr->self, varID, levID);
+
   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);
+  int 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);
@@ -52967,7 +51987,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 ( int i = 0; i < gridsize; i++ )
     if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
       {
 	data[i] = missval;
@@ -52976,101 +51996,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, int *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 = (size_t) 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);
 
-  param    = vlistInqVarParam(vlistID, varID);
+  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);
+
+  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);
+  int 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 ( int 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 = (size_t) 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 */
@@ -53161,18 +52150,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;
 }
 
 
@@ -53245,14 +52235,15 @@ 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)
     {
@@ -53370,7 +52361,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;
@@ -53414,10 +52404,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;
@@ -53448,6 +52436,32 @@ void cdi_create_records(stream_t *streamptr, int tsID)
 	}
     }
 }
+
+
+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"
@@ -53468,11 +52482,9 @@ void cdi_create_records(stream_t *streamptr, int tsID)
 
 
 
-#undef  UNDEFID
-#define UNDEFID  CDI_UNDEFID
+#undef  CDI_UNDEFID
+#define CDI_UNDEFID  CDI_UNDEFID
 
-#define SINGLE_PRECISION  4
-#define DOUBLE_PRECISION  8
 
 #if defined (HAVE_LIBSERVICE)
 
@@ -53480,34 +52492,25 @@ void cdi_create_records(stream_t *streamptr, int tsID)
 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) ? DATATYPE_FLT64 : DATATYPE_FLT32;
 }
 
-
-static int srvDefDatatype(int datatype)
+static
+int srvDefDatatype(int datatype)
 {
-  int prec;
-
   if ( datatype == DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
     Error("CDI/SERVICE library does not support complex numbers!");
 
   if ( datatype != DATATYPE_FLT32 && datatype != DATATYPE_FLT64 )
     datatype = DATATYPE_FLT32;
 
-  if ( datatype == DATATYPE_FLT64 ) prec = DOUBLE_PRECISION;
-  else                              prec = SINGLE_PRECISION;
-
-  return (prec);
+  return (datatype == DATATYPE_FLT64) ? EXSE_DOUBLE_PRECISION : EXSE_SINGLE_PRECISION;
 }
 
 /* not used
@@ -53537,25 +52540,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)
 {
-  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;
@@ -53566,21 +52562,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);
+  int size    = gridInqSize(gridID);
 
   streamptr->numvals += size;
 
   *nmiss = 0;
-  for ( i = 0; i < size; i++ )
+  for ( int i = 0; i < size; i++ )
     if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
       {
 	data[i] = missval;
@@ -53597,20 +52595,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 gridID = record->gridID;
   int xsize = gridInqXsize(gridID),
-    ysize = gridInqYsize(gridID);
+      ysize = gridInqYsize(gridID);
   if ( xsize == 0 || ysize == 0 )
     {
       xsize = gridInqSize(gridID);
@@ -53626,7 +52625,6 @@ void srvDefRecord(stream_t *streamptr)
   header[7] = 0;
 
   int datatype = record->prec;
-
   srvp->dprec = srvDefDatatype(datatype);
 
   srvDefHeader(srvp, header);
@@ -53656,14 +52654,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);
   /*
@@ -53688,8 +52684,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
@@ -53709,7 +52704,6 @@ void srvScanTimestep1(stream_t *streamptr)
     taxis = &streamptr->tsteps[tsID].taxis;
   }
 
-
   int fileID = streamptr->fileID;
 
   int nrecs = 0;
@@ -53815,54 +52809,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;
@@ -53872,12 +52855,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 )
 	{
@@ -53888,17 +52871,18 @@ 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
 		{
@@ -53911,7 +52895,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;
@@ -53924,24 +52908,24 @@ 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;
+	  int varID = streamptr->tsteps[tsID].records[recID].varID;
           vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
 	}
       else
@@ -53963,40 +52947,33 @@ int srvScanTimestep2(stream_t *streamptr)
       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 )
@@ -54022,14 +52999,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;
@@ -54039,14 +53016,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;
@@ -54098,128 +53075,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);
-}
-
-
-void srvReadVarDP(stream_t *streamptr, int varID, double *data, int *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;
-
-  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)++;
-      }
+  return nrecs;
 }
 
 
 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;
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d  levID = %d", streamptr->self, varID, levID);
+
   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);
+  int 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 ( int i = 0; i < gridsize; i++ )
     if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
       {
 	data[i] = missval;
@@ -54228,105 +53138,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, int *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 = (size_t) 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);
+  int xsize = gridInqXsize(gridID);
+  int ysize = gridInqYsize(gridID);
   if ( xsize == 0 || ysize == 0 )
     {
       xsize = gridInqSize(gridID);
@@ -54341,8 +53185,9 @@ void srvWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double
   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);
@@ -54350,7 +53195,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 = (size_t) 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"
@@ -54363,8 +53222,6 @@ void srvWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double
 #if defined (HAVE_CONFIG_H)
 #endif
 
-#include <string.h>
-
 
 
 
@@ -54380,7 +53237,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;
@@ -54395,30 +53252,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
     {
@@ -54433,11 +53284,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 )
 	{
@@ -54446,8 +53294,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;
@@ -54455,8 +53303,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;
 }
 
 
@@ -54466,7 +53315,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;
@@ -54511,7 +53360,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:
@@ -54566,7 +53415,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
     {
@@ -54634,7 +53483,7 @@ void grbCopyRecord(stream_t * streamptr2, stream_t * streamptr1)
       long unzipsize;
       int izip = gribGetZip((long)recsize, gribbuffer, &unzipsize);
 
-      if ( izip == 0 && streamptr2->comptype == COMPRESS_SZIP )
+      if ( izip == 0 && streamptr2->comptype == CDI_COMPRESS_SZIP )
           nbytes = grbSzip(filetype, gribbuffer, nbytes);
     }
 
@@ -54691,9 +53540,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 == FILETYPE_GRB && comptype == CDI_COMPRESS_JPEG )
     {
       static int ljpeg_warn = 1;
       if ( ljpeg_warn ) Warning("JPEG compression of GRIB1 records not available!");
@@ -54703,11 +53552,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 == 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);
@@ -54759,7 +53607,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, int nmiss)
 {
   int varID   = streamptr->record->varID;
   int levelID = streamptr->record->levelID;
@@ -54767,6 +53615,7 @@ void grb_write_record(stream_t * streamptr, int memtype, const void *data, int n
   grb_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
 }
 
+
 #endif
 #ifdef HAVE_CONFIG_H
 #endif
@@ -54806,7 +53655,7 @@ int grbDecode(int filetype, int memtype, void *gribbuffer, int gribsize, void *d
           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
@@ -54840,7 +53689,7 @@ int grbUnzipRecord(void *gribbuffer, size_t *gribsize)
 	  if ( unzipsize < (long) igribsize )
 	    {
 	      fprintf(stderr, "Decompressed size smaller than compressed size (in %ld; out %ld)!\n", (long)igribsize, unzipsize);
-	      return (0);
+	      return 0;
 	    }
 
 	  if ( itmpbuffersize < igribsize )
@@ -55003,13 +53852,13 @@ void grb_read_var_slice(stream_t *streamptr, int varID, int levelID, int memtype
 
 
 
-#undef  UNDEFID
-#define UNDEFID  CDI_UNDEFID
+#undef  CDI_UNDEFID
+#define CDI_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;
@@ -55017,16 +53866,15 @@ 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
@@ -55075,7 +53923,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;
@@ -55093,7 +53941,7 @@ void cdfDefVarMissval(stream_t *streamptr, int varID, int dtype, int lcheck)
 
       if ( lcheck && streamptr->ncmode == 2 ) cdf_enddef(fileID);
 
-      streamptr->vars[varID].defmiss = TRUE;
+      streamptr->vars[varID].defmiss = true;
     }
 }
 
@@ -55104,7 +53952,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 )
@@ -55127,7 +53975,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 )
@@ -55146,7 +53994,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;
@@ -55154,8 +54002,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;
@@ -55164,11 +54012,11 @@ 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;
 
@@ -55176,23 +54024,33 @@ void cdfDefineAttributes(int vlistID, int varID, int fileID, int ncvarID)
         {
           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 == DATATYPE_INT8  || atttype == DATATYPE_UINT8  ||
+                atttype == DATATYPE_INT16 || atttype == DATATYPE_UINT16 ||
+                atttype == DATATYPE_INT32 || atttype == 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 == DATATYPE_INT8)  ? NC_BYTE :
+                          (atttype == DATATYPE_INT16) ? NC_SHORT :
+#if  defined  (HAVE_NETCDF4)
+                          (atttype == DATATYPE_UINT8)  ? NC_UBYTE :
+                          (atttype == DATATYPE_UINT16) ? NC_USHORT :
+                          (atttype == 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 )
         {
           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 )
             {
@@ -55204,7 +54062,7 @@ void cdfDefineAttributes(int vlistID, int varID, int fileID, int ncvarID)
             cdf_put_att_double(fileID, ncvarID, attname, NC_DOUBLE, len, attflt);
         }
     }
-  
+
   Free(attBuf);
 }
 
@@ -55220,7 +54078,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);
 
@@ -55238,7 +54096,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;
 
@@ -55247,7 +54105,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);
@@ -55263,14 +54121,48 @@ 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_MAPPING, CDI_MAX_NAME, mapping);
+
+  if ( !mapping[0] )
+    {
+      int projID = gridInqProj(gridID);
+      if ( projID != CDI_UNDEFID )
+        {
+          pgridID = projID;
+          cdiGridInqKeyStr(pgridID, CDI_KEY_MAPPING, CDI_MAX_NAME, mapping);
+        }
+    }
+
+  if ( mapping[0] )
+    cdiGridInqKeyStr(pgridID, CDI_KEY_MAPNAME, 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;
@@ -55285,7 +54177,7 @@ int cdfDefVar(stream_t *streamptr, int varID)
   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;
@@ -55302,23 +54194,23 @@ int cdfDefVar(stream_t *streamptr, int varID)
   vlistInqVarDimorder(vlistID, varID, &dimorder);
 
   int gridsize  = gridInqSize(gridID);
-  if ( gridsize > 1 ) lchunk = TRUE;
+  bool lchunk = (gridsize > 1);
   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].xdimID;
+      yid = streamptr->ncgrid[gridindex].ydimID;
+      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)) )
     {
@@ -55330,41 +54222,41 @@ int cdfDefVar(stream_t *streamptr, int varID)
 
   if ( tsteptype != TSTEP_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;
   */
   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 )
+          if ( chunktype == CDI_CHUNK_LINES )
             chunks[ndims] = 1;
           else
             chunks[ndims] = ysize;
           dims[ndims] = yid;
           ndims++;
         }
-      else if ( dimorder[id] == 1 && xid != UNDEFID )
+      else if ( dimorder[id] == 1 && xid != CDI_UNDEFID )
         {
           chunks[ndims] = xsize;
           dims[ndims] = xid;
@@ -55387,24 +54279,17 @@ int cdfDefVar(stream_t *streamptr, int varID)
   if ( units    == NULL )    units = tableInqParUnitsPtr(tableID, code);
   if ( name )
     {
-      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++;
 
@@ -55433,7 +54318,7 @@ int cdfDefVar(stream_t *streamptr, int varID)
 
       char *varname2 = varname+strlen(varname);
 
-      int checkname = TRUE;
+      bool checkname = true;
       int iz = 0;
 
       while ( checkname )
@@ -55441,7 +54326,7 @@ 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++;
 
@@ -55463,7 +54348,7 @@ int cdfDefVar(stream_t *streamptr, int varID)
 #if  defined  (HAVE_NETCDF4)
   if ( lchunk && (streamptr->filetype == FILETYPE_NC4 || streamptr->filetype == FILETYPE_NC4C) )
     {
-      if ( chunktype == CHUNK_AUTO )
+      if ( chunktype == CDI_CHUNK_AUTO )
         retval = nc_def_var_chunking(fileID, ncvarid, NC_CHUNKED, NULL);
       else
         retval = nc_def_var_chunking(fileID, ncvarid, NC_CHUNKED, chunks);
@@ -55472,7 +54357,7 @@ int cdfDefVar(stream_t *streamptr, int varID)
     }
 #endif
 
-  if ( streamptr->comptype == COMPRESS_ZIP )
+  if ( streamptr->comptype == CDI_COMPRESS_ZIP )
     {
       if ( lchunk && (streamptr->filetype == FILETYPE_NC4 || streamptr->filetype == FILETYPE_NC4C) )
         {
@@ -55482,40 +54367,37 @@ 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 ( streamptr->comptype == CDI_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;
-
+          static bool lwarn = true;
           if ( lwarn )
             {
-              lwarn = FALSE;
+              lwarn = false;
               Warning("NetCDF4/SZIP compression not available!");
             }
 #endif
         }
       else
         {
-          static int lwarn = TRUE;
-
+          static bool lwarn = true;
           if ( lwarn )
             {
-              lwarn = FALSE;
+              lwarn = false;
               Warning("SZIP compression is only available for NetCDF4!");
             }
         }
@@ -55540,15 +54422,14 @@ 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 )
     {
@@ -55561,42 +54442,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 )
     {
       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" );
     }
-  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].xvarID;
+      int ncyvarID = streamptr->ncgrid[gridindex].yvarID;
       if ( ncyvarID != CDI_UNDEFID )
         {
           size_t len = strlen(coordinates);
@@ -55613,9 +54480,9 @@ 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];
+      int ncxvarID = streamptr->ncgrid[gridindex].xvarID;
+      int ncyvarID = streamptr->ncgrid[gridindex].yvarID;
+      int ncavarID = streamptr->ncgrid[gridindex].avarID;
       if ( ncyvarID != CDI_UNDEFID )
         {
           size_t len = strlen(coordinates);
@@ -55721,14 +54588,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 */
@@ -55769,25 +54628,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].xdimID;
+  int latID = streamptr->ncgrid[gridindex].ydimID;
 
   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, int nmiss)
 {
   const double *pdata_dp = (const double *) data;
   double *mdata_dp = NULL;
@@ -55915,9 +54772,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) )
@@ -55931,7 +54787,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 )
@@ -55972,7 +54828,7 @@ 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;
+  bool swapxy = false;
   int ndims = 0;
   int idim;
 
@@ -55992,16 +54848,16 @@ void cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data
   int zaxisID   = vlistInqVarZaxis(vlistID, varID);
   int tsteptype = vlistInqVarTsteptype(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].xdimID;
+      yid = streamptr->ncgrid[gridindex].ydimID;
     }
 
   int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
@@ -56014,14 +54870,14 @@ void cdf_write_var(stream_t *streamptr, int varID, int memtype, const void *data
       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);
@@ -56030,7 +54886,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);
@@ -56064,11 +54920,11 @@ void cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
 {
   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;
+  bool swapxy = false;
   int ndims = 0;
   int idim;
   int streamID = streamptr->self;
@@ -56097,9 +54953,9 @@ 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].xdimID;
+      yid = streamptr->ncgrid[gridindex].ydimID;
     }
 
   int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
@@ -56111,7 +54967,7 @@ void cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
       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]
@@ -56120,7 +54976,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);
@@ -56130,7 +54986,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);
@@ -56170,7 +55026,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);
 
@@ -56195,15 +55051,15 @@ 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].xdimID;
+      yid = streamptr->ncgrid[gridindex].ydimID;
     }
 
   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 )
@@ -56215,20 +55071,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);
@@ -56260,6 +55116,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
 
@@ -56270,8 +55136,8 @@ void cdf_write_record(stream_t *streamptr, int memtype, const void *data, int nm
 
 
 
-#undef  UNDEFID
-#define UNDEFID  CDI_UNDEFID
+#undef  CDI_UNDEFID
+#define CDI_UNDEFID  CDI_UNDEFID
 
 
 static
@@ -56307,7 +55173,7 @@ void cdfGetSlapDescription(stream_t *streamptr, int varID, size_t (*start)[4], s
 
   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);
@@ -56328,9 +55194,9 @@ void cdfGetSlapDescription(stream_t *streamptr, int varID, size_t (*start)[4], s
       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 ( 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));
 #undef addDimension
 
   assert(ndims <= (int)(sizeof(*start)/sizeof(**start)));
@@ -56568,18 +55434,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]);
 }
@@ -56609,18 +55469,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);
 }
@@ -56631,7 +55485,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:
@@ -56656,8 +55510,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;
@@ -56702,7 +55556,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;
 
@@ -56719,7 +55573,7 @@ void cdfGetSliceSlapDescription(stream_t *streamptr, int varId, int levelId, boo
     {
       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");
@@ -56832,15 +55686,13 @@ 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)
 {
-  size_t start[4];
-  size_t count[4];
-
   if ( CDI_Debug )
     Message("streamID = %d  varID = %d  levelID = %d", streamptr->self, varID, levelID);
 
   int vlistID = streamptr->vlistID;
   int fileID = streamptr->fileID;
 
+  size_t start[4], count[4];
   bool swapxy;
   cdfGetSliceSlapDescription(streamptr, varID, levelID, &swapxy, &start, &count);
 
@@ -56858,19 +55710,20 @@ void cdfReadVarSliceDP(stream_t *streamptr, int varID, int levelID, double *data
         data[i] = (double) data_fp[i];
       Free(data_fp);
     }
-  else if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_UINT8 )
-    {
-      nc_type xtype;
-      cdf_inq_vartype(fileID, ncvarid, &xtype);
-      if ( xtype == NC_BYTE )
-        {
-          for ( size_t i = 0; i < gridsize; i++ )
-            if ( data[i] < 0 ) data[i] += 256;
-        }
-    }
   else
     {
       cdf_get_vara_double(fileID, ncvarid, start, count, data);
+      
+      if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_UINT8 )
+        {
+          nc_type xtype;
+          cdf_inq_vartype(fileID, ncvarid, &xtype);
+          if ( xtype == NC_BYTE )
+            {
+              for ( size_t i = 0; i < gridsize; i++ )
+                if ( data[i] < 0 ) data[i] += 256;
+            }
+        }
     }
 
   if ( swapxy ) transpose2dArrayDP(ysize, xsize, data);
@@ -56890,15 +55743,13 @@ 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)
 {
-  size_t start[4];
-  size_t count[4];
-
   if ( CDI_Debug )
     Message("streamID = %d  varID = %d  levelID = %d", streamptr->self, varID, levelID);
 
   int vlistID = streamptr->vlistID;
   int fileID = streamptr->fileID;
 
+  size_t start[4], count[4];
   bool swapxy;
   cdfGetSliceSlapDescription(streamptr, varID, levelID, &swapxy, &start, &count);
 
@@ -56916,19 +55767,20 @@ void cdfReadVarSliceSP(stream_t *streamptr, int varID, int levelID, float *data,
         data[i] = (float) data_dp[i];
       Free(data_dp);
     }
-  else if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_UINT8 )
-    {
-      nc_type xtype;
-      cdf_inq_vartype(fileID, ncvarid, &xtype);
-      if ( xtype == NC_BYTE )
-        {
-          for ( size_t i = 0; i < gridsize; i++ )
-            if ( data[i] < 0 ) data[i] += 256;
-        }
-    }
   else
     {
       cdf_get_vara_float(fileID, ncvarid, start, count, data);
+
+      if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_UINT8 )
+        {
+          nc_type xtype;
+          cdf_inq_vartype(fileID, ncvarid, &xtype);
+          if ( xtype == NC_BYTE )
+            {
+              for ( size_t i = 0; i < gridsize; i++ )
+                if ( data[i] < 0 ) data[i] += 256;
+            }
+        }
     }
 
   if ( swapxy ) transpose2dArraySP(ysize, xsize, data);
@@ -59377,8 +58229,8 @@ void tableDefault(void)
 #include <string.h>
 
 
-#undef  UNDEFID
-#define UNDEFID -1
+#undef  CDI_UNDEFID
+#define CDI_UNDEFID -1
 
 /*int TableDefine = 0; */ /* Define new table also if the entry already exist */
                           /* This is needed for createtable */
@@ -59461,8 +58313,8 @@ static void parTableInitEntry(int tableID)
   parTable[tableID].used    = 0;
   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;
 }
 
@@ -59690,7 +58542,7 @@ int tableRead(const char *tablefile)
   int lnr = 0;
   int id;
   char name[256], longname[256], units[256];
-  int tableID = UNDEFID;
+  int tableID = CDI_UNDEFID;
   int err;
   char *tablename;
   FILE *tablefp;
@@ -59744,7 +58596,7 @@ int tableRead(const char *tablefile)
 
 static int tableFromEnv(int modelID, int tablenum)
 {
-  int tableID = UNDEFID;
+  int tableID = CDI_UNDEFID;
   char tablename[256] = {'\0'};
   int tablenamefound = 0;
 
@@ -59762,7 +58614,7 @@ static int tableFromEnv(int modelID, int tablenum)
   else
     {
       int instID = modelInqInstitut(modelID);
-      if ( instID != UNDEFID )
+      if ( instID != CDI_UNDEFID )
 	{
           const char *instName;
 	  if ( (instName = institutInqNamePtr(instID)) )
@@ -59799,7 +58651,7 @@ static int tableFromEnv(int modelID, int tablenum)
       /* if (tablefile) printf("tableFile = %s\n", tablefile); */
 
       tableID = tableRead(tablefile);
-      if ( tableID != UNDEFID )
+      if ( tableID != CDI_UNDEFID )
 	{
 	  tableDefModelID(tableID, modelID);
 	  tableDefNum(tableID, tablenum);
@@ -59814,8 +58666,8 @@ static int tableFromEnv(int modelID, int tablenum)
 
 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();
@@ -59837,7 +58689,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);
     }
@@ -59852,11 +58704,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)) )
@@ -59868,7 +58720,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 )
@@ -59879,9 +58731,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 )
@@ -59894,14 +58746,14 @@ int tableInq(int modelID, int tablenum, const char *tablename)
 
 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();
 
@@ -59983,7 +58835,7 @@ void tableWrite(const char *ptfile, int tableID)
   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;
@@ -60095,7 +58947,7 @@ void tableFWriteC(FILE *ptfp, int tableID)
   char tablename[256];
 
 
-  if ( tableID == UNDEFID )
+  if ( tableID == CDI_UNDEFID )
     {
       Warning("parameter table ID undefined");
       return;
@@ -60163,7 +59015,7 @@ int tableInqParCode(int tableID, char *varname, int *code)
 {
   int err = 1;
 
-  if ( tableID != UNDEFID && varname != NULL )
+  if ( tableID != CDI_UNDEFID && varname != NULL )
     {
       int npars = parTable[tableID].npars;
       for ( int item = 0; item < npars; item++ )
@@ -60200,7 +59052,7 @@ int tableInqParName(int tableID, int code, char *varname)
 	    }
 	}
     }
-  else if ( tableID == UNDEFID )
+  else if ( tableID == CDI_UNDEFID )
     { }
   else
     Error("Invalid table ID %d", tableID);
@@ -60213,7 +59065,7 @@ const char *tableInqParNamePtr(int tableID, int code)
 {
   const char *name = NULL;
 
-  if ( tableID != UNDEFID )
+  if ( tableID != CDI_UNDEFID )
     {
       int npars = parTable[tableID].npars;
       for ( int item = 0; item < npars; item++ )
@@ -60234,7 +59086,7 @@ const char *tableInqParLongnamePtr(int tableID, int code)
 {
   const char *longname = NULL;
 
-  if ( tableID != UNDEFID )
+  if ( tableID != CDI_UNDEFID )
     {
       int npars = parTable[tableID].npars;
       for ( int item = 0; item < npars; item++ )
@@ -60255,7 +59107,7 @@ const char *tableInqParUnitsPtr(int tableID, int code)
 {
   const char *units = NULL;
 
-  if ( tableID != UNDEFID )
+  if ( tableID != CDI_UNDEFID )
     {
       int npars = parTable[tableID].npars;
       for ( int item = 0; item < npars; item++ )
@@ -60274,12 +59126,12 @@ const char *tableInqParUnitsPtr(int tableID, int code)
 
 int tableInqParLongname(int tableID, int code, char *longname)
 {
-  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++ )
@@ -60301,12 +59153,12 @@ int tableInqParLongname(int tableID, int code, char *longname)
 int tableInqParUnits(int tableID, int code, 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++ )
@@ -60328,7 +59180,7 @@ int tableInqParUnits(int tableID, int code, char *units)
 void tableInqPar(int tableID, int code, 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 npars = parTable[tableID].npars;
@@ -60465,7 +59317,7 @@ const char *tunitNamePtr(int unitID)
   else
     name = Timeunits[0];
 
-  return (name);
+  return name;
 }
 
 #if 0
@@ -60503,7 +59355,7 @@ static
 void taxisDefaultValue(taxis_t* taxisptr)
 {
   taxisptr->self        = CDI_UNDEFID;
-  taxisptr->used        = FALSE;
+  taxisptr->used        = false;
   taxisptr->type        = DefaultTimeType;
   taxisptr->vdate       = 0;
   taxisptr->vtime       = 0;
@@ -60514,8 +59366,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;
@@ -60540,20 +59392,19 @@ taxisNewEntry(cdiResH resH)
       reshReplace(resH, taxisptr, &taxisOps);
     }
 
-  return (taxisptr);
+  return taxisptr;
 }
 
 static
 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);
 }
 
@@ -60600,8 +59451,7 @@ taxisDefRtime(taxisID, 120000);
 */
 int taxisCreate(int taxistype)
 {
-  if ( CDI_Debug )
-    Message("taxistype: %d", taxistype);
+  if ( CDI_Debug ) Message("taxistype: %d", taxistype);
 
   taxisInit ();
 
@@ -60610,10 +59460,9 @@ 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)
@@ -60655,11 +59504,11 @@ 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;
 }
 
 
@@ -60907,7 +59756,7 @@ int taxisInqType(int taxisID)
 {
   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
 
-  return (taxisptr->type);
+  return taxisptr->type;
 }
 
 
@@ -60915,7 +59764,7 @@ int taxisHasBounds(int taxisID)
 {
   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
 
-  return (taxisptr->has_bounds);
+  return taxisptr->has_bounds;
 }
 
 
@@ -60923,9 +59772,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);
     }
 }
@@ -60982,7 +59831,7 @@ int taxisInqVdate(int taxisID)
 {
   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
 
-  return (taxisptr->vdate);
+  return taxisptr->vdate;
 }
 
 
@@ -60999,13 +59848,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);
     }
 }
@@ -61030,7 +59879,7 @@ int taxisInqVtime(int taxisID)
 {
   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
 
-  return (taxisptr->vtime);
+  return taxisptr->vtime;
 }
 
 
@@ -61047,13 +59896,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);
     }
 }
@@ -61085,7 +59934,7 @@ int taxisInqRdate(int taxisID)
       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
     }
 
-  return (taxisptr->rdate);
+  return taxisptr->rdate;
 }
 
 /*
@@ -61115,7 +59964,7 @@ int taxisInqRtime(int taxisID)
       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
     }
 
-  return (taxisptr->rtime);
+  return taxisptr->rtime;
 }
 
 /*
@@ -61144,7 +59993,7 @@ int taxisInqFdate(int taxisID)
       taxisptr->ftime = taxisptr->vtime;
     }
 
-  return (taxisptr->fdate);
+  return taxisptr->fdate;
 }
 
 /*
@@ -61173,7 +60022,7 @@ int taxisInqFtime(int taxisID)
       taxisptr->ftime = taxisptr->vtime;
     }
 
-  return (taxisptr->ftime);
+  return taxisptr->ftime;
 }
 
 /*
@@ -61199,7 +60048,7 @@ int taxisInqCalendar(int taxisID)
 {
   taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
 
-  return (taxisptr->calendar);
+  return taxisptr->calendar;
 }
 
 
@@ -61207,7 +60056,7 @@ int taxisInqTunit(int taxisID)
 {
   taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
 
-  return (taxisptr->unit);
+  return taxisptr->unit;
 }
 
 
@@ -61231,7 +60080,7 @@ int taxisInqNumavg(int taxisID)
 {
   taxis_t *taxisptr = ( taxis_t * ) reshGetVal ( taxisID, &taxisOps );
 
-  return (taxisptr->numavg);
+  return taxisptr->numavg;
 }
 
 
@@ -61239,7 +60088,7 @@ taxis_t *taxisPtr(int taxisID)
 {
   taxis_t *taxisptr = (taxis_t *)reshGetVal(taxisID, &taxisOps);
 
-  return (taxisptr);
+  return taxisptr;
 }
 
 void
@@ -61270,8 +60119,6 @@ ptaxisDefLongname(taxis_t *taxisptr, const char *longname)
 static void
 cdiDecodeTimevalue(int timeunit, double timevalue, int *days, int *secs)
 {
-  static int lwarn = TRUE;
-
   *days = 0;
   *secs = 0;
 
@@ -61316,10 +60163,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;
 	}
     }
 }
@@ -61327,8 +60175,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;
@@ -61352,10 +60198,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;
 	}
     }
 }
@@ -61439,7 +60286,7 @@ double vtime2timeval(int vdate, int vtime, taxis_t *taxis)
       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;
 
   cdiDecodeDate(rdate, &ryear, &rmonth, &day);
   cdiDecodeTime(rtime, &hour, &minute, &second);
@@ -61492,7 +60339,7 @@ double vtime2timeval(int vdate, int vtime, taxis_t *taxis)
       value /= 30;
     }
 
-  return (value);
+  return value;
 }
 
 
@@ -61524,7 +60371,6 @@ 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 )
     {
@@ -61564,10 +60410,11 @@ 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;
 	}
     }
 
@@ -61588,9 +60435,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);
         }
@@ -61707,7 +60555,7 @@ double cdiEncodeTimeval(int date, int time, taxis_t *taxis)
   else
     timevalue = vtime2timeval(date, time, taxis);
 
-  return (timevalue);
+  return timevalue;
 }
 
 
@@ -61787,13 +60635,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 );
 }
@@ -61986,21 +60834,16 @@ void decode_julday(int calendar,
 		   int *day)	/* Gregorian day (1-31) (out)   */
 {
   int a = julday;
-  double b, c;
-  double d, e, f;
 
-  b = floor((a - 1867216.25)/36524.25);
-  c = a + b - floor(b/4) + 1525;
+  double b = floor((a - 1867216.25)/36524.25);
+  double c = a + b - floor(b/4) + 1525;
 
   if ( calendar == CALENDAR_STANDARD )
-    if ( a < 2299161 )
-      {
-	c = a + 1524;
-      } 
+    if ( a < 2299161 ) c = a + 1524;
 
-  d = floor((c - 122.1)/365.25);
-  e = floor(365.25*d);
-  f = floor((c - e)/30.6001);
+  double d = floor((c - 122.1)/365.25);
+  double e = floor(365.25*d);
+  double f = floor((c - e)/30.6001);
 
   *day  = (int)(c - e - floor(30.6001*f));
   *mon  = (int)(f - 1 - 12*floor(f/14));
@@ -62014,7 +60857,6 @@ int encode_julday(int calendar, int year, int month, int day)
   int iy;
   int im;
   int ib;
-  int julday;
 
   if ( month <= 2 )
     {
@@ -62050,63 +60892,54 @@ int encode_julday(int calendar, int year, int month, int day)
 	}
     }
 
-  julday = (int) (floor(365.25*iy) + (int)(30.6001*(im+1)) + ib + 1720996.5 + day + 0.5);
+  int julday = (int) (floor(365.25*iy) + (int)(30.6001*(im+1)) + ib + 1720996.5 + day + 0.5);
 
-  return (julday);
+  return julday;
 }
 
 
 int date_to_julday(int calendar, int date)
 {
-  int julday;
   int year, month, day;
-
   cdiDecodeDate(date, &year, &month, &day);
 
-  julday = encode_julday(calendar, year, month, day);
+  int julday = encode_julday(calendar, year, month, day);
 
-  return (julday);
+  return julday;
 }
 
 
 int julday_to_date(int calendar, int julday)
 {
-  int date;
   int year, month, day;
-
   decode_julday(calendar, julday, &year, &month, &day);
 
-  date = cdiEncodeDate(year, month, day);
+  int date = cdiEncodeDate(year, month, day);
 
-  return (date);
+  return date;
 }
 
 
 int time_to_sec(int time)
 {
-  int secofday;
   int hour, minute, second;
-
   cdiDecodeTime(time, &hour, &minute, &second);
 
-  secofday = hour*3600 + minute*60 + second;
+  int secofday = hour*3600 + minute*60 + second;
 
-  return (secofday);
+  return secofday;
 }
 
 
 int sec_to_time(int secofday)
 {
-  int time;
-  int hour, minute, second;
-
-  hour   = secofday/3600;
-  minute = secofday/60 - hour*60;
-  second = secofday - hour*3600 - minute*60;
+  int hour   = secofday/3600;
+  int minute = secofday/60 - hour*60;
+  int second = secofday - hour*3600 - minute*60;
 
-  time = cdiEncodeTime(hour, minute, second);
+  int time = cdiEncodeTime(hour, minute, second);
 
-  return (time);
+  return time;
 }
 
 static
@@ -62114,14 +60947,14 @@ void adjust_seconds(int *julday, int64_t *secofday)
 {
   int64_t secperday = 86400;
 
-  while ( *secofday >= secperday ) 
-    { 
-      *secofday -= secperday; 
+  while ( *secofday >= secperday )
+    {
+      *secofday -= secperday;
       (*julday)++;
     }
 
-  while ( *secofday <  0 ) 
-    { 
+  while ( *secofday <  0 )
+    {
       *secofday += secperday;
       (*julday)--;
     }
@@ -62155,19 +60988,16 @@ void julday_add(int days, int secs, int *julday, int *secofday)
 /* subtract julday1/secofday1 from julday2/secofday2 and returns the result in seconds */
 double julday_sub(int julday1, int secofday1, int julday2, int secofday2, int *days, int *secs)
 {
-  int64_t sec_of_day;
-  int64_t seconds;
-
   *days = julday2 - julday1;
   *secs = secofday2 - secofday1;
 
-  sec_of_day = *secs;
+  int64_t sec_of_day = *secs;
 
   adjust_seconds(days, &sec_of_day);
 
   *secs = (int) sec_of_day;
 
-  seconds = *days * 86400 + sec_of_day;
+  int64_t seconds = (int64_t)(*days) * (int64_t)86400 + sec_of_day;
 
   return (double)seconds;
 }
@@ -62439,6 +61269,7 @@ void cdiPrintDatatypes(void)
            "+-------------+-------+\n"
            "| char        |   %3d |\n"
            "+-------------+-------+\n"
+           "| bool        |   %3d |\n"
            "| short       |   %3d |\n"
            "| int         |   %3d |\n"
            "| long        |   %3d |\n"
@@ -62457,7 +61288,7 @@ void cdiPrintDatatypes(void)
            "| FLT64       | %-9s |\n"
            "+-------------+-----------+\n"
            "\n  byte ordering is %s\n\n",
-           (int) sizeof(void *), (int) sizeof(char),
+           (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),
@@ -62659,8 +61490,8 @@ void cdiCreateUUID(unsigned char *uuid)
 
 
 
-#undef  UNDEFID
-#define UNDEFID -1
+#undef  CDI_UNDEFID
+#define CDI_UNDEFID -1
 
 static size_t Vctsize = 0;
 static double *Vct = NULL;
@@ -62748,7 +61579,7 @@ paramInitEntry(unsigned varID, int param)
   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;
@@ -62758,12 +61589,12 @@ 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].missval        = 0;
@@ -62799,11 +61630,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;
                 }
             }
         }
@@ -62939,12 +61770,12 @@ 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;
     }
   /*
@@ -62956,7 +61787,7 @@ static int levelNewEntry(unsigned varID, int level1, int level2, int tileID)
                                             (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;
@@ -62967,7 +61798,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
@@ -63026,7 +61857,7 @@ paramNewEntry(int param)
 
   paramInitEntry(varID, param);
 
-  return (varID);
+  return varID;
 }
 
 
@@ -63146,37 +61977,37 @@ 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;
 }
 
 
@@ -63192,32 +62023,19 @@ param_t;
 static
 int cmpparam(const void* s1, const void* s2)
 {
-  const param_t* x = (const param_t*) s1;
-  const param_t* y = (const param_t*) s2;
+  const param_t *x = (const param_t*) s1;
+  const param_t *y = (const param_t*) s2;
 
   int cmp = (( x->param > y->param ) - ( x->param < y->param )) * 2
            + ( x->ltype > y->ltype ) - ( x->ltype < y->ltype );
 
-  return (cmp);
+  return cmp;
 }
 
 
 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));
@@ -63245,32 +62063,30 @@ void cdi_generate_vars(stream_t *streamptr)
     {
       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",
@@ -63281,7 +62097,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))
@@ -63290,32 +62106,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]);
@@ -63348,33 +62163,34 @@ 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 *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, 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 )
         {
@@ -63401,10 +62217,10 @@ void cdi_generate_vars(stream_t *streamptr)
       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);
@@ -63417,10 +62233,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;
@@ -63428,20 +62242,20 @@ 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;
         }
       /* 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) )
 	    {
-	      if ( tableID != UNDEFID )
+	      if ( tableID != CDI_UNDEFID )
 		{
 		  strcpy(name, tableInqParNamePtr(cdiDefaultTableID, pnum));
 		  vlistDefVarName(vlistID, varID, name);
@@ -63459,13 +62273,13 @@ void cdi_generate_vars(stream_t *streamptr)
 	      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++ )
@@ -63473,29 +62287,18 @@ void cdi_generate_vars(stream_t *streamptr)
       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 )
@@ -63530,32 +62333,34 @@ 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;
+  bool zlbounds = false;
+  bool ltype_is_equal = false;
 
-  if ( ltype1 == zaxisInqLtype(zaxisID) ) ltype_is_equal = TRUE;
+  if ( ltype1 == zaxisInqLtype(zaxisID) ) ltype_is_equal = true;
 
   if ( ltype_is_equal && (zaxistype == zaxisInqType(zaxisID) || zaxistype == ZAXIS_GENERIC) )
     {
-      if ( zaxisInqLbounds(zaxisID, NULL) > 0 ) zlbounds = 1;
+      if ( zaxisInqLbounds(zaxisID, NULL) > 0 ) zlbounds = true;
       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;
-	    }
+	  const double *dlevels = zaxisInqLevelsPtr(zaxisID);
+          if ( dlevels )
+            {
+              int levelID;
+              for ( levelID = 0; levelID < nlevels; levelID++ )
+                {
+                  if ( fabs(dlevels[levelID] - levels[levelID]) > 1.e-9 )
+                    break;
+                }
 
-	  if ( levelID == nlevels ) differ = 0;
+              if ( levelID == nlevels ) differ = false;
+            }
 
 	  if ( ! differ )
 	    {
@@ -63563,17 +62368,17 @@ int zaxisCompare(int zaxisID, int zaxistype, int nlevels, int lbounds, const dou
 	      zaxisInqUnits(zaxisID, zunits);
 	      if ( longname && zlongname[0] )
 		{
-		  if ( strcmp(longname, zlongname) != 0 ) differ = 1;
+		  if ( strcmp(longname, zlongname) != 0 ) differ = true;
 		}
 	      if ( units && zunits[0] )
 		{
-		  if ( strcmp(units, zunits) != 0 ) differ = 1;
+		  if ( strcmp(units, zunits) != 0 ) differ = true;
 		}
 	    }
 	}
     }
 
-  return (differ);
+  return differ;
 }
 
 struct varDefZAxisSearchState
@@ -63581,7 +62386,7 @@ struct varDefZAxisSearchState
   int resIDValue;
   int zaxistype;
   int nlevels;
-  int lbounds;
+  bool lbounds;
   const double *levels;
   const char *longname;
   const char *units;
@@ -63593,9 +62398,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;
@@ -63605,7 +62410,7 @@ varDefZAxisSearch(int id, void *res, void *data)
 }
 
 
-int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, int lbounds,
+int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, 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)
 {
@@ -63613,9 +62418,9 @@ int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, i
     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;
 
@@ -63624,9 +62429,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) == false )
 	  {
-	    zaxisdefined = 1;
+	    zaxisdefined = true;
 	    break;
 	  }
       }
@@ -63651,7 +62456,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;
 	    }
     }
@@ -63682,7 +62487,7 @@ int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, i
       vlistptr->nzaxis++;
     }
 
-  return (zaxisID);
+  return zaxisID;
 }
 
 
@@ -63695,7 +62500,7 @@ void varDefMissval(int varID, double missval)
 
 void varDefCompType(int varID, int comptype)
 {
-  if ( vartable[varID].comptype == COMPRESS_NONE )
+  if ( vartable[varID].comptype == CDI_COMPRESS_NONE )
     vartable[varID].comptype = comptype;
 }
 
@@ -63708,7 +62513,7 @@ void varDefCompLevel(int varID, int complevel)
 
 int varInqInst(int varID)
 {
-  return (vartable[varID].instID);
+  return vartable[varID].instID;
 }
 
 
@@ -63720,7 +62525,7 @@ void varDefInst(int varID, int instID)
 
 int varInqModel(int varID)
 {
-  return (vartable[varID].modelID);
+  return vartable[varID].modelID;
 }
 
 
@@ -63732,7 +62537,7 @@ void varDefModel(int varID, int modelID)
 
 int varInqTable(int varID)
 {
-  return (vartable[varID].tableID);
+  return vartable[varID].tableID;
 }
 
 
@@ -63766,10 +62571,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 */
     }
@@ -63842,7 +62647,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;
@@ -63864,9 +62669,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
 
@@ -63909,35 +62713,6 @@ void cdiVlistCreateVarLevInfo(vlist_t *vlistptr, int varID);
  * 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
 
@@ -63973,8 +62748,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);
@@ -63983,7 +62757,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;
 }
 
@@ -64003,8 +62777,8 @@ const
 resOps vlistOps = {
   (valCompareFunc)vlist_compare,
   (valDestroyFunc)vlist_delete,
-  (valPrintFunc)vlistPrintKernel
-  , vlistGetSizeP,
+  (valPrintFunc)vlistPrintKernel,
+  vlistGetSizeP,
   vlistPackP,
   vlistTxCode
 };
@@ -64013,7 +62787,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
@@ -64035,7 +62809,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;
 }
 
@@ -64051,15 +62825,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 );
 
@@ -64072,9 +62844,7 @@ 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;
@@ -64135,7 +62905,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
@@ -64144,7 +62914,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;
@@ -64160,17 +62930,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);
@@ -64273,7 +63044,7 @@ void vlistCopy(int vlistID2, int vlistID1)
   var_t *vars2 = vlistptr2->vars;
   vlist_copy(vlistptr2, vlistptr1);
 
-  vlistCopyVarAtts(vlistID1, CDI_GLOBAL, vlistID2, CDI_GLOBAL);
+  cdiCopyVarAtts(vlistID1, CDI_GLOBAL, vlistID2, CDI_GLOBAL);
 
   if ( vars1 )
     {
@@ -64290,7 +63061,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);
+	  cdiCopyVarAtts(vlistID1, varID, vlistID2, varID);
 
           if ( vars1[varID].levinfo )
             {
@@ -64324,22 +63095,21 @@ 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;
       if ( vlistptr->vars[varID].levinfo )
         {
           int nlevs = zaxisInqSize(vlistptr->vars[varID].zaxisID);
-          for ( levID = 0; levID < nlevs; levID++ )
+          for ( int levID = 0; levID < nlevs; levID++ )
             vlistptr->vars[varID].levinfo[levID].flag = FALSE;
         }
     }
@@ -64351,7 +63121,7 @@ struct vgzSearchState
   int resIDValue;
   int zaxistype;
   int nlevels;
-  int lbounds;
+  bool lbounds;
   const double *levels;
 };
 
@@ -64362,7 +63132,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;
@@ -64371,27 +63141,26 @@ 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)
 {
   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;
         }
     }
@@ -64431,7 +63200,7 @@ int vlist_generate_zaxis(int vlistID, int zaxistype, int nlevels, const double *
       vlistptr->nzaxis++;
     }
 
-  return (zaxisID);
+  return zaxisID;
 }
 
 /*
@@ -64457,13 +63226,12 @@ void vlistCopyFlag(int vlistID2, int vlistID1)
 
   vlist_copy(vlistptr2, vlistptr1);
 
-  vlistCopyVarAtts(vlistID1, CDI_GLOBAL, vlistID2, CDI_GLOBAL);
+  cdiCopyVarAtts(vlistID1, CDI_GLOBAL, vlistID2, CDI_GLOBAL);
 
   if ( vlistptr1->vars )
     {
       int nvars = vlistptr1->nvars;
       int nvars2 = 0;
-      int varID2;
 
       vlistptr2->ngrids = 0;
       vlistptr2->nzaxis = 0;
@@ -64480,7 +63248,7 @@ void vlistCopyFlag(int vlistID2, int vlistID1)
 
       vlistptr2->vars = vars2;
 
-      varID2 = 0;
+      int varID2 = 0;
       for ( int varID = 0; varID < nvars; varID++ )
 	if ( vars1[varID].flag )
 	  {
@@ -64499,7 +63267,7 @@ void vlistCopyFlag(int vlistID2, int vlistID1)
             var_copy_entries(&vars2[varID2], &vars1[varID]);
 
 	    vlistptr2->vars[varID2].atts.nelems = 0;
-	    vlistCopyVarAtts(vlistID1, varID, vlistID2, varID2);
+	    cdiCopyVarAtts(vlistID1, varID, vlistID2, varID2);
 
 	    int nlevs  = zaxisInqSize(vars1[varID].zaxisID);
 	    int nlevs2 = 0;
@@ -64546,7 +63314,7 @@ 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);
@@ -64564,7 +63332,7 @@ void vlistCopyFlag(int vlistID2, int vlistID1)
                   }
 
 		int zaxisID2 = vlist_generate_zaxis(vlistID2, zaxisType, nlevs2, levels, lbounds, ubounds, nvct, vct);
-		free(levels);
+		Free(levels);
                 Free(lbounds);
 
                 zaxisInqName(zaxisID, ctemp);
@@ -64663,7 +63431,7 @@ void vlistCat(int vlistID2, int vlistID1)
         }
 
       vars2[varID2].atts.nelems = 0;
-      vlistCopyVarAtts(vlistID1, varID, vlistID2, varID2);
+      cdiCopyVarAtts(vlistID1, varID, vlistID2, varID2);
 
       vlistAdd2GridIDs(vlistptr2, vars1[varID].gridID);
       vlistAdd2ZaxisIDs(vlistptr2, vars1[varID].zaxisID);
@@ -64821,28 +63589,28 @@ 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;
+  int datatype = vlistptr->vars[0].datatype;
   if (  datatype== DATATYPE_CPX32 || datatype == DATATYPE_CPX64 )
     number = CDI_COMP;
   else
@@ -64863,7 +63631,7 @@ int vlistNumber(int vlistID)
         }
     }
 
-  return (number);
+  return number;
 }
 
 /*
@@ -64886,7 +63654,7 @@ int vlistNgrids(int vlistID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  return (vlistptr->ngrids);
+  return vlistptr->ngrids;
 }
 
 /*
@@ -64909,7 +63677,7 @@ int vlistNzaxis(int vlistID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  return (vlistptr->nzaxis);
+  return vlistptr->nzaxis;
 }
 
 
@@ -64917,7 +63685,7 @@ int vlistNsubtypes(int vlistID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  return (vlistptr->nsubtypes);
+  return vlistptr->nsubtypes;
 }
 
 
@@ -64925,7 +63693,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);
@@ -65047,7 +63815,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;
@@ -65075,7 +63843,7 @@ int vlistInqTaxis(int vlistID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  return (vlistptr->taxisID);
+  return vlistptr->taxisID;
 }
 
 
@@ -65083,7 +63851,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);
@@ -65095,7 +63863,7 @@ int vlistInqTable(int vlistID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  return (vlistptr->tableID);
+  return vlistptr->tableID;
 }
 
 
@@ -65103,7 +63871,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);
@@ -65130,7 +63898,7 @@ int vlistInqInstitut(int vlistID)
       vlistDefInstitut(vlistID, instID);
     }
 
-  return (instID);
+  return instID;
 }
 
 
@@ -65138,7 +63906,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);
@@ -65166,7 +63934,7 @@ int vlistInqModel(int vlistID)
       vlistDefModel(vlistID, modelID);
     }
 
-  return (modelID);
+  return modelID;
 }
 
 
@@ -65182,7 +63950,7 @@ int vlistGridsizeMax(int vlistID)
       if ( gridsize > gridsizemax ) gridsizemax = gridsize;
     }
 
-  return (gridsizemax);
+  return gridsizemax;
 }
 
 
@@ -65194,7 +63962,7 @@ int vlistGrid(int vlistID, int index)
   if ( index < vlistptr->ngrids && index >= 0 )
     gridID = vlistptr->gridIDs[index];
 
-  return (gridID);
+  return gridID;
 }
 
 
@@ -65208,7 +63976,7 @@ int vlistGridIndex(int vlistID, int gridID)
 
   if ( index == vlistptr->ngrids ) index = -1;
 
-  return (index);
+  return index;
 }
 
 
@@ -65262,7 +64030,7 @@ int vlistZaxis(int vlistID, int index)
   if ( index < vlistptr->nzaxis && index >= 0 )
     zaxisID = vlistptr->zaxisIDs[index];
 
-  return (zaxisID);
+  return zaxisID;
 }
 
 
@@ -65276,7 +64044,7 @@ int vlistZaxisIndex(int vlistID, int zaxisID)
 
   if ( index == vlistptr->nzaxis ) index = -1;
 
-  return (index);
+  return index;
 }
 
 
@@ -65380,15 +64148,14 @@ int vlistHasTime(int vlistID)
         break;
       }
 
-  return (hastime);
+  return hastime;
 }
 
 enum {
   vlist_nints=6,
 };
 
-static int
-vlistTxCode ( void )
+static int vlistTxCode ( void )
 {
   return VLIST;
 }
@@ -65401,7 +64168,7 @@ int  vlistGetSizeP ( void * vlistptr, void *context)
   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 += cdiAttsGetSize(p, CDI_GLOBAL, context);
   for ( varID = 0; varID <  p->nvars; varID++ )
     txsize += vlistVarGetPackSize(p, varID, context);
   return txsize;
@@ -65423,7 +64190,7 @@ void vlistPackP ( void * vlistptr, void * buf, int size, int *position,
   serializePack(tempbuf, vlist_nints, DATATYPE_INT, buf, size, position, context);
   serializePack(&p->ntsteps, 1, 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);
@@ -65447,7 +64214,7 @@ void vlistUnpack(char * buf, int size, int *position, int originNamespace,
   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);
+  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,
@@ -65457,11 +64224,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 )
@@ -65473,7 +64239,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);
@@ -65521,6 +64287,7 @@ void resize_opt_grib_entries(var_t *var, int nentries)
 
 
 
+
 static
 cdi_atts_t *get_attsp(vlist_t *vlistptr, int varID)
 {
@@ -65536,7 +64303,7 @@ cdi_atts_t *get_attsp(vlist_t *vlistptr, int varID)
 	attsp = &(vlistptr->vars[varID].atts);
     }
 
-  return (attsp);
+  return attsp;
 }
 
 static
@@ -65554,27 +64321,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);
@@ -65582,7 +64346,7 @@ cdi_att_t *new_att(cdi_atts_t *attsp, const char *name)
   attp->namesz = slen;
   attp->xvalue = NULL;
 
-  return (attp);
+  return attp;
 }
 
 static
@@ -65602,44 +64366,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
@@ -65649,22 +64433,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]);
 
@@ -65682,102 +64464,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);
-    }
-
-  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);
-  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);
-    }
+    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);
+  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);
@@ -65794,40 +64553,34 @@ 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 cdiCopyVarAtts(int cdiID1, int varID_1, int cdiID2, int varID_2)
 {
   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, varID_1);
   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, varID_2, 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}).
@@ -65835,23 +64588,23 @@ int vlistCopyVarAtts(int vlistID1, int varID_1, int vlistID2, int varID_2)
     @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(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}).
@@ -65859,110 +64612,110 @@ int vlistDefAttInt(int vlistID, int varID, const char *name, int type, int len,
     @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(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(DATATYPE_TXT, 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(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(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(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)
@@ -65982,8 +64735,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);
@@ -66007,8 +64759,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;
@@ -66016,30 +64768,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)
+  int txsize = serializeGetSize(cdi_att_nints, DATATYPE_INT, context)
     + serializeGetSize((int)attp->namesz, DATATYPE_TXT, context);
-  txsize += serializeGetSize((int)attp->nelems, vlistAttTypeLookup(attp), 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);
   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);
@@ -66048,33 +64801,32 @@ 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(tempbuf, cdi_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(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);
   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, DATATYPE_INT, context);
   char *attName = (char *) Malloc((size_t)tempbuf[0] + 1);
   serializeUnpack(buf, size, position, attName, tempbuf[0], DATATYPE_TXT, context);
   attName[tempbuf[0]] = '\0';
@@ -66100,22 +64852,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;
+  int numAtts;
   serializeUnpack(buf, size, position, &numAtts, 1, DATATYPE_INT, context);
-  for (i = 0; i < numAtts; ++i)
-  {
-    vlistAttUnpack(vlistID, varID, buf, size, position, context);
-  }
+  for ( int i = 0; i < numAtts; ++i )
+    cdiAttUnpack(cdiID, varID, buf, size, position, context);
 }
 
 /*
@@ -66171,7 +64920,7 @@ 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;
@@ -66185,18 +64934,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).
@@ -66205,8 +64949,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
     {
@@ -66221,7 +64965,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;
@@ -66229,9 +64973,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)
@@ -66251,12 +64995,12 @@ void vlistCheckVarID(const char *caller, int vlistID, int varID)
 
 int vlistDefVarTiles(int vlistID, int gridID, int zaxisID, int tsteptype, int tilesetID)
 {
-  vlist_t *vlistptr = vlist_to_pointer(vlistID);
   if ( CDI_Debug )
     Message("gridID = %d  zaxisID = %d  tsteptype = %d", gridID, zaxisID, tsteptype);
 
   int varID = vlistvarNewEntry(vlistID);
 
+  vlist_t *vlistptr = vlist_to_pointer(vlistID);
   vlistptr->nvars++;
   vlistptr->vars[varID].gridID    = gridID;
   vlistptr->vars[varID].zaxisID   = zaxisID;
@@ -66275,7 +65019,8 @@ 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;
 }
 
 /*
@@ -66433,7 +65178,7 @@ int vlistInqVarGrid(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].gridID);
+  return vlistptr->vars[varID].gridID;
 }
 
 /*
@@ -66459,7 +65204,7 @@ int vlistInqVarZaxis(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].zaxisID);
+  return vlistptr->vars[varID].zaxisID;
 }
 
 
@@ -66480,7 +65225,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;
 }
 
 
@@ -66507,7 +65253,7 @@ int vlistInqVarParam(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].param);
+  return vlistptr->vars[varID].param;
 }
 
 /*
@@ -66544,7 +65290,7 @@ int vlistInqVarCode(int vlistID, int varID)
       tableInqParCode(vlistptr->vars[varID].tableID, vlistptr->vars[varID].name, &code);
     }
 
-  return (code);
+  return code;
 }
 
 
@@ -66554,7 +65300,7 @@ const char *vlistInqVarNamePtr(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].name);
+  return vlistptr->vars[varID].name;
 }
 
 
@@ -66564,7 +65310,7 @@ const char *vlistInqVarLongnamePtr(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].longname);
+  return vlistptr->vars[varID].longname;
 }
 
 
@@ -66574,7 +65320,7 @@ const char *vlistInqVarStdnamePtr(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].stdname);
+  return vlistptr->vars[varID].stdname;
 }
 
 
@@ -66584,7 +65330,7 @@ const char *vlistInqVarUnitsPtr(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].units);
+  return vlistptr->vars[varID].units;
 }
 
 /*
@@ -66831,10 +65577,10 @@ 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;
 }
 
 
@@ -66842,8 +65588,7 @@ int vlistInqVarSize(int vlistID, int varID)
 {
   vlistCheckVarID(__func__, vlistID, varID);
 
-  int zaxisID, gridID;
-  int tsteptype;
+  int zaxisID, gridID, tsteptype;
   vlistInqVar(vlistID, varID, &gridID, &zaxisID, &tsteptype);
 
   int nlevs = zaxisInqSize(zaxisID);
@@ -66852,7 +65597,7 @@ int vlistInqVarSize(int vlistID, int varID)
 
   int size = gridsize*nlevs;
 
-  return (size);
+  return size;
 }
 
 /*
@@ -66881,7 +65626,7 @@ int vlistInqVarDatatype(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].datatype);
+  return vlistptr->vars[varID].datatype;
 }
 
 
@@ -66896,7 +65641,7 @@ int vlistInqVarNumber(int vlistID, int varID)
        vlistptr->vars[varID].datatype == DATATYPE_CPX64 )
     number = CDI_COMP;
 
-  return (number);
+  return number;
 }
 
 /*
@@ -66956,7 +65701,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;
 }
 
 
@@ -66974,7 +65719,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;
 }
 
 
@@ -67000,7 +65745,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;
 }
 
 /*
@@ -67162,7 +65907,7 @@ double vlistInqVarMissval(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].missval);
+  return vlistptr->vars[varID].missval;
 }
 
 /*
@@ -67272,7 +66017,7 @@ int vlistInqVarValidrange(int vlistID, int varID, double *validrange)
       validrange[1] = vlistptr->vars[varID].validrange[1];
     }
 
-  return (vlistptr->vars[varID].lvalidrange);
+  return vlistptr->vars[varID].lvalidrange;
 }
 
 
@@ -67295,7 +66040,7 @@ double vlistInqVarScalefactor(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].scalefactor);
+  return vlistptr->vars[varID].scalefactor;
 }
 
 
@@ -67305,7 +66050,7 @@ double vlistInqVarAddoffset(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].addoffset);
+  return vlistptr->vars[varID].addoffset;
 }
 
 
@@ -67370,7 +66115,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;
 }
 
 
@@ -67388,7 +66133,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;
 }
 
 
@@ -67406,7 +66151,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;
 }
 
 
@@ -67424,7 +66169,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;
 }
 
 
@@ -67443,8 +66188,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;
 }
 
 
@@ -67502,7 +66246,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 vlistptr->vars[varID].missvalused;
 }
 
 
@@ -67541,7 +66285,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);
@@ -67566,7 +66310,7 @@ int vlistFindVar(int vlistID, int fvarID)
       Message("varID not found for fvarID %d in vlistID %d!", fvarID, vlistID);
     }
 
-  return (varID);
+  return varID;
 }
 
 
@@ -67593,14 +66337,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;
 }
 
 
@@ -67639,7 +66383,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);
@@ -67728,7 +66472,7 @@ int vlistInqVarCompType(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].comptype);
+  return vlistptr->vars[varID].comptype;
 }
 
 
@@ -67752,7 +66496,7 @@ int vlistInqVarCompLevel(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].complevel);
+  return vlistptr->vars[varID].complevel;
 }
 
 
@@ -67776,7 +66520,7 @@ int vlistInqVarChunkType(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].chunktype);
+  return vlistptr->vars[varID].chunktype;
 }
 
 static
@@ -67837,9 +66581,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);
 
@@ -67853,7 +66595,7 @@ int vlistInqVarXYZ(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].xyz);
+  return vlistptr->vars[varID].xyz;
 }
 
 /* Ensemble Info Routines */
@@ -67890,7 +66632,7 @@ int vlistInqVarEnsemble( int vlistID, int varID, int *ensID, int *ensCount, int
       status = 1;
     }
 
-  return (status);
+  return status;
 }
 
 
@@ -68180,7 +66922,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)
@@ -68212,7 +66954,7 @@ int vlistVarGetPackSize(vlist_t *p, int varID, void *context)
     varsize += serializeGetSize((int)strlen(var->extra), DATATYPE_TXT, context);
   varsize += serializeGetSize(4 * zaxisInqSize(var->zaxisID),
                               DATATYPE_INT, context);
-  varsize += vlistAttsGetSize(p, varID, context);
+  varsize += cdiAttsGetSize(p, varID, context);
   return varsize;
 }
 
@@ -68280,7 +67022,7 @@ void vlistVarPack(vlist_t *p, int varID, char * buf, int size, int *position,
       serializePack(levbuf, nlevs * 4, DATATYPE_INT,
                     buf, size, position, context);
     }
-  vlistAttsPack(p, varID, buf, size, position, context);
+  cdiAttsPack(p, varID, buf, size, position, context);
 }
 
 static inline int
@@ -68389,7 +67131,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);
 }
 
 
@@ -68456,35 +67198,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 );
@@ -68531,31 +67244,33 @@ void zaxisGetTypeDescription(int zaxisType, int* outPositive, const char** outNa
 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;
+  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;
   memset(zaxisptr->uuid, 0, CDI_UUID_SIZE);
+  zaxisptr->atts.nalloc   = MAX_ATTRIBUTES;
+  zaxisptr->atts.nelems   = 0;
 }
 
 
@@ -68566,7 +67281,7 @@ zaxis_t *zaxisNewEntry(int id)
 
   zaxisDefaultValue ( zaxisptr );
 
-  if (id == CDI_UNDEFID)
+  if ( id == CDI_UNDEFID )
     zaxisptr->self = reshPut(zaxisptr, &zaxisOps);
   else
     {
@@ -68574,11 +67289,11 @@ zaxis_t *zaxisNewEntry(int id)
       reshReplace(id, zaxisptr, &zaxisOps);
     }
 
-  return (zaxisptr);
+  return zaxisptr;
 }
 
-static inline zaxis_t *
-zaxisID2Ptr(int id)
+
+zaxis_t *zaxis_to_pointer(int id)
 {
   return (zaxis_t *)reshGetVal(id, &zaxisOps);
 }
@@ -68587,14 +67302,11 @@ zaxisID2Ptr(int id)
 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);
 }
 
@@ -68643,7 +67355,6 @@ zaxisCreate_(int zaxistype, int size, int id)
   return zaxisID;
 }
 
-
 /*
 @Function  zaxisCreate
 @Title     Create a vertical Z-axis
@@ -68685,8 +67396,7 @@ 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 ();
   return zaxisCreate_(zaxistype, size, CDI_UNDEFID);
@@ -68722,16 +67432,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);
 }
 
 
@@ -68740,7 +67449,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;
 }
 
 
@@ -68754,36 +67463,42 @@ 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;
     }
 
-  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
@@ -68791,37 +67506,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 || *mesg == 0 ) 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.
@@ -68832,26 +67547,26 @@ 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;
 }
@@ -68872,14 +67587,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);
 }
 
 /*
@@ -68898,14 +67606,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);
 }
 
 /*
@@ -68924,27 +67625,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);
 }
 
 /*
@@ -68968,13 +67649,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;
 }
 
@@ -68999,8 +67679,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);
 }
 
 /*
@@ -69024,28 +67703,20 @@ 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)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
   if (zaxisptr->prec != prec)
     {
@@ -69057,18 +67728,18 @@ void zaxisDefPrec(int zaxisID, int prec)
 
 int zaxisInqPrec(int zaxisID)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
-  return (zaxisptr->prec);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
+  return zaxisptr->prec;
 }
 
 
 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);
     }
 }
@@ -69076,14 +67747,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);
@@ -69091,14 +67762,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)
     {
@@ -69110,14 +67781,14 @@ 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)
     {
@@ -69129,7 +67800,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;
 }
 
@@ -69149,14 +67820,14 @@ 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);
 
   int size = zaxisptr->size;
-
   double *vals = zaxisptr->vals;
 
   for (int ilev = 0; ilev < size; ilev++ )
     vals[ilev] = levels[ilev];
+
   reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
 }
 
@@ -69177,7 +67848,7 @@ The function @func{zaxisDefLevel} defines one level of a Z-axis.
 */
 void zaxisDefLevel(int zaxisID, int levelID, double level)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
   if ( levelID >= 0 && levelID < zaxisptr->size )
     zaxisptr->vals[levelID] = level;
   reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
@@ -69186,7 +67857,7 @@ void zaxisDefLevel(int zaxisID, int levelID, double level)
 
 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;
@@ -69197,7 +67868,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;
 }
 
@@ -69217,7 +67888,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;
@@ -69242,7 +67913,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;
 }
 
@@ -69262,7 +67933,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);
 }
@@ -69285,7 +67956,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);
 }
 
@@ -69308,7 +67979,7 @@ 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 )
     level = zaxisptr->vals[levelID];
@@ -69319,7 +67990,7 @@ double zaxisInqLevel(int zaxisID, int levelID)
 double zaxisInqLbound(int zaxisID, int index)
 {
   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];
@@ -69331,7 +68002,7 @@ double zaxisInqLbound(int zaxisID, int index)
 double zaxisInqUbound(int zaxisID, int index)
 {
   double level = 0;
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
   if ( zaxisptr->ubounds && ( index >= 0 && index < zaxisptr->size ) )
     level = zaxisptr->ubounds[index];
@@ -69341,7 +68012,7 @@ double zaxisInqUbound(int zaxisID, int index)
 
 const double *zaxisInqLevelsPtr(int zaxisID)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
   return zaxisptr->vals;
 }
 
@@ -69364,7 +68035,7 @@ The function @func{zaxisInqLevels} returns all levels of a Z-axis.
 */
 void zaxisInqLevels(int zaxisID, double *levels)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
   int size = zaxisptr->size;
   for (int i = 0; i < size; i++ )
     levels[i] =  zaxisptr->vals[i];
@@ -69374,7 +68045,7 @@ void zaxisInqLevels(int zaxisID, double *levels)
 int zaxisInqLbounds(int zaxisID, double *lbounds)
 {
   int size = 0;
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
   if ( zaxisptr->lbounds )
     {
@@ -69385,14 +68056,14 @@ int zaxisInqLbounds(int zaxisID, double *lbounds)
           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 )
     {
@@ -69403,14 +68074,14 @@ int zaxisInqUbounds(int zaxisID, double *ubounds)
           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 )
     {
@@ -69421,14 +68092,14 @@ int zaxisInqWeights(int zaxisID, double *weights)
           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++ )
@@ -69468,8 +68139,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;
 }
 
 /*
@@ -69490,14 +68161,14 @@ 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 )
     {
@@ -69533,7 +68204,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 )
     {
@@ -69548,28 +68219,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;
 
@@ -69587,7 +68258,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;
 
@@ -69605,7 +68276,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;
 
@@ -69623,14 +68294,14 @@ 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);
 
@@ -69644,13 +68315,13 @@ void zaxisResize(int zaxisID, int size)
 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);
+  zaxis_t *zaxisptrnew = zaxis_to_pointer(zaxisIDnew);
 
   zaxis_copy(zaxisptrnew, zaxisptr);
 
@@ -69694,22 +68365,24 @@ int zaxisDuplicate(int zaxisID)
         }
     }
 
-  return (zaxisIDnew);
+  return zaxisIDnew;
 }
 
 
-static void zaxisPrintKernel ( zaxis_t * zaxisptr, int index, FILE * fp )
+static
+void zaxisPrintKernel(zaxis_t *zaxisptr, int index, 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 dig = (prec == DATATYPE_FLT64) ? 15 : 7;
 
   int nbyte0 = 0;
   fprintf(fp, "#\n");
@@ -69717,13 +68390,18 @@ static void zaxisPrintKernel ( zaxis_t * zaxisptr, int index, FILE * fp )
   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++ )
+  int nbyte = nbyte0;
+  for ( int levelID = 0; levelID < nlevels; levelID++ )
     {
       if ( nbyte > 80 )
 	{
@@ -69731,7 +68409,7 @@ static void zaxisPrintKernel ( zaxis_t * zaxisptr, int index, FILE * fp )
 	  fprintf(fp, "%*s", nbyte0, "");
 	  nbyte = nbyte0;
 	}
-      nbyte += fprintf(fp, "%.9g ", zaxisptr->vals[levelID]);
+      nbyte += fprintf(fp, "%.*g ", dig, zaxisptr->vals[levelID]);
     }
   fprintf(fp, "\n");
 
@@ -69739,7 +68417,7 @@ static void zaxisPrintKernel ( zaxis_t * zaxisptr, int index, FILE * fp )
     {
       nbyte0 = fprintf(fp, "lbounds   = ");
       nbyte = nbyte0;
-      for ( levelID = 0; levelID < nlevels; levelID++ )
+      for ( int levelID = 0; levelID < nlevels; levelID++ )
 	{
 	  if ( nbyte > 80 )
 	    {
@@ -69747,13 +68425,13 @@ static void zaxisPrintKernel ( zaxis_t * zaxisptr, int index, FILE * fp )
 	      fprintf(fp, "%*s", nbyte0, "");
 	      nbyte = nbyte0;
 	    }
-	  nbyte += fprintf(fp, "%.9g ", zaxisptr->lbounds[levelID]);
+	  nbyte += fprintf(fp, "%.*g ", dig, zaxisptr->lbounds[levelID]);
 	}
       fprintf(fp, "\n");
 
       nbyte0 = fprintf(fp, "ubounds   = ");
       nbyte = nbyte0;
-      for ( levelID = 0; levelID < nlevels; levelID++ )
+      for ( int levelID = 0; levelID < nlevels; levelID++ )
 	{
 	  if ( nbyte > 80 )
 	    {
@@ -69761,7 +68439,7 @@ static void zaxisPrintKernel ( zaxis_t * zaxisptr, int index, FILE * fp )
 	      fprintf(fp, "%*s", nbyte0, "");
 	      nbyte = nbyte0;
 	    }
-	  nbyte += fprintf(fp, "%.9g ", zaxisptr->ubounds[levelID]);
+	  nbyte += fprintf(fp, "%.*g ", dig, zaxisptr->ubounds[levelID]);
 	}
       fprintf(fp, "\n");
     }
@@ -69782,7 +68460,7 @@ static void zaxisPrintKernel ( zaxis_t * zaxisptr, int index, FILE * fp )
                   fprintf(fp, "\n%*s", nbyte0, "");
                   nbyte = nbyte0;
                 }
-              nbyte += fprintf(fp, "%.9g ", vct[i]);
+              nbyte += fprintf(fp, "%.15g ", vct[i]);
             }
           fprintf(fp, "\n");
           /*
@@ -69795,7 +68473,7 @@ static void zaxisPrintKernel ( zaxis_t * zaxisptr, int index, FILE * fp )
                   fprintf(fp, "\n%*s", nbyte0, "");
                   nbyte = nbyte0;
                 }
-              nbyte += fprintf(fp, "%.9g ", vct[vctsize/2+i]);
+              nbyte += fprintf(fp, "%.15g ", vct[vctsize/2+i]);
             }
           fprintf(fp, "\n");
           */
@@ -69818,7 +68496,7 @@ static void zaxisPrintKernel ( zaxis_t * zaxisptr, int index, FILE * fp )
 
 void zaxisPrint ( int zaxisID, int index )
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
   zaxisPrintKernel ( zaxisptr, index, stdout );
 }
@@ -69835,12 +68513,10 @@ void zaxisPrintP ( void * voidptr, FILE * 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);
 
@@ -69852,8 +68528,8 @@ zaxisCompareP(zaxis_t *z1, zaxis_t *z2)
     | (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);
@@ -70223,7 +68899,7 @@ void cdiZaxisGetIndexList(unsigned nzaxis, int *zaxisResHs)
  * require-trailing-newline: t
  * End:
  */
-   static const char cdi_libvers[] = "1.7.2rc3" " of " "Apr 18 2016"" " "14:13:00";
+   static const char cdi_libvers[] = "1.8.0rc3" " of " "Sep 16 2016"" " "09:21:04";
 const char *cdiLibraryVersion(void)
 {
   return (cdi_libvers);
@@ -73084,17 +71760,17 @@ FCALLSCFUN2 (STRING, vlistInqVarNamePtr, VLISTINQVARNAMEPTR, vlistinqvarnameptr,
 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)
+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  */
 
@@ -73109,6 +71785,10 @@ FCALLSCSUB3 (gridPrint, GRIDPRINT, gridprint, INT, INT, INT)
 FCALLSCFUN2 (INT, gridCreate, 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)
+FCALLSCSUB2 (gridDefProjType, GRIDDEFPROJTYPE, griddefprojtype, INT, 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)
@@ -73124,8 +71804,8 @@ FCALLSCFUN2 (INT, gridInqYvals, GRIDINQYVALS, gridinqyvals, INT, DOUBLEV)
 
 /*  CDI grid string key values  */
 
-FCALLSCFUN4 (INT, cdiGridDefString, CDIGRIDDEFSTRING, cdigriddefstring, INT, INT, INT, STRING)
-FCALLSCFUN4 (INT, cdiGridInqString, CDIGRIDINQSTRING, cdigridinqstring, INT, INT, INT, PSTRING)
+FCALLSCFUN4 (INT, cdiGridDefKeyStr, CDIGRIDDEFKEYSTR, cdigriddefkeystr, INT, INT, INT, STRING)
+FCALLSCFUN4 (INT, cdiGridInqKeyStr, CDIGRIDINQKEYSTR, cdigridinqkeystr, INT, INT, INT, PSTRING)
 FCALLSCSUB2 (gridDefXname, GRIDDEFXNAME, griddefxname, INT, STRING)
 FCALLSCSUB2 (gridInqXname, GRIDINQXNAME, gridinqxname, INT, PSTRING)
 FCALLSCSUB2 (gridDefXlongname, GRIDDEFXLONGNAME, griddefxlongname, INT, STRING)
@@ -73147,27 +71827,9 @@ FCALLSCFUN2 (DOUBLE, gridInqYval, 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)
@@ -73179,20 +71841,20 @@ 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)
+FCALLSCSUB10 (gridDefParamLCC, GRIDDEFPARAMLCC, griddefparamlcc, INT, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, INT, INT)
+FCALLSCSUB10 (gridInqParamLCC, GRIDINQPARAMLCC, gridinqparamlcc, INT, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PDOUBLE, PINT, PINT)
 FCALLSCSUB2 (gridDefArea, GRIDDEFAREA, griddefarea, INT, DOUBLEV)
 FCALLSCSUB2 (gridInqArea, GRIDINQAREA, gridinqarea, INT, DOUBLEV)
 FCALLSCFUN1 (INT, gridHasArea, GRIDHASAREA, gridhasarea, INT)
@@ -73231,8 +71893,8 @@ 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, CDIZAXISDEFSTRING, cdizaxisdefstring, INT, INT, INT, STRING)
+FCALLSCFUN4 (INT, cdiZaxisInqKeyStr, CDIZAXISINQSTRING, cdizaxisinqstring, INT, INT, INT, PSTRING)
 FCALLSCSUB2 (zaxisDefName, ZAXISDEFNAME, zaxisdefname, INT, STRING)
 FCALLSCSUB2 (zaxisInqName, ZAXISINQNAME, zaxisinqname, INT, PSTRING)
 FCALLSCSUB2 (zaxisDefLongname, ZAXISDEFLONGNAME, zaxisdeflongname, INT, STRING)
diff --git a/libcdi/src/cgribex.h b/libcdi/src/cgribex.h
index 0f0f713..7b4d589 100644
--- a/libcdi/src/cgribex.h
+++ b/libcdi/src/cgribex.h
@@ -16,6 +16,7 @@
 #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
@@ -32,7 +33,6 @@
 #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
 
 /* GRIB1 Data representation type (Grid Type) [Table 6] */
 #define  GRIB1_GTYPE_LATLON                0  /*  latitude/longitude                                   */
@@ -226,7 +226,7 @@ void  gribPrintBDS(int nrec, long recpos, long recsize, unsigned char *gribbuffe
 void  gribCheck1(int nrec, long recpos, long recsize, unsigned char *gribbuffer);
 void  gribRepair1(int nrec, long recsize, unsigned char *gribbuffer);
 
-int   gribGetZip(long recsize, unsigned char *gribbuffer, long *urecsize);
+int   gribGetZip(size_t recsize, unsigned char *gribbuffer, size_t *urecsize);
 
 int   gribBzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize);
 int   gribZip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize);
@@ -238,10 +238,10 @@ void  gribClose(int fileID);
 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);
+size_t gribGetSize(int fileID);
 int   gribCheckSeek(int fileID, long *offset, int *version);
 int   gribFileSeek(int fileID, long *offset);
-int   gribReadSize(int fileID);
+size_t gribReadSize(int fileID);
 int   gribVersion(unsigned char *buffer, size_t buffersize);
 
 int   grib_info_for_grads(off_t recpos, long recsize, unsigned char *gribbuffer, int *intnum, float *fltnum, off_t *bignum);
diff --git a/libcdi/src/cgribexlib.c b/libcdi/src/cgribexlib.c
index 8739592..d7a0ad3 100644
--- a/libcdi/src/cgribexlib.c
+++ b/libcdi/src/cgribexlib.c
@@ -1,7 +1,7 @@
 
-/* Automatically generated by m214003 at 2016-06-03, do not edit */
+/* Automatically generated by m214003 at 2016-12-20, do not edit */
 
-/* CGRIBEXLIB_VERSION="1.7.5" */
+/* CGRIBEXLIB_VERSION="1.7.6" */
 
 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5) || defined (__clang__)
 #pragma GCC diagnostic push
@@ -139,8 +139,8 @@ int correct_bdslen(int bdslen, long recsize, long gribpos);
 
 /* param format:  DDDCCCNNN */
 
-void    cdiDecodeParam(int param, int *dis, int *cat, int *num);
-int     cdiEncodeParam(int dis, int cat, int num);
+void    cdiDecodeParam(int param, int *pnum, int *pcat, int *pdis);
+int     cdiEncodeParam(int pnum, int pcat, int pdis);
 
 /* date format:  YYYYMMDD */
 /* time format:  hhmmss   */
@@ -3957,8 +3957,10 @@ read3ByteMSBFirst(void *fileptr)
   return (int)((b1 << 16) + (b2 << 8) + b3);
 }
 
-int gribReadSize(int fileID)
+
+size_t gribReadSize(int fileID)
 {
+  size_t rgribsize = 0;
   void *fileptr = filePtr(fileID);
   off_t pos = fileGetPos(fileID); 
 
@@ -4009,6 +4011,7 @@ int gribReadSize(int fileID)
       if ( CGRIBEX_Debug ) Message("bdssize     = %d", bdssize);
 
       gribsize = issize + pdssize + gdssize + bmssize + bdssize + essize;
+      rgribsize = (size_t) gribsize;
     }
   else if ( gribversion == 1 )
     {
@@ -4044,51 +4047,50 @@ int gribReadSize(int fileID)
 	  bdssize = correct_bdslen(bdssize, gribsize, issize+pdssize+gdssize+bmssize);
 	  if ( CGRIBEX_Debug ) Message("bdssize     = %d", bdssize);
 
-	  gribsize = issize+pdssize+gdssize+bmssize+bdssize+essize;
+	  gribsize = issize + pdssize + gdssize + bmssize + bdssize + essize;
 	}
+      rgribsize = (size_t) gribsize;
     }
   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);
+      rgribsize = 0;
+      for ( int i = 0; i < 8; i++ ) rgribsize = (rgribsize << 8) | filePtrGetc(fileptr);
     }
   else
     {
-      gribsize = 0;
+      rgribsize = 0;
       Warning("GRIB version %d unsupported!", gribversion);
     }
 
-  if ( filePtrEOF(fileptr) ) gribsize = 0;
+  if ( filePtrEOF(fileptr) ) rgribsize = 0;
 
-  if ( CGRIBEX_Debug )
-    Message("gribsize    = %d", gribsize);
+  if ( CGRIBEX_Debug ) Message("gribsize = %zu", rgribsize);
 
   fileSetPos(fileID, pos, SEEK_SET);
 
-  return gribsize;
+  return rgribsize;
 }
 
 
-int gribGetSize(int fileID)
+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);
+      return 0;
     }
 
   if      ( ierr == -1 ) return 0;
   else if ( ierr ==  1 ) return 0;
 
-  int recSize = gribReadSize(fileID);
+  size_t recSize = gribReadSize(fileID);
 
-  if ( CGRIBEX_Debug ) Message("recsize = %d", recSize);
+  if ( CGRIBEX_Debug ) Message("recsize = %zu", recSize);
 
   fileSetPos(fileID, (off_t) -4, SEEK_CUR);
 
@@ -4109,7 +4111,7 @@ int gribRead(int fileID, unsigned char *buffer, size_t *buffersize)
   if      ( ierr == -1 ) { *buffersize = 0; return -1; }
   else if ( ierr ==  1 ) { *buffersize = 0; return -2; }
 
-  size_t recSize  = (size_t)gribReadSize(fileID);
+  size_t recSize  = gribReadSize(fileID);
   size_t readSize = recSize;
 
   if ( readSize > *buffersize )
@@ -6049,34 +6051,25 @@ void gribRepair1(int nrec, long recsize, unsigned char *gribbuffer)
 #  include "config.h"
 #endif
 
-#if  defined (HAVE_LIBSZ) || defined (HAVE_LIBAEC)
+#if  defined (HAVE_LIBSZ)
 #if defined(__cplusplus)
 extern "C" {
 #endif
-#if defined (HAVE_LIBAEC)
-#  include <libaec.h>
-#else
-#  include <szlib.h>
-#endif
+#include <szlib.h>
 #if defined (__cplusplus)
 }
 #endif
 
-#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
+#define OPTIONS_MASK        (SZ_RAW_OPTION_MASK | SZ_MSB_OPTION_MASK | SZ_NN_OPTION_MASK)
 
-#  define PIXELS_PER_BLOCK    (8)
-#  define PIXELS_PER_SCANLINE (PIXELS_PER_BLOCK*128)
+#define PIXELS_PER_BLOCK    (8)
+#define PIXELS_PER_SCANLINE (PIXELS_PER_BLOCK*128)
 
-#  define MIN_COMPRESS        (0.95)
-#  define MIN_SIZE            (256)
+#define MIN_COMPRESS        (0.95)
+#define MIN_SIZE            (256)
 #endif
 
 #define  Z_SZIP  128
-#define  Z_AEC   130
 
 
 #define SetLen3(var, offset, value) ((var[offset+0] = 0xFF & (value >> 16)), \
@@ -6088,120 +6081,93 @@ extern "C" {
 				     (var[offset+3] = 0xFF & (value      )))
 
 
-int gribGetZip(long recsize, unsigned char *gribbuffer, long *urecsize)
+int gribGetZip(size_t recsize, unsigned char *gribbuffer, size_t *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;
 
-  int gribversion = gribVersion(gribbuffer, (size_t)recsize);
+  int gribversion = gribVersion(gribbuffer, recsize);
 
-  if ( gribversion == 2 ) return (compress);
+  if ( gribversion == 2 ) return compress;
 
   long gribrecsize;
-  nerr = grib1Sections(gribbuffer, recsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  int nerr = grib1Sections(gribbuffer, (long)recsize, &pds, &gds, &bms, &bds, &gribrecsize);
   if ( nerr < 0 )
     {
       fprintf(stdout, "GRIB message error\n");
-      return (compress);
+      return compress;
     }
 
   if ( nerr > 0 )
     {
       fprintf(stdout, "GRIB data corrupted!\n");
-      return (compress);
+      return compress;
     }
 
   /* bds_len   = BDS_Len; */
   /* bds_nbits = BDS_NumBits; */
-  bds_flag  = BDS_Flag;
+  int bds_flag  = BDS_Flag;
   /* lspherc   =  bds_flag >> 7; */
   /* lcomplex  = (bds_flag >> 6)&1; */
-  lcompress = (bds_flag >> 4)&1;
+  int lcompress = (bds_flag >> 4)&1;
 
-  *urecsize = 0;
+  size_t gribsize = 0;
   if ( lcompress )
     {
       compress = BDS_Z;
-      if ( compress == Z_SZIP || compress == Z_AEC )
-	{
-	  gribsize = gribrec_len(bds[14], bds[15], bds[16]);
-	}
+      if ( compress == Z_SZIP ) gribsize = (size_t) gribrec_len(bds[14], bds[15], bds[16]);
     }
 
   *urecsize = gribsize;
 
-  return (compress);
+  return compress;
 }
 
 
 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))
+#if ! defined(HAVE_LIBSZ)
   static int libszwarn = 1;
 #endif
   unsigned char *pds = NULL, *gds = NULL, *bms = NULL, *bds = NULL;
 
-  gribLen = gribrec_len(dbuf[4], dbuf[5], dbuf[6]);
-  if ( gribLen > JP23SET ) llarge = TRUE;
+  int gribLen = gribrec_len(dbuf[4], dbuf[5], dbuf[6]);
+  int llarge = (gribLen > JP23SET);
 
-  rec_len = gribLen;
+  int rec_len = gribLen;
 
   long gribrecsize;
-  nerr = grib1Sections(dbuf, dbufsize, &pds, &gds, &bms, &bds, &gribrecsize);
+  int nerr = grib1Sections(dbuf, dbufsize, &pds, &gds, &bms, &bds, &gribrecsize);
   if ( nerr < 0 )
     {
       fprintf(stdout, "GRIB message error\n");
-      return (rec_len);
+      return rec_len;
     }
 
   if ( nerr > 0 )
     {
       fprintf(stdout, "GRIB data corrupted!\n");
-      return (rec_len);
+      return rec_len;
     }
 
-#if  defined (HAVE_LIBSZ) || defined (HAVE_LIBAEC)
-
+#if  defined(HAVE_LIBSZ)
   {
-    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;
+    int bds_zstart  = 14;
+    int bds_zoffset = 12;
     if ( llarge ) bds_zoffset += 2;
 
-    bds_len   = BDS_Len;
+    int 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;
+    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 )
@@ -6212,36 +6178,23 @@ int  gribZip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufs
 	    linfo = 0;
 	    fprintf(stderr, "GRIB szip only supports 8, 16, 24 and 32 bit data!\n");
 	  }
-	return (rec_len);
+	return rec_len;
       }
 
-#if defined (HAVE_LIBSZ)
-    if ( bds_nbits == 24 )
-      bits_per_sample    = 8;
-    else
-#endif
-      bits_per_sample    = bds_nbits;
+    int bits_per_sample = (bds_nbits == 24) ? 8 : 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_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;
-#endif
 
     if ( lspherc )
       {
 	if ( lcomplex  )
 	  {
-	    int jup, ioff;
-	    jup  = bds[15];
-	    ioff = (jup+1)*(jup+2);
+	    int jup  = bds[15];
+	    int ioff = (jup+1)*(jup+2);
 	    bds_ext = 4 + 3 + 4*ioff;
 	  }
 	else
@@ -6250,27 +6203,25 @@ int  gribZip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufs
 	  }
       }
 
-    datstart = bds_head + bds_ext;
+    size_t datstart = bds_head + bds_ext;
 
-    datsize = ((((bds_len - datstart)*8-bds_ubits)/bds_nbits)*bds_nbits)/8;
+    size_t datsize = ((((bds_len - datstart)*8-bds_ubits)/bds_nbits)*bds_nbits)/8;
 
-    if ( datsize < MIN_SIZE ) return (rec_len);
+    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;
+    size_t sourceLen = datsize;
+    size_t destLen   = sbufsize;
     
-    source = bds + datstart;
-    dest = sbuf;
+    unsigned char *source = bds + datstart;
+    unsigned char *dest = sbuf;
 
-#if defined (HAVE_LIBSZ)
     if ( bds_nbits == 24 )
       {
-	long nelem;
-	nelem = sourceLen/3;
+	long nelem = sourceLen/3;
 	pbuf = (unsigned char*) Malloc(sourceLen);
-	for ( i = 0; i < nelem; i++ )
+	for ( long i = 0; i < nelem; i++ )
 	  {
 	    pbuf[        i] = source[3*i  ];
 	    pbuf[  nelem+i] = source[3*i+1];
@@ -6278,24 +6229,8 @@ int  gribZip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufs
 	  }
 	source = pbuf;
       }
-#endif
-
-#if defined (HAVE_LIBAEC)
-    strm.next_in = source;
-    strm.avail_in = sourceLen;
-    strm.next_out = dest;
-    strm.avail_out = destLen;
-
-    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);
-      }
 
-    destLen = strm.total_out;
-#else
-    status = SZ_BufftoBuffCompress(dest, &destLen, source, sourceLen, &sz_param);
+    int status = SZ_BufftoBuffCompress(dest, &destLen, source, sourceLen, &sz_param);
     if ( status != SZ_OK )
       {
 	if ( status == SZ_NO_ENCODER_ERROR )
@@ -6309,7 +6244,6 @@ int  gribZip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufs
 	else
 	  Warning("SZ ERROR: %d code %3d level %3d", status, PDS_Parameter, PDS_Level2);
       }
-#endif
     
     if ( pbuf ) Free(pbuf);
     /*
@@ -6327,7 +6261,7 @@ int  gribZip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufs
 	gribLenOld = gribLen;
 
 	if ( bds_ext )
-	  for ( i = bds_ext-1; i >= 0; --i )
+	  for ( long i = bds_ext-1; i >= 0; --i )
 	    bds[bds_zoffset+bds_head+i] = bds[bds_head+i];
 
 	/*
@@ -6359,15 +6293,12 @@ int  gribZip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufs
 	    SetLen3(bds, bds_zstart+6, destLen);
 	  }
 
-	bdsLen = datstart + bds_zoffset + destLen;
+	int bdsLen = datstart + bds_zoffset + destLen;
 
 	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 )
@@ -6387,7 +6318,6 @@ int  gribZip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufs
 
 	if ( llarge )
 	  {
-	    long itemp;
 	    long bdslen = gribLen - 4;
 
 	    /*
@@ -6400,7 +6330,7 @@ int  gribZip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufs
 	    */
 	    while ( gribLen%120 ) dbuf[gribLen++] = 0;
 
-	    itemp = gribLen / (-120);
+	    long itemp = gribLen / (-120);
 	    itemp = JP23SET - itemp + 1;
 
 	    SetLen3(dbuf, 4, itemp);
@@ -6432,7 +6362,7 @@ int  gribZip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufs
 
   if ( libszwarn )
     {
-      Warning("Compression disabled, szlib or libaec not available!");
+      Warning("Compression disabled, szlib not available!");
       libszwarn = 0;
     }
 #endif
@@ -6444,23 +6374,20 @@ int  gribZip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufs
 
   rec_len = gribLen;
 
-  return (rec_len);
+  return rec_len;
 }
 
 
 int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbufsize)
 {
-#if ! (defined (HAVE_LIBSZ) || defined (HAVE_LIBAEC))
+#if ! defined(HAVE_LIBSZ)
   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;
 
   UNUSED(dbufsize);
@@ -6470,37 +6397,36 @@ int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbu
   if ( nerr < 0 )
     {
       fprintf(stdout, "GRIB message error\n");
-      return (0);
+      return 0;
     }
 
   if ( nerr > 0 )
     {
       fprintf(stdout, "GRIB data corrupted!\n");
-      return (0);
+      return 0;
     }
 
-  bds_zstart = 14;
+  int bds_zstart = 14;
 
   int recLen = gribrec_len(bds[bds_zstart], bds[bds_zstart+1], bds[bds_zstart+2]);
   if ( recLen > JP23SET ) llarge = TRUE;
 
-  bds_zoffset = 12;
+  int bds_zoffset = 12;
   if ( llarge ) bds_zoffset += 2;
 
   /* bds_len   = BDS_Len; */
-  bds_nbits = BDS_NumBits;
-  bds_flag  = BDS_Flag;
-  lspherc   =  bds_flag >> 7;
-  lcomplex  = (bds_flag >> 6)&1;
+  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 )
     {
       if ( lcomplex  )
 	{
-	  int jup, ioff;
-	  jup  = bds[bds_zoffset+15];
-	  ioff = (jup+1)*(jup+2);
+	  int jup  = bds[bds_zoffset+15];
+	  int ioff = (jup+1)*(jup+2);
 	  bds_ext = 4 + 3 + 4*ioff;
 	}
       else
@@ -6511,7 +6437,7 @@ int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbu
 
   size_t datstart = bds_head + (size_t)bds_ext;
 
-  source = bds + datstart + bds_zoffset;
+  unsigned char *source = bds + datstart + bds_zoffset;
   if ( llarge )
     sourceLen = ((size_t) ((bds[21]<<24)+(bds[22]<<16)+(bds[23]<<8)+bds[24]));
   else
@@ -6521,16 +6447,16 @@ int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbu
   if ( nerr < 0 )
     {
       fprintf(stdout, "GRIB message error\n");
-      return (0);
+      return 0;
     }
 
   if ( nerr > 0 )
     {
       fprintf(stdout, "GRIB data corrupted!\n");
-      return (0);
+      return 0;
     }
 
-  dest = bds + datstart;
+  unsigned char *dest = bds + datstart;
   if ( llarge )
     destLen = ((size_t) ((bds[17]<<24)+(bds[18]<<16)+(bds[19]<<8)+bds[20]));
   else
@@ -6540,63 +6466,28 @@ int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbu
 
   size_t bdsLen = datstart + destLen;
 
-#if  defined (HAVE_LIBSZ) || defined (HAVE_LIBAEC)
+#if  defined(HAVE_LIBSZ)
   {
-    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;
+    int bits_per_sample = (bds_nbits == 24) ? 8 : 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_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;
-#endif
 
     if ( bds_ext )
-      for ( i = 0; i < bds_ext; ++i )
+      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: 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);
+    size_t tmpLen = destLen;
 
-    tmpLen = strm.total_out;
-#else
-    status = SZ_BufftoBuffDecompress(dest, &tmpLen, source, sourceLen, &sz_param);
+    int status = SZ_BufftoBuffDecompress(dest, &tmpLen, source, sourceLen, &sz_param);
     if ( status != SZ_OK )
       {
 	if ( status == SZ_NO_ENCODER_ERROR )
@@ -6610,7 +6501,6 @@ int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbu
 	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);
@@ -6619,14 +6509,11 @@ int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbu
       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++ )
+	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];
@@ -6635,9 +6522,8 @@ int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbu
 	memcpy(dest, pbuf, tmpLen);
 	Free(pbuf);
       }
-#endif
 
-    bds_ubits = BDS_Flag & 15;
+    int bds_ubits = BDS_Flag & 15;
     BDS_Flag -= bds_ubits;
 
     if ( (bdsLen%2) == 1 )
@@ -6705,7 +6591,7 @@ int  gribUnzip(unsigned char *dbuf, long dbufsize, unsigned char *sbuf, long sbu
   
   if ( libszwarn )
     {
-      Warning("Decompression disabled, szlib or libaec not available!");
+      Warning("Decompression disabled, szlib not available!");
       libszwarn = 0;
     }
 #endif
@@ -8737,19 +8623,20 @@ int decodePDS(unsigned char *pds, int *isec0, int *isec1)
   ISEC1_LevelType      = PDS_LevelType;
 
   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 != 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 != GRIB1_LTYPE_SEADEPTH)     && 
        (ISEC1_LevelType != 210) )
     {
       ISEC1_Level1 = PDS_Level1;
@@ -11222,7 +11109,7 @@ void encodeES(GRIBPACK *lGrib, long *gribLen, long bdsstart)
 
       if ( z > JP23SET*120 )
 	{
-	  fprintf(stderr, "Abort: GRIB record too large (max = %d)!\n", JP23SET*120);
+	  fprintf(stderr, "Abort: GRIB1 record too large (size = %ld; max = %d)!\n", z, JP23SET*120);
 	  exit(1);
 	}
 
@@ -11418,14 +11305,15 @@ void encodePDS(GRIBPACK *lpds, long pdsLen, int *isec1)
   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 != 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) &&
@@ -13823,7 +13711,7 @@ 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";
+static const char grb_libvers[] = "1.7.6" " of ""Dec 20 2016"" ""19:55:24";
 const char *
 cgribexLibraryVersion(void)
 {
diff --git a/libcdi/src/config.h.in b/libcdi/src/config.h.in
index 8f6932d..8c9bcb7 100644
--- a/libcdi/src/config.h.in
+++ b/libcdi/src/config.h.in
@@ -85,9 +85,6 @@
 /* Define to 1 if you have the <inttypes.h> header file. */
 #undef HAVE_INTTYPES_H
 
-/* Define to 1 if you have the <jasper.h> header file. */
-#undef HAVE_JASPER_H
-
 /* Define to 1 for GRIB1 decoding/encoding with cgribex */
 #undef HAVE_LIBCGRIBEX
 
@@ -103,12 +100,6 @@
 /* Define to 1 for IEG interface */
 #undef HAVE_LIBIEG
 
-/* Define to 1 for JPEG compression for GRIB2 */
-#undef HAVE_LIBJASPER
-
-/* Define to 1 for PNG compression for GRIB2 */
-#undef HAVE_LIBLIBPNG
-
 /* Define to 1 if you have the `m' library (-lm). */
 #undef HAVE_LIBM
 
@@ -121,9 +112,6 @@
 /* Define to 1 for NetCDF support */
 #undef HAVE_LIBNETCDF
 
-/* Define to 1 for JPEG compression for GRIB2 */
-#undef HAVE_LIBOPENJPEG
-
 /* Define to 1 if you have the `pthread' library (-lpthread). */
 #undef HAVE_LIBPTHREAD
 
@@ -163,15 +151,9 @@
 /* Define to 1 if you have the <netcdf_par.h> header file. */
 #undef HAVE_NETCDF_PAR_H
 
-/* Define to 1 if you have the <openjpeg.h> header file. */
-#undef HAVE_OPENJPEG_H
-
 /* netCDF library does support MPI parallel invocations */
 #undef HAVE_PARALLEL_NC4
 
-/* Define to 1 if you have the <png.h> header file. */
-#undef HAVE_PNG_H
-
 /* ScalES PPM C core library is available */
 #undef HAVE_PPM_CORE
 
diff --git a/libcdi/src/file.c b/libcdi/src/file.c
index 529732e..4ea2e81 100644
--- a/libcdi/src/file.c
+++ b/libcdi/src/file.c
@@ -6,7 +6,7 @@
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <limits.h>
+#include <stdint.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
@@ -915,7 +915,7 @@ int file_fill_buffer(bfile_t *fileptr)
 	}
       else
 	{
-          xassert(fileptr->bufferSize <= SSIZE_MAX);
+          xassert(fileptr->bufferSize <= SIZE_MAX);
 	  nread = (ssize_t)fileptr->bufferSize;
 	  if ( (nread + fileptr->bufferPos) > fileptr->size )
 	    nread = fileptr->size - fileptr->bufferPos;
diff --git a/libcdi/src/gaussgrid.c b/libcdi/src/gaussgrid.c
index 2ae1b9f..a26e1d7 100644
--- a/libcdi/src/gaussgrid.c
+++ b/libcdi/src/gaussgrid.c
@@ -10,44 +10,26 @@
 
 #include "dmemory.h"
 #include "gaussgrid.h"
-
-#ifndef  M_PI
-#define  M_PI        3.14159265358979323846  /* pi */
-#endif
-
-#ifndef  M_SQRT2
-#define  M_SQRT2     1.41421356237309504880
-#endif
+#include "cdi_int.h"
 
 
 static
-void cpledn(size_t kn, size_t kodd, double *pfn, double pdx, int kflag, 
+void cpledn(size_t kn, size_t kodd, double *pfn, double pdx, int kflag,
             double *pw, double *pdxn, double *pxmod)
 {
-  double zdlk;
-  double zdlldn;
-  double zdlx;
-  double zdlmod;
-  double zdlxn;
-
-  size_t ik;
-
   /* 1.0 Newton iteration step */
 
-  zdlx = pdx;
-  zdlk = 0.0;
-  if (kodd == 0) 
-    {
-      zdlk = 0.5*pfn[0];
-    }
-  zdlxn  = 0.0;
-  zdlldn = 0.0;
+  double zdlx = pdx;
+  double zdlk = 0.0;
+  if ( kodd == 0 ) zdlk = 0.5*pfn[0];
+  double zdlxn  = 0.0;
+  double zdlldn = 0.0;
 
-  ik = 1;
+  size_t ik = 1;
 
-  if (kflag == 0) 
+  if ( kflag == 0 )
     {
-      for(size_t jn = 2-kodd; jn <= kn; jn += 2) 
+      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);
@@ -56,7 +38,7 @@ void cpledn(size_t kn, size_t kodd, double *pfn, double pdx, int kflag,
 	  ik++;
 	}
       /* Newton method */
-      zdlmod = -(zdlk/zdlldn);
+      double zdlmod = -(zdlk/zdlldn);
       zdlxn = zdlx + zdlmod;
       *pdxn = zdlxn;
       *pxmod = zdlmod;
@@ -64,9 +46,9 @@ void cpledn(size_t kn, size_t kodd, double *pfn, double pdx, int kflag,
 
   /* 2.0 Compute weights */
 
-  if (kflag == 1) 
+  if ( kflag == 1 )
     {
-      for(size_t jn = 2-kodd; jn <= kn; jn += 2) 
+      for ( size_t jn = 2-kodd; jn <= kn; jn += 2 )
 	{
 	  /* normalised derivative */
 	  zdlldn = zdlldn - pfn[ik]*(double)(jn)*sin((double)(jn)*zdlx);
@@ -82,24 +64,21 @@ static
 void gawl(double *pfn, double *pl, double *pw, size_t kn)
 {
   double pmod = 0;
-  int iflag;
-  int itemax;
   double zw = 0;
-  double zdlx;
   double zdlxn = 0;
 
   /* 1.0 Initizialization */
 
-  iflag  =  0;
-  itemax = 20;
+  int iflag  =  0;
+  int itemax = 20;
 
   size_t iodd   = (kn % 2);
 
-  zdlx   =  *pl;
+  double zdlx   =  *pl;
 
   /* 2.0 Newton iteration */
 
-  for (int jter = 1; jter <= itemax+1; jter++)
+  for ( int jter = 1; jter <= itemax+1; jter++ )
     {
       cpledn(kn, iodd, pfn, zdlx, iflag, &zw, &zdlxn, &pmod);
       zdlx = zdlxn;
@@ -114,7 +93,7 @@ void gawl(double *pfn, double *pl, double *pw, size_t kn)
 }
 
 static
-void gauaw(size_t kn, double *__restrict__ pl, double *__restrict__ pw)
+void gauaw(size_t kn, double *restrict pl, double *restrict pw)
 {
   /*
    * 1.0 Initialize Fourier coefficients for ordinary Legendre polynomials
@@ -122,26 +101,22 @@ void gauaw(size_t kn, double *__restrict__ pl, double *__restrict__ pw)
    * 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));
+  double *zfn    = (double *) Malloc((kn+1) * (kn+1) * sizeof(double));
+  double *zfnlat = (double *) Malloc((kn/2+1+1)*sizeof(double));
 
   zfn[0] = M_SQRT2;
-  for (size_t jn = 1; jn <= kn; jn++)
+  for ( size_t jn = 1; jn <= kn; jn++ )
     {
-      zfnn = zfn[0];
+      double zfnn = zfn[0];
       for (size_t jgl = 1; jgl <= jn; jgl++)
 	{
-	  zfnn *= sqrt(1.0-0.25/((double)(jgl*jgl))); 
+	  zfnn *= sqrt(1.0-0.25/((double)(jgl*jgl)));
 	}
 
       zfn[jn*(kn+1)+jn] = zfnn;
 
       size_t iodd = jn % 2;
-      for (size_t jgl = 2; jgl <= jn-iodd; jgl += 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)));
@@ -153,11 +128,11 @@ void gauaw(size_t kn, double *__restrict__ pl, double *__restrict__ pw)
 
   size_t iodd = kn % 2;
   size_t ik = iodd;
-  for (size_t jgl = iodd; jgl <= kn; jgl += 2)
+  for ( size_t jgl = iodd; jgl <= kn; jgl += 2 )
     {
       zfnlat[ik] = zfn[kn*(kn+1)+jgl];
       ik++;
-    } 
+    }
 
   /*
    * 2.1 Find first approximation of the roots of the
@@ -165,16 +140,17 @@ void gauaw(size_t kn, double *__restrict__ pl, double *__restrict__ pw)
    */
 
   size_t ins2 = kn/2+(kn % 2);
+  double z;
 
-  for (size_t jgl = 1; jgl <= ins2; jgl++) 
+  for ( size_t jgl = 1; jgl <= ins2; jgl++ )
     {
-      z = ((double)(4*jgl-1))*M_PI/((double)(4*kn+2)); 
+      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 */
 
-  for (size_t jgl = ins2; jgl >= 1 ; jgl--) 
+  for ( size_t jgl = ins2; jgl >= 1 ; jgl-- )
     {
       size_t jglm1 = jgl-1;
       gawl(zfnlat, &(pl[jglm1]), &(pw[jglm1]), kn);
@@ -182,12 +158,12 @@ void gauaw(size_t kn, double *__restrict__ pl, double *__restrict__ pw)
 
   /* convert to physical latitude */
 
-  for (size_t jgl = 0; jgl < ins2; jgl++) 
+  for ( size_t jgl = 0; jgl < ins2; jgl++ )
     {
       pl[jgl] = cos(pl[jgl]);
     }
 
-  for (size_t jgl = 1; jgl <= kn/2; jgl++) 
+  for ( size_t jgl = 1; jgl <= kn/2; jgl++ )
     {
       size_t jglm1 = jgl-1;
       size_t isym =  kn-jgl;
@@ -201,103 +177,48 @@ void gauaw(size_t kn, double *__restrict__ pl, double *__restrict__ pw)
   return;
 }
 
-#if 0
-static
-void gauaw_old(double *pa, double *pw, int nlat)
-{
-  /*
-   * Compute Gaussian latitudes.  On return pa contains the
-   * sine of the latitudes starting closest to the north pole and going
-   * toward the south
-   *
-   */
-
-  const int itemax = 20;
-
-  int isym, iter, ins2, jn, j;
-  double za, zw, zan;
-  double z, zk, zkm1, zkm2, zx, zxn, zldn, zmod;
 
-  /*
-   * Perform the Newton loop
-   * Find 0 of Legendre polynomial with Newton loop
-   */
-
-  ins2 = nlat/2 + nlat%2;
-
-  for ( j = 0; j < ins2; j++ )
-    {
-      z = (double) (4*(j+1)-1)*M_PI / (double) (4*nlat+2);
-      pa[j] = cos(z + 1.0/(tan(z)*(double)(8*nlat*nlat)));
-    }
-
-  for ( j = 0; j < ins2; j++ )
-    {
-
-      za = pa[j];
+void gaussaw(double *restrict pa, double *restrict pw, size_t nlat)
+{
+  //gauaw_old(pa, pw, nlat);
+  gauaw(nlat, pa, pw);
+}
 
-      iter = 0;
-      do
-	{
-	  iter++;
-	  zk = 0.0;
-
-	  /* Newton iteration step */
-
-	  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 );
 
-      pa[j] = zan;
-      pw[j] = 2.0*zw;
-    }
+bool isGaussGrid(size_t ysize, double yinc, const double *yvals)
+{
+  bool lgauss = false;
 
-#if defined (SX)
-#pragma vdir nodep
-#endif
-  for (j = 0; j < nlat/2; j++)
+  if ( IS_EQUAL(yinc, 0) && ysize > 2 ) /* check if gaussian */
     {
-      isym = nlat-(j+1);
-      pa[isym] = -pa[j];
-      pw[isym] =  pw[j];
+      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;
+
+      if ( i == ysize ) lgauss = true;
+
+      /* 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;
-}
-#endif
-
-void gaussaw(double *restrict pa, double *restrict pw, size_t nlat)
-{
-  //gauaw_old(pa, pw, nlat);
-  gauaw(nlat, pa, pw);
+  return lgauss;
 }
 
 /*
@@ -312,7 +233,6 @@ int main (int rgc, char *argv[])
   int 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;
diff --git a/libcdi/src/gaussgrid.h b/libcdi/src/gaussgrid.h
index e33df5e..3973a63 100644
--- a/libcdi/src/gaussgrid.h
+++ b/libcdi/src/gaussgrid.h
@@ -1,11 +1,14 @@
 #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)
 }
diff --git a/libcdi/src/grb_read.c b/libcdi/src/grb_read.c
index 4e52232..2c1bc98 100644
--- a/libcdi/src/grb_read.c
+++ b/libcdi/src/grb_read.c
@@ -23,7 +23,7 @@ int grbDecode(int filetype, int memtype, void *gribbuffer, int gribsize, void *d
   int status = 0;
 
 #if  defined  (HAVE_LIBCGRIBEX)
-  if ( filetype == FILETYPE_GRB )
+  if ( filetype == CDI_FILETYPE_GRB )
     {
 #if  defined  (HAVE_LIBGRIB_API)
       extern int cdiNAdditionalGRIBKeys;
@@ -47,7 +47,7 @@ int grbDecode(int filetype, int memtype, void *gribbuffer, int gribsize, void *d
           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
@@ -65,12 +65,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 */
@@ -78,10 +78,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 )
@@ -94,7 +94,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);
 
diff --git a/libcdi/src/grb_write.c b/libcdi/src/grb_write.c
index f47eb68..6477635 100644
--- a/libcdi/src/grb_write.c
+++ b/libcdi/src/grb_write.c
@@ -25,7 +25,7 @@ size_t grbEncode(int filetype, int memtype, int varID, int levelID, int vlistID,
   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);
@@ -53,7 +53,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
     {
@@ -75,7 +75,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);
     }
@@ -116,12 +116,12 @@ 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);
+      size_t unzipsize;
+      int izip = gribGetZip(recsize, gribbuffer, &unzipsize);
 
-      if ( izip == 0 && streamptr2->comptype == COMPRESS_SZIP )
+      if ( izip == 0 && streamptr2->comptype == CDI_COMPRESS_SZIP )
           nbytes = grbSzip(filetype, gribbuffer, nbytes);
     }
 
@@ -163,7 +163,7 @@ void grb_write_var_slice(stream_t *streamptr, int varID, int levelID, int memtyp
   size_t datasize = (size_t)gridInqSize(gridID);
 
 #ifdef HAVE_LIBCGRIBEX
-  if ( filetype == FILETYPE_GRB )
+  if ( filetype == CDI_FILETYPE_GRB )
     {
     }
   else
@@ -178,9 +178,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!");
@@ -190,11 +190,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);
diff --git a/libcdi/src/gribapi.c b/libcdi/src/gribapi.c
index 675816e..0a9aeb4 100644
--- a/libcdi/src/gribapi.c
+++ b/libcdi/src/gribapi.c
@@ -53,12 +53,10 @@ const char *gribapiLibraryVersionString(void)
 
 void gribContainersNew(stream_t * streamptr)
 {
-  int editionNumber = 2;
+  int editionNumber = (streamptr->filetype == CDI_FILETYPE_GRB) ? 1 : 2;
 
-  if ( streamptr->filetype == FILETYPE_GRB ) editionNumber = 1;
-  (void)editionNumber;
 #if  defined  (HAVE_LIBCGRIBEX)
-  if ( streamptr->filetype == FILETYPE_GRB )
+  if ( editionNumber == 1 )
     {
     }
   else
diff --git a/libcdi/src/gribapi_utilities.c b/libcdi/src/gribapi_utilities.c
index 9bdcaf6..fffb30a 100644
--- a/libcdi/src/gribapi_utilities.c
+++ b/libcdi/src/gribapi_utilities.c
@@ -276,7 +276,7 @@ static int getAvailabilityOfRelativeTimes(grib_handle* gh, bool* outHaveForecast
         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 60: case 1000: case 1002: case 1100: case 40033: case 40455:
+      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;
 
@@ -289,6 +289,7 @@ static int getAvailabilityOfRelativeTimes(grib_handle* gh, bool* outHaveForecast
     }
 }
 
+
 char* gribMakeTimeString(grib_handle* gh, CdiTimeType timeType)
 {
   //Get the parts of the reference date.
@@ -336,9 +337,10 @@ char* gribMakeTimeString(grib_handle* gh, CdiTimeType timeType)
   return makeDateString(&date);
 }
 
+
 int gribapiTimeIsFC(grib_handle *gh)
 {
-  if(gribEditionNumber(gh) <= 1) return true;
+  if (gribEditionNumber(gh) <= 1) return true;
 
   long sigofrtime;
   FAIL_ON_GRIB_ERROR(grib_get_long, gh, "significanceOfReferenceTime", &sigofrtime);
@@ -380,24 +382,26 @@ int gribapiGetTsteptype(grib_handle *gh)
         }
     }
 
-  return (tsteptype);
+  return tsteptype;
 }
 
+
 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;
+      datatype = gribCheckLong(gribHandle, "precision", 1) ? CDI_DATATYPE_FLT32 : CDI_DATATYPE_FLT64;
     }
   else
     {
       long bitsPerValue;
-      datatype = (!grib_get_long(gribHandle, "bitsPerValue", &bitsPerValue) && bitsPerValue > 0 && bitsPerValue <= 32) ? (int)bitsPerValue : DATATYPE_PACK;
+      datatype = (!grib_get_long(gribHandle, "bitsPerValue", &bitsPerValue) && bitsPerValue > 0 && bitsPerValue <= 32) ? (int)bitsPerValue : CDI_DATATYPE_PACK;
     }
   return datatype;
 }
 
+
 int gribapiGetParam(grib_handle *gh)
 {
   long pdis, pcat, pnum;
@@ -416,6 +420,7 @@ int gribapiGetParam(grib_handle *gh)
   return cdiEncodeParam((int)pnum, (int)pcat, (int)pdis);
 }
 
+
 int gribapiGetGridType(grib_handle *gh)
 {
   int gridtype = GRID_GENERIC;
@@ -424,12 +429,10 @@ int gribapiGetGridType(grib_handle *gh)
       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_LONLAT; 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;
@@ -450,6 +453,7 @@ 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 ( streamptr->unreduced && gridtype == GRID_GAUSSIAN_REDUCED )
     {
@@ -466,306 +470,251 @@ void gribapiGetGrid(grib_handle *gh, grid_t *grid)
   long numberOfPoints;
   FAIL_ON_GRIB_ERROR(grib_get_long, gh, "numberOfPoints", &numberOfPoints);
 
-  switch (gridtype)
+  long lpar;
+
+  if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN || projtype == CDI_PROJ_RLL )
     {
-    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);
+      long nlon, nlat;
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Ni", &nlon);
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Nj", &nlat);
 
-        if ( gridtype == GRID_GAUSSIAN )
-          {
-            long lpar;
-            FAIL_ON_GRIB_ERROR(grib_get_long, gh, "numberOfParallelsBetweenAPoleAndTheEquator", &lpar);
-            grid->np = (int)lpar;
-          }
+      if ( gridtype == GRID_GAUSSIAN )
+        {
+          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 ( numberOfPoints != nlon*nlat )
+        Error("numberOfPoints (%ld) and gridSize (%ld) differ!", numberOfPoints, nlon*nlat);
+
+      grid->size  = (int)numberOfPoints;
+      grid->x.size = (int)nlon;
+      grid->y.size = (int)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);
+
+      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 ( grid->y.inc > 0 && grid->y.first > grid->y.last ) grid->y.inc = -grid->y.inc;
+
+      /* if ( IS_NOT_EQUAL(grid->x.first, 0) || IS_NOT_EQUAL(grid->x.last, 0) ) */
+      {
+        if ( grid->x.size > 1 )
           {
-            if ( grid->xsize > 1 )
-              {
-                if ( (grid->xfirst >= grid->xlast) && (grid->xfirst >= 180) ) grid->xfirst -= 360;
+            if ( (grid->x.first >= grid->x.last) && (grid->x.first >= 180) ) grid->x.first -= 360;
 
-                if ( editionNumber <= 1 )
+            if ( editionNumber <= 1 )
+              {
+                /* correct xinc if necessary */
+                if ( IS_EQUAL(grid->x.first, 0) && grid->x.last > 354 )
                   {
-                    /* correct xinc if necessary */
-                    if ( IS_EQUAL(grid->xfirst, 0) && grid->xlast > 354 )
+                    double xinc = 360. / grid->x.size;
+                    if ( fabs(grid->x.inc-xinc) > 0.0 )
                       {
-                        double xinc = 360. / grid->xsize;
-
-                        if ( fabs(grid->xinc-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->xdef = 2;
           }
-        grid->ydef = 0;
-        /* if ( IS_NOT_EQUAL(grid->yfirst, 0) || IS_NOT_EQUAL(grid->ylast, 0) ) */
+        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 ( grid->ysize > 1 )
+            if ( editionNumber <= 1 )
               {
-                if ( editionNumber <= 1 )
-                  {
-                  }
               }
-            grid->ydef = 2;
           }
-        break;
+        grid->y.flag = 2;
       }
-    case GRID_GAUSSIAN_REDUCED:
+    }
+  else if ( gridtype == GRID_GAUSSIAN_REDUCED )
+    {
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "numberOfParallelsBetweenAPoleAndTheEquator", &lpar);
+      grid->np = (int)lpar;
+
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "Nj", &lpar);
+      int nlat = (int)lpar;
+
+      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);
+      for ( int i = 0; i < nlat; ++i ) grid->rowlon[i] = (int)pl[i];
+      Free(pl);
+
+      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);
+
+      // 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;
+
+      /* if ( IS_NOT_EQUAL(grid->x.first, 0) || IS_NOT_EQUAL(grid->x.last, 0) ) */
       {
-        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->x.size > 1 )
           {
-            if ( grid->xsize > 1 )
-              {
-                if ( (grid->xfirst > grid->xlast) && (grid->xfirst >= 180) ) grid->xfirst -= 360;
+            if ( (grid->x.first > grid->x.last) && (grid->x.first >= 180) ) grid->x.first -= 360;
 
-                if ( editionNumber <= 1 )
+            if ( editionNumber <= 1 )
+              {
+                /* correct xinc if necessary */
+                if ( IS_EQUAL(grid->x.first, 0) && grid->x.last > 354 )
                   {
-                    /* correct xinc if necessary */
-                    if ( IS_EQUAL(grid->xfirst, 0) && grid->xlast > 354 )
+                    double xinc = 360. / grid->x.size;
+                    if ( fabs(grid->x.inc-xinc) > 0.0 )
                       {
-                        double xinc = 360. / grid->xsize;
-
-                        if ( fabs(grid->xinc-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->xdef = 2;
           }
-        grid->ydef  = 0;
-        /* if ( IS_NOT_EQUAL(grid->yfirst, 0) || IS_NOT_EQUAL(grid->ylast, 0) ) */
+        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 ( grid->ysize > 1 )
+            if ( editionNumber <= 1 )
               {
-                if ( editionNumber <= 1 )
-                  {
-                  }
               }
-            grid->ydef = 2;
           }
-        break;
+        grid->y.flag = 2;
       }
-    case GRID_LCC:
-      {
-        int nlon, nlat;
-        long lpar;
-
-        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;
-
-        if ( numberOfPoints != nlon*nlat )
-          Error("numberOfPoints (%d) and gridSize (%d) differ!", (int)numberOfPoints, nlon*nlat);
-
-        grid->size  = (int)numberOfPoints;
-        grid->xsize = nlon;
-        grid->ysize = nlat;
-
-        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 ( 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;
-          }
-
-        grid->xdef   = 0;
-        grid->ydef   = 0;
+    }
+  else if ( gridtype == GRID_LCC )
+    {
+      int nlon, nlat;
+      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;
+
+      if ( numberOfPoints != nlon*nlat )
+        Error("numberOfPoints (%d) and gridSize (%d) differ!", (int)numberOfPoints, nlon*nlat);
+
+      grid->size  = (int)numberOfPoints;
+      grid->x.size = nlon;
+      grid->y.size = nlat;
+
+      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 ( 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;
+        }
 
-        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;
+      grid->x.flag = 0;
+      grid->y.flag = 0;
+    }
+  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;
 
-        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;
+      grid->size  = (int)datasize;
 
-        break;
-      }
-    case GRID_UNSTRUCTURED:
-      {
-        unsigned char uuid[CDI_UUID_SIZE];
-        /*
+      FAIL_ON_GRIB_ERROR(grib_get_long, gh, "J", &lpar);
+      grid->trunc = (int)lpar;
+    }
+  else if ( gridtype == GRID_GME )
+    {
+      grid->size  = (int)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 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  = (int)numberOfPoints;
 
-        /* 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_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);
-              }
-          }
-        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;
-
-        /* FIXME: assert(numberOfPoints <= INT_MAX && numberOfPoints >= INT_MIN) */
-        grid->size  = (int)numberOfPoints;
+            {
+            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 )
+    {
+      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;
 
-        if ( nlon > 0 && nlat > 0 && nlon*nlat == grid->size )
-          {
-            grid->xsize = nlon;
-            grid->ysize = nlat;
-          }
-        else
-          {
-            grid->xsize = 0;
-            grid->ysize = 0;
-          }
+      grid->size  = (int)numberOfPoints;
 
-        break;
-      }
-    default:
-      {
-        Error("Unsupported grid type: %s", gridNamePtr(gridtype));
-        break;
-      }
+      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;
+        }
     }
-
-  grid->isRotated = FALSE;
-  if ( gribapiGetIsRotated(gh) )
+  else
     {
-      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;
+      Error("Unsupported grid type: %s", gridNamePtr(gridtype));
     }
 
-  grid->xvals = NULL;
-  grid->yvals = NULL;
   grid->type  = gridtype;
+  grid->projtype  = projtype;
 }
 #endif
 /*
diff --git a/libcdi/src/grid.c b/libcdi/src/grid.c
index 9a68135..fb64c10 100644
--- a/libcdi/src/grid.c
+++ b/libcdi/src/grid.c
@@ -20,8 +20,6 @@
 #include "serialize.h"
 #include "vlist.h"
 
-#undef  UNDEFID
-#define UNDEFID -1
 
 /* the value in the second pair of brackets must match the length of
  * the longest string (including terminating NUL) */
@@ -38,10 +36,7 @@ static const char Grids[][17] = {
   /*  9 */  "unstructured",
   /* 10 */  "curvilinear",
   /* 11 */  "lcc",
-  /* 12 */  "lcc2",
-  /* 13 */  "laea",
-  /* 14 */  "sinusoidal",
-  /* 15 */  "projection",
+  /* 12 */  "projection",
 };
 
 /* must match table below */
@@ -66,8 +61,7 @@ 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 void   gridPack        ( void * gridptr, void * buff, int size, int *position, void *context);
 static int    gridTxCode      ( void );
 
 static const resOps gridOps = {
@@ -81,11 +75,12 @@ static const resOps gridOps = {
 
 static int  GRID_Debug = 0;   /* If set to 1, debugging */
 
-grid_t *gridID2Ptr(int gridID)
+
+grid_t *grid_to_pointer(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)
 
 
@@ -94,92 +89,88 @@ void grid_init(grid_t *gridptr)
   gridptr->self          = CDI_UNDEFID;
   gridptr->type          = CDI_UNDEFID;
   gridptr->proj          = CDI_UNDEFID;
+  gridptr->projtype      = CDI_UNDEFID;
   gridptr->mask          = NULL;
   gridptr->mask_gme      = NULL;
-  gridptr->xvals         = NULL;
-  gridptr->yvals         = NULL;
+  gridptr->x.vals        = NULL;
+  gridptr->y.vals        = NULL;
+  gridptr->x.bounds      = NULL;
+  gridptr->y.bounds      = 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->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;
+
+  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->gme.nd        = 0;
+  gridptr->gme.ni        = 0;
+  gridptr->gme.ni2       = 0;
+  gridptr->gme.ni3       = 0;
+
   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->x.size        = 0;
+  gridptr->y.size        = 0;
   gridptr->np            = 0;
-  gridptr->xdef          = 0;
-  gridptr->ydef          = 0;
+  gridptr->x.flag        = 0;
+  gridptr->y.flag        = 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->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->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;
+  gridptr->mapname[0]    = 0;
+  gridptr->mapping[0]    = 0;
   memset(gridptr->uuid, 0, CDI_UUID_SIZE);
   gridptr->name          = NULL;
   gridptr->vtable        = &cdiGridVtable;
-  gridptr->extraData     = NULL;
+  gridptr->atts.nalloc   = MAX_ATTRIBUTES;
+  gridptr->atts.nelems   = 0;
 }
 
 
-static void
-grid_free_components(grid_t *gridptr)
+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]);
+                     gridptr->x.vals, gridptr->y.vals,
+                     gridptr->x.bounds, gridptr->y.bounds,
+                     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]);
 }
 
 void grid_free(grid_t *gridptr)
@@ -188,46 +179,46 @@ void grid_free(grid_t *gridptr)
   grid_init(gridptr);
 }
 
-static grid_t *
-gridNewEntry(cdiResH resH)
+static
+grid_t *gridNewEntry(cdiResH resH)
 {
   grid_t *gridptr = (grid_t*) Malloc(sizeof(grid_t));
   grid_init(gridptr);
-  if (resH == CDI_UNDEFID)
+
+  if ( resH == CDI_UNDEFID )
     gridptr->self = reshPut(gridptr, &gridOps);
   else
     {
       gridptr->self = resH;
       reshReplace(resH, gridptr, &gridOps);
     }
+
   return gridptr;
 }
 
 static
 void gridInit(void)
 {
-  static int gridInitialized = 0;
-
+  static bool gridInitialized = false;
   if ( gridInitialized ) return;
-
-  gridInitialized = 1;
+  gridInitialized = true;
 
   const char *env = getenv("GRID_DEBUG");
   if ( env ) GRID_Debug = atoi(env);
 }
 
-static void
-grid_copy_base_scalar_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
+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)
+  if ( gridptrOrig->reference )
     gridptrDup->reference = strdupx(gridptrOrig->reference);
 }
 
 
-static grid_t *
-grid_copy_base(grid_t *gridptrOrig)
+static
+grid_t *grid_copy_base(grid_t *gridptrOrig)
 {
   grid_t *gridptrDup = (grid_t *)Malloc(sizeof (*gridptrDup));
   gridptrOrig->vtable->copyScalarFields(gridptrOrig, gridptrDup);
@@ -235,6 +226,7 @@ grid_copy_base(grid_t *gridptrOrig)
   return gridptrDup;
 }
 
+
 unsigned cdiGridCount(void)
 {
   return reshCountType(&gridOps);
@@ -256,100 +248,67 @@ void gridGetString(char *name, const char *gridstrname, size_t len)
   name[len - 1] = 0;
 }
 
-static inline void
-gridSetName(char *gridstrname, const char *name)
+static inline
+void gridSetName(char *gridstrname, const char *name)
 {
   strncpy(gridstrname, name, CDI_MAX_NAME);
   gridstrname[CDI_MAX_NAME - 1] = 0;
 }
 
-void
-cdiGridTypeInit(grid_t *gridptr, int gridtype, int size)
+
+void cdiGridTypeInit(grid_t *gridptr, int gridtype, int size)
 {
   gridptr->type = gridtype;
   gridptr->size = size;
 
+  if      ( gridtype == GRID_CURVILINEAR  ) gridptr->nvertex = 4;
+  else if ( gridtype == GRID_UNSTRUCTURED ) gridptr->x.size = size;
+
   switch (gridtype)
     {
-    case GRID_CURVILINEAR:
-      gridptr->nvertex = 4;
-      /* Fall through */
     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->xname[0] == 0 ) gridSetName(gridptr->xname, "tlon");
-            if ( gridptr->yname[0] == 0 ) gridSetName(gridptr->yname, "tlat");
+            if ( gridptr->x.name[0] == 0 ) gridSetName(gridptr->x.name, "tlon");
+            if ( gridptr->y.name[0] == 0 ) gridSetName(gridptr->y.name, "tlat");
           }
         else
           {
-            if ( gridptr->xname[0] == 0 ) gridSetName(gridptr->xname, "lon");
-            if ( gridptr->yname[0] == 0 ) gridSetName(gridptr->yname, "lat");
+            if ( gridptr->x.name[0] == 0 ) gridSetName(gridptr->x.name, "lon");
+            if ( gridptr->y.name[0] == 0 ) gridSetName(gridptr->y.name, "lat");
           }
-        gridSetName(gridptr->xlongname, "longitude");
-        gridSetName(gridptr->ylongname, "latitude");
 
-        /*
-        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");
-          }
+        gridSetName(gridptr->x.longname, "longitude");
+        gridSetName(gridptr->y.longname, "latitude");
+
+        gridptr->x.stdname = xystdname_tab[grid_xystdname_latlon][0];
+        gridptr->y.stdname = xystdname_tab[grid_xystdname_latlon][1];
+        gridSetName(gridptr->x.units, "degrees_east");
+        gridSetName(gridptr->y.units, "degrees_north");
 
-        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:
+    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");
 
-        /* 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");
+            gridptr->x.stdname = xystdname_tab[grid_xystdname_projection][0];
+            gridptr->y.stdname = xystdname_tab[grid_xystdname_projection][1];
+            gridSetName(gridptr->x.units, "m");
+            gridSetName(gridptr->y.units, "m");
+          }
         break;
       }
     }
@@ -551,11 +510,9 @@ int gridCreate(int gridtype, int size)
 static
 void gridDestroyKernel( grid_t * gridptr )
 {
-  int id;
-
   xassert ( gridptr );
 
-  id = gridptr->self;
+  int id = gridptr->self;
 
   grid_free_components(gridptr);
   Free( gridptr );
@@ -575,11 +532,12 @@ void gridDestroyKernel( grid_t * gridptr )
 */
 void gridDestroy(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   gridptr->vtable->destroy(gridptr);
 }
 
-void gridDestroyP ( void * gridptr )
+static
+void gridDestroyP(void * gridptr)
 {
   ((grid_t *)gridptr)->vtable->destroy((grid_t *)gridptr);
 }
@@ -589,7 +547,7 @@ const char *gridNamePtr(int gridtype)
 {
   int size = (int) (sizeof(Grids)/sizeof(Grids[0]));
 
-  const char *name = gridtype >= 0 && gridtype < size ? Grids[gridtype] : Grids[GRID_GENERIC];
+  const char *name = (gridtype >= 0 && gridtype < size) ? Grids[gridtype] : Grids[GRID_GENERIC];
 
   return name;
 }
@@ -601,25 +559,33 @@ void gridName(int gridtype, char *gridname)
 }
 
 static
-char *grid_key_to_string(grid_t *gridptr, int key)
+void *grid_key_to_ptr(grid_t *gridptr, int key)
 {
-  char *gridstring = NULL;
+  void *keyptr = NULL;
 
   switch (key)
     {
-    case CDI_GRID_XDIMNAME: gridstring = gridptr->xdimname; break;
-    case CDI_GRID_YDIMNAME: gridstring = gridptr->ydimname; break;
-    case CDI_GRID_VDIMNAME: gridstring = gridptr->vdimname; break;
+    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;
     }
 
-  return gridstring;
+  return keyptr;
 }
 
 /*
- at Function  cdiGridDefString
+ at Function  cdiGridDefKeyStr
 @Title     Define a CDI grid string value from a key
 
- at Prototype int cdiGridDefString(int gridID, int key, int size, const char *mesg)
+ at Prototype int cdiGridDefKeyStr(int gridID, int key, int size, const char *mesg)
 @Parameter
     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
     @Item  key      The key to be searched
@@ -627,37 +593,37 @@ char *grid_key_to_string(grid_t *gridptr, int key)
     @Item  mesg     The address of a string where the data will be read
 
 @Description
-The function @func{cdiGridDefString} defines a CDI grid string value from a key.
+The function @func{cdiGridDefKeyStr} defines a CDI grid string value from a key.
 
 @Result
- at func{cdiGridDefString} returns 0 if OK and integer value on error.
+ at func{cdiGridDefKeyStr} returns 0 if OK and integer value on error.
 
 @EndFunction
 */
-int cdiGridDefString(int gridID, int key, int size, const char *mesg)
+int cdiGridDefKeyStr(int gridID, int key, int size, const char *mesg)
 {
   if ( size < 1 || mesg == NULL || *mesg == 0 ) return -1;
 
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  char *gridstring = grid_key_to_string(gridptr, key);
-  if ( gridstring == NULL )
+  char *keyptr = (char*)grid_key_to_ptr(gridptr, key);
+  if ( keyptr == NULL )
     {
       Warning("CDI grid string key %d not supported!", key);
       return -1;
     }
 
-  gridSetString(gridstring, mesg, (size_t)size);
+  gridSetString(keyptr, mesg, (size_t)size);
   gridMark4Update(gridID);
 
   return 0;
 }
 
 /*
- at Function  cdiGridInqString
+ at Function  cdiGridInqKeyStr
 @Title     Get a CDI grid string value from a key
 
- at Prototype int cdiGridInqString(int gridID, int key, int size, char *mesg)
+ at Prototype int cdiGridInqKeyStr(int gridID, int key, int size, char *mesg)
 @Parameter
     @Item  gridID   Grid ID, from a previous call to @fref{gridCreate}.
     @Item  key      The key to be searched.
@@ -668,26 +634,26 @@ int cdiGridDefString(int gridID, int key, int size, const char *mesg)
                     is given by the predefined constant @func{CDI_MAX_NAME}.
 
 @Description
-The function @func{cdiGridInqString} return a CDI grid string value from a key.
+The function @func{cdiGridInqKeyStr} return a CDI grid string value from a key.
 
 @Result
- at func{cdiGridInqString} returns 0 if OK and integer value on error.
+ at func{cdiGridInqKeyStr} returns 0 if OK and integer value on error.
 
 @EndFunction
 */
-int cdiGridInqString(int gridID, int key, int size, char *mesg)
+int cdiGridInqKeyStr(int gridID, int key, int size, char *mesg)
 {
   if ( size < 1 || mesg == NULL ) return -1;
 
-  grid_t *gridptr = gridID2Ptr(gridID);
-  const char *gridstring = grid_key_to_string(gridptr, key);
-  if ( gridstring == NULL)
+  grid_t *gridptr = grid_to_pointer(gridID);
+  const char *keyptr = (const char*)grid_key_to_ptr(gridptr, key);
+  if ( keyptr == NULL)
     {
       Warning("CDI grid string key %d not supported!", key);
       return -1;
     }
 
-  gridGetString(mesg, gridstring, (size_t)size);
+  gridGetString(mesg, keyptr, (size_t)size);
 
   return 0;
 }
@@ -708,12 +674,7 @@ The function @func{gridDefXname} defines the name of a X-axis.
 */
 void gridDefXname(int gridID, const char *xname)
 {
-  if ( xname && *xname )
-    {
-      grid_t *gridptr = gridID2Ptr(gridID);
-      gridSetName(gridptr->xname, xname);
-      gridMark4Update(gridID);
-    }
+  (void)cdiGridDefKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, xname);
 }
 
 /*
@@ -732,12 +693,7 @@ The function @func{gridDefXlongname} defines the longname of a X-axis.
 */
 void gridDefXlongname(int gridID, const char *xlongname)
 {
-  if ( xlongname )
-    {
-      grid_t *gridptr = gridID2Ptr(gridID);
-      gridSetName(gridptr->xlongname, xlongname);
-      gridMark4Update(gridID);
-    }
+  (void)cdiGridDefKeyStr(gridID, CDI_KEY_XLONGNAME, CDI_MAX_NAME, xlongname);
 }
 
 /*
@@ -756,12 +712,7 @@ The function @func{gridDefXunits} defines the units of a X-axis.
 */
 void gridDefXunits(int gridID, const char *xunits)
 {
-  if ( xunits )
-    {
-      grid_t *gridptr = gridID2Ptr(gridID);
-      gridSetName(gridptr->xunits, xunits);
-      gridMark4Update(gridID);
-    }
+  (void)cdiGridDefKeyStr(gridID, CDI_KEY_XUNITS, CDI_MAX_NAME, xunits);
 }
 
 /*
@@ -780,12 +731,7 @@ The function @func{gridDefYname} defines the name of a Y-axis.
 */
 void gridDefYname(int gridID, const char *yname)
 {
-  if ( yname && *yname )
-    {
-      grid_t *gridptr = gridID2Ptr(gridID);
-      gridSetName(gridptr->yname, yname);
-      gridMark4Update(gridID);
-    }
+  (void)cdiGridDefKeyStr(gridID, CDI_KEY_YNAME, CDI_MAX_NAME, yname);
 }
 
 /*
@@ -804,12 +750,7 @@ The function @func{gridDefYlongname} defines the longname of a Y-axis.
 */
 void gridDefYlongname(int gridID, const char *ylongname)
 {
-  if ( ylongname )
-    {
-      grid_t *gridptr = gridID2Ptr(gridID);
-      gridSetName(gridptr->ylongname, ylongname);
-      gridMark4Update(gridID);
-    }
+  (void)cdiGridDefKeyStr(gridID, CDI_KEY_YLONGNAME, CDI_MAX_NAME, ylongname);
 }
 
 /*
@@ -828,12 +769,7 @@ The function @func{gridDefYunits} defines the units of a Y-axis.
 */
 void gridDefYunits(int gridID, const char *yunits)
 {
-  if ( yunits )
-    {
-      grid_t *gridptr = gridID2Ptr(gridID);
-      gridSetName(gridptr->yunits, yunits);
-      gridMark4Update(gridID);
-    }
+  (void)cdiGridDefKeyStr(gridID, CDI_KEY_YUNITS, CDI_MAX_NAME, yunits);
 }
 
 /*
@@ -857,15 +793,7 @@ The function @func{gridInqXname} returns the name of a X-axis.
 */
 void gridInqXname(int gridID, char *xname)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  strcpy(xname, gridptr->xname);
-}
-
-const char *gridInqXnamePtr(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->xname;
+  (void)cdiGridInqKeyStr(gridID, CDI_KEY_XNAME, CDI_MAX_NAME, xname);
 }
 
 /*
@@ -889,9 +817,7 @@ The function @func{gridInqXlongname} returns the longname of a X-axis.
 */
 void gridInqXlongname(int gridID, char *xlongname)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  strcpy(xlongname, gridptr->xlongname);
+  (void)cdiGridInqKeyStr(gridID, CDI_KEY_XLONGNAME, CDI_MAX_NAME, xlongname);
 }
 
 /*
@@ -915,19 +841,18 @@ The function @func{gridInqXunits} returns the units of a X-axis.
 */
 void gridInqXunits(int gridID, char *xunits)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  strcpy(xunits, gridptr->xunits);
+  (void)cdiGridInqKeyStr(gridID, CDI_KEY_XUNITS, CDI_MAX_NAME, xunits);
 }
 
 
 void gridInqXstdname(int gridID, char *xstdname)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  if ( gridptr->xstdname )
-    strcpy(xstdname, gridptr->xstdname);
-  else
-    xstdname[0] = 0;
+  if ( xstdname )
+    {
+      xstdname[0] = 0;
+      grid_t *gridptr = grid_to_pointer(gridID);
+      if ( gridptr->x.stdname ) strcpy(xstdname, gridptr->x.stdname);
+    }
 }
 
 /*
@@ -951,22 +876,14 @@ The function @func{gridInqYname} returns the name of a Y-axis.
 */
 void gridInqYname(int gridID, char *yname)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  strcpy(yname, gridptr->yname);
-}
-
-const char *gridInqYnamePtr(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-  return gridptr->yname;
+  (void)cdiGridInqKeyStr(gridID, CDI_KEY_YNAME, CDI_MAX_NAME, yname);
 }
 
 /*
 @Function  gridInqYlongname
 @Title     Get the longname of a Y-axis
 
- at Prototype void gridInqXlongname(int gridID, char *longname)
+ at Prototype void gridInqYlongname(int gridID, char *longname)
 @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
@@ -983,9 +900,7 @@ The function @func{gridInqYlongname} returns the longname of a Y-axis.
 */
 void gridInqYlongname(int gridID, char *ylongname)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  strcpy(ylongname, gridptr->ylongname);
+  (void)cdiGridInqKeyStr(gridID, CDI_KEY_YLONGNAME, CDI_MAX_NAME, ylongname);
 }
 
 /*
@@ -1009,18 +924,80 @@ The function @func{gridInqYunits} returns the units of a Y-axis.
 */
 void gridInqYunits(int gridID, char *yunits)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  strcpy(yunits, gridptr->yunits);
+  (void)cdiGridInqKeyStr(gridID, CDI_KEY_YUNITS, CDI_MAX_NAME, yunits);
 }
 
+
 void gridInqYstdname(int gridID, char *ystdname)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  if ( gridptr->ystdname )
-    strcpy(ystdname, gridptr->ystdname);
-  else
-    ystdname[0] = 0;
+  if ( ystdname )
+    {
+      ystdname[0] = 0;
+      grid_t *gridptr = grid_to_pointer(gridID);
+      if ( gridptr->y.stdname ) strcpy(ystdname, gridptr->y.stdname);
+    }
+}
+
+
+void gridDefProj(int gridID, int projID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->proj = projID;
+
+  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);
+    }
+}
+
+
+int gridInqProj(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->proj;
+}
+
+
+int gridInqProjType(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+
+  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;
+
+          gridptr->projtype = projtype;
+        }
+    }
+
+  return projtype;
+}
+
+
+void gridVerifyProj(int gridID)
+{
+  grid_t *gridptr = grid_to_pointer(gridID);
+
+  int projtype = gridInqProjType(gridID);
+
+  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");
+    }
 }
 
 /*
@@ -1045,7 +1022,7 @@ The valid CDI grid types are @func{GRID_GENERIC}, @func{GRID_GAUSSIAN},
 */
 int gridInqType(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
   return gridptr->type;
 }
@@ -1069,14 +1046,14 @@ The function @func{gridInqSize} returns the size of a Grid.
 */
 int gridInqSize(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
   int size = gridptr->size;
 
   if ( size == 0 )
     {
-      int xsize = gridptr->xsize;
-      int ysize = gridptr->ysize;
+      int xsize = gridptr->x.size;
+      int ysize = gridptr->y.size;
 
       if ( ysize )
         size = xsize * ysize;
@@ -1105,7 +1082,7 @@ int nsp2trunc(int nsp)
 
 int gridInqTrunc(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
   if ( gridptr->trunc == 0 )
     {
@@ -1113,7 +1090,7 @@ int gridInqTrunc(int gridID)
         gridptr->trunc = nsp2trunc(gridptr->size);
       /*
       else if      ( gridptr->type == GRID_GAUSSIAN )
-        gridptr->trunc = nlat2trunc(gridptr->ysize);
+        gridptr->trunc = nlat2trunc(gridptr->y.size);
       */
     }
 
@@ -1123,7 +1100,7 @@ int gridInqTrunc(int gridID)
 
 void gridDefTrunc(int gridID, int trunc)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
   if ( gridptr->trunc != trunc )
     {
@@ -1148,7 +1125,7 @@ The function @func{gridDefXsize} defines the number of values of a X-axis.
 */
 void gridDefXsize(int gridID, int xsize)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
   int gridSize = gridInqSize(gridID);
   if ( xsize > gridSize )
@@ -1158,18 +1135,18 @@ void gridDefXsize(int gridID, int xsize)
   if ( gridType == GRID_UNSTRUCTURED && xsize != gridSize )
     Error("xsize %d must be equal to gridsize %d for gridtype: UNSTRUCTURED", xsize, gridSize);
 
-  if ( gridptr->xsize != xsize )
+  if ( gridptr->x.size != xsize )
     {
       gridMark4Update(gridID);
-      gridptr->xsize = xsize;
+      gridptr->x.size = xsize;
     }
 
-  if ( gridType != GRID_UNSTRUCTURED )
+  if ( gridType != GRID_UNSTRUCTURED && gridType != GRID_PROJECTION )
     {
-      long axisproduct = gridptr->xsize*gridptr->ysize;
+      long axisproduct = gridptr->x.size*gridptr->y.size;
       if ( axisproduct > 0 && axisproduct != gridSize )
         Error("Inconsistent grid declaration! (xsize=%d ysize=%d gridsize=%d)",
-              gridptr->xsize, gridptr->ysize, gridSize);
+              gridptr->x.size, gridptr->y.size, gridSize);
     }
 }
 
@@ -1185,7 +1162,7 @@ void gridDefXsize(int gridID, int xsize)
 */
 void gridDefPrec(int gridID, int prec)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
   if ( gridptr->prec != prec )
     {
@@ -1206,8 +1183,7 @@ void gridDefPrec(int gridID, int prec)
 */
 int gridInqPrec(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
+  grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->prec;
 }
 
@@ -1229,9 +1205,8 @@ The function @func{gridInqXsize} returns the number of values of a X-axis.
 */
 int gridInqXsize(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  return gridptr->xsize;
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->x.size;
 }
 
 /*
@@ -1250,28 +1225,29 @@ The function @func{gridDefYsize} defines the number of values of a Y-axis.
 */
 void gridDefYsize(int gridID, int ysize)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(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 )
+  int gridType = gridInqType(gridID);
+  if ( gridType == GRID_UNSTRUCTURED && ysize != gridSize )
     Error("ysize %d must be equal gridsize %d for gridtype: UNSTRUCTURED", ysize, gridSize);
 
-  if ( gridptr->ysize != ysize )
+  if ( gridptr->y.size != ysize )
     {
       gridMark4Update(gridID);
-      gridptr->ysize = ysize;
+      gridptr->y.size = ysize;
     }
 
-  if ( gridInqType(gridID) != GRID_UNSTRUCTURED )
+  if ( gridType != GRID_UNSTRUCTURED && gridType != GRID_PROJECTION )
     {
-      long axisproduct = gridptr->xsize*gridptr->ysize;
+      long axisproduct = gridptr->x.size*gridptr->y.size;
       if ( axisproduct > 0 && axisproduct != gridSize )
         Error("Inconsistent grid declaration! (xsize=%d ysize=%d gridsize=%d)",
-              gridptr->xsize, gridptr->ysize, gridSize);
+              gridptr->x.size, gridptr->y.size, gridSize);
     }
 }
 
@@ -1293,9 +1269,8 @@ The function @func{gridInqYsize} returns the number of values of a Y-axis.
 */
 int gridInqYsize(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  return gridptr->ysize;
+  grid_t *gridptr = grid_to_pointer(gridID);
+  return gridptr->y.size;
 }
 
 /*
@@ -1315,7 +1290,7 @@ of a Gaussian grid.
 */
 void gridDefNP(int gridID, int np)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
   if ( gridptr->np != np )
     {
@@ -1343,8 +1318,7 @@ of a Gaussian grid.
 */
 int gridInqNP(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
+  grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->np;
 }
 
@@ -1360,7 +1334,7 @@ int gridInqNP(int gridID)
 */
 void gridDefRowlon(int gridID, int nrowlon, const int rowlon[])
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
   gridptr->rowlon = (int *) Malloc((size_t)nrowlon * sizeof(int));
   gridptr->nrowlon = nrowlon;
@@ -1380,7 +1354,7 @@ void gridDefRowlon(int gridID, int nrowlon, const int rowlon[])
 */
 void gridInqRowlon(int gridID, int *rowlon)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
   if ( gridptr->rowlon == 0 )  Error("undefined pointer!");
 
@@ -1418,7 +1392,7 @@ gridInqMaskSerial(grid_t *gridptr, int *mask)
 
 int gridInqMask(int gridID, int *mask)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->vtable->inqMask(gridptr, mask);
 }
 
@@ -1452,7 +1426,7 @@ gridDefMaskSerial(grid_t *gridptr, const int *mask)
 
 void gridDefMask(int gridID, const int *mask)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   gridptr->vtable->defMask(gridptr, mask);
   gridMark4Update(gridID);
 }
@@ -1465,7 +1439,7 @@ gridInqMaskGMESerial(grid_t *gridptr, int *mask_gme)
 
 int gridInqMaskGME(int gridID, int *mask)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->vtable->inqMaskGME(gridptr, mask);
 }
 
@@ -1488,14 +1462,14 @@ gridDefMaskGMESerial(grid_t *gridptr, const int *mask)
 
 void gridDefMaskGME(int gridID, const int *mask)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   gridptr->vtable->defMaskGME(gridptr, mask);
   gridMark4Update(gridID);
 }
 
 
-static int
-gridInqXValsSerial(grid_t *gridptr, double *xvals)
+static
+int gridInqXValsSerial(grid_t *gridptr, double *xvals)
 {
   long size;
   if ( gridptr->type == GRID_CURVILINEAR || gridptr->type == GRID_UNSTRUCTURED )
@@ -1503,12 +1477,12 @@ gridInqXValsSerial(grid_t *gridptr, double *xvals)
   else if ( gridptr->type == GRID_GAUSSIAN_REDUCED )
     size = 2;
   else
-    size = gridptr->xsize;
+    size = gridptr->x.size;
 
   if ( CDI_Debug && size == 0 )
     Warning("size undefined for gridID = %d", gridptr->self);
 
-  if ( gridptr->xvals )
+  if ( gridptr->x.vals )
     {
       if ( size && xvals )
         {
@@ -1544,13 +1518,13 @@ Otherwise, 0 is returned and @func{xvals} is empty.
 */
 int gridInqXvals(int gridID, double *xvals)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->vtable->inqXVals(gridptr, xvals);
 }
 
 
-static void
-gridDefXValsSerial(grid_t *gridptr, const double *xvals)
+static
+void gridDefXValsSerial(grid_t *gridptr, const double *xvals)
 {
   int gridtype = gridptr->type;
 
@@ -1560,16 +1534,16 @@ gridDefXValsSerial(grid_t *gridptr, const double *xvals)
   else if ( gridtype == GRID_GAUSSIAN_REDUCED )
     size = 2;
   else
-    size = gridptr->xsize;
+    size = gridptr->x.size;
 
   if ( size == 0 )
     Error("Size undefined for gridID = %d", gridptr->self);
 
-  if (gridptr->xvals && CDI_Debug)
+  if (gridptr->x.vals && CDI_Debug)
     Warning("values already defined!");
-  gridptr->xvals = (double *)Realloc(gridptr->xvals,
+  gridptr->x.vals = (double *)Realloc(gridptr->x.vals,
                                       (size_t)size * sizeof(double));
-  memcpy(gridptr->xvals, xvals, (size_t)size * sizeof (double));
+  memcpy(gridptr->x.vals, xvals, (size_t)size * sizeof (double));
 }
 
 /*
@@ -1588,23 +1562,22 @@ The function @func{gridDefXvals} defines all values of the X-axis.
 */
 void gridDefXvals(int gridID, const double *xvals)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   gridptr->vtable->defXVals(gridptr, xvals);
   gridMark4Update(gridID);
 }
 
-static int
-gridInqYValsSerial(grid_t *gridptr, double *yvals)
+static
+int gridInqYValsSerial(grid_t *gridptr, double *yvals)
 {
   int gridtype = gridptr->type;
-  long size
-    = (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
-    ? gridptr->size : gridptr->ysize;
+  long size = (gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED)
+            ? gridptr->size : gridptr->y.size;
 
   if ( CDI_Debug && size == 0 )
     Warning("size undefined for gridID = %d!", gridptr->self);
 
-  if ( gridptr->yvals )
+  if ( gridptr->y.vals )
     {
       if ( size && yvals )
         {
@@ -1640,26 +1613,25 @@ Otherwise, 0 is returned and @func{yvals} is empty.
 */
 int gridInqYvals(int gridID, double *yvals)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->vtable->inqYVals(gridptr, yvals);
 }
 
-static void
-gridDefYValsSerial(grid_t *gridptr, const double *yvals)
+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;
+  long 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->yvals && CDI_Debug)
+  if ( gridptr->y.vals && CDI_Debug )
     Warning("Values already defined!");
 
-  gridptr->yvals = (double *)Realloc(gridptr->yvals, (size_t)size * sizeof (double));
-  memcpy(gridptr->yvals, yvals, (size_t)size * sizeof (double));
+  gridptr->y.vals = (double *)Realloc(gridptr->y.vals, (size_t)size * sizeof (double));
+  memcpy(gridptr->y.vals, yvals, (size_t)size * sizeof (double));
 }
 
 
@@ -1679,7 +1651,7 @@ The function @func{gridDefYvals} defines all values of the Y-axis.
 */
 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);
 }
@@ -1687,21 +1659,21 @@ void gridDefYvals(int gridID, const double *yvals)
 static double
 gridInqXValSerial(grid_t *gridptr, int index)
 {
-  double xval = gridptr->xvals ? gridptr->xvals[index] : 0;
+  double xval = gridptr->x.vals ? gridptr->x.vals[index] : 0;
   return xval;
 }
 
 
 double gridInqXval(int gridID, int index)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->vtable->inqXVal(gridptr, index);
 }
 
 static double
 gridInqYValSerial(grid_t *gridptr, int index)
 {
-  double yval = gridptr->yvals ? gridptr->yvals[index] : 0;
+  double yval = gridptr->y.vals ? gridptr->y.vals[index] : 0;
   return yval;
 }
 
@@ -1717,7 +1689,7 @@ gridInqYValSerial(grid_t *gridptr, int index)
 */
 double gridInqYval(int gridID, int index)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->vtable->inqYVal(gridptr, index);
 }
 
@@ -1733,24 +1705,24 @@ double gridInqYval(int gridID, int index)
 */
 double gridInqXinc(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  double xinc = gridptr->xinc;
+  grid_t *gridptr = grid_to_pointer(gridID);
+  double xinc = gridptr->x.inc;
   const double *restrict xvals = gridptr->vtable->inqXValsPtr(gridptr);
 
   if ( (! (fabs(xinc) > 0)) && xvals )
     {
-      int xsize = gridptr->xsize;
+      int xsize = gridptr->x.size;
       if ( xsize > 1 )
         {
           xinc = fabs(xvals[xsize-1] - xvals[0])/(xsize-1);
-          for (size_t i = 2; i < (size_t)xsize; i++ )
+          for ( int i = 2; i < xsize; i++ )
             if ( fabs(fabs(xvals[i-1] - xvals[i]) - xinc) > 0.01*xinc )
               {
                 xinc = 0;
                 break;
               }
 
-          gridptr->xinc = xinc;
+          gridptr->x.inc = xinc;
         }
     }
 
@@ -1769,13 +1741,13 @@ double gridInqXinc(int gridID)
 */
 double gridInqYinc(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-  double yinc = gridptr->yinc;
+  grid_t *gridptr = grid_to_pointer(gridID);
+  double yinc = gridptr->y.inc;
   const double *yvals = gridptr->vtable->inqYValsPtr(gridptr);
 
   if ( (! (fabs(yinc) > 0)) && yvals )
     {
-      int ysize = gridptr->ysize;
+      int ysize = gridptr->y.size;
       if ( ysize > 1 )
         {
           yinc = yvals[1] - yvals[0];
@@ -1787,7 +1759,7 @@ double gridInqYinc(int gridID)
                 break;
               }
 
-          gridptr->yinc = yinc;
+          gridptr->y.inc = yinc;
         }
     }
 
@@ -1804,161 +1776,39 @@ double gridInqYinc(int gridID)
 
 @EndFunction
 */
-double gridInqXpole(int gridID)
-{
-  // Xpole -> grid_north_pole_longitude
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  return gridptr->xpole;
-}
-
-/*
- at Function
- at Title
-
- at Prototype
- at Parameter
-    @Item  Grid identifier
-
- at EndFunction
-*/
-void gridDefXpole(int gridID, double xpole)
-{
-  // Xpole -> grid_north_pole_longitude
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  if ( gridptr->xstdname && memcmp(gridptr->xstdname, "grid", 4) != 0 )
-    gridptr->xstdname = xystdname_tab[grid_xystdname_grid_latlon][0];
-
-  if ( gridptr->isRotated != TRUE || IS_NOT_EQUAL(gridptr->xpole, xpole) )
-    {
-      gridptr->isRotated = TRUE;
-      gridptr->xpole = xpole;
-      gridMark4Update(gridID);
-    }
-}
-
-/*
- at Function
- at Title
-
- at Prototype
- at Parameter
-    @Item  Grid identifier
-
- at EndFunction
-*/
-double gridInqYpole(int gridID)
+void gridInqParamRLL(int gridID, double *xpole, double *ypole, double *angle)
 {
-  // Ypole -> grid_north_pole_latitude
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  return gridptr->ypole;
-}
+  *xpole = 0; *ypole = 0; *angle = 0;
 
-/*
- at Function
- at Title
-
- at Prototype
- at Parameter
-    @Item  Grid identifier
-
- at EndFunction
-*/
-void gridDefYpole(int gridID, double ypole)
-{
-  // Ypole -> grid_north_pole_latitude
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  if ( gridptr->ystdname && memcmp(gridptr->ystdname, "grid", 4) != 0 )
-    gridptr->ystdname = xystdname_tab[grid_xystdname_grid_latlon][1];
-
-  if ( gridptr->isRotated != TRUE || IS_NOT_EQUAL(gridptr->ypole, ypole) )
+  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 )
     {
-      gridptr->isRotated = TRUE;
-      gridptr->ypole = ypole;
-      gridMark4Update(gridID);
-    }
-}
-
-/*
- at Function
- at Title
-
- at Prototype
- at Parameter
-    @Item  Grid identifier
-
- at EndFunction
-*/
-double gridInqAngle(int gridID)
-{
-  // Angle -> north_pole_grid_longitude
-  grid_t *gridptr = gridID2Ptr(gridID);
+      int atttype, attlen;
+      char attname[CDI_MAX_NAME+1];
 
-  return gridptr->angle;
-}
-
-/*
- at Function
- at Title
-
- at Prototype
- at Parameter
-    @Item  Grid identifier
-
- at EndFunction<
-*/
-void gridDefAngle(int gridID, double angle)
-{
-  // Angle -> north_pole_grid_longitude
-  grid_t *gridptr = gridID2Ptr(gridID);
+      int natts;
+      cdiInqNatts(gridID, CDI_GLOBAL, &natts);
 
-  if ( gridptr->isRotated != TRUE || IS_NOT_EQUAL(gridptr->angle, angle) )
-    {
-      gridptr->isRotated = TRUE;
-      gridptr->angle = angle;
-      gridMark4Update(gridID);
-    }
-}
-
-/*
- at Function
- at Title
-
- at Prototype
- at Parameter
-    @Item  Grid identifier
-
- at EndFunction
-*/
-int gridInqGMEnd(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  return gridptr->nd;
-}
-
-/*
- at Function
- at Title
-
- at Prototype
- at Parameter
-    @Item  Grid identifier
+      for ( int iatt = 0; iatt < natts; ++iatt )
+        {
+          cdiInqAtt(gridID, CDI_GLOBAL, iatt, attname, &atttype, &attlen);
 
- at EndFunction
-*/
-void gridDefGMEnd(int gridID, int nd)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
+          if ( attlen != 1 ) continue;
 
-  if (gridptr->nd != nd)
-    {
-      gridptr->nd = nd;
-      gridMark4Update(gridID);
+          if ( atttype == CDI_DATATYPE_FLT32 || atttype == CDI_DATATYPE_FLT64 )
+            {
+              double attflt;
+              cdiInqAttFlt(gridID, CDI_GLOBAL, 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);
 }
 
 /*
@@ -1971,49 +1821,21 @@ void gridDefGMEnd(int gridID, int nd)
 
 @EndFunction
 */
-int gridInqGMEni(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  return gridptr->ni;
-}
-
-/*
- at Function
- at Title
-
- at Prototype
- at Parameter
-    @Item  Grid identifier
-
- at EndFunction
-*/
-void gridDefGMEni(int gridID, int ni)
+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->ni != ni )
-    {
-      gridptr->ni = ni;
-      gridMark4Update(gridID);
-    }
-}
+  const char *mapping = "rotated_latitude_longitude";
+  cdiGridDefKeyStr(gridID, CDI_KEY_MAPNAME, CDI_MAX_NAME, mapping);
+  cdiDefAttTxt(gridID, CDI_GLOBAL, "grid_mapping_name", 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);
 
-/*
- at Function
- at Title
+  grid_t *gridptr = grid_to_pointer(gridID);
+  gridptr->projtype = CDI_PROJ_RLL;
 
- at Prototype
- at Parameter
-    @Item  Grid identifier
-
- at EndFunction
-*/
-int gridInqGMEni2(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  return gridptr->ni2;
+  gridVerifyProj(gridID);
 }
 
 /*
@@ -2026,15 +1848,14 @@ int gridInqGMEni2(int gridID)
 
 @EndFunction
 */
-void gridDefGMEni2(int gridID, int ni2)
+void gridInqParamGME(int gridID, int *nd, int *ni, int *ni2, int *ni3)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
-  if ( gridptr->ni2 != ni2 )
-    {
-      gridptr->ni2 = ni2;
-      gridMark4Update(gridID);
-    }
+  *nd  = gridptr->gme.nd;
+  *ni  = gridptr->gme.ni;
+  *ni2 = gridptr->gme.ni2;
+  *ni3 = gridptr->gme.ni3;
 }
 
 /*
@@ -2047,20 +1868,16 @@ void gridDefGMEni2(int gridID, int ni2)
 
 @EndFunction
 */
-int gridInqGMEni3(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  return gridptr->ni3;
-}
-
-void gridDefGMEni3(int gridID, int ni3)
+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 ( gridptr->ni3 != ni3 )
+  if ( gridptr->gme.nd != nd )
     {
-      gridptr->ni3 = ni3;
+      gridptr->gme.nd  = nd;
+      gridptr->gme.ni  = ni;
+      gridptr->gme.ni2 = ni2;
+      gridptr->gme.ni3 = ni3;
       gridMark4Update(gridID);
     }
 }
@@ -2077,7 +1894,7 @@ void gridDefGMEni3(int gridID, int ni3)
 */
 void gridChangeType(int gridID, int gridtype)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
   if ( CDI_Debug )
     Message("Changed grid type from %s to %s", gridNamePtr(gridptr->type), gridNamePtr(gridtype));
@@ -2094,8 +1911,8 @@ 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;
+  size_t xsize = gridptr->x.size >= 0 ? (size_t)gridptr->x.size : 0,
+    ysize = gridptr->y.size >= 0 ? (size_t)gridptr->y.size : 0;
   const double *xvals = gridptr->vtable->inqXValsPtr(gridptr),
     (*xbounds)[numVertices]
     = (const double (*)[numVertices])gridptr->vtable->inqXBoundsPtr(gridptr);
@@ -2181,27 +1998,19 @@ void grid_check_cyclic(grid_t *gridptr)
 
 int gridIsCircular(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
   if ( gridptr->isCyclic == CDI_UNDEFID ) grid_check_cyclic(gridptr);
 
   return gridptr->isCyclic;
 }
 
-
-int gridIsRotated(int gridID)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  return gridptr->isRotated;
-}
-
 static
 bool compareXYvals(grid_t *gridRef, grid_t *gridTest)
 {
   bool differ = false;
 
-  int xsizeTest = gridTest->xsize, ysizeTest = gridTest->ysize;
+  int 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),
@@ -2234,96 +2043,95 @@ static
 bool compareXYvals2(grid_t *gridRef, grid_t *gridTest)
 {
   int gridsize = gridTest->size;
-  bool differ
-    = ((gridTest->xvals == NULL) ^ (gridRef->xvals == NULL))
-    || ((gridTest->yvals == NULL) ^ (gridRef->yvals == NULL));
+  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);
   inqVal inqXValRef = gridRef->vtable->inqXVal,
-    inqYValRef = gridRef->vtable->inqXVal,
-    inqXValTest = gridTest->vtable->inqXVal,
-    inqYValTest = gridTest->vtable->inqYVal;
+         inqYValRef = gridRef->vtable->inqYVal,
+         inqXValTest = gridTest->vtable->inqXVal,
+         inqYValTest = gridTest->vtable->inqYVal;
 
-  if ( !differ && gridTest->xvals )
+  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;
+          || fabs(inqXValTest(gridTest, gridsize-1) - inqXValRef(gridRef, gridsize-1)) > 1.e-9;
 
-  if ( !differ && gridTest->yvals )
+  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;
+          || fabs(inqYValTest(gridTest, gridsize-1) - inqYValRef(gridRef, gridsize-1)) > 1.e-9;
 
   return differ;
 }
 
 static
-bool gridCompare(int gridID, const grid_t *grid)
+bool gridCompare(int gridID, const grid_t *grid, bool coord_compare)
 {
   bool differ = true;
-  grid_t *gridRef = gridID2Ptr(gridID);
+  const grid_t *gridRef = grid_to_pointer(gridID);
 
   if ( grid->type == gridRef->type || grid->type == GRID_GENERIC )
     {
       if ( grid->size == gridRef->size )
 	{
 	  differ = false;
-	  if ( grid->type == GRID_LONLAT )
+	  if ( grid->type == GRID_LONLAT || grid->type == GRID_PROJECTION )
 	    {
 	      /*
 	      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.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.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->xinc);
-	      printf("grid.yinc   %f\n", grid->yinc);
+	      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->xsize == gridRef->xsize && grid->ysize == gridRef->ysize )
+	      if ( grid->x.size == gridRef->x.size && grid->y.size == gridRef->y.size )
 		{
-		  if ( grid->xdef == 2 && grid->ydef == 2 )
+		  if ( grid->x.flag == 2 && grid->y.flag == 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_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->xfirst, gridInqXval(gridID, 0)) ||
-			       IS_NOT_EQUAL(grid->yfirst, gridInqYval(gridID, 0)))
+			  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->xinc) > 0 &&
-			       fabs(fabs(grid->xinc) - fabs(gridRef->xinc)) > fabs(grid->xinc/1000))
+			  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->yinc) > 0 &&
-			       fabs(fabs(grid->yinc) - fabs(gridRef->yinc)) > fabs(grid->yinc/1000))
+			  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->xvals && grid->yvals )
-                    differ = gridRef->vtable->compareXYFull(gridRef, (grid_t *)grid);
+		  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->xsize == gridRef->xsize && grid->ysize == gridRef->ysize )
+	      if ( grid->x.size == gridRef->x.size && grid->y.size == gridRef->y.size )
 		{
-		  if ( grid->xdef == 1 && grid->ydef == 1
-                       && grid->xvals && grid->yvals )
-                    differ = gridRef->vtable->compareXYFull(gridRef, (grid_t *)grid);
+		  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->ysize == 0 || grid->ysize == 1) &&
-			grid->xsize == gridRef->xsize*gridRef->ysize )
+	      else if ( (grid->y.size == 0 || grid->y.size == 1) &&
+			grid->x.size == gridRef->x.size*gridRef->y.size )
 		{
 		}
 	      else
@@ -2331,21 +2139,21 @@ bool gridCompare(int gridID, const grid_t *grid)
 	    }
 	  else if ( grid->type == GRID_GAUSSIAN )
 	    {
-	      if ( grid->xsize == gridRef->xsize && grid->ysize == gridRef->ysize )
+	      if ( grid->x.size == gridRef->x.size && grid->y.size == gridRef->y.size )
 		{
-		  if ( grid->xdef == 2 && grid->ydef == 2 )
+		  if ( grid->x.flag == 2 && grid->y.flag == 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)) )
+		      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->xvals && grid->yvals )
-                    differ = gridRef->vtable->compareXYFull(gridRef, (grid_t *)grid);
+		  else if ( grid->x.vals && grid->y.vals )
+                    differ = gridRef->vtable->compareXYFull((grid_t *)gridRef, (grid_t *)grid);
 		}
 	      else
 		differ = true;
@@ -2354,62 +2162,79 @@ bool gridCompare(int gridID, const grid_t *grid)
 	    {
 	      /*
 	      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.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->xvals[grid->size-1]);
-	      printf("grid.ylast  %f\n", grid->yvals[grid->size-1]);
+	      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->xsize == gridRef->xsize && grid->ysize == gridRef->ysize )
-                differ = gridRef->vtable->compareXYAO(gridRef, (grid_t *)grid);
+	      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 )
 	    {
-              /* 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->xvals == NULL) ^ (gridRef->xvals == NULL)) &&
-                   ((grid->yvals == NULL) ^ (gridRef->yvals == NULL)) )
+              if ( coord_compare )
                 {
-                  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) ) );
+                  differ = grid->nvertex != gridRef->nvertex
+                    || gridRef->vtable->compareXYAO((grid_t *)gridRef, (grid_t *)grid);
                 }
-              else if ( !differ )
+              else
                 {
-                  differ = grid->nvertex != gridRef->nvertex
-                    || grid->number != gridRef->number
-                    || (grid->number > 0 && grid->position != gridRef->position)
-                    || gridRef->vtable->compareXYAO(gridRef, (grid_t *)grid);
+                  /* 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);
+                    }
                 }
-              }
+            }
 	}
     }
 
   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 )
+int gridCompareP(void *gridptr1, void *gridptr2)
 {
-  grid_t * g1 = ( grid_t * ) gridptr1;
-  grid_t * g2 = ( grid_t * ) gridptr2;
+  grid_t *g1 = ( grid_t * ) gridptr1;
+  grid_t *g2 = ( grid_t * ) gridptr2;
   enum { equal = 0,
          differ = -1 };
   int i, size;
@@ -2419,62 +2244,48 @@ int gridCompareP ( void * gridptr1, void * gridptr2 )
 
   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->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->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->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->xsize         != g2->xsize        ) return differ;
-  if ( g1->ysize         != g2->ysize        ) 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 ( 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;
+  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->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;
 
   const double *restrict g1_xvals = g1->vtable->inqXValsPtr(g1),
-    *restrict g2_xvals = g2->vtable->inqXValsPtr(g2);
+               *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;
+        size = g1->x.size;
       xassert ( size );
 
       if ( !g2_xvals ) return differ;
@@ -2486,13 +2297,13 @@ int gridCompareP ( void * gridptr1, void * gridptr2 )
     return differ;
 
   const double *restrict g1_yvals = g1->vtable->inqYValsPtr(g1),
-    *restrict g2_yvals = g2->vtable->inqYValsPtr(g2);
+               *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;
+	size = g1->y.size;
       xassert ( size );
 
       if ( !g2_yvals ) return differ;
@@ -2504,7 +2315,7 @@ int gridCompareP ( void * gridptr1, void * gridptr2 )
     return differ;
 
   const double *restrict g1_area = g1->vtable->inqAreaPtr(g1),
-    *restrict g2_area = g2->vtable->inqAreaPtr(g2);
+               *restrict g2_area = g2->vtable->inqAreaPtr(g2);
   if ( g1_area )
     {
       xassert ( g1->size );
@@ -2525,7 +2336,7 @@ int gridCompareP ( void * gridptr1, void * gridptr2 )
         if ( g1->type == GRID_CURVILINEAR || g1->type == GRID_UNSTRUCTURED )
           size = g1->nvertex * g1->size;
         else
-          size = g1->nvertex * g1->xsize;
+          size = g1->nvertex * g1->x.size;
         xassert ( size );
 
         if ( !(g2_xbounds = g2->vtable->inqXBoundsPtr(g2)) ) return differ;
@@ -2545,26 +2356,28 @@ int gridCompareP ( void * gridptr1, void * gridptr2 )
         if ( g1->type == GRID_CURVILINEAR || g1->type == GRID_UNSTRUCTURED )
           size = g1->nvertex * g1->size;
         else
-          size = g1->nvertex * g1->ysize;
+          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->ybounds[i], g2->ybounds[i]) ) return differ;
+          if ( IS_NOT_EQUAL(g1->y.bounds[i], g2->y.bounds[i]) ) return differ;
       }
     else if ( g2->vtable->inqYBoundsPtr(g2) )
       return differ;
   }
 
-  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;
+  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;
+
+  if (strcmp(g1->mapping, g2->mapping)) return differ;
 
   if ( g1->reference )
     {
@@ -2592,13 +2405,14 @@ int gridCompareP ( void * gridptr1, void * gridptr2 )
   else if ( g2->mask_gme )
     return differ;
 
-  if (memcmp(g1->uuid, g2->uuid, CDI_UUID_SIZE))
+  if ( memcmp(g1->uuid, g2->uuid, CDI_UUID_SIZE) )
     return differ;
 
   return equal;
 }
 
-static void gridComplete(grid_t *grid)
+static
+void gridComplete(grid_t *grid)
 {
   int gridID = grid->self;
   gridDefPrec(gridID, grid->prec);
@@ -2612,83 +2426,63 @@ static void gridComplete(grid_t *grid)
     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);
+	if ( grid->x.size > 0 ) gridDefXsize(gridID, grid->x.size);
+	if ( grid->y.size > 0 ) gridDefYsize(gridID, grid->y.size);
 
         if ( gridtype == GRID_GAUSSIAN ) gridDefNP(gridID, grid->np);
 
 	if ( grid->nvertex > 0 )
 	  gridDefNvertex(gridID, grid->nvertex);
 
-	if ( grid->xdef == 2 )
+	if ( grid->x.flag == 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;
+            assert(gridtype != GRID_UNSTRUCTURED && gridtype != GRID_CURVILINEAR);
+	    double *xvals = (double *) Malloc((size_t)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->xinc);
+	    gridDefXinc(gridID, grid->x.inc);
 	    */
 	  }
 
-	if ( grid->ydef == 2 )
+	if ( grid->y.flag == 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;
+            assert(gridtype != GRID_UNSTRUCTURED && gridtype != GRID_CURVILINEAR);
+	    double *yvals = (double *) Malloc((size_t)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->yinc);
+	    gridDefYinc(gridID, grid->y.inc);
 	    */
 	  }
 
-	if ( grid->isRotated )
+	if ( grid->projtype == CDI_PROJ_RLL )
 	  {
-	    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);
+	    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");
 	  }
 
         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);
+            gridDefParamLCC(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);
-                }
+              if ( number > 0 ) gridDefNumber(gridID, number);
+              gridDefPosition(gridID, position);
             }
             break;
 	  }
@@ -2698,21 +2492,20 @@ static void gridComplete(grid_t *grid)
     case GRID_GAUSSIAN_REDUCED:
       {
 	gridDefNP(gridID, grid->np);
-	gridDefYsize(gridID, grid->ysize);
-        if ( grid->xdef == 2 )
+	gridDefYsize(gridID, grid->y.size);
+        if ( grid->x.flag == 2 )
           {
-            double xvals[2] = { grid->xfirst, grid->xlast };
+            double xvals[2] = { grid->x.first, grid->x.last };
             gridDefXvals(gridID, xvals);
           }
 
-        if ( grid->ydef == 2 )
+        if ( grid->y.flag == 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;
+	    double *yvals = (double *) Malloc((size_t)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->yinc);
+	    gridDefYinc(gridID, grid->y.inc);
 	    */
 	  }
 	break;
@@ -2730,21 +2523,18 @@ static void gridComplete(grid_t *grid)
       }
     case GRID_GME:
       {
-        gridDefGMEnd(gridID, grid->nd);
-        gridDefGMEni(gridID, grid->ni);
-        gridDefGMEni2(gridID, grid->ni2);
-        gridDefGMEni3(gridID, grid->ni3);
+        gridDefParamGME(gridID, grid->gme.nd, grid->gme.ni, grid->gme.ni2, grid->gme.ni3);
         break;
       }
       /*
     case GRID_GENERIC:
       {
-        if ( grid->xsize > 0 && grid->ysize > 0 )
+        if ( grid->x.size > 0 && grid->y.size > 0 )
           {
-            gridDefXsize(gridID, grid->xsize);
-            gridDefYsize(gridID, grid->ysize);
-            if ( grid->xvals ) gridDefXvals(gridID, grid->xvals);
-            if ( grid->yvals ) gridDefYvals(gridID, grid->yvals);
+            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;
       }
@@ -2762,80 +2552,67 @@ static void gridComplete(grid_t *grid)
       }
     }
 
-  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;
+  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;
 }
 
-#define GRID_STR_SERIALIZE(gridP) { gridP->xdimname, gridP->ydimname,  \
-    gridP->vdimname, gridP->xname, gridP->yname,  \
-    gridP->xlongname, gridP->ylongname, \
-    gridP->xunits, gridP->yunits }
+#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 }
 
 int gridGenerate(const grid_t *grid)
 {
   int gridtype = grid->type;
   int gridID = gridCreate(gridtype, grid->size);
-  grid_t *restrict gridptr = gridID2Ptr(gridID);
+  grid_t *restrict gridptr = grid_to_pointer(gridID);
   gridptr->prec = grid->prec;
-  gridptr->xsize = grid->xsize;
-  gridptr->ysize = grid->ysize;
+  gridptr->x.size = grid->x.size;
+  gridptr->y.size = grid->y.size;
   gridptr->np = grid->np;
   gridptr->nvertex = grid->nvertex;
-  gridptr->xdef = grid->xdef;
+  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_LCC, GRID_LCC2, GRID_SINUSOIDAL, GRID_LAEA,
-    GRID_PROJECTION
+    GRID_GENERIC, GRID_LCC, 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 )
+  if ( valdef_group1 && grid->x.flag == 1 )
     {
-      gridDefXvals(gridID, grid->xvals);
-      if ( grid->xbounds )
-        gridDefXbounds(gridID, grid->xbounds);
+      gridDefXvals(gridID, grid->x.vals);
+      if ( grid->x.bounds )
+        gridDefXbounds(gridID, grid->x.bounds);
     }
-  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)
+  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->yvals);
-      if ( grid->ybounds )
-        gridDefYbounds(gridID, grid->ybounds);
+      gridDefYvals(gridID, grid->y.vals);
+      if ( grid->y.bounds )
+        gridDefYbounds(gridID, grid->y.bounds);
     }
-  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;
+  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->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->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);
@@ -2844,19 +2621,20 @@ int gridGenerate(const grid_t *grid)
   if ( gridtype == GRID_PROJECTION )
     gridptr->name = strdup(grid->name);
   if ( gridtype == GRID_GAUSSIAN_REDUCED )
-    gridDefRowlon(gridID, grid->ysize, grid->rowlon);
+    gridDefRowlon(gridID, grid->y.size, 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;
+  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);
+
   return gridID;
 }
 
@@ -2873,38 +2651,38 @@ grid_copy_base_array_fields(grid_t *gridptrOrig, grid_t *gridptrDup)
       memcpy(gridptrDup->rowlon, gridptrOrig->rowlon, nrowlon * sizeof(int));
     }
 
-  if ( gridptrOrig->xvals != NULL )
+  if ( gridptrOrig->x.vals != NULL )
     {
-      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->xsize;
+      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->x.size;
 
-      gridptrDup->xvals = (double *)Malloc(size * sizeof (double));
-      memcpy(gridptrDup->xvals, gridptrOrig->xvals, size * sizeof (double));
+      gridptrDup->x.vals = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->x.vals, gridptrOrig->x.vals, size * sizeof (double));
     }
 
-  if ( gridptrOrig->yvals != NULL )
+  if ( gridptrOrig->y.vals != NULL )
     {
-      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->ysize;
+      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->y.size;
 
-      gridptrDup->yvals = (double *)Malloc(size * sizeof (double));
-      memcpy(gridptrDup->yvals, gridptrOrig->yvals, size * sizeof (double));
+      gridptrDup->y.vals = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->y.vals, gridptrOrig->y.vals, size * sizeof (double));
     }
 
-  if ( gridptrOrig->xbounds != NULL )
+  if ( gridptrOrig->x.bounds != NULL )
     {
-      size_t size  = (irregular ? gridsize : (size_t)gridptrOrig->xsize)
+      size_t size  = (irregular ? gridsize : (size_t)gridptrOrig->x.size)
         * (size_t)gridptrOrig->nvertex;
 
-      gridptrDup->xbounds = (double *)Malloc(size * sizeof (double));
-      memcpy(gridptrDup->xbounds, gridptrOrig->xbounds, size * sizeof (double));
+      gridptrDup->x.bounds = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->x.bounds, gridptrOrig->x.bounds, size * sizeof (double));
     }
 
-  if ( gridptrOrig->ybounds != NULL )
+  if ( gridptrOrig->y.bounds != NULL )
     {
-      size_t size = (irregular ? gridsize : (size_t)gridptrOrig->ysize)
+      size_t size = (irregular ? gridsize : (size_t)gridptrOrig->y.size)
         * (size_t)gridptrOrig->nvertex;
 
-      gridptrDup->ybounds = (double *)Malloc(size * sizeof (double));
-      memcpy(gridptrDup->ybounds, gridptrOrig->ybounds, size * sizeof (double));
+      gridptrDup->y.bounds = (double *)Malloc(size * sizeof (double));
+      memcpy(gridptrDup->y.bounds, gridptrOrig->y.bounds, size * sizeof (double));
     }
 
   {
@@ -2955,7 +2733,7 @@ The function @func{gridDuplicate} duplicates a horizontal Grid.
 */
 int gridDuplicate(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   grid_t *gridptrnew = gridptr->vtable->copy(gridptr);
   int gridIDnew = reshPut(gridptrnew, &gridOps);
   gridptrnew->self = gridIDnew;
@@ -2965,7 +2743,7 @@ int gridDuplicate(int gridID)
 
 void gridCompress(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
   int gridtype = gridInqType(gridID);
   if ( gridtype == GRID_UNSTRUCTURED )
@@ -3012,12 +2790,12 @@ void gridCompress(int gridID)
 	  /* 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;
+	  gridptr->x.size = (int)gridsize;
+	  gridptr->y.size = (int)gridsize;
 
-          double **resizeP[] = { &gridptr->xvals, &gridptr->yvals,
+          double **resizeP[] = { &gridptr->x.vals, &gridptr->y.vals,
                                  &gridptr->area,
-                                 &gridptr->xbounds, &gridptr->ybounds };
+                                 &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)
@@ -3052,7 +2830,7 @@ gridDefAreaSerial(grid_t *gridptr, const double *area)
 
 void gridDefArea(int gridID, const double *area)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   gridptr->vtable->defArea(gridptr, area);
   gridMark4Update(gridID);
 }
@@ -3067,7 +2845,7 @@ gridInqAreaSerial(grid_t *gridptr, double *area)
 
 void gridInqArea(int gridID, double *area)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   gridptr->vtable->inqArea(gridptr, area);
 }
 
@@ -3079,7 +2857,7 @@ gridHasAreaBase(grid_t *gridptr)
 
 int gridHasArea(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->vtable->hasArea(gridptr);
 }
 
@@ -3091,14 +2869,14 @@ static const double *gridInqAreaPtrBase(grid_t *gridptr)
 
 const double *gridInqAreaPtr(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->vtable->inqAreaPtr(gridptr);
 }
 
 
 void gridDefNvertex(int gridID, int nvertex)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
   if (gridptr->nvertex != nvertex)
     {
@@ -3110,8 +2888,7 @@ void gridDefNvertex(int gridID, int nvertex)
 
 int gridInqNvertex(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
+  grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->nvertex;
 }
 
@@ -3144,7 +2921,7 @@ gridDefBoundsGeneric(grid_t *gridptr, const double *bounds, int regularSize,
 static void
 gridDefXBoundsSerial(grid_t *gridptr, const double *xbounds)
 {
-  gridDefBoundsGeneric(gridptr, xbounds, gridptr->xsize, &gridptr->xbounds);
+  gridDefBoundsGeneric(gridptr, xbounds, gridptr->x.size, &gridptr->x.bounds);
 }
 
 /*
@@ -3163,7 +2940,7 @@ The function @func{gridDefXbounds} defines all bounds of the X-axis.
 */
 void gridDefXbounds(int gridID, const double *xbounds)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   gridptr->vtable->defXBounds(gridptr, xbounds);
   gridMark4Update(gridID);
 }
@@ -3175,7 +2952,7 @@ gridInqXBoundsSerial(grid_t *gridptr, double *xbounds)
 
   int irregular = gridptr->type == GRID_CURVILINEAR
     || gridptr->type == GRID_UNSTRUCTURED;
-  size_t size = nvertex * (size_t)(irregular ? gridptr->size : gridptr->xsize);
+  size_t size = nvertex * (size_t)(irregular ? gridptr->size : gridptr->x.size);
 
   const double *gridptr_xbounds = gridptr->vtable->inqXBoundsPtr(gridptr);
   if ( gridptr_xbounds )
@@ -3211,27 +2988,27 @@ Otherwise, 0 is returned and @func{xbounds} is empty.
 */
 int gridInqXbounds(int gridID, double *xbounds)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->vtable->inqXBounds(gridptr, xbounds);
 }
 
 static const double *
 gridInqXBoundsPtrSerial(grid_t *gridptr)
 {
-  return gridptr->xbounds;
+  return gridptr->x.bounds;
 }
 
 
 const double *gridInqXboundsPtr(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->vtable->inqXBoundsPtr(gridptr);
 }
 
 static void
 gridDefYBoundsSerial(grid_t *gridptr, const double *ybounds)
 {
-  gridDefBoundsGeneric(gridptr, ybounds, gridptr->ysize, &gridptr->ybounds);
+  gridDefBoundsGeneric(gridptr, ybounds, gridptr->y.size, &gridptr->y.bounds);
 }
 
 /*
@@ -3250,7 +3027,7 @@ The function @func{gridDefYbounds} defines all bounds of the Y-axis.
 */
 void gridDefYbounds(int gridID, const double *ybounds)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   gridptr->vtable->defYBounds(gridptr, ybounds);
   gridMark4Update(gridID);
 }
@@ -3262,7 +3039,7 @@ gridInqYBoundsSerial(grid_t *gridptr, double *ybounds)
 
   int irregular = gridptr->type == GRID_CURVILINEAR
     || gridptr->type == GRID_UNSTRUCTURED;
-  size_t size = nvertex * (size_t)(irregular ? gridptr->size : gridptr->ysize);
+  size_t size = nvertex * (size_t)(irregular ? gridptr->size : gridptr->y.size);
 
   const double *gridptr_ybounds = gridptr->vtable->inqYBoundsPtr(gridptr);
   if ( gridptr_ybounds )
@@ -3299,20 +3076,20 @@ Otherwise, 0 is returned and @func{ybounds} is empty.
 */
 int gridInqYbounds(int gridID, double *ybounds)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->vtable->inqYBounds(gridptr, ybounds);
 }
 
 static const double *
 gridInqYBoundsPtrSerial(grid_t *gridptr)
 {
-  return gridptr->ybounds;
+  return gridptr->y.bounds;
 }
 
 
 const double *gridInqYboundsPtr(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->vtable->inqYBoundsPtr(gridptr);
 }
 
@@ -3373,7 +3150,7 @@ printBounds(FILE *fp, int dig, const char prefix[], size_t nbyte0,
 
 static void
 printMask(FILE *fp, const char prefix[], size_t nbyte0,
-          size_t n, const mask_t mask[])
+          size_t n, const int mask[])
 {
   fputs(prefix, fp);
   size_t nbyte = nbyte0;
@@ -3384,51 +3161,140 @@ printMask(FILE *fp, const char prefix[], size_t nbyte0,
           fprintf(fp, "\n%*s", (int)nbyte0, "");
           nbyte = nbyte0;
         }
-      nbyte += (size_t)fprintf(fp, "%d ", (int)mask[i]);
+      nbyte += (size_t)fprintf(fp, "%d ", mask[i]);
     }
   fputs("\n", fp);
 }
 
-static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
+static inline
+void *resizeBuffer(void **buf, size_t *bufSize, size_t reqSize)
+{
+  if (reqSize > *bufSize)
+    {
+      *buf = Realloc(*buf, reqSize);
+      *bufSize = reqSize;
+    }
+  return *buf;
+}
+
+static
+void gridPrintAttributes(FILE *fp, int gridID)
+{
+  int cdiID = gridID;
+  int varID = CDI_GLOBAL;
+  int atttype, attlen;
+  char attname[CDI_MAX_NAME+1];
+  void *attBuf = NULL;
+  size_t attBufSize = 0;
+
+  int natts;
+  cdiInqNatts(cdiID, varID, &natts);
+
+  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
+void gridPrintKernel(int gridID, int opt, FILE *fp)
 {
   int xdim, ydim;
+  char attstr[CDI_MAX_NAME];
+  char attstr2[CDI_MAX_NAME];
   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);
+  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);
 
   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;
+  int dig = (prec == CDI_DATATYPE_FLT64) ? 15 : 7;
 
-  fprintf(fp, "#\n"
-          "# gridID %d\n"
-          "#\n"
-          "gridtype  = %s\n"
-          "gridsize  = %d\n", index, gridNamePtr(type), gridsize);
+  fprintf(fp, "gridtype  = %s\n" "gridsize  = %d\n", gridNamePtr(type), gridsize);
 
   if ( type != GRID_GME )
     {
-      if ( xvals )
+      if ( type != GRID_UNSTRUCTURED && type != GRID_SPECTRAL && type != GRID_FOURIER )
         {
-          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 ( xsize > 0 ) fprintf(fp, "xsize     = %d\n", xsize);
+          if ( ysize > 0 ) fprintf(fp, "ysize     = %d\n", ysize);
         }
-      if ( yvals )
+
+      if ( nxvals > 0 )
         {
-          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);
+          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 )
+        {
+          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);
     }
@@ -3439,13 +3305,11 @@ static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
     case GRID_GAUSSIAN:
     case GRID_GAUSSIAN_REDUCED:
     case GRID_GENERIC:
-    case GRID_LCC2:
-    case GRID_SINUSOIDAL:
-    case GRID_LAEA:
+    case GRID_PROJECTION:
     case GRID_CURVILINEAR:
     case GRID_UNSTRUCTURED:
       {
-        if ( type == GRID_GAUSSIAN || type == GRID_GAUSSIAN_REDUCED ) fprintf(fp, "np        = %d\n", gridptr->np);
+        if ( type == GRID_GAUSSIAN || type == GRID_GAUSSIAN_REDUCED ) fprintf(fp, "np        = %d\n", gridInqNP(gridID));
 
 	if ( type == GRID_CURVILINEAR || type == GRID_UNSTRUCTURED )
 	  {
@@ -3463,12 +3327,6 @@ static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
 	    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);
@@ -3494,41 +3352,12 @@ static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
               }
           }
 
-	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);
-	  }
-
-	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);
-	  }
-
-	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);
- 	  }
-
-	if ( xvals )
+	if ( nxvals > 0 )
 	  {
 	    double xfirst = 0.0, xinc = 0.0;
 
 	    if ( type == GRID_LONLAT     || type == GRID_GAUSSIAN ||
-		 type == GRID_GENERIC    || type == GRID_LCC2     ||
-                 type == GRID_SINUSOIDAL || type == GRID_LAEA )
+		 type == GRID_PROJECTION || type == GRID_GENERIC )
 	      {
 		xfirst = gridInqXval(gridID, 0);
 		xinc   = gridInqXinc(gridID);
@@ -3541,26 +3370,29 @@ static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
 	      }
 	    else
 	      {
+                double *xvals = (double*) Malloc(nxvals*sizeof(double));
+                gridInqXvals(gridID, xvals);
                 static const char prefix[] = "xvals     = ";
-                printDblsPrefixAutoBrk(fp, dig, prefix, sizeof(prefix)-1,
-                                       (size_t)(xdim > 0 ? xdim : 0), xvals);
+                printDblsPrefixAutoBrk(fp, dig, prefix, sizeof(prefix)-1, nxvals, xvals);
+                Free(xvals);
 	      }
 	  }
 
-	if ( xbounds )
+	if ( nxbounds )
 	  {
+            double *xbounds = (double*) Malloc(nxbounds*sizeof(double));
+            gridInqXbounds(gridID, 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);
+            printBounds(fp, dig, prefix, sizeof(prefix)-1, xdim, nvertex, xbounds);
+            Free(xbounds);
 	  }
 
-	if ( yvals )
+	if ( nyvals > 0 )
 	  {
 	    double yfirst = 0.0, yinc = 0.0;
 
-	    if ( type == GRID_LONLAT || type == GRID_GENERIC || type == GRID_LCC2 ||
-		 type == GRID_SINUSOIDAL || type == GRID_LAEA )
+	    if ( type == GRID_LONLAT || type == GRID_GENERIC ||
+                 type == GRID_PROJECTION || type == GRID_GENERIC )
 	      {
 		yfirst = gridInqYval(gridID, 0);
 		yinc   = gridInqYinc(gridID);
@@ -3573,25 +3405,30 @@ static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
 	      }
 	    else
 	      {
+                double *yvals = (double*) Malloc(nyvals*sizeof(double));
+                gridInqYvals(gridID, yvals);
                 static const char prefix[] = "yvals     = ";
-                printDblsPrefixAutoBrk(fp, dig, prefix, sizeof(prefix)-1,
-                                       (size_t)(ydim > 0 ? ydim : 0), yvals);
+                printDblsPrefixAutoBrk(fp, dig, prefix, sizeof(prefix)-1, nyvals, yvals);
+                Free(yvals);
 	      }
 	  }
 
-	if ( ybounds )
+	if ( nybounds )
 	  {
+            double *ybounds = (double*) Malloc(nybounds*sizeof(double));
+            gridInqYbounds(gridID, 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);
+            printBounds(fp, dig, prefix, sizeof(prefix)-1, ydim, nvertex, ybounds);
+            Free(ybounds);
 	  }
 
-	if ( area )
+	if ( gridHasArea(gridID) )
 	  {
+            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 > 0 ? gridsize : 0), area);
+            printDblsPrefixAutoBrk(fp, dig, prefix, sizeof(prefix)-1, gridsize, area);
+            Free(area);
 	  }
 
         if ( type == GRID_GAUSSIAN_REDUCED )
@@ -3604,18 +3441,18 @@ static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
             Free(rowlon);
           }
 
+        if ( type == GRID_PROJECTION ) gridPrintAttributes(fp, gridID);
+
 	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);
+	gridInqParamLCC(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"
@@ -3624,7 +3461,7 @@ static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
                 "xinc      = %.*g\n"
                 "yinc      = %.*g\n"
                 "projection = %s\n",
-                xsize, ysize, dig, originLon, dig, originLat, dig, lonParY,
+                dig, originLon, dig, originLat, dig, lonParY,
                 dig, lat1, dig, lat2, dig, xincm, dig, yincm,
                 (projflag & 128) == 0 ? "northpole" : "southpole");
 	break;
@@ -3632,17 +3469,19 @@ static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
     case GRID_SPECTRAL:
       {
         fprintf(fp, "truncation = %d\n"
-                "complexpacking = %d\n", trunc, gridptr->lcomplex );
+                "complexpacking = %d\n", gridInqTrunc(gridID), gridInqComplexPacking(gridID) );
         break;
       }
     case GRID_FOURIER:
       {
-	fprintf(fp, "truncation = %d\n", trunc);
+	fprintf(fp, "truncation = %d\n", gridInqTrunc(gridID));
 	break;
       }
     case GRID_GME:
       {
-        fprintf(fp, "ni        = %d\n", gridptr->ni );
+        int nd, ni, ni2, ni3;
+        gridInqParamGME(gridID, &nd, &ni, &ni2, &ni3);
+        fprintf(fp, "ni        = %d\n", ni );
         break;
       }
    default:
@@ -3661,30 +3500,32 @@ static void gridPrintKernel(grid_t * gridptr, int index, int opt, FILE *fp)
         fprintf(fp, "uuid      = %s\n", uuidOfHGridStr);
     }
 
-  if ( gridptr->mask )
+  if ( gridInqMask(gridID, NULL) )
     {
+      int *mask = (gridsize>0) ? (int*) Malloc((size_t)gridsize*sizeof(int)) : NULL;
+      gridInqMask(gridID, mask);
       static const char prefix[] = "mask      = ";
       printMask(fp, prefix, sizeof(prefix)-1,
-                (size_t)(gridsize > 0 ? gridsize : 0), gridptr->mask);
+                (size_t)(gridsize > 0 ? gridsize : 0), mask);
+      if ( mask ) Free(mask);
     }
 }
 
-void gridPrint ( int gridID, int index, int opt )
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
 
-  gridPrintKernel ( gridptr, index, opt, stdout );
+void gridPrint(int gridID, int opt)
+{
+  gridPrintKernel(gridID, opt, stdout);
 }
 
 
-
-void gridPrintP ( void * voidptr, FILE * fp )
+void gridPrintP(void *voidptr, FILE *fp)
 {
-  grid_t * gridptr = ( grid_t * ) voidptr;
+  grid_t *gridptr = (grid_t *) voidptr;
+  int gridID = gridptr->self;
 
-  xassert ( gridptr );
+  xassert( gridptr );
 
-  gridPrintKernel ( gridptr , gridptr->self, 0, fp );
+  gridPrintKernel(gridID, 0, fp);
 
   fprintf(fp,
           "precision = %d\n"
@@ -3697,8 +3538,8 @@ void gridPrintP ( void * voidptr, FILE * fp )
           "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->prec, gridptr->gme.nd, gridptr->gme.ni, gridptr->gme.ni2,
+          gridptr->gme.ni3, gridptr->number, gridptr->position, gridptr->trunc,
           gridptr->lcomplex, gridptr->nrowlon );
 
   if ( gridptr->rowlon )
@@ -3709,43 +3550,46 @@ void gridPrintP ( void * voidptr, FILE * fp )
                                       ? gridptr->nrowlon : 0), gridptr->rowlon);
     }
 
-  if ( gridptr->mask_gme )
+  if ( gridInqMaskGME(gridID, NULL) )
     {
+      int gridsize = gridptr->size;
+      int *mask = (gridsize>0) ? (int*) Malloc((size_t)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),
-                gridptr->mask_gme);
+                (size_t)(gridptr->size > 0 ? gridptr->size : 0), mask);
+      if ( mask ) Free(mask);
     }
 }
 
 static const double *gridInqXValsPtrSerial(grid_t *gridptr)
 {
-  return gridptr->xvals;
+  return gridptr->x.vals;
 }
 
 const double *gridInqXvalsPtr(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->vtable->inqXValsPtr(gridptr);
 }
 
 
 static const double *gridInqYValsPtrSerial(grid_t *gridptr)
 {
-  return gridptr->yvals;
+  return gridptr->y.vals;
 }
 
 const double *gridInqYvalsPtr(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->vtable->inqYValsPtr(gridptr);
 }
 
 /*
- at Function  gridDefLCC
+ at Function  gridDefParamLCC
 @Title     Define the parameter of a Lambert Conformal Conic grid
 
- 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 Prototype void gridDefParamLCC(int gridID, double originLon, double originLat, double lonParY, double lat1, double lat2, double xinc, double yinc, int projflag, int scanflag)
 @Parameter
     @Item  gridID    Grid ID, from a previous call to @fref{gridCreate}.
     @Item  originLon Longitude of the first grid point.
@@ -3759,40 +3603,40 @@ const double *gridInqYvalsPtr(int gridID)
     @Item  scanflag  Scanning mode flag.
 
 @Description
-The function @func{gridDefLCC} defines the parameter of a Lambert Conformal Conic grid.
+The function @func{gridDefParamLCC} defines the parameter of a Lambert Conformal Conic grid.
 
 @EndFunction
 */
-void gridDefLCC(int gridID, double originLon, double originLat, double lonParY,
+void gridDefParamLCC(int gridID, double originLon, double originLat, double lonParY,
                 double lat1, double lat2, double xinc, double yinc,
                 int projflag, int scanflag)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
   if ( gridptr->type != GRID_LCC )
     Warning("Definition of LCC grid for %s grid not allowed!",
 	    gridNamePtr(gridptr->type));
   else
     {
-      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;
+      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);
     }
 }
 
 /*
- at Function  gridInqLCC
+ at Function  gridInqParamLCC
 @Title     Get the parameter of a Lambert Conformal Conic grid
 
- 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 void gridInqParamLCC(int gridID, double *originLon, double *originLat, double *lonParY, double *lat1, double *lat2, double *xinc, double *yinc, int *projflag, int *scanflag)
 @Parameter
     @Item  gridID    Grid ID, from a previous call to @fref{gridCreate} or @fref{vlistInqVarGrid}.
     @Item  originLon Longitude of the first grid point.
@@ -3806,126 +3650,46 @@ void gridDefLCC(int gridID, double originLon, double originLat, double lonParY,
     @Item  scanflag  Scanning mode flag.
  
 @Description
-The function @func{gridInqLCC} returns the parameter of a Lambert Conformal Conic grid.
+The function @func{gridInqParamLCC} returns the parameter of a Lambert Conformal Conic grid.
 
 @EndFunction
 */
-void gridInqLCC(int gridID, double *originLon, double *originLat, double *lonParY,
+void gridInqParamLCC(int gridID, double *originLon, double *originLat, double *lonParY,
                 double *lat1, double *lat2, double *xinc, double *yinc,
                 int *projflag, int *scanflag)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(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 )
+      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;
+          *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);
     }
 }
 
-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);
-    }
-}
-
-
-void gridInqLcc2(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("Inquire of LCC2 grid definition for %s grid not allowed!",
-	    gridNamePtr(gridptr->type));
-  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);
-    }
-}
-
-void gridDefLaea(int gridID, double earth_radius, double lon_0, double lat_0)
-{
-  grid_t *gridptr = gridID2Ptr(gridID);
-
-  if ( gridptr->type != GRID_LAEA )
-    Warning("Definition of LAEA grid for %s grid not allowed!",
-            gridNamePtr(gridptr->type));
-  else
-    {
-      gridptr->laea_a       = earth_radius;
-      gridptr->laea_lon_0   = lon_0;
-      gridptr->laea_lat_0   = lat_0;
-      gridptr->laea_defined = TRUE;
-      gridMark4Update(gridID);
-    }
-}
-
-
-void gridInqLaea(int gridID, double *earth_radius, double *lon_0, double *lat_0)
-{
-  grid_t* gridptr = gridID2Ptr(gridID);
-
-  if ( gridptr->type != GRID_LAEA )
-    Warning("Inquire of LAEA grid definition for %s grid not allowed!",
-            gridNamePtr(gridptr->type));
-  else
-    {
-      if ( gridptr->laea_defined )
-        {
-          *earth_radius = gridptr->laea_a;
-          *lon_0        = gridptr->laea_lon_0;
-          *lat_0        = gridptr->laea_lat_0;
-        }
-      else
-        Warning("LAEA grid undefined (gridID = %d)", gridID);
-    }
-}
-
 
 void gridDefComplexPacking(int gridID, int lcomplex)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
   if (gridptr->lcomplex != lcomplex)
     {
-      gridptr->lcomplex = (short)(lcomplex != 0);
+      gridptr->lcomplex = lcomplex != 0;
       gridMark4Update(gridID);
     }
 }
@@ -3933,15 +3697,15 @@ void gridDefComplexPacking(int gridID, int lcomplex)
 
 int gridInqComplexPacking(int gridID)
 {
-  grid_t* gridptr = gridID2Ptr(gridID);
+  grid_t* gridptr = grid_to_pointer(gridID);
 
-  return gridptr->lcomplex;
+  return (int)gridptr->lcomplex;
 }
 
 
 void gridDefHasDims(int gridID, int hasdims)
 {
-  grid_t* gridptr = gridID2Ptr(gridID);
+  grid_t* gridptr = grid_to_pointer(gridID);
 
   if ( gridptr->hasdims != (hasdims != 0) )
     {
@@ -3953,9 +3717,9 @@ void gridDefHasDims(int gridID, int hasdims)
 
 int gridInqHasDims(int gridID)
 {
-  grid_t* gridptr = gridID2Ptr(gridID);
+  grid_t* gridptr = grid_to_pointer(gridID);
 
-  return gridptr->hasdims;
+  return (int)gridptr->hasdims;
 }
 
 /*
@@ -3974,7 +3738,7 @@ The function @func{gridDefNumber} defines the reference number for an unstructur
 */
 void gridDefNumber(int gridID, const int number)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
   if ( gridptr->number != number )
     {
@@ -4000,7 +3764,7 @@ The function @func{gridInqNumber} returns the reference number to an unstructure
 */
 int gridInqNumber(int gridID)
 {
-  grid_t* gridptr = gridID2Ptr(gridID);
+  grid_t* gridptr = grid_to_pointer(gridID);
   return gridptr->number;
 }
 
@@ -4020,7 +3784,7 @@ The function @func{gridDefPosition} defines the position of grid in the referenc
 */
 void gridDefPosition(int gridID, int position)
 {
-  grid_t* gridptr = gridID2Ptr(gridID);
+  grid_t* gridptr = grid_to_pointer(gridID);
 
   if ( gridptr->position != position )
     {
@@ -4046,8 +3810,7 @@ The function @func{gridInqPosition} returns the position of grid in the referenc
 */
 int gridInqPosition(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
-
+  grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->position;
 }
 
@@ -4067,7 +3830,7 @@ The function @func{gridDefReference} defines the reference URI for an unstructur
 */
 void gridDefReference(int gridID, const char *reference)
 {
-  grid_t* gridptr = gridID2Ptr(gridID);
+  grid_t* gridptr = grid_to_pointer(gridID);
 
   if ( reference )
     {
@@ -4100,7 +3863,7 @@ The function @func{gridInqReference} returns the reference URI to an unstructure
 int gridInqReference(int gridID, char *reference)
 {
   size_t len = 0;
-  grid_t* gridptr = gridID2Ptr(gridID);
+  grid_t* gridptr = grid_to_pointer(gridID);
 
   if ( gridptr->reference )
     {
@@ -4114,7 +3877,7 @@ int gridInqReference(int gridID, char *reference)
 
 const char *gridInqReferencePtr(int gridID)
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
   return gridptr->reference;
 }
 
@@ -4134,7 +3897,7 @@ The function @func{gridDefUUID} defines the UUID for an unstructured grid.
 */
 void gridDefUUID(int gridID, const unsigned char uuid[CDI_UUID_SIZE])
 {
-  grid_t* gridptr = gridID2Ptr(gridID);
+  grid_t* gridptr = grid_to_pointer(gridID);
 
   memcpy(gridptr->uuid, uuid, CDI_UUID_SIZE);
   gridMark4Update(gridID);
@@ -4157,7 +3920,7 @@ The function @func{gridInqUUID} returns the UUID to an unstructured grid.
 */
 void gridInqUUID(int gridID, unsigned char uuid[CDI_UUID_SIZE])
 {
-  grid_t *gridptr = gridID2Ptr(gridID);
+  grid_t *gridptr = grid_to_pointer(gridID);
 
   memcpy(uuid, gridptr->uuid, CDI_UUID_SIZE);
 }
@@ -4201,8 +3964,8 @@ static int gridGetComponentFlags(const grid_t * gridP)
     | (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))
+    | (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));
@@ -4215,27 +3978,27 @@ gridGetPackSize(void * voidP, void *context)
   grid_t * gridP = ( grid_t * ) voidP;
   int packBuffSize = 0, count;
 
-  packBuffSize += serializeGetSize(gridNint, DATATYPE_INT, context)
-    + serializeGetSize(1, DATATYPE_UINT32, context);
+  packBuffSize += serializeGetSize(gridNint, CDI_DATATYPE_INT, context)
+    + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
 
   if (gridP->rowlon)
     {
       xassert(gridP->nrowlon);
-      packBuffSize += serializeGetSize(gridP->nrowlon, DATATYPE_INT, context)
-        + serializeGetSize( 1, DATATYPE_UINT32, context);
+      packBuffSize += serializeGetSize(gridP->nrowlon, CDI_DATATYPE_INT, context)
+        + serializeGetSize( 1, CDI_DATATYPE_UINT32, context);
     }
 
-  packBuffSize += serializeGetSize(gridNdouble, DATATYPE_FLT64, context);
+  packBuffSize += serializeGetSize(gridNdouble, CDI_DATATYPE_FLT64, context);
 
   if (gridP->vtable->inqXValsPtr(gridP))
     {
       if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR)
 	count = gridP->size;
       else
-	count = gridP->xsize;
+	count = gridP->x.size;
       xassert(count);
-      packBuffSize += serializeGetSize(count, DATATYPE_FLT64, context)
-        + serializeGetSize(1, DATATYPE_UINT32, context);
+      packBuffSize += serializeGetSize(count, CDI_DATATYPE_FLT64, context)
+        + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
     }
 
   if (gridP->vtable->inqYValsPtr(gridP))
@@ -4243,44 +4006,44 @@ gridGetPackSize(void * voidP, void *context)
       if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR)
 	count = gridP->size;
       else
-	count = gridP->ysize;
+	count = gridP->y.size;
       xassert(count);
-      packBuffSize += serializeGetSize(count, DATATYPE_FLT64, context)
-        + serializeGetSize(1, DATATYPE_UINT32, context);
+      packBuffSize += serializeGetSize(count, CDI_DATATYPE_FLT64, context)
+        + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
     }
 
   if (gridP->vtable->inqAreaPtr(gridP))
     {
       xassert(gridP->size);
       packBuffSize +=
-        serializeGetSize(gridP->size, DATATYPE_FLT64, context)
-        + serializeGetSize(1, DATATYPE_UINT32, context);
+        serializeGetSize(gridP->size, CDI_DATATYPE_FLT64, context)
+        + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
     }
 
-  if (gridP->xbounds)
+  if (gridP->x.bounds)
     {
       xassert(gridP->nvertex);
       if (gridP->type == GRID_CURVILINEAR || gridP->type == GRID_UNSTRUCTURED)
 	count = gridP->size;
       else
-	count = gridP->xsize;
+	count = gridP->x.size;
       xassert(count);
       packBuffSize
-        += (serializeGetSize(gridP->nvertex * count, DATATYPE_FLT64, context)
-            + serializeGetSize(1, DATATYPE_UINT32, context));
+        += (serializeGetSize(gridP->nvertex * count, CDI_DATATYPE_FLT64, context)
+            + serializeGetSize(1, CDI_DATATYPE_UINT32, context));
     }
 
-  if (gridP->ybounds)
+  if (gridP->y.bounds)
     {
       xassert(gridP->nvertex);
       if (gridP->type == GRID_CURVILINEAR || gridP->type == GRID_UNSTRUCTURED)
 	count = gridP->size;
       else
-	count = gridP->ysize;
+	count = gridP->y.size;
       xassert(count);
       packBuffSize
-        += (serializeGetSize(gridP->nvertex * count, DATATYPE_FLT64, context)
-            + serializeGetSize(1, DATATYPE_UINT32, context));
+        += (serializeGetSize(gridP->nvertex * count, CDI_DATATYPE_FLT64, context)
+            + serializeGetSize(1, CDI_DATATYPE_UINT32, context));
     }
 
   {
@@ -4293,28 +4056,28 @@ gridGetPackSize(void * voidP, void *context)
   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);
+      packBuffSize += serializeGetSize(1, CDI_DATATYPE_INT, context)
+        + serializeGetSize((int)len + 1, CDI_DATATYPE_TXT, context)
+        + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
     }
 
   if (gridP->mask)
     {
       xassert(gridP->size);
       packBuffSize
-        += serializeGetSize(gridP->size, DATATYPE_UCHAR, context)
-        + serializeGetSize(1, DATATYPE_UINT32, context);
+        += serializeGetSize(gridP->size, CDI_DATATYPE_UCHAR, context)
+        + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
     }
 
   if (gridP->mask_gme)
     {
       xassert(gridP->size);
-      packBuffSize += serializeGetSize(gridP->size, DATATYPE_UCHAR, context)
-        + serializeGetSize(1, DATATYPE_UINT32, context);
+      packBuffSize += serializeGetSize(gridP->size, CDI_DATATYPE_UCHAR, context)
+        + serializeGetSize(1, CDI_DATATYPE_UINT32, context);
     }
 
   if (!cdiUUIDIsNull(gridP->uuid))
-    packBuffSize += serializeGetSize(CDI_UUID_SIZE, DATATYPE_UCHAR, context);
+    packBuffSize += serializeGetSize(CDI_UUID_SIZE, CDI_DATATYPE_UCHAR, context);
 
   return packBuffSize;
 }
@@ -4333,11 +4096,11 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
   {
     int intBuffer[gridNint];
     serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                    intBuffer, gridNint, DATATYPE_INT, context);
+                    intBuffer, gridNint, CDI_DATATYPE_INT, context);
     serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                    &d, 1, DATATYPE_UINT32, context);
+                    &d, 1, CDI_DATATYPE_UINT32, context);
 
-    xassert(cdiCheckSum(DATATYPE_INT, gridNint, intBuffer) == d);
+    xassert(cdiCheckSum(CDI_DATATYPE_INT, gridNint, intBuffer) == d);
     int targetID = namespaceAdaptKey(intBuffer[0], originNamespace);
     gridP = gridNewEntry(force_id?targetID:CDI_UNDEFID);
 
@@ -4345,31 +4108,28 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
 
     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->lcc.projflag  =   intBuffer[3];
+    gridP->lcc.scanflag  =   intBuffer[4];
+    gridP->lcc.defined   =   (short)intBuffer[5];
     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->x.flag        =   (short)intBuffer[10];
+    gridP->y.flag        =   (short)intBuffer[11];
+    gridP->gme.nd        =   intBuffer[12];
+    gridP->gme.ni        =   intBuffer[13];
+    gridP->gme.ni2       =   intBuffer[14];
+    gridP->gme.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];
+    gridP->x.size        =   intBuffer[22];
+    gridP->y.size        =   intBuffer[23];
+    gridP->lcomplex      =   (bool)intBuffer[24];
     memberMask           =   intBuffer[25];
-    gridP->xstdname      =   xystdname_tab[intBuffer[26]][0];
-    gridP->ystdname      =   xystdname_tab[intBuffer[27]][1];
+    gridP->x.stdname     =   xystdname_tab[intBuffer[26]][0];
+    gridP->y.stdname     =   xystdname_tab[intBuffer[27]][1];
   }
 
   if (memberMask & gridHasRowLonFlag)
@@ -4377,70 +4137,59 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
       xassert(gridP->nrowlon);
       gridP->rowlon = (int *) Malloc((size_t)gridP->nrowlon * sizeof (int));
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      gridP->rowlon, gridP->nrowlon , DATATYPE_INT, context);
+                      gridP->rowlon, gridP->nrowlon , CDI_DATATYPE_INT, context);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_INT, gridP->nrowlon, gridP->rowlon) == d);
+                      &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, DATATYPE_FLT64, context);
+                    doubleBuffer, gridNdouble, CDI_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];
+                    &d, 1, CDI_DATATYPE_UINT32, context);
+    xassert(d == cdiCheckSum(CDI_DATATYPE_FLT, gridNdouble, doubleBuffer));
+
+    gridP->x.first = doubleBuffer[0];
+    gridP->y.first = doubleBuffer[1];
+    gridP->x.last = doubleBuffer[2];
+    gridP->y.last = doubleBuffer[3];
+    gridP->x.inc = doubleBuffer[4];
+    gridP->y.inc = 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];
   }
 
   int irregular = gridP->type == GRID_UNSTRUCTURED
     || gridP->type == GRID_CURVILINEAR;
   if (memberMask & gridHasXValsFlag)
     {
-      size = irregular ? gridP->size : gridP->xsize;
+      size = irregular ? gridP->size : gridP->x.size;
 
-      gridP->xvals = (double *) Malloc((size_t)size * sizeof (double));
+      gridP->x.vals = (double *) Malloc((size_t)size * sizeof (double));
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      gridP->xvals, size, DATATYPE_FLT64, context);
+                      gridP->x.vals, size, CDI_DATATYPE_FLT64, context);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_FLT, size, gridP->xvals) == d );
+                      &d, 1, CDI_DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(CDI_DATATYPE_FLT, size, gridP->x.vals) == d );
     }
 
   if (memberMask & gridHasYValsFlag)
     {
-      size = irregular ? gridP->size : gridP->ysize;
+      size = irregular ? gridP->size : gridP->y.size;
 
-      gridP->yvals = (double *) Malloc((size_t)size * sizeof (double));
+      gridP->y.vals = (double *) Malloc((size_t)size * sizeof (double));
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      gridP->yvals, size, DATATYPE_FLT64, context);
+                      gridP->y.vals, size, CDI_DATATYPE_FLT64, context);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_FLT, size, gridP->yvals) == d);
+                      &d, 1, CDI_DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(CDI_DATATYPE_FLT, size, gridP->y.vals) == d);
     }
 
   if (memberMask & gridHasAreaFlag)
@@ -4449,36 +4198,36 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
       xassert(size);
       gridP->area = (double *) Malloc((size_t)size * sizeof (double));
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      gridP->area, size, DATATYPE_FLT64, context);
+                      gridP->area, size, CDI_DATATYPE_FLT64, context);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_FLT, size, gridP->area) == d);
+                      &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->xsize);
+      size = gridP->nvertex * (irregular ? gridP->size : gridP->x.size);
       xassert(size);
 
-      gridP->xbounds = (double *) Malloc((size_t)size * sizeof (double));
+      gridP->x.bounds = (double *) Malloc((size_t)size * sizeof (double));
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      gridP->xbounds, size, DATATYPE_FLT64, context);
+                      gridP->x.bounds, size, CDI_DATATYPE_FLT64, context);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_FLT, size, gridP->xbounds) == d);
+                      &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->ysize);
+      size = gridP->nvertex * (irregular ? gridP->size : gridP->y.size);
       xassert(size);
 
-      gridP->ybounds = (double *) Malloc((size_t)size * sizeof (double));
+      gridP->y.bounds = (double *) Malloc((size_t)size * sizeof (double));
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-			  gridP->ybounds, size, DATATYPE_FLT64, context);
+			  gridP->y.bounds, size, CDI_DATATYPE_FLT64, context);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_FLT, size, gridP->ybounds) == d);
+                      &d, 1, CDI_DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(CDI_DATATYPE_FLT, size, gridP->y.bounds) == d);
     }
 
   {
@@ -4492,13 +4241,13 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
     {
       int referenceSize;
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &referenceSize, 1, DATATYPE_INT, context);
+                      &referenceSize, 1, CDI_DATATYPE_INT, context);
       gridP->reference = (char *) Malloc((size_t)referenceSize);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      gridP->reference, referenceSize, DATATYPE_TXT, context);
+                      gridP->reference, referenceSize, CDI_DATATYPE_TXT, context);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_TXT, referenceSize, gridP->reference) == d);
+                      &d, 1, CDI_DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(CDI_DATATYPE_TXT, referenceSize, gridP->reference) == d);
     }
 
   if (memberMask & gridHasMaskFlag)
@@ -4506,10 +4255,10 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
       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);
+                      gridP->mask, gridP->size, CDI_DATATYPE_UCHAR, context);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_UCHAR, gridP->size, gridP->mask) == d);
+                      &d, 1, CDI_DATATYPE_UINT32, context);
+      xassert(cdiCheckSum(CDI_DATATYPE_UCHAR, gridP->size, gridP->mask) == d);
     }
 
   if (memberMask & gridHasGMEMaskFlag)
@@ -4517,15 +4266,15 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
       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);
+                      gridP->mask_gme, gridP->size, CDI_DATATYPE_UCHAR, context);
       serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                      &d, 1, DATATYPE_UINT32, context);
-      xassert(cdiCheckSum(DATATYPE_UCHAR, gridP->size, gridP->mask_gme) == d);
+                      &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, DATATYPE_UCHAR, context);
+                      gridP->uuid, CDI_UUID_SIZE, CDI_DATATYPE_UCHAR, context);
     }
 
   reshSetStatus(gridP->self, &gridOps,
@@ -4548,38 +4297,35 @@ gridPack(void * voidP, void * packBuffer, int packBufferSize,
     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[3]  = gridP->lcc.projflag;
+    intBuffer[4]  = gridP->lcc.scanflag;
+    intBuffer[5]  = gridP->lcc.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[10] = gridP->x.flag;
+    intBuffer[11] = gridP->y.flag;
+    intBuffer[12] = gridP->gme.nd;
+    intBuffer[13] = gridP->gme.ni;
+    intBuffer[14] = gridP->gme.ni2;
+    intBuffer[15] = gridP->gme.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[22] = gridP->x.size;
+    intBuffer[23] = gridP->y.size;
     intBuffer[24] = gridP->lcomplex;
     intBuffer[25] = memberMask = gridGetComponentFlags(gridP);
-    intBuffer[26] = (int)((const char (*)[2][24])gridP->xstdname
+    intBuffer[26] = (int)((const char (*)[2][24])gridP->x.stdname
                           - xystdname_tab);
-    intBuffer[27] = (int)((const char (*)[2][24])gridP->ystdname
+    intBuffer[27] = (int)((const char (*)[2][24])gridP->y.stdname
                           - (const char (*)[2][24])xystdname_tab[0][1]);
 
-    serializePack(intBuffer, gridNint, DATATYPE_INT,
+    serializePack(intBuffer, gridNint, CDI_DATATYPE_INT,
                   packBuffer, packBufferSize, packBufferPos, context);
-    d = cdiCheckSum(DATATYPE_INT, gridNint, intBuffer);
-    serializePack(&d, 1, DATATYPE_UINT32,
+    d = cdiCheckSum(CDI_DATATYPE_INT, gridNint, intBuffer);
+    serializePack(&d, 1, CDI_DATATYPE_UINT32,
                   packBuffer, packBufferSize, packBufferPos, context);
   }
 
@@ -4587,45 +4333,34 @@ gridPack(void * voidP, void * packBuffer, int packBufferSize,
     {
       size = gridP->nrowlon;
       xassert(size > 0);
-      serializePack(gridP->rowlon, size, DATATYPE_INT,
+      serializePack(gridP->rowlon, size, CDI_DATATYPE_INT,
                     packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_INT , size, gridP->rowlon);
-      serializePack(&d, 1, DATATYPE_UINT32,
+      d = cdiCheckSum(CDI_DATATYPE_INT , size, gridP->rowlon);
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
                     packBuffer, packBufferSize, packBufferPos, context);
     }
 
   {
     double doubleBuffer[gridNdouble];
 
-    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,
+    doubleBuffer[0]  = gridP->x.first;
+    doubleBuffer[1]  = gridP->y.first;
+    doubleBuffer[2]  = gridP->x.last;
+    doubleBuffer[3]  = gridP->y.last;
+    doubleBuffer[4]  = gridP->x.inc;
+    doubleBuffer[5]  = gridP->y.inc;
+    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;
+
+    serializePack(doubleBuffer, gridNdouble, CDI_DATATYPE_FLT64,
                   packBuffer, packBufferSize, packBufferPos, context);
-    d = cdiCheckSum(DATATYPE_FLT, gridNdouble, doubleBuffer);
-    serializePack(&d, 1, DATATYPE_UINT32,
+    d = cdiCheckSum(CDI_DATATYPE_FLT, gridNdouble, doubleBuffer);
+    serializePack(&d, 1, CDI_DATATYPE_UINT32,
                   packBuffer, packBufferSize, packBufferPos, context);
   }
 
@@ -4634,14 +4369,14 @@ gridPack(void * voidP, void * packBuffer, int packBufferSize,
       if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR)
 	size = gridP->size;
       else
-	size = gridP->xsize;
+	size = gridP->x.size;
       xassert(size);
 
       const double *gridP_xvals = gridP->vtable->inqXValsPtr(gridP);
-      serializePack(gridP_xvals, size, DATATYPE_FLT64,
+      serializePack(gridP_xvals, size, CDI_DATATYPE_FLT64,
                     packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_FLT, size, gridP_xvals);
-      serializePack(&d, 1, DATATYPE_UINT32,
+      d = cdiCheckSum(CDI_DATATYPE_FLT, size, gridP_xvals);
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
                     packBuffer, packBufferSize, packBufferPos, context);
     }
 
@@ -4650,13 +4385,13 @@ gridPack(void * voidP, void * packBuffer, int packBufferSize,
       if (gridP->type == GRID_UNSTRUCTURED || gridP->type == GRID_CURVILINEAR )
 	size = gridP->size;
       else
-	size = gridP->ysize;
+	size = gridP->y.size;
       xassert(size);
       const double *gridP_yvals = gridP->vtable->inqYValsPtr(gridP);
-      serializePack(gridP_yvals, size, DATATYPE_FLT64,
+      serializePack(gridP_yvals, size, CDI_DATATYPE_FLT64,
                     packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_FLT, size, gridP_yvals);
-      serializePack(&d, 1, DATATYPE_UINT32,
+      d = cdiCheckSum(CDI_DATATYPE_FLT, size, gridP_yvals);
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
                     packBuffer, packBufferSize, packBufferPos, context);
     }
 
@@ -4664,10 +4399,10 @@ gridPack(void * voidP, void * packBuffer, int packBufferSize,
     {
       xassert(gridP->size);
 
-      serializePack(gridP->area, gridP->size, DATATYPE_FLT64,
+      serializePack(gridP->area, gridP->size, CDI_DATATYPE_FLT64,
                     packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_FLT, gridP->size, gridP->area);
-      serializePack(&d, 1, DATATYPE_UINT32,
+      d = cdiCheckSum(CDI_DATATYPE_FLT, gridP->size, gridP->area);
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
                     packBuffer, packBufferSize, packBufferPos, context);
     }
 
@@ -4677,13 +4412,13 @@ gridPack(void * voidP, void * packBuffer, int packBufferSize,
       if (gridP->type == GRID_CURVILINEAR || gridP->type == GRID_UNSTRUCTURED)
 	size = gridP->nvertex * gridP->size;
       else
-	size = gridP->nvertex * gridP->xsize;
+	size = gridP->nvertex * gridP->x.size;
       xassert ( size );
 
-      serializePack(gridP->xbounds, size, DATATYPE_FLT64,
+      serializePack(gridP->x.bounds, size, CDI_DATATYPE_FLT64,
                     packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_FLT, size, gridP->xbounds);
-      serializePack(&d, 1, DATATYPE_UINT32,
+      d = cdiCheckSum(CDI_DATATYPE_FLT, size, gridP->x.bounds);
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
                     packBuffer, packBufferSize, packBufferPos, context);
     }
 
@@ -4693,13 +4428,13 @@ gridPack(void * voidP, void * packBuffer, int packBufferSize,
       if (gridP->type == GRID_CURVILINEAR || gridP->type == GRID_UNSTRUCTURED)
 	size = gridP->nvertex * gridP->size;
       else
-	size = gridP->nvertex * gridP->ysize;
+	size = gridP->nvertex * gridP->y.size;
       xassert ( size );
 
-      serializePack(gridP->ybounds, size, DATATYPE_FLT64,
+      serializePack(gridP->y.bounds, size, CDI_DATATYPE_FLT64,
                     packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_FLT, size, gridP->ybounds);
-      serializePack(&d, 1, DATATYPE_UINT32,
+      d = cdiCheckSum(CDI_DATATYPE_FLT, size, gridP->y.bounds);
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
                     packBuffer, packBufferSize, packBufferPos, context);
     }
 
@@ -4713,22 +4448,22 @@ gridPack(void * voidP, void * packBuffer, int packBufferSize,
   if (memberMask & gridHasReferenceFlag)
     {
       size = (int)strlen(gridP->reference) + 1;
-      serializePack(&size, 1, DATATYPE_INT,
+      serializePack(&size, 1, CDI_DATATYPE_INT,
                     packBuffer, packBufferSize, packBufferPos, context);
-      serializePack(gridP->reference, size, DATATYPE_TXT,
+      serializePack(gridP->reference, size, CDI_DATATYPE_TXT,
                     packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_TXT, size, gridP->reference);
-      serializePack(&d, 1, DATATYPE_UINT32,
+      d = cdiCheckSum(CDI_DATATYPE_TXT, size, gridP->reference);
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
                     packBuffer, packBufferSize, packBufferPos, context);
     }
 
   if (memberMask & gridHasMaskFlag)
     {
       xassert((size = gridP->size));
-      serializePack(gridP->mask, size, DATATYPE_UCHAR,
+      serializePack(gridP->mask, size, CDI_DATATYPE_UCHAR,
                     packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_UCHAR, size, gridP->mask);
-      serializePack(&d, 1, DATATYPE_UINT32,
+      d = cdiCheckSum(CDI_DATATYPE_UCHAR, size, gridP->mask);
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
                     packBuffer, packBufferSize, packBufferPos, context);
     }
 
@@ -4736,15 +4471,15 @@ gridPack(void * voidP, void * packBuffer, int packBufferSize,
     {
       xassert((size = gridP->size));
 
-      serializePack(gridP->mask_gme, size, DATATYPE_UCHAR,
+      serializePack(gridP->mask_gme, size, CDI_DATATYPE_UCHAR,
                     packBuffer, packBufferSize, packBufferPos, context);
-      d = cdiCheckSum(DATATYPE_UCHAR, size, gridP->mask_gme);
-      serializePack(&d, 1, DATATYPE_UINT32,
+      d = cdiCheckSum(CDI_DATATYPE_UCHAR, size, gridP->mask_gme);
+      serializePack(&d, 1, CDI_DATATYPE_UINT32,
                     packBuffer, packBufferSize, packBufferPos, context);
     }
 
   if (memberMask & gridHasUUIDFlag)
-    serializePack(gridP->uuid, CDI_UUID_SIZE, DATATYPE_UCHAR,
+    serializePack(gridP->uuid, CDI_UUID_SIZE, CDI_DATATYPE_UCHAR,
                   packBuffer, packBufferSize, packBufferPos, context);
 }
 
@@ -4762,7 +4497,7 @@ gridCompareSearch(int id, void *res, void *data)
 {
   struct gridCompareSearchState *state = (struct gridCompareSearchState*)data;
   (void)res;
-  if ( gridCompare(id, state->queryKey) == false )
+  if ( gridCompare(id, state->queryKey, false) == false )
     {
       state->resIDValue = id;
       return CDI_APPLY_STOP;
@@ -4771,12 +4506,13 @@ gridCompareSearch(int id, void *res, void *data)
     return CDI_APPLY_GO_ON;
 }
 
-/* Add grid (which must be Malloc'ed to vlist if not already found */
-struct addIffNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode)
+/* Add grid (which must be Malloc'ed to vlist if not already found) */
+struct addIfNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode)
 {
   /*
     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;
@@ -4788,9 +4524,9 @@ struct addIffNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode)
   if ( mode == 0 )
     for ( unsigned index = 0; index < ngrids; index++ )
       {
-	if ( (gridID = vlistptr->gridIDs[index]) != UNDEFID )
+	if ( (gridID = vlistptr->gridIDs[index]) != CDI_UNDEFID )
           {
-            if ( gridCompare(gridID, grid) == false )
+            if ( gridCompare(gridID, grid, false) == false )
               {
                 griddefined = true;
                 break;
@@ -4799,20 +4535,18 @@ struct addIffNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode)
         else
           Error("Internal problem: undefined gridID in vlist "
                 "%d, position %u!", vlistID, index);
-
       }
 
   if ( ! griddefined )
     {
       struct gridCompareSearchState query;
       query.queryKey = grid;// = { .queryKey = grid };
-      if ((gridglobdefined
-           = (cdiResHFilterApply(&gridOps, gridCompareSearch, &query)
-              == CDI_APPLY_STOP)))
+      if ( (gridglobdefined = (cdiResHFilterApply(&gridOps, gridCompareSearch, &query)
+              == CDI_APPLY_STOP)) )
         gridID = query.resIDValue;
 
       if ( mode == 1 && gridglobdefined )
-	for (unsigned index = 0; index < ngrids; index++ )
+	for ( unsigned index = 0; index < ngrids; index++ )
 	  if ( vlistptr->gridIDs[index] == gridID )
 	    {
 	      gridglobdefined = false;
@@ -4827,14 +4561,17 @@ struct addIffNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode)
           grid->self = gridID = reshPut(grid, &gridOps);
           gridComplete(grid);
         }
-      vlistptr->gridIDs[ngrids] = gridID;
-      vlistptr->ngrids++;
+      if ( mode < 2 )
+        {
+          vlistptr->gridIDs[ngrids] = gridID;
+          vlistptr->ngrids++;
+        }
     }
 
-  return (struct addIffNewRes){ .Id = gridID,
-      .isNew = !griddefined && !gridglobdefined };
+  return (struct addIfNewRes){ .Id = gridID, .isNew = !griddefined && !gridglobdefined };
 }
 
+
 const struct gridVirtTable cdiGridVtable
   = {
   .destroy = gridDestroyKernel,
diff --git a/libcdi/src/grid.h b/libcdi/src/grid.h
index 5ae1682..9c41140 100644
--- a/libcdi/src/grid.h
+++ b/libcdi/src/grid.h
@@ -4,6 +4,8 @@
 #include "cdi.h"
 #include <stdbool.h>
 
+#include "cdi_att.h"
+
 typedef unsigned char mask_t;
 
 typedef struct grid_t grid_t;
@@ -43,47 +45,54 @@ struct gridVirtTable
   const double *(*inqYBoundsPtr)(grid_t *gridptr);
 };
 
+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;
+  int     size;                  // number of values
+  short   flag;                  // 0: undefined 1:vals 2:first+inc
+  double  first, last, inc;
+  double *vals;
+  double *bounds;
+};
+
+// Lambert Conformal Conic
+struct grid_lcc_t {
+  double  originLon;
+  double  originLat;
+  double  lonParY;
+  double  lat1;
+  double  lat2;
+  double  xinc;
+  double  yinc;
+  int     projflag;
+  int     scanflag;
+  short   defined;
+};
+
+// GME Grid
+struct grid_gme_t {
+  int     nd, ni, ni2, ni3;       /* parameter for GRID_GME         */
+};
+
 struct grid_t {
+  char    vdimname[CDI_MAX_NAME];
+  char    mapname[CDI_MAX_NAME];
+  char    mapping[CDI_MAX_NAME];
+  char   *name;
   int     self;
   int     type;                   /* grid type                      */
   int     prec;                   /* grid precision                 */
   int     proj;                   /* grid projection                */
+  int     projtype;               /* grid projection type           */
   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             */
+  struct grid_lcc_t  lcc;
+  struct grid_gme_t  gme;
   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;
@@ -92,37 +101,26 @@ struct grid_t {
   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;
+  bool    lcomplex;
+  bool    hasdims;
+  struct gridaxis_t x;
+  struct gridaxis_t y;
   const struct gridVirtTable *vtable;
-  void *extraData;
+  cdi_atts_t atts;
 };
 
 
 void grid_init(grid_t *gridptr);
-void
-cdiGridTypeInit(grid_t *gridptr, int gridtype, int size);
+void cdiGridTypeInit(grid_t *gridptr, int gridtype, int size);
 void grid_free(grid_t *gridptr);
-grid_t *gridID2Ptr(int gridID);
+grid_t *grid_to_pointer(int gridID);
 extern const struct gridVirtTable cdiGridVtable;
 
 unsigned cdiGridCount(void);
 
+void gridVerifyProj(int gridID);
+
 const double *gridInqXvalsPtr(int gridID);
 const double *gridInqYvalsPtr(int gridID);
 
@@ -130,13 +128,12 @@ const double *gridInqXboundsPtr(int gridID);
 const double *gridInqYboundsPtr(int gridID);
 const double *gridInqAreaPtr(int gridID);
 
-const char *gridInqXnamePtr(int gridID);
-const char *gridInqYnamePtr(int gridID);
-
 const char *gridInqReferencePtr(int gridID);
 
 int gridGenerate(const grid_t *grid);
 
+//int gridIsEqual(int gridID1, int gridID2);
+
 void cdiGridGetIndexList(unsigned, int * );
 
 void
@@ -144,13 +141,13 @@ gridUnpack(char * unpackBuffer, int unpackBufferSize,
            int * unpackBufferPos, int originNamespace, void *context,
            int force_id);
 
-struct addIffNewRes
+struct addIfNewRes
 {
   int Id;
   int isNew;
 };
 
-struct addIffNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode);
+struct addIfNewRes cdiVlistAddGridIfNew(int vlistID, grid_t *grid, int mode);
 
 #endif
 /*
diff --git a/libcdi/src/ieg.h b/libcdi/src/ieg.h
index 7b72d88..c92aaf9 100644
--- a/libcdi/src/ieg.h
+++ b/libcdi/src/ieg.h
@@ -14,7 +14,6 @@
 #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]
diff --git a/libcdi/src/institution.c b/libcdi/src/institution.c
index 69c1cff..eb1ef6b 100644
--- a/libcdi/src/institution.c
+++ b/libcdi/src/institution.c
@@ -15,12 +15,10 @@
 #include "serialize.h"
 #include "institution.h"
 
-#undef  UNDEFID
-#define UNDEFID  -1
 
-static int ECMWF  = UNDEFID,
-  MPIMET = UNDEFID,
-  MCH    = UNDEFID;
+static int ECMWF  = CDI_UNDEFID,
+  MPIMET = CDI_UNDEFID,
+  MCH    = CDI_UNDEFID;
 
 typedef struct
 {
@@ -53,10 +51,10 @@ static const resOps instituteOps = {
 static
 void instituteDefaultValue ( institute_t * instituteptr )
 {
-  instituteptr->self       = UNDEFID;
+  instituteptr->self       = CDI_UNDEFID;
   instituteptr->used       = 0;
-  instituteptr->center     = UNDEFID;
-  instituteptr->subcenter  = UNDEFID;
+  instituteptr->center     = CDI_UNDEFID;
+  instituteptr->subcenter  = CDI_UNDEFID;
   instituteptr->name       = NULL;
   instituteptr->longname   = NULL;
 }
@@ -151,14 +149,14 @@ findInstitute(int id, void *res, void *data)
 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       = UNDEFID;
+  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;
 
-  struct instLoc state = { .ip = ip_ref, .id = UNDEFID };
+  struct instLoc state = { .ip = ip_ref, .id = CDI_UNDEFID };
   cdiResHFilterApply(&instituteOps, findInstitute, &state);
 
   Free(ip_ref);
@@ -202,10 +200,10 @@ int institutInqCenter(int instID)
 {
   institute_t * instituteptr = NULL;
 
-  if ( instID != UNDEFID )
+  if ( instID != CDI_UNDEFID )
     instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
 
-  return  instituteptr ? instituteptr->center : UNDEFID;
+  return  instituteptr ? instituteptr->center : CDI_UNDEFID;
 }
 
 
@@ -213,10 +211,10 @@ int institutInqSubcenter(int instID)
 {
   institute_t * instituteptr = NULL;
 
-  if ( instID != UNDEFID )
+  if ( instID != CDI_UNDEFID )
     instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
 
-  return instituteptr ? instituteptr->subcenter: UNDEFID;
+  return instituteptr ? instituteptr->subcenter: CDI_UNDEFID;
 }
 
 
@@ -224,7 +222,7 @@ const char *institutInqNamePtr(int instID)
 {
   institute_t * instituteptr = NULL;
 
-  if ( instID != UNDEFID )
+  if ( instID != CDI_UNDEFID )
     instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
 
   return instituteptr ? instituteptr->name : NULL;
@@ -235,7 +233,7 @@ const char *institutInqLongnamePtr(int instID)
 {
   institute_t * instituteptr = NULL;
 
-  if ( instID != UNDEFID )
+  if ( instID != CDI_UNDEFID )
     instituteptr = ( institute_t * ) reshGetVal ( instID, &instituteOps );
 
   return instituteptr ? instituteptr->longname : NULL;
@@ -304,9 +302,9 @@ static int instituteGetPackSize(institute_t *ip, void *context)
 {
   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);
+  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;
 }
@@ -320,9 +318,9 @@ static void institutePackP(void * instituteptr, void *buf, int size, int *positi
   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);
+  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,
@@ -331,11 +329,11 @@ int instituteUnpack(void *buf, int size, int *position, int originNamespace,
   int tempbuf[institute_nints];
   int instituteID;
   char *name, *longname;
-  serializeUnpack(buf, size, position, tempbuf, institute_nints, DATATYPE_INT, context);
+  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], DATATYPE_TXT, context);
-  serializeUnpack(buf, size, position, longname, tempbuf[4], DATATYPE_TXT, context);
+  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);
diff --git a/libcdi/src/iterator.c b/libcdi/src/iterator.c
index eb63a23..37f8933 100644
--- a/libcdi/src/iterator.c
+++ b/libcdi/src/iterator.c
@@ -21,23 +21,23 @@ static const char* fileType2String(int fileType)
   switch(fileType)
     {
 #ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB: return "CDI::Iterator::GRIB1";
-        case FILETYPE_GRB2: return "CDI::Iterator::GRIB2";
+        case CDI_FILETYPE_GRB: return "CDI::Iterator::GRIB1";
+        case CDI_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";
+        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";
 #endif
 #ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV: return "CDI::Iterator::SRV";
+        case CDI_FILETYPE_SRV: return "CDI::Iterator::SRV";
 #endif
 #ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT: return "CDI::Iterator::EXT";
+        case CDI_FILETYPE_EXT: return "CDI::Iterator::EXT";
 #endif
 #ifdef HAVE_LIBIEG
-        case FILETYPE_IEG: return "CDI::Iterator::IEG";
+        case CDI_FILETYPE_IEG: return "CDI::Iterator::IEG";
 #endif
 
       default: return NULL;
@@ -54,24 +54,24 @@ static int string2FileType(const char* fileType, const char **outRestString)
           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; \
+          return CDI_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);
+  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::SRV", CDI_FILETYPE_SRV);
+  check(fileType, "CDI::Iterator::EXT", CDI_FILETYPE_EXT);
+  check(fileType, "CDI::Iterator::IEG", CDI_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;
+  return CDI_FILETYPE_UNDEF;
 }
 
 /*
@@ -99,30 +99,30 @@ CdiIterator* cdiIterator_new(const char* path)
   int filetype = cdiGetFiletype(path, &trash);
   switch(filetype)
     {
-      case FILETYPE_UNDEF:
+      case CDI_FILETYPE_UNDEF:
         Warning("Can't open file \"%s\": unknown format\n", path);
         return NULL;
 
 #ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
           return cdiGribIterator_new(path, filetype);
 #endif
 
 #ifdef 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:
 #endif
 #ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
+        case CDI_FILETYPE_SRV:
 #endif
 #ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
+        case CDI_FILETYPE_EXT:
 #endif
 #ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
+        case CDI_FILETYPE_IEG:
 #endif
           return cdiFallbackIterator_new(path, filetype);
 
@@ -142,7 +142,7 @@ const char* baseIter_constructFromString(CdiIterator* me, const char* descriptio
 {
   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.
+  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))
     {
@@ -193,25 +193,25 @@ CdiIterator* cdiIterator_clone(CdiIterator* me)
   switch(me->filetype)
     {
 #ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
           return cdiGribIterator_getSuper(cdiGribIterator_clone(me));
 #endif
 
 #ifdef 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:
 #endif
 #ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
+        case CDI_FILETYPE_SRV:
 #endif
 #ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
+        case CDI_FILETYPE_EXT:
 #endif
 #ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
+        case CDI_FILETYPE_IEG:
 #endif
           return cdiFallbackIterator_getSuper(cdiFallbackIterator_clone(me));
 
@@ -243,8 +243,8 @@ CdiGribIterator* cdiGribIterator_clone(CdiIterator* me)
   switch(me->filetype)
     {
 #ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
           return cdiGribIterator_makeClone(me);
 #endif
 
@@ -273,26 +273,26 @@ char* cdiIterator_serialize(CdiIterator* me)
   switch(me->filetype)
     {
 #ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
           subclassDescription = cdiGribIterator_serialize(me);
           break;
 #endif
 
 #ifdef 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:
 #endif
 #ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
+        case CDI_FILETYPE_SRV:
 #endif
 #ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
+        case CDI_FILETYPE_EXT:
 #endif
 #ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
+        case CDI_FILETYPE_IEG:
 #endif
           subclassDescription = cdiFallbackIterator_serialize(me);
           break;
@@ -333,25 +333,25 @@ CdiIterator* cdiIterator_deserialize(const char* description)
   switch(string2FileType(description, NULL))
     {
 #ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
           return cdiGribIterator_getSuper(cdiGribIterator_deserialize(description));
 #endif
 
 #ifdef 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:
 #endif
 #ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
+        case CDI_FILETYPE_SRV:
 #endif
 #ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
+        case CDI_FILETYPE_EXT:
 #endif
 #ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
+        case CDI_FILETYPE_IEG:
 #endif
           return cdiFallbackIterator_getSuper(cdiFallbackIterator_deserialize(description));
 
@@ -405,25 +405,25 @@ int cdiIterator_nextField(CdiIterator* me)
   switch(me->filetype)
     {
 #ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
           return cdiGribIterator_nextField(me);
 #endif
 
 #ifdef 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:
 #endif
 #ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
+        case CDI_FILETYPE_SRV:
 #endif
 #ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
+        case CDI_FILETYPE_EXT:
 #endif
 #ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
+        case CDI_FILETYPE_IEG:
 #endif
           return cdiFallbackIterator_nextField(me);
 
@@ -439,25 +439,25 @@ static char* cdiIterator_inqTime(CdiIterator* me, CdiTimeType timeType)
   switch(me->filetype)
     {
 #ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
           return cdiGribIterator_inqTime(me, timeType);
 #endif
 
 #ifdef 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:
 #endif
 #ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
+        case CDI_FILETYPE_SRV:
 #endif
 #ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
+        case CDI_FILETYPE_EXT:
 #endif
 #ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
+        case CDI_FILETYPE_IEG:
 #endif
           return cdiFallbackIterator_inqTime(me, timeType);
 
@@ -599,25 +599,25 @@ int cdiIterator_inqLevelType(CdiIterator* me, int levelSelector, char **outName,
   switch(me->filetype)
     {
 #ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
           return cdiGribIterator_levelType(me, levelSelector, outName, outLongName, outStdName, outUnit);
 #endif
 
 #ifdef 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:
 #endif
 #ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
+        case CDI_FILETYPE_SRV:
 #endif
 #ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
+        case CDI_FILETYPE_EXT:
 #endif
 #ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
+        case CDI_FILETYPE_IEG:
 #endif
           return cdiFallbackIterator_levelType(me, levelSelector, outName, outLongName, outStdName, outUnit);
 
@@ -649,25 +649,25 @@ int cdiIterator_inqLevel(CdiIterator* me, int levelSelector, double* outValue1,
   switch(me->filetype)
     {
 #ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
           return cdiGribIterator_level(me, levelSelector, outValue1, outValue2);
 #endif
 
 #ifdef 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:
 #endif
 #ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
+        case CDI_FILETYPE_SRV:
 #endif
 #ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
+        case CDI_FILETYPE_EXT:
 #endif
 #ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
+        case CDI_FILETYPE_IEG:
 #endif
           return cdiFallbackIterator_level(me, levelSelector, outValue1, outValue2);
 
@@ -699,25 +699,25 @@ int cdiIterator_inqLevelUuid(CdiIterator* me, int* outVgridNumber, int* outLevel
   switch(me->filetype)
     {
 #ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
           return cdiGribIterator_zaxisUuid(me, outVgridNumber, outLevelCount, outUuid);
 #endif
 
 #ifdef 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:
 #endif
 #ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
+        case CDI_FILETYPE_SRV:
 #endif
 #ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
+        case CDI_FILETYPE_EXT:
 #endif
 #ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
+        case CDI_FILETYPE_IEG:
 #endif
           return cdiFallbackIterator_zaxisUuid(me, outVgridNumber, outLevelCount, outUuid);
 
@@ -748,25 +748,25 @@ int cdiIterator_inqTile(CdiIterator* me, int* outTileIndex, int* outTileAttribut
   switch(me->filetype)
     {
       #ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
           return cdiGribIterator_inqTile(me, outTileIndex, outTileAttribute);
       #endif
 
       #ifdef 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:
       #endif
       #ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
+        case CDI_FILETYPE_SRV:
       #endif
       #ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
+        case CDI_FILETYPE_EXT:
       #endif
       #ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
+        case CDI_FILETYPE_IEG:
       #endif
           return cdiFallbackIterator_inqTile(me, outTileIndex, outTileAttribute);
 
@@ -798,25 +798,25 @@ int cdiIterator_inqTileCount(CdiIterator* me, int* outTileCount, int* outTileAtt
   switch(me->filetype)
     {
       #ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
           return cdiGribIterator_inqTileCount(me, outTileCount, outTileAttributeCount);
       #endif
 
       #ifdef 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:
       #endif
       #ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
+        case CDI_FILETYPE_SRV:
       #endif
       #ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
+        case CDI_FILETYPE_EXT:
       #endif
       #ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
+        case CDI_FILETYPE_IEG:
       #endif
           return cdiFallbackIterator_inqTileCount(me, outTileCount, outTileAttributeCount);
 
@@ -928,25 +928,25 @@ char* cdiIterator_inqVariableName(CdiIterator* me)
   switch(me->filetype)
     {
 #ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
           return cdiGribIterator_copyVariableName(me);
 #endif
 
 #ifdef 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:
 #endif
 #ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
+        case CDI_FILETYPE_SRV:
 #endif
 #ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
+        case CDI_FILETYPE_EXT:
 #endif
 #ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
+        case CDI_FILETYPE_IEG:
 #endif
           return cdiFallbackIterator_copyVariableName(me);
 
@@ -997,26 +997,26 @@ void cdiIterator_readField(CdiIterator* me, double* buffer, size_t* nmiss)
   switch(me->filetype)
     {
 #ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
           cdiGribIterator_readField(me, buffer, nmiss);
 	  return;
 #endif
 
 #ifdef 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:
 #endif
 #ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
+        case CDI_FILETYPE_SRV:
 #endif
 #ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
+        case CDI_FILETYPE_EXT:
 #endif
 #ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
+        case CDI_FILETYPE_IEG:
 #endif
           cdiFallbackIterator_readField(me, buffer, nmiss);
           return;
@@ -1046,26 +1046,26 @@ void cdiIterator_readFieldF(CdiIterator* me, float* buffer, size_t* nmiss)
   switch(me->filetype)
     {
 #ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
           cdiGribIterator_readFieldF(me, buffer, nmiss);
 	  return;
 #endif
 
 #ifdef 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:
 #endif
 #ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
+        case CDI_FILETYPE_SRV:
 #endif
 #ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
+        case CDI_FILETYPE_EXT:
 #endif
 #ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
+        case CDI_FILETYPE_IEG:
 #endif
           cdiFallbackIterator_readFieldF(me, buffer, nmiss);
           return; 
@@ -1091,26 +1091,26 @@ void cdiIterator_delete(CdiIterator* me)
   switch(me->filetype)
     {
 #ifdef HAVE_LIBGRIB_API
-        case FILETYPE_GRB:
-        case FILETYPE_GRB2:
+        case CDI_FILETYPE_GRB:
+        case CDI_FILETYPE_GRB2:
           cdiGribIterator_delete((CdiGribIterator*)me);
           break;
 #endif
 
 #ifdef 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:
 #endif
 #ifdef HAVE_LIBSERVICE
-        case FILETYPE_SRV:
+        case CDI_FILETYPE_SRV:
 #endif
 #ifdef HAVE_LIBEXTRA
-        case FILETYPE_EXT:
+        case CDI_FILETYPE_EXT:
 #endif
 #ifdef HAVE_LIBIEG
-        case FILETYPE_IEG:
+        case CDI_FILETYPE_IEG:
 #endif
           cdiFallbackIterator_delete(me);
           break;
diff --git a/libcdi/src/iterator_grib.c b/libcdi/src/iterator_grib.c
index fc8ef71..496e124 100644
--- a/libcdi/src/iterator_grib.c
+++ b/libcdi/src/iterator_grib.c
@@ -142,7 +142,7 @@ char *cdiGribIterator_serialize(CdiIterator *super)
   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);
+  sprintf(result, "%s %zu", escapedPath, (size_t)me->fileOffset);
   Free(escapedPath);
   return result;
 }
diff --git a/libcdi/src/mo_cdi.f90 b/libcdi/src/mo_cdi.f90
index 23098dd..4b37d26 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 "../interfaces/f2003/bindGen.rb" from input file "../src/cdi.h".
+! Generated by "../../../../libcdi/interfaces/f2003/bindGen.rb" from input file "../../../../libcdi/src/cdi.h".
 
 module mo_cdi
   use iso_c_binding
@@ -40,7 +40,15 @@ module mo_cdi
   integer(c_int), public, parameter :: CDI_EUFSTRUCT = -23
   integer(c_int), public, parameter :: CDI_EUNC4 = -24
   integer(c_int), public, parameter :: CDI_ELIMIT = -99
-  integer(c_int), public, parameter :: FILETYPE_UNDEF = -1
+  integer(c_int), public, parameter :: CDI_FILETYPE_GRB = 1
+  integer(c_int), public, parameter :: CDI_FILETYPE_GRB2 = 2
+  integer(c_int), public, parameter :: CDI_FILETYPE_NC = 3
+  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_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
@@ -50,64 +58,77 @@ module mo_cdi
   integer(c_int), public, parameter :: FILETYPE_SRV = 7
   integer(c_int), public, parameter :: FILETYPE_EXT = 8
   integer(c_int), public, parameter :: FILETYPE_IEG = 9
-  integer(c_int), public, parameter :: COMPRESS_NONE = 0
-  integer(c_int), public, parameter :: COMPRESS_SZIP = 1
-  integer(c_int), public, parameter :: COMPRESS_GZIP = 2
-  integer(c_int), public, parameter :: COMPRESS_BZIP2 = 3
-  integer(c_int), public, parameter :: COMPRESS_ZIP = 4
-  integer(c_int), public, parameter :: COMPRESS_JPEG = 5
+  integer(c_int), public, parameter :: CDI_COMPRESS_NONE = 0
+  integer(c_int), public, parameter :: CDI_COMPRESS_SZIP = 1
+  integer(c_int), public, parameter :: CDI_COMPRESS_GZIP = 2
+  integer(c_int), public, parameter :: CDI_COMPRESS_BZIP2 = 3
+  integer(c_int), public, parameter :: CDI_COMPRESS_ZIP = 4
+  integer(c_int), public, parameter :: CDI_COMPRESS_JPEG = 5
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK = 0
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK1 = 1
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK2 = 2
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK3 = 3
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK4 = 4
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK5 = 5
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK6 = 6
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK7 = 7
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK8 = 8
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK9 = 9
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK10 = 10
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK11 = 11
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK12 = 12
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK13 = 13
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK14 = 14
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK15 = 15
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK16 = 16
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK17 = 17
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK18 = 18
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK19 = 19
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK20 = 20
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK21 = 21
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK22 = 22
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK23 = 23
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK24 = 24
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK25 = 25
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK26 = 26
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK27 = 27
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK28 = 28
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK29 = 29
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK30 = 30
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK31 = 31
+  integer(c_int), public, parameter :: CDI_DATATYPE_PACK32 = 32
+  integer(c_int), public, parameter :: CDI_DATATYPE_CPX32 = 64
+  integer(c_int), public, parameter :: CDI_DATATYPE_CPX64 = 128
+  integer(c_int), public, parameter :: CDI_DATATYPE_FLT32 = 132
+  integer(c_int), public, parameter :: CDI_DATATYPE_FLT64 = 164
+  integer(c_int), public, parameter :: CDI_DATATYPE_INT8 = 208
+  integer(c_int), public, parameter :: CDI_DATATYPE_INT16 = 216
+  integer(c_int), public, parameter :: CDI_DATATYPE_INT32 = 232
+  integer(c_int), public, parameter :: CDI_DATATYPE_UINT8 = 308
+  integer(c_int), public, parameter :: CDI_DATATYPE_UINT16 = 316
+  integer(c_int), public, parameter :: CDI_DATATYPE_UINT32 = 332
   integer(c_int), public, parameter :: DATATYPE_PACK = 0
-  integer(c_int), public, parameter :: DATATYPE_PACK1 = 1
-  integer(c_int), public, parameter :: DATATYPE_PACK2 = 2
-  integer(c_int), public, parameter :: DATATYPE_PACK3 = 3
-  integer(c_int), public, parameter :: DATATYPE_PACK4 = 4
-  integer(c_int), public, parameter :: DATATYPE_PACK5 = 5
-  integer(c_int), public, parameter :: DATATYPE_PACK6 = 6
-  integer(c_int), public, parameter :: DATATYPE_PACK7 = 7
   integer(c_int), public, parameter :: DATATYPE_PACK8 = 8
-  integer(c_int), public, parameter :: DATATYPE_PACK9 = 9
-  integer(c_int), public, parameter :: DATATYPE_PACK10 = 10
-  integer(c_int), public, parameter :: DATATYPE_PACK11 = 11
-  integer(c_int), public, parameter :: DATATYPE_PACK12 = 12
-  integer(c_int), public, parameter :: DATATYPE_PACK13 = 13
-  integer(c_int), public, parameter :: DATATYPE_PACK14 = 14
-  integer(c_int), public, parameter :: DATATYPE_PACK15 = 15
   integer(c_int), public, parameter :: DATATYPE_PACK16 = 16
-  integer(c_int), public, parameter :: DATATYPE_PACK17 = 17
-  integer(c_int), public, parameter :: DATATYPE_PACK18 = 18
-  integer(c_int), public, parameter :: DATATYPE_PACK19 = 19
-  integer(c_int), public, parameter :: DATATYPE_PACK20 = 20
-  integer(c_int), public, parameter :: DATATYPE_PACK21 = 21
-  integer(c_int), public, parameter :: DATATYPE_PACK22 = 22
-  integer(c_int), public, parameter :: DATATYPE_PACK23 = 23
   integer(c_int), public, parameter :: DATATYPE_PACK24 = 24
-  integer(c_int), public, parameter :: DATATYPE_PACK25 = 25
-  integer(c_int), public, parameter :: DATATYPE_PACK26 = 26
-  integer(c_int), public, parameter :: DATATYPE_PACK27 = 27
-  integer(c_int), public, parameter :: DATATYPE_PACK28 = 28
-  integer(c_int), public, parameter :: DATATYPE_PACK29 = 29
-  integer(c_int), public, parameter :: DATATYPE_PACK30 = 30
-  integer(c_int), public, parameter :: DATATYPE_PACK31 = 31
-  integer(c_int), public, parameter :: DATATYPE_PACK32 = 32
-  integer(c_int), public, parameter :: DATATYPE_CPX32 = 64
-  integer(c_int), public, parameter :: DATATYPE_CPX64 = 128
   integer(c_int), public, parameter :: DATATYPE_FLT32 = 132
   integer(c_int), public, parameter :: DATATYPE_FLT64 = 164
-  integer(c_int), public, parameter :: DATATYPE_INT8 = 208
-  integer(c_int), public, parameter :: DATATYPE_INT16 = 216
   integer(c_int), public, parameter :: DATATYPE_INT32 = 232
-  integer(c_int), public, parameter :: DATATYPE_UINT8 = 308
-  integer(c_int), public, parameter :: DATATYPE_UINT16 = 316
-  integer(c_int), public, parameter :: DATATYPE_UINT32 = 332
+  integer(c_int), public, parameter :: CDI_DATATYPE_INT = 251
+  integer(c_int), public, parameter :: CDI_DATATYPE_FLT = 252
+  integer(c_int), public, parameter :: CDI_DATATYPE_TXT = 253
+  integer(c_int), public, parameter :: CDI_DATATYPE_CPX = 254
+  integer(c_int), public, parameter :: CDI_DATATYPE_UCHAR = 255
+  integer(c_int), public, parameter :: CDI_DATATYPE_LONG = 256
   integer(c_int), public, parameter :: DATATYPE_INT = 251
   integer(c_int), public, parameter :: DATATYPE_FLT = 252
   integer(c_int), public, parameter :: DATATYPE_TXT = 253
   integer(c_int), public, parameter :: DATATYPE_CPX = 254
   integer(c_int), public, parameter :: DATATYPE_UCHAR = 255
   integer(c_int), public, parameter :: DATATYPE_LONG = 256
-  integer(c_int), public, parameter :: CHUNK_AUTO = 1
-  integer(c_int), public, parameter :: CHUNK_GRID = 2
-  integer(c_int), public, parameter :: CHUNK_LINES = 3
+  integer(c_int), public, parameter :: CDI_CHUNK_AUTO = 1
+  integer(c_int), public, parameter :: CDI_CHUNK_GRID = 2
+  integer(c_int), public, parameter :: CDI_CHUNK_LINES = 3
   integer(c_int), public, parameter :: GRID_GENERIC = 1
   integer(c_int), public, parameter :: GRID_GAUSSIAN = 2
   integer(c_int), public, parameter :: GRID_GAUSSIAN_REDUCED = 3
@@ -119,10 +140,11 @@ module mo_cdi
   integer(c_int), public, parameter :: GRID_UNSTRUCTURED = 9
   integer(c_int), public, parameter :: GRID_CURVILINEAR = 10
   integer(c_int), public, parameter :: GRID_LCC = 11
-  integer(c_int), public, parameter :: GRID_LCC2 = 12
-  integer(c_int), public, parameter :: GRID_LAEA = 13
-  integer(c_int), public, parameter :: GRID_SINUSOIDAL = 14
-  integer(c_int), public, parameter :: GRID_PROJECTION = 15
+  integer(c_int), public, parameter :: GRID_PROJECTION = 12
+  integer(c_int), public, parameter :: CDI_PROJ_RLL = 21
+  integer(c_int), public, parameter :: CDI_PROJ_LCC = 22
+  integer(c_int), public, parameter :: CDI_PROJ_LAEA = 23
+  integer(c_int), public, parameter :: CDI_PROJ_SINU = 24
   integer(c_int), public, parameter :: ZAXIS_SURFACE = 0
   integer(c_int), public, parameter :: ZAXIS_GENERIC = 1
   integer(c_int), public, parameter :: ZAXIS_HYBRID = 2
@@ -412,15 +434,16 @@ module mo_cdi
   public :: vlistInqVarNamePtr
   public :: vlistInqVarLongnamePtr
   public :: vlistInqVarUnitsPtr
-  public :: vlistInqNatts
-  public :: vlistInqAtt
-  public :: vlistDelAtt
-  public :: vlistDefAttInt
-  public :: vlistDefAttFlt
-  public :: vlistDefAttTxt
-  public :: vlistInqAttInt
-  public :: vlistInqAttFlt
-  public :: vlistInqAttTxt
+  public :: cdiInqNatts
+  public :: cdiInqAtt
+  public :: cdiDelAtt
+  public :: cdiCopyAtts
+  public :: cdiDefAttInt
+  public :: cdiDefAttFlt
+  public :: cdiDefAttTxt
+  public :: cdiInqAttInt
+  public :: cdiInqAttFlt
+  public :: cdiInqAttTxt
   public :: gridName
   public :: gridNamePtr
   public :: gridCompress
@@ -432,6 +455,9 @@ module mo_cdi
   public :: gridCreate
   public :: gridDestroy
   public :: gridDuplicate
+  public :: gridDefProj
+  public :: gridInqProj
+  public :: gridInqProjType
   public :: gridInqType
   public :: gridInqSize
   public :: gridDefXsize
@@ -444,17 +470,28 @@ module mo_cdi
   public :: gridInqXvals
   public :: gridDefYvals
   public :: gridInqYvals
-  integer(c_int), public, parameter :: CDI_GRID_XNAME = 901
-  integer(c_int), public, parameter :: CDI_GRID_YNAME = 902
-  integer(c_int), public, parameter :: CDI_GRID_XDIMNAME = 903
-  integer(c_int), public, parameter :: CDI_GRID_YDIMNAME = 904
-  integer(c_int), public, parameter :: CDI_GRID_VDIMNAME = 905
-  integer(c_int), public, parameter :: CDI_GRID_XLONGNAME = 906
-  integer(c_int), public, parameter :: CDI_GRID_YLONGNAME = 907
-  integer(c_int), public, parameter :: CDI_GRID_XUNITS = 908
-  integer(c_int), public, parameter :: CDI_GRID_YUNITS = 909
-  public :: cdiGridDefString
-  public :: cdiGridInqString
+  integer(c_int), public, parameter :: CDI_KEY_XNAME = 901
+  integer(c_int), public, parameter :: CDI_KEY_XDIMNAME = 902
+  integer(c_int), public, parameter :: CDI_KEY_XLONGNAME = 903
+  integer(c_int), public, parameter :: CDI_KEY_XUNITS = 904
+  integer(c_int), public, parameter :: CDI_KEY_YNAME = 911
+  integer(c_int), public, parameter :: CDI_KEY_YDIMNAME = 912
+  integer(c_int), public, parameter :: CDI_KEY_YLONGNAME = 913
+  integer(c_int), public, parameter :: CDI_KEY_YUNITS = 914
+  integer(c_int), public, parameter :: CDI_KEY_VDIMNAME = 920
+  integer(c_int), public, parameter :: CDI_KEY_MAPPING = 921
+  integer(c_int), public, parameter :: CDI_KEY_MAPNAME = 922
+  integer(c_int), public, parameter :: CDI_KEY_NAME = 941
+  integer(c_int), public, parameter :: CDI_KEY_DIMNAME = 942
+  integer(c_int), public, parameter :: CDI_KEY_LONGNAME = 943
+  integer(c_int), public, parameter :: CDI_KEY_UNITS = 944
+  integer(c_int), public, parameter :: CDI_KEY_PSNAME = 950
+  integer(c_int), public, parameter :: CDI_KEY_P0NAME = 951
+  integer(c_int), public, parameter :: CDI_KEY_P0VALUE = 952
+  public :: cdiGridDefKeyStr
+  public :: cdiGridInqKeyStr
+  public :: cdiZaxisDefKeyFlt
+  public :: cdiZaxisInqKeyFlt
   public :: gridDefXname
   public :: gridInqXname
   public :: gridDefXlongname
@@ -476,23 +513,8 @@ module mo_cdi
   public :: gridInqXinc
   public :: gridInqYinc
   public :: gridIsCircular
-  public :: gridIsRotated
-  public :: gridDefXpole
-  public :: gridInqXpole
-  public :: gridDefYpole
-  public :: gridInqYpole
-  public :: gridDefAngle
-  public :: gridInqAngle
   public :: gridInqTrunc
   public :: gridDefTrunc
-  public :: gridDefGMEnd
-  public :: gridInqGMEnd
-  public :: gridDefGMEni
-  public :: gridInqGMEni
-  public :: gridDefGMEni2
-  public :: gridInqGMEni2
-  public :: gridDefGMEni3
-  public :: gridInqGMEni3
   public :: gridDefNumber
   public :: gridInqNumber
   public :: gridDefPosition
@@ -501,12 +523,12 @@ module mo_cdi
   public :: gridInqReference
   public :: gridDefUUID
   public :: gridInqUUID
-  public :: gridDefLCC
-  public :: gridInqLCC
-  public :: gridDefLcc2
-  public :: gridInqLcc2
-  public :: gridDefLaea
-  public :: gridInqLaea
+  public :: gridDefParamRLL
+  public :: gridInqParamRLL
+  public :: gridDefParamGME
+  public :: gridInqParamGME
+  public :: gridDefParamLCC
+  public :: gridInqParamLCC
   public :: gridDefArea
   public :: gridInqArea
   public :: gridHasArea
@@ -522,12 +544,12 @@ module mo_cdi
   public :: gridDefComplexPacking
   public :: gridInqComplexPacking
   public :: zaxisName
+  public :: zaxisNamePtr
   public :: zaxisCreate
   public :: zaxisDestroy
   public :: zaxisInqType
   public :: zaxisInqSize
   public :: zaxisDuplicate
-  public :: zaxisResize
   public :: zaxisPrint
   public :: zaxisDefLevels
   public :: zaxisInqLevels
@@ -539,13 +561,8 @@ module mo_cdi
   public :: zaxisInqNumber
   public :: zaxisDefUUID
   public :: zaxisInqUUID
-  integer(c_int), public, parameter :: CDI_ZAXIS_NAME = 801
-  integer(c_int), public, parameter :: CDI_ZAXIS_DIMNAME = 802
-  integer(c_int), public, parameter :: CDI_ZAXIS_VDIMNAME = 803
-  integer(c_int), public, parameter :: CDI_ZAXIS_LONGNAME = 804
-  integer(c_int), public, parameter :: CDI_ZAXIS_UNITS = 805
-  public :: cdiZaxisDefString
-  public :: cdiZaxisInqString
+  public :: cdiZaxisDefKeyStr
+  public :: cdiZaxisInqKeyStr
   public :: zaxisDefName
   public :: zaxisInqName
   public :: zaxisDefLongname
@@ -553,8 +570,6 @@ module mo_cdi
   public :: zaxisDefUnits
   public :: zaxisInqUnits
   public :: zaxisInqStdname
-  public :: zaxisDefPsName
-  public :: zaxisInqPsName
   public :: zaxisDefPrec
   public :: zaxisInqPrec
   public :: zaxisDefPositive
@@ -563,7 +578,6 @@ module mo_cdi
   public :: zaxisInqScalar
   public :: zaxisDefLtype
   public :: zaxisInqLtype
-  public :: zaxisInqLevelsPtr
   public :: zaxisDefVct
   public :: zaxisInqVct
   public :: zaxisInqVctSize
@@ -1735,14 +1749,24 @@ module mo_cdi
     & 'cdiClearAdditionalKeys')
     end subroutine cdiClearAdditionalKeys
 
-    function vlistInqNatts(vlistID_dummy, varID_dummy, nattsp_dummy) bind(c,&
-    & name = 'vlistInqNatts') result(f_result)
+    function cdiInqNatts(cdiID_dummy, varID_dummy, nattsp_dummy) bind(c, name =&
+    & 'cdiInqNatts') result(f_result)
       import c_int
-      integer(c_int), value :: vlistID_dummy
+      integer(c_int), value :: cdiID_dummy
       integer(c_int), value :: varID_dummy
       integer(c_int), intent(inout) :: nattsp_dummy
       integer(c_int) :: f_result
-    end function vlistInqNatts
+    end function cdiInqNatts
+
+    function cdiCopyAtts(cdiID1_dummy, varID1_dummy, cdiID2_dummy,&
+    & varID2_dummy) bind(c, name = 'cdiCopyAtts') result(f_result)
+      import c_int
+      integer(c_int), value :: cdiID1_dummy
+      integer(c_int), value :: varID1_dummy
+      integer(c_int), value :: cdiID2_dummy
+      integer(c_int), value :: varID2_dummy
+      integer(c_int) :: f_result
+    end function cdiCopyAtts
 
     subroutine gridCompress(gridID_dummy) bind(c, name = 'gridCompress')
       import c_int
@@ -1779,11 +1803,9 @@ module mo_cdi
       integer(c_int) :: f_result
     end function gridInqMask
 
-    subroutine gridPrint(gridID_dummy, index_dummy, opt_dummy) bind(c, name =&
-    & 'gridPrint')
+    subroutine gridPrint(gridID_dummy, opt_dummy) bind(c, name = 'gridPrint')
       import c_int
       integer(c_int), value :: gridID_dummy
-      integer(c_int), value :: index_dummy
       integer(c_int), value :: opt_dummy
     end subroutine gridPrint
 
@@ -1807,6 +1829,27 @@ module mo_cdi
       integer(c_int) :: f_result
     end function gridDuplicate
 
+    subroutine gridDefProj(gridID_dummy, projID_dummy) bind(c, name =&
+    & 'gridDefProj')
+      import c_int
+      integer(c_int), value :: gridID_dummy
+      integer(c_int), value :: projID_dummy
+    end subroutine gridDefProj
+
+    function gridInqProj(gridID_dummy) bind(c, name = 'gridInqProj')&
+    & result(f_result)
+      import c_int
+      integer(c_int), value :: gridID_dummy
+      integer(c_int) :: f_result
+    end function gridInqProj
+
+    function gridInqProjType(gridID_dummy) bind(c, name = 'gridInqProjType')&
+    & result(f_result)
+      import c_int
+      integer(c_int), value :: gridID_dummy
+      integer(c_int) :: f_result
+    end function gridInqProjType
+
     function gridInqType(gridID_dummy) bind(c, name = 'gridInqType')&
     & result(f_result)
       import c_int
@@ -1892,6 +1935,24 @@ module mo_cdi
       integer(c_int) :: f_result
     end function gridInqYvals
 
+    function cdiZaxisDefKeyFlt(zaxisID_dummy, key_dummy, value_dummy) bind(c,&
+    & name = 'cdiZaxisDefKeyFlt') result(f_result)
+      import c_double, c_int
+      integer(c_int), value :: zaxisID_dummy
+      integer(c_int), value :: key_dummy
+      real(c_double), value :: value_dummy
+      integer(c_int) :: f_result
+    end function cdiZaxisDefKeyFlt
+
+    function cdiZaxisInqKeyFlt(zaxisID_dummy, key_dummy, value_dummy) bind(c,&
+    & name = 'cdiZaxisInqKeyFlt') result(f_result)
+      import c_double, c_int
+      integer(c_int), value :: zaxisID_dummy
+      integer(c_int), value :: key_dummy
+      real(c_double), intent(inout) :: value_dummy
+      integer(c_int) :: f_result
+    end function cdiZaxisInqKeyFlt
+
     subroutine gridDefPrec(gridID_dummy, prec_dummy) bind(c, name =&
     & 'gridDefPrec')
       import c_int
@@ -1943,55 +2004,6 @@ module mo_cdi
       integer(c_int) :: f_result
     end function gridIsCircular
 
-    function gridIsRotated(gridID_dummy) bind(c, name = 'gridIsRotated')&
-    & result(f_result)
-      import c_int
-      integer(c_int), value :: gridID_dummy
-      integer(c_int) :: f_result
-    end function gridIsRotated
-
-    subroutine gridDefXpole(gridID_dummy, xpole_dummy) bind(c, name =&
-    & 'gridDefXpole')
-      import c_double, c_int
-      integer(c_int), value :: gridID_dummy
-      real(c_double), value :: xpole_dummy
-    end subroutine gridDefXpole
-
-    function gridInqXpole(gridID_dummy) bind(c, name = 'gridInqXpole')&
-    & result(f_result)
-      import c_double, c_int
-      integer(c_int), value :: gridID_dummy
-      real(c_double) :: f_result
-    end function gridInqXpole
-
-    subroutine gridDefYpole(gridID_dummy, ypole_dummy) bind(c, name =&
-    & 'gridDefYpole')
-      import c_double, c_int
-      integer(c_int), value :: gridID_dummy
-      real(c_double), value :: ypole_dummy
-    end subroutine gridDefYpole
-
-    function gridInqYpole(gridID_dummy) bind(c, name = 'gridInqYpole')&
-    & result(f_result)
-      import c_double, c_int
-      integer(c_int), value :: gridID_dummy
-      real(c_double) :: f_result
-    end function gridInqYpole
-
-    subroutine gridDefAngle(gridID_dummy, angle_dummy) bind(c, name =&
-    & 'gridDefAngle')
-      import c_double, c_int
-      integer(c_int), value :: gridID_dummy
-      real(c_double), value :: angle_dummy
-    end subroutine gridDefAngle
-
-    function gridInqAngle(gridID_dummy) bind(c, name = 'gridInqAngle')&
-    & result(f_result)
-      import c_double, c_int
-      integer(c_int), value :: gridID_dummy
-      real(c_double) :: f_result
-    end function gridInqAngle
-
     function gridInqTrunc(gridID_dummy) bind(c, name = 'gridInqTrunc')&
     & result(f_result)
       import c_int
@@ -2006,62 +2018,6 @@ module mo_cdi
       integer(c_int), value :: trunc_dummy
     end subroutine gridDefTrunc
 
-    subroutine gridDefGMEnd(gridID_dummy, nd_dummy) bind(c, name =&
-    & 'gridDefGMEnd')
-      import c_int
-      integer(c_int), value :: gridID_dummy
-      integer(c_int), value :: nd_dummy
-    end subroutine gridDefGMEnd
-
-    function gridInqGMEnd(gridID_dummy) bind(c, name = 'gridInqGMEnd')&
-    & result(f_result)
-      import c_int
-      integer(c_int), value :: gridID_dummy
-      integer(c_int) :: f_result
-    end function gridInqGMEnd
-
-    subroutine gridDefGMEni(gridID_dummy, ni_dummy) bind(c, name =&
-    & 'gridDefGMEni')
-      import c_int
-      integer(c_int), value :: gridID_dummy
-      integer(c_int), value :: ni_dummy
-    end subroutine gridDefGMEni
-
-    function gridInqGMEni(gridID_dummy) bind(c, name = 'gridInqGMEni')&
-    & result(f_result)
-      import c_int
-      integer(c_int), value :: gridID_dummy
-      integer(c_int) :: f_result
-    end function gridInqGMEni
-
-    subroutine gridDefGMEni2(gridID_dummy, ni2_dummy) bind(c, name =&
-    & 'gridDefGMEni2')
-      import c_int
-      integer(c_int), value :: gridID_dummy
-      integer(c_int), value :: ni2_dummy
-    end subroutine gridDefGMEni2
-
-    function gridInqGMEni2(gridID_dummy) bind(c, name = 'gridInqGMEni2')&
-    & result(f_result)
-      import c_int
-      integer(c_int), value :: gridID_dummy
-      integer(c_int) :: f_result
-    end function gridInqGMEni2
-
-    subroutine gridDefGMEni3(gridID_dummy, ni3_dummy) bind(c, name =&
-    & 'gridDefGMEni3')
-      import c_int
-      integer(c_int), value :: gridID_dummy
-      integer(c_int), value :: ni3_dummy
-    end subroutine gridDefGMEni3
-
-    function gridInqGMEni3(gridID_dummy) bind(c, name = 'gridInqGMEni3')&
-    & result(f_result)
-      import c_int
-      integer(c_int), value :: gridID_dummy
-      integer(c_int) :: f_result
-    end function gridInqGMEni3
-
     subroutine gridDefNumber(gridID_dummy, number_dummy) bind(c, name =&
     & 'gridDefNumber')
       import c_int
@@ -2104,9 +2060,47 @@ module mo_cdi
       integer(kind = c_signed_char), intent(inout) :: uuid_dummy(CDI_UUID_SIZE)
     end subroutine gridInqUUID
 
-    subroutine gridDefLCC(gridID_dummy, originLon_dummy, originLat_dummy,&
+    subroutine gridDefParamRLL(gridID_dummy, xpole_dummy, ypole_dummy,&
+    & angle_dummy) bind(c, name = 'gridDefParamRLL')
+      import c_double, c_int
+      integer(c_int), value :: gridID_dummy
+      real(c_double), value :: xpole_dummy
+      real(c_double), value :: ypole_dummy
+      real(c_double), value :: angle_dummy
+    end subroutine gridDefParamRLL
+
+    subroutine gridInqParamRLL(gridID_dummy, xpole_dummy, ypole_dummy,&
+    & angle_dummy) bind(c, name = 'gridInqParamRLL')
+      import c_double, c_int
+      integer(c_int), value :: gridID_dummy
+      real(c_double), intent(inout) :: xpole_dummy
+      real(c_double), intent(inout) :: ypole_dummy
+      real(c_double), intent(inout) :: angle_dummy
+    end subroutine gridInqParamRLL
+
+    subroutine gridDefParamGME(gridID_dummy, nd_dummy, ni_dummy, ni2_dummy,&
+    & ni3_dummy) bind(c, name = 'gridDefParamGME')
+      import c_int
+      integer(c_int), value :: gridID_dummy
+      integer(c_int), value :: nd_dummy
+      integer(c_int), value :: ni_dummy
+      integer(c_int), value :: ni2_dummy
+      integer(c_int), value :: ni3_dummy
+    end subroutine gridDefParamGME
+
+    subroutine gridInqParamGME(gridID_dummy, nd_dummy, ni_dummy, ni2_dummy,&
+    & ni3_dummy) bind(c, name = 'gridInqParamGME')
+      import c_int
+      integer(c_int), value :: gridID_dummy
+      integer(c_int), intent(inout) :: nd_dummy
+      integer(c_int), intent(inout) :: ni_dummy
+      integer(c_int), intent(inout) :: ni2_dummy
+      integer(c_int), intent(inout) :: ni3_dummy
+    end subroutine gridInqParamGME
+
+    subroutine gridDefParamLCC(gridID_dummy, originLon_dummy, originLat_dummy,&
     & lonParY_dummy, lat1_dummy, lat2_dummy, xinc_dummy, yinc_dummy,&
-    & projflag_dummy, scanflag_dummy) bind(c, name = 'gridDefLCC')
+    & projflag_dummy, scanflag_dummy) bind(c, name = 'gridDefParamLCC')
       import c_double, c_int
       integer(c_int), value :: gridID_dummy
       real(c_double), value :: originLon_dummy
@@ -2118,11 +2112,11 @@ module mo_cdi
       real(c_double), value :: yinc_dummy
       integer(c_int), value :: projflag_dummy
       integer(c_int), value :: scanflag_dummy
-    end subroutine gridDefLCC
+    end subroutine gridDefParamLCC
 
-    subroutine gridInqLCC(gridID_dummy, originLon_dummy, originLat_dummy,&
+    subroutine gridInqParamLCC(gridID_dummy, originLon_dummy, originLat_dummy,&
     & lonParY_dummy, lat1_dummy, lat2_dummy, xinc_dummy, yinc_dummy,&
-    & projflag_dummy, scanflag_dummy) bind(c, name = 'gridInqLCC')
+    & projflag_dummy, scanflag_dummy) bind(c, name = 'gridInqParamLCC')
       import c_double, c_int
       integer(c_int), value :: gridID_dummy
       real(c_double), intent(inout) :: originLon_dummy
@@ -2134,47 +2128,7 @@ module mo_cdi
       real(c_double), intent(inout) :: yinc_dummy
       integer(c_int), intent(inout) :: projflag_dummy
       integer(c_int), intent(inout) :: scanflag_dummy
-    end subroutine gridInqLCC
-
-    subroutine gridDefLcc2(gridID_dummy, earth_radius_dummy, lon_0_dummy,&
-    & lat_0_dummy, lat_1_dummy, lat_2_dummy) bind(c, name = 'gridDefLcc2')
-      import c_double, c_int
-      integer(c_int), value :: gridID_dummy
-      real(c_double), value :: earth_radius_dummy
-      real(c_double), value :: lon_0_dummy
-      real(c_double), value :: lat_0_dummy
-      real(c_double), value :: lat_1_dummy
-      real(c_double), value :: lat_2_dummy
-    end subroutine gridDefLcc2
-
-    subroutine gridInqLcc2(gridID_dummy, earth_radius_dummy, lon_0_dummy,&
-    & lat_0_dummy, lat_1_dummy, lat_2_dummy) bind(c, name = 'gridInqLcc2')
-      import c_double, c_int
-      integer(c_int), value :: gridID_dummy
-      real(c_double), intent(inout) :: earth_radius_dummy
-      real(c_double), intent(inout) :: lon_0_dummy
-      real(c_double), intent(inout) :: lat_0_dummy
-      real(c_double), intent(inout) :: lat_1_dummy
-      real(c_double), intent(inout) :: lat_2_dummy
-    end subroutine gridInqLcc2
-
-    subroutine gridDefLaea(gridID_dummy, earth_radius_dummy, lon_0_dummy,&
-    & lat_0_dummy) bind(c, name = 'gridDefLaea')
-      import c_double, c_int
-      integer(c_int), value :: gridID_dummy
-      real(c_double), value :: earth_radius_dummy
-      real(c_double), value :: lon_0_dummy
-      real(c_double), value :: lat_0_dummy
-    end subroutine gridDefLaea
-
-    subroutine gridInqLaea(gridID_dummy, earth_radius_dummy, lon_0_dummy,&
-    & lat_0_dummy) bind(c, name = 'gridInqLaea')
-      import c_double, c_int
-      integer(c_int), value :: gridID_dummy
-      real(c_double), intent(inout) :: earth_radius_dummy
-      real(c_double), intent(inout) :: lon_0_dummy
-      real(c_double), intent(inout) :: lat_0_dummy
-    end subroutine gridInqLaea
+    end subroutine gridInqParamLCC
 
     subroutine gridDefArea(gridID_dummy, area_dummy) bind(c, name =&
     & 'gridDefArea')
@@ -2311,18 +2265,9 @@ module mo_cdi
       integer(c_int) :: f_result
     end function zaxisDuplicate
 
-    subroutine zaxisResize(zaxisID_dummy, size_dummy) bind(c, name =&
-    & 'zaxisResize')
+    subroutine zaxisPrint(zaxisID_dummy) bind(c, name = 'zaxisPrint')
       import c_int
       integer(c_int), value :: zaxisID_dummy
-      integer(c_int), value :: size_dummy
-    end subroutine zaxisResize
-
-    subroutine zaxisPrint(zaxisID_dummy, index_dummy) bind(c, name =&
-    & 'zaxisPrint')
-      import c_int
-      integer(c_int), value :: zaxisID_dummy
-      integer(c_int), value :: index_dummy
     end subroutine zaxisPrint
 
     subroutine zaxisDefLevels(zaxisID_dummy, levels_dummy) bind(c, name =&
@@ -2332,12 +2277,13 @@ module mo_cdi
       real(c_double), intent(in) :: levels_dummy(*)
     end subroutine zaxisDefLevels
 
-    subroutine zaxisInqLevels(zaxisID_dummy, levels_dummy) bind(c, name =&
-    & 'zaxisInqLevels')
+    function zaxisInqLevels(zaxisID_dummy, levels_dummy) bind(c, name =&
+    & 'zaxisInqLevels') result(f_result)
       import c_double, c_int
       integer(c_int), value :: zaxisID_dummy
       real(c_double), intent(inout) :: levels_dummy(*)
-    end subroutine zaxisInqLevels
+      integer(c_int) :: f_result
+    end function zaxisInqLevels
 
     subroutine zaxisDefLevel(zaxisID_dummy, levelID_dummy, levels_dummy)&
     & bind(c, name = 'zaxisDefLevel')
@@ -2451,13 +2397,6 @@ module mo_cdi
       integer(c_int) :: f_result
     end function zaxisInqLtype
 
-    function zaxisInqLevelsPtr(zaxisID_dummy) bind(c, name =&
-    & 'zaxisInqLevelsPtr') result(f_result)
-      import c_int, c_ptr
-      integer(c_int), value :: zaxisID_dummy
-      type(c_ptr) :: f_result
-    end function zaxisInqLevelsPtr
-
     subroutine zaxisDefVct(zaxisID_dummy, size_dummy, vct_dummy) bind(c, name =&
     & 'zaxisDefVct')
       import c_double, c_int
@@ -4588,10 +4527,10 @@ contains
     end if
   end function vlistInqVarUnitsPtr
 
-  function vlistInqAtt(vlistID_dummy, varID_dummy, attrnum_dummy, name_dummy,&
+  function cdiInqAtt(cdiID_dummy, varID_dummy, attrnum_dummy, name_dummy,&
   & typep_dummy, lenp_dummy) result(f_result)
     integer(c_int) :: f_result
-    integer(c_int), value :: vlistID_dummy
+    integer(c_int), value :: cdiID_dummy
     integer(c_int), value :: varID_dummy
     integer(c_int), value :: attrnum_dummy
     character(kind = c_char, len = *), intent(inout) :: name_dummy
@@ -4600,18 +4539,18 @@ contains
     character(kind = c_char) :: name_temp(len(name_dummy) + 1)
     integer :: name_i
     interface
-      function lib_vlistInqAtt(vlistID_dummy, varID_dummy, attrnum_dummy,&
-      & name_dummy, typep_dummy, lenp_dummy) bind(c, name = 'vlistInqAtt')&
+      function lib_cdiInqAtt(cdiID_dummy, varID_dummy, attrnum_dummy,&
+      & name_dummy, typep_dummy, lenp_dummy) bind(c, name = 'cdiInqAtt')&
       & result(c_result)
         import c_char, c_int
         integer(c_int) :: c_result
-        integer(c_int), value :: vlistID_dummy
+        integer(c_int), value :: cdiID_dummy
         integer(c_int), value :: varID_dummy
         integer(c_int), value :: attrnum_dummy
         character(kind = c_char) :: name_dummy(*)
         integer(c_int), intent(inout) :: typep_dummy
         integer(c_int), intent(inout) :: lenp_dummy
-      end function lib_vlistInqAtt
+      end function lib_cdiInqAtt
     end interface
     name_temp(len(name_dummy) + 1) = c_null_char
     do name_i = len(name_dummy), 1, -1
@@ -4621,7 +4560,7 @@ contains
     do name_i = name_i, 1, -1
         name_temp(name_i) = name_dummy(name_i:name_i)
     end do
-    f_result = lib_vlistInqAtt(vlistID_dummy, varID_dummy, attrnum_dummy,&
+    f_result = lib_cdiInqAtt(cdiID_dummy, varID_dummy, attrnum_dummy,&
     & name_temp, typep_dummy, lenp_dummy)
     do name_i = 1, len(name_dummy)
       if(name_temp(name_i) == c_null_char) exit
@@ -4630,36 +4569,36 @@ contains
     do name_i = name_i, len(name_dummy)
       name_dummy(name_i:name_i) = ' '
     end do
-  end function vlistInqAtt
+  end function cdiInqAtt
 
-  function vlistDelAtt(vlistID_dummy, varID_dummy, name_dummy) result(f_result)
+  function cdiDelAtt(cdiID_dummy, varID_dummy, name_dummy) result(f_result)
     integer(c_int) :: f_result
-    integer(c_int), value :: vlistID_dummy
+    integer(c_int), value :: cdiID_dummy
     integer(c_int), value :: varID_dummy
     character(kind = c_char, len = *), intent(in) :: name_dummy
     character(kind = c_char) :: name_temp(len(name_dummy) + 1)
     integer :: name_i
     interface
-      function lib_vlistDelAtt(vlistID_dummy, varID_dummy, name_dummy) bind(c,&
-      & name = 'vlistDelAtt') result(c_result)
+      function lib_cdiDelAtt(cdiID_dummy, varID_dummy, name_dummy) bind(c, name&
+      & = 'cdiDelAtt') result(c_result)
         import c_char, c_int
         integer(c_int) :: c_result
-        integer(c_int), value :: vlistID_dummy
+        integer(c_int), value :: cdiID_dummy
         integer(c_int), value :: varID_dummy
         character(kind = c_char) :: name_dummy(*)
-      end function lib_vlistDelAtt
+      end function lib_cdiDelAtt
     end interface
     do name_i = 1, len(name_dummy)
       name_temp(name_i) = name_dummy(name_i:name_i)
     end do
     name_temp(len(name_dummy) + 1) = c_null_char
-    f_result = lib_vlistDelAtt(vlistID_dummy, varID_dummy, name_temp)
-  end function vlistDelAtt
+    f_result = lib_cdiDelAtt(cdiID_dummy, varID_dummy, name_temp)
+  end function cdiDelAtt
 
-  function vlistDefAttInt(vlistID_dummy, varID_dummy, name_dummy, type_dummy,&
+  function cdiDefAttInt(cdiID_dummy, varID_dummy, name_dummy, type_dummy,&
   & len_dummy, ip_dummy) result(f_result)
     integer(c_int) :: f_result
-    integer(c_int), value :: vlistID_dummy
+    integer(c_int), value :: cdiID_dummy
     integer(c_int), value :: varID_dummy
     character(kind = c_char, len = *), intent(in) :: name_dummy
     integer(c_int), value :: type_dummy
@@ -4668,31 +4607,31 @@ contains
     character(kind = c_char) :: name_temp(len(name_dummy) + 1)
     integer :: name_i
     interface
-      function lib_vlistDefAttInt(vlistID_dummy, varID_dummy, name_dummy,&
-      & type_dummy, len_dummy, ip_dummy) bind(c, name = 'vlistDefAttInt')&
+      function lib_cdiDefAttInt(cdiID_dummy, varID_dummy, name_dummy,&
+      & type_dummy, len_dummy, ip_dummy) bind(c, name = 'cdiDefAttInt')&
       & result(c_result)
         import c_char, c_int
         integer(c_int) :: c_result
-        integer(c_int), value :: vlistID_dummy
+        integer(c_int), value :: cdiID_dummy
         integer(c_int), value :: varID_dummy
         character(kind = c_char) :: name_dummy(*)
         integer(c_int), value :: type_dummy
         integer(c_int), value :: len_dummy
         integer(c_int), intent(in) :: ip_dummy(*)
-      end function lib_vlistDefAttInt
+      end function lib_cdiDefAttInt
     end interface
     do name_i = 1, len(name_dummy)
       name_temp(name_i) = name_dummy(name_i:name_i)
     end do
     name_temp(len(name_dummy) + 1) = c_null_char
-    f_result = lib_vlistDefAttInt(vlistID_dummy, varID_dummy, name_temp,&
+    f_result = lib_cdiDefAttInt(cdiID_dummy, varID_dummy, name_temp,&
     & type_dummy, len_dummy, ip_dummy)
-  end function vlistDefAttInt
+  end function cdiDefAttInt
 
-  function vlistDefAttFlt(vlistID_dummy, varID_dummy, name_dummy, type_dummy,&
+  function cdiDefAttFlt(cdiID_dummy, varID_dummy, name_dummy, type_dummy,&
   & len_dummy, dp_dummy) result(f_result)
     integer(c_int) :: f_result
-    integer(c_int), value :: vlistID_dummy
+    integer(c_int), value :: cdiID_dummy
     integer(c_int), value :: varID_dummy
     character(kind = c_char, len = *), intent(in) :: name_dummy
     integer(c_int), value :: type_dummy
@@ -4701,31 +4640,31 @@ contains
     character(kind = c_char) :: name_temp(len(name_dummy) + 1)
     integer :: name_i
     interface
-      function lib_vlistDefAttFlt(vlistID_dummy, varID_dummy, name_dummy,&
-      & type_dummy, len_dummy, dp_dummy) bind(c, name = 'vlistDefAttFlt')&
+      function lib_cdiDefAttFlt(cdiID_dummy, varID_dummy, name_dummy,&
+      & type_dummy, len_dummy, dp_dummy) bind(c, name = 'cdiDefAttFlt')&
       & result(c_result)
         import c_char, c_double, c_int
         integer(c_int) :: c_result
-        integer(c_int), value :: vlistID_dummy
+        integer(c_int), value :: cdiID_dummy
         integer(c_int), value :: varID_dummy
         character(kind = c_char) :: name_dummy(*)
         integer(c_int), value :: type_dummy
         integer(c_int), value :: len_dummy
         real(c_double), intent(in) :: dp_dummy(*)
-      end function lib_vlistDefAttFlt
+      end function lib_cdiDefAttFlt
     end interface
     do name_i = 1, len(name_dummy)
       name_temp(name_i) = name_dummy(name_i:name_i)
     end do
     name_temp(len(name_dummy) + 1) = c_null_char
-    f_result = lib_vlistDefAttFlt(vlistID_dummy, varID_dummy, name_temp,&
+    f_result = lib_cdiDefAttFlt(cdiID_dummy, varID_dummy, name_temp,&
     & type_dummy, len_dummy, dp_dummy)
-  end function vlistDefAttFlt
+  end function cdiDefAttFlt
 
-  function vlistDefAttTxt(vlistID_dummy, varID_dummy, name_dummy, len_dummy,&
+  function cdiDefAttTxt(cdiID_dummy, varID_dummy, name_dummy, len_dummy,&
   & tp_cbuf_dummy) result(f_result)
     integer(c_int) :: f_result
-    integer(c_int), value :: vlistID_dummy
+    integer(c_int), value :: cdiID_dummy
     integer(c_int), value :: varID_dummy
     character(kind = c_char, len = *), intent(in) :: name_dummy
     integer(c_int), value :: len_dummy
@@ -4735,17 +4674,17 @@ contains
     character(kind = c_char) :: tp_cbuf_temp(len(tp_cbuf_dummy) + 1)
     integer :: tp_cbuf_i
     interface
-      function lib_vlistDefAttTxt(vlistID_dummy, varID_dummy, name_dummy,&
-      & len_dummy, tp_cbuf_dummy) bind(c, name = 'vlistDefAttTxt')&
+      function lib_cdiDefAttTxt(cdiID_dummy, varID_dummy, name_dummy,&
+      & len_dummy, tp_cbuf_dummy) bind(c, name = 'cdiDefAttTxt')&
       & result(c_result)
         import c_char, c_int
         integer(c_int) :: c_result
-        integer(c_int), value :: vlistID_dummy
+        integer(c_int), value :: cdiID_dummy
         integer(c_int), value :: varID_dummy
         character(kind = c_char) :: name_dummy(*)
         integer(c_int), value :: len_dummy
         character(kind = c_char) :: tp_cbuf_dummy(*)
-      end function lib_vlistDefAttTxt
+      end function lib_cdiDefAttTxt
     end interface
     do name_i = 1, len(name_dummy)
       name_temp(name_i) = name_dummy(name_i:name_i)
@@ -4755,14 +4694,14 @@ contains
       tp_cbuf_temp(tp_cbuf_i) = tp_cbuf_dummy(tp_cbuf_i:tp_cbuf_i)
     end do
     tp_cbuf_temp(len(tp_cbuf_dummy) + 1) = c_null_char
-    f_result = lib_vlistDefAttTxt(vlistID_dummy, varID_dummy, name_temp,&
-    & len_dummy, tp_cbuf_temp)
-  end function vlistDefAttTxt
+    f_result = lib_cdiDefAttTxt(cdiID_dummy, varID_dummy, name_temp, len_dummy,&
+    & tp_cbuf_temp)
+  end function cdiDefAttTxt
 
-  function vlistInqAttInt(vlistID_dummy, varID_dummy, name_dummy, mlen_dummy,&
+  function cdiInqAttInt(cdiID_dummy, varID_dummy, name_dummy, mlen_dummy,&
   & ip_dummy) result(f_result)
     integer(c_int) :: f_result
-    integer(c_int), value :: vlistID_dummy
+    integer(c_int), value :: cdiID_dummy
     integer(c_int), value :: varID_dummy
     character(kind = c_char, len = *), intent(in) :: name_dummy
     integer(c_int), value :: mlen_dummy
@@ -4770,29 +4709,29 @@ contains
     character(kind = c_char) :: name_temp(len(name_dummy) + 1)
     integer :: name_i
     interface
-      function lib_vlistInqAttInt(vlistID_dummy, varID_dummy, name_dummy,&
-      & mlen_dummy, ip_dummy) bind(c, name = 'vlistInqAttInt') result(c_result)
+      function lib_cdiInqAttInt(cdiID_dummy, varID_dummy, name_dummy,&
+      & mlen_dummy, ip_dummy) bind(c, name = 'cdiInqAttInt') result(c_result)
         import c_char, c_int
         integer(c_int) :: c_result
-        integer(c_int), value :: vlistID_dummy
+        integer(c_int), value :: cdiID_dummy
         integer(c_int), value :: varID_dummy
         character(kind = c_char) :: name_dummy(*)
         integer(c_int), value :: mlen_dummy
         integer(c_int), intent(inout) :: ip_dummy(*)
-      end function lib_vlistInqAttInt
+      end function lib_cdiInqAttInt
     end interface
     do name_i = 1, len(name_dummy)
       name_temp(name_i) = name_dummy(name_i:name_i)
     end do
     name_temp(len(name_dummy) + 1) = c_null_char
-    f_result = lib_vlistInqAttInt(vlistID_dummy, varID_dummy, name_temp,&
+    f_result = lib_cdiInqAttInt(cdiID_dummy, varID_dummy, name_temp,&
     & mlen_dummy, ip_dummy)
-  end function vlistInqAttInt
+  end function cdiInqAttInt
 
-  function vlistInqAttFlt(vlistID_dummy, varID_dummy, name_dummy, mlen_dummy,&
+  function cdiInqAttFlt(cdiID_dummy, varID_dummy, name_dummy, mlen_dummy,&
   & dp_dummy) result(f_result)
     integer(c_int) :: f_result
-    integer(c_int), value :: vlistID_dummy
+    integer(c_int), value :: cdiID_dummy
     integer(c_int), value :: varID_dummy
     character(kind = c_char, len = *), intent(in) :: name_dummy
     integer(c_int), value :: mlen_dummy
@@ -4800,29 +4739,29 @@ contains
     character(kind = c_char) :: name_temp(len(name_dummy) + 1)
     integer :: name_i
     interface
-      function lib_vlistInqAttFlt(vlistID_dummy, varID_dummy, name_dummy,&
-      & mlen_dummy, dp_dummy) bind(c, name = 'vlistInqAttFlt') result(c_result)
+      function lib_cdiInqAttFlt(cdiID_dummy, varID_dummy, name_dummy,&
+      & mlen_dummy, dp_dummy) bind(c, name = 'cdiInqAttFlt') result(c_result)
         import c_char, c_double, c_int
         integer(c_int) :: c_result
-        integer(c_int), value :: vlistID_dummy
+        integer(c_int), value :: cdiID_dummy
         integer(c_int), value :: varID_dummy
         character(kind = c_char) :: name_dummy(*)
         integer(c_int), value :: mlen_dummy
         real(c_double), intent(inout) :: dp_dummy(*)
-      end function lib_vlistInqAttFlt
+      end function lib_cdiInqAttFlt
     end interface
     do name_i = 1, len(name_dummy)
       name_temp(name_i) = name_dummy(name_i:name_i)
     end do
     name_temp(len(name_dummy) + 1) = c_null_char
-    f_result = lib_vlistInqAttFlt(vlistID_dummy, varID_dummy, name_temp,&
+    f_result = lib_cdiInqAttFlt(cdiID_dummy, varID_dummy, name_temp,&
     & mlen_dummy, dp_dummy)
-  end function vlistInqAttFlt
+  end function cdiInqAttFlt
 
-  function vlistInqAttTxt(vlistID_dummy, varID_dummy, name_dummy, mlen_dummy,&
+  function cdiInqAttTxt(cdiID_dummy, varID_dummy, name_dummy, mlen_dummy,&
   & tp_cbuf_dummy) result(f_result)
     integer(c_int) :: f_result
-    integer(c_int), value :: vlistID_dummy
+    integer(c_int), value :: cdiID_dummy
     integer(c_int), value :: varID_dummy
     character(kind = c_char, len = *), intent(in) :: name_dummy
     integer(c_int), value :: mlen_dummy
@@ -4832,17 +4771,17 @@ contains
     character(kind = c_char) :: tp_cbuf_temp(len(tp_cbuf_dummy) + 1)
     integer :: tp_cbuf_i
     interface
-      function lib_vlistInqAttTxt(vlistID_dummy, varID_dummy, name_dummy,&
-      & mlen_dummy, tp_cbuf_dummy) bind(c, name = 'vlistInqAttTxt')&
+      function lib_cdiInqAttTxt(cdiID_dummy, varID_dummy, name_dummy,&
+      & mlen_dummy, tp_cbuf_dummy) bind(c, name = 'cdiInqAttTxt')&
       & result(c_result)
         import c_char, c_int
         integer(c_int) :: c_result
-        integer(c_int), value :: vlistID_dummy
+        integer(c_int), value :: cdiID_dummy
         integer(c_int), value :: varID_dummy
         character(kind = c_char) :: name_dummy(*)
         integer(c_int), value :: mlen_dummy
         character(kind = c_char) :: tp_cbuf_dummy(*)
-      end function lib_vlistInqAttTxt
+      end function lib_cdiInqAttTxt
     end interface
     do name_i = 1, len(name_dummy)
       name_temp(name_i) = name_dummy(name_i:name_i)
@@ -4856,7 +4795,7 @@ contains
     do tp_cbuf_i = tp_cbuf_i, 1, -1
         tp_cbuf_temp(tp_cbuf_i) = tp_cbuf_dummy(tp_cbuf_i:tp_cbuf_i)
     end do
-    f_result = lib_vlistInqAttTxt(vlistID_dummy, varID_dummy, name_temp,&
+    f_result = lib_cdiInqAttTxt(cdiID_dummy, varID_dummy, name_temp,&
     & mlen_dummy, tp_cbuf_temp)
     do tp_cbuf_i = 1, len(tp_cbuf_dummy)
       if(tp_cbuf_temp(tp_cbuf_i) == c_null_char) exit
@@ -4865,7 +4804,7 @@ contains
     do tp_cbuf_i = tp_cbuf_i, len(tp_cbuf_dummy)
       tp_cbuf_dummy(tp_cbuf_i:tp_cbuf_i) = ' '
     end do
-  end function vlistInqAttTxt
+  end function cdiInqAttTxt
 
   subroutine gridName(gridtype_dummy, gridname_dummy)
     integer(c_int), value :: gridtype_dummy
@@ -4919,7 +4858,7 @@ contains
     end if
   end function gridNamePtr
 
-  function cdiGridDefString(gridID_dummy, key_dummy, size_dummy, mesg_dummy)&
+  function cdiGridDefKeyStr(gridID_dummy, key_dummy, size_dummy, mesg_dummy)&
   & result(f_result)
     integer(c_int) :: f_result
     integer(c_int), value :: gridID_dummy
@@ -4929,25 +4868,25 @@ contains
     character(kind = c_char) :: mesg_temp(len(mesg_dummy) + 1)
     integer :: mesg_i
     interface
-      function lib_cdiGridDefString(gridID_dummy, key_dummy, size_dummy,&
-      & mesg_dummy) bind(c, name = 'cdiGridDefString') result(c_result)
+      function lib_cdiGridDefKeyStr(gridID_dummy, key_dummy, size_dummy,&
+      & mesg_dummy) bind(c, name = 'cdiGridDefKeyStr') result(c_result)
         import c_char, c_int
         integer(c_int) :: c_result
         integer(c_int), value :: gridID_dummy
         integer(c_int), value :: key_dummy
         integer(c_int), value :: size_dummy
         character(kind = c_char) :: mesg_dummy(*)
-      end function lib_cdiGridDefString
+      end function lib_cdiGridDefKeyStr
     end interface
     do mesg_i = 1, len(mesg_dummy)
       mesg_temp(mesg_i) = mesg_dummy(mesg_i:mesg_i)
     end do
     mesg_temp(len(mesg_dummy) + 1) = c_null_char
-    f_result = lib_cdiGridDefString(gridID_dummy, key_dummy, size_dummy,&
+    f_result = lib_cdiGridDefKeyStr(gridID_dummy, key_dummy, size_dummy,&
     & mesg_temp)
-  end function cdiGridDefString
+  end function cdiGridDefKeyStr
 
-  function cdiGridInqString(gridID_dummy, key_dummy, size_dummy, mesg_dummy)&
+  function cdiGridInqKeyStr(gridID_dummy, key_dummy, size_dummy, mesg_dummy)&
   & result(f_result)
     integer(c_int) :: f_result
     integer(c_int), value :: gridID_dummy
@@ -4957,15 +4896,15 @@ contains
     character(kind = c_char) :: mesg_temp(len(mesg_dummy) + 1)
     integer :: mesg_i
     interface
-      function lib_cdiGridInqString(gridID_dummy, key_dummy, size_dummy,&
-      & mesg_dummy) bind(c, name = 'cdiGridInqString') result(c_result)
+      function lib_cdiGridInqKeyStr(gridID_dummy, key_dummy, size_dummy,&
+      & mesg_dummy) bind(c, name = 'cdiGridInqKeyStr') result(c_result)
         import c_char, c_int
         integer(c_int) :: c_result
         integer(c_int), value :: gridID_dummy
         integer(c_int), value :: key_dummy
         integer(c_int), value :: size_dummy
         character(kind = c_char) :: mesg_dummy(*)
-      end function lib_cdiGridInqString
+      end function lib_cdiGridInqKeyStr
     end interface
     mesg_temp(len(mesg_dummy) + 1) = c_null_char
     do mesg_i = len(mesg_dummy), 1, -1
@@ -4975,7 +4914,7 @@ contains
     do mesg_i = mesg_i, 1, -1
         mesg_temp(mesg_i) = mesg_dummy(mesg_i:mesg_i)
     end do
-    f_result = lib_cdiGridInqString(gridID_dummy, key_dummy, size_dummy,&
+    f_result = lib_cdiGridInqKeyStr(gridID_dummy, key_dummy, size_dummy,&
     & mesg_temp)
     do mesg_i = 1, len(mesg_dummy)
       if(mesg_temp(mesg_i) == c_null_char) exit
@@ -4984,7 +4923,7 @@ contains
     do mesg_i = mesg_i, len(mesg_dummy)
       mesg_dummy(mesg_i:mesg_i) = ' '
     end do
-  end function cdiGridInqString
+  end function cdiGridInqKeyStr
 
   subroutine gridDefXname(gridID_dummy, xname_dummy)
     integer(c_int), value :: gridID_dummy
@@ -5438,7 +5377,28 @@ contains
     end do
   end subroutine zaxisName
 
-  function cdiZaxisDefString(zaxisID_dummy, key_dummy, size_dummy, mesg_dummy)&
+  function zaxisNamePtr(leveltype_dummy) result(f_result)
+    character(kind = c_char), dimension(:), pointer :: f_result
+    integer(c_int), value :: leveltype_dummy
+    type(c_ptr) :: ptr
+    integer :: rv_shape(1)
+    interface
+      function lib_zaxisNamePtr(leveltype_dummy) bind(c, name = 'zaxisNamePtr')&
+      & result(c_result)
+        import c_int, c_ptr
+        type(c_ptr) :: c_result
+        integer(c_int), value :: leveltype_dummy
+      end function lib_zaxisNamePtr
+    end interface
+    f_result => null()
+    ptr = lib_zaxisNamePtr(leveltype_dummy)
+    if(c_associated(ptr)) then
+      rv_shape(1) = int(lib_strlen(ptr))
+      call c_f_pointer(ptr, f_result, rv_shape)
+    end if
+  end function zaxisNamePtr
+
+  function cdiZaxisDefKeyStr(zaxisID_dummy, key_dummy, size_dummy, mesg_dummy)&
   & result(f_result)
     integer(c_int) :: f_result
     integer(c_int), value :: zaxisID_dummy
@@ -5448,25 +5408,25 @@ contains
     character(kind = c_char) :: mesg_temp(len(mesg_dummy) + 1)
     integer :: mesg_i
     interface
-      function lib_cdiZaxisDefString(zaxisID_dummy, key_dummy, size_dummy,&
-      & mesg_dummy) bind(c, name = 'cdiZaxisDefString') result(c_result)
+      function lib_cdiZaxisDefKeyStr(zaxisID_dummy, key_dummy, size_dummy,&
+      & mesg_dummy) bind(c, name = 'cdiZaxisDefKeyStr') result(c_result)
         import c_char, c_int
         integer(c_int) :: c_result
         integer(c_int), value :: zaxisID_dummy
         integer(c_int), value :: key_dummy
         integer(c_int), value :: size_dummy
         character(kind = c_char) :: mesg_dummy(*)
-      end function lib_cdiZaxisDefString
+      end function lib_cdiZaxisDefKeyStr
     end interface
     do mesg_i = 1, len(mesg_dummy)
       mesg_temp(mesg_i) = mesg_dummy(mesg_i:mesg_i)
     end do
     mesg_temp(len(mesg_dummy) + 1) = c_null_char
-    f_result = lib_cdiZaxisDefString(zaxisID_dummy, key_dummy, size_dummy,&
+    f_result = lib_cdiZaxisDefKeyStr(zaxisID_dummy, key_dummy, size_dummy,&
     & mesg_temp)
-  end function cdiZaxisDefString
+  end function cdiZaxisDefKeyStr
 
-  function cdiZaxisInqString(zaxisID_dummy, key_dummy, size_dummy, mesg_dummy)&
+  function cdiZaxisInqKeyStr(zaxisID_dummy, key_dummy, size_dummy, mesg_dummy)&
   & result(f_result)
     integer(c_int) :: f_result
     integer(c_int), value :: zaxisID_dummy
@@ -5476,15 +5436,15 @@ contains
     character(kind = c_char) :: mesg_temp(len(mesg_dummy) + 1)
     integer :: mesg_i
     interface
-      function lib_cdiZaxisInqString(zaxisID_dummy, key_dummy, size_dummy,&
-      & mesg_dummy) bind(c, name = 'cdiZaxisInqString') result(c_result)
+      function lib_cdiZaxisInqKeyStr(zaxisID_dummy, key_dummy, size_dummy,&
+      & mesg_dummy) bind(c, name = 'cdiZaxisInqKeyStr') result(c_result)
         import c_char, c_int
         integer(c_int) :: c_result
         integer(c_int), value :: zaxisID_dummy
         integer(c_int), value :: key_dummy
         integer(c_int), value :: size_dummy
         character(kind = c_char) :: mesg_dummy(*)
-      end function lib_cdiZaxisInqString
+      end function lib_cdiZaxisInqKeyStr
     end interface
     mesg_temp(len(mesg_dummy) + 1) = c_null_char
     do mesg_i = len(mesg_dummy), 1, -1
@@ -5494,7 +5454,7 @@ contains
     do mesg_i = mesg_i, 1, -1
         mesg_temp(mesg_i) = mesg_dummy(mesg_i:mesg_i)
     end do
-    f_result = lib_cdiZaxisInqString(zaxisID_dummy, key_dummy, size_dummy,&
+    f_result = lib_cdiZaxisInqKeyStr(zaxisID_dummy, key_dummy, size_dummy,&
     & mesg_temp)
     do mesg_i = 1, len(mesg_dummy)
       if(mesg_temp(mesg_i) == c_null_char) exit
@@ -5503,7 +5463,7 @@ contains
     do mesg_i = mesg_i, len(mesg_dummy)
       mesg_dummy(mesg_i:mesg_i) = ' '
     end do
-  end function cdiZaxisInqString
+  end function cdiZaxisInqKeyStr
 
   subroutine zaxisDefName(zaxisID_dummy, name)
     integer(c_int), value :: zaxisID_dummy
@@ -5722,68 +5682,6 @@ contains
     end do
   end subroutine zaxisInqStdname
 
-  subroutine zaxisDefPsName(zaxisID_dummy, psname)
-    integer(c_int), value :: zaxisID_dummy
-    character(kind = c_char, len = *), optional, intent(in) :: psname
-    character(kind = c_char), allocatable, target :: psname_temp(:)
-    integer :: psname_i
-    type(c_ptr) :: psname_cptr
-    interface
-      subroutine lib_zaxisDefPsName(zaxisID_dummy, psname) bind(c, name =&
-      & 'zaxisDefPsName')
-        import c_int, c_ptr
-        integer(c_int), value :: zaxisID_dummy
-        type(c_ptr), value :: psname
-      end subroutine lib_zaxisDefPsName
-    end interface
-    if (present(psname)) then
-      allocate(psname_temp(len(psname) + 1))
-      psname_temp(len(psname) + 1) = c_null_char
-      do psname_i = len(psname), 1, -1
-        if(psname(psname_i:psname_i) /= ' ') exit
-        psname_temp(psname_i) = c_null_char
-      end do
-      do psname_i = psname_i, 1, -1
-          psname_temp(psname_i) = psname(psname_i:psname_i)
-      end do
-      psname_cptr = c_loc(psname_temp)
-    else
-      psname_cptr = c_null_ptr
-    end if
-    call lib_zaxisDefPsName(zaxisID_dummy, psname_cptr)
-  end subroutine zaxisDefPsName
-
-  subroutine zaxisInqPsName(zaxisID_dummy, psname_dummy)
-    integer(c_int), value :: zaxisID_dummy
-    character(kind = c_char, len = *), intent(inout) :: psname_dummy
-    character(kind = c_char) :: psname_temp(len(psname_dummy) + 1)
-    integer :: psname_i
-    interface
-      subroutine lib_zaxisInqPsName(zaxisID_dummy, psname_dummy) bind(c, name =&
-      & 'zaxisInqPsName')
-        import c_char, c_int
-        integer(c_int), value :: zaxisID_dummy
-        character(kind = c_char) :: psname_dummy(*)
-      end subroutine lib_zaxisInqPsName
-    end interface
-    psname_temp(len(psname_dummy) + 1) = c_null_char
-    do psname_i = len(psname_dummy), 1, -1
-      if(psname_dummy(psname_i:psname_i) /= ' ') exit
-      psname_temp(psname_i) = c_null_char
-    end do
-    do psname_i = psname_i, 1, -1
-        psname_temp(psname_i) = psname_dummy(psname_i:psname_i)
-    end do
-    call lib_zaxisInqPsName(zaxisID_dummy, psname_temp)
-    do psname_i = 1, len(psname_dummy)
-      if(psname_temp(psname_i) == c_null_char) exit
-      psname_dummy(psname_i:psname_i) = psname_temp(psname_i)
-    end do
-    do psname_i = psname_i, len(psname_dummy)
-      psname_dummy(psname_i:psname_i) = ' '
-    end do
-  end subroutine zaxisInqPsName
-
   function zaxisInqLbounds(zaxisID_dummy, lbounds) result(f_result)
     integer(c_int) :: f_result
     integer(c_int), value :: zaxisID_dummy
diff --git a/libcdi/src/model.c b/libcdi/src/model.c
index 00b48ac..7b8b047 100644
--- a/libcdi/src/model.c
+++ b/libcdi/src/model.c
@@ -13,12 +13,12 @@
 #include "resource_unpack.h"
 #include "serialize.h"
 
-#undef  UNDEFID
-#define UNDEFID -1
+#undef  CDI_UNDEFID
+#define CDI_UNDEFID -1
 
-static int ECHAM4 = UNDEFID,
-  ECHAM5 = UNDEFID,
-  COSMO  = UNDEFID;
+static int ECHAM4 = CDI_UNDEFID,
+  ECHAM5 = CDI_UNDEFID,
+  COSMO  = CDI_UNDEFID;
 
 typedef struct
 {
@@ -56,10 +56,10 @@ static const resOps modelOps = {
 static
 void modelDefaultValue ( model_t *modelptr )
 {
-  modelptr->self        = UNDEFID;
+  modelptr->self        = CDI_UNDEFID;
   modelptr->used        = 0;
-  modelptr->instID      = UNDEFID;
-  modelptr->modelgribID = UNDEFID;
+  modelptr->instID      = CDI_UNDEFID;
+  modelptr->modelgribID = CDI_UNDEFID;
   modelptr->name        = NULL;
 }
 
@@ -186,7 +186,7 @@ int modelInq(int instID, int modelgribID, const char *name)
 
   struct modelLoc searchState = { .name = name, .instID = instID,
                                   .modelgribID = modelgribID,
-                                  .resID = UNDEFID };
+                                  .resID = CDI_UNDEFID };
   if (name && *name)
     cdiResHFilterApply(&modelOps, findModelByName, &searchState);
   else
@@ -213,10 +213,10 @@ int modelInqInstitut(int modelID)
 
   modelInit ();
 
-  if ( modelID != UNDEFID )
+  if ( modelID != CDI_UNDEFID )
     modelptr = ( model_t * ) reshGetVal ( modelID, &modelOps );
 
-  return modelptr ? modelptr->instID : UNDEFID;
+  return modelptr ? modelptr->instID : CDI_UNDEFID;
 }
 
 
@@ -226,10 +226,10 @@ int modelInqGribID(int modelID)
 
   modelInit ();
 
-  if ( modelID != UNDEFID )
+  if ( modelID != CDI_UNDEFID )
     modelptr = ( model_t * ) reshGetVal ( modelID, &modelOps );
 
-  return modelptr ? modelptr->modelgribID : UNDEFID;
+  return modelptr ? modelptr->modelgribID : CDI_UNDEFID;
 }
 
 
@@ -239,7 +239,7 @@ const char *modelInqNamePtr(int modelID)
 
   modelInit ();
 
-  if ( modelID != UNDEFID )
+  if ( modelID != CDI_UNDEFID )
     modelptr = ( model_t * ) reshGetVal ( modelID, &modelOps );
 
   return modelptr ? modelptr->name : NULL;
@@ -298,8 +298,8 @@ enum {
 static int modelGetSizeP(void * modelptr, void *context)
 {
   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);
+  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;
 }
@@ -313,9 +313,9 @@ static void modelPackP(void * modelptr, void * buf, int size, int *position, voi
   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);
+  serializePack(tempbuf, model_nints, CDI_DATATYPE_INT, buf, size, position, context);
   if (p->name)
-    serializePack(p->name, tempbuf[3], DATATYPE_TXT, buf, size, position, context);
+    serializePack(p->name, tempbuf[3], CDI_DATATYPE_TXT, buf, size, position, context);
 }
 
 int
@@ -324,12 +324,12 @@ modelUnpack(void *buf, int size, int *position, int originNamespace, void *conte
 {
   int tempbuf[model_nints];
   char *name;
-  serializeUnpack(buf, size, position, tempbuf, model_nints, DATATYPE_INT, context);
+  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], DATATYPE_TXT, context);
+                      name, tempbuf[3], CDI_DATATYPE_TXT, context);
     }
   else
     {
diff --git a/libcdi/src/pio_interface.c b/libcdi/src/pio_interface.c
index da371c6..37b2f03 100644
--- a/libcdi/src/pio_interface.c
+++ b/libcdi/src/pio_interface.c
@@ -2,7 +2,7 @@
 #  include "config.h"
 #endif
 
-#include <limits.h>
+#include <stdint.h>
 #include <stdarg.h>
 #include <stdbool.h>
 #include <stdlib.h>
@@ -340,7 +340,7 @@ scatterGatherPackFunc(void *dataDesc, void *buf, int size, int *pos,
   unsigned char *dstBuf = (unsigned char *)buf + pos_,
     *bufEnd = (unsigned char *)buf + size;
   size_t elemSize = p->elemSize;
-  xassert(elemSize <= SSIZE_MAX);
+  xassert(elemSize <= SIZE_MAX);
   const unsigned char *data = p->data;
   unsigned copyCount = 0, numElems = p->numElems;
   for (unsigned j = 0; j < numBlocks && copyCount < numElems; ++j)
@@ -356,7 +356,7 @@ scatterGatherPackFunc(void *dataDesc, void *buf, int size, int *pos,
             }
           size_t bsize = (size_t)bl * elemSize;
           xassert(dstBuf + bsize <= bufEnd);
-          memcpy(dstBuf, data + (ssize_t)elemSize * (ssize_t)disps[j], bsize);
+          memcpy(dstBuf, data + (size_t)elemSize * (size_t)disps[j], bsize);
           dstBuf += bsize;
         }
     }
diff --git a/libcdi/src/pio_mpi_fw_at_all.c b/libcdi/src/pio_mpi_fw_at_all.c
index 22366c9..a470d17 100644
--- a/libcdi/src/pio_mpi_fw_at_all.c
+++ b/libcdi/src/pio_mpi_fw_at_all.c
@@ -117,7 +117,7 @@ fwFileWriteAtAll(int fileID, const void *buffer, size_t len)
     rankPio = commInqRankPio();
   /* find position to write to */
   of->collWriteSize[rankPio] = (int)len;
-  xmpi(MPI_Allgather(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL,
+  xmpi(MPI_Allgather(MPI_IN_PLACE, 0, MPI_CDI_DATATYPE_NULL,
                      of->collWriteSize, 1, MPI_INT, commPio));
   MPI_Offset myPos = of->pos, nextWritePos;
   for (size_t i = 0; i < (size_t)rankPio; ++i)
diff --git a/libcdi/src/pio_mpi_fw_at_reblock.c b/libcdi/src/pio_mpi_fw_at_reblock.c
index e945fda..c60df0d 100644
--- a/libcdi/src/pio_mpi_fw_at_reblock.c
+++ b/libcdi/src/pio_mpi_fw_at_reblock.c
@@ -355,7 +355,7 @@ fwFileWriteAtReblock(int fileID, const void *buffer, size_t len)
     rankPio = commInqRankPio();
   /* find position to write to */
   of->collWriteSize[rankPio] = (long)len;
-  xmpi(MPI_Allgather(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL,
+  xmpi(MPI_Allgather(MPI_IN_PLACE, 0, MPI_CDI_DATATYPE_NULL,
                      of->collWriteSize, 1, MPI_LONG, commPio));
   /* figure out which block buffers intersect locally held data and
    * what remotely held data intersects buffers on task */
diff --git a/libcdi/src/pio_serialize.c b/libcdi/src/pio_serialize.c
index 6cbbfe3..a3139be 100644
--- a/libcdi/src/pio_serialize.c
+++ b/libcdi/src/pio_serialize.c
@@ -19,19 +19,19 @@ static struct
   = {
 #if MPI_VERSION == 1 || (MPI_VERSION == 2 && MPI_SUBVERSION < 2)
 #define CDI_DT_MATCH_NEEDED 1
-  { DATATYPE_INT8, MPI_SIGNED_CHAR },
-  { DATATYPE_INT16, MPI_SHORT },
-  { DATATYPE_UINT32, MPI_INT },
+  { CDI_DATATYPE_INT8, MPI_SIGNED_CHAR },
+  { CDI_DATATYPE_INT16, MPI_SHORT },
+  { CDI_DATATYPE_UINT32, MPI_INT },
 #else
-  { DATATYPE_INT8, MPI_INT8_T },
-  { DATATYPE_INT16, MPI_INT16_T },
-  { DATATYPE_UINT32, MPI_UINT32_T },
+  { CDI_DATATYPE_INT8, MPI_INT8_T },
+  { CDI_DATATYPE_INT16, MPI_INT16_T },
+  { CDI_DATATYPE_UINT32, MPI_UINT32_T },
 #endif
-  { DATATYPE_INT, MPI_INT },
-  { DATATYPE_FLT64, MPI_DOUBLE },
-  { DATATYPE_TXT, MPI_CHAR },
-  { DATATYPE_UCHAR, MPI_UNSIGNED_CHAR },
-  { DATATYPE_LONG, MPI_LONG },
+  { CDI_DATATYPE_INT, MPI_INT },
+  { CDI_DATATYPE_FLT64, MPI_DOUBLE },
+  { CDI_DATATYPE_TXT, MPI_CHAR },
+  { CDI_DATATYPE_UCHAR, MPI_UNSIGNED_CHAR },
+  { CDI_DATATYPE_LONG, MPI_LONG },
 };
 
 static inline size_t
@@ -61,11 +61,11 @@ dtDictFixMPIType(size_t i, int typeclass, int size)
 static void
 setupDtDict()
 {
-  dtDictFixMPIType(lookupDt(DATATYPE_INT8), MPI_TYPECLASS_INTEGER,
+  dtDictFixMPIType(lookupDt(CDI_DATATYPE_INT8), MPI_TYPECLASS_INTEGER,
                    (int)sizeof (int8_t));
-  dtDictFixMPIType(lookupDt(DATATYPE_INT16), MPI_TYPECLASS_INTEGER,
+  dtDictFixMPIType(lookupDt(CDI_DATATYPE_INT16), MPI_TYPECLASS_INTEGER,
                    (int)sizeof (int16_t));
-  dtDictFixMPIType(lookupDt(DATATYPE_UINT32), MPI_TYPECLASS_INTEGER,
+  dtDictFixMPIType(lookupDt(CDI_DATATYPE_UINT32), MPI_TYPECLASS_INTEGER,
                    (int)sizeof (uint32_t));
   dtDictMatchComplete = 1;
 }
diff --git a/libcdi/src/pio_server.c b/libcdi/src/pio_server.c
index 74aad92..5a11f16 100644
--- a/libcdi/src/pio_server.c
+++ b/libcdi/src/pio_server.c
@@ -1109,14 +1109,14 @@ readGetBuffers(size_t streamIdx, const struct cdiPioConf *conf)
 
     switch (filetype)
       {
-      case FILETYPE_GRB:
-      case FILETYPE_GRB2:
+      case CDI_FILETYPE_GRB:
+      case CDI_FILETYPE_GRB2:
         writeGribStream(streamIdx, map, &data, &currentDataBufSize, conf);
         break;
 #ifdef HAVE_NETCDF4
-      case FILETYPE_NC:
-      case FILETYPE_NC2:
-      case FILETYPE_NC4:
+      case CDI_FILETYPE_NC:
+      case CDI_FILETYPE_NC2:
+      case CDI_FILETYPE_NC4:
         writeNetCDFStream(streamIdx, map, &data, &currentDataBufSize, conf);
         break;
 #endif
@@ -1193,8 +1193,8 @@ cdiPioServerStreamOpen(const char *filename, char filemode,
   switch (filetype)
     {
 #if defined HAVE_LIBNETCDF && ! defined HAVE_PARALLEL_NC4
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
+    case CDI_FILETYPE_NC4:
+    case CDI_FILETYPE_NC4C:
       {
         int ioMode = commInqIOMode();
         if (ioMode == PIO_NONE
@@ -1258,10 +1258,10 @@ cdiPioServerStreamClose(stream_t *streamptr, int recordBufIsToBeDeleted)
       switch (filetype)
         {
 #if defined (HAVE_LIBNETCDF) && ! defined (HAVE_PARALLEL_NC4)
-        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:
           {
             int rank, rankOpen = cdiPioSerialOpenFileMap(streamptr->self);
             if (commInqIOMode() == PIO_NONE
diff --git a/libcdi/src/pio_util.c b/libcdi/src/pio_util.c
index 8225d2c..529d2ed 100644
--- a/libcdi/src/pio_util.c
+++ b/libcdi/src/pio_util.c
@@ -147,13 +147,13 @@ void printArray ( const char *cdiPioDebugString, const char *ps, const void *arr
 
   switch ( datatype )
     {
-    case DATATYPE_INT:
+    case CDI_DATATYPE_INT:
       iArray = ( int * ) array;
       for ( i = 0; i < n-1; i++ )
 	fprintf ( stdout, "%d ", * ( iArray + i ));
       fprintf ( stdout, "%d\n", * ( iArray + n - 1 ));
       break;
-    case DATATYPE_FLT:
+    case CDI_DATATYPE_FLT:
       dArray = ( double * ) array;
       for ( i = 0; i < n-1; i++ )
 	fprintf ( stdout, "%.2f ", * ( dArray + i ));
diff --git a/libcdi/src/resource_handle.c b/libcdi/src/resource_handle.c
index 0685d61..405334f 100644
--- a/libcdi/src/resource_handle.c
+++ b/libcdi/src/resource_handle.c
@@ -379,17 +379,15 @@ 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 );
 
   LIST_INIT(1);
 
   LIST_LOCK();
 
-  nsp = namespaceGetActive ();
+  int nsp = namespaceGetActive ();
 
-  nspT = namespaceResHDecode ( resH );
+  namespaceTuple_t nspT = namespaceResHDecode ( resH );
   assert(nspT.idx >= 0);
 
   if (nspT.nsp == nsp &&
@@ -548,7 +546,7 @@ static int getPackBufferSize(void *context)
   int nsp = namespaceGetActive ();
 
   /* pack start marker, namespace and sererator marker */
-  packBufferSize += resHPackHeaderNInt * (intpacksize = serializeGetSize(1, DATATYPE_INT, context));
+  packBufferSize += resHPackHeaderNInt * (intpacksize = serializeGetSize(1, CDI_DATATYPE_INT, context));
 
   /* pack resources, type marker and seperator marker */
   listElem_t *r = resHList[nsp].resources;
@@ -583,9 +581,35 @@ void reshPackBufferDestroy ( char ** buffer )
 
 /**************************************************************/
 
+int reshGetTxCode(cdiResH resH)
+{
+  int type = 0;
+
+  LIST_LOCK();
+
+  int nsp = namespaceGetActive ();
+
+  namespaceTuple_t nspT = namespaceResHDecode ( resH );
+  assert(nspT.idx >= 0);
+
+  if (nspT.nsp == nsp &&
+      nspT.idx < resHList[nsp].size)
+    {
+      listElem_t *listElem = resHList[nsp].resources + nspT.idx;
+      xassert ( listElem->res.v.ops );
+      type = listElem->res.v.ops->valTxCode();
+    }
+
+  LIST_UNLOCK();
+
+  return type;
+}
+
+/**************************************************************/
+
 int reshPackBufferCreate(char **packBuffer, int *packBufferSize, void *context)
 {
-  int i, packBufferPos = 0;
+  int packBufferPos = 0;
   int end = END;
 
   xassert ( packBuffer );
@@ -599,18 +623,18 @@ int reshPackBufferCreate(char **packBuffer, int *packBufferSize, void *context)
 
   {
     int header[resHPackHeaderNInt] = { START, nsp };
-    serializePack(header, resHPackHeaderNInt,  DATATYPE_INT, pB, pBSize, &packBufferPos, context);
+    serializePack(header, resHPackHeaderNInt,  CDI_DATATYPE_INT, pB, pBSize, &packBufferPos, context);
   }
 
   listElem_t *r = resHList[nsp].resources;
-  for ( i = 0; i < resHList[nsp].size; i++ )
+  for ( int 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,
+            serializePack(temp, resHDeleteNInt, CDI_DATATYPE_INT,
                           pB, pBSize, &packBufferPos, context);
           }
         else
@@ -619,7 +643,7 @@ int reshPackBufferCreate(char **packBuffer, int *packBufferSize, void *context)
             xassert ( curr->res.v.ops );
             int type = curr->res.v.ops->valTxCode();
             if ( ! type ) continue;
-            serializePack(&type, 1, DATATYPE_INT, pB,
+            serializePack(&type, 1, CDI_DATATYPE_INT, pB,
                           pBSize, &packBufferPos, context);
             curr->res.v.ops->valPack(curr->res.v.val,
                                      pB, pBSize, &packBufferPos, context);
@@ -629,7 +653,8 @@ int reshPackBufferCreate(char **packBuffer, int *packBufferSize, void *context)
 
   LIST_UNLOCK();
 
-  serializePack(&end, 1,  DATATYPE_INT, pB, pBSize, &packBufferPos, context);
+  serializePack(&end, 1,  CDI_DATATYPE_INT, pB, pBSize, &packBufferPos, context);
+
   return packBufferPos;
 }
 
diff --git a/libcdi/src/resource_handle.h b/libcdi/src/resource_handle.h
index 88264ad..44f8b63 100644
--- a/libcdi/src/resource_handle.h
+++ b/libcdi/src/resource_handle.h
@@ -99,6 +99,7 @@ enum reshListMismatch {
 
 int reshListCompare(int nsp0, int nsp1);
 void reshListPrint(FILE *fp);
+int reshGetTxCode(cdiResH resH);
 
 #endif
 /*
diff --git a/libcdi/src/resource_unpack.c b/libcdi/src/resource_unpack.c
index dd9cef8..bfb6569 100644
--- a/libcdi/src/resource_unpack.c
+++ b/libcdi/src/resource_unpack.c
@@ -31,7 +31,7 @@ int reshUnpackResources(char * unpackBuffer, int unpackBufferSize,
   {
     int msgHdr[2];
     serializeUnpack(unpackBuffer, unpackBufferSize, &unpackBufferPos,
-                    &msgHdr, 2, DATATYPE_INT, context);
+                    &msgHdr, 2, CDI_DATATYPE_INT, context);
     if (msgHdr[0] != START)
       xabort("error parsing resource serialization buffer");
     originNamespace = msgHdr[1];
@@ -39,7 +39,7 @@ int reshUnpackResources(char * unpackBuffer, int unpackBufferSize,
   while ( unpackBufferPos < unpackBufferSize )
     {
       serializeUnpack(unpackBuffer, unpackBufferSize, &unpackBufferPos,
-                      &updateType, 1, DATATYPE_INT, context);
+                      &updateType, 1, CDI_DATATYPE_INT, context);
       if (updateType == END)
         break;
       switch (updateType)
@@ -80,7 +80,7 @@ int reshUnpackResources(char * unpackBuffer, int unpackBufferSize,
 	  break;
         case RESH_DELETE:
           serializeUnpack(unpackBuffer, unpackBufferSize, &unpackBufferPos,
-                          &resH, 1, DATATYPE_INT, context);
+                          &resH, 1, CDI_DATATYPE_INT, context);
           resH = namespaceAdaptKey(resH, originNamespace);
           reshDestroy(resH);
           reshSetStatus(resH, NULL, RESH_UNUSED);
diff --git a/libcdi/src/serialize.c b/libcdi/src/serialize.c
index 8f7ffbc..8c81aca 100644
--- a/libcdi/src/serialize.c
+++ b/libcdi/src/serialize.c
@@ -45,27 +45,27 @@ serializeGetSizeInCore(int count, int datatype, void *context)
   (void)context;
   switch (datatype)
   {
-  case DATATYPE_INT8:
+  case CDI_DATATYPE_INT8:
     elemSize = sizeof (int8_t);
     break;
-  case DATATYPE_INT16:
+  case CDI_DATATYPE_INT16:
     elemSize = sizeof (int16_t);
     break;
-  case DATATYPE_UINT32:
+  case CDI_DATATYPE_UINT32:
     elemSize = sizeof (uint32_t);
     break;
-  case DATATYPE_INT:
+  case CDI_DATATYPE_INT:
     elemSize = sizeof (int);
     break;
-  case DATATYPE_FLT:
-  case DATATYPE_FLT64:
+  case CDI_DATATYPE_FLT:
+  case CDI_DATATYPE_FLT64:
     elemSize = sizeof (double);
     break;
-  case DATATYPE_TXT:
-  case DATATYPE_UCHAR:
+  case CDI_DATATYPE_TXT:
+  case CDI_DATATYPE_UCHAR:
     elemSize = 1;
     break;
-  case DATATYPE_LONG:
+  case CDI_DATATYPE_LONG:
     elemSize = sizeof (long);
     break;
   default:
diff --git a/libcdi/src/serialize.h b/libcdi/src/serialize.h
index ba363a0..f60cab5 100644
--- a/libcdi/src/serialize.h
+++ b/libcdi/src/serialize.h
@@ -37,11 +37,11 @@ serializeStrTabGetPackSize(const char **strTab, int numStr,
   {
     size_t len = strlen(strTab[i]);
     packBuffSize +=
-      serializeGetSize(1, DATATYPE_INT, context)
-      + serializeGetSize((int)len, DATATYPE_TXT, context);
+      serializeGetSize(1, CDI_DATATYPE_INT, context)
+      + serializeGetSize((int)len, CDI_DATATYPE_TXT, context);
   }
   packBuffSize +=
-    serializeGetSize(1, DATATYPE_UINT32, context);
+    serializeGetSize(1, CDI_DATATYPE_UINT32, context);
   return packBuffSize;
 }
 
@@ -54,13 +54,13 @@ serializeStrTabPack(const char **strTab, int numStr,
   for (size_t i = 0; i < (size_t)numStr; ++i)
   {
     int len = (int)strlen(strTab[i]);
-    serializePack(&len, 1, DATATYPE_INT,
+    serializePack(&len, 1, CDI_DATATYPE_INT,
                   buf, buf_size, position, context);
-    serializePack(strTab[i], len, DATATYPE_TXT,
+    serializePack(strTab[i], len, CDI_DATATYPE_TXT,
                   buf, buf_size, position, context);
-    d ^= cdiCheckSum(DATATYPE_TXT, len, strTab[i]);
+    d ^= cdiCheckSum(CDI_DATATYPE_TXT, len, strTab[i]);
   }
-  serializePack(&d, 1, DATATYPE_UINT32,
+  serializePack(&d, 1, CDI_DATATYPE_UINT32,
                 buf, buf_size, position, context);
 }
 
@@ -74,14 +74,14 @@ serializeStrTabUnpack(const void *buf, int buf_size, int *position,
     {
       int len;
       serializeUnpack(buf, buf_size, position,
-                      &len, 1, DATATYPE_INT, context);
+                      &len, 1, CDI_DATATYPE_INT, context);
       serializeUnpack(buf, buf_size, position,
-                      strTab[i], len, DATATYPE_TXT, context);
+                      strTab[i], len, CDI_DATATYPE_TXT, context);
       strTab[i][len] = '\0';
-      d2 ^= cdiCheckSum(DATATYPE_TXT, len, strTab[i]);
+      d2 ^= cdiCheckSum(CDI_DATATYPE_TXT, len, strTab[i]);
     }
   serializeUnpack(buf, buf_size, position,
-                  &d, 1, DATATYPE_UINT32, context);
+                  &d, 1, CDI_DATATYPE_UINT32, context);
   xassert(d == d2);
 }
 
diff --git a/libcdi/src/stream.c b/libcdi/src/stream.c
index c6467c2..844d706 100644
--- a/libcdi/src/stream.c
+++ b/libcdi/src/stream.c
@@ -85,7 +85,7 @@ int cdiGetFiletype(const char *filename, int *byteorder)
   if ( fileID == CDI_UNDEFID )
     {
       if ( strncmp(filename, "http:", 5) == 0 || strncmp(filename, "https:", 6) == 0 )
-	return FILETYPE_NC;
+	return CDI_FILETYPE_NC;
       else
 	return CDI_ESYSTEM;
     }
@@ -99,48 +99,48 @@ int cdiGetFiletype(const char *filename, int *byteorder)
       version = buffer[7];
       if ( version <= 1 )
 	{
-	  filetype = FILETYPE_GRB;
+	  filetype = CDI_FILETYPE_GRB;
 	  if ( CDI_Debug ) Message("found GRIB file = %s, version %d", filename, version);
 	}
       else if ( version == 2 )
 	{
-	  filetype = FILETYPE_GRB2;
+	  filetype = CDI_FILETYPE_GRB2;
 	  if ( CDI_Debug ) Message("found GRIB2 file = %s", filename);
 	}
     }
   else if ( memcmp(buffer, "CDF\001", 4) == 0 )
     {
-      filetype = FILETYPE_NC;
+      filetype = CDI_FILETYPE_NC;
       if ( CDI_Debug ) Message("found CDF1 file = %s", filename);
     }
   else if ( memcmp(buffer, "CDF\002", 4) == 0 )
     {
-      filetype = FILETYPE_NC2;
+      filetype = CDI_FILETYPE_NC2;
       if ( CDI_Debug ) Message("found CDF2 file = %s", filename);
     }
   else if ( memcmp(buffer+1, "HDF", 3) == 0 )
     {
-      filetype = FILETYPE_NC4;
+      filetype = CDI_FILETYPE_NC4;
       if ( CDI_Debug ) Message("found HDF file = %s", filename);
     }
 #if  defined  (HAVE_LIBSERVICE)
   else if ( srvCheckFiletype(fileID, &swap) )
     {
-      filetype = FILETYPE_SRV;
+      filetype = CDI_FILETYPE_SRV;
       if ( CDI_Debug ) Message("found SRV file = %s", filename);
     }
 #endif
 #if  defined  (HAVE_LIBEXTRA)
   else if ( extCheckFiletype(fileID, &swap) )
     {
-      filetype = FILETYPE_EXT;
+      filetype = CDI_FILETYPE_EXT;
       if ( CDI_Debug ) Message("found EXT file = %s", filename);
     }
 #endif
 #if  defined  (HAVE_LIBIEG)
   else if ( iegCheckFiletype(fileID, &swap) )
     {
-      filetype = FILETYPE_IEG;
+      filetype = CDI_FILETYPE_IEG;
       if ( CDI_Debug ) Message("found IEG file = %s", filename);
     }
 #endif
@@ -149,12 +149,12 @@ int cdiGetFiletype(const char *filename, int *byteorder)
     {
       if ( version <= 1 )
 	{
-	  filetype = FILETYPE_GRB;
+	  filetype = CDI_FILETYPE_GRB;
 	  if ( CDI_Debug ) Message("found seeked GRIB file = %s", filename);
 	}
       else if ( version == 2 )
 	{
-	  filetype = FILETYPE_GRB2;
+	  filetype = CDI_FILETYPE_GRB2;
 	  if ( CDI_Debug ) Message("found seeked GRIB2 file = %s", filename);
 	}
     }
@@ -181,8 +181,8 @@ The function @func{streamInqFiletype} returns the filetype of a stream.
 @Result
 @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}.
+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_SRV}, @func{CDI_FILETYPE_EXT} and @func{CDI_FILETYPE_IEG}.
 
 @EndFunction
 */
@@ -225,7 +225,7 @@ int getByteswap(int byteorder)
 
 @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}.
+with the file format type @func{CDI_FILETYPE_SRV}, @func{CDI_FILETYPE_EXT} or @func{CDI_FILETYPE_IEG}.
 
 @EndFunction
 */
@@ -238,7 +238,7 @@ void streamDefByteorder(int streamID, int byteorder)
   switch (filetype)
     {
 #if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
+    case CDI_FILETYPE_SRV:
       {
 	srvrec_t *srvp = (srvrec_t*) streamptr->record->exsep;
 	srvp->byteswap = getByteswap(byteorder);
@@ -247,7 +247,7 @@ void streamDefByteorder(int streamID, int byteorder)
       }
 #endif
 #if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
+    case CDI_FILETYPE_EXT:
       {
 	extrec_t *extp = (extrec_t*) streamptr->record->exsep;
 	extp->byteswap = getByteswap(byteorder);
@@ -256,7 +256,7 @@ void streamDefByteorder(int streamID, int byteorder)
       }
 #endif
 #if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
+    case CDI_FILETYPE_IEG:
       {
 	iegrec_t *iegp = (iegrec_t*) streamptr->record->exsep;
 	iegp->byteswap = getByteswap(byteorder);
@@ -278,7 +278,7 @@ void streamDefByteorder(int streamID, int byteorder)
 
 @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}.
+with the file format type @func{CDI_FILETYPE_SRV}, @func{CDI_FILETYPE_EXT} or @func{CDI_FILETYPE_IEG}.
 
 @Result
 @func{streamInqByteorder} returns the type of the byte order.
@@ -330,48 +330,47 @@ long cdiInqTimeSize(int streamID)
 }
 
 static
-int cdiInqContents(stream_t * streamptr)
+int cdiInqContents(stream_t *streamptr)
 {
   int status = 0;
-
   int filetype = streamptr->filetype;
 
   switch (filetype)
     {
 #if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
+    case CDI_FILETYPE_GRB:
+    case CDI_FILETYPE_GRB2:
       {
         status = grbInqContents(streamptr);
 	break;
       }
 #endif
 #if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
+    case CDI_FILETYPE_SRV:
       {
         status = srvInqContents(streamptr);
 	break;
       }
 #endif
 #if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
+    case CDI_FILETYPE_EXT:
       {
         status = extInqContents(streamptr);
 	break;
       }
 #endif
 #if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
+    case CDI_FILETYPE_IEG:
       {
         status = iegInqContents(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:
       {
         status = cdfInqContents(streamptr);
 	break;
@@ -410,8 +409,10 @@ int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
   switch (filetype)
     {
 #if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
+    case CDI_FILETYPE_GRB:
+#if  defined  (HAVE_LIBGRIB_API)
+    case CDI_FILETYPE_GRB2:
+#endif
       {
 #ifndef __cplusplus
         fileID = gribOpen(filename, (char [2]){filemode, 0});
@@ -429,7 +430,7 @@ int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
       }
 #endif
 #if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
+    case CDI_FILETYPE_SRV:
       {
 #ifndef __cplusplus
         fileID = fileOpen(filename, (char [2]){filemode, 0});
@@ -448,7 +449,7 @@ int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
       }
 #endif
 #if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
+    case CDI_FILETYPE_EXT:
       {
 #ifndef __cplusplus
         fileID = fileOpen(filename, (char [2]){filemode, 0});
@@ -468,7 +469,7 @@ int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
       }
 #endif
 #if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
+    case CDI_FILETYPE_IEG:
       {
 #ifndef __cplusplus
         fileID = fileOpen(filename, (char [2]){filemode, 0});
@@ -481,13 +482,13 @@ int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
           {
             streamptr->record = (Record *) Malloc(sizeof(Record));
             streamptr->record->buffer = NULL;
-            streamptr->record->exsep   = iegNew();
+            streamptr->record->exsep  = iegNew();
           }
         break;
       }
 #endif
 #if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
+    case CDI_FILETYPE_NC:
       {
 #ifndef __cplusplus
         fileID = cdfOpen(filename, (char [2]){filemode, 0});
@@ -497,7 +498,7 @@ int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
 #endif
         break;
       }
-    case FILETYPE_NC2:
+    case CDI_FILETYPE_NC2:
       {
 #ifndef __cplusplus
         fileID = cdfOpen64(filename, (char [2]){filemode, 0});
@@ -507,8 +508,8 @@ int cdiStreamOpenDefaultDelegate(const char *filename, char filemode,
 #endif
         break;
       }
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
+    case CDI_FILETYPE_NC4:
+    case CDI_FILETYPE_NC4C:
       {
 #ifndef __cplusplus
         fileID = cdf4Open(filename, (char [2]){filemode, 0}, &filetype);
@@ -593,27 +594,25 @@ int streamOpenID(const char *filename, char filemode, int filetype, int resH)
   return streamID;
 }
 
-static int streamOpen(const char *filename, const char *filemode, int filetype)
+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);
+  if ( !filemode || strlen(filemode) != 1 ) return CDI_EINVAL;
+  return streamOpenID(filename, (char)tolower(filemode[0]), filetype, CDI_UNDEFID);
 }
 
-static int streamOpenA(const char *filename, const char *filemode, int filetype)
+static
+int streamOpenA(const char *filename, const char *filemode, int filetype)
 {
-  int fileID = CDI_UNDEFID;
-  int streamID = CDI_ESYSTEM;
-  int status;
-  stream_t *streamptr = stream_new_entry(CDI_UNDEFID);
-  vlist_t *vlistptr;
-
   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)
@@ -625,7 +624,7 @@ static int streamOpenA(const char *filename, const char *filemode, int filetype)
 
   if ( fileID == CDI_UNDEFID || fileID == CDI_ELIBNAVAIL || fileID == CDI_ESYSTEM ) return fileID;
 
-  streamID = streamptr->self;
+  int streamID = streamptr->self;
 
   streamptr->filemode = tolower(*filemode);
   streamptr->filename = strdupx(filename);
@@ -634,11 +633,11 @@ static int streamOpenA(const char *filename, const char *filemode, int filetype)
   streamptr->vlistID = vlistCreate();
   cdiVlistMakeInternal(streamptr->vlistID);
   /* cdiReadByteorder(streamID); */
-  status = cdiInqContents(streamptr);
+  int status = cdiInqContents(streamptr);
   if ( status < 0 ) return status;
-  vlistptr = vlist_to_pointer(streamptr->vlistID);
+  vlist_t *vlistptr = vlist_to_pointer(streamptr->vlistID);
   vlistptr->ntsteps = (int)cdiInqTimeSize(streamID);
-  if(!strcmp(filemode, "r")) cdiVlistMakeImmutable(streamptr->vlistID);
+  if ( !strcmp(filemode, "r") ) cdiVlistMakeImmutable(streamptr->vlistID);
 
   {
     void (*streamCloseDelegate)(stream_t *streamptr, int recordBufIsToBeDeleted)
@@ -651,49 +650,52 @@ static int streamOpenA(const char *filename, const char *filemode, int filetype)
   switch (filetype)
     {
 #if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
+    case CDI_FILETYPE_GRB:
+#if  defined  (HAVE_LIBGRIB_API)
+    case CDI_FILETYPE_GRB2:
+#endif
       {
         fileID = gribOpen(filename, filemode);
+        if ( fileID != CDI_UNDEFID ) gribContainersNew(streamptr);
 	break;
       }
 #endif
 #if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
+    case CDI_FILETYPE_SRV:
       {
         fileID = fileOpen(filename, filemode);
 	break;
       }
 #endif
 #if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
+    case CDI_FILETYPE_EXT:
       {
         fileID = fileOpen(filename, filemode);
 	break;
       }
 #endif
 #if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
+    case CDI_FILETYPE_IEG:
       {
         fileID = fileOpen(filename, filemode);
 	break;
       }
 #endif
 #if  defined  (HAVE_LIBNETCDF)
-    case FILETYPE_NC:
+    case CDI_FILETYPE_NC:
       {
 	fileID = cdfOpen(filename, filemode);
 	streamptr->ncmode = 2;
 	break;
       }
-    case FILETYPE_NC2:
+    case CDI_FILETYPE_NC2:
       {
 	fileID = cdfOpen64(filename, filemode);
 	streamptr->ncmode = 2;
 	break;
       }
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C:
+    case CDI_FILETYPE_NC4:
+    case CDI_FILETYPE_NC4C:
       {
 	fileID = cdf4Open(filename, filemode, &filetype);
 	streamptr->ncmode = 2;
@@ -802,9 +804,9 @@ int streamOpenAppend(const char *filename)
 @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}.
+                     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_SRV},
+                     @func{CDI_FILETYPE_EXT} and @func{CDI_FILETYPE_IEG}.
 
 @Description
 The function @func{streamOpenWrite} creates a new datset.
@@ -828,7 +830,7 @@ Here is an example using @func{streamOpenWrite} to create a new NetCDF file name
    ...
 int streamID;
    ...
-streamID = streamOpenWrite("foo.nc", FILETYPE_NC);
+streamID = streamOpenWrite("foo.nc", CDI_FILETYPE_NC);
 if ( streamID < 0 ) handle_error(streamID);
    ...
 @EndSource
@@ -847,7 +849,7 @@ void streamDefaultValue ( stream_t * streamptr )
   streamptr->self              = CDI_UNDEFID;
   streamptr->accesstype        = CDI_UNDEFID;
   streamptr->accessmode        = 0;
-  streamptr->filetype          = FILETYPE_UNDEF;
+  streamptr->filetype          = CDI_FILETYPE_UNDEF;
   streamptr->byteorder         = CDI_UNDEFID;
   streamptr->fileID            = 0;
   streamptr->filemode          = 0;
@@ -869,39 +871,46 @@ void streamDefaultValue ( stream_t * streamptr )
   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->sortname          = cdiSortName > 0;
+  streamptr->sortparam         = cdiSortParam > 0;
   streamptr->have_missval      = cdiHaveMissval;
-  streamptr->comptype          = COMPRESS_NONE;
+  streamptr->comptype          = CDI_COMPRESS_NONE;
   streamptr->complevel         = 0;
 
   basetimeInit(&streamptr->basetime);
 
-  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;
+#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;
+
+  for ( int i = 0; i < MAX_GRIDS_PS; i++ )
+    {
+      streamptr->ncgrid[i].gridID = CDI_UNDEFID;
+      streamptr->ncgrid[i].xdimID = CDI_UNDEFID;
+      streamptr->ncgrid[i].ydimID = CDI_UNDEFID;
+      streamptr->ncgrid[i].xvarID = CDI_UNDEFID;
+      streamptr->ncgrid[i].yvarID = CDI_UNDEFID;
+      streamptr->ncgrid[i].avarID = 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 stream_t *stream_new_entry(int resH)
+static
+stream_t *stream_new_entry(int resH)
 {
-  stream_t *streamptr;
-
   cdiInitialize(); /* ***************** make MT version !!! */
 
-  streamptr = (stream_t *) Malloc(sizeof(stream_t));
+  stream_t *streamptr = (stream_t *) Malloc(sizeof(stream_t));
   streamDefaultValue ( streamptr );
+
   if (resH == CDI_UNDEFID)
     streamptr->self = reshPut(streamptr, &streamOps);
   else
@@ -914,8 +923,7 @@ static stream_t *stream_new_entry(int resH)
 }
 
 
-void
-cdiStreamCloseDefaultDelegate(stream_t *streamptr, int recordBufIsToBeDeleted)
+void cdiStreamCloseDefaultDelegate(stream_t *streamptr, int recordBufIsToBeDeleted)
 {
   int fileID   = streamptr->fileID;
   int filetype = streamptr->filetype;
@@ -925,47 +933,43 @@ cdiStreamCloseDefaultDelegate(stream_t *streamptr, int recordBufIsToBeDeleted)
     switch (filetype)
       {
 #if  defined  (HAVE_LIBGRIB)
-      case FILETYPE_GRB:
-      case FILETYPE_GRB2:
+      case CDI_FILETYPE_GRB:
+      case CDI_FILETYPE_GRB2:
         {
           gribClose(fileID);
-          if (recordBufIsToBeDeleted)
-            gribContainersDelete(streamptr);
+          if ( recordBufIsToBeDeleted ) gribContainersDelete(streamptr);
           break;
         }
 #endif
 #if  defined  (HAVE_LIBSERVICE)
-      case FILETYPE_SRV:
+      case CDI_FILETYPE_SRV:
         {
           fileClose(fileID);
-          if (recordBufIsToBeDeleted)
-            srvDelete(streamptr->record->exsep);
+          if ( recordBufIsToBeDeleted ) srvDelete(streamptr->record->exsep);
           break;
         }
 #endif
 #if  defined  (HAVE_LIBEXTRA)
-      case FILETYPE_EXT:
+      case CDI_FILETYPE_EXT:
         {
           fileClose(fileID);
-          if (recordBufIsToBeDeleted)
-            extDelete(streamptr->record->exsep);
+          if ( recordBufIsToBeDeleted ) extDelete(streamptr->record->exsep);
           break;
         }
 #endif
 #if  defined  (HAVE_LIBIEG)
-      case FILETYPE_IEG:
+      case CDI_FILETYPE_IEG:
         {
           fileClose(fileID);
-          if (recordBufIsToBeDeleted)
-            iegDelete(streamptr->record->exsep);
+          if ( recordBufIsToBeDeleted ) iegDelete(streamptr->record->exsep);
           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:
         {
           cdfClose(fileID);
           break;
@@ -980,7 +984,8 @@ cdiStreamCloseDefaultDelegate(stream_t *streamptr, int recordBufIsToBeDeleted)
 }
 
 
-static void deallocate_sleveltable_t(sleveltable_t *entry)
+static
+void deallocate_sleveltable_t(sleveltable_t *entry)
 {
   if (entry->recordID) Free(entry->recordID);
   if (entry->lindex)   Free(entry->lindex);
@@ -1004,7 +1009,6 @@ The function @func{streamClose} closes an open dataset.
 */
 void streamClose(int streamID)
 {
-  int index;
   stream_t *streamptr = stream_to_pointer(streamID);
 
   if ( CDI_Debug )
@@ -1029,7 +1033,7 @@ void streamClose(int streamID)
   streamptr->filetype = 0;
   if ( streamptr->filename ) Free(streamptr->filename);
 
-  for ( index = 0; index < streamptr->nvars; index++ )
+  for ( int index = 0; index < streamptr->nvars; index++ )
     {
       sleveltable_t *pslev = streamptr->vars[index].recordTable;
       unsigned nsub = streamptr->vars[index].subtypeSize >= 0
@@ -1043,12 +1047,10 @@ void streamClose(int streamID)
   Free(streamptr->vars);
   streamptr->vars = NULL;
 
-  for ( index = 0; index < streamptr->ntsteps; ++index )
+  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);
+      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);
     }
 
@@ -1058,11 +1060,8 @@ void streamClose(int streamID)
 
   if ( vlistID != -1 )
     {
-      if ( streamptr->filemode != 'w' )
-	if ( vlistInqTaxis(vlistID) != -1 )
-	  {
-	    taxisDestroy(vlistInqTaxis(vlistID));
-	  }
+      if ( streamptr->filemode != 'w' && vlistInqTaxis(vlistID) != -1 )
+        taxisDestroy(vlistInqTaxis(vlistID));
 
       cdiVlistDestroy_(vlistID);
     }
@@ -1070,14 +1069,13 @@ void streamClose(int streamID)
   stream_delete_entry(streamptr);
 }
 
-static void stream_delete_entry(stream_t *streamptr)
+static
+void stream_delete_entry(stream_t *streamptr)
 {
-  int idx;
-
   xassert ( streamptr );
 
-  idx = streamptr->self;
-  Free( streamptr );
+  int idx = streamptr->self;
+  Free(streamptr);
   reshRemove ( idx, &streamOps );
 
   if ( CDI_Debug )
@@ -1092,12 +1090,9 @@ void cdiStreamSync_(stream_t *streamptr)
   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!");
+  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
     {
       if ( streamptr->filemode == 'w' || streamptr->filemode == 'a' )
@@ -1105,10 +1100,10 @@ void cdiStreamSync_(stream_t *streamptr)
 	  switch (filetype)
 	    {
 #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:
 	      {
 		void cdf_sync(int ncid);
 		if ( streamptr->ncmode == 2 ) cdf_sync(fileID);
@@ -1154,8 +1149,7 @@ int cdiStreamDefTimestep_(stream_t *streamptr, int tsID)
 
   stream_check_ptr(__func__, streamptr);
 
-  if ( CDI_Debug )
-    Message("streamID = %d  tsID = %d", streamptr->self, tsID);
+  if ( CDI_Debug ) Message("streamID = %d  tsID = %d", streamptr->self, tsID);
 
   int vlistID = streamptr->vlistID;
 
@@ -1189,10 +1183,10 @@ int cdiStreamDefTimestep_(stream_t *streamptr, int tsID)
   streamptr->ntsteps = tsID + 1;
 
 #ifdef HAVE_LIBNETCDF
-  if ((streamptr->filetype == FILETYPE_NC  ||
-       streamptr->filetype == FILETYPE_NC2 ||
-       streamptr->filetype == FILETYPE_NC4 ||
-       streamptr->filetype == FILETYPE_NC4C)
+  if ((streamptr->filetype == CDI_FILETYPE_NC  ||
+       streamptr->filetype == CDI_FILETYPE_NC2 ||
+       streamptr->filetype == CDI_FILETYPE_NC4 ||
+       streamptr->filetype == CDI_FILETYPE_NC4C)
       && time_is_varying)
     {
       void (*myCdfDefTimestep)(stream_t *streamptr, int tsID)
@@ -1233,13 +1227,13 @@ int streamDefTimestep(int streamID, int tsID)
   return myStreamDefTimestep_(streamptr, tsID);
 }
 
+
 int streamInqCurTimestepID(int streamID)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
   return streamptr->curTsID;
 }
 
-
 /*
 @Function  streamInqTimestep
 @Title     Get time step
@@ -1290,39 +1284,39 @@ int streamInqTimestep(int streamID, int tsID)
   switch (filetype)
     {
 #if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
+    case CDI_FILETYPE_GRB:
+    case CDI_FILETYPE_GRB2:
       {
         nrecs = grbInqTimestep(streamptr, tsID);
 	break;
       }
 #endif
 #if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
+    case CDI_FILETYPE_SRV:
       {
         nrecs = srvInqTimestep(streamptr, tsID);
 	break;
       }
 #endif
 #if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
+    case CDI_FILETYPE_EXT:
       {
         nrecs = extInqTimestep(streamptr, tsID);
 	break;
       }
 #endif
 #if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
+    case CDI_FILETYPE_IEG:
       {
         nrecs = iegInqTimestep(streamptr, tsID);
 	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:
       {
         nrecs = cdfInqTimestep(streamptr, tsID);
 	break;
@@ -1444,7 +1438,6 @@ void streamWriteContents(int streamID, char *cname)
 off_t streamNvals(int streamID)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
-
   return streamptr->numvals;
 }
 
@@ -1474,8 +1467,7 @@ void streamDefVlist(int streamID, int vlistID)
 }
 
 /* the single image implementation of streamDefVlist */
-void
-cdiStreamDefVlist_(int streamID, int vlistID)
+void cdiStreamDefVlist_(int streamID, int vlistID)
 {
   stream_t *streamptr = stream_to_pointer(streamID);
 
@@ -1581,50 +1573,46 @@ int streamTxCode(void)
   return STREAM;
 }
 
-void
-cdiStreamSetupVlist(stream_t *streamptr, int vlistID)
+void cdiStreamSetupVlist(stream_t *streamptr, int vlistID)
 {
   void (*myStreamSetupVlist)(stream_t *streamptr, int vlistID)
-    = (void (*)(stream_t *, int))
-    namespaceSwitchGet(NSSWITCH_STREAM_SETUP_VLIST).func;
+    = (void (*)(stream_t *, int)) namespaceSwitchGet(NSSWITCH_STREAM_SETUP_VLIST).func;
   myStreamSetupVlist(streamptr, vlistID);
 }
 
-void
-cdiStreamSetupVlist_(stream_t *streamptr, int vlistID)
+
+void cdiStreamSetupVlist_(stream_t *streamptr, int vlistID)
 {
-  int nvars = vlistNvars(vlistID);
   streamptr->vlistID = vlistID;
-  for (int varID = 0; varID < nvars; varID++ )
+  int nvars = vlistNvars(vlistID);
+  for ( int varID = 0; varID < nvars; varID++ )
     {
       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));
+        vlistDefVarMissval(vlistID, varID, vlistInqVarMissval(vlistID, varID));
     }
 
   if (streamptr->filemode == 'w')
     switch (streamptr->filetype)
       {
 #ifdef 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:
         {
           void (*myCdfDefVars)(stream_t *streamptr)
-            = (void (*)(stream_t *))
-            namespaceSwitchGet(NSSWITCH_CDF_STREAM_SETUP).func;
+            = (void (*)(stream_t *)) namespaceSwitchGet(NSSWITCH_CDF_STREAM_SETUP).func;
           myCdfDefVars(streamptr);
         }
         break;
 #endif
 #ifdef HAVE_LIBGRIB
-      case FILETYPE_GRB:
-      case FILETYPE_GRB2:
+      case CDI_FILETYPE_GRB:
+      case CDI_FILETYPE_GRB2:
         gribContainersNew(streamptr);
         break;
 #endif
@@ -1677,7 +1665,7 @@ static int streamCompareP(void * streamptr1, void * streamptr2)
 
 void streamDestroyP ( void * streamptr )
 {
-  stream_t * sp = ( stream_t * ) streamptr;
+  stream_t *sp = ( stream_t * ) streamptr;
 
   xassert ( sp );
 
@@ -1739,11 +1727,11 @@ streamGetPackSize(void * voidP, void *context)
 {
   stream_t * streamP = ( stream_t * ) voidP;
   int packBufferSize
-    = serializeGetSize(streamNint, DATATYPE_INT, context)
-    + serializeGetSize(2, DATATYPE_UINT32, context)
+    = serializeGetSize(streamNint, CDI_DATATYPE_INT, context)
+    + serializeGetSize(2, CDI_DATATYPE_UINT32, context)
     + serializeGetSize((int)strlen(streamP->filename) + 1,
-                       DATATYPE_TXT, context)
-    + serializeGetSize(1, DATATYPE_FLT64, context);
+                       CDI_DATATYPE_TXT, context)
+    + serializeGetSize(1, CDI_DATATYPE_FLT64, context);
   return packBufferSize;
 }
 
@@ -1766,14 +1754,14 @@ streamPack(void * streamptr, void * packBuffer, int packBufferSize,
   intBuffer[8] = streamP->sortname;
   intBuffer[9] = streamP->have_missval;
 
-  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);
+  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);
 
-  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);
+  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);
 }
 
 struct streamAssoc
@@ -1785,18 +1773,18 @@ streamUnpack(char * unpackBuffer, int unpackBufferSize,
   char filename[CDI_MAX_NAME];
 
   serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                  intBuffer, streamNint, DATATYPE_INT, context);
+                  intBuffer, streamNint, CDI_DATATYPE_INT, context);
   serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                  &d, 1, DATATYPE_UINT32, context);
-  xassert(cdiCheckSum(DATATYPE_INT, streamNint, intBuffer) == d);
+                  &d, 1, CDI_DATATYPE_UINT32, context);
+  xassert(cdiCheckSum(CDI_DATATYPE_INT, streamNint, intBuffer) == d);
 
   serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                  &cdiDefaultMissval, 1, DATATYPE_FLT64, context);
+                  &cdiDefaultMissval, 1, CDI_DATATYPE_FLT64, context);
   serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                  &filename, intBuffer[2], DATATYPE_TXT, context);
+                  &filename, intBuffer[2], CDI_DATATYPE_TXT, context);
   serializeUnpack(unpackBuffer, unpackBufferSize, unpackBufferPos,
-                  &d, 1, DATATYPE_UINT32, context);
-  xassert(d == cdiCheckSum(DATATYPE_TXT, intBuffer[2], filename));
+                  &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);
diff --git a/libcdi/src/stream_cdf.c b/libcdi/src/stream_cdf.c
deleted file mode 100644
index 90c5a15..0000000
--- a/libcdi/src/stream_cdf.c
+++ /dev/null
@@ -1,7180 +0,0 @@
-#if defined (HAVE_CONFIG_H)
-#  include "config.h"
-#endif
-
-#ifdef HAVE_LIBNETCDF
-
-//#define TEST_GROUPS 1
-
-#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>
-#endif
-
-#include <netcdf.h>
-
-#include "dmemory.h"
-#include "cdi.h"
-#include "basetime.h"
-#include "gaussgrid.h"
-#include "cdi_int.h"
-#include "cdi_uuid.h"
-#include "stream_cdf.h"
-#include "cdf.h"
-#include "cdf_int.h"
-#include "varscan.h"
-#include "vlist.h"
-#include "zaxis.h"
-
-//#define PROJECTION_TEST
-
-#undef  UNDEFID
-#define UNDEFID  CDI_UNDEFID
-
-static const char bndsName[] = "bnds";
-
-#define  X_AXIS  1
-#define  Y_AXIS  2
-#define  Z_AXIS  3
-#define  T_AXIS  4
-
-#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      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 */
-}
-ncvar_t;
-
-static
-void strtolower(char *str)
-{
-  if ( str )
-    for (size_t i = 0; str[i]; ++i)
-      str[i] = (char)tolower((int)str[i]);
-}
-
-static
-int get_timeunit(size_t len, const char *ptu)
-{
-  int timeunit = -1;
-
-  if ( len > 2 )
-    {
-      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;
-    }
-  else if ( len == 1 )
-    {
-      if ( ptu[0] == 's' ) timeunit = TUNIT_SECOND;
-    }
-
-  return timeunit;
-}
-
-static
-bool isTimeUnits(const char *timeunits)
-{
-  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;
-}
-
-static
-bool isTimeAxisUnits(const char *timeunits)
-{
-  bool status = false;
-
-  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 = memcmp(ptu, "as", 2) == 0 ? TAXIS_ABSOLUTE :
-            memcmp(ptu, "since", 5) == 0 ? TAXIS_RELATIVE : -1;
-
-          status = timetype != -1;
-        }
-    }
-
-  Free(tu);
-
-  return status;
-}
-
-static
-void scanTimeString(const char *ptu, int *rdate, int *rtime)
-{
-  int year = 1, month = 1, day = 1;
-  int hour = 0, minute = 0, second = 0;
-  int v1 = 1, v2 = 1, v3 = 1;
-
-  *rdate = 0;
-  *rtime = 0;
-
-  if ( *ptu )
-    {
-      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++;
-            }
-        }
-    }
-
-  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 )
-    {
-      while ( ! isdigit((int) *ptu) ) ptu++;
-
-      hour = atoi(ptu);
-      while ( isdigit((int) *ptu) ) ptu++;
-      if ( *ptu == ':' )
-        {
-          ptu++;
-          minute = atoi(ptu);
-          while ( isdigit((int) *ptu) ) ptu++;
-          if ( *ptu == ':' )
-            {
-              ptu++;
-              second = atoi(ptu);
-            }
-        }
-    }
-
-  *rdate = cdiEncodeDate(year, month, day);
-  *rtime = cdiEncodeTime(hour, minute, second);
-}
-
-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;
-}
-
-static
-void setForecastTime(const char *timestr, taxis_t *taxis)
-{
-  (*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;
-}
-
-static
-int setBaseTime(const char *timeunits, taxis_t *taxis)
-{
-  int timetype = TAXIS_ABSOLUTE;
-  int rdate = -1, rtime = -1;
-
-  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 )
-    {
-      Message("Unsupported TIMEUNIT: %s!", timeunits);
-      return (1);
-    }
-
-  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;
-
-      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);
-
-              (*taxis).rdate = rdate;
-              (*taxis).rtime = rtime;
-
-              if ( CDI_Debug )
-                Message("rdate = %d  rtime = %d", rdate, rtime);
-            }
-        }
-    }
-
-  (*taxis).type = timetype;
-  (*taxis).unit = timeunit;
-
-  Free(tu);
-
-  if ( CDI_Debug )
-    Message("timetype = %d  unit = %d", timetype, timeunit);
-
-  return 0;
-}
-
-static
-void cdfGetAttInt(int fileID, int ncvarid, const char *attname, int attlen, int *attint)
-{
-  nc_type atttype;
-  size_t nc_attlen;
-
-  *attint = 0;
-
-  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
-  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
-
-  if ( atttype != NC_CHAR )
-    {
-      int *pintatt = (int)nc_attlen > attlen
-        ? (int *)(Malloc(nc_attlen * sizeof (int))) : attint;
-
-      cdf_get_att_int(fileID, ncvarid, attname, pintatt);
-
-      if ( (int)nc_attlen > attlen )
-        {
-          memcpy(attint, pintatt, (size_t)attlen * sizeof (int));
-          Free(pintatt);
-        }
-    }
-}
-
-static
-void cdfGetAttDouble(int fileID, int ncvarid, char *attname, int attlen, double *attdouble)
-{
-  nc_type atttype;
-  size_t nc_attlen;
-
-  *attdouble = 0;
-
-  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
-  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
-
-  if ( atttype != NC_CHAR )
-    {
-      double *pdoubleatt = NULL;
-
-      if ( (int)nc_attlen > attlen )
-        pdoubleatt = (double *) Malloc(nc_attlen * sizeof (double));
-      else
-        pdoubleatt = attdouble;
-
-      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)
-{
-  nc_type atttype;
-  size_t nc_attlen;
-
-  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
-  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
-
-  if ( atttype == NC_CHAR )
-    {
-      char attbuf[65636];
-      if ( nc_attlen < sizeof(attbuf) )
-        {
-          cdf_get_att_text(fileID, ncvarid, attname, attbuf);
-
-          if ( (int) nc_attlen > (attlen-1) ) nc_attlen = (size_t)(attlen-1);
-
-          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);
-
-          size_t ssize = strlen(attbuf) + 1;
-
-          if ( ssize > (size_t)attlen ) ssize = (size_t)attlen;
-          memcpy(atttext, attbuf, ssize);
-          atttext[ssize - 1] = 0;
-          Free(attbuf);
-        }
-      else
-        {
-          atttext[0] = 0;
-        }
-    }
-#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;
-#endif
-
-  return isText;
-}
-
-static
-int xtypeIsFloat(int xtype)
-{
-  int isFloat = xtype == NC_FLOAT || xtype == NC_DOUBLE;
-  return isFloat;
-}
-
-static
-int cdfInqDatatype(int xtype, int lunsigned)
-{
-  int datatype = -1;
-
-#if  defined  (HAVE_NETCDF4)
-  if ( xtype == NC_BYTE && lunsigned ) xtype = NC_UBYTE;
-#endif
-
-  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
-
-  return datatype;
-}
-
-
-void cdfCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
-{
-  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;
-
-  void *data
-    = Malloc((size_t)datasize
-             * (memtype == MEMTYPE_DOUBLE ? sizeof(double) : sizeof(float)));
-
-  int nmiss;
-  cdf_read_record(streamptr1, memtype, data, &nmiss);
-  cdf_write_record(streamptr2, memtype, data, nmiss);
-
-  Free(data);
-}
-
-/* not used
-int cdfInqRecord(stream_t *streamptr, int *varID, int *levelID)
-{
-  int tsID, recID;
-
-  recID = streamptr->tsteps[0].curRecID++;
-  printf("cdfInqRecord recID %d %d\n", recID, streamptr->tsteps[0].curRecID);
-  printf("cdfInqRecord tsID %d\n", streamptr->curTsID);
-
-  if ( streamptr->tsteps[0].curRecID >= streamptr->tsteps[0].nrecs )
-    {
-      streamptr->tsteps[0].curRecID = 0;
-    }
-
-  *varID   = streamptr->tsteps[0].records[recID].varID;
-  *levelID = streamptr->tsteps[0].records[recID].levelID;
-
-  streamptr->record->varID   = *varID;
-  streamptr->record->levelID = *levelID;
-
-  if ( CDI_Debug )
-    Message("recID = %d  varID = %d  levelID = %d", recID, *varID, *levelID);
-
-  return (recID+1);
-}
-*/
-
-
-void cdfDefRecord(stream_t *streamptr)
-{
-  (void)streamptr;
-}
-
-#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;
-
-          if ( lwarn )
-            {
-              lwarn = FALSE;
-              Warning("NetCDF4/Szip compression not compiled in!");
-            }
-        }
-      else
-        Error("nc_def_var_szip failed, status = %d", retval);
-    }
-}
-#endif
-
-static
-void cdfDefTimeValue(stream_t *streamptr, int tsID)
-{
-  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 )
-    {
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
-    }
-
-  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);
-
-  if ( taxis->has_bounds )
-    {
-      size_t start[2], count[2];
-
-      ncvarid = streamptr->basetime.ncvarboundsid;
-
-      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);
-
-      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 != UNDEFID )
-    {
-      timevalue = taxis->fc_period;
-      cdf_put_var1_double(fileID, ncvarid, &index, &timevalue);
-    }
-
-  /*
-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 time_bndsid = -1;
-  int dims[2];
-
-  dims[0] = nctimedimid;
-
-  /* fprintf(stderr, "time has bounds\n"); */
-
-  if ( nc_inq_dimid(fileID, bndsName, &dims[1]) != NC_NOERR )
-    cdf_def_dim(fileID, bndsName, 2, &dims[1]);
-
-  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
-    {
-      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 (time_bndsid);
-}
-
-static
-void cdfDefTimeUnits(char *unitstr, taxis_t* taxis0, taxis_t* taxis)
-{
-  unitstr[0] = 0;
-
-  if ( taxis0->type == TAXIS_ABSOLUTE )
-    {
-      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");
-    }
-  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);
-
-      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);
-    }
-}
-
-static
-void cdfDefForecastTimeUnits(char *unitstr, int timeunit)
-{
-  unitstr[0] = 0;
-
-  if ( timeunit == -1 ) timeunit = TUNIT_HOUR;
-
-  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;
-
-  strcpy(unitstr, tunitNamePtr(timeunit));
-}
-
-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] };
-
-  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;
-      }
-}
-
-
-void cdfDefTime(stream_t* streamptr)
-{
-  int time_varid;
-  int time_dimid;
-  int time_bndsid = -1;
-  static const char default_name[] = "time";
-
-  if ( streamptr->basetime.ncvarid != UNDEFID ) return;
-
-  int fileID = streamptr->fileID;
-
-  if ( streamptr->ncmode == 0 ) streamptr->ncmode = 1;
-  if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-
-  taxis_t *taxis = &streamptr->tsteps[0].taxis;
-
-  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;
-
-  cdf_def_var(fileID, taxis_name, NC_DOUBLE, 1, &time_dimid, &time_varid);
-
-  streamptr->basetime.ncvarid = time_varid;
-
-  {
-    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);
-
-  if ( taxis->has_bounds )
-    {
-      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);
-        */
-      }
-  }
-
-  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;
-
-      {
-        static const char stdname[] = "forecast_period";
-        cdf_put_att_text(fileID, leadtimeid, "standard_name", sizeof(stdname) - 1, stdname);
-      }
-
-      {
-        static const char lname[] = "Time elapsed since the start of the forecast";
-        cdf_put_att_text(fileID, leadtimeid, "long_name", sizeof(lname) - 1, lname);
-      }
-
-      {
-          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);
-}
-
-
-void cdfDefTimestep(stream_t *streamptr, int tsID)
-{
-  int vlistID = streamptr->vlistID;
-
-  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
-
-  cdfDefTimeValue(streamptr, tsID);
-}
-
-static
-void cdfDefComplex(stream_t *streamptr, int gridID)
-{
-  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 ( 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;
-            }
-        }
-    }
-
-  if ( dimID == UNDEFID )
-    {
-      size_t dimlen = 2;
-
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-
-      cdf_def_dim(fileID, axisname, dimlen, &dimID);
-
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
-    }
-
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  streamptr->xdimID[gridindex] = dimID;
-}
-
-static void
-cdfDefSPorFC(stream_t *streamptr, int gridID,
-             char *restrict axisname, int gridRefType)
-{
-  int index, iz = 0;
-  int dimID = UNDEFID;
-
-  int vlistID = streamptr->vlistID;
-
-  int ngrids = vlistNgrids(vlistID);
-
-  size_t dimlen = (size_t)gridInqSize(gridID)/2;
-
-  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++;
-            }
-        }
-    }
-
-  if ( dimID == UNDEFID )
-    {
-      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;
-    }
-
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  streamptr->ydimID[gridindex] = dimID;
-}
-
-static
-void cdfDefSP(stream_t *streamptr, int gridID)
-{
-  /*
-  char longname[] = "Spherical harmonic coefficient";
-  */
-  char axisname[5] = "nspX";
-  cdfDefSPorFC(streamptr, gridID, axisname, GRID_SPECTRAL);
-}
-
-
-static
-void cdfDefFC(stream_t *streamptr, int gridID)
-{
-  char axisname[5] = "nfcX";
-  cdfDefSPorFC(streamptr, gridID, axisname, GRID_FOURIER);
-}
-
-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,
-};
-
-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;
-
-  int vlistID = streamptr->vlistID;
-  int dimlen = inqs->axisSize(gridID);
-  if ( dimlen != 1 )
-    Error("%s isn't 1 for %s grid!", sizeName, gridNamePtr(gridInqType(gridID)));
-
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  int ncvarid = dimID[gridindex];
-
-  if ( ncvarid == UNDEFID )
-    {
-      int dimNcID = streamptr->basetime.ncvarid;
-      int fileID  = streamptr->fileID;
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-
-      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;
-    }
-
-  dimID[gridindex] = ncvarid; /* var ID for trajectory !!! */
-}
-
-static
-void cdfDefTrajLon(stream_t *streamptr, int gridID)
-{
-  cdfDefTrajLatLon(streamptr, gridID, &gridInqsX, streamptr->xdimID, "Xsize");
-}
-
-
-static
-void cdfDefTrajLat(stream_t *streamptr, int gridID)
-{
-  cdfDefTrajLatLon(streamptr, gridID, &gridInqsY, streamptr->ydimID, "Ysize");
-}
-
-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];
-
-  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;
-}
-
-static
-void checkGridName(char *axisname, int fileID, int vlistID, int gridID, int ngrids, int mode)
-{
-  int ncdimid;
-  char axisname2[CDI_MAX_NAME];
-
-  /* check that the name is not already defined */
-  unsigned iz = 0;
-
-  size_t axisnameLen = strlen(axisname);
-  memcpy(axisname2, axisname, axisnameLen + 1);
-  do
-    {
-      if ( iz ) sprintf(axisname2 + axisnameLen, "_%u", iz+1);
-
-      int status = nc_inq_varid(fileID, axisname2, &ncdimid);
-
-      if ( status != NC_NOERR )
-        {
-          if ( iz )
-            {
-              /* 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;
-                    }
-                }
-            }
-          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];
-
-  /* check that the name is not already defined */
-  unsigned iz = 0;
-
-  size_t axisnameLen = strlen(axisname);
-  memcpy(axisname2, axisname, axisnameLen + 1);
-  do
-    {
-      if ( iz ) sprintf(axisname2 + axisnameLen, "_%u", iz+1);
-
-      int ncdimid, status = nc_inq_varid(fileID, axisname2, &ncdimid);
-
-      if ( status != NC_NOERR )
-        {
-          if ( iz )
-            {
-              /* 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);
-
-
-  if ( iz ) sprintf(axisname + axisnameLen, "_%u", iz+1);
-
-  return (int)iz;
-}
-
-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;
-                  }
-                }
-            }
-        }
-    }
-
-  if ( dimID == UNDEFID )
-    {
-      const double *pvals = gridAxisInq->axisValsPtr(gridID);
-
-      /* 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);
-
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-
-      if ( ndims )
-        {
-          char dimname[CDI_MAX_NAME+3];
-          dimname[0] = 0;
-
-          if ( pvals == NULL )
-            cdiGridInqString(gridID, dimKey, CDI_MAX_NAME, dimname);
-
-          if ( dimname[0] == 0 ) strcpy(dimname, extendedAxisname);
-          dimID = checkDimName(fileID, dimlen, dimname);
-
-          if ( dimID == UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID);
-        }
-
-      bool gen_bounds = false;
-      int grid_is_cyclic = gridIsCircular(gridID);
-      double *pbounds = NULL;
-      if ( pvals )
-        {
-          cdf_def_var(fileID, extendedAxisname, xtype, ndims, &dimID, &ncvarid);
-
-          cdfPutGridStdAtts(fileID, ncvarid, gridID, gridAxisInq);
-          {
-            char axisStr[2] = { axisLetter, '\0' };
-            cdf_put_att_text(fileID, ncvarid, "axis", 1, axisStr);
-          }
-
-          pbounds = (double *)gridAxisInq->axisBoundsPtr(gridID);
-
-          if ( CDI_cmor_mode && grid_is_cyclic && !pbounds )
-            {
-              gen_bounds = true;
-              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 )
-            {
-              size_t nvertex = 2;
-              if ( nc_inq_dimid(fileID, bndsName, &nvdimID) != NC_NOERR )
-                cdf_def_dim(fileID, bndsName, nvertex, &nvdimID);
-            }
-          if ( pbounds && nvdimID != 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);
-            }
-        }
-
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
-
-      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);
-
-      if ( ndims == 0 ) ncAxisVarIDs[gridindex] = ncvarid;
-    }
-
-  axisDimIDs[gridindex] = dimID;
-}
-
-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;
-}
-
-static
-void cdfDefXaxis(stream_t *streamptr, int gridID, int ndims)
-{
-  cdfDefAxisCommon(streamptr, gridID, ndims, &gridInqsX, streamptr->xdimID,
-                   CDI_GRID_XDIMNAME, 'X', finishCyclicXBounds,
-                   streamptr->ncxvarID);
-}
-
-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]);
-}
-
-static
-void cdfDefYaxis(stream_t *streamptr, int gridID, int ndims)
-{
-  cdfDefAxisCommon(streamptr, gridID, ndims, &gridInqsY, streamptr->ydimID,
-                   CDI_GRID_YDIMNAME, 'Y', finishCyclicYBounds,
-                   streamptr->ncyvarID);
-}
-
-static
-void cdfGridCompress(int fileID, int ncvarid, int gridsize, int filetype, int comptype)
-{
-#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);
-    }
-#endif
-}
-
-static
-void cdfDefCurvilinear(stream_t *streamptr, int gridID)
-{
-  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;
-
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-
-  int ngrids = vlistNgrids(vlistID);
-
-  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);
-
-  for ( int index = 0; index < ngrids; index++ )
-    {
-      if ( streamptr->xdimID[index] != UNDEFID )
-        {
-          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;
-                  }
-            }
-        }
-    }
-
-  if ( xdimID == UNDEFID || ydimID == 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 ) { 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);
-      }
-
-      int nvdimID = UNDEFID;
-      int dimIDs[3];
-      if ( gridInqXboundsPtr(gridID) || gridInqYboundsPtr(gridID) )
-        {
-          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);
-        }
-
-      dimIDs[0] = ydimID;
-      dimIDs[1] = xdimID;
-      dimIDs[2] = nvdimID;
-
-      if ( gridInqXvalsPtr(gridID) )
-        {
-          char xaxisname[CDI_MAX_NAME];
-          gridInqXname(gridID, xaxisname);
-          checkGridName(xaxisname, fileID, vlistID, gridID, ngrids, 'X');
-
-          cdf_def_var(fileID, xaxisname, xtype, 2, dimIDs, &ncxvarid);
-          cdfGridCompress(fileID, ncxvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
-
-          cdfPutGridStdAtts(fileID, ncxvarid, gridID, &gridInqsX);
-
-          /* attribute for Panoply */
-          cdf_put_att_text(fileID, ncxvarid, "_CoordinateAxisType", 3, "Lon");
-
-          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);
-
-              cdf_put_att_text(fileID, ncxvarid, "bounds", xaxisnameLen + sizeof (bndsName), xaxisname);
-            }
-        }
-
-      if ( gridInqYvalsPtr(gridID) )
-        {
-          char yaxisname[CDI_MAX_NAME];
-          gridInqYname(gridID, yaxisname);
-          checkGridName(yaxisname, fileID, vlistID, gridID, ngrids, 'Y');
-
-          cdf_def_var(fileID, yaxisname, xtype, 2, dimIDs, &ncyvarid);
-          cdfGridCompress(fileID, ncyvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
-
-          cdfPutGridStdAtts(fileID, ncyvarid, gridID, &gridInqsY);
-
-          /* attribute for Panoply */
-          cdf_put_att_text(fileID, ncyvarid, "_CoordinateAxisType", 3, "Lat");
-
-          if ( gridInqYboundsPtr(gridID) && nvdimID != UNDEFID )
-            {
-              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);
-            }
-        }
-
-      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";
-
-          cdf_def_var(fileID, yaxisname_, xtype, 2, 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);
-        }
-
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
-
-      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));
-    }
-
-  streamptr->xdimID[gridindex] = xdimID;
-  streamptr->ydimID[gridindex] = ydimID;
-  streamptr->ncxvarID[gridindex] = ncxvarid;
-  streamptr->ncyvarID[gridindex] = ncyvarid;
-  streamptr->ncavarID[gridindex] = ncavarid;
-}
-
-static
-void cdfDefRgrid(stream_t *streamptr, int gridID)
-{
-  int dimID = UNDEFID;
-
-  int vlistID = streamptr->vlistID;
-  int ngrids = vlistNgrids(vlistID);
-
-  size_t dimlen = (size_t)gridInqSize(gridID);
-
-  int iz = 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_GAUSSIAN_REDUCED )
-            {
-              size_t dimlen0 = (size_t)gridInqSize(gridID0);
-
-              if ( dimlen == dimlen0 )
-                {
-                  dimID = streamptr->xdimID[index];
-                  break;
-                }
-              iz++;
-            }
-        }
-    }
-
-  if ( dimID == 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;
-        }
-
-      char axisname[7] = "rgridX";
-      if ( iz == 0 ) axisname[5] = '\0';
-      else           sprintf(&axisname[5], "%1d", iz+1);
-
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-
-      cdf_def_dim(fileID, axisname, dimlen, &dimID);
-
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
-    }
-
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  streamptr->xdimID[gridindex] = dimID;
-}
-
-static
-void cdfDefGdim(stream_t *streamptr, int gridID)
-{
-  int iz = 0;
-  int dimID = UNDEFID;
-
-  int vlistID = streamptr->vlistID;
-  int ngrids = vlistNgrids(vlistID);
-
-  size_t dimlen = (size_t)gridInqSize(gridID);
-
-  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++;
-              }
-          }
-      }
-
-  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++;
-              }
-          }
-      }
-
-  if ( dimID == UNDEFID )
-    {
-      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 == UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID);
-
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
-    }
-
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  streamptr->xdimID[gridindex] = dimID;
-}
-
-static
-void cdfDefGridReference(stream_t *streamptr, int gridID)
-{
-  int fileID  = streamptr->fileID;
-  int number = gridInqNumber(gridID);
-
-  if ( number > 0 )
-    {
-      cdf_put_att_int(fileID, NC_GLOBAL, "number_of_grid_used", NC_INT, 1, &number);
-    }
-
-  const char *gridfile = gridInqReferencePtr(gridID);
-  if ( gridfile && gridfile[0] != 0 )
-    cdf_put_att_text(fileID, NC_GLOBAL, "grid_file_uri", strlen(gridfile), gridfile);
-}
-
-static
-void cdfDefGridUUID(stream_t *streamptr, int gridID)
-{
-  unsigned char uuidOfHGrid[CDI_UUID_SIZE];
-
-  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);
-        }
-    }
-}
-
-static
-void cdfDefZaxisUUID(stream_t *streamptr, int zaxisID)
-{
-  unsigned char uuidOfVGrid[CDI_UUID_SIZE];
-  zaxisInqUUID(zaxisID, uuidOfVGrid);
-
-  if ( uuidOfVGrid[0] != 0 )
-    {
-      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);
-        }
-    }
-}
-
-static
-void cdfDefUnstructured(stream_t *streamptr, int gridID)
-{
-  int dimID = UNDEFID;
-  int ncxvarid = UNDEFID, ncyvarid = UNDEFID;
-  int ncbxvarid = UNDEFID, ncbyvarid = UNDEFID, ncavarid = UNDEFID;
-  int nvdimID = UNDEFID;
-  nc_type xtype = NC_DOUBLE;
-
-  if ( gridInqPrec(gridID) == DATATYPE_FLT32 ) xtype = NC_FLOAT;
-
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-
-  int ngrids = vlistNgrids(vlistID);
-
-  size_t dimlen = (size_t)gridInqSize(gridID);
-  int gridindex = vlistGridIndex(vlistID, gridID);
-
-  for ( int index = 0; index < ngrids; index++ )
-    {
-      if ( streamptr->xdimID[index] != UNDEFID )
-        {
-          int gridID0 = vlistGrid(vlistID, index);
-          int gridtype0 = gridInqType(gridID0);
-          if ( gridtype0 == GRID_UNSTRUCTURED )
-            {
-              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 ( 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);
-      }
-
-      size_t nvertex = (size_t)gridInqNvertex(gridID);
-      if ( nvertex > 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);
-        }
-
-      cdfDefGridReference(streamptr, gridID);
-
-      cdfDefGridUUID(streamptr, gridID);
-
-      if ( gridInqXvalsPtr(gridID) )
-        {
-          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);
-
-          cdfPutGridStdAtts(fileID, ncxvarid, gridID, &gridInqsX);
-
-          if ( gridInqXboundsPtr(gridID) && nvdimID != UNDEFID )
-            {
-              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);
-            }
-        }
-
-      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);
-
-          cdfPutGridStdAtts(fileID, ncyvarid, gridID, &gridInqsY);
-
-          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_put_att_text(fileID, ncyvarid, "bounds", yaxisnameLen + sizeof (bndsName), yaxisname);
-            }
-        }
-
-      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";
-
-          cdf_def_var(fileID, yaxisname_, xtype, 1, &dimID, &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);
-        }
-
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
-
-      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));
-    }
-
-  streamptr->xdimID[gridindex] = dimID;
-  streamptr->ncxvarID[gridindex] = ncxvarid;
-  streamptr->ncyvarID[gridindex] = ncyvarid;
-  streamptr->ncavarID[gridindex] = ncavarid;
-}
-
-struct attTxtTab2
-{
-  const char *attName, *attVal;
-  size_t valLen;
-};
-
-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;
-      size_t start;
-      size_t count = 1;
-      int ncdimid, ncdimid2;
-      int hyaiid, hybiid, hyamid, hybmid;
-      double mval;
-
-      if ( streamptr->vct.ilev > 0 )
-        {
-          if ( streamptr->vct.ilev != ilev )
-            Error("more than one VCT for each file unsupported!");
-          return;
-        }
-
-      int fileID = streamptr->fileID;
-
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-
-      cdf_def_dim(fileID, "nhym", (size_t)mlev, &ncdimid);
-      cdf_def_dim(fileID, "nhyi", (size_t)ilev, &ncdimid2);
-
-      streamptr->vct.mlev   = mlev;
-      streamptr->vct.ilev   = ilev;
-      streamptr->vct.mlevID = ncdimid;
-      streamptr->vct.ilevID = ncdimid2;
-
-      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);
-
-      {
-        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);
-      }
-
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
-
-      const double *vctptr = zaxisInqVctPtr(zaxisID);
-
-      cdf_put_var_double(fileID, hyaiid, vctptr);
-      cdf_put_var_double(fileID, hybiid, vctptr+ilev);
-
-      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);
-        }
-    }
-}
-
-static
-void cdf_def_vct_cf(stream_t *streamptr, int zaxisID, int nclevID, int ncbndsID)
-{
-  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;
-      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;
-        }
-
-      int fileID = streamptr->fileID;
-
-      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
-
-      int dimIDs[2];
-      dimIDs[0] = nclevID;
-      dimIDs[1] = ncbndsID;
-
-      streamptr->vct.mlev   = mlev;
-      streamptr->vct.ilev   = ilev;
-      streamptr->vct.mlevID = nclevID;
-      streamptr->vct.ilevID = nclevID;
-
-      cdf_def_var(fileID, "ap", NC_DOUBLE, 1, dimIDs,  &hyamid);
-      cdf_def_var(fileID, "b",  NC_DOUBLE, 1, dimIDs,  &hybmid);
-
-      {
-        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 ( ncbndsID != -1 )
-        {
-          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);
-          }
-        }
-
-      cdf_enddef(fileID);
-      streamptr->ncmode = 2;
-
-      const double *vctptr = zaxisInqVctPtr(zaxisID);
-      double tarray[ilev*2];
-
-      if ( ncbndsID != -1 )
-        {
-          for ( int i = 0; i < mlev; ++i )
-            {
-              tarray[2*i  ] = vctptr[i];
-              tarray[2*i+1] = vctptr[i+1];
-            }
-          cdf_put_var_double(fileID, hyaiid, tarray);
-
-          for ( int i = 0; i < mlev; ++i )
-            {
-              tarray[2*i  ] = vctptr[ilev+i];
-              tarray[2*i+1] = vctptr[ilev+i+1];
-            }
-          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);
-    }
-}
-
-struct attTxtTab { const char *txt; size_t txtLen; };
-
-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)
-{
-  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);
-  }
-
-  cdf_enddef(fileID);
-  streamptr->ncmode = 2;
-
-  cdf_put_var_double(fileID, ncvarid, zaxisInqLevelsPtr(zaxisID));
-
-  cdf_def_vct_echam(streamptr, zaxisID);
-
-  if ( *dimID == UNDEFID )
-    {
-      if ( type == ZAXIS_HYBRID )
-        streamptr->zaxisID[zaxisindex] = streamptr->vct.mlevID;
-      else
-        streamptr->zaxisID[zaxisindex] = streamptr->vct.ilevID;
-    }
-}
-
-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)
-{
-  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 ( 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 ( 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));
-          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);
-          }
-        }
-    }
-
-  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 )
-        {
-          zbounds[2*i  ] = lbounds[i];
-          zbounds[2*i+1] = ubounds[i];
-        }
-      cdf_put_var_double(fileID, ncbvarid, zbounds);
-    }
-
-  cdf_def_vct_cf(streamptr, zaxisID, *dimID, nvdimID);
-
-  if ( *dimID == UNDEFID )
-    {
-      if ( type == ZAXIS_HYBRID )
-        streamptr->zaxisID[zaxisindex] = streamptr->vct.mlevID;
-      else
-        streamptr->zaxisID[zaxisindex] = streamptr->vct.ilevID;
-    }
-}
-
-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)
-{
-  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);
-}
-
-static
-void cdfDefZaxis(stream_t *streamptr, int zaxisID)
-{
-  /*  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 )
-    {
-      is_scalar = zaxisInqScalar(zaxisID);
-      if ( !is_scalar && CDI_cmor_mode )
-        {
-          is_scalar = TRUE;
-          zaxisDefScalar(zaxisID);
-        }
-    }
-
-  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 )
-    {
-      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);
-	    }
-
-          if ( ndims == 0 ) streamptr->nczvarID[zaxisindex] = ncvarid;
-        }
-    }
-
-  if ( dimID != UNDEFID )
-    streamptr->zaxisID[zaxisindex] = dimID;
-}
-
-static
-void cdfDefPole(stream_t *streamptr, int gridID)
-{
-  int ncvarid = UNDEFID;
-  static const char varname[] = "rotated_pole";
-  static const char mapname[] = "rotated_latitude_longitude";
-
-  int fileID  = streamptr->fileID;
-
-  double ypole = gridInqYpole(gridID);
-  double xpole = gridInqXpole(gridID);
-  double angle = gridInqAngle(gridID);
-
-  cdf_redef(fileID);
-
-  int ncerrcode = nc_def_var(fileID, varname, (nc_type) NC_CHAR, 0, NULL, &ncvarid);
-  if ( ncerrcode == NC_NOERR )
-    {
-      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);
-    }
-
-  cdf_enddef(fileID);
-}
-
-
-static
-void cdfDefMapping(stream_t *streamptr, int gridID)
-{
-  int ncvarid = UNDEFID;
-  int fileID  = streamptr->fileID;
-
-  if ( gridInqType(gridID) == GRID_SINUSOIDAL )
-    {
-      static const char varname[] = "sinusoidal";
-      static const char mapname[] = "sinusoidal";
-
-      cdf_redef(fileID);
-
-      int ncerrcode = nc_def_var(fileID, varname, (nc_type) NC_CHAR, 0, NULL, &ncvarid);
-      if ( ncerrcode == NC_NOERR )
-        {
-          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);
-          */
-        }
-
-      cdf_enddef(fileID);
-    }
-  else if ( gridInqType(gridID) == GRID_LAEA )
-    {
-      static const char varname[] = "laea";
-      static const char mapname[] = "lambert_azimuthal_equal_area";
-
-      cdf_redef(fileID);
-
-      int ncerrcode = nc_def_var(fileID, varname, (nc_type) NC_CHAR, 0, NULL, &ncvarid);
-      if ( ncerrcode == NC_NOERR )
-        {
-          double a, lon_0, lat_0;
-
-          gridInqLaea(gridID, &a, &lon_0, &lat_0);
-
-          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);
-        }
-
-      cdf_enddef(fileID);
-    }
-  else if ( gridInqType(gridID) == GRID_LCC2 )
-    {
-      static const char varname[] = "Lambert_Conformal";
-      static const char mapname[] = "lambert_conformal_conic";
-
-      cdf_redef(fileID);
-
-      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;
-
-          gridInqLcc2(gridID, &radius, &lon_0, &lat_0, &lat_1, &lat_2);
-
-          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_enddef(fileID);
-    }
-}
-
-
-static
-void cdfDefGrid(stream_t *streamptr, int gridID)
-{
-  int vlistID = streamptr->vlistID;
-  int gridindex = vlistGridIndex(vlistID, gridID);
-  if ( streamptr->xdimID[gridindex] != UNDEFID ) return;
-
-  int gridtype = gridInqType(gridID);
-  int size     = gridInqSize(gridID);
-
-  if ( CDI_Debug )
-    Message("gridtype = %d  size = %d", gridtype, size);
-
-  if ( gridtype == GRID_GAUSSIAN ||
-       gridtype == GRID_LONLAT   ||
-       gridtype == GRID_GENERIC )
-    {
-      if ( gridtype == GRID_GENERIC )
-        {
-          if ( size == 1 && gridInqXsize(gridID) == 0 && gridInqYsize(gridID) == 0 )
-            {
-              /* no grid information */
-            }
-          else
-            {
-              int lx = 0, ly = 0;
-              if ( gridInqXsize(gridID) > 0 /*&& gridInqXvals(gridID, NULL) > 0*/ )
-                {
-                  cdfDefXaxis(streamptr, gridID, 1);
-                  lx = 1;
-                }
-
-              if ( gridInqYsize(gridID) > 0 /*&& gridInqYvals(gridID, NULL) > 0*/ )
-                {
-                  cdfDefYaxis(streamptr, gridID, 1);
-                  ly = 1;
-                }
-
-              if ( lx == 0 && ly == 0 ) cdfDefGdim(streamptr, gridID);
-            }
-        }
-      else
-        {
-          int ndims = 1;
-          if ( gridtype == GRID_LONLAT && size == 1 && gridInqHasDims(gridID) == FALSE )
-            ndims = 0;
-
-          if ( gridInqXsize(gridID) > 0 ) cdfDefXaxis(streamptr, gridID, ndims);
-          if ( gridInqYsize(gridID) > 0 ) cdfDefYaxis(streamptr, gridID, ndims);
-        }
-
-      if ( gridIsRotated(gridID) ) cdfDefPole(streamptr, gridID);
-    }
-  else if ( gridtype == GRID_CURVILINEAR )
-    {
-      cdfDefCurvilinear(streamptr, gridID);
-    }
-  else if ( gridtype == GRID_UNSTRUCTURED )
-    {
-      cdfDefUnstructured(streamptr, gridID);
-    }
-  else if ( gridtype == GRID_GAUSSIAN_REDUCED )
-    {
-      cdfDefRgrid(streamptr, gridID);
-    }
-  else if ( gridtype == GRID_SPECTRAL )
-    {
-      cdfDefComplex(streamptr, gridID);
-      cdfDefSP(streamptr, gridID);
-    }
-  else if ( gridtype == GRID_FOURIER )
-    {
-      cdfDefComplex(streamptr, gridID);
-      cdfDefFC(streamptr, gridID);
-    }
-  else if ( gridtype == GRID_TRAJECTORY )
-    {
-      cdfDefTrajLon(streamptr, gridID);
-      cdfDefTrajLat(streamptr, gridID);
-    }
-  else if ( gridtype == GRID_SINUSOIDAL || gridtype == GRID_LAEA || gridtype == GRID_LCC2 )
-    {
-      cdfDefXaxis(streamptr, gridID, 1);
-      cdfDefYaxis(streamptr, gridID, 1);
-
-      cdfDefMapping(streamptr, gridID);
-    }
-  /*
-  else if ( gridtype == GRID_LCC )
-    {
-      cdfDefLcc(streamptr, gridID);
-    }
-  */
-  else
-    {
-      Error("Unsupported grid type: %s", gridNamePtr(gridtype));
-    }
-}
-
-static
-void scale_add(size_t size, double *data, double addoffset, double scalefactor)
-{
-  int laddoffset;
-  int lscalefactor;
-
-  laddoffset   = IS_NOT_EQUAL(addoffset, 0);
-  lscalefactor = IS_NOT_EQUAL(scalefactor, 1);
-
-  if ( laddoffset || lscalefactor )
-    {
-      for (size_t i = 0; i < size; ++i )
-        {
-          if ( lscalefactor ) data[i] *= scalefactor;
-          if ( laddoffset )   data[i] += addoffset;
-        }
-    }
-}
-
-static
-void cdfCreateRecords(stream_t *streamptr, int tsID)
-{
-  if ( tsID < 0 || (tsID >= streamptr->ntsteps && tsID > 0) ) return;
-
-  if ( streamptr->tsteps[tsID].nallrecs > 0 ) return;
-
-  int vlistID  = streamptr->vlistID;
-
-  tsteps_t* sourceTstep = streamptr->tsteps;
-  tsteps_t* destTstep = sourceTstep + tsID;
-
-  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   = 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;
-
-      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++;
-            }
-        }
-    }
-  else if ( tsID == 1 )
-    {
-      int nvrecs = 0;
-      for ( int varID = 0; varID < nvars; varID++ )
-        {
-          if ( vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT )
-            {
-              int zaxisID = vlistInqVarZaxis(vlistID, varID);
-              nvrecs += zaxisInqSize(zaxisID);
-            }
-        }
-
-      streamptr->nrecs += nvrecs;
-
-      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
-      destTstep->nrecs      = nvrecs;
-      destTstep->nallrecs   = nrecs;
-      destTstep->recordSize = nrecs;
-      destTstep->curRecID   = UNDEFID;
-
-      memcpy(destTstep->records, sourceTstep->records, (size_t)nrecs*sizeof(record_t));
-
-      if ( nvrecs )
-        {
-          destTstep->recIDs = (int *) Malloc((size_t)nvrecs * sizeof (int));
-          for ( int recID = 0, vrecID = 0; recID < nrecs; recID++ )
-            {
-              int varID = destTstep->records[recID].varID;
-              if ( vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT )
-                {
-                  destTstep->recIDs[vrecID++] = recID;
-                }
-            }
-        }
-    }
-  else
-    {
-      if ( streamptr->tsteps[1].records == 0 ) cdfCreateRecords(streamptr, 1);
-
-      int nvrecs = streamptr->tsteps[1].nrecs;
-
-      streamptr->nrecs += nvrecs;
-
-      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
-      destTstep->nrecs      = nvrecs;
-      destTstep->nallrecs   = nrecs;
-      destTstep->recordSize = nrecs;
-      destTstep->curRecID   = UNDEFID;
-
-      memcpy(destTstep->records, sourceTstep->records, (size_t)nrecs*sizeof(record_t));
-
-      destTstep->recIDs     = (int *) Malloc((size_t)nvrecs * sizeof(int));
-
-      memcpy(destTstep->recIDs, streamptr->tsteps[1].recIDs, (size_t)nvrecs*sizeof(int));
-    }
-}
-
-
-static
-int cdfTimeDimID(int fileID, int ndims, int nvars)
-{
-  for ( int dimid = 0; dimid < ndims; dimid++ )
-    {
-      char dimname[80];
-      cdf_inq_dimname(fileID, dimid, dimname);
-      if ( memcmp(dimname, "time", 4) == 0 )
-        return dimid;
-    }
-
-
-  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++ )
-            {
-              char sbuf[CDI_MAX_NAME];
-              cdf_inq_attname(fileID, varid, iatt, sbuf);
-              if ( strncmp(sbuf, "units", 5) == 0 )
-                {
-                  cdfGetAttText(fileID, varid, "units", sizeof(sbuf), sbuf);
-                  strtolower(sbuf);
-
-                  if ( isTimeUnits(sbuf) )
-                    return dimids[0];
-                }
-            }
-        }
-    }
-
-  return UNDEFID;
-}
-
-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;
-    }
-}
-
-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;
-    }
-}
-
-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);
-
-      ncvars[ncvarid].warn = TRUE;
-      isvar = FALSE;
-    }
-
-  ncvars[ncvarid].isvar = isvar;
-}
-
-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);
-    }
-
-  ncvars[ncvarid].dimtype[dimid] = dimtype;
-}
-
-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;
-    }
-
-  return status;
-}
-
-static
-bool isLatAxis(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_latitude", 13) == 0 || memcmp(stdname, "latitude", 8) == 0)) )
-    {
-      status = true;
-    }
-
-  if ( status == false &&
-       memcmp(stdname, "grid_longitude", 14) && memcmp(stdname, "longitude", 9) &&
-       memcmp(lc_units, "degree", 6) == 0 )
-    {
-      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;
-}
-
-static
-bool isDBLAxis(/*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;
-}
-
-static
-bool unitsIsHeight(const char *units)
-{
-  bool status = false;
-  int u0 = units[0];
-
-  if ( (u0=='m' && (!units[1] || strncmp(units, "meter", 5) == 0)) ||
-       (!units[2] && units[1]=='m' && (u0=='c' || u0=='d' || u0=='k')) )
-    {
-      status = true;
-    }
-
-  return status;
-}
-
-static
-bool isDepthAxis(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;
-}
-
-static
-bool isHeightAxis(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;
-}
-
-static
-bool unitsIsPressure(const char *units)
-{
-  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;
-}
-
-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;
-
-      for ( int i = 0; i < 3; 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;
-
-          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 )
-            {
-              Warning("%s - %s", nc_strerror(status_nc), varname);
-            }
-
-          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++ )
-        {
-          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);
-            }
-
-          if ( lstop ) break;
-        }
-    }
-
-  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 )
-    {
-      cdiConvention = CDI_CONVENTION_CF;
-
-      status = true;
-      ncvar->zaxistype = ZAXIS_HYBRID;
-      int dimid = ncvar->dimids[0];
-      size_t dimlen = ncdims[dimid].len;
-
-      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;
-
-      if ( ncvar->bounds != UNDEFID && ncvars[ncvar->bounds].lformula && ncvars[ncvar->bounds].lformulaterms )
-        {
-          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;
-
-              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);
-
-                  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];
-
-                  if ( ret == 2 && IS_NOT_EQUAL(px, 1) )
-                    for ( size_t i = 0; i < dimlen+1; ++i ) vct[i] *= px;
-
-                  ncvar->vct = vct;
-                  ncvar->vctsize = vctsize;
-                }
-            }
-        }
-    }
-
-  return status;
-}
-
-
-static
-int isGaussGrid(size_t ysize, double yinc, const double *yvals)
-{
-  int lgauss = FALSE;
-  double *yv, *yw;
-
-  if ( IS_EQUAL(yinc, 0) && ysize > 2 ) /* check if gaussian */
-    {
-      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;
-
-      for ( i = 0; i < ysize; i++ )
-        if ( fabs(yv[i] - yvals[i]) >
-             ((yv[0] - yv[1])/500) ) break;
-
-      if ( i == ysize ) lgauss = TRUE;
-
-      /* 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);
-}
-
-static
-void printNCvars(const ncvar_t *ncvars, int nvars, const char *oname)
-{
-  char axis[7];
-  int ncvarid, i;
-  int ndim;
-  static const char iaxis[] = {'t', 'z', 'y', 'x'};
-
-  fprintf(stderr, "%s:\n", oname);
-
-  for ( 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);
-    }
-}
-
-static
-void cdfScanVarAttributes(int nvars, ncvar_t *ncvars, ncdim_t *ncdims,
-                          int timedimid, int modelID, int format)
-{
-  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;
-
-  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
-    {
-      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
-
-      if ( nvdims > 0 )
-        {
-          if ( timedimid == dimidsp[0] )
-            {
-              ncvars[ncvarid].tsteptype = TSTEP_INSTANT;
-              cdfSetDim(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;
-                    }
-                }
-            }
-        }
-
-      for ( iatt = 0; iatt < nvatts; iatt++ )
-        {
-          cdf_inq_attname(ncid, ncvarid, iatt, attname);
-          cdf_inq_atttype(ncid, ncvarid, attname, &atttype);
-          cdf_inq_attlen(ncid, ncvarid, attname, &attlen);
-
-          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) )
-            {
-              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);
-                }
-              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) )
-            {
-              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
-                {
-                  static int warn = TRUE;
-                  if ( warn )
-                    {
-                      warn = FALSE;
-                      Warning("NetCDF attribute level_type='%s' unsupported!", attstring);
-                    }
-                }
-
-              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 )
-                {
-                  ncvars[ncvarid].climatology = TRUE;
-                  ncvars[ncvarid].bounds = ncboundsid;
-                  cdfSetVar(ncvars, ncvars[ncvarid].bounds, FALSE);
-                  cdfSetVar(ncvars, ncvarid, 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 )
-                {
-                  ncvars[ncvarid].bounds = ncboundsid;
-                  cdfSetVar(ncvars, ncvars[ncvarid].bounds, FALSE);
-                  cdfSetVar(ncvars, ncvarid, FALSE);
-                }
-              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 )
-            {
-              ncvars[ncvarid].lformula = TRUE;
-            }
-          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;
-
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              pstring = attstring;
-
-              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;
-
-              cdf_inq_varid(ncid, xvarname, &ncvars[ncvarid].xvarid);
-              cdf_inq_varid(ncid, yvarname, &ncvars[ncvarid].yvarid);
-
-              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;
-
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              char *pstring = attstring;
-
-              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;
-
-                  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 ( k == nchecked_vars )
-                        {
-                          if ( nchecked_vars < max_check_vars ) checked_vars[nchecked_vars++] = strdup(varname);
-                          Warning("%s - %s", nc_strerror(status), varname);
-                        }
-                    }
-
-                  if ( lstop ) break;
-                }
-
-              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;
-
-              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;
-
-                  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);
-
-                  if ( lstop ) break;
-                }
-
-              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);
-
-              cdfSetVar(ncvars, ncvarid, TRUE);
-            }
-          else if ( strcmp(attname, "positive") == 0 && xtypeIsText(atttype) )
-            {
-              cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-              strtolower(attstring);
-
-              if    ( memcmp(attstring, "down", 4) == 0 ) ncvars[ncvarid].positive = POSITIVE_DOWN;
-              else if ( memcmp(attstring, "up", 2) == 0 ) ncvars[ncvarid].positive = POSITIVE_UP;
-
-              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 ( 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);
-
-              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 ( 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);
-
-	      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;
-			}
-		    }
-
-		  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 ) );
-
-	      cdfGetAttInt(ncid, ncvarid, attname, 1, &temp);
-
-	      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));
-
-	      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) )
-		{
-		  cdfGetAttDouble(ncid, ncvarid, attname, 1, &attrflt);
-		  printf("flt: %s.%s = %g\n", ncvars[ncvarid].name, attname, attrflt);
-		}
-	      else if ( attrtype == NC_CHAR )
-		{
-		  cdfGetAttText(ncid, ncvarid, attname, attstringlen, attstring);
-		  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 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);
-	    }
-
-	  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");
-	    }
-
-	  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; */
-	    }
-
-          if ( lxdim == FALSE && ncvars[ncvarid].xvarid != UNDEFID )
-            {
-              if (  ncvars[ncvars[ncvarid].xvarid].ndims == 0 ) lxdim = TRUE;
-            }
-
-          if ( lydim == FALSE && ncvars[ncvarid].yvarid != UNDEFID )
-            {
-              if (  ncvars[ncvars[ncvarid].yvarid].ndims == 0 ) lydim = TRUE;
-            }
-
-          //   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;
-                      }
-                  }
-              }
-	}
-    }
-}
-
-/* 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;
-
-  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;
-		}
-	    }
-
-	  if ( ncvars[ncvarid].zaxistype != UNDEFID )
-	    {
-              ncvars[ncvarid].islev = TRUE;
-	      cdfSetVar(ncvars, ncvarid, FALSE);
-	      cdfSetDim(ncvars, ncvarid, 0, Z_AXIS);
-	      ncdims[ncdimid].dimtype = Z_AXIS;
-	    }
-	}
-    }
-}
-
-/* verify coordinate vars - second scan (all other variables) */
-static
-void verify_coordinate_vars_2(int nvars, ncvar_t *ncvars)
-{
-  int ncvarid;
-
-  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
-    {
-      if ( ncvars[ncvarid].isvar == 0 )
-	{
-	  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 )
-	    {
-	      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 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;
-
-  cdf_inq_varnatts(ncfileID, ncvarID, &nvatts);
-
-  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);
-    }
-
-}
-#endif
-
-static
-void grid_set_chunktype(grid_t *grid, ncvar_t *ncvar)
-{
-  if ( ncvar->chunked )
-    {
-      int ndims = ncvar->ndims;
-
-      if ( grid->type == GRID_UNSTRUCTURED )
-        {
-          if ( ncvar->chunks[ndims-1] == grid->size )
-            ncvar->chunktype = CHUNK_GRID;
-          else
-            ncvar->chunktype = CHUNK_AUTO;
-        }
-      else
-        {
-          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;
-        }
-    }
-}
-
-static struct gridVirtTable cdfLazyGridVtable;
-static double *cdfPendingLoad;
-#ifdef HAVE_LIBPTHREAD
-static pthread_once_t cdfLazyInitialized = PTHREAD_ONCE_INIT;
-#else
-static bool cdfLazyInitialized;
-#endif
-
-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
-};
-
-#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
-
-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);
-}
-
-static void cdfLazyGridDelete(grid_t *grid)
-{
-  struct cdfLazyGrid *cdfGrid = (struct cdfLazyGrid *)grid;
-  void (*baseDestroy)(grid_t *grid) = cdfGrid->baseVtable->destroy;
-  cdfLazyGridDestroy(cdfGrid);
-  baseDestroy(grid);
-}
-
-static void cdfLazyGridDestroyOnce(void)
-{
-  /*
-#ifdef HAVE_MMAP
-  size_t pgSize = cdiGetPageSize(false);
-  munmap(cdfPendingLoad, pgSize);
-#endif
-  */
-}
-
-static void
-cdfLazyGridDefArea(grid_t *grid, const double *area)
-{
-  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);
-}
-
-
-static const double *
-cdfLazyGridInqAreaPtr(grid_t *grid)
-{
-  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
-  lock_lazy_load(lazyGrid);
-  if (grid->area == cdfPendingLoad)
-    {
-      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);
-}
-
-static void
-cdfLazyGridInqArea(grid_t *grid, double *area)
-{
-  grid->vtable->inqAreaPtr(grid);
-  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
-  lazyGrid->baseVtable->inqArea(grid, area);
-}
-
-
-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);
-  scale_add(valsGet->size, grid_vals, valsGet->addoffset, valsGet->scalefactor);
-}
-
-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);
-}
-
-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))
-{
-  size_t size = valsGet->size;
-  double v;
-  if ( vals == cdfPendingLoad )
-    {
-      /* prevent full load if only first/last values get inspected */
-      if ( index == 0 || index == size - 1 )
-        {
-          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);
-        }
-      else
-        {
-          const double *grid_vals = inqValsPtr(grid);
-          v = grid_vals[index];
-        }
-    }
-  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);
-}
-
-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);
-}
-
-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)
-{
-  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;
-}
-
-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;
-}
-
-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;
-}
-
-
-static const double *
-cdfLazyGridInqXBoundsPtr(grid_t *grid)
-{
-  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
-  lock_lazy_load(lazyGrid);
-  if (grid->xbounds == cdfPendingLoad)
-    {
-      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);
-    }
-  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);
-}
-
-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);
-}
-
-static const double *
-cdfLazyGridInqYBoundsPtr(grid_t *grid)
-{
-  struct cdfLazyGrid *lazyGrid = (struct cdfLazyGrid *)grid;
-  lock_lazy_load(lazyGrid);
-  if (grid->ybounds == cdfPendingLoad)
-    {
-      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);
-    }
-  unlock_lazy_load(lazyGrid);
-  return lazyGrid->baseVtable->inqYBoundsPtr(grid);
-}
-
-static void
-cdfLazyGridCopyScalarFields(grid_t *gridptrOrig, grid_t *gridptrDup)
-{
-  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);
-}
-
-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 ( gridptrOrig->xvals != NULL && gridptrOrig->xvals != cdfPendingLoad )
-    {
-      size_t size  = irregular ? gridsize : (size_t)gridptrOrig->xsize;
-
-      gridptrDup->xvals = (double *)Malloc(size * sizeof (double));
-      memcpy(gridptrDup->xvals, gridptrOrig->xvals, size * sizeof (double));
-    }
-
-  if ( gridptrOrig->yvals != NULL && gridptrOrig->yvals != cdfPendingLoad )
-    {
-      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 ( gridptrOrig->xbounds != NULL && gridptrOrig->xbounds != cdfPendingLoad )
-    {
-      size_t size  = (irregular ? gridsize : (size_t)gridptrOrig->xsize)
-        * (size_t)gridptrOrig->nvertex;
-
-      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;
-
-      gridptrDup->ybounds = (double *)Malloc(size * sizeof (double));
-      memcpy(gridptrDup->ybounds, gridptrOrig->ybounds, size * sizeof (double));
-    }
-
-  {
-    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));
-      }
-  }
-
-  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));
-    }
-
-  if ( gridptrOrig->mask_gme != NULL )
-    {
-      size_t size = gridsize;
-
-      gridptrDup->mask_gme = (mask_t *)Malloc(size * sizeof (mask_t));
-      memcpy(gridptrDup->mask_gme, gridptrOrig->mask_gme, size * sizeof(mask_t));
-    }
-}
-
-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;
-}
-
-static void
-cdfLazyGridInitOnce(void)
-{
-  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
-}
-
-static void
-cdfBaseGridInit(grid_t *grid, int gridtype)
-{
-  grid_init(grid);
-  cdiGridTypeInit(grid, gridtype, 0);
-}
-
-static void
-cdfLazyGridInit(struct cdfLazyGrid *grid, int gridtype)
-{
-#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);
-}
-
-static void
-cdfLazyGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype)
-{
-  struct cdfLazyGrid *restrict grid = *gridpptr;
-  if (!grid)
-    *gridpptr = grid = (struct cdfLazyGrid *)Malloc(sizeof (*grid));
-  cdfLazyGridInit(grid, gridtype);
-}
-
-static void
-cdfBaseGridRenew(struct cdfLazyGrid *restrict *restrict gridpptr, int gridtype)
-{
-  struct cdfLazyGrid *restrict grid = *gridpptr;
-  if (!grid)
-    *gridpptr = grid = (struct cdfLazyGrid *)Malloc(sizeof (grid_t));
-  cdfBaseGridInit((grid_t*)grid, gridtype);
-}
-
-
-/* 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)
-{
-  int ltwarn = TRUE;
-  struct cdfLazyGrid *restrict lazyGrid = NULL, *restrict lazyProj = NULL;
-#define grid (&lazyGrid->base)
-#define proj (&lazyProj->base)
-
-  for ( int ncvarid = 0; ncvarid < nvars; ++ncvarid )
-    {
-      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 };
-
-	  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++;
-		}
-	    }
-
-	  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];
-	    }
-
-	  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 ( 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;
-	  */
-
-	  if ( xdimid != UNDEFID ) xsize = ncdims[xdimid].len;
-	  if ( ydimid != UNDEFID ) ysize = ncdims[ydimid].len;
-
-	  if ( ydimid == UNDEFID && yvarid != UNDEFID )
-	    {
-	      if ( ncvars[yvarid].ndims == 1 )
-		{
-		  ydimid = ncvars[yvarid].dimids[0];
-		  ysize  = ncdims[ydimid].len;
-		}
-	    }
-
-	  if ( ncvars[ncvarid].gridtype == UNDEFID || ncvars[ncvarid].gridtype == GRID_GENERIC )
-	    if ( xdimid != UNDEFID && xdimid == ydimid && nydims == 0 ) ncvars[ncvarid].gridtype = GRID_UNSTRUCTURED;
-
-          if (CDI_netcdf_lazy_grid_load)
-            {
-              cdfLazyGridRenew(&lazyGrid, ncvars[ncvarid].gridtype);
-              cdfLazyGridRenew(&lazyProj, GRID_PROJECTION);
-            }
-          else
-            {
-              cdfBaseGridRenew(&lazyGrid, ncvars[ncvarid].gridtype);
-              cdfBaseGridRenew(&lazyProj, GRID_PROJECTION);
-            }
-
-	  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 ( 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;
-		    }
-
-		  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;
-			}
-		    }
-		}
-
-              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;
-                    }
-                }
-
-              if ( yvarid != UNDEFID )
-                {
-                  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;
-                    }
-                }
-
-              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 ( skipvar )
-                    {
-                      Warning("Unsupported array structure, skipped variable %s!", ncvars[ncvarid].name);
-                      ncvars[ncvarid].isvar = -1;
-                      continue;
-                    }
-
-		  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 ( 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 ( skipvar )
-                    {
-                      Warning("Unsupported array structure, skipped variable %s!", ncvars[ncvarid].name);
-                      ncvars[ncvarid].isvar = -1;
-                      continue;
-                    }
-
-		  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);
-		}
-
-	      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;
-	    }
-
-	  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;
-	    }
-
-	  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 ( 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);
-                      }
-                  }
-
-		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 ( grid->type != ncvars[ncvarid].gridtype )
-            {
-              int gridtype = ncvars[ncvarid].gridtype;
-              grid->type = gridtype;
-              cdiGridTypeInit(grid, gridtype, grid->size);
-            }
-
-	  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;
-		}
-	    }
-
-	  if ( number_of_grid_used != UNDEFID && (grid->type == UNDEFID || grid->type == GRID_GENERIC) )
-            grid->type   = GRID_UNSTRUCTURED;
-
-	  if ( number_of_grid_used != UNDEFID && grid->type == GRID_UNSTRUCTURED )
-            grid->number = number_of_grid_used;
-
-	  if ( ncvars[ncvarid].gmapid >= 0 && ncvars[ncvarid].gridtype != GRID_CURVILINEAR )
-	    {
-              int nvatts;
-	      cdf_inq_varnatts(ncvars[ncvarid].ncid, ncvars[ncvarid].gmapid, &nvatts);
-
-	      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);
-
-		  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);
-		    }
-		}
-	    }
-
-          if ( grid->type == GRID_UNSTRUCTURED )
-            {
-              int zdimid = UNDEFID;
-              int xdimidx = -1, ydimidx = -1;
-
-              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 ( 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;
-                    }
-                }
-
-              if ( grid->size != grid->xsize )
-                {
-                  Warning("Unsupported array structure, skipped variable %s!", ncvars[ncvarid].name);
-                  ncvars[ncvarid].isvar = -1;
-                  continue;
-                }
-
-              if ( ncvars[ncvarid].position > 0 ) grid->position = ncvars[ncvarid].position;
-              if ( uuidOfHGrid[0] != 0 ) memcpy(grid->uuid, uuidOfHGrid, 16);
-            }
-
-#if defined (PROJECTION_TEST)
-	  if ( proj->type == GRID_PROJECTION )
-	    {
-	      if ( grid->type == GRID_GENERIC )
-		{
-		  grid->type = GRID_CURVILINEAR;
-		}
-
-	      if ( grid->type == GRID_CURVILINEAR )
-		{
-                  proj->size  = grid->size;
-                  proj->xsize = grid->xsize;
-                  proj->ysize = grid->ysize;
-		}
-
-	      //  grid->proj = gridGenerate(proj);
-	    }
-#endif
-
-	  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 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;
-            }
-
-          if ( grid->type == GRID_UNSTRUCTURED )
-            {
-              if ( gridfile[0] != 0 ) gridDefReference(ncvars[ncvarid].gridID, gridfile);
-            }
-
-          if ( ncvars[ncvarid].chunked ) grid_set_chunktype(grid, &ncvars[ncvarid]);
-
-	  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);
-
-          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);
-
-	  if ( CDI_Debug )
-	    Message("gridID %d %d %s", ncvars[ncvarid].gridID, ncvarid, ncvars[ncvarid].name);
-
-	  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;
-
-		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]; }
-		  }
-
-                if ( ncvars[ncvarid2].gridtype == UNDEFID && grid->type == GRID_UNSTRUCTURED )
-                  {
-                    if ( xdimid == xdimid2 && ydimid2 != UNDEFID && zdimid2 == UNDEFID )
-                      {
-                        ncvars[ncvarid2].dimtype[ydimidx] = Z_AXIS;
-                        ydimid2 = UNDEFID;
-                      }
-
-                    if ( xdimid == ydimid2 && xdimid2 != UNDEFID && zdimid2 == UNDEFID )
-                      {
-                        ncvars[ncvarid2].dimtype[xdimidx] = Z_AXIS;
-                        xdimid2 = ydimid2;
-                        ydimid2 = UNDEFID;
-                      }
-                  }
-
-                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;
-		      }
-		  }
-	      }
-
-          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 (lazyProj)
-    {
-      if (CDI_netcdf_lazy_grid_load) cdfLazyGridDestroy(lazyProj);
-      grid_free(proj);
-      Free(proj);
-    }
-#undef proj
-#undef grid
-}
-
-/* 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;
-
-          int positive = 0;
-	  int ndims = ncvars[ncvarid].ndims;
-
-          if ( ncvars[ncvarid].zvarid != -1 && ncvars[ncvars[ncvarid].zvarid].ndims == 0 )
-            {
-              zvarid = ncvars[ncvarid].zvarid;
-              is_scalar = TRUE;
-            }
-          else
-            {
-              for ( i = 0; i < ndims; i++ )
-                {
-                  if ( ncvars[ncvarid].dimtype[i] == Z_AXIS )
-                    zdimid = ncvars[ncvarid].dimids[i];
-                }
-
-              if ( zdimid != UNDEFID )
-                {
-                  zvarid = ncdims[zdimid].ncvarid;
-                  zsize  = (int)ncdims[zdimid].len;
-                }
-            }
-
-	  if ( CDI_Debug ) Message("nlevs = %d", zsize);
-
-	  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;
-
-	  int zprec = DATATYPE_FLT64;
-
-	  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;
-
-                  if ( ncvars[zvarid].psvarid != -1 ) psvarid = ncvars[zvarid].psvarid;
-                }
-
-	      cdf_get_var_double(ncvars[zvarid].ncid, zvarid, zvar);
-
-	      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;
-
-	      if ( zsize == 1 )
-		{
-                  if ( ncvars[ncvarid].zaxistype != UNDEFID )
-                    zaxisType = ncvars[ncvarid].zaxistype;
-                  else
-                    zaxisType = ZAXIS_SURFACE;
-
-		  zvar[0] = 0;
-		  /*
-		  if ( zdimid == UNDEFID )
-		    zvar[0] = 9999;
-		  else
-		    zvar[0] = 0;
-		  */
-		}
-	      else
-		{
-		  for ( ilev = 0; ilev < zsize; ilev++ ) zvar[ilev] = ilev + 1;
-		}
-	    }
-
-      	  ncvars[ncvarid].zaxisID = varDefZaxis(vlistID, zaxisType, (int) zsize, zvar, with_bounds, lbounds, ubounds,
-						(int)vctsize, vct, pname, plongname, punits, zprec, 1, 0);
-
-	  if ( uuidOfVGrid[0] != 0 )
-            {
-              // printf("uuidOfVGrid: defined\n");
-              zaxisDefUUID(ncvars[ncvarid].zaxisID, uuidOfVGrid);
-            }
-
-          if ( zaxisType == ZAXIS_HYBRID && psvarid != -1 ) zaxisDefPsName(ncvars[ncvarid].zaxisID, ncvars[psvarid].name);
-
-          if ( positive > 0 ) zaxisDefPositive(ncvars[ncvarid].zaxisID, positive);
-          if ( is_scalar ) zaxisDefScalar(ncvars[ncvarid].zaxisID);
-
-          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);
-
-	  zaxisindex = vlistZaxisIndex(vlistID, ncvars[ncvarid].zaxisID);
-	  streamptr->zaxisID[zaxisindex]  = zdimid;
-
-	  if ( CDI_Debug )
-	    Message("zaxisID %d %d %s", ncvars[ncvarid].zaxisID, ncvarid, ncvars[ncvarid].name);
-
-	  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;
-
-		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];
-		  }
-
-		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;
-                      }
-                  }
-	      }
-	}
-    }
-}
-
-struct varinfo
-{
-  int      ncvarid;
-  const char *name;
-};
-
-static
-int cmpvarname(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));
-}
-
-/* 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 )
-    {
-      struct varinfo *varInfo
-        = (struct varinfo *) Malloc((size_t)nvars * sizeof (struct varinfo));
-
-      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 )
-        {
-          for(int i = 0; i < nvars; i++) Message("sorted varids[%d] = %d", i, varids[i]);
-        }
-    }
-
-  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;
-
-      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 ( ncvars[ncvarid].lvalidrange )
-        vlistDefVarValidrange(vlistID, varID, ncvars[ncvarid].validrange);
-
-      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);
-
-      vlistDefVarDatatype(vlistID, varID, cdfInqDatatype(ncvars[ncvarid].xtype, ncvars[ncvarid].lunsigned));
-
-      vlistDefVarInstitut(vlistID, varID, instID);
-      vlistDefVarModel(vlistID, varID, modelID);
-      if ( ncvars[ncvarid].tableID != UNDEFID )
-	vlistDefVarTable(vlistID, varID, ncvars[ncvarid].tableID);
-
-      if ( ncvars[ncvarid].deffillval == FALSE && ncvars[ncvarid].defmissval == TRUE )
-        {
-          ncvars[ncvarid].deffillval = TRUE;
-          ncvars[ncvarid].fillval    = ncvars[ncvarid].missval;
-        }
-
-      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];
-
-      int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
-      int zdimid = streamptr->zaxisID[zaxisindex];
-
-      int ndims = ncvars[ncvarid].ndims;
-      int iodim = 0;
-      int ixyz = 0;
-      int ipow10[4] = {1, 10, 100, 1000};
-
-      if ( ncvars[ncvarid].tsteptype != TSTEP_CONSTANT ) iodim++;
-
-      if ( gridInqType(gridID) == GRID_UNSTRUCTURED && ndims-iodim <= 2 && ydimid == xdimid )
-        {
-          if ( xdimid == ncvars[ncvarid].dimids[ndims-1] )
-            {
-              ixyz = 321;
-            }
-          else
-            {
-              ixyz = 213;
-            }
-        }
-      else
-        {
-          for ( int idim = iodim; idim < ndims; idim++ )
-            {
-              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];
-            }
-        }
-
-      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;
-        }
-
-      if ( ncvars[ncvarid].extra[0] != 0 )
-        {
-          vlistDefVarExtra(vlistID, varID, ncvars[ncvarid].extra);
-        }
-    }
-
-  for ( int varID = 0; varID < nvars; varID++ )
-    {
-      int ncvarid = varids[varID];
-      int ncid = ncvars[ncvarid].ncid;
-
-      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);
-
-	      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 (ncvars[ncvarid].vct) Free(ncvars[ncvarid].vct);
-	  if (ncvars[ncvarid].atts) Free(ncvars[ncvarid].atts);
-          ncvars[ncvarid].vct = NULL;
-          ncvars[ncvarid].atts = NULL;
-	}
-    }
-
-  /* release mem of not freed attributes */
-  for ( int ncvarid = 0; ncvarid < num_ncvars; ncvarid++ )
-    if ( ncvars[ncvarid].atts ) Free(ncvars[ncvarid].atts);
-
-  if ( varids ) Free(varids);
-
-  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);
-		}
-	    }
-	}
-    }
-
-  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);
-
-	      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;
-		}
-	    }
-
-	  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);
-    }
-}
-
-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)
-{
-  nc_type xtype;
-  size_t attlen;
-  char attname[CDI_MAX_NAME];
-  enum { attstringlen = 65636 };
-  char attstring[attstringlen];
-  int iatt;
-
-  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);
-
-      if ( xtypeIsText(xtype) )
-	{
-	  cdfGetAttText(fileID, NC_GLOBAL, attname, attstringlen, attstring);
-
-          size_t attstrlen = strlen(attstring);
-
-	  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);
-                    }
-
-		  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);
-            }
-        }
-      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;
-
-  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
-    {
-      if ( ncvars[ncvarid].stdname[0] )
-        {
-          if ( strcmp(ncvars[ncvarid].stdname, "forecast_period") == 0 )
-            {
-              leadtime_id = ncvarid;
-              break;
-            }
-        }
-    }
-
-  return (leadtime_id);
-}
-
-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)
-{
-  int ncvarid;
-
-  if ( timedimid == UNDEFID )
-    {
-      char timeunits[CDI_MAX_NAME];
-
-      for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
-        {
-          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;
-                    }
-                }
-            }
-        }
-    }
-  else
-    {
-      int ltimevar = FALSE;
-
-      if ( ncdims[timedimid].ncvarid != UNDEFID )
-        {
-          streamptr->basetime.ncvarid = ncdims[timedimid].ncvarid;
-          ltimevar = TRUE;
-        }
-
-      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;
-
-            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 == UNDEFID )
-        {
-          Warning("Time variable >%s< not found!", ncdims[timedimid].name);
-        }
-    }
-
-  /* time varID */
-  ncvarid = streamptr->basetime.ncvarid;
-
-  if ( ncvarid != UNDEFID && streamptr->basetime.lwrf == FALSE )
-    {
-      if ( ncvars[ncvarid].units[0] != 0 ) *time_has_units = TRUE;
-
-      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;
-                }
-            }
-        }
-    }
-}
-
-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;
-
-  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' )
-            {
-              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
-                }
-            }
-	}
-    }
-
-  /* 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;
-    }
-}
-
-
-int cdfInqContents(stream_t *streamptr)
-{
-  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;
-
-  int vlistID = streamptr->vlistID;
-  int fileID  = streamptr->fileID;
-
-  if ( CDI_Debug ) Message("streamID = %d, fileID = %d", streamptr->self, fileID);
-
-#if  defined  (HAVE_NETCDF4)
-  nc_inq_format(fileID, &format);
-#endif
-
-  cdf_inq(fileID, &ndims , &nvars, &ngatts, &unlimdimid);
-
-  if ( CDI_Debug )
-    Message("root: ndims %d, nvars %d, ngatts %d", ndims, nvars, ngatts);
-
-  if ( ndims == 0 )
-    {
-      Warning("ndims = %d", ndims);
-      return (CDI_EUFSTRUCT);
-    }
-
-  /* alloc ncdims */
-  ncdims = (ncdim_t *) Malloc((size_t)ndims * sizeof (ncdim_t));
-  init_ncdims(ndims, ncdims);
-
-  if ( nvars > 0 )
-    {
-      /* alloc ncvars */
-      ncvars = (ncvar_t *) Malloc((size_t)nvars * sizeof (ncvar_t));
-      init_ncvars(nvars, ncvars);
-
-      for ( ncvarid = 0; ncvarid < nvars; ++ncvarid )
-        ncvars[ncvarid].ncid = fileID;
-    }
-
-#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 )
-            {
-            }
-        }
-    }
-#endif
-#endif
-
-  if ( nvars == 0 )
-    {
-      Warning("nvars = %d", nvars);
-      return (CDI_EUFSTRUCT);
-    }
-
-  /* scan global attributes */
-  scan_global_attributes(fileID, vlistID, streamptr, ngatts, &instID, &modelID, &ucla_les,
-                         uuidOfHGrid, uuidOfVGrid, gridfile, &number_of_grid_used);
-
-  /* find time dim */
-  if ( unlimdimid >= 0 )
-    timedimid = unlimdimid;
-  else
-    timedimid = cdfTimeDimID(fileID, ndims, nvars);
-
-  streamptr->basetime.ncdimid = timedimid;
-
-  if ( timedimid != UNDEFID )
-    cdf_inq_dimlen(fileID, timedimid, &ntsteps);
-  else
-    ntsteps = 0;
-
-  if ( CDI_Debug ) Message("Number of timesteps = %d", 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 ) printNCvars(ncvars, nvars, "cdfScanVarAttributes");
-
-  /* scan attributes of all variables */
-  cdfScanVarAttributes(nvars, ncvars, ncdims, timedimid, modelID, format);
-
-
-  if ( CDI_Debug ) printNCvars(ncvars, nvars, "find coordinate vars");
-
-  /* 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);
-
-	      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;
-		  }
-	    }
-	}
-    }
-
-  /* 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;
-
-  /* check ncvars */
-  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
-    {
-      if ( timedimid != UNDEFID )
-	if ( ncvars[ncvarid].isvar == -1 &&
-	     ncvars[ncvarid].ndims > 1   &&
-	     timedimid == ncvars[ncvarid].dimids[0] )
-	  cdfSetVar(ncvars, ncvarid, TRUE);
-
-      if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims == 0 )
-	cdfSetVar(ncvars, ncvarid, FALSE);
-
-      //if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims > 1 )
-      if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims >= 1 )
-	cdfSetVar(ncvars, ncvarid, TRUE);
-
-      if ( ncvars[ncvarid].isvar == -1 )
-	{
-	  ncvars[ncvarid].isvar = 0;
-	  Warning("Variable %s has an unknown type, skipped!", ncvars[ncvarid].name);
-	  continue;
-	}
-
-      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 ( 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;
-	}
-
-      if ( xtypeIsText(ncvars[ncvarid].xtype) )
-	{
-	  ncvars[ncvarid].isvar = 0;
-	  continue;
-	}
-
-      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;
-	}
-
-      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;
-	    }
-	}
-    }
-
-  /* verify coordinate vars - first scan (dimname == varname) */
-  verify_coordinate_vars_1(fileID, ndims, ncdims, ncvars, timedimid);
-
-  /* verify coordinate vars - second scan (all other variables) */
-  verify_coordinate_vars_2(nvars, ncvars);
-
-  if ( CDI_Debug ) printNCvars(ncvars, nvars, "verify_coordinate_vars");
-
-  if ( ucla_les == TRUE )
-    {
-      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;
-		}
-	    }
-	}
-    }
-  /*
-  for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
-    {
-      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);
-
-	  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);
-	}
-    }
-  */
-
-  /* Set coordinate varids (att: associate)  */
-  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
-    {
-      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];
-	    }
-	}
-    }
-
-  /* set dim type */
-  setDimType(nvars, ncvars, ncdims);
-
-  /* read ECHAM VCT if present */
-  size_t vctsize = 0;
-  double *vct = NULL;
-  read_vct_echam(fileID, nvars, ncvars, ncdims, &vct, &vctsize);
-
-
-  if ( CDI_Debug ) printNCvars(ncvars, nvars, "define_all_grids");
-
-  /* define all grids */
-  define_all_grids(streamptr, vlistID, ncdims, nvars, ncvars, timedimid, uuidOfHGrid, gridfile, number_of_grid_used);
-
-
-  /* define all zaxes */
-  define_all_zaxes(streamptr, vlistID, ncdims, nvars, ncvars, vctsize, vct, uuidOfVGrid);
-  if ( vct ) Free(vct);
-
-
-  /* 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 = %d", ntsteps);
-  if ( CDI_Debug ) Message("nvars_data = %d", nvars_data);
-
-
-  if ( nvars_data == 0 )
-    {
-      streamptr->ntsteps = 0;
-      return (CDI_EUFSTRUCT);
-    }
-
-  if ( ntsteps == 0 && streamptr->basetime.ncdimid == UNDEFID && streamptr->basetime.ncvarid != UNDEFID )
-    ntsteps = 1;
-
-  streamptr->ntsteps = (long)ntsteps;
-
-  /* define all data variables */
-  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 )
-    {
-      taxis_t *taxis = &streamptr->tsteps[0].taxis;
-
-      if ( setBaseTime(ncvars[nctimevarid].units, taxis) == 1 )
-        {
-          nctimevarid = UNDEFID;
-          streamptr->basetime.ncvarid = UNDEFID;
-        }
-
-      if ( leadtime_id != UNDEFID && taxis->type == TAXIS_RELATIVE )
-        {
-          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);
-        }
-    }
-
-  if ( time_has_bounds )
-    {
-      streamptr->tsteps[0].taxis.has_bounds = TRUE;
-      if ( time_climatology ) streamptr->tsteps[0].taxis.climatology = TRUE;
-    }
-
-  if ( nctimevarid != UNDEFID )
-    {
-      taxis_t *taxis = &streamptr->tsteps[0].taxis;
-      ptaxisDefName(taxis, ncvars[nctimevarid].name);
-      if ( ncvars[nctimevarid].longname[0] )
-        ptaxisDefLongname(taxis, ncvars[nctimevarid].longname);
-    }
-
-  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 )
-    {
-      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 == 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 != 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
-
-  vlistDefTaxis(vlistID, taxisID);
-
-  streamptr->curTsID = 0;
-  streamptr->rtsteps = 1;
-
-  (void) cdfInqTimestep(streamptr, 0);
-
-  cdfCreateRecords(streamptr, 0);
-
-  /* free ncdims */
-  Free(ncdims);
-
-  /* free ncvars */
-  Free(ncvars);
-
-  return (0);
-}
-
-static
-void wrf_read_timestep(int fileID, int nctimevarid, int tsID, 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;
-  }
-}
-
-static
-double get_timevalue(int fileID, int nctimevarid, int tsID, timecache_t *tcache)
-{
-  double timevalue = 0;
-  size_t index = (size_t) tsID;
-
-  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++;
-            }
-        }
-
-      timevalue = tcache->cache[tsID%MAX_TIMECACHE_SIZE];
-    }
-  else
-    {
-      cdf_get_var1_double(fileID, nctimevarid, &index, &timevalue);
-      if ( timevalue >= NC_FILL_DOUBLE || timevalue < -NC_FILL_DOUBLE ) timevalue = 0;
-    }
-
-  return timevalue;
-}
-
-
-int cdfInqTimestep(stream_t * streamptr, int tsID)
-{
-  long nrecs = 0;
-  double timevalue;
-  int fileID;
-  taxis_t *taxis;
-
-  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 )
-    {
-      cdfCreateRecords(streamptr, tsID);
-
-      taxis = &streamptr->tsteps[tsID].taxis;
-      if ( tsID > 0 )
-	ptaxisCopy(taxis, &streamptr->tsteps[0].taxis);
-
-      timevalue = tsID;
-
-      int nctimevarid = streamptr->basetime.ncvarid;
-      if ( nctimevarid != UNDEFID )
-	{
-	  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 != 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 != UNDEFID )
-            {
-              timevalue = get_timevalue(fileID, leadtimeid, tsID, NULL);
-              cdiSetForecastPeriod(timevalue, taxis);
-            }
-	}
-    }
-
-  streamptr->curTsID = tsID;
-  nrecs = streamptr->tsteps[tsID].nrecs;
-
-  return ((int) nrecs);
-}
-
-
-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);
-}
-
-
-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);
-
-  return ((int) size);
-}
-
-
-void cdfInqHistoryString(stream_t *streamptr, char *history)
-{
-  int ncid = streamptr->fileID;
-  if ( streamptr->historyID != UNDEFID )
-    {
-      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
-    }
-}
-
-
-void cdfDefVars(stream_t *streamptr)
-{
-  int vlistID = streamptr->vlistID;
-  if ( vlistID == UNDEFID )
-    Error("Internal problem! vlist undefined for streamptr %p", streamptr);
-
-  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);
-      }
-
-  if ( nzaxis > 0 )
-    for ( int index = 0; index < nzaxis; index++ )
-      {
-        int zaxisID = vlistZaxis(vlistID, index);
-        if ( streamptr->zaxisID[index] == UNDEFID ) cdfDefZaxis(streamptr, zaxisID);
-      }
-
-  /* define time first!!!
-    int nvars  = vlistNvars(vlistID);
-  for ( int varID = 0; varID < nvars; varID++ )
-    {
-      int ncvarid = cdfDefVar(streamptr, 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:
- */
diff --git a/libcdi/src/stream_cdf.h b/libcdi/src/stream_cdf.h
index c0228b8..8056b6e 100644
--- a/libcdi/src/stream_cdf.h
+++ b/libcdi/src/stream_cdf.h
@@ -1,6 +1,8 @@
 #ifndef _STREAM_CDF_H
 #define _STREAM_CDF_H
 
+#include "cdi_int.h"
+
 void   cdfDefVars(stream_t *streamptr);
 void   cdfDefTimestep(stream_t *streamptr, int tsID);
 int    cdfInqTimestep(stream_t *streamptr, int tsID);
@@ -14,6 +16,8 @@ void   cdfDefRecord(stream_t * streamptr);
 
 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);
 
@@ -29,6 +33,10 @@ void   cdf_write_var_chunk(stream_t *streamptr, int varID, int memtype,
 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:
diff --git a/libcdi/src/stream_cdf_i.c b/libcdi/src/stream_cdf_i.c
new file mode 100644
index 0000000..8eb7510
--- /dev/null
+++ b/libcdi/src/stream_cdf_i.c
@@ -0,0 +1,4074 @@
+#if defined (HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#ifdef HAVE_LIBNETCDF
+
+//#define TEST_GROUPS 1
+
+#include <ctype.h>
+#include <limits.h>
+
+#include "dmemory.h"
+#include "gaussgrid.h"
+#include "cdi_int.h"
+#include "cdi_uuid.h"
+#include "stream_cdf.h"
+#include "cdf_int.h"
+#include "varscan.h"
+#include "vlist.h"
+#include "cdf_util.h"
+#include "cdf_lazy_grid.h"
+
+
+#define  X_AXIS  1
+#define  Y_AXIS  2
+#define  Z_AXIS  3
+#define  T_AXIS  4
+
+#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     islon;
+  bool     islat;
+  bool     islev;
+  bool     istime;
+  bool     warn;
+  bool     calendar;
+  bool     climatology;
+  bool     lformulaterms;
+  int      tsteptype;
+  int      param;
+  int      code;
+  int      tabnum;
+  int      bounds;
+  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      tableID;
+  int      truncation;
+  int      position;
+  bool     defmissval;
+  bool     deffillval;
+  int      xtype;
+  int      gmapid;
+  int      positive;
+  int      ndims;
+  int      dimids[8];
+  int      dimtype[8];
+  int      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 scanTimeString(const char *ptu, int *rdate, int *rtime)
+{
+  int year = 1, month = 1, day = 1;
+  int hour = 0, minute = 0, second = 0;
+  int v1 = 1, v2 = 1, v3 = 1;
+
+  *rdate = 0;
+  *rtime = 0;
+
+  if ( *ptu )
+    {
+      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++;
+            }
+        }
+    }
+
+  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 )
+    {
+      while ( ! isdigit((int) *ptu) ) ptu++;
+
+      hour = atoi(ptu);
+      while ( isdigit((int) *ptu) ) ptu++;
+      if ( *ptu == ':' )
+        {
+          ptu++;
+          minute = atoi(ptu);
+          while ( isdigit((int) *ptu) ) ptu++;
+          if ( *ptu == ':' )
+            {
+              ptu++;
+              second = atoi(ptu);
+            }
+        }
+    }
+
+  *rdate = cdiEncodeDate(year, month, day);
+  *rtime = cdiEncodeTime(hour, minute, second);
+}
+
+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;
+}
+
+static
+void setForecastTime(const char *timestr, taxis_t *taxis)
+{
+  (*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;
+}
+
+static
+int setBaseTime(const char *timeunits, taxis_t *taxis)
+{
+  int timetype = TAXIS_ABSOLUTE;
+  int rdate = -1, rtime = -1;
+
+  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 )
+    {
+      Message("Unsupported TIMEUNIT: %s!", timeunits);
+      return 1;
+    }
+
+  while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
+  if ( *ptu )
+    {
+      while ( isspace(*ptu) ) ptu++;
+
+      if ( str_is_equal(ptu, "as") )
+        timetype = TAXIS_ABSOLUTE;
+      else if ( str_is_equal(ptu, "since") )
+        timetype = TAXIS_RELATIVE;
+
+      while ( ! isspace(*ptu) && *ptu != 0 ) ptu++;
+      if ( *ptu )
+        {
+          while ( isspace(*ptu) ) ptu++;
+
+          if ( timetype == TAXIS_ABSOLUTE )
+            {
+              if ( !str_is_equal(ptu, "%y%m%d.%f") && timeunit == TUNIT_DAY )
+                {
+                  Message("Unsupported format %s for TIMEUNIT day!", ptu);
+                  timeunit = -1;
+                }
+              else if ( !str_is_equal(ptu, "%y%m.%f") && timeunit == TUNIT_MONTH )
+                {
+                  Message("Unsupported format %s for TIMEUNIT month!", ptu);
+                  timeunit = -1;
+                }
+            }
+          else if ( timetype == TAXIS_RELATIVE )
+            {
+              scanTimeString(ptu, &rdate, &rtime);
+
+              (*taxis).rdate = rdate;
+              (*taxis).rtime = rtime;
+
+              if ( CDI_Debug )
+                Message("rdate = %d  rtime = %d", rdate, rtime);
+            }
+        }
+    }
+
+  (*taxis).type = timetype;
+  (*taxis).unit = timeunit;
+
+  Free(tu);
+
+  if ( CDI_Debug )
+    Message("timetype = %d  unit = %d", timetype, timeunit);
+
+  return 0;
+}
+
+static
+void cdfGetAttInt(int fileID, int ncvarid, const char *attname, int attlen, int *attint)
+{
+  nc_type atttype;
+  size_t nc_attlen;
+
+  *attint = 0;
+
+  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
+  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
+
+  if ( atttype != NC_CHAR )
+    {
+      int *pintatt = (int)nc_attlen > attlen
+        ? (int *)(Malloc(nc_attlen * sizeof (int))) : attint;
+
+      cdf_get_att_int(fileID, ncvarid, attname, pintatt);
+
+      if ( (int)nc_attlen > attlen )
+        {
+          memcpy(attint, pintatt, (size_t)attlen * sizeof (int));
+          Free(pintatt);
+        }
+    }
+}
+
+static
+void cdfGetAttDouble(int fileID, int ncvarid, char *attname, int attlen, double *attdouble)
+{
+  nc_type atttype;
+  size_t nc_attlen;
+
+  *attdouble = 0;
+
+  cdf_inq_atttype(fileID, ncvarid, attname, &atttype);
+  cdf_inq_attlen(fileID, ncvarid, attname, &nc_attlen);
+
+  if ( atttype != NC_CHAR )
+    {
+      double *pdoubleatt = NULL;
+
+      if ( (int)nc_attlen > attlen )
+        pdoubleatt = (double *) Malloc(nc_attlen * sizeof (double));
+      else
+        pdoubleatt = attdouble;
+
+      cdf_get_att_double(fileID, ncvarid, attname, pdoubleatt);
+
+      if ( (int)nc_attlen > attlen )
+        {
+          memcpy(attdouble, pdoubleatt, (size_t)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 ( atttype == NC_CHAR )
+    {
+      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);
+
+          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);
+
+          size_t ssize = strlen(attbuf) + 1;
+
+          if ( ssize > attlen ) ssize = attlen;
+          memcpy(atttext, attbuf, ssize);
+          atttext[ssize - 1] = 0;
+          Free(attbuf);
+        }
+      else
+        {
+          atttext[0] = 0;
+        }
+    }
+#endif
+}
+
+static
+bool xtypeIsText(nc_type xtype)
+{
+  bool isText = false;
+
+  if      ( xtype == NC_CHAR ) isText = true;
+#if  defined  (HAVE_NETCDF4)
+  else if ( xtype == NC_STRING ) isText = true;
+#endif
+
+  return isText;
+}
+
+static
+bool xtypeIsFloat(nc_type xtype)
+{
+  bool isFloat = xtype == NC_FLOAT || xtype == NC_DOUBLE;
+
+  return isFloat;
+}
+
+static
+bool xtypeIsInt(nc_type xtype)
+{
+  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
+int cdfInqDatatype(int xtype, bool lunsigned)
+{
+  int datatype = -1;
+
+#if  defined  (HAVE_NETCDF4)
+  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;
+}
+
+
+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 )
+        {
+          if ( lscalefactor ) data[i] *= scalefactor;
+          if ( laddoffset )   data[i] += addoffset;
+        }
+    }
+}
+
+static
+void cdfCreateRecords(stream_t *streamptr, int tsID)
+{
+  if ( tsID < 0 || (tsID >= streamptr->ntsteps && tsID > 0) ) return;
+
+  if ( streamptr->tsteps[tsID].nallrecs > 0 ) return;
+
+  int vlistID  = streamptr->vlistID;
+
+  tsteps_t* sourceTstep = streamptr->tsteps;
+  tsteps_t* destTstep = sourceTstep + tsID;
+
+  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;
+
+      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++;
+            }
+        }
+    }
+  else if ( tsID == 1 )
+    {
+      int nvrecs = 0;
+      for ( int varID = 0; varID < nvars; varID++ )
+        {
+          if ( vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT )
+            {
+              int zaxisID = vlistInqVarZaxis(vlistID, varID);
+              nvrecs += zaxisInqSize(zaxisID);
+            }
+        }
+
+      streamptr->nrecs += nvrecs;
+
+      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
+      destTstep->nrecs      = nvrecs;
+      destTstep->nallrecs   = nrecs;
+      destTstep->recordSize = nrecs;
+      destTstep->curRecID   = CDI_UNDEFID;
+
+      memcpy(destTstep->records, sourceTstep->records, (size_t)nrecs*sizeof(record_t));
+
+      if ( nvrecs )
+        {
+          destTstep->recIDs = (int *) Malloc((size_t)nvrecs * sizeof (int));
+          for ( int recID = 0, vrecID = 0; recID < nrecs; recID++ )
+            {
+              int varID = destTstep->records[recID].varID;
+              if ( vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT )
+                {
+                  destTstep->recIDs[vrecID++] = recID;
+                }
+            }
+        }
+    }
+  else
+    {
+      if ( streamptr->tsteps[1].records == 0 ) cdfCreateRecords(streamptr, 1);
+
+      int nvrecs = streamptr->tsteps[1].nrecs;
+
+      streamptr->nrecs += nvrecs;
+
+      destTstep->records    = (record_t *) Malloc((size_t)nrecs*sizeof(record_t));
+      destTstep->nrecs      = nvrecs;
+      destTstep->nallrecs   = nrecs;
+      destTstep->recordSize = nrecs;
+      destTstep->curRecID   = CDI_UNDEFID;
+
+      memcpy(destTstep->records, sourceTstep->records, (size_t)nrecs*sizeof(record_t));
+
+      destTstep->recIDs     = (int *) Malloc((size_t)nvrecs * sizeof(int));
+
+      memcpy(destTstep->recIDs, streamptr->tsteps[1].recIDs, (size_t)nvrecs*sizeof(int));
+    }
+}
+
+static
+int cdf_time_dimid(int fileID, int ndims, int nvars)
+{
+  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;
+    }
+
+  for ( int varid = 0; varid < nvars; ++varid )
+    {
+      nc_type xtype;
+      int nvdims, nvatts, dimids[9];
+      cdf_inq_var(fileID, varid, NULL, &xtype, &nvdims, dimids, &nvatts);
+      if ( nvdims == 1 )
+        {
+          char sbuf[CDI_MAX_NAME];
+          for ( int iatt = 0; iatt < nvatts; ++iatt )
+            {
+              sbuf[0] = 0;
+              cdf_inq_attname(fileID, varid, iatt, sbuf);
+              if ( strncmp(sbuf, "units", 5) == 0 )
+                {
+                  cdfGetAttText(fileID, varid, "units", sizeof(sbuf), sbuf);
+                  str_tolower(sbuf);
+
+                  if ( is_time_units(sbuf) ) return dimids[0];
+                }
+            }
+        }
+    }
+
+  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 )
+    {
+      ncvars[ncvarid].ncid            = CDI_UNDEFID;
+      ncvars[ncvarid].isvar           = CDI_UNDEFID;
+      ncvars[ncvarid].ignore          = false;
+      ncvars[ncvarid].isx             = false;
+      ncvars[ncvarid].isy             = 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].tsteptype       = TSTEP_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 )
+        ncvars[ncvarid].coordvarids[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);
+    }
+}
+
+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);
+
+      ncvars[ncvarid].warn = true;
+      isvar = FALSE;
+    }
+
+  ncvars[ncvarid].isvar = isvar;
+}
+
+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);
+    }
+
+  ncvars[ncvarid].dimtype[dimid] = dimtype;
+}
+
+static
+void scan_hybrid_formulaterms(int ncid, int ncfvarid, int *avarid, int *bvarid, int *psvarid, int *p0varid)
+{
+  *avarid  = -1;
+  *bvarid  = -1;
+  *psvarid = -1;
+  *p0varid = -1;
+
+  char attstring[1024];
+  cdfGetAttText(ncid, ncfvarid, "formula_terms", sizeof(attstring), attstring);
+  char *pstring = attstring;
+
+  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;
+
+      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 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 ( strcmp(ncvar->stdname, "atmosphere_hybrid_sigma_pressure_coordinate") == 0 )
+    {
+      cdiConvention = CDI_CONVENTION_CF;
+
+      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 ( 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;
+
+              int ndims2 = ncvars[avarid2].ndims;
+              int dimid2 = ncvars[avarid2].dimids[0];
+              size_t dimlen2 = ncdims[dimid2].len;
+
+              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;
+                }
+            }
+        }
+    }
+
+  return status;
+}
+
+static
+void cdf_set_cdi_attr(int ncid, int ncvarid, int attnum, int cdiID, int varID)
+{
+  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, (int)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, (int)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++] = '?';
+        }
+
+      axis[ndim++] = 0;
+
+      fprintf(stderr, "%3d %3d  %-6s %s\n", ncvarid, ndim-3, axis, ncvars[ncvarid].name);
+    }
+}
+
+static
+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)
+{
+  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;
+        }
+    }
+
+  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");
+              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
+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") )
+    {
+      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 cdf_scan_var_attr(int nvars, ncvar_t *ncvars, ncdim_t *ncdims, int timedimid, int modelID, int format)
+{
+  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];
+
+  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;
+
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      int ncid    = ncvars[ncvarid].ncid;
+      int *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
+
+      if ( nvdims > 0 )
+        {
+          if ( timedimid == dimidsp[0] )
+            {
+              ncvars[ncvarid].tsteptype = TSTEP_INSTANT;
+              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;
+                    }
+                }
+            }
+        }
+
+      for ( iatt = 0; iatt < nvatts; iatt++ )
+        {
+          int nc_cell_id = CDI_UNDEFID;
+
+          cdf_inq_attname(ncid, ncvarid, iatt, attname);
+          cdf_inq_atttype(ncid, ncvarid, attname, &atttype);
+          cdf_inq_attlen(ncid, ncvarid, attname, &attlen);
+
+          size_t attstringsize = sizeof(attstring);
+          bool isText = xtypeIsText(atttype);
+          if ( isText )
+            {
+              cdfGetAttText(ncid, ncvarid, attname, sizeof(attstring), attstring);
+              attstringsize = strlen(attstring) + 1;
+              if ( attstringsize > CDI_MAX_NAME ) attstringsize = CDI_MAX_NAME;
+            }
+
+          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 ( !isText && strcmp(attname, "code") == 0 )
+            {
+              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].code);
+              cdf_set_var(ncvars, ncvarid, TRUE);
+            }
+          else if ( !isText && 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 ( !isText && strcmp(attname, "trunc_count") == 0 )
+            {
+              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].truncation);
+            }
+          else if ( !isText && strcmp(attname, "truncation") == 0 )
+            {
+              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].truncation);
+            }
+          else if ( !isText && strcmp(attname, "number_of_grid_in_reference") == 0 )
+            {
+              cdfGetAttInt(ncid, ncvarid, attname, 1, &ncvars[ncvarid].position);
+            }
+          else if ( !isText && 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 ( !isText && 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;
+
+              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;
+
+              cdf_inq_varid(ncid, xvarname, &ncvars[ncvarid].xvarid);
+              cdf_inq_varid(ncid, yvarname, &ncvars[ncvarid].yvarid);
+
+              cdf_set_var(ncvars, ncvars[ncvarid].xvarid, FALSE);
+              cdf_set_var(ncvars, ncvars[ncvarid].yvarid, FALSE);
+              cdf_set_var(ncvars, ncvarid, TRUE);
+            }
+          */
+          else if ( isText && (strcmp(attname, "associate")  == 0 || strcmp(attname, "coordinates") == 0) )
+            {
+              bool lstop = false;
+              char *pstring = attstring;
+
+              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;
+
+                  int dimvarid;
+                  int status = nc_inq_varid(ncid, varname, &dimvarid);
+                  if ( status == NC_NOERR )
+                    {
+                      cdf_set_var(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 ( k == nchecked_vars )
+                        {
+                          if ( nchecked_vars < max_check_vars ) checked_vars[nchecked_vars++] = strdup(varname);
+                          Warning("%s - %s", nc_strerror(status), varname);
+                        }
+                    }
+
+                  if ( lstop ) break;
+                }
+
+              cdf_set_var(ncvars, ncvarid, TRUE);
+            }
+          else if ( isText && strcmp(attname, "auxiliary_variable") == 0 )
+            {
+              bool lstop = false;
+              char *pstring = attstring;
+
+              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;
+
+                  int dimvarid;
+                  int status = nc_inq_varid(ncid, varname, &dimvarid);
+                  if ( status == NC_NOERR )
+                    {
+                      cdf_set_var(ncvars, dimvarid, FALSE);
+                      //  if ( cdiIgnoreAttCoordinates == FALSE )
+                        {
+                          ncvars[ncvarid].auxvarids[i] = dimvarid;
+                          ncvars[ncvarid].nauxvars++;
+                        }
+                    }
+                  else
+                    Warning("%s - %s", nc_strerror(status), varname);
+
+                  if ( lstop ) break;
+                }
+
+              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);
+
+              cdf_set_var(ncvars, ncvarid, TRUE);
+            }
+          else if ( isText && strcmp(attname, "positive") == 0 )
+            {
+              str_tolower(attstring);
+
+              if      ( str_is_equal(attstring, "down") ) ncvars[ncvarid].positive = POSITIVE_DOWN;
+              else if ( str_is_equal(attstring, "up")   ) ncvars[ncvarid].positive = POSITIVE_UP;
+
+              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 ( !isText && strcmp(attname, "_FillValue") == 0 )
+            {
+	      cdfGetAttDouble(ncid, ncvarid, attname, 1, &ncvars[ncvarid].fillval);
+	      ncvars[ncvarid].deffillval = true;
+	      /* cdf_set_var(ncvars, ncvarid, TRUE); */
+            }
+          else if ( !isText && 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 ( strcmp(attname, "valid_range") == 0 && attlen == 2 )
+            {
+              if ( ncvars[ncvarid].lvalidrange == false )
+                {
+                  extern int cdiIgnoreValidRange;
+                  bool 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;
+                      /* cdf_set_var(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;
+                  bool 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 ( ncvars[ncvarid].lvalidrange == false )
+                {
+                  extern int cdiIgnoreValidRange;
+                  bool 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 ( isText && strcmp(attname, "_Unsigned") == 0 )
+            {
+              str_tolower(attstring);
+
+              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);
+
+	      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);
+
+	      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 ( ( 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 ) );
+
+	      cdfGetAttInt(ncid, ncvarid, attname, 1, &temp);
+
+	      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_set_var(ncvars, ncvarid, TRUE);
+	    }
+	  else
+	    {
+	      if ( ncvars[ncvarid].natts == 0 )
+		ncvars[ncvarid].atts = (int*) Malloc((size_t)nvatts*sizeof(int));
+
+	      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_set_dimtype(int nvars, ncvar_t *ncvars, ncdim_t *ncdims)
+{
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      if ( ncvars[ncvarid].isvar == TRUE )
+	{
+	  int ndims = ncvars[ncvarid].ndims;
+	  for ( int i = 0; i < ndims; i++ )
+	    {
+	      int ncdimid = ncvars[ncvarid].dimids[i];
+	      if      ( ncdims[ncdimid].dimtype == X_AXIS ) cdf_set_dim(ncvars, ncvarid, i, X_AXIS);
+	      else if ( ncdims[ncdimid].dimtype == Y_AXIS ) cdf_set_dim(ncvars, ncvarid, i, Y_AXIS);
+	      else if ( ncdims[ncdimid].dimtype == Z_AXIS ) cdf_set_dim(ncvars, ncvarid, i, Z_AXIS);
+	      else if ( ncdims[ncdimid].dimtype == T_AXIS ) cdf_set_dim(ncvars, ncvarid, i, T_AXIS);
+	    }
+
+	  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");
+	    }
+          }
+      }
+
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      if ( ncvars[ncvarid].isvar == TRUE )
+	{
+	  bool lxdim = false, lydim = false, lzdim = false/* , ltdim = false */;
+	  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].dimtype[i] == T_AXIS ) ltdim = true; */
+	    }
+
+          if ( !lxdim && ncvars[ncvarid].xvarid != CDI_UNDEFID )
+            {
+              if ( ncvars[ncvars[ncvarid].xvarid].ndims == 0 ) lxdim = true;
+            }
+
+          if ( !lydim && ncvars[ncvarid].yvarid != CDI_UNDEFID )
+            {
+              if ( ncvars[ncvars[ncvarid].yvarid].ndims == 0 ) lydim = true;
+            }
+
+          if ( lxdim && (lydim || ncvars[ncvarid].gridtype == GRID_UNSTRUCTURED) )
+            for ( int i = ndims-1; i >= 0; i-- )
+              {
+                if ( ncvars[ncvarid].dimtype[i] == -1 )
+                  {
+                    if ( !lzdim )
+                      {
+                        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;
+                      }
+                  }
+              }
+	}
+    }
+
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      int ndims = ncvars[ncvarid].ndims;
+      for ( int i = 0; i < ndims; i++ )
+        {
+          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);
+                }
+            }
+        }
+    }
+
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      if ( ncvars[ncvarid].isvar == TRUE )
+	{
+	  bool lxdim = false, lydim = false, lzdim = false/* , ltdim = false */;
+	  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].dimtype[i] == T_AXIS ) ltdim = true; */
+	    }
+
+          if ( !lxdim && ncvars[ncvarid].xvarid != CDI_UNDEFID )
+            {
+              if ( ncvars[ncvars[ncvarid].xvarid].ndims == 0 ) lxdim = true;
+            }
+
+          if ( !lydim && ncvars[ncvarid].yvarid != CDI_UNDEFID )
+            {
+              if ( ncvars[ncvars[ncvarid].yvarid].ndims == 0 ) lydim = true;
+            }
+
+          //   if ( ndims > 1 )
+            for ( int i = ndims-1; i >= 0; i-- )
+              {
+                if ( ncvars[ncvarid].dimtype[i] == -1 )
+                  {
+                    if ( !lxdim )
+                      {
+                        cdf_set_dim(ncvars, ncvarid, i, X_AXIS);
+                        lxdim = true;
+                      }
+                    else if ( !lydim && ncvars[ncvarid].gridtype != GRID_UNSTRUCTURED )
+                      {
+                        cdf_set_dim(ncvars, ncvarid, i, Y_AXIS);
+                        lydim = true;
+                      }
+                    else if ( !lzdim )
+                      {
+                        cdf_set_dim(ncvars, ncvarid, i, Z_AXIS);
+                        lzdim = true;
+                      }
+                  }
+              }
+	}
+    }
+}
+
+/* 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, bool *lhybrid_cf)
+{
+  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;
+	    }
+
+          if ( isHybridSigmaPressureCoordinate(ncid, ncvarid, ncvars, ncdims) )
+            {
+              *lhybrid_cf = true;
+              continue;
+            }
+
+	  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;
+            }
+
+	  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 ( 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 verify_coordinate_vars_2(int nvars, ncvar_t *ncvars)
+{
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      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 ( 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;
+		}
+            }
+
+	  /* 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;
+		}
+	    }
+	}
+    }
+}
+
+static
+void grid_set_chunktype(grid_t *grid, ncvar_t *ncvar)
+{
+  if ( ncvar->chunked )
+    {
+      int ndims = ncvar->ndims;
+
+      if ( grid->type == GRID_UNSTRUCTURED )
+        {
+          if ( ncvar->chunks[ndims-1] == grid->size )
+            ncvar->chunktype = CDI_CHUNK_GRID;
+          else
+            ncvar->chunktype = CDI_CHUNK_AUTO;
+        }
+      else
+        {
+          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;
+        }
+    }
+}
+
+/* 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
+    {
+      *gridvals = (double*) Malloc(size*sizeof(double));
+      if ( ntdims == 1 )
+        cdf_get_vara_double(ncvar->ncid, varid, start, count, *gridvals);
+      else
+        cdf_get_var_double(ncvar->ncid, varid, *gridvals);
+      cdf_scale_add(size, *gridvals, ncvar->addoffset, ncvar->scalefactor);
+    }
+}
+
+static
+void cdf_load_bounds(size_t size, ncvar_t *ncvar, double **gridbounds, struct cdfLazyGridIds *cellBoundsGet)
+{
+  if ( CDI_netcdf_lazy_grid_load )
+    {
+      cellBoundsGet->datasetNCId = ncvar->ncid;
+      cellBoundsGet->varNCId  = ncvar->bounds;
+      *gridbounds = cdfPendingLoad;
+    }
+  else
+    {
+      *gridbounds = (double*) Malloc(size*sizeof(double));
+      cdf_get_var_double(ncvar->ncid, ncvar->bounds, *gridbounds);
+    }
+}
+
+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);
+    }
+}
+
+static
+void cdf_copy_axis_attr(ncvar_t *ncvar, struct gridaxis_t *gridaxis)
+{
+  strcpy(gridaxis->name, ncvar->name);
+  strcpy(gridaxis->longname, ncvar->longname);
+  strcpy(gridaxis->units, ncvar->units);
+}
+
+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};
+
+  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++;
+        }
+    }
+
+  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];
+    }
+
+  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 && (int) 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
+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)
+{
+  grid_t *grid = &lazyGrid->base;
+  bool skipvar = true;
+  *islon = axisvar->islon;
+  int ndims = axisvar->ndims;
+  size_t size = 0;
+  if ( (ndims - ntdims) == 2 )
+    {
+      ncvar->gridtype = GRID_CURVILINEAR;
+      size = (*xsize)*ysize;
+      /* 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;
+      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;
+    }
+
+  if ( skipvar )
+    {
+      Warning("Unsupported array structure, skipped variable %s!", ncvar->name);
+      ncvar->isvar = -1;
+      return true;
+    }
+
+  int prec = cdfInqDatatype(axisvar->xtype, axisvar->lunsigned);
+  if ( prec != -1 )  grid->prec = prec;
+
+  cdf_load_vals(size, ndims, xvarid, axisvar, &grid->x.vals, &lazyGrid->xValsGet, ntdims, start, count);
+
+  cdf_copy_axis_attr(axisvar, &grid->x);
+
+  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;
+  if ( (ndims - ntdims) == 2 )
+    {
+      ncvar->gridtype = GRID_CURVILINEAR;
+      size = xsize*(*ysize);
+      /* 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;
+      skipvar = dimsize1*dimsize2 != size;
+    }
+  else if ( (ndims - ntdims) == 1 )
+    {
+      if ( (int) *ysize == 0 ) size = xsize;
+      else                    size = *ysize;
+
+      int dimid = axisvar->dimids[ndims-1];
+      size_t dimsize = ncdims[dimid].len;
+      skipvar = dimsize != size;
+    }
+  else if ( ndims == 0 && *ysize == 0 )
+    {
+      size = *ysize = 1;
+      skipvar = false;
+    }
+
+  if ( skipvar )
+    {
+      Warning("Unsupported array structure, skipped variable %s!", ncvar->name);
+      ncvar->isvar = -1;
+      return true;
+    }
+
+  int prec = cdfInqDatatype(axisvar->xtype, axisvar->lunsigned);
+  if ( prec != -1 )  grid->prec = prec;
+
+  cdf_load_vals(size, ndims, yvarid, axisvar, &grid->y.vals, &lazyGrid->yValsGet, ntdims, start, count);
+
+  cdf_copy_axis_attr(axisvar, &grid->y);
+
+  return false;
+}
+
+static
+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)
+{
+  grid_t *grid = &lazyGrid->base;
+  size_t size = 0;
+
+  grid->prec = CDI_DATATYPE_FLT64;
+
+  if ( ncvar->gridtype == GRID_TRAJECTORY )
+    {
+      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 )
+        {
+          int ndims = ncvars[xvarid].ndims;
+          if ( ndims != ncvars[yvarid].ndims )
+            {
+              Warning("Inconsistent grid structure for variable %s!", ncvar->name);
+              ncvar->xvarid = xvarid = CDI_UNDEFID;
+              ncvar->yvarid = yvarid = CDI_UNDEFID;
+            }
+          if ( ndims > 1 )
+            {
+              if ( ndims <= 3 )
+                {
+                  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;
+                    }
+                }
+              else
+                {
+                  Warning("Unsupported grid structure for variable %s (grid dims > 2)!", ncvar->name);
+                  ncvar->xvarid = xvarid = CDI_UNDEFID;
+                  ncvar->yvarid = yvarid = CDI_UNDEFID;
+                }
+            }
+        }
+
+      if ( xvarid != CDI_UNDEFID )
+        {
+          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 ( 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;
+            }
+        }
+
+      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      ( (int) ysize == 0 ) size = xsize;
+      else if ( (int) 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);
+    }
+
+  int gridtype = grid->type;
+  if ( gridtype != GRID_PROJECTION ) gridtype = ncvar->gridtype;
+  else if ( gridtype == GRID_PROJECTION && ncvar->gridtype == GRID_LONLAT )
+    {
+      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;
+        }
+    }
+
+  switch (gridtype)
+    {
+    case GRID_GENERIC:
+    case GRID_LONLAT:
+    case GRID_GAUSSIAN:
+    case GRID_UNSTRUCTURED:
+    case GRID_CURVILINEAR:
+    case GRID_PROJECTION:
+      {
+        grid->size  = (int)size;
+        grid->x.size = (int)xsize;
+        grid->y.size = (int)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(grid->size*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(grid->size*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 = (int)size;
+        grid->lcomplex = 1;
+        grid->trunc = ncvar->truncation;
+        break;
+      }
+    case GRID_FOURIER:
+      {
+        grid->size = (int)size;
+        grid->trunc = ncvar->truncation;
+        break;
+      }
+    case GRID_TRAJECTORY:
+      {
+        grid->size = 1;
+        break;
+      }
+    }
+
+  // if ( grid->type != GRID_PROJECTION && grid->type != ncvar->gridtype )
+  if ( grid->type != gridtype )
+    {
+      // int gridtype = ncvar->gridtype;
+      grid->type = gridtype;
+      cdiGridTypeInit(grid, gridtype, grid->size);
+    }
+
+  if ( grid->size == 0 )
+    {
+      int ndims = ncvar->ndims;
+      int *dimtype = ncvar->dimtype;
+      if ( (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("Variable %s has an unsupported grid, skipped!", ncvar->name);
+          ncvar->isvar = -1;
+          return true;
+        }
+    }
+
+  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++ )
+    {
+      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];
+    }
+
+  if ( *xdimid != CDI_UNDEFID && *ydimid != CDI_UNDEFID && zdimid == CDI_UNDEFID )
+    {
+      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;
+        }
+    }
+
+  if ( grid->size != grid->x.size )
+    {
+      Warning("Unsupported array structure, skipped variable %s!", ncvar->name);
+      ncvar->isvar = -1;
+      return true;
+    }
+
+  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") )
+    {
+      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
+    {
+      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 cdf_set_grid_to_similar_vars(ncvar_t *ncvar1, ncvar_t *ncvar2, int gridtype, int xdimid, int ydimid)
+{
+  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]; }
+        }
+
+      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 ( 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)) )
+        {
+          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 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)
+{
+  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;
+		}
+	    }
+
+          int gmapvarid = ncvar->gmapid;
+          bool lproj = gmapvarid != CDI_UNDEFID;
+
+          if ( !lproj && xaxisid != CDI_UNDEFID && xaxisid != xvarid && yaxisid != CDI_UNDEFID && yaxisid != yvarid )
+            {
+              lproj = true;
+            }
+
+          bool lgrid = !(lproj && ncvar->xvarid == CDI_UNDEFID);
+
+          bool lunstructured = xdimid != CDI_UNDEFID && xdimid == ydimid && nydims == 0;
+	  if ( (ncvar->gridtype == CDI_UNDEFID || ncvar->gridtype == GRID_GENERIC) && lunstructured )
+            ncvar->gridtype = GRID_UNSTRUCTURED;
+
+          struct cdfLazyGrid *restrict lazyGrid = NULL, *restrict lazyProj = NULL;
+
+          {
+            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;
+
+          xaxisid = (xdimid != CDI_UNDEFID) ? ncdims[xdimid].ncvarid : CDI_UNDEFID;
+          yaxisid = (ydimid != CDI_UNDEFID) ? ncdims[ydimid].ncvarid : CDI_UNDEFID;
+
+
+          if ( cdf_read_coordinates(lazyGrid, ncvar, ncvars, ncdims,
+                                    timedimid, xvarid, yvarid, xsize, ysize, &vdimid) )
+            continue;
+
+	  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 )
+            {
+              int dumid;
+              cdf_read_coordinates(lazyProj, ncvar, ncvars, ncdims, timedimid,
+                                   xaxisid, yaxisid, xsize, ysize, &dumid);
+	    }
+
+	  if ( CDI_Debug )
+	    {
+	      Message("grid: type = %d, size = %d, nx = %d, ny %d",
+		      grid->type, grid->size, grid->x.size, grid->y.size);
+              if ( proj )
+                Message("proj: type = %d, size = %d, nx = %d, ny %d",
+                        proj->type, proj->size, proj->x.size, proj->y.size);
+	    }
+
+
+          if ( lgrid && lproj )
+            {
+              projAdded = cdiVlistAddGridIfNew(vlistID, proj, 2);
+              grid->proj = projAdded.Id;
+            }
+
+          gridAdded = cdiVlistAddGridIfNew(vlistID, grid, 1);
+          ncvar->gridID = gridAdded.Id;
+
+          int gridID = ncvar->gridID;
+
+          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 ( 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].xdimID = xdimid;
+          ncgrid[gridindex].ydimID = ydimid;
+
+          if ( xdimid == CDI_UNDEFID && ydimid == CDI_UNDEFID && grid->size == 1 )
+            gridDefHasDims(gridID, FALSE);
+
+          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);
+
+	  if ( CDI_Debug ) Message("gridID %d %d %s", gridID, ncvarid, ncvar->name);
+
+	  for ( int ncvarid2 = ncvarid+1; ncvarid2 < nvars; ncvarid2++ )
+            cdf_set_grid_to_similar_vars(ncvar, &ncvars[ncvarid2], grid->type, xdimid, ydimid);
+
+          if ( gridAdded.isNew ) lazyGrid = NULL;
+          if ( projAdded.isNew ) lazyProj = NULL;
+
+          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); }
+            }
+	}
+    }
+}
+
+/* define all input zaxes */
+static
+void 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)
+{
+  char *pname, *plongname, *punits;
+  size_t vctsize = vctsize_echam;
+  double *vct = vct_echam;
+
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      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;
+	  int zsize = 1;
+          int psvarid = -1;
+          int p0varid = -1;
+	  double *lbounds = NULL;
+	  double *ubounds = NULL;
+
+          int positive = 0;
+	  int ndims = ncvar->ndims;
+
+          if ( ncvar->zvarid != -1 && ncvars[ncvar->zvarid].ndims == 0 )
+            {
+              zvarid = ncvar->zvarid;
+              is_scalar = true;
+            }
+          else
+            {
+              for ( int i = 0; i < ndims; i++ )
+                {
+                  if ( ncvar->dimtype[i] == Z_AXIS )
+                    zdimid = ncvar->dimids[i];
+                }
+
+              if ( zdimid != CDI_UNDEFID )
+                {
+                  zvarid = ncdims[zdimid].ncvarid;
+                  zsize  = (int)ncdims[zdimid].len;
+                }
+            }
+
+	  if ( CDI_Debug ) Message("nlevs = %d", zsize);
+
+	  double *zvar = NULL;
+
+	  int zaxisType = CDI_UNDEFID;
+	  if ( zvarid != CDI_UNDEFID ) zaxisType = ncvars[zvarid].zaxistype;
+	  if ( zaxisType == CDI_UNDEFID ) zaxisType = ZAXIS_GENERIC;
+
+	  int zprec = CDI_DATATYPE_FLT64;
+
+	  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 ) zprec = 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_HYBRID && ncvars[zvarid].vct )
+                {
+                  vct = ncvars[zvarid].vct;
+                  vctsize = ncvars[zvarid].vctsize;
+
+                  if ( ncvars[zvarid].psvarid != -1 ) psvarid = ncvars[zvarid].psvarid;
+                  if ( ncvars[zvarid].p0varid != -1 ) p0varid = ncvars[zvarid].p0varid;
+                }
+
+              zvar = (double*) Malloc((size_t)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 )
+		    {
+		      int nlevel  = (int)ncdims[ncvars[ncvars[zvarid].bounds].dimids[0]].len;
+		      int 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 ( int 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;
+                    }
+                }
+	    }
+
+      	  ncvar->zaxisID = varDefZaxis(vlistID, zaxisType, (int) zsize, zvar, with_bounds, lbounds, ubounds,
+                                       (int)vctsize, vct, pname, plongname, punits, zprec, 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, 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, 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 ( lbounds ) Free(lbounds);
+	  if ( ubounds ) Free(ubounds);
+
+          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;
+                      }
+                  }
+	      }
+	}
+    }
+}
+
+
+struct cdf_varinfo
+{
+  int        varid;
+  const char *name;
+};
+
+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
+void cdf_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 )
+    {
+      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]);
+    }
+
+  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, CDI_COMPRESS_ZIP);
+
+      if ( ncvars[ncvarid].chunked && ncvars[ncvarid].chunktype != CDI_UNDEFID )
+        vlistDefVarChunkType(vlistID, varID, ncvars[ncvarid].chunktype);
+#endif
+
+      streamptr->vars[varID1].defmiss = false;
+      streamptr->vars[varID1].ncvarid = ncvarid;
+
+      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 ( ncvars[ncvarid].lvalidrange )
+        vlistDefVarValidrange(vlistID, varID, ncvars[ncvarid].validrange);
+
+      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);
+
+      vlistDefVarDatatype(vlistID, varID, cdfInqDatatype(ncvars[ncvarid].xtype, ncvars[ncvarid].lunsigned));
+
+      vlistDefVarInstitut(vlistID, varID, instID);
+      vlistDefVarModel(vlistID, varID, modelID);
+      if ( ncvars[ncvarid].tableID != CDI_UNDEFID )
+	vlistDefVarTable(vlistID, varID, ncvars[ncvarid].tableID);
+
+      if ( ncvars[ncvarid].deffillval == false && ncvars[ncvarid].defmissval )
+        {
+          ncvars[ncvarid].deffillval = true;
+          ncvars[ncvarid].fillval    = ncvars[ncvarid].missval;
+        }
+
+      if ( ncvars[ncvarid].deffillval )
+        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->ncgrid[gridindex].xdimID;
+      int ydimid = streamptr->ncgrid[gridindex].ydimID;
+
+      int zaxisindex = vlistZaxisIndex(vlistID, zaxisID);
+      int zdimid = streamptr->zaxisID[zaxisindex];
+
+      int ndims = ncvars[ncvarid].ndims;
+      int iodim = 0;
+      int ixyz = 0;
+      int ipow10[4] = {1, 10, 100, 1000};
+
+      if ( ncvars[ncvarid].tsteptype != TSTEP_CONSTANT ) iodim++;
+
+      int *dimids = ncvars[ncvarid].dimids;
+
+      if ( gridInqType(gridID) == GRID_UNSTRUCTURED && ndims-iodim <= 2 && ydimid == xdimid )
+        {
+          ixyz = (xdimid == dimids[ndims-1]) ? 321 : 213;
+        }
+      else
+        {
+          for ( int idim = iodim; idim < ndims; idim++ )
+            {
+              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];
+            }
+        }
+
+      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 )
+        {
+          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 ( ncvars[ncvarid].extra[0] != 0 )
+        {
+          vlistDefVarExtra(vlistID, varID, ncvars[ncvarid].extra);
+        }
+    }
+
+  for ( int varID = 0; varID < nvars; varID++ )
+    {
+      int ncvarid = varids[varID];
+      int ncid = ncvars[ncvarid].ncid;
+
+      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 ( ncvars[ncvarid].atts )
+        {
+          Free(ncvars[ncvarid].atts);
+          ncvars[ncvarid].atts = NULL;
+        }
+
+      if ( ncvars[ncvarid].vct )
+        {
+          Free(ncvars[ncvarid].vct);
+          ncvars[ncvarid].vct = NULL;
+        }
+    }
+
+  /* release mem of not freed attributes */
+  for ( int ncvarid = 0; ncvarid < num_ncvars; ncvarid++ )
+    if ( ncvars[ncvarid].atts ) Free(ncvars[ncvarid].atts);
+
+  if ( varids ) Free(varids);
+
+  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 ( str_is_equal(pname, "var") )
+		{
+		  vlistDefVarCode(vlistID, varID, atoi(pname+3));
+                  // vlistDestroyVarName(vlistID, varID);
+		}
+	    }
+	  else if ( len > 4 && isdigit((int) pname[4]) )
+	    {
+	      if ( str_is_equal(pname, "code") )
+		{
+		  vlistDefVarCode(vlistID, varID, atoi(pname+4));
+		  // vlistDestroyVarName(vlistID, varID);
+		}
+	    }
+	  else if ( len > 5 && isdigit((int) pname[5]) )
+	    {
+	      if ( str_is_equal(pname, "param") )
+		{
+		  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);
+		}
+	    }
+	}
+    }
+
+  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 )
+	{
+	  if ( tableInqParNamePtr(cdiDefaultTableID, code) )
+	    {
+	      vlistDestroyVarName(vlistID, varID);
+	      vlistDestroyVarLongname(vlistID, varID);
+	      vlistDestroyVarUnits(vlistID, varID);
+
+	      if ( varTableID != CDI_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;
+		}
+	    }
+
+	  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
+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)
+{
+  nc_type xtype;
+  size_t attlen;
+  char attname[CDI_MAX_NAME];
+  char attstring[65636];
+
+  for ( int 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);
+
+      if ( xtypeIsText(xtype) )
+	{
+	  cdfGetAttText(fileID, NC_GLOBAL, attname, sizeof(attstring), attstring);
+
+          size_t attstrlen = strlen(attstring);
+
+	  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);
+
+		  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, (int)attlen, attint);
+              int datatype = (xtype == NC_SHORT) ? CDI_DATATYPE_INT16 : CDI_DATATYPE_INT32;
+              cdiDefAttInt(vlistID, CDI_GLOBAL, attname, datatype, (int)attlen, attint);
+            }
+        }
+      else if ( xtype == NC_FLOAT || xtype == NC_DOUBLE )
+	{
+	  double attflt[attlen];
+	  cdfGetAttDouble(fileID, NC_GLOBAL, attname, (int)attlen, attflt);
+          int datatype = (xtype == NC_FLOAT) ? CDI_DATATYPE_FLT32 : CDI_DATATYPE_FLT64;
+          cdiDefAttFlt(vlistID, CDI_GLOBAL, attname, datatype, (int)attlen, attflt);
+	}
+    }
+}
+
+static
+int find_leadtime(int nvars, ncvar_t *ncvars)
+{
+  int leadtime_id = CDI_UNDEFID;
+
+  for ( int ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      if ( ncvars[ncvarid].stdname[0] && strcmp(ncvars[ncvarid].stdname, "forecast_period") == 0 )
+        {
+          leadtime_id = ncvarid;
+          break;
+        }
+    }
+
+  return leadtime_id;
+}
+
+static
+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 ncvarid;
+
+  if ( timedimid == CDI_UNDEFID )
+    {
+      char timeunits[CDI_MAX_NAME];
+
+      for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+        {
+          if ( ncvars[ncvarid].ndims == 0 && strcmp(ncvars[ncvarid].name, "time") == 0 )
+            {
+              if ( ncvars[ncvarid].units[0] )
+                {
+                  strcpy(timeunits, ncvars[ncvarid].units);
+                  str_tolower(timeunits);
+
+                  if ( is_time_units(timeunits) )
+                    {
+                      streamptr->basetime.ncvarid = ncvarid;
+                      break;
+                    }
+                }
+            }
+        }
+    }
+  else
+    {
+      bool ltimevar = false;
+
+      if ( ncdims[timedimid].ncvarid != CDI_UNDEFID )
+        {
+          streamptr->basetime.ncvarid = ncdims[timedimid].ncvarid;
+          ltimevar = true;
+        }
+
+      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 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;
+                }
+            }
+        }
+    }
+}
+
+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' )
+            {
+              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
+                }
+            }
+	}
+    }
+
+  /* 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' )
+            {
+              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;
+            }
+        }
+    }
+}
+
+static
+int cdf_check_vars(int nvars, ncvar_t *ncvars, int 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);
+
+      if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims == 0 )
+	cdf_set_var(ncvars, ncvarid, FALSE);
+
+      //if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims > 1 )
+      if ( ncvars[ncvarid].isvar == -1 && ncvars[ncvarid].ndims >= 1 )
+	cdf_set_var(ncvars, ncvarid, TRUE);
+
+      if ( ncvars[ncvarid].isvar == -1 )
+	{
+	  ncvars[ncvarid].isvar = 0;
+	  Warning("Variable %s has an unknown type, skipped!", ncvars[ncvarid].name);
+	  continue;
+	}
+
+      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 ( 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;
+	}
+
+      if ( xtypeIsText(ncvars[ncvarid].xtype) )
+	{
+	  ncvars[ncvarid].isvar = 0;
+	  continue;
+	}
+
+      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;
+	}
+
+      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;
+	    }
+	}
+    }
+
+  return timedimid;
+}
+
+
+int cdfInqContents(stream_t *streamptr)
+{
+  int ndims, nvars, ngatts, unlimdimid;
+  int ncvarid;
+  int ncdimid;
+  int timedimid = -1;
+  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;
+
+  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 vlistID = streamptr->vlistID;
+  int fileID  = streamptr->fileID;
+
+  if ( CDI_Debug ) Message("streamID = %d, fileID = %d", streamptr->self, fileID);
+
+#if  defined  (HAVE_NETCDF4)
+  nc_inq_format(fileID, &format);
+#endif
+
+  cdf_inq(fileID, &ndims , &nvars, &ngatts, &unlimdimid);
+
+  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 = (ncdim_t *) Malloc((size_t)ndims * sizeof (ncdim_t));
+  init_ncdims(ndims, ncdims);
+
+#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 )
+            {
+            }
+        }
+    }
+#endif
+#endif
+
+  if ( nvars == 0 )
+    {
+      Warning("No arrays found!");
+      return CDI_EUFSTRUCT;
+    }
+
+  /* alloc ncvars */
+  ncvar_t *ncvars = (ncvar_t *) Malloc((size_t)nvars * sizeof (ncvar_t));
+  init_ncvars(nvars, ncvars);
+
+  for ( ncvarid = 0; ncvarid < nvars; ++ncvarid ) ncvars[ncvarid].ncid = fileID;
+
+
+  /* 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 */
+  if ( unlimdimid >= 0 )
+    timedimid = unlimdimid;
+  else
+    timedimid = 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 ( CDI_Debug ) Message("Number of timesteps = %d", 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");
+
+  /* scan attributes of all variables */
+  cdf_scan_var_attr(nvars, ncvars, ncdims, timedimid, modelID, format);
+
+
+  if ( CDI_Debug ) cdf_print_vars(ncvars, nvars, "find coordinate vars");
+
+  /* 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] )
+		{
+		  if ( ncvars[ncvarid].isvar != FALSE ) cdf_set_var(ncvars, ncvarid, TRUE);
+		}
+	      else
+		{
+                  //  if ( ncvars[ncvarid].isvar != TRUE ) cdf_set_var(ncvars, ncvarid, FALSE);
+		}
+	      // 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;
+		  }
+	    }
+	}
+    }
+
+  /* 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 != CDI_UNDEFID ) ncvars[leadtime_id].isvar = FALSE;
+
+  /* check ncvars */
+  timedimid = cdf_check_vars(nvars, ncvars, ntsteps, timedimid);
+
+  /* verify coordinate vars - first scan (dimname == varname) */
+  bool lhybrid_cf = false;
+  verify_coordinate_vars_1(fileID, ndims, ncdims, ncvars, timedimid, &lhybrid_cf);
+
+  /* verify coordinate vars - second scan (all other variables) */
+  verify_coordinate_vars_2(nvars, ncvars);
+
+  if ( CDI_Debug ) cdf_print_vars(ncvars, nvars, "verify_coordinate_vars");
+
+  if ( ucla_les ) cdf_set_ucla_dimtype(ndims, ncdims, ncvars);
+
+  /*
+  for ( ncdimid = 0; ncdimid < ndims; ncdimid++ )
+    {
+      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);
+
+	  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);
+	}
+    }
+  */
+
+  /* Set coordinate varids (att: associate)  */
+  for ( ncvarid = 0; ncvarid < nvars; ncvarid++ )
+    {
+      ncvar_t *ncvar = &ncvars[ncvarid];
+      if ( ncvar->isvar == TRUE && ncvar->ncoordvars )
+	{
+	  int ndims = ncvar->ncoordvars;
+	  for ( int i = 0; i < ndims; i++ )
+	    {
+	      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];
+	    }
+	}
+    }
+
+  /* set dim type */
+  cdf_set_dimtype(nvars, ncvars, ncdims);
+
+  /* read ECHAM VCT if present */
+  size_t vctsize = 0;
+  double *vct = NULL;
+  if ( !lhybrid_cf ) read_vct_echam(fileID, nvars, ncvars, ncdims, &vct, &vctsize);
+
+
+  if ( CDI_Debug ) cdf_print_vars(ncvars, nvars, "cdf_define_all_grids");
+
+  /* define all grids */
+  cdf_define_all_grids(streamptr->ncgrid, vlistID, ncdims, nvars, ncvars, timedimid, uuidOfHGrid, gridfile, number_of_grid_used);
+
+
+  /* define all zaxes */
+  cdf_define_all_zaxes(streamptr, vlistID, ncdims, nvars, ncvars, vctsize, vct, uuidOfVGrid);
+  if ( vct ) Free(vct);
+
+
+  /* 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 = %d", ntsteps);
+  if ( CDI_Debug ) Message("nvars_data = %d", nvars_data);
+
+
+  if ( nvars_data == 0 )
+    {
+      streamptr->ntsteps = 0;
+      return CDI_EUFSTRUCT;
+    }
+
+  if ( ntsteps == 0 && streamptr->basetime.ncdimid == CDI_UNDEFID && streamptr->basetime.ncvarid != CDI_UNDEFID )
+    ntsteps = 1;
+
+  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 )
+    {
+      taxis_t *taxis = &streamptr->tsteps[0].taxis;
+
+      if ( setBaseTime(ncvars[nctimevarid].units, taxis) == 1 )
+        {
+          nctimevarid = CDI_UNDEFID;
+          streamptr->basetime.ncvarid = CDI_UNDEFID;
+        }
+
+      if ( leadtime_id != CDI_UNDEFID && taxis->type == TAXIS_RELATIVE )
+        {
+          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);
+        }
+    }
+
+  if ( time_has_bounds )
+    {
+      streamptr->tsteps[0].taxis.has_bounds = true;
+      if ( time_climatology ) streamptr->tsteps[0].taxis.climatology = true;
+    }
+
+  if ( nctimevarid != CDI_UNDEFID )
+    {
+      taxis_t *taxis = &streamptr->tsteps[0].taxis;
+      ptaxisDefName(taxis, ncvars[nctimevarid].name);
+
+      if ( ncvars[nctimevarid].longname[0] )
+        ptaxisDefLongname(taxis, ncvars[nctimevarid].longname);
+
+      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
+
+  vlistDefTaxis(vlistID, taxisID);
+
+  streamptr->curTsID = 0;
+  streamptr->rtsteps = 1;
+
+  (void) cdfInqTimestep(streamptr, 0);
+
+  cdfCreateRecords(streamptr, 0);
+
+  /* free ncdims */
+  Free(ncdims);
+
+  /* free ncvars */
+  Free(ncvars);
+
+  return 0;
+}
+
+static
+void wrf_read_timestep(int fileID, int nctimevarid, int tsID, 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;
+  }
+}
+
+static
+double get_timevalue(int fileID, int nctimevarid, int tsID, timecache_t *tcache)
+{
+  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;
+}
+
+
+int cdfInqTimestep(stream_t * streamptr, int tsID)
+{
+  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 )
+    {
+      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);
+            }
+	}
+    }
+
+  streamptr->curTsID = tsID;
+  long nrecs = streamptr->tsteps[tsID].nrecs;
+
+  return (int) nrecs;
+}
+
+
+int cdfInqHistorySize(stream_t *streamptr)
+{
+  size_t size = 0;
+  int ncid = streamptr->fileID;
+  if ( streamptr->historyID != CDI_UNDEFID )
+    cdf_inq_attlen(ncid, NC_GLOBAL, "history", &size);
+
+  return (int) size;
+}
+
+
+void cdfInqHistoryString(stream_t *streamptr, char *history)
+{
+  int ncid = streamptr->fileID;
+  if ( streamptr->historyID != CDI_UNDEFID )
+    {
+      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
+    }
+}
+
+#endif
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
diff --git a/libcdi/src/stream_cdf_o.c b/libcdi/src/stream_cdf_o.c
new file mode 100644
index 0000000..c86a9a2
--- /dev/null
+++ b/libcdi/src/stream_cdf_o.c
@@ -0,0 +1,2115 @@
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#ifdef HAVE_LIBNETCDF
+
+#include "dmemory.h"
+#include "cdi_int.h"
+#include "cdi_uuid.h"
+#include "stream_cdf.h"
+#include "cdf_int.h"
+#include "varscan.h"
+#include "vlist.h"
+#include "zaxis.h"
+
+
+#define  POSITIVE_UP    1
+#define  POSITIVE_DOWN  2
+
+
+static const char bndsName[] = "bnds";
+
+
+void cdfCopyRecord(stream_t *streamptr2, stream_t *streamptr1)
+{
+  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 != CDI_DATATYPE_FLT32 ? MEMTYPE_DOUBLE : MEMTYPE_FLOAT;
+
+  void *data = Malloc((size_t)datasize
+             * (memtype == MEMTYPE_DOUBLE ? sizeof(double) : sizeof(float)));
+
+  int nmiss;
+  cdf_read_record(streamptr1, memtype, data, &nmiss);
+  cdf_write_record(streamptr2, memtype, data, nmiss);
+
+  Free(data);
+}
+
+
+void cdfDefRecord(stream_t *streamptr)
+{
+  (void)streamptr;
+}
+
+static
+void cdfDefTimeValue(stream_t *streamptr, int tsID)
+{
+  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 )
+    {
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
+    }
+
+  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);
+
+  if ( taxis->has_bounds )
+    {
+      size_t start[2], count[2];
+
+      ncvarid = streamptr->basetime.ncvarboundsid;
+
+      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);
+
+      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);
+    }
+
+  /*
+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 time_bndsid = -1;
+  int dims[2];
+
+  dims[0] = nctimedimid;
+
+  /* fprintf(stderr, "time has bounds\n"); */
+
+  if ( nc_inq_dimid(fileID, bndsName, &dims[1]) != NC_NOERR )
+    cdf_def_dim(fileID, bndsName, 2, &dims[1]);
+
+  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
+    {
+      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 time_bndsid;
+}
+
+static
+void cdfDefTimeUnits(char *unitstr, taxis_t* taxis0, taxis_t* taxis)
+{
+  unitstr[0] = 0;
+
+  if ( taxis0->type == TAXIS_ABSOLUTE )
+    {
+      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");
+    }
+  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);
+
+      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);
+    }
+}
+
+static
+void cdfDefForecastTimeUnits(char *unitstr, int timeunit)
+{
+  unitstr[0] = 0;
+
+  if ( timeunit == -1 ) timeunit = TUNIT_HOUR;
+
+  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;
+
+  strcpy(unitstr, tunitNamePtr(timeunit));
+}
+
+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] };
+
+  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;
+      }
+}
+
+
+void cdfDefTime(stream_t* streamptr)
+{
+  int time_varid;
+  int time_dimid;
+  int time_bndsid = -1;
+  static const char default_name[] = "time";
+
+  if ( streamptr->basetime.ncvarid != CDI_UNDEFID ) return;
+
+  int fileID = streamptr->fileID;
+
+  if ( streamptr->ncmode == 0 ) streamptr->ncmode = 1;
+  if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+
+  taxis_t *taxis = &streamptr->tsteps[0].taxis;
+
+  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;
+
+  nc_type xtype = (taxis->datatype == CDI_DATATYPE_FLT32) ? NC_FLOAT : NC_DOUBLE;
+
+  cdf_def_var(fileID, taxis_name, xtype, 1, &time_dimid, &time_varid);
+
+  streamptr->basetime.ncvarid = time_varid;
+
+  {
+    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);
+
+  if ( taxis->has_bounds )
+    {
+      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);
+        */
+      }
+  }
+
+  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;
+
+      {
+        static const char stdname[] = "forecast_period";
+        cdf_put_att_text(fileID, leadtimeid, "standard_name", sizeof(stdname) - 1, stdname);
+      }
+
+      {
+        static const char lname[] = "Time elapsed since the start of the forecast";
+        cdf_put_att_text(fileID, leadtimeid, "long_name", sizeof(lname) - 1, lname);
+      }
+
+      {
+          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);
+}
+
+
+void cdfDefTimestep(stream_t *streamptr, int tsID)
+{
+  int vlistID = streamptr->vlistID;
+
+  if ( vlistHasTime(vlistID) ) cdfDefTime(streamptr);
+
+  cdfDefTimeValue(streamptr, tsID);
+}
+
+static
+void cdfDefComplex(stream_t *streamptr, int gridID, int gridindex)
+{
+  int dimID = CDI_UNDEFID;
+  int fileID  = streamptr->fileID;
+  ncgrid_t *ncgrid = streamptr->ncgrid;
+
+  for ( int index = 0; index < gridindex; ++index )
+    {
+      if ( ncgrid[index].xdimID != CDI_UNDEFID )
+        {
+          int gridID0 = ncgrid[index].gridID;
+          int gridtype0 = gridInqType(gridID0);
+          if ( gridtype0 == GRID_SPECTRAL || gridtype0 == GRID_FOURIER )
+            {
+              dimID = ncgrid[index].xdimID;
+              break;
+            }
+        }
+    }
+
+  if ( dimID == CDI_UNDEFID )
+    {
+      static const char axisname[] = "nc2";
+      size_t dimlen = 2;
+
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+      cdf_def_dim(fileID, axisname, dimlen, &dimID);
+      cdf_enddef(fileID);
+
+      streamptr->ncmode = 2;
+    }
+
+  ncgrid[gridindex].gridID = gridID;
+  ncgrid[gridindex].xdimID = dimID;
+}
+
+static void
+cdfDefSPorFC(stream_t *streamptr, int gridID, int gridindex,
+             char *restrict axisname, int gridRefType)
+{
+  int iz = 0;
+  int dimID = CDI_UNDEFID;
+  ncgrid_t *ncgrid = streamptr->ncgrid;
+
+  size_t dimlen = (size_t)gridInqSize(gridID)/2;
+
+  for ( int index = 0; index < gridindex; index++ )
+    {
+      if ( ncgrid[index].ydimID != CDI_UNDEFID )
+        {
+          int gridID0 = ncgrid[index].gridID;
+          int gridtype0 = gridInqType(gridID0);
+          if ( gridtype0 == gridRefType )
+            {
+              size_t dimlen0 = (size_t)gridInqSize(gridID0)/2;
+              if ( dimlen == dimlen0 )
+                {
+                  dimID = ncgrid[index].ydimID;
+                  break;
+                }
+              else
+                iz++;
+            }
+        }
+    }
+
+  if ( dimID == CDI_UNDEFID )
+    {
+      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;
+    }
+
+  ncgrid[gridindex].gridID = gridID;
+  ncgrid[gridindex].ydimID = dimID;
+}
+
+static
+void cdfDefSP(stream_t *streamptr, int gridID, int gridindex)
+{
+  /*
+  char longname[] = "Spherical harmonic coefficient";
+  */
+  char axisname[5] = "nspX";
+  cdfDefSPorFC(streamptr, gridID, gridindex, axisname, GRID_SPECTRAL);
+}
+
+
+static
+void cdfDefFC(stream_t *streamptr, int gridID, int gridindex)
+{
+  char axisname[5] = "nfcX";
+  cdfDefSPorFC(streamptr, gridID, gridindex, axisname, GRID_FOURIER);
+}
+
+static const struct cdfDefGridAxisInqs {
+  int (*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);
+  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)
+{
+  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
+cdfDefTrajLatLon(stream_t *streamptr, int gridID, int gridindex,
+                 const struct cdfDefGridAxisInqs *inqs, int dimtype)
+{
+  nc_type xtype = (gridInqPrec(gridID) == CDI_DATATYPE_FLT32) ? NC_FLOAT : NC_DOUBLE;
+  ncgrid_t *ncgrid = streamptr->ncgrid;
+
+  int dimlen = inqs->axisSize(gridID);
+  if ( dimlen != 1 )
+    Error("%c size isn't 1 for %s grid!", dimtype, gridNamePtr(gridInqType(gridID)));
+
+  int ncvarid = CDI_UNDEFID;
+  if ( dimtype == 'X' )
+    ncvarid = ncgrid[gridindex].xdimID;
+  else
+    ncvarid = ncgrid[gridindex].ydimID;
+
+  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;
+  if ( dimtype == 'X' )
+    ncgrid[gridindex].xdimID = ncvarid; /* var ID for trajectory !!! */
+  else
+    ncgrid[gridindex].ydimID = ncvarid; /* var ID for trajectory !!! */
+}
+
+static
+void cdfDefTrajLon(stream_t *streamptr, int gridID, int gridindex)
+{
+  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;
+}
+
+static
+void checkGridName(char *axisname, int fileID)
+{
+  int ncdimid;
+  char axisname2[CDI_MAX_NAME];
+
+  /* check that the name is not already defined */
+  unsigned iz = 0;
+
+  size_t axisnameLen = strlen(axisname);
+  memcpy(axisname2, axisname, axisnameLen + 1);
+  do
+    {
+      if ( iz ) sprintf(axisname2 + axisnameLen, "_%u", iz+1);
+
+      int status = nc_inq_varid(fileID, axisname2, &ncdimid);
+      if ( status != NC_NOERR ) break;
+
+      ++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];
+
+  /* check that the name is not already defined */
+  unsigned iz = 0;
+
+  size_t axisnameLen = strlen(axisname);
+  memcpy(axisname2, axisname, axisnameLen + 1);
+  do
+    {
+      if ( iz ) sprintf(axisname2 + axisnameLen, "_%u", iz+1);
+
+      int ncdimid, status = nc_inq_varid(fileID, axisname2, &ncdimid);
+
+      if ( status != NC_NOERR )
+        {
+          if ( iz )
+            {
+              /* 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);
+
+
+  if ( iz ) sprintf(axisname + axisnameLen, "_%u", iz+1);
+
+  return (int)iz;
+}
+
+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 = (size_t)gridAxisInq->axisSize(gridID);
+  nc_type xtype = (nc_type)cdfDefDatatype(gridInqPrec(gridID), streamptr->filetype);
+
+  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);
+
+  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 = (size_t)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;
+              if ( IS_EQUAL(inqVal(gridID0, 0), inqVal(gridID, 0)) &&
+                   IS_EQUAL(inqVal(gridID0, (int)dimlen-1), inqVal(gridID, (int)dimlen-1)) )
+                {
+                  dimID = (dimKey == CDI_KEY_XDIMNAME) ? ncgrid[index].xdimID : ncgrid[index].ydimID;
+                  break;
+                }
+            }
+        }
+    }
+
+  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);
+
+      /* 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 ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+
+      if ( ndims )
+        {
+          if ( dimname[0] == 0 ) strcpy(dimname, extendedAxisname);
+          dimID = checkDimName(fileID, dimlen, dimname);
+
+          if ( dimID == CDI_UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID);
+        }
+
+      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);
+
+          cdfPutGridStdAtts(fileID, ncvarid, gridID, axisLetter, gridAxisInq);
+          {
+            char axisStr[2] = { axisLetter, '\0' };
+            cdf_put_att_text(fileID, ncvarid, "axis", 1, axisStr);
+          }
+
+          pbounds = (double *)gridAxisInq->axisBoundsPtr(gridID);
+
+          if ( CDI_cmor_mode && grid_is_cyclic && !pbounds )
+            {
+              gen_bounds = true;
+              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 )
+            {
+              size_t nvertex = 2;
+              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);
+            }
+        }
+
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
+
+      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 ( ndims == 0 )
+        {
+          if ( dimKey == CDI_KEY_XDIMNAME )
+            ncgrid[gridindex].xvarID = ncvarid;
+          else
+            ncgrid[gridindex].yvarID = ncvarid;
+        }
+    }
+
+  ncgrid[gridindex].gridID = gridID;
+  if ( dimKey == CDI_KEY_XDIMNAME )
+    ncgrid[gridindex].xdimID = dimID;
+  else
+    ncgrid[gridindex].ydimID = dimID;
+}
+
+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;
+}
+
+static
+void cdfDefXaxis(stream_t *streamptr, int gridID, int gridindex, int ndims)
+{
+  cdfDefAxisCommon(streamptr, gridID, gridindex, ndims, &gridInqsX,
+                   CDI_KEY_XDIMNAME, 'X', finishCyclicXBounds);
+}
+
+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]);
+}
+
+static
+void cdfDefYaxis(stream_t *streamptr, int gridID, int gridindex, int ndims)
+{
+  cdfDefAxisCommon(streamptr, gridID, gridindex, ndims, &gridInqsY,
+                   CDI_KEY_YDIMNAME, 'Y', finishCyclicYBounds);
+}
+
+static
+void cdfGridCompress(int fileID, int ncvarid, int gridsize, int filetype, int comptype)
+{
+#if  defined  (HAVE_NETCDF4)
+  if ( gridsize > 1 && comptype == CDI_COMPRESS_ZIP && (filetype == CDI_FILETYPE_NC4 || filetype == CDI_FILETYPE_NC4C) )
+    {
+      nc_def_var_chunking(fileID, ncvarid, NC_CHUNKED, NULL);
+      cdfDefVarDeflate(fileID, ncvarid, 1);
+    }
+#endif
+}
+
+static
+void cdfDefCurvilinear(stream_t *streamptr, int gridID, int gridindex)
+{
+  int xdimID = CDI_UNDEFID;
+  int ydimID = CDI_UNDEFID;
+  int ncxvarid = CDI_UNDEFID, ncyvarid = CDI_UNDEFID;
+  int ncbxvarid = CDI_UNDEFID, ncbyvarid = CDI_UNDEFID, ncavarid = CDI_UNDEFID;
+  nc_type xtype = (nc_type)cdfDefDatatype(gridInqPrec(gridID), streamptr->filetype);
+  ncgrid_t *ncgrid = streamptr->ncgrid;
+
+  int fileID  = streamptr->fileID;
+
+  size_t dimlen = (size_t)gridInqSize(gridID);
+  size_t xdimlen = (size_t)gridInqXsize(gridID);
+  size_t ydimlen = (size_t)gridInqYsize(gridID);
+
+  for ( int index = 0; index < gridindex; index++ )
+    {
+      if ( ncgrid[index].xdimID != CDI_UNDEFID )
+        {
+          int gridID0 = ncgrid[index].gridID;
+          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 = ncgrid[index].xdimID;
+                    ydimID = ncgrid[index].ydimID;
+                    ncxvarid = ncgrid[index].xvarID;
+                    ncyvarid = ncgrid[index].yvarID;
+                    break;
+                  }
+            }
+        }
+    }
+
+  if ( xdimID == CDI_UNDEFID || ydimID == CDI_UNDEFID )
+    {
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+      {
+        char xdimname[CDI_MAX_NAME+3];
+        xdimname[0] = 0;
+        cdiGridInqKeyStr(gridID, CDI_KEY_XDIMNAME, CDI_MAX_NAME, xdimname);
+        if ( xdimname[0] == 0 ) { xdimname[0] = 'x'; xdimname[1] = 0; }
+        xdimID = checkDimName(fileID, xdimlen, xdimname);
+        if ( xdimID == CDI_UNDEFID ) cdf_def_dim(fileID, xdimname, xdimlen, &xdimID);
+      }
+      {
+        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);
+      }
+
+      int nvdimID = CDI_UNDEFID;
+      int dimIDs[3];
+      if ( gridInqXboundsPtr(gridID) || gridInqYboundsPtr(gridID) )
+        {
+          char vdimname[CDI_MAX_NAME+3]; vdimname[0] = 0;
+          cdiGridInqKeyStr(gridID, CDI_KEY_VDIMNAME, CDI_MAX_NAME, vdimname);
+          if ( vdimname[0] == 0 ) strcpy(vdimname, "nv4");
+          size_t nvertex = 4;
+          nvdimID = checkDimName(fileID, nvertex, vdimname);
+          if ( nvdimID == CDI_UNDEFID ) cdf_def_dim(fileID, vdimname, nvertex, &nvdimID);
+        }
+
+      dimIDs[0] = ydimID;
+      dimIDs[1] = xdimID;
+      dimIDs[2] = nvdimID;
+
+      if ( gridInqXvalsPtr(gridID) )
+        {
+          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, 2, dimIDs, &ncxvarid);
+          cdfGridCompress(fileID, ncxvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
+
+          cdfPutGridStdAtts(fileID, ncxvarid, gridID, 'X', &gridInqsX);
+
+          /* attribute for Panoply */
+          cdf_put_att_text(fileID, ncxvarid, "_CoordinateAxisType", 3, "Lon");
+
+          if ( 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, 3, dimIDs, &ncbxvarid);
+              cdfGridCompress(fileID, ncbxvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
+
+              cdf_put_att_text(fileID, ncxvarid, "bounds", xaxisnameLen + sizeof (bndsName), xaxisname);
+            }
+        }
+
+      if ( gridInqYvalsPtr(gridID) )
+        {
+          char yaxisname[CDI_MAX_NAME];
+          gridInqYname(gridID, yaxisname);
+          checkGridName(yaxisname, fileID);
+
+          cdf_def_var(fileID, yaxisname, xtype, 2, dimIDs, &ncyvarid);
+          cdfGridCompress(fileID, ncyvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
+
+          cdfPutGridStdAtts(fileID, ncyvarid, gridID, 'Y', &gridInqsY);
+
+          /* attribute for Panoply */
+          cdf_put_att_text(fileID, ncyvarid, "_CoordinateAxisType", 3, "Lat");
+
+          if ( 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, 3, dimIDs, &ncbyvarid);
+              cdfGridCompress(fileID, ncbyvarid, (int)(xdimlen*ydimlen), streamptr->filetype, streamptr->comptype);
+
+              cdf_put_att_text(fileID, ncyvarid, "bounds", yaxisnameLen + sizeof (bndsName), yaxisname);
+            }
+        }
+
+      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";
+
+          cdf_def_var(fileID, yaxisname_, xtype, 2, 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);
+        }
+
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
+
+      if ( ncxvarid  != CDI_UNDEFID ) cdf_put_var_double(fileID, ncxvarid,  gridInqXvalsPtr(gridID));
+      if ( ncbxvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncbxvarid, gridInqXboundsPtr(gridID));
+      if ( ncyvarid  != CDI_UNDEFID ) cdf_put_var_double(fileID, ncyvarid,  gridInqYvalsPtr(gridID));
+      if ( ncbyvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncbyvarid, gridInqYboundsPtr(gridID));
+      if ( ncavarid  != CDI_UNDEFID ) cdf_put_var_double(fileID, ncavarid,  gridInqAreaPtr(gridID));
+    }
+
+  ncgrid[gridindex].gridID = gridID;
+  ncgrid[gridindex].xdimID = xdimID;
+  ncgrid[gridindex].ydimID = ydimID;
+  ncgrid[gridindex].xvarID = ncxvarid;
+  ncgrid[gridindex].yvarID = ncyvarid;
+  ncgrid[gridindex].avarID = ncavarid;
+}
+
+static
+void cdfDefRgrid(stream_t *streamptr, int gridID, int gridindex)
+{
+  ncgrid_t *ncgrid = streamptr->ncgrid;
+  int dimID = CDI_UNDEFID;
+
+  size_t dimlen = (size_t)gridInqSize(gridID);
+
+  int iz = 0;
+  for ( int index = 0; index < gridindex; index++ )
+    {
+      if ( ncgrid[index].xdimID != CDI_UNDEFID )
+        {
+          int gridID0 = ncgrid[index].gridID;
+          int gridtype0 = gridInqType(gridID0);
+          if ( gridtype0 == GRID_GAUSSIAN_REDUCED )
+            {
+              size_t dimlen0 = (size_t)gridInqSize(gridID0);
+
+              if ( dimlen == dimlen0 )
+                {
+                  dimID = ncgrid[index].xdimID;
+                  break;
+                }
+              iz++;
+            }
+        }
+    }
+
+  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;
+        }
+
+      char axisname[7] = "rgridX";
+      if ( iz == 0 ) axisname[5] = '\0';
+      else           sprintf(&axisname[5], "%1d", iz+1);
+
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+
+      cdf_def_dim(fileID, axisname, dimlen, &dimID);
+
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
+    }
+
+  ncgrid[gridindex].gridID = gridID;
+  ncgrid[gridindex].xdimID = dimID;
+}
+
+static
+void cdfDefGdim(stream_t *streamptr, int gridID, int gridindex)
+{
+  ncgrid_t *ncgrid = streamptr->ncgrid;
+  int iz = 0;
+  int dimID = CDI_UNDEFID;
+
+  size_t dimlen = (size_t)gridInqSize(gridID);
+
+  if ( gridInqYsize(gridID) == 0 )
+    for ( int index = 0; index < gridindex; index++ )
+      {
+        if ( ncgrid[index].xdimID != CDI_UNDEFID )
+          {
+            int gridID0 = ncgrid[index].gridID;
+            int gridtype0 = gridInqType(gridID0);
+            if ( gridtype0 == GRID_GENERIC )
+              {
+                size_t dimlen0 = (size_t)gridInqSize(gridID0);
+                if ( dimlen == dimlen0 )
+                  {
+                    dimID = ncgrid[index].xdimID;
+                    break;
+                  }
+                else
+                  iz++;
+              }
+          }
+      }
+
+  if ( gridInqXsize(gridID) == 0 )
+    for ( int index = 0; index < gridindex; index++ )
+      {
+        if ( ncgrid[index].ydimID != CDI_UNDEFID )
+          {
+            int gridID0 = ncgrid[index].gridID;
+            int gridtype0 = gridInqType(gridID0);
+            if ( gridtype0 == GRID_GENERIC )
+              {
+                size_t dimlen0 = (size_t)gridInqSize(gridID0);
+                if ( dimlen == dimlen0 )
+                  {
+                    dimID = ncgrid[index].ydimID;
+                    break;
+                  }
+                else
+                  iz++;
+              }
+          }
+      }
+
+  if ( dimID == CDI_UNDEFID )
+    {
+      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;
+    }
+
+  ncgrid[gridindex].gridID = gridID;
+  ncgrid[gridindex].xdimID = dimID;
+}
+
+static
+void cdfDefGridReference(stream_t *streamptr, int gridID)
+{
+  int fileID  = streamptr->fileID;
+  int number = gridInqNumber(gridID);
+  if ( number > 0 )
+    cdf_put_att_int(fileID, NC_GLOBAL, "number_of_grid_used", NC_INT, 1, &number);
+
+  const char *gridfile = gridInqReferencePtr(gridID);
+  if ( gridfile && gridfile[0] != 0 )
+    cdf_put_att_text(fileID, NC_GLOBAL, "grid_file_uri", strlen(gridfile), gridfile);
+}
+
+static
+void cdfDefGridUUID(stream_t *streamptr, int gridID)
+{
+  unsigned char uuidOfHGrid[CDI_UUID_SIZE];
+
+  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);
+        }
+    }
+}
+
+static
+void cdfDefZaxisUUID(stream_t *streamptr, int zaxisID)
+{
+  unsigned char uuidOfVGrid[CDI_UUID_SIZE];
+  zaxisInqUUID(zaxisID, uuidOfVGrid);
+
+  if ( uuidOfVGrid[0] != 0 )
+    {
+      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);
+        }
+    }
+}
+
+static
+void cdfDefUnstructured(stream_t *streamptr, int gridID, int gridindex)
+{
+  int dimID = CDI_UNDEFID;
+  int ncxvarid = CDI_UNDEFID, ncyvarid = CDI_UNDEFID;
+  int ncbxvarid = CDI_UNDEFID, ncbyvarid = CDI_UNDEFID, ncavarid = CDI_UNDEFID;
+  int nvdimID = CDI_UNDEFID;
+  nc_type xtype = (nc_type)cdfDefDatatype(gridInqPrec(gridID), streamptr->filetype);
+  ncgrid_t *ncgrid = streamptr->ncgrid;
+
+  int fileID  = streamptr->fileID;
+
+  size_t dimlen = (size_t)gridInqSize(gridID);
+
+  for ( int index = 0; index < gridindex; index++ )
+    {
+      if ( ncgrid[index].xdimID != CDI_UNDEFID )
+        {
+          int gridID0 = ncgrid[index].gridID;
+          int gridtype0 = gridInqType(gridID0);
+          if ( gridtype0 == GRID_UNSTRUCTURED )
+            {
+              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 = ncgrid[index].xdimID;
+                    ncxvarid = ncgrid[index].xvarID;
+                    ncyvarid = ncgrid[index].yvarID;
+                    ncavarid = ncgrid[index].avarID;
+		    break;
+		  }
+            }
+        }
+    }
+
+  if ( dimID == CDI_UNDEFID )
+    {
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+      {
+        char xdimname[CDI_MAX_NAME+3];
+        xdimname[0] = 0;
+        cdiGridInqKeyStr(gridID, CDI_KEY_XDIMNAME, CDI_MAX_NAME, xdimname);
+        if ( xdimname[0] == 0 ) strcpy(xdimname, "ncells");
+        dimID = checkDimName(fileID, dimlen, xdimname);
+        if ( dimID == CDI_UNDEFID ) cdf_def_dim(fileID, xdimname, dimlen, &dimID);
+      }
+
+      size_t nvertex = (size_t)gridInqNvertex(gridID);
+      if ( nvertex > 0 )
+        {
+          char vdimname[CDI_MAX_NAME+3];
+          vdimname[0] = 0;
+          cdiGridInqKeyStr(gridID, CDI_KEY_VDIMNAME, CDI_MAX_NAME, vdimname);
+          if ( vdimname[0] == 0 ) strcpy(vdimname, "vertices");
+          nvdimID = checkDimName(fileID, nvertex, vdimname);
+          if ( nvdimID == CDI_UNDEFID ) cdf_def_dim(fileID, vdimname, nvertex, &nvdimID);
+        }
+
+      cdfDefGridReference(streamptr, gridID);
+
+      cdfDefGridUUID(streamptr, gridID);
+
+      if ( gridInqXvalsPtr(gridID) )
+        {
+          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, 1, &dimID, &ncxvarid);
+          cdfGridCompress(fileID, ncxvarid, (int)dimlen, streamptr->filetype, streamptr->comptype);
+
+          cdfPutGridStdAtts(fileID, ncxvarid, gridID, 'X', &gridInqsX);
+
+          if ( gridInqXboundsPtr(gridID) && nvdimID != CDI_UNDEFID )
+            {
+              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);
+            }
+        }
+
+      if ( gridInqYvalsPtr(gridID) )
+        {
+          char yaxisname[CDI_MAX_NAME];
+          gridInqYname(gridID, yaxisname);
+          checkGridName(yaxisname, fileID);
+          cdf_def_var(fileID, yaxisname, xtype, 1, &dimID, &ncyvarid);
+          cdfGridCompress(fileID, ncyvarid, (int)dimlen, streamptr->filetype, streamptr->comptype);
+
+          cdfPutGridStdAtts(fileID, ncyvarid, gridID, 'Y', &gridInqsY);
+
+          if ( gridInqYboundsPtr(gridID) && nvdimID != CDI_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_put_att_text(fileID, ncyvarid, "bounds", yaxisnameLen + sizeof (bndsName), yaxisname);
+            }
+        }
+
+      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";
+
+          cdf_def_var(fileID, yaxisname_, xtype, 1, &dimID, &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);
+        }
+
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
+
+      if ( ncxvarid  != CDI_UNDEFID ) cdf_put_var_double(fileID, ncxvarid,  gridInqXvalsPtr(gridID));
+      if ( ncbxvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncbxvarid, gridInqXboundsPtr(gridID));
+      if ( ncyvarid  != CDI_UNDEFID ) cdf_put_var_double(fileID, ncyvarid,  gridInqYvalsPtr(gridID));
+      if ( ncbyvarid != CDI_UNDEFID ) cdf_put_var_double(fileID, ncbyvarid, gridInqYboundsPtr(gridID));
+      if ( ncavarid  != CDI_UNDEFID ) cdf_put_var_double(fileID, ncavarid,  gridInqAreaPtr(gridID));
+    }
+
+  ncgrid[gridindex].gridID = gridID;
+  ncgrid[gridindex].xdimID = dimID;
+  ncgrid[gridindex].xvarID = ncxvarid;
+  ncgrid[gridindex].yvarID = ncyvarid;
+  ncgrid[gridindex].avarID = ncavarid;
+}
+
+struct attTxtTab2
+{
+  const char *attName, *attVal;
+  size_t valLen;
+};
+
+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;
+        }
+
+      int fileID = streamptr->fileID;
+
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+
+      int ncdimid, ncdimid2 = -1;
+      int hyaiid, hybiid, hyamid = -1, hybmid = -1;
+
+      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);
+        }
+
+      streamptr->vct.ilev   = ilev;
+      streamptr->vct.mlev   = mlev;
+      streamptr->vct.mlevID = ncdimid;
+      streamptr->vct.ilevID = ncdimid2;
+
+      {
+        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);
+      }
+
+      {
+        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);
+      }
+
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
+
+      const double *vctptr = zaxisInqVctPtr(zaxisID);
+
+      cdf_put_var_double(fileID, hyaiid, vctptr);
+      cdf_put_var_double(fileID, hybiid, vctptr+ilev);
+
+      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);
+        }
+    }
+}
+
+static
+void cdf_def_vct_cf(stream_t *streamptr, int zaxisID, int nclevID, int ncbndsID, int p0status, double p0value)
+{
+  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;
+      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;
+        }
+
+      int fileID = streamptr->fileID;
+
+      if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+
+      int dimIDs[2];
+      dimIDs[0] = nclevID;
+      dimIDs[1] = ncbndsID;
+
+      streamptr->vct.mlev   = mlev;
+      streamptr->vct.ilev   = ilev;
+      streamptr->vct.mlevID = nclevID;
+      streamptr->vct.ilevID = nclevID;
+
+      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);
+
+      {
+        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 ( ncbndsID != -1 )
+        {
+          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);
+          }
+        }
+
+      cdf_enddef(fileID);
+      streamptr->ncmode = 2;
+
+      int vctsize = zaxisInqVctSize(zaxisID);
+      double vct[vctsize];
+      zaxisInqVct(zaxisID, vct);
+
+      if ( p0status == 0 && IS_NOT_EQUAL(p0value,0) )
+        for ( int i = 0; i < vctsize/2; ++i ) vct[i] /= p0value;
+
+      double tarray[ilev*2];
+
+      if ( ncbndsID != -1 )
+        {
+          for ( int i = 0; i < mlev; ++i )
+            {
+              tarray[2*i  ] = vct[i];
+              tarray[2*i+1] = vct[i+1];
+            }
+          cdf_put_var_double(fileID, hyaiid, tarray);
+
+          for ( int i = 0; i < mlev; ++i )
+            {
+              tarray[2*i  ] = vct[ilev+i];
+              tarray[2*i+1] = vct[ilev+i+1];
+            }
+          cdf_put_var_double(fileID, hybiid, tarray);
+        }
+
+      for ( int i = 0; i < mlev; ++i )
+        tarray[i] = (vct[i] + vct[i+1]) * 0.5;
+      cdf_put_var_double(fileID, hyamid, tarray);
+
+      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);
+    }
+}
+
+struct attTxtTab { const char *txt; size_t txtLen; };
+
+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 ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+
+  int ncvarid;
+  cdf_def_dim(fileID, axisname, dimlen, dimID);
+  cdf_def_var(fileID, axisname, (nc_type) xtype, 1, dimID,  &ncvarid);
+  *ncvaridp = 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);
+  }
+
+  cdf_enddef(fileID);
+  streamptr->ncmode = 2;
+
+  cdf_put_var_double(fileID, ncvarid, zaxisInqLevelsPtr(zaxisID));
+
+  cdf_def_vct_echam(streamptr, zaxisID);
+
+  if ( *dimID == CDI_UNDEFID )
+    {
+      if ( type == ZAXIS_HYBRID )
+        streamptr->zaxisID[zaxisindex] = streamptr->vct.mlevID;
+      else
+        streamptr->zaxisID[zaxisindex] = streamptr->vct.ilevID;
+    }
+}
+
+static
+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)
+{
+  int fileID = streamptr->fileID;
+  if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+
+  char psname[CDI_MAX_NAME]; psname[0] = 0;
+  cdiZaxisInqKeyStr(zaxisID, CDI_KEY_PSNAME, CDI_MAX_NAME, psname);
+  if ( psname[0] == 0 ) strcpy(psname, "ps");
+
+  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");
+
+  int ncvarid;
+  cdf_def_dim(fileID, axisname, dimlen, dimID);
+  cdf_def_var(fileID, axisname, (nc_type) xtype, 1, dimID,  &ncvarid);
+  *ncvaridp = ncvarid;
+
+  {
+    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);
+
+    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);
+        }
+    }
+
+  cdf_enddef(fileID);
+  streamptr->ncmode = 2;
+
+  cdf_put_var_double(fileID, ncvarid, levels);
+
+  if ( p0varid != CDI_UNDEFID ) cdf_put_var_double(fileID, p0varid, &p0value);
+
+  if ( ncbvarid != CDI_UNDEFID )
+    {
+      double zbounds[2*dimlen];
+      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);
+    }
+
+  cdf_def_vct_cf(streamptr, zaxisID, *dimID, nvdimID, p0status, p0value);
+
+  if ( *dimID == CDI_UNDEFID )
+    {
+      if ( type == ZAXIS_HYBRID )
+        streamptr->zaxisID[zaxisindex] = streamptr->vct.mlevID;
+      else
+        streamptr->zaxisID[zaxisindex] = streamptr->vct.ilevID;
+    }
+}
+
+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)
+{
+  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);
+}
+
+static
+void cdfDefZaxis(stream_t *streamptr, int zaxisID)
+{
+  /*  char zaxisname0[CDI_MAX_NAME]; */
+  char axisname[CDI_MAX_NAME];
+  int dimID = CDI_UNDEFID;
+  int dimIDs[2];
+  int ncvarid = CDI_UNDEFID, ncbvarid = CDI_UNDEFID;
+  int nvdimID = CDI_UNDEFID;
+  int xtype = NC_DOUBLE;
+
+  if ( zaxisInqPrec(zaxisID) == CDI_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);
+
+  bool is_scalar = false;
+  if ( dimlen == 1 )
+    {
+      is_scalar = zaxisInqScalar(zaxisID) > 0;
+      if ( !is_scalar && CDI_cmor_mode )
+        {
+          is_scalar = true;
+          zaxisDefScalar(zaxisID);
+        }
+    }
+
+  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 == CDI_UNDEFID )
+    {
+      checkZaxisName(axisname, fileID, vlistID, zaxisID, nzaxis);
+
+      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 ( 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);
+
+          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);
+        }
+      else
+        {
+          dimID = checkDimName(fileID, dimlen, dimname);
+
+          if ( streamptr->ncmode == 2 ) cdf_redef(fileID);
+
+          if ( ndims && dimID == CDI_UNDEFID ) cdf_def_dim(fileID, dimname, dimlen, &dimID);
+
+          if ( zaxisInqLevels(zaxisID, NULL) )
+            {
+              cdf_def_var(fileID, axisname, (nc_type) xtype, ndims, &dimID, &ncvarid);
+
+              cdfPutGridStdAtts(fileID, ncvarid, zaxisID, 'Z', &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 != CDI_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);
+                    }
+                }
+
+              cdfDefineAttributes(zaxisID, CDI_GLOBAL, fileID, ncvarid);
+            }
+
+          cdf_enddef(fileID);
+          streamptr->ncmode = 2;
+
+          if ( zaxisInqLevels(zaxisID, NULL) )
+            {
+              cdf_put_var_double(fileID, ncvarid, zaxisInqLevelsPtr(zaxisID));
+
+              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];
+                    }
+
+                  cdf_put_var_double(fileID, ncbvarid, zbounds);
+                }
+
+              if ( ndims == 0 ) streamptr->nczvarID[zaxisindex] = ncvarid;
+            }
+        }
+    }
+
+  if ( dimID != CDI_UNDEFID )
+    streamptr->zaxisID[zaxisindex] = dimID;
+}
+
+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] )
+    {
+      char gmapvarname[CDI_MAX_NAME]; gmapvarname[0] = 0;
+      cdiGridInqKeyStr(gridID, CDI_KEY_MAPPING, CDI_MAX_NAME, gmapvarname);
+
+      int fileID = streamptr->fileID;
+      cdf_redef(fileID);
+
+      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);
+
+      cdf_enddef(fileID);
+
+      if ( ncerrcode == NC_NOERR )
+        {
+          int dummy = 1;
+          cdf_put_var_int(fileID, ncvarid, &dummy);
+        }
+    }
+}
+
+static
+void cdfDefGrid(stream_t *streamptr, int gridID, int gridindex)
+{
+  if ( streamptr->ncgrid[gridindex].xdimID != CDI_UNDEFID ) return;
+
+  int gridtype = gridInqType(gridID);
+  int size     = gridInqSize(gridID);
+
+  if ( CDI_Debug )
+    Message("gridtype = %d  size = %d", gridtype, size);
+
+  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 ( gridInqYsize(gridID) > 0 /*&& gridInqYvals(gridID, NULL) > 0*/ )
+                {
+                  cdfDefYaxis(streamptr, gridID, gridindex, 1);
+                  ly = true;
+                }
+
+              if ( !lx && !ly ) cdfDefGdim(streamptr, gridID, gridindex);
+            }
+        }
+      else
+        {
+          int ndims = 1;
+          if ( gridtype == GRID_LONLAT && size == 1 && gridInqHasDims(gridID) == FALSE )
+            ndims = 0;
+
+          if ( gridInqXsize(gridID) > 0 ) cdfDefXaxis(streamptr, gridID, gridindex, ndims);
+          if ( gridInqYsize(gridID) > 0 ) cdfDefYaxis(streamptr, gridID, gridindex, ndims);
+
+          cdf_def_mapping(streamptr, gridID);
+        }
+    }
+  else if ( gridtype == GRID_CURVILINEAR )
+    {
+      cdfDefCurvilinear(streamptr, gridID, gridindex);
+    }
+  else if ( gridtype == GRID_UNSTRUCTURED )
+    {
+      cdfDefUnstructured(streamptr, gridID, gridindex);
+    }
+  else if ( gridtype == GRID_GAUSSIAN_REDUCED )
+    {
+      cdfDefRgrid(streamptr, gridID, gridindex);
+    }
+  else if ( gridtype == GRID_SPECTRAL )
+    {
+      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_LCC )
+    {
+      cdfDefLcc(streamptr, gridID);
+    }
+  */
+  else
+    {
+      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 index = 0;
+  int vlistID = streamptr->vlistID;
+  if ( vlistID == CDI_UNDEFID )
+    Error("Internal problem! vlist undefined for streamptr %p", streamptr);
+
+  int ngrids = vlistNgrids(vlistID);
+  if ( 2*ngrids > MAX_GRIDS_PS ) Error("Internaal problem! Too many grids per stream (max=%d)\n", MAX_GRIDS_PS);
+  for ( index = 0; index < 2*ngrids; ++index )
+    {
+      streamptr->ncgrid[index].gridID = CDI_UNDEFID;
+      streamptr->ncgrid[index].xdimID = CDI_UNDEFID;
+      streamptr->ncgrid[index].ydimID = CDI_UNDEFID;
+      streamptr->ncgrid[index].xvarID = CDI_UNDEFID;
+      streamptr->ncgrid[index].yvarID = CDI_UNDEFID;
+      streamptr->ncgrid[index].avarID = CDI_UNDEFID;
+    }
+
+  for ( index = 0; index < ngrids; ++index )
+    {
+      int gridID = vlistGrid(vlistID, index);
+      cdfDefGrid(streamptr, gridID, index);
+    }
+  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);
+    }
+}
+
+#endif
+
+/*
+ * Local Variables:
+ * c-file-style: "Java"
+ * c-basic-offset: 2
+ * indent-tabs-mode: nil
+ * show-trailing-whitespace: t
+ * require-trailing-newline: t
+ * End:
+ */
diff --git a/libcdi/src/stream_cgribex.c b/libcdi/src/stream_cgribex.c
index 474e331..5173931 100644
--- a/libcdi/src/stream_cgribex.c
+++ b/libcdi/src/stream_cgribex.c
@@ -36,17 +36,17 @@ 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_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:   { 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_SPECTRAL:   { gridtype = GRID_SPECTRAL;   break; }
+    case  GRIB1_GTYPE_GME:        { gridtype = GRID_GME;        break; }
     }
 
   return gridtype;
@@ -55,9 +55,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
@@ -143,10 +141,11 @@ 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 ( streamptr->unreduced && gridtype == GRID_GAUSSIAN_REDUCED && iret != -801 )
     {
@@ -161,197 +160,184 @@ 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->x.size = ISEC2_NumLon;
+      grid->y.size = ISEC2_NumLat;
+      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 ( 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;
+        if ( grid->x.size > 1 )
+          {
+            bool recompinc = true;
 
-                if ( ISEC2_LastLon < ISEC2_FirstLon && ISEC2_LastLon < 0 ) ISEC2_LastLon += 360000;
+            if ( ISEC2_LastLon < ISEC2_FirstLon && ISEC2_LastLon < 0 ) ISEC2_LastLon += 360000;
 
-		if ( ISEC2_ResFlag && ISEC2_LonIncr > 0 )
+            if ( ISEC2_ResFlag && ISEC2_LonIncr > 0 )
+              {
+                if ( abs(ISEC2_LastLon - (ISEC2_FirstLon+ISEC2_LonIncr*(grid->x.size-1))) <= 2 )
                   {
-                    if ( abs(ISEC2_LastLon - (ISEC2_FirstLon+ISEC2_LonIncr*(grid->xsize-1))) <= 2 )
-                      {
-                        recompinc = false;
-                        grid->xinc = ISEC2_LonIncr * 0.001;
-                      }
+                    recompinc = false;
+                    grid->x.inc = ISEC2_LonIncr * 0.001;
                   }
+              }
 
-		/* recompute xinc if necessary */
-                if ( recompinc ) grid->xinc = (ISEC2_LastLon - ISEC2_FirstLon) * 0.001 / (grid->xsize-1);
+            /* recompute xinc if necessary */
+            if ( recompinc ) grid->x.inc = (ISEC2_LastLon - ISEC2_FirstLon) * 0.001 / (grid->x.size-1);
 
-		/* correct xinc if necessary */
-		if ( ISEC2_FirstLon == 0 && ISEC2_LastLon > 354000 && ISEC2_LastLon < 360000 )
-		  {
-		    double xinc = 360. / grid->xsize;
-
-		    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 )
+            /* 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 )
                   {
-                    if ( abs(ISEC2_LastLat - (ISEC2_FirstLat+ISEC2_LatIncr*(grid->ysize-1))) <= 2 )
-                      {
-                        recompinc = false;
-                        grid->yinc = ISEC2_LatIncr * 0.001;
-                      }
+                    grid->x.inc = xinc;
+                    if ( CDI_Debug ) Message("set xinc to %g", grid->x.inc);
                   }
-
-		/* 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;
-
-		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;
+              }
+          }
+        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 ( ISEC2_ResFlag && 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 )
+    {
+      grid->np      = ISEC2_NumPar;
+      grid->size    = ISEC4_NumValues;
+      grid->rowlon  = ISEC2_RowLonPtr;
+      grid->nrowlon = ISEC2_NumLat;
+      grid->y.size  = 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 ( ISEC2_ResFlag && 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 ( ISEC2_ResFlag && 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;
       }
     }
-
-  grid->isRotated = FALSE;
-  if ( cgribexGetIsRotated(isec2) )
+  else if ( gridtype == GRID_LCC )
     {
-      grid->isRotated = TRUE;
-      grid->ypole     = - ISEC2_LatSP*0.001;
-      grid->xpole     =   ISEC2_LonSP*0.001 - 180;
-      grid->angle     = - FSEC2_RotAngle;
+      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;
+
+      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->x.flag = 0;
+      grid->y.flag = 0;
     }
+  else if ( gridtype == GRID_SPECTRAL )
+    {
+      grid->size  = ISEC4_NumValues;
+      grid->trunc = ISEC2_PentaJ;
+      if ( ISEC2_RepMode == 2 )
+        grid->lcomplex = 1;
+      else
+        grid->lcomplex = 0;
+    }
+  else if ( gridtype == GRID_GME )
+    {
+      grid->size  = 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  = ISEC4_NumValues;
+      grid->x.size = 0;
+      grid->y.size = 0;
+    }
+  else
+    {
+      Error("Unsupported grid type: %s", gridNamePtr(gridtype));
+    }
+
+  grid->type = gridtype;
+  grid->projtype = projtype;
+}
 
-  grid->xvals = NULL;
-  grid->yvals = NULL;
-  grid->type  = gridtype;
+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;
@@ -364,23 +350,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 )
     {
@@ -391,11 +377,18 @@ 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
     Free(gridptr);
 
-  int zaxistype = grib1ltypeToZaxisType(ISEC1_LevelType);
+  int zaxistype = grib1ltypeToZaxisType(leveltype);
 
   if ( zaxistype == ZAXIS_HYBRID || zaxistype == ZAXIS_HYBRID_HALF )
     {
@@ -405,13 +398,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;
@@ -431,10 +424,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);
@@ -442,8 +434,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);
@@ -451,10 +442,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);
@@ -531,11 +519,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)
@@ -573,16 +560,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++ )
+            vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
 	}
     }
 }
 
 
-int cgribexScanTimestep1(stream_t * streamptr)
+int cgribexScanTimestep1(stream_t *streamptr)
 {
   double fsec2[512], fsec3[2], *fsec4 = NULL;
   int lmv = 0, iret = 0;
@@ -591,13 +576,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;
@@ -605,7 +590,7 @@ int cgribexScanTimestep1(stream_t * streamptr)
   bool fcast = false;
   int vlistID;
   int comptype;
-  long unzipsize;
+  size_t unzipsize;
   char paramstr[32];
   int nskip = cdiSkipRecords;
 
@@ -649,24 +634,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);
 	    }
 	}
@@ -678,17 +663,14 @@ 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 = CDI_DATATYPE_PACK;
 
       if ( nrecs == 0 )
 	{
@@ -701,9 +683,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;
@@ -794,7 +776,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);
@@ -810,15 +792,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;
@@ -872,22 +854,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);
 	    }
 	}
@@ -900,10 +882,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);
 
@@ -948,7 +927,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++ )
 	{
@@ -992,7 +971,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 )
 	{
@@ -1052,13 +1031,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;
@@ -1066,7 +1045,7 @@ int cgribexScanTimestep(stream_t * streamptr)
   int taxisID = -1;
   int rindex, nrecs = 0;
   int nrecs_scanned;
-  long unzipsize;
+  size_t unzipsize;
   char paramstr[32];
 
   /*
@@ -1118,15 +1097,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 )
 	    {
@@ -1138,9 +1117,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);
 		}
 	    }
@@ -1153,10 +1132,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);
 
@@ -1203,7 +1179,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++ )
 	    {
@@ -1260,7 +1236,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++;
 	}
@@ -1616,8 +1592,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));
 
@@ -1655,13 +1631,29 @@ 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!");
-	}
+      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 && gridInqProjType(gridID) == CDI_PROJ_RLL )
+    {
       gridtype = GRID_LONLAT;
-      lcurvi = true;
+      lrotated = true;
     }
 
   ISEC2_Reduced  = FALSE;
@@ -1676,11 +1668,10 @@ 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;
@@ -1696,25 +1687,19 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
 	  }
 	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);
 	      }
 	  }
 
-	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));
 	  }
@@ -1756,14 +1741,16 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
 
         ISEC2_ResFlag = ( ISEC2_LatIncr == 0 || ISEC2_LonIncr == 0 ) ? 0 : 128;
 
-	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;
@@ -1782,7 +1769,7 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
 	int xsize = gridInqXsize(gridID),
           ysize = gridInqYsize(gridID);
 
-	gridInqLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
+	gridInqParamLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
 		   &projflag, &scanflag);
 
 	ISEC2_GridType = GRIB1_GTYPE_LCC;
@@ -1829,10 +1816,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;
@@ -1850,8 +1839,17 @@ void cgribexDefGrid(int *isec1, int *isec2, double *fsec2, int *isec4, int gridI
 }
 
 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;
 
@@ -1861,8 +1859,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");
@@ -1880,9 +1877,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:
@@ -1892,26 +1887,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 )
@@ -1933,32 +1919,24 @@ 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);
+	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);
 
-	char units[128];
 	zaxisInqUnits(zaxisID, units);
         if ( units[1] == 'm' && !units[2] )
           {
@@ -1967,32 +1945,21 @@ 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;
@@ -2002,26 +1969,16 @@ void cgribexDefLevel(int *isec1, int *isec2, double *fsec2, int zaxisID, int lev
         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:
diff --git a/libcdi/src/stream_ext.c b/libcdi/src/stream_ext.c
index 048de70..8035949 100644
--- a/libcdi/src/stream_ext.c
+++ b/libcdi/src/stream_ext.c
@@ -13,22 +13,15 @@
 #include "cdi.h"
 #include "cdi_int.h"
 #include "stream_ext.h"
-#include "stream_fcommon.h"
 #include "varscan.h"
 #include "datetime.h"
 #include "extra.h"
 #include "vlist.h"
+#include "exse.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;
@@ -40,36 +33,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
@@ -90,7 +71,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);
 
@@ -99,55 +80,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)
 {
-  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);
+  int size    = gridInqSize(gridID);
 
   streamptr->numvals += size;
 
   *nmiss = 0;
   if ( vlistInqVarNumber(vlistID, varID) == CDI_REAL )
     {
-      for ( i = 0; i < size; i++ )
+      for ( int i = 0; i < size; i++ )
 	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
 	  {
 	    data[i] = missval;
@@ -156,7 +128,7 @@ void extReadRecord(stream_t *streamptr, double *data, int *nmiss)
     }
   else
     {
-      for ( i = 0; i < 2*size; i+=2 )
+      for ( int i = 0; i < 2*size; i+=2 )
 	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
 	  {
 	    data[i] = missval;
@@ -174,21 +146,18 @@ 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;
+  int gridID = streamptr->record->gridID;
   header[3] = gridInqSize(gridID);
 
+  extrec_t *extp = (extrec_t*) streamptr->record->exsep;
   extDefDatatype(streamptr->record->prec, &extp->prec, &extp->number);
-
   extDefHeader(extp, header);
 }
 
@@ -219,11 +188,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);
   /*
@@ -243,46 +210,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;
+  int nrecs = 0;
   while ( TRUE )
     {
       recpos = fileGetPos(fileID);
-      status = extRead(fileID, extp);
+      int status = extRead(fileID, extp);
       if ( status != 0 )
 	{
 	  streamptr->ntsteps = 1;
@@ -292,13 +249,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 )
 	{
@@ -334,17 +291,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;
@@ -384,43 +341,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 =
@@ -429,10 +376,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;
@@ -442,13 +389,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 )
 	{
@@ -459,7 +406,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;
@@ -469,7 +417,7 @@ int extScanTimestep2(stream_t *streamptr)
 	    {
 	      if ( streamptr->tsteps[tsID].records[recID].used )
 		{
-		  nextstep = TRUE;
+		  nextstep = true;
 		}
 	      else
 		{
@@ -482,7 +430,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;
@@ -501,14 +449,14 @@ 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 )
 	{
@@ -534,40 +482,32 @@ int extScanTimestep2(stream_t *streamptr)
       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;
   /*
@@ -594,14 +534,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;
@@ -611,13 +551,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;
@@ -673,131 +613,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);
-}
-
-
-void extReadVarDP(stream_t *streamptr, int varID, double *data, int *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)++;
-	  }
-    }
+  return nrecs;
 }
 
 
 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;
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d  levID = %d", streamptr->self, varID, levID);
+
   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);
+  int 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);
 
@@ -806,7 +669,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 ( int i = 0; i < gridsize; i++ )
 	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
 	  {
 	    data[i] = missval;
@@ -815,7 +678,7 @@ void extReadVarSliceDP(stream_t *streamptr, int varID, int levID, double *data,
     }
   else
     {
-      for ( i = 0; i < 2*gridsize; i+=2 )
+      for ( int i = 0; i < 2*gridsize; i+=2 )
 	if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
 	  {
 	    data[i] = missval;
@@ -825,88 +688,59 @@ 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, int *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 = (size_t) 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);
+  header[3] = gridInqSize(vlistInqVarGrid(vlistID, varID));
 
+  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);
 }
 
+
+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 nlevs    = (size_t) zaxisInqSize(vlistInqVarZaxis(vlistID, varID));
+
+  for ( size_t levID = 0;  levID < nlevs; levID++ )
+    extWriteVarSliceDP(streamptr, varID, levID, &data[levID*gridsize]);
+}
+
 #endif /* HAVE_LIBEXTRA */
+
 /*
  * Local Variables:
  * c-file-style: "Java"
diff --git a/libcdi/src/stream_fcommon.c b/libcdi/src/stream_fcommon.c
deleted file mode 100644
index 482a031..0000000
--- a/libcdi/src/stream_fcommon.c
+++ /dev/null
@@ -1,42 +0,0 @@
-#include <stdlib.h>
-
-#include "cdi_int.h"
-#include "dmemory.h"
-#include "file.h"
-#include "stream_fcommon.h"
-
-
-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"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
diff --git a/libcdi/src/stream_fcommon.h b/libcdi/src/stream_fcommon.h
deleted file mode 100644
index f021f86..0000000
--- a/libcdi/src/stream_fcommon.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef STREAM_FCOMMON_H
-#define STREAM_FCOMMON_H
-
-#ifndef  _CDI_INT_H
-#include "cdi_int.h"
-#endif
-
-void streamFCopyRecord(stream_t *streamptr2, stream_t *streamptr1,
-                       const char *container_name);
-
-#endif
-/*
- * Local Variables:
- * c-file-style: "Java"
- * c-basic-offset: 2
- * indent-tabs-mode: nil
- * show-trailing-whitespace: t
- * require-trailing-newline: t
- * End:
- */
diff --git a/libcdi/src/stream_grb.c b/libcdi/src/stream_grb.c
index 3900e8a..5d15934 100644
--- a/libcdi/src/stream_grb.c
+++ b/libcdi/src/stream_grb.c
@@ -27,6 +27,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;
@@ -166,14 +167,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;
@@ -207,7 +208,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)
@@ -228,7 +229,7 @@ int grbScanTimestep2(stream_t * streamptr)
 #if  defined  (HAVE_LIBCGRIBEX)
   int filetype = streamptr->filetype;
 
-  if ( filetype == FILETYPE_GRB )
+  if ( filetype == CDI_FILETYPE_GRB )
     {
       status = cgribexScanTimestep2(streamptr);
     }
@@ -252,7 +253,7 @@ int grbScanTimestep(stream_t * streamptr)
   filetype  = streamptr->filetype;
 
 #if  defined  (HAVE_LIBCGRIBEX)
-  if ( filetype == FILETYPE_GRB )
+  if ( filetype == CDI_FILETYPE_GRB )
     {
       status = cgribexScanTimestep(streamptr);
     }
@@ -329,7 +330,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;
diff --git a/libcdi/src/stream_gribapi.c b/libcdi/src/stream_gribapi.c
index 8189a76..79ed40b 100644
--- a/libcdi/src/stream_gribapi.c
+++ b/libcdi/src/stream_gribapi.c
@@ -20,10 +20,10 @@
 #include "subtype.h"
 
 
-#  include "cgribex.h"      /* gribGetSize, gribRead, gribGetZip, GRIB1_LTYPE_99 */
-#  include "gribapi.h"
+#include "cgribex.h"      /* gribGetSize, gribRead, gribGetZip, GRIB1_LTYPE_99 */
+#include "gribapi.h"
 
-#  include <grib_api.h>
+#include <grib_api.h>
 
 extern int cdiInventoryMode;
 
@@ -276,9 +276,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;
@@ -430,11 +430,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);
 
@@ -459,12 +459,24 @@ 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 =  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);
+    }
 
   int zaxistype = gribapiGetZaxisType(gribEditionNumber(gh), leveltype1);
 
@@ -492,10 +504,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);
@@ -508,8 +517,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;
@@ -560,12 +569,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 )
@@ -577,10 +585,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);
@@ -588,12 +595,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);
@@ -603,16 +609,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);
@@ -627,7 +629,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;
@@ -680,7 +682,7 @@ 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;
 
@@ -693,34 +695,34 @@ 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 )
+      if( gribGetZip(recsize, *gribbuffer, outUnzipsize) > 0 )
         {
-          *outCompressionType = COMPRESS_SZIP;
-          ensureBufferSize((size_t)*outUnzipsize + 100, buffersize, gribbuffer);
+          *outCompressionType = CDI_COMPRESS_SZIP;
+          ensureBufferSize(*outUnzipsize + 100, buffersize, gribbuffer);
         }
       else
         {
-          *outCompressionType = COMPRESS_NONE;
+          *outCompressionType = CDI_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 )
         {
@@ -792,8 +794,8 @@ int gribapiScanTimestep1(stream_t * streamptr)
   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 )
         {
@@ -807,7 +809,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++;
@@ -1015,8 +1017,8 @@ int gribapiScanTimestep2(stream_t * streamptr)
     {
       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;
@@ -1028,9 +1030,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);
@@ -1236,8 +1238,8 @@ int gribapiScanTimestep(stream_t * streamptr)
 	{
 	  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;
@@ -1256,9 +1258,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);
@@ -1663,7 +1665,7 @@ 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
         {
@@ -1837,18 +1839,18 @@ struct gribApiMsg {
 };
 
 static struct gribApiMsg
-getGribApiCompTypeMsg(grib_handle *gh, int comptype, int gridsize)
+getGribApiCompTypeMsg(int comptype, int 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;
@@ -1869,6 +1871,8 @@ static
 void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype, bool lieee, int datatype, int nmiss, int gcinit)
 {
   UNUSED(nmiss);
+  bool lrotated = false;
+  bool lcurvi = false;
 
   int gridtype = gridInqType(gridID);
   int gridsize = gridInqSize(gridID);
@@ -1904,13 +1908,29 @@ 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!");
-	}
+      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 && gridInqProjType(gridID) == CDI_PROJ_RLL )
+    {
       gridtype = GRID_LONLAT;
+      lrotated = true;
     }
 
   if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN )
@@ -1919,8 +1939,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);
@@ -1940,43 +1959,39 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
 	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);
 
 	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));
@@ -1995,26 +2010,20 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
 	  }
 	else
 	  {
-	    if ( nlon == 0 )
-	      {
-		nlon = 1;
-	      }
+	    if ( nlon == 0 ) nlon = 1;
 	    else
 	      {
-		xfirst = gridInqXval(gridID,      0);
-		xlast  = gridInqXval(gridID, nlon-1);
+		xfirst = gridInqXval(gridID, 0);
+                xlast  = gridInqXval(gridID, (lcurvi ? nlon*nlat : nlon) - 1);
 		xinc   = gridInqXinc(gridID);
 	      }
 	  }
 
-	if ( nlat == 0 )
-	  {
-	    nlat = 1;
-	  }
+	if ( nlat == 0 ) nlat = 1;
 	else
 	  {
-	    yfirst = gridInqYval(gridID,      0);
-	    ylast  = gridInqYval(gridID, nlat-1);
+	    yfirst = gridInqYval(gridID, 0);
+            ylast  = gridInqYval(gridID, (lcurvi ? nlon*nlat : nlat) - 1);
 	    yinc   = gridInqYinc(gridID);
 	  }
 
@@ -2032,10 +2041,7 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
           if ( yfirst < ylast ) jscan = 1;
           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);
@@ -2047,67 +2053,38 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
 	    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;
-	    */
 	  }
-	/*
-	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);
-	  }
+            double xpole = 0, ypole = 0, angle = 0;
+            gridInqParamRLL(gridID, &xpole, &ypole, &angle);
 
-	/* East -> West */
-	//if ( ISEC2_LastLon < ISEC2_FirstLon ) ISEC2_ScanFlag += 128;
-
-	/* South -> North */
-	//if ( ISEC2_LastLat > ISEC2_FirstLat ) ISEC2_ScanFlag += 64;
+            xpole =  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);
 
 	break;
       }
@@ -2119,8 +2096,8 @@ void gribapiDefGrid(int editionNumber, grib_handle *gh, int gridID, int comptype
 	int xsize = gridInqXsize(gridID);
 	int ysize = gridInqYsize(gridID);
 
-	gridInqLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
-		   &projflag, &scanflag);
+	gridInqParamLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
+                        &projflag, &scanflag);
 
         static const char mesg[] = "lambert";
         size_t len = sizeof (mesg) -1;
@@ -2192,17 +2169,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);
 
-        if ( comptype == COMPRESS_SZIP )
+        if ( comptype == CDI_COMPRESS_SZIP )
           {
             static const char mesg[] = "grid_ccsds";
             size_t len = sizeof (mesg) -1;
@@ -2238,7 +2217,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;
@@ -2279,7 +2258,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;
     }
@@ -2324,34 +2303,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) )
     {
@@ -2392,7 +2354,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] )
               {
@@ -2440,13 +2401,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;
       }
@@ -2479,7 +2436,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 )
           {
@@ -2492,7 +2448,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;
 
@@ -2519,7 +2475,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
 
@@ -2614,7 +2569,7 @@ 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[];
 
   int param    = vlistInqVarParam(vlistID, varID);
@@ -2628,8 +2583,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 )
@@ -2654,7 +2612,7 @@ size_t gribapiEncode(int varID, int levelID, int vlistID, int gridID, int zaxisI
 
   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 )
@@ -2665,7 +2623,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)
diff --git a/libcdi/src/stream_history.c b/libcdi/src/stream_history.c
index b06ea79..ff2ef1b 100644
--- a/libcdi/src/stream_history.c
+++ b/libcdi/src/stream_history.c
@@ -13,10 +13,10 @@ 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 ( streamptr->filetype == CDI_FILETYPE_NC  ||
+       streamptr->filetype == CDI_FILETYPE_NC2 ||
+       streamptr->filetype == CDI_FILETYPE_NC4 ||
+       streamptr->filetype == CDI_FILETYPE_NC4C )
     {
       char *histstring;
       size_t len;
@@ -45,10 +45,10 @@ 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 ( streamptr->filetype == CDI_FILETYPE_NC  ||
+       streamptr->filetype == CDI_FILETYPE_NC2 ||
+       streamptr->filetype == CDI_FILETYPE_NC4 ||
+       streamptr->filetype == CDI_FILETYPE_NC4C )
     {
       size = cdfInqHistorySize(streamptr);
     }
@@ -64,10 +64,10 @@ 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 ( streamptr->filetype == CDI_FILETYPE_NC  ||
+       streamptr->filetype == CDI_FILETYPE_NC2 ||
+       streamptr->filetype == CDI_FILETYPE_NC4 ||
+       streamptr->filetype == CDI_FILETYPE_NC4C )
     {
       cdfInqHistoryString(streamptr, history);
     }
diff --git a/libcdi/src/stream_ieg.c b/libcdi/src/stream_ieg.c
index 20c08f9..ea209be 100644
--- a/libcdi/src/stream_ieg.c
+++ b/libcdi/src/stream_ieg.c
@@ -19,51 +19,35 @@
 #include "varscan.h"
 #include "datetime.h"
 #include "ieg.h"
-#include "stream_fcommon.h"
 #include "stream_ieg.h"
 #include "vlist.h"
+#include "exse.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
@@ -83,7 +67,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 )
@@ -93,51 +77,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)
 {
-  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);
+  int size    = gridInqSize(gridID);
 
   streamptr->numvals += size;
 
   *nmiss = 0;
-  for ( i = 0; i < size; i++ )
+  for ( int i = 0; i < size; i++ )
     if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
       {
 	data[i] = missval;
@@ -197,19 +173,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);
 
@@ -260,21 +235,25 @@ 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);
+  int xsize = gridInqXsize(gridID);
+  int ysize = gridInqYsize(gridID);
 
+  if ( gridtype == GRID_GENERIC )
+    {
       if ( (ysize == 32  || ysize == 48 || ysize == 64 ||
 	    ysize == 96  || ysize == 160) &&
 	   (xsize == 2*ysize || xsize == 1) )
@@ -298,39 +277,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;
@@ -341,8 +313,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)   = xsize;
+      IEG_G_NumLat(gdb)   = 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);
@@ -352,7 +324,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) = ysize/2;
       else
 	{
 	  IEG_G_LatIncr(gdb) = (int)lround(yinc*resfac);
@@ -368,15 +340,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
@@ -393,19 +365,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");
@@ -417,36 +395,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
@@ -460,11 +428,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 )
@@ -472,81 +439,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:
@@ -566,68 +495,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;
+  int fileID = streamptr->fileID;
+  int gridsize = gridInqSize(record->gridID);
 
-  gridsize = gridInqSize(gridID);
-
-  refval = data[0];
-  for ( i = 1; i < gridsize; i++ )
+  double refval = data[0];
+  for ( int i = 1; i < gridsize; i++ )
     if ( data[i] < refval ) refval = data[i];
 
   iegp->refval = refval;
 
   iegDefDataDP(iegp, data);
-
   iegWrite(fileID, iegp);
 }
 
@@ -635,7 +551,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);
@@ -661,18 +576,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;
+  int xsize = IEG_G_NumLon(gdb);
+  int ysize = 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;
@@ -680,78 +597,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);
     }
@@ -761,6 +665,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);
@@ -772,8 +677,7 @@ 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
@@ -783,9 +687,8 @@ void iegCmpRecord(stream_t *streamptr, int tsID, int recID, off_t position, int
 {
   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");
@@ -805,17 +708,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);
-
-  rmonth  = IEG_P_Month(pdb);
-  rday    = IEG_P_Day(pdb);
+  int ryear   = IEG_P_Year(pdb);
+  int rmonth  = IEG_P_Month(pdb);
+  int 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;
 
@@ -826,51 +727,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;
+  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
@@ -878,6 +767,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 )
@@ -889,12 +779,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};
@@ -914,17 +805,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;
@@ -935,7 +826,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 )
@@ -953,7 +844,7 @@ void iegScanTimestep1(stream_t *streamptr)
       if ( taxis->vdate == 0 && taxis->vtime == 0 )
 	{
 	  streamptr->ntsteps = 0;
-	  for ( varID = 0; varID < streamptr->nvars; varID++ )
+	  for ( int varID = 0; varID < streamptr->nvars; varID++ )
 	    {
 	      vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
 	    }
@@ -964,67 +855,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
@@ -1032,6 +911,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 )
@@ -1043,17 +923,18 @@ 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
 		{
@@ -1068,7 +949,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;
@@ -1081,24 +962,24 @@ 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;
+	  int varID = streamptr->tsteps[tsID].records[recID].varID;
           vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
 	}
       else
@@ -1120,43 +1001,31 @@ int iegScanTimestep2(stream_t *streamptr)
       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 )
@@ -1170,9 +1039,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);
@@ -1182,28 +1052,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
@@ -1211,11 +1082,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 )
 	    {
@@ -1229,7 +1101,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,
@@ -1267,113 +1139,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);
-}
-
-
-void iegReadVarDP(stream_t *streamptr, int varID, double *data, int *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)++;
-      }
+  return nrecs;
 }
 
 
 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;
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d  levID = %d", streamptr->self, varID, levID);
+
   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);
+  int 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);
@@ -1381,7 +1191,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 ( int i = 0; i < gridsize; i++ )
     if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
       {
 	data[i] = missval;
@@ -1390,101 +1200,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, int *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 = (size_t) 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;
 
-  param    = vlistInqVarParam(vlistID, varID);
+  int vlistID  = streamptr->vlistID;
+  int fileID   = streamptr->fileID;
+  int tsID     = streamptr->curTsID;
+  int gridID   = vlistInqVarGrid(vlistID, varID);
+  int zaxisID  = vlistInqVarZaxis(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(datatype);
+  iegp->dprec = iegDefDatatype(vlistInqVarDatatype(vlistID, varID));
 
-  for ( levID = 0;  levID < nlevs; levID++ )
-    {
-      iegDefLevel(iegp->ipdb, iegp->igdb, iegp->vct, zaxisID, levID);
+  int 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 ( int 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);
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
-  /* param = vlistInqVarParam(vlistID, varID); */
-  /* date = streamptr->tsteps[tsID].taxis.vdate; */
-  /* time = streamptr->tsteps[tsID].taxis.vtime; */
-  /* datasize = gridInqSize(gridID); */
-
-  datatype = vlistInqVarDatatype(vlistID, varID);
-
-  iegp->dprec = iegDefDatatype(datatype);
+  int vlistID = streamptr->vlistID;
+  size_t gridsize = (size_t) 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 */
diff --git a/libcdi/src/stream_read.c b/libcdi/src/stream_read.c
index c4e9d7f..b4e4971 100644
--- a/libcdi/src/stream_read.c
+++ b/libcdi/src/stream_read.c
@@ -34,15 +34,15 @@ int cdiStreamReadVar(int streamID, int varID, int memtype, void *data, int *nmis
   switch (filetype)
     {
 #if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
+    case CDI_FILETYPE_GRB:
+    case CDI_FILETYPE_GRB2:
       {
         grb_read_var(streamptr, varID, memtype, data, nmiss);
 	break;
       }
 #endif
 #if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
+    case CDI_FILETYPE_SRV:
       {
         if ( memtype == MEMTYPE_FLOAT ) return 1;
         srvReadVarDP(streamptr, varID, (double *)data, nmiss);
@@ -50,7 +50,7 @@ int cdiStreamReadVar(int streamID, int varID, int memtype, void *data, int *nmis
       }
 #endif
 #if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
+    case CDI_FILETYPE_EXT:
       {
         if ( memtype == MEMTYPE_FLOAT ) return 1;
         extReadVarDP(streamptr, varID, (double *)data, nmiss);
@@ -58,7 +58,7 @@ int cdiStreamReadVar(int streamID, int varID, int memtype, void *data, int *nmis
       }
 #endif
 #if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
+    case CDI_FILETYPE_IEG:
       {
         if ( memtype == MEMTYPE_FLOAT ) return 1;
         iegReadVarDP(streamptr, varID, (double *)data, nmiss);
@@ -66,10 +66,10 @@ int cdiStreamReadVar(int streamID, int varID, int memtype, void *data, int *nmis
       }
 #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:
       {
         cdf_read_var(streamptr, varID, memtype, data, nmiss);
 	break;
@@ -160,15 +160,15 @@ int cdiStreamReadVarSlice(int streamID, int varID, int levelID, int memtype, voi
   switch (filetype)
     {
 #if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
+    case CDI_FILETYPE_GRB:
+    case CDI_FILETYPE_GRB2:
       {
         grb_read_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
 	break;
       }
 #endif
 #if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
+    case CDI_FILETYPE_SRV:
       {
         if ( memtype == MEMTYPE_FLOAT ) return 1;
         srvReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
@@ -176,7 +176,7 @@ int cdiStreamReadVarSlice(int streamID, int varID, int levelID, int memtype, voi
       }
 #endif
 #if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
+    case CDI_FILETYPE_EXT:
       {
         if ( memtype == MEMTYPE_FLOAT ) return 1;
         extReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
@@ -184,7 +184,7 @@ int cdiStreamReadVarSlice(int streamID, int varID, int levelID, int memtype, voi
       }
 #endif
 #if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
+    case CDI_FILETYPE_IEG:
       {
         if ( memtype == MEMTYPE_FLOAT ) return 1;
         iegReadVarSliceDP(streamptr, varID, levelID, (double *)data, nmiss);
@@ -192,10 +192,10 @@ int cdiStreamReadVarSlice(int streamID, int varID, int levelID, int memtype, voi
       }
 #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:
       {
         cdf_read_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
         break;
@@ -289,34 +289,34 @@ int stream_read_record(int streamID, int memtype, void *data, int *nmiss)
   switch (streamptr->filetype)
     {
 #if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
+    case CDI_FILETYPE_GRB:
+    case CDI_FILETYPE_GRB2:
       grb_read_record(streamptr, memtype, data, nmiss);
       break;
 #endif
 #if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
+    case CDI_FILETYPE_SRV:
       if ( memtype == MEMTYPE_FLOAT ) return 1;
       srvReadRecord(streamptr, (double *)data, nmiss);
       break;
 #endif
 #if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
+    case CDI_FILETYPE_EXT:
       if ( memtype == MEMTYPE_FLOAT ) return 1;
       extReadRecord(streamptr, (double *)data, nmiss);
       break;
 #endif
 #if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
+    case CDI_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:
+    case CDI_FILETYPE_NC:
+    case CDI_FILETYPE_NC2:
+    case CDI_FILETYPE_NC4:
+    case CDI_FILETYPE_NC4C:
       cdf_read_record(streamptr, memtype, data, nmiss);
       break;
 #endif
diff --git a/libcdi/src/stream_record.c b/libcdi/src/stream_record.c
index ea43cd1..c41d54a 100644
--- a/libcdi/src/stream_record.c
+++ b/libcdi/src/stream_record.c
@@ -86,18 +86,19 @@ int recordNewEntry(stream_t *streamptr, int tsID)
 static
 void cdiInitRecord(stream_t *streamptr)
 {
-  streamptr->record = (Record *) Malloc(sizeof(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 *record = (Record *) Malloc(sizeof(Record));
+  streamptr->record = record;
+
+  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;
 }
 
 
@@ -170,43 +171,44 @@ 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:
       if ( streamptr->accessmode == 0 ) cdfEndDef(streamptr);
       cdfDefRecord(streamptr);
       break;
@@ -224,24 +226,24 @@ 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:
           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:
+              // Warning("Streams have different file types (%s -> %s)!", strfiletype(filetype1), strfiletype(filetype2));
               filetype = filetype2;
               break;
             }
@@ -249,37 +251,37 @@ 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:
       cdfCopyRecord(streamptr2, streamptr1);
       break;
 #endif
@@ -295,7 +297,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;
@@ -339,10 +340,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;
@@ -373,6 +372,33 @@ void cdi_create_records(stream_t *streamptr, int tsID)
 	}
     }
 }
+
+#include "file.h"
+
+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"
diff --git a/libcdi/src/stream_srv.c b/libcdi/src/stream_srv.c
index 52752b0..3aa74f0 100644
--- a/libcdi/src/stream_srv.c
+++ b/libcdi/src/stream_srv.c
@@ -16,51 +16,35 @@
 #include "varscan.h"
 #include "datetime.h"
 #include "service.h"
-#include "stream_fcommon.h"
 #include "stream_srv.h"
 #include "vlist.h"
+#include "exse.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 == DATATYPE_FLT64 ) prec = DOUBLE_PRECISION;
-  else                              prec = SINGLE_PRECISION;
+  if ( datatype != CDI_DATATYPE_FLT32 && datatype != CDI_DATATYPE_FLT64 )
+    datatype = CDI_DATATYPE_FLT32;
 
-  return (prec);
+  return (datatype == CDI_DATATYPE_FLT64) ? EXSE_DOUBLE_PRECISION : EXSE_SINGLE_PRECISION;
 }
 
 /* not used
@@ -90,25 +74,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)
 {
-  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;
@@ -119,21 +96,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);
+  int size    = gridInqSize(gridID);
 
   streamptr->numvals += size;
 
   *nmiss = 0;
-  for ( i = 0; i < size; i++ )
+  for ( int i = 0; i < size; i++ )
     if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
       {
 	data[i] = missval;
@@ -150,20 +129,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 gridID = record->gridID;
   int xsize = gridInqXsize(gridID),
-    ysize = gridInqYsize(gridID);
+      ysize = gridInqYsize(gridID);
   if ( xsize == 0 || ysize == 0 )
     {
       xsize = gridInqSize(gridID);
@@ -179,7 +159,6 @@ void srvDefRecord(stream_t *streamptr)
   header[7] = 0;
 
   int datatype = record->prec;
-
   srvp->dprec = srvDefDatatype(datatype);
 
   srvDefHeader(srvp, header);
@@ -209,14 +188,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);
   /*
@@ -241,8 +218,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
@@ -262,7 +238,6 @@ void srvScanTimestep1(stream_t *streamptr)
     taxis = &streamptr->tsteps[tsID].taxis;
   }
 
-
   int fileID = streamptr->fileID;
 
   int nrecs = 0;
@@ -368,54 +343,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;
@@ -425,12 +389,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 )
 	{
@@ -441,17 +405,18 @@ 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
 		{
@@ -464,7 +429,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;
@@ -477,24 +442,24 @@ 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;
+	  int varID = streamptr->tsteps[tsID].records[recID].varID;
           vlistDefVarTsteptype(vlistID, varID, TSTEP_CONSTANT);
 	}
       else
@@ -516,40 +481,33 @@ int srvScanTimestep2(stream_t *streamptr)
       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 )
@@ -575,14 +533,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;
@@ -592,14 +550,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;
@@ -651,128 +609,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);
-}
-
-
-void srvReadVarDP(stream_t *streamptr, int varID, double *data, int *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;
-
-  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)++;
-      }
+  return nrecs;
 }
 
 
 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;
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d  levID = %d", streamptr->self, varID, levID);
+
   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;
+  double missval = vlistInqVarMissval(vlistID, varID);
+  int gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
+  int tsid     = streamptr->curTsID;
 
-  if ( CDI_Debug )
-    Message("nlevs = %d gridID = %d gridsize = %d",
-	     nlevs, gridID, gridsize);
-
-  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 ( int i = 0; i < gridsize; i++ )
     if ( DBL_IS_EQUAL(data[i], missval) || DBL_IS_EQUAL(data[i], (float)missval) )
       {
 	data[i] = missval;
@@ -781,105 +672,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, int *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);
+  if ( CDI_Debug ) Message("streamID = %d  varID = %d", streamptr->self, varID);
 
-  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);
-
-  for ( levID = 0; levID < nlevs; levID++ )
-    {
-      level = zaxisInqLevel(zaxisID, levID);
+  int vlistID = streamptr->vlistID;
+  size_t gridsize = (size_t) 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;
-
-  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("streamID = %d  varID = %d  levID = %d", streamptr->self, varID, 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);
+  int xsize = gridInqXsize(gridID);
+  int ysize = gridInqYsize(gridID);
   if ( xsize == 0 || ysize == 0 )
     {
       xsize = gridInqSize(gridID);
@@ -894,8 +719,9 @@ void srvWriteVarSliceDP(stream_t *streamptr, int varID, int levID, const double
   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);
@@ -903,7 +729,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 = (size_t) 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"
diff --git a/libcdi/src/stream_var.c b/libcdi/src/stream_var.c
index 79e0c6b..d349b00 100644
--- a/libcdi/src/stream_var.c
+++ b/libcdi/src/stream_var.c
@@ -2,10 +2,7 @@
 #  include "config.h"
 #endif
 
-#include <string.h>
-
 #include "dmemory.h"
-#include "error.h"
 
 #include "cdi.h"
 #include "cdi_int.h"
@@ -23,7 +20,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;
@@ -38,30 +35,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
     {
@@ -76,11 +67,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 )
 	{
@@ -89,8 +77,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;
@@ -98,8 +86,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;
 }
 
 
@@ -109,7 +98,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;
@@ -154,7 +143,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:
diff --git a/libcdi/src/stream_write.c b/libcdi/src/stream_write.c
index eef2129..21014e0 100644
--- a/libcdi/src/stream_write.c
+++ b/libcdi/src/stream_write.c
@@ -36,15 +36,15 @@ int cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data, i
   switch (filetype)
     {
 #if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
+    case CDI_FILETYPE_GRB:
+    case CDI_FILETYPE_GRB2:
       {
         grb_write_var(streamptr, varID, memtype, data, nmiss);
 	break;
       }
 #endif
 #if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
+    case CDI_FILETYPE_SRV:
       {
         if ( memtype == MEMTYPE_FLOAT ) return 1;
         srvWriteVarDP(streamptr, varID, (double *)data);
@@ -52,7 +52,7 @@ int cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data, i
       }
 #endif
 #if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
+    case CDI_FILETYPE_EXT:
       {
         if ( memtype == MEMTYPE_FLOAT ) return 1;
         extWriteVarDP(streamptr, varID, (double *)data);
@@ -60,7 +60,7 @@ int cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data, i
       }
 #endif
 #if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
+    case CDI_FILETYPE_IEG:
       {
         if ( memtype == MEMTYPE_FLOAT ) return 1;
         iegWriteVarDP(streamptr, varID, (double *)data);
@@ -68,10 +68,10 @@ int cdiStreamWriteVar_(int streamID, int varID, int memtype, const void *data, i
       }
 #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:
       {
         cdf_write_var(streamptr, varID, memtype, data, nmiss);
 	break;
@@ -105,8 +105,7 @@ The values are converted to the external data type of the variable, if necessary
 */
 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 (*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;
 
@@ -131,8 +130,7 @@ The values are converted to the external data type of the variable, if necessary
 */
 void streamWriteVarF(int streamID, int varID, const float *data, int nmiss)
 {
-  int (*myCdiStreamWriteVar_)(int streamID, int varID, int memtype,
-                              const void *data, int nmiss)
+  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;
   
@@ -172,15 +170,15 @@ int cdiStreamWriteVarSlice(int streamID, int varID, int levelID, int memtype, co
   switch (filetype)
     {
 #if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
+    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 FILETYPE_SRV:
+    case CDI_FILETYPE_SRV:
       {
         if ( memtype == MEMTYPE_FLOAT ) return 1;
         srvWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
@@ -188,7 +186,7 @@ int cdiStreamWriteVarSlice(int streamID, int varID, int levelID, int memtype, co
       }
 #endif
 #if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
+    case CDI_FILETYPE_EXT:
       {
         if ( memtype == MEMTYPE_FLOAT ) return 1;
         extWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
@@ -196,7 +194,7 @@ int cdiStreamWriteVarSlice(int streamID, int varID, int levelID, int memtype, co
       }
 #endif
 #if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
+    case CDI_FILETYPE_IEG:
       {
         if ( memtype == MEMTYPE_FLOAT ) return 1;
         iegWriteVarSliceDP(streamptr, varID, levelID, (double *)data);
@@ -204,10 +202,10 @@ int cdiStreamWriteVarSlice(int streamID, int varID, int levelID, int memtype, co
       }
 #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:
       cdf_write_var_slice(streamptr, varID, levelID, memtype, data, nmiss);
       break;
 #endif
@@ -275,22 +273,19 @@ 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)
+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)
+                                    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);
 }
 
 /* single image implementation */
-void
-cdiStreamWriteVarChunk_(int streamID, int varID, int memtype,
-                        const int rect[][2], const void *data, int nmiss)
+void cdiStreamWriteVarChunk_(int streamID, int varID, int memtype,
+                             const int rect[][2], const void *data, int nmiss)
 {
   if ( CDI_Debug ) Message("streamID = %d varID = %d", streamID, varID);
 
@@ -303,17 +298,17 @@ cdiStreamWriteVarChunk_(int streamID, int varID, int memtype,
   switch (filetype)
     {
 #if defined (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
+    case CDI_FILETYPE_GRB:
+    case CDI_FILETYPE_GRB2:
 #endif
 #if defined (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
+    case CDI_FILETYPE_SRV:
 #endif
 #if defined (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
+    case CDI_FILETYPE_EXT:
 #endif
 #if defined (HAVE_LIBIEG)
-    case FILETYPE_IEG:
+    case CDI_FILETYPE_IEG:
 #endif
 #if  defined (HAVE_LIBGRIB) || defined (HAVE_LIBSERVICE)      \
   || defined (HAVE_LIBEXTRA) || defined (HAVE_LIBIEG)
@@ -322,10 +317,10 @@ cdiStreamWriteVarChunk_(int streamID, int varID, int memtype,
       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:
       cdf_write_var_chunk(streamptr, varID, memtype, rect, data, nmiss);
       break;
 #endif
@@ -349,34 +344,34 @@ int stream_write_record(int streamID, int memtype, const void *data, int nmiss)
   switch (streamptr->filetype)
     {
 #if  defined  (HAVE_LIBGRIB)
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2:
+    case CDI_FILETYPE_GRB:
+    case CDI_FILETYPE_GRB2:
       grb_write_record(streamptr, memtype, data, nmiss);
       break;
 #endif
 #if  defined  (HAVE_LIBSERVICE)
-    case FILETYPE_SRV:
+    case CDI_FILETYPE_SRV:
       if ( memtype == MEMTYPE_FLOAT ) return 1;
       srvWriteRecord(streamptr, (const double *)data);
       break;
 #endif
 #if  defined  (HAVE_LIBEXTRA)
-    case FILETYPE_EXT:
+    case CDI_FILETYPE_EXT:
       if ( memtype == MEMTYPE_FLOAT ) return 1;
       extWriteRecord(streamptr, (const double *)data);
       break;
 #endif
 #if  defined  (HAVE_LIBIEG)
-    case FILETYPE_IEG:
+    case CDI_FILETYPE_IEG:
       if ( memtype == MEMTYPE_FLOAT ) return 1;
       iegWriteRecord(streamptr, (const double *)data);
       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:
       {
 	cdf_write_record(streamptr, memtype, data, nmiss);
 	break;
@@ -420,7 +415,7 @@ void streamWriteRecordF(int streamID, const float *data, int 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.
       stream_t *streamptr = stream_to_pointer(streamID);
-      int varID  = streamptr->record->varID;
+      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];
diff --git a/libcdi/src/table.c b/libcdi/src/table.c
index a3eb991..387afc7 100644
--- a/libcdi/src/table.c
+++ b/libcdi/src/table.c
@@ -10,8 +10,6 @@
 #include "cdi.h"
 #include "cdi_int.h"
 
-#undef  UNDEFID
-#define UNDEFID -1
 
 /*int TableDefine = 0; */ /* Define new table also if the entry already exist */
                           /* This is needed for createtable */
@@ -96,8 +94,8 @@ static void parTableInitEntry(int tableID)
   parTable[tableID].used    = 0;
   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;
 }
 
@@ -325,7 +323,7 @@ int tableRead(const char *tablefile)
   int lnr = 0;
   int id;
   char name[256], longname[256], units[256];
-  int tableID = UNDEFID;
+  int tableID = CDI_UNDEFID;
   int err;
   char *tablename;
   FILE *tablefp;
@@ -379,7 +377,7 @@ int tableRead(const char *tablefile)
 
 static int tableFromEnv(int modelID, int tablenum)
 {
-  int tableID = UNDEFID;
+  int tableID = CDI_UNDEFID;
   char tablename[256] = {'\0'};
   int tablenamefound = 0;
 
@@ -397,7 +395,7 @@ static int tableFromEnv(int modelID, int tablenum)
   else
     {
       int instID = modelInqInstitut(modelID);
-      if ( instID != UNDEFID )
+      if ( instID != CDI_UNDEFID )
 	{
           const char *instName;
 	  if ( (instName = institutInqNamePtr(instID)) )
@@ -434,7 +432,7 @@ static int tableFromEnv(int modelID, int tablenum)
       /* if (tablefile) printf("tableFile = %s\n", tablefile); */
 
       tableID = tableRead(tablefile);
-      if ( tableID != UNDEFID )
+      if ( tableID != CDI_UNDEFID )
 	{
 	  tableDefModelID(tableID, modelID);
 	  tableDefNum(tableID, tablenum);
@@ -449,8 +447,8 @@ static int tableFromEnv(int modelID, int tablenum)
 
 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();
@@ -472,7 +470,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);
     }
@@ -487,11 +485,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)) )
@@ -503,7 +501,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 )
@@ -514,9 +512,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 )
@@ -529,14 +527,14 @@ int tableInq(int modelID, int tablenum, const char *tablename)
 
 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();
 
@@ -618,7 +616,7 @@ void tableWrite(const char *ptfile, int tableID)
   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;
@@ -730,7 +728,7 @@ void tableFWriteC(FILE *ptfp, int tableID)
   char tablename[256];
 
 
-  if ( tableID == UNDEFID )
+  if ( tableID == CDI_UNDEFID )
     {
       Warning("parameter table ID undefined");
       return;
@@ -798,7 +796,7 @@ int tableInqParCode(int tableID, char *varname, int *code)
 {
   int err = 1;
 
-  if ( tableID != UNDEFID && varname != NULL )
+  if ( tableID != CDI_UNDEFID && varname != NULL )
     {
       int npars = parTable[tableID].npars;
       for ( int item = 0; item < npars; item++ )
@@ -835,7 +833,7 @@ int tableInqParName(int tableID, int code, char *varname)
 	    }
 	}
     }
-  else if ( tableID == UNDEFID )
+  else if ( tableID == CDI_UNDEFID )
     { }
   else
     Error("Invalid table ID %d", tableID);
@@ -848,7 +846,7 @@ const char *tableInqParNamePtr(int tableID, int code)
 {
   const char *name = NULL;
 
-  if ( tableID != UNDEFID )
+  if ( tableID != CDI_UNDEFID )
     {
       int npars = parTable[tableID].npars;
       for ( int item = 0; item < npars; item++ )
@@ -869,7 +867,7 @@ const char *tableInqParLongnamePtr(int tableID, int code)
 {
   const char *longname = NULL;
 
-  if ( tableID != UNDEFID )
+  if ( tableID != CDI_UNDEFID )
     {
       int npars = parTable[tableID].npars;
       for ( int item = 0; item < npars; item++ )
@@ -890,7 +888,7 @@ const char *tableInqParUnitsPtr(int tableID, int code)
 {
   const char *units = NULL;
 
-  if ( tableID != UNDEFID )
+  if ( tableID != CDI_UNDEFID )
     {
       int npars = parTable[tableID].npars;
       for ( int item = 0; item < npars; item++ )
@@ -909,12 +907,12 @@ const char *tableInqParUnitsPtr(int tableID, int code)
 
 int tableInqParLongname(int tableID, int code, char *longname)
 {
-  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++ )
@@ -936,12 +934,12 @@ int tableInqParLongname(int tableID, int code, char *longname)
 int tableInqParUnits(int tableID, int code, 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++ )
@@ -963,7 +961,7 @@ int tableInqParUnits(int tableID, int code, char *units)
 void tableInqPar(int tableID, int code, 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 npars = parTable[tableID].npars;
diff --git a/libcdi/src/taxis.c b/libcdi/src/taxis.c
index a0db8d5..2223932 100644
--- a/libcdi/src/taxis.c
+++ b/libcdi/src/taxis.c
@@ -112,7 +112,7 @@ const char *tunitNamePtr(int unitID)
   else
     name = Timeunits[0];
 
-  return (name);
+  return name;
 }
 
 #if 0
@@ -150,7 +150,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;
@@ -161,8 +162,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;
@@ -187,20 +188,19 @@ taxisNewEntry(cdiResH resH)
       reshReplace(resH, taxisptr, &taxisOps);
     }
 
-  return (taxisptr);
+  return taxisptr;
 }
 
 static
 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);
 }
 
@@ -248,8 +248,7 @@ taxisDefRtime(taxisID, 120000);
 */
 int taxisCreate(int taxistype)
 {
-  if ( CDI_Debug )
-    Message("taxistype: %d", taxistype);
+  if ( CDI_Debug ) Message("taxistype: %d", taxistype);
 
   taxisInit ();
 
@@ -258,10 +257,9 @@ 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)
@@ -303,11 +301,11 @@ 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;
 }
 
 
@@ -554,16 +552,14 @@ 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;
 }
 
 
@@ -571,9 +567,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);
     }
 }
@@ -582,7 +578,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();
 
@@ -629,8 +625,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;
 }
 
 
@@ -647,13 +642,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);
     }
 }
@@ -677,8 +672,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;
 }
 
 
@@ -695,13 +689,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);
     }
 }
@@ -733,7 +727,7 @@ int taxisInqRdate(int taxisID)
       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
     }
 
-  return (taxisptr->rdate);
+  return taxisptr->rdate;
 }
 
 /*
@@ -763,7 +757,7 @@ int taxisInqRtime(int taxisID)
       reshSetStatus(taxisID, &taxisOps, RESH_DESYNC_IN_USE);
     }
 
-  return (taxisptr->rtime);
+  return taxisptr->rtime;
 }
 
 /*
@@ -792,7 +786,7 @@ int taxisInqFdate(int taxisID)
       taxisptr->ftime = taxisptr->vtime;
     }
 
-  return (taxisptr->fdate);
+  return taxisptr->fdate;
 }
 
 /*
@@ -821,7 +815,7 @@ int taxisInqFtime(int taxisID)
       taxisptr->ftime = taxisptr->vtime;
     }
 
-  return (taxisptr->ftime);
+  return taxisptr->ftime;
 }
 
 /*
@@ -845,55 +839,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);
@@ -902,10 +896,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);
@@ -918,8 +912,6 @@ ptaxisDefLongname(taxis_t *taxisptr, const char *longname)
 static void
 cdiDecodeTimevalue(int timeunit, double timevalue, int *days, int *secs)
 {
-  static int lwarn = TRUE;
-
   *days = 0;
   *secs = 0;
 
@@ -964,10 +956,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;
 	}
     }
 }
@@ -975,8 +968,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;
@@ -1000,10 +991,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;
 	}
     }
 }
@@ -1067,28 +1059,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;
     }
 
-  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);
 
@@ -1097,7 +1085,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 )
     {
@@ -1106,17 +1094,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);
 
@@ -1140,39 +1126,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 )
     {
@@ -1212,16 +1194,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 )
@@ -1236,9 +1221,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);
         }
@@ -1251,22 +1237,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);
 
@@ -1355,7 +1338,7 @@ double cdiEncodeTimeval(int date, int time, taxis_t *taxis)
   else
     timevalue = vtime2timeval(date, time, taxis);
 
-  return (timevalue);
+  return timevalue;
 }
 
 
@@ -1371,6 +1354,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;
@@ -1435,13 +1419,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 );
 }
@@ -1488,12 +1472,12 @@ 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,
+       serializeGetSize((int)strlen(taxisptr->longname), CDI_DATATYPE_TXT,
                         context) : 0);
   return packBufferSize;
 }
@@ -1508,11 +1492,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();
 
@@ -1545,7 +1529,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;
     }
@@ -1555,7 +1539,7 @@ 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;
     }
@@ -1598,16 +1582,16 @@ taxisPack(void * voidP, void * packBuffer, int packBufferSize, int * packBufferP
   intBuffer[idx++] = taxisP->name ? (int)strlen(taxisP->name) : 0;
   intBuffer[idx++] = taxisP->longname ? (int)strlen(taxisP->longname) : 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);
 
 }
diff --git a/libcdi/src/taxis.h b/libcdi/src/taxis.h
index 78cf402..7f1f3ed 100644
--- a/libcdi/src/taxis.h
+++ b/libcdi/src/taxis.h
@@ -1,6 +1,8 @@
 #ifndef _TAXIS_H
 #define _TAXIS_H
 
+#include <stdbool.h>
+
 #ifndef RESOURCE_HANDLE_H
 #include "resource_handle.h"
 #endif
@@ -9,8 +11,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
@@ -21,15 +24,15 @@ 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;
 }
 taxis_t;
 
@@ -42,6 +45,7 @@ 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    taxisDestroyKernel(taxis_t *taxisptr);
diff --git a/libcdi/src/util.c b/libcdi/src/util.c
index cef54cf..8125f8e 100644
--- a/libcdi/src/util.c
+++ b/libcdi/src/util.c
@@ -30,6 +30,7 @@ void cdiPrintDatatypes(void)
            "+-------------+-------+\n"
            "| char        |   %3d |\n"
            "+-------------+-------+\n"
+           "| bool        |   %3d |\n"
            "| short       |   %3d |\n"
            "| int         |   %3d |\n"
            "| long        |   %3d |\n"
@@ -48,7 +49,7 @@ void cdiPrintDatatypes(void)
            "| FLT64       | %-9s |\n"
            "+-------------+-----------+\n"
            "\n  byte ordering is %s\n\n",
-           (int) sizeof(void *), (int) sizeof(char),
+           (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),
@@ -150,7 +151,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)
@@ -177,7 +178,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;
diff --git a/libcdi/src/varscan.c b/libcdi/src/varscan.c
index d89fa32..810bc3d 100644
--- a/libcdi/src/varscan.c
+++ b/libcdi/src/varscan.c
@@ -2,9 +2,6 @@
 #  include "config.h"
 #endif
 
-#include <stdbool.h>
-#include <string.h>
-#include <math.h>
 
 #include "cdi.h"
 #include "cdi_int.h"
@@ -18,9 +15,6 @@
 #include "subtype.h"
 
 
-#undef  UNDEFID
-#define UNDEFID -1
-
 static size_t Vctsize = 0;
 static double *Vct = NULL;
 
@@ -51,6 +45,7 @@ typedef struct
 
 typedef struct
 {
+  int            varID;
   int            param;
   int            prec;
   int            tsteptype;
@@ -74,7 +69,7 @@ typedef struct
   int            comptype;       // compression type
   int            complevel;      // compression level
   short          timave;
-  short          lmissval;
+  bool           lmissval;
   double         missval;
   char          *name;
   char          *stdname;
@@ -98,16 +93,16 @@ static vartable_t *vartable;
 static unsigned varTablesize = 0;
 static unsigned nvars = 0;
 
-
-static void
-paramInitEntry(unsigned varID, int param)
+static
+void paramInitEntry(unsigned varID, int param)
 {
+  vartable[varID].varID          = 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;
@@ -117,14 +112,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;
@@ -143,7 +138,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;
@@ -158,11 +153,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;
                 }
             }
         }
@@ -298,24 +293,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;
@@ -326,7 +321,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
@@ -374,7 +369,7 @@ paramNewEntry(int param)
     {
       vartable = (vartable_t *) Realloc(vartable, (size_t)(varTablesize *= 2)
                                         * sizeof (vartable_t));
-      for( unsigned i = varID; i < varTablesize; i++ )
+      for ( unsigned i = varID; i < varTablesize; i++ )
         {
           vartable[i].param = UNDEF_PARAM;
           vartable[i].opt_grib_kvpair      = NULL;
@@ -385,7 +380,7 @@ paramNewEntry(int param)
 
   paramInitEntry(varID, param);
 
-  return (varID);
+  return varID;
 }
 
 
@@ -422,6 +417,7 @@ int varInsertTileSubtype(vartable_t *vptr, const var_tile_t *tiles)
     subtypeDestroyPtr(subtype_ptr);
     return vptr->tiles->nentries - 1;
   }
+
   return CDI_UNDEFID;
 }
 
@@ -433,9 +429,9 @@ 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++;
       varID = paramNewEntry(param);
@@ -478,11 +474,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);
@@ -505,86 +502,91 @@ 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 )
+  /*
+  if ( streamptr->sortparam )
     {
-      param_t *varInfo = (param_t *) Malloc((size_t)nvars * sizeof (param_t));
+      struct paraminfo *varInfo = (struct paraminfo *) Malloc((size_t)nvars * sizeof(struct paraminfo));
 
       for ( unsigned varID = 0; varID < nvars; varID++ )
 	{
@@ -592,7 +594,7 @@ void cdi_generate_vars(stream_t *streamptr)
 	  varInfo[varID].param = vartable[varID].param;
 	  varInfo[varID].ltype = vartable[varID].ltype1;
 	}
-      qsort(varInfo, (size_t)nvars, sizeof(param_t), cmpparam);
+      qsort(varInfo, (size_t)nvars, sizeof(struct paraminfo), cmp_param);
       for ( unsigned varID = 0; varID < nvars; varID++ )
 	{
 	  varids[varID] = varInfo[varID].varid;
@@ -600,36 +602,39 @@ void cdi_generate_vars(stream_t *streamptr)
       Free(varInfo);
     }
 
+  if ( streamptr->sortname )
+    {
+      qsort(vartable, (size_t)nvars, sizeof(vartable_t), cmp_varname);
+    }
+  */
   for ( unsigned index = 0; index < nvars; 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",
@@ -640,7 +645,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))
@@ -649,32 +654,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]);
@@ -686,7 +690,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;
@@ -707,33 +711,34 @@ 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 *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, 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 )
         {
@@ -760,10 +765,10 @@ void cdi_generate_vars(stream_t *streamptr)
       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);
@@ -776,10 +781,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;
@@ -787,20 +790,20 @@ 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;
         }
       /* 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) )
 	    {
-	      if ( tableID != UNDEFID )
+	      if ( tableID != CDI_UNDEFID )
 		{
 		  strcpy(name, tableInqParNamePtr(cdiDefaultTableID, pnum));
 		  vlistDefVarName(vlistID, varID, name);
@@ -818,13 +821,13 @@ void cdi_generate_vars(stream_t *streamptr)
 	      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++ )
@@ -832,29 +835,18 @@ void cdi_generate_vars(stream_t *streamptr)
       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 )
@@ -889,50 +881,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 )
+                {
+                  char zlongname[CDI_MAX_NAME];
+                  zaxisInqLongname(zaxisID, zlongname);
+                  if ( zlongname[0] && strcmp(longname, zlongname) != 0 ) differ = true;
+                }
+              if ( units )
+                {
+                  char zunits[CDI_MAX_NAME];
+                  zaxisInqUnits(zaxisID, zunits);
+                  if ( zunits[0] && strcmp(units, zunits) != 0 ) differ = true;
+                }
+            }
 	}
     }
 
-  return (differ);
+  return differ;
 }
 
 struct varDefZAxisSearchState
@@ -940,7 +930,7 @@ struct varDefZAxisSearchState
   int resIDValue;
   int zaxistype;
   int nlevels;
-  int lbounds;
+  bool lbounds;
   const double *levels;
   const char *longname;
   const char *units;
@@ -952,9 +942,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;
@@ -964,7 +954,7 @@ varDefZAxisSearch(int id, void *res, void *data)
 }
 
 
-int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, int lbounds,
+int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, 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)
 {
@@ -972,9 +962,9 @@ int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, i
     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;
 
@@ -983,9 +973,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;
 	  }
       }
@@ -1010,7 +1000,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;
 	    }
     }
@@ -1020,7 +1010,7 @@ 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);
@@ -1030,9 +1020,9 @@ int varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, i
 	  if ( (zaxistype == ZAXIS_HYBRID || zaxistype == ZAXIS_HYBRID_HALF) && vctsize > 0 )
             zaxisDefVct(zaxisID, vctsize, vct);
 
-	  zaxisDefName(zaxisID, name);
-	  zaxisDefLongname(zaxisID, longname);
-	  zaxisDefUnits(zaxisID, units);
+	  if ( name && name[0] ) zaxisDefName(zaxisID, name);
+	  if ( longname && longname[0] ) zaxisDefLongname(zaxisID, longname);
+	  if ( units && units[0] ) zaxisDefUnits(zaxisID, units);
 	  zaxisDefPrec(zaxisID, prec);
 	  zaxisDefLtype(zaxisID, ltype1);
 	}
@@ -1041,20 +1031,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;
 }
 
@@ -1067,7 +1057,7 @@ void varDefCompLevel(int varID, int complevel)
 
 int varInqInst(int varID)
 {
-  return (vartable[varID].instID);
+  return vartable[varID].instID;
 }
 
 
@@ -1079,7 +1069,7 @@ void varDefInst(int varID, int instID)
 
 int varInqModel(int varID)
 {
-  return (vartable[varID].modelID);
+  return vartable[varID].modelID;
 }
 
 
@@ -1091,7 +1081,7 @@ void varDefModel(int varID, int modelID)
 
 int varInqTable(int varID)
 {
-  return (vartable[varID].tableID);
+  return vartable[varID].tableID;
 }
 
 
@@ -1125,10 +1115,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 */
     }
@@ -1201,7 +1191,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;
@@ -1223,9 +1213,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
 
diff --git a/libcdi/src/varscan.h b/libcdi/src/varscan.h
index c992a7f..5462492 100644
--- a/libcdi/src/varscan.h
+++ b/libcdi/src/varscan.h
@@ -15,7 +15,7 @@ void varAddRecord(int recID, int param, int gridID, int zaxistype, int lbounds,
 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,
+int  varDefZaxis(int vlistID, int zaxistype, int nlevels, const double *levels, 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);
 
@@ -38,7 +38,7 @@ 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);
 
-int  zaxisCompare(int zaxisID, int zaxistype, int nlevels, int lbounds, const double *levels, const char *longname, const char *units, int ltype);
+bool zaxisCompare(int zaxisID, int zaxistype, int nlevels, bool lbounds, const double *levels, const char *longname, const char *units, int ltype);
 
 #endif
 /*
diff --git a/libcdi/src/vlist.c b/libcdi/src/vlist.c
index f941413..6721087 100644
--- a/libcdi/src/vlist.c
+++ b/libcdi/src/vlist.c
@@ -12,7 +12,7 @@
 #include "namespace.h"
 #include "resource_handle.h"
 #include "vlist_var.h"
-#include "vlist_att.h"
+#include "cdi_att.h"
 
 #include "resource_unpack.h"
 #include "serialize.h"
@@ -47,8 +47,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);
@@ -57,7 +56,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;
 }
 
@@ -77,8 +76,8 @@ const
 resOps vlistOps = {
   (valCompareFunc)vlist_compare,
   (valDestroyFunc)vlist_delete,
-  (valPrintFunc)vlistPrintKernel
-  , vlistGetSizeP,
+  (valPrintFunc)vlistPrintKernel,
+  vlistGetSizeP,
   vlistPackP,
   vlistTxCode
 };
@@ -87,7 +86,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
@@ -109,7 +108,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;
 }
 
@@ -125,15 +124,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 );
 
@@ -146,9 +143,7 @@ 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;
@@ -210,7 +205,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
@@ -219,7 +214,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;
@@ -235,17 +230,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);
@@ -348,7 +344,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 )
     {
@@ -365,7 +361,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 )
             {
@@ -399,22 +395,21 @@ 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;
       if ( vlistptr->vars[varID].levinfo )
         {
           int nlevs = zaxisInqSize(vlistptr->vars[varID].zaxisID);
-          for ( levID = 0; levID < nlevs; levID++ )
+          for ( int levID = 0; levID < nlevs; levID++ )
             vlistptr->vars[varID].levinfo[levID].flag = FALSE;
         }
     }
@@ -426,7 +421,7 @@ struct vgzSearchState
   int resIDValue;
   int zaxistype;
   int nlevels;
-  int lbounds;
+  bool lbounds;
   const double *levels;
 };
 
@@ -437,7 +432,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;
@@ -446,27 +441,26 @@ 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)
 {
   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;
         }
     }
@@ -506,7 +500,7 @@ int vlist_generate_zaxis(int vlistID, int zaxistype, int nlevels, const double *
       vlistptr->nzaxis++;
     }
 
-  return (zaxisID);
+  return zaxisID;
 }
 
 /*
@@ -532,13 +526,12 @@ 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;
@@ -555,7 +548,7 @@ void vlistCopyFlag(int vlistID2, int vlistID1)
 
       vlistptr2->vars = vars2;
 
-      varID2 = 0;
+      int varID2 = 0;
       for ( int varID = 0; varID < nvars; varID++ )
 	if ( vars1[varID].flag )
 	  {
@@ -574,7 +567,7 @@ 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;
@@ -587,33 +580,41 @@ void vlistCopyFlag(int vlistID2, int vlistID1)
 	    if ( nlevs != nlevs2 )
 	      {
 		int nvct = 0;
+                double *levels = NULL;
 		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 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;
-                        levels[levID2++] = zaxisInqLevel(zaxisID, levID);
-                      }
-                }
-
-		int zaxisType = zaxisInqType(zaxisID);
-
-		if ( zaxisType == ZAXIS_HYBRID )
-		  {
-		    nvct = zaxisInqVctSize(zaxisID);
-		    vct  = zaxisInqVctPtr(zaxisID);
-		  }
+                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;
+                    }
+
+                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);
+                        }
+                  }
+
+                if ( zaxisType == ZAXIS_HYBRID )
+                  {
+                    nvct = zaxisInqVctSize(zaxisID);
+                    vct  = zaxisInqVctPtr(zaxisID);
+                  }
 
                 if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
                   {
@@ -621,12 +622,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 )
                         {
@@ -639,8 +640,8 @@ void vlistCopyFlag(int vlistID2, int vlistID1)
                   }
 
 		int zaxisID2 = vlist_generate_zaxis(vlistID2, zaxisType, nlevs2, levels, lbounds, ubounds, nvct, vct);
-		free(levels);
-                Free(lbounds);
+		if ( levels )  Free(levels);
+                if ( lbounds ) Free(lbounds);
 
                 zaxisInqName(zaxisID, ctemp);
                 zaxisDefName(zaxisID2, ctemp);
@@ -649,6 +650,8 @@ void vlistCopyFlag(int vlistID2, int vlistID1)
                 zaxisInqUnits(zaxisID, ctemp);
                 zaxisDefUnits(zaxisID2, ctemp);
 
+                if ( zaxisType == ZAXIS_GENERIC ) zaxisDefLtype(zaxisID2, zaxisInqLtype(zaxisID));
+
 		zaxisID = zaxisID2;
 		vars2[varID2].zaxisID = zaxisID2;
 	      }
@@ -738,7 +741,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);
@@ -822,11 +825,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;
@@ -842,30 +845,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;
               }
         }
 
@@ -896,29 +901,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;
@@ -926,7 +931,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;
@@ -938,7 +943,7 @@ int vlistNumber(int vlistID)
         }
     }
 
-  return (number);
+  return number;
 }
 
 /*
@@ -961,7 +966,7 @@ int vlistNgrids(int vlistID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  return (vlistptr->ngrids);
+  return vlistptr->ngrids;
 }
 
 /*
@@ -984,7 +989,7 @@ int vlistNzaxis(int vlistID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  return (vlistptr->nzaxis);
+  return vlistptr->nzaxis;
 }
 
 
@@ -992,7 +997,7 @@ int vlistNsubtypes(int vlistID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  return (vlistptr->nsubtypes);
+  return vlistptr->nsubtypes;
 }
 
 
@@ -1000,7 +1005,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);
@@ -1078,7 +1083,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,
@@ -1122,7 +1128,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;
@@ -1150,7 +1156,7 @@ int vlistInqTaxis(int vlistID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  return (vlistptr->taxisID);
+  return vlistptr->taxisID;
 }
 
 
@@ -1158,7 +1164,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);
@@ -1170,7 +1176,7 @@ int vlistInqTable(int vlistID)
 {
   vlist_t *vlistptr = vlist_to_pointer(vlistID);
 
-  return (vlistptr->tableID);
+  return vlistptr->tableID;
 }
 
 
@@ -1178,7 +1184,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);
@@ -1205,7 +1211,7 @@ int vlistInqInstitut(int vlistID)
       vlistDefInstitut(vlistID, instID);
     }
 
-  return (instID);
+  return instID;
 }
 
 
@@ -1213,7 +1219,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);
@@ -1241,7 +1247,7 @@ int vlistInqModel(int vlistID)
       vlistDefModel(vlistID, modelID);
     }
 
-  return (modelID);
+  return modelID;
 }
 
 
@@ -1257,7 +1263,7 @@ int vlistGridsizeMax(int vlistID)
       if ( gridsize > gridsizemax ) gridsizemax = gridsize;
     }
 
-  return (gridsizemax);
+  return gridsizemax;
 }
 
 
@@ -1269,7 +1275,7 @@ int vlistGrid(int vlistID, int index)
   if ( index < vlistptr->ngrids && index >= 0 )
     gridID = vlistptr->gridIDs[index];
 
-  return (gridID);
+  return gridID;
 }
 
 
@@ -1283,7 +1289,7 @@ int vlistGridIndex(int vlistID, int gridID)
 
   if ( index == vlistptr->ngrids ) index = -1;
 
-  return (index);
+  return index;
 }
 
 
@@ -1337,7 +1343,7 @@ int vlistZaxis(int vlistID, int index)
   if ( index < vlistptr->nzaxis && index >= 0 )
     zaxisID = vlistptr->zaxisIDs[index];
 
-  return (zaxisID);
+  return zaxisID;
 }
 
 
@@ -1351,7 +1357,7 @@ int vlistZaxisIndex(int vlistID, int zaxisID)
 
   if ( index == vlistptr->nzaxis ) index = -1;
 
-  return (index);
+  return index;
 }
 
 
@@ -1455,15 +1461,14 @@ int vlistHasTime(int vlistID)
         break;
       }
 
-  return (hastime);
+  return hastime;
 }
 
 enum {
   vlist_nints=6,
 };
 
-static int
-vlistTxCode ( void )
+static int vlistTxCode ( void )
 {
   return VLIST;
 }
@@ -1474,9 +1479,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;
@@ -1495,10 +1500,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);
@@ -1509,7 +1514,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);
@@ -1521,8 +1526,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,
@@ -1532,11 +1537,10 @@ void vlistUnpack(char * buf, int size, int *position, int originNamespace,
 
 void vlist_check_contents(int vlistID)
 {
-  int index, nzaxis, zaxisID;
+  int zaxisID;
+  int nzaxis = vlistNzaxis(vlistID);
 
-  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 )
@@ -1548,7 +1552,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);
diff --git a/libcdi/src/vlist.h b/libcdi/src/vlist.h
index 0179579..0b633a7 100644
--- a/libcdi/src/vlist.h
+++ b/libcdi/src/vlist.h
@@ -17,30 +17,8 @@
 
 #define VALIDMISS 1.e+303
 
-/*
- * 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;
-
-
-typedef struct {
-  size_t     nalloc;		/* number allocated >= nelems */
-  size_t     nelems;		/* length of the array */
-  cdi_att_t  value[MAX_ATTRIBUTES];
-} cdi_atts_t;
-
+#include "cdi_att.h"
+#include "grid.h"
 
 typedef struct
 {
@@ -69,15 +47,15 @@ ensinfo_t;
 
 typedef struct
 {
+  bool        isUsed;
   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         datatype;  /* CDI_DATATYPE_PACKX for GRIB data, else CDI_DATATYPE_FLT32 or CDI_DATATYPE_FLT64 */
   int         instID;
   int         modelID;
   int         tableID;
@@ -117,9 +95,9 @@ var_t;
 typedef struct
 {
   //set when a vlist is passed to streamDefVlist() to safeguard against modifications of the wrong vlist object
-  bool    immutable;
+  bool        immutable;
   //set if this vlist has been created by CDI itself, and must not be destroyed by the user, consequently
-  bool    internal;
+  bool        internal;
   int         self;
   int         nvars;        /* number of variables                */
   int         ngrids;
@@ -154,8 +132,7 @@ void     vlistDefVarTsteptype(int vlistID, int varID, int tsteptype);
 int      vlistInqVarMissvalUsed(int vlistID, int varID);
 int      vlistHasTime(int vlistID);
 
-int      vlistDelAtts(int vlistID, int varID);
-int      vlistCopyVarAtts(int vlistID1, int varID_1, int vlistID2, int varID_2);
+int      cdiDelAtts(int vlistID, int varID);
 
 void     vlistUnpack(char * buffer, int bufferSize, int * pos,
                      int originNamespace, void *context, int force_id);
@@ -168,29 +145,33 @@ int     vlistInqVarValidrange(int vlistID, int varID, double *validrange);
 
 void vlistInqVarDimorder(int vlistID, int varID, int (*outDimorder)[3]);
 
-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);
 
 void resize_opt_grib_entries(var_t *var, int nentries);
 
 
 
-static inline void
-vlistAdd2GridIDs(vlist_t *vlistptr, int gridID)
+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 ( vlistptr->gridIDs[index] == gridID ) break;
+      //      if ( gridIsEqual(vlistptr->gridIDs[index], gridID) ) break;
+    }
+
   if ( index == ngrids )
     {
-      if (ngrids >= MAX_GRIDS_PS)
+      if ( ngrids >= MAX_GRIDS_PS )
         Error("Internal limit exceeded: more than %d grids.", MAX_GRIDS_PS);
-      ++(vlistptr->ngrids);
       vlistptr->gridIDs[ngrids] = gridID;
+      ++(vlistptr->ngrids);
     }
 }
 
-static inline void
-vlistAdd2ZaxisIDs(vlist_t *vlistptr, int zaxisID)
+static inline
+void vlistAdd2ZaxisIDs(vlist_t *vlistptr, int zaxisID)
 {
   int index, nzaxis = vlistptr->nzaxis;
   for ( index = 0; index < nzaxis; index++ )
@@ -201,24 +182,25 @@ vlistAdd2ZaxisIDs(vlist_t *vlistptr, int zaxisID)
       if ( nzaxis >= MAX_ZAXES_PS )
 	Error("Internal limit exceeded: more than %d zaxis.", MAX_ZAXES_PS);
       vlistptr->zaxisIDs[nzaxis] = zaxisID;
-      vlistptr->nzaxis++;
+      ++(vlistptr->nzaxis);
     }
 }
 
-static inline void
-vlistAdd2SubtypeIDs(vlist_t *vlistptr, int subtypeID)
+static inline
+void vlistAdd2SubtypeIDs(vlist_t *vlistptr, int subtypeID)
 {
   if ( subtypeID == CDI_UNDEFID ) return;
 
   int index, nsubs = vlistptr->nsubtypes;
   for ( index = 0; index < nsubs; index++ )
-    if (vlistptr->subtypeIDs[index] == subtypeID ) break;
+    if ( vlistptr->subtypeIDs[index] == subtypeID ) break;
+
   if ( index == nsubs )
     {
-      if (nsubs >= MAX_SUBTYPES_PS)
+      if ( nsubs >= MAX_SUBTYPES_PS )
         Error("Internal limit exceeded: more than %d subs.", MAX_SUBTYPES_PS);
-      ++(vlistptr->nsubtypes);
       vlistptr->subtypeIDs[nsubs] = subtypeID;
+      ++(vlistptr->nsubtypes);
     }
 }
 
diff --git a/libcdi/src/vlist_att.h b/libcdi/src/vlist_att.h
deleted file mode 100644
index c42b364..0000000
--- a/libcdi/src/vlist_att.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef VLIST_ATT_H
-#define VLIST_ATT_H
-
-#ifdef HAVE_CONFIG_H
-#include "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:
- */
diff --git a/libcdi/src/vlist_var.c b/libcdi/src/vlist_var.c
index 12b63f0..9b5b78e 100644
--- a/libcdi/src/vlist_var.c
+++ b/libcdi/src/vlist_var.c
@@ -10,7 +10,7 @@
 #include "vlist.h"
 #include "vlist_var.h"
 #include "resource_handle.h"
-#include "vlist_att.h"
+#include "cdi_att.h"
 #include "namespace.h"
 #include "serialize.h"
 #include "error.h"
@@ -54,7 +54,7 @@ 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;
@@ -68,18 +68,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).
@@ -88,8 +83,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
     {
@@ -104,7 +99,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;
@@ -112,9 +107,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)
@@ -134,12 +129,12 @@ void vlistCheckVarID(const char *caller, int vlistID, int varID)
 
 int vlistDefVarTiles(int vlistID, int gridID, int zaxisID, int tsteptype, int tilesetID)
 {
-  vlist_t *vlistptr = vlist_to_pointer(vlistID);
   if ( CDI_Debug )
     Message("gridID = %d  zaxisID = %d  tsteptype = %d", gridID, zaxisID, tsteptype);
 
   int varID = vlistvarNewEntry(vlistID);
 
+  vlist_t *vlistptr = vlist_to_pointer(vlistID);
   vlistptr->nvars++;
   vlistptr->vars[varID].gridID    = gridID;
   vlistptr->vars[varID].zaxisID   = zaxisID;
@@ -158,7 +153,8 @@ 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;
 }
 
 /*
@@ -317,7 +313,7 @@ int vlistInqVarGrid(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].gridID);
+  return vlistptr->vars[varID].gridID;
 }
 
 /*
@@ -343,7 +339,7 @@ int vlistInqVarZaxis(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].zaxisID);
+  return vlistptr->vars[varID].zaxisID;
 }
 
 
@@ -364,7 +360,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;
 }
 
 
@@ -391,7 +388,7 @@ int vlistInqVarParam(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].param);
+  return vlistptr->vars[varID].param;
 }
 
 /*
@@ -428,7 +425,7 @@ int vlistInqVarCode(int vlistID, int varID)
       tableInqParCode(vlistptr->vars[varID].tableID, vlistptr->vars[varID].name, &code);
     }
 
-  return (code);
+  return code;
 }
 
 
@@ -438,7 +435,7 @@ const char *vlistInqVarNamePtr(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].name);
+  return vlistptr->vars[varID].name;
 }
 
 
@@ -448,7 +445,7 @@ const char *vlistInqVarLongnamePtr(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].longname);
+  return vlistptr->vars[varID].longname;
 }
 
 
@@ -458,7 +455,7 @@ const char *vlistInqVarStdnamePtr(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].stdname);
+  return vlistptr->vars[varID].stdname;
 }
 
 
@@ -468,7 +465,7 @@ const char *vlistInqVarUnitsPtr(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].units);
+  return vlistptr->vars[varID].units;
 }
 
 /*
@@ -715,10 +712,10 @@ 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;
 }
 
 
@@ -726,8 +723,7 @@ int vlistInqVarSize(int vlistID, int varID)
 {
   vlistCheckVarID(__func__, vlistID, varID);
 
-  int zaxisID, gridID;
-  int tsteptype;
+  int zaxisID, gridID, tsteptype;
   vlistInqVar(vlistID, varID, &gridID, &zaxisID, &tsteptype);
 
   int nlevs = zaxisInqSize(zaxisID);
@@ -736,7 +732,7 @@ int vlistInqVarSize(int vlistID, int varID)
 
   int size = gridsize*nlevs;
 
-  return (size);
+  return size;
 }
 
 /*
@@ -753,9 +749,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
 */
@@ -765,7 +761,7 @@ int vlistInqVarDatatype(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].datatype);
+  return vlistptr->vars[varID].datatype;
 }
 
 
@@ -776,11 +772,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;
 }
 
 /*
@@ -792,9 +788,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.
@@ -814,12 +810,12 @@ void vlistDefVarDatatype(int vlistID, int varID, int datatype)
       if ( vlistptr->vars[varID].missvalused == FALSE )
         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);
     }
@@ -840,7 +836,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;
 }
 
 
@@ -858,7 +854,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;
 }
 
 
@@ -884,7 +880,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;
 }
 
 /*
@@ -1046,7 +1042,7 @@ double vlistInqVarMissval(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].missval);
+  return vlistptr->vars[varID].missval;
 }
 
 /*
@@ -1156,7 +1152,7 @@ int vlistInqVarValidrange(int vlistID, int varID, double *validrange)
       validrange[1] = vlistptr->vars[varID].validrange[1];
     }
 
-  return (vlistptr->vars[varID].lvalidrange);
+  return vlistptr->vars[varID].lvalidrange;
 }
 
 
@@ -1179,7 +1175,7 @@ double vlistInqVarScalefactor(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].scalefactor);
+  return vlistptr->vars[varID].scalefactor;
 }
 
 
@@ -1189,7 +1185,7 @@ double vlistInqVarAddoffset(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].addoffset);
+  return vlistptr->vars[varID].addoffset;
 }
 
 
@@ -1254,7 +1250,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;
 }
 
 
@@ -1272,7 +1268,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;
 }
 
 
@@ -1290,7 +1286,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;
 }
 
 
@@ -1308,7 +1304,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;
 }
 
 
@@ -1327,8 +1323,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;
 }
 
 
@@ -1386,7 +1381,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 vlistptr->vars[varID].missvalused;
 }
 
 
@@ -1425,7 +1420,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);
@@ -1450,7 +1445,7 @@ int vlistFindVar(int vlistID, int fvarID)
       Message("varID not found for fvarID %d in vlistID %d!", fvarID, vlistID);
     }
 
-  return (varID);
+  return varID;
 }
 
 
@@ -1477,14 +1472,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;
 }
 
 
@@ -1523,7 +1518,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);
@@ -1612,7 +1607,7 @@ int vlistInqVarCompType(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].comptype);
+  return vlistptr->vars[varID].comptype;
 }
 
 
@@ -1636,7 +1631,7 @@ int vlistInqVarCompLevel(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].complevel);
+  return vlistptr->vars[varID].complevel;
 }
 
 
@@ -1660,7 +1655,7 @@ int vlistInqVarChunkType(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].chunktype);
+  return vlistptr->vars[varID].chunktype;
 }
 
 static
@@ -1721,9 +1716,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);
 
@@ -1737,7 +1730,7 @@ int vlistInqVarXYZ(int vlistID, int varID)
 
   vlistCheckVarID(__func__, vlistID, varID);
 
-  return (vlistptr->vars[varID].xyz);
+  return vlistptr->vars[varID].xyz;
 }
 
 /* Ensemble Info Routines */
@@ -1774,7 +1767,7 @@ int vlistInqVarEnsemble( int vlistID, int varID, int *ensID, int *ensCount, int
       status = 1;
     }
 
-  return (status);
+  return status;
 }
 
 
@@ -2004,7 +1997,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 );
 
@@ -2064,7 +2057,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)
@@ -2082,21 +2075,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;
 }
 
@@ -2133,23 +2126,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)
     {
@@ -2161,10 +2154,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
@@ -2182,9 +2175,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!!! */
@@ -2202,35 +2195,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);
     }
@@ -2259,7 +2252,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]);
@@ -2273,7 +2266,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);
 }
 
 
diff --git a/libcdi/src/zaxis.c b/libcdi/src/zaxis.c
index 054b46c..114f6d4 100644
--- a/libcdi/src/zaxis.c
+++ b/libcdi/src/zaxis.c
@@ -32,10 +32,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"},
@@ -64,35 +64,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 );
@@ -116,65 +87,73 @@ 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) *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->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;
   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
     {
@@ -182,27 +161,17 @@ zaxis_t *zaxisNewEntry(int id)
       reshReplace(id, zaxisptr, &zaxisOps);
     }
 
-  return (zaxisptr);
-}
-
-static inline zaxis_t *
-zaxisID2Ptr(int id)
-{
-  return (zaxis_t *)reshGetVal(id, &zaxisOps);
+  return zaxisptr;
 }
 
-
 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);
 }
 
@@ -214,14 +183,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);
 
@@ -242,16 +211,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
@@ -294,15 +256,15 @@ 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 );
 
@@ -331,16 +293,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);
 }
 
 
@@ -349,7 +310,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;
 }
 
 
@@ -363,36 +324,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
@@ -400,37 +369,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 || *mesg == 0 ) 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.
@@ -441,26 +410,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;
 }
@@ -481,14 +523,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);
 }
 
 /*
@@ -507,14 +542,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);
 }
 
 /*
@@ -533,27 +561,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);
 }
 
 /*
@@ -577,13 +585,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;
 }
 
@@ -608,8 +615,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);
 }
 
 /*
@@ -633,30 +639,22 @@ 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)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
 
-  if (zaxisptr->prec != prec)
+  if ( zaxisptr->prec != prec )
     {
       zaxisptr->prec = prec;
       reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
@@ -666,18 +664,18 @@ void zaxisDefPrec(int zaxisID, int prec)
 
 int zaxisInqPrec(int zaxisID)
 {
-  zaxis_t *zaxisptr = zaxisID2Ptr(zaxisID);
-  return (zaxisptr->prec);
+  zaxis_t *zaxisptr = zaxis_to_pointer(zaxisID);
+  return zaxisptr->prec;
 }
 
 
 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);
     }
 }
@@ -685,14 +683,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);
@@ -700,14 +698,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)
     {
@@ -719,16 +717,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);
@@ -738,7 +736,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;
 }
 
@@ -758,15 +756,21 @@ 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;
 
-  int size = zaxisptr->size;
+  if ( levels )
+    {
+      if ( zaxisptr->vals == NULL )
+        zaxisptr->vals = (double*) Malloc(size*sizeof(double));
 
-  double *vals = zaxisptr->vals;
+      double *vals = zaxisptr->vals;
 
-  for (int ilev = 0; ilev < size; ilev++ )
-    vals[ilev] = levels[ilev];
-  reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
+      for ( size_t ilev = 0; ilev < size; ++ilev )
+        vals[ilev] = levels[ilev];
+
+      reshSetStatus(zaxisID, &zaxisOps, RESH_DESYNC_IN_USE);
+    }
 }
 
 /*
@@ -786,16 +790,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;
@@ -806,7 +816,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;
 }
 
@@ -826,7 +836,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;
@@ -851,7 +861,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;
 }
 
@@ -871,7 +881,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);
 }
@@ -894,7 +904,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);
 }
 
@@ -917,40 +927,42 @@ 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;
 }
 
@@ -971,55 +983,64 @@ 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 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 )
     {
@@ -1027,25 +1048,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;
 }
@@ -1077,8 +1102,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;
 }
 
 /*
@@ -1099,16 +1124,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 )
@@ -1142,7 +1167,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 )
     {
@@ -1157,28 +1182,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;
 
@@ -1196,7 +1221,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;
 
@@ -1214,7 +1239,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;
 
@@ -1232,34 +1257,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);
 
@@ -1267,10 +1291,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));
     }
@@ -1278,7 +1301,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));
     }
@@ -1286,15 +1308,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;
@@ -1303,55 +1323,56 @@ 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 dig = (prec == DATATYPE_FLT64) ? 15 : 7;
+  int dig = (prec == 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");
     }
-  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 )
 	    {
@@ -1365,7 +1386,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 )
 	    {
@@ -1416,6 +1437,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 )
         {
@@ -1428,31 +1450,28 @@ 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);
 
@@ -1464,8 +1483,8 @@ zaxisCompareP(zaxis_t *z1, zaxis_t *z2)
     | (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);
@@ -1474,7 +1493,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]);
     }
 
@@ -1484,7 +1503,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]);
     }
 
@@ -1494,7 +1513,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]);
     }
 
@@ -1504,7 +1523,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]);
     }
 
@@ -1515,7 +1534,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]);
     }
 
@@ -1531,8 +1550,8 @@ zaxisCompareP(zaxis_t *z1, zaxis_t *z2)
 }
 
 
-static int
-zaxisTxCode ( void )
+static
+int zaxisTxCode(void)
 {
   return ZAXIS;
 }
@@ -1547,10 +1566,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;
 
@@ -1567,33 +1586,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);
     }
 
   {
@@ -1603,10 +1622,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;
 }
@@ -1621,11 +1640,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();
 
@@ -1648,10 +1667,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)
@@ -1661,10 +1680,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)
@@ -1674,10 +1693,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)
@@ -1687,10 +1706,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 )
@@ -1700,10 +1719,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);
     }
 
   {
@@ -1714,11 +1733,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);
@@ -1742,30 +1761,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);
     }
 
@@ -1773,10 +1792,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);
     }
 
@@ -1784,10 +1803,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);
     }
 
@@ -1795,10 +1814,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);
     }
 
@@ -1809,11 +1828,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);
 
 }
diff --git a/libcdi/src/zaxis.h b/libcdi/src/zaxis.h
index 2c5bceb..d6a772e 100644
--- a/libcdi/src/zaxis.h
+++ b/libcdi/src/zaxis.h
@@ -1,10 +1,53 @@
 #ifndef _ZAXIS_H
 #define _ZAXIS_H
 
+#include "cdi_att.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;
+  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];
+  cdi_atts_t atts;
+}
+zaxis_t;
+
+
 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.
 
 unsigned cdiZaxisCount(void);
 
+zaxis_t *zaxis_to_pointer(int zaxisID);
+
 void cdiZaxisGetIndexList(unsigned numIDs, int *IDs);
 
 void
@@ -18,6 +61,10 @@ const resOps *getZaxisOps(void);
 
 const char *zaxisInqNamePtr(int zaxisID);
 
+const double *zaxisInqLevelsPtr(int zaxisID);
+
+void zaxisResize(int zaxisID, int size);
+
 #endif
 
 /*
diff --git a/libcdi/tests/Makefile.in b/libcdi/tests/Makefile.in
index 632acad..1e41e34 100644
--- a/libcdi/tests/Makefile.in
+++ b/libcdi/tests/Makefile.in
@@ -390,11 +390,9 @@ INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
 INSTALL_SCRIPT = @INSTALL_SCRIPT@
 INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
-JASPER_LIBS = @JASPER_LIBS@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
 LIBOBJS = @LIBOBJS@
-LIBPNG_LIBS = @LIBPNG_LIBS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
 LIPO = @LIPO@
@@ -418,7 +416,6 @@ NM = @NM@
 NMEDIT = @NMEDIT@
 OBJDUMP = @OBJDUMP@
 OBJEXT = @OBJEXT@
-OPENJPEG_LIBS = @OPENJPEG_LIBS@
 OTOOL = @OTOOL@
 OTOOL64 = @OTOOL64@
 PACKAGE = @PACKAGE@
@@ -500,7 +497,6 @@ localstatedir = @localstatedir@
 mandir = @mandir@
 mkdir_p = @mkdir_p@
 oldincludedir = @oldincludedir@
-openjpeg_LIBS = @openjpeg_LIBS@
 pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
diff --git a/libcdi/tests/cksum_write.c b/libcdi/tests/cksum_write.c
index 68e848c..f9a0954 100644
--- a/libcdi/tests/cksum_write.c
+++ b/libcdi/tests/cksum_write.c
@@ -99,13 +99,13 @@ static const struct {
   char suffix[4];
   int type, defaultDT, defaultGrid;
 } suffix2type[] = {
-  { "nc", FILETYPE_NC, DATATYPE_FLT64, GRID_LONLAT },
-  { "grb",  FILETYPE_GRB, DATATYPE_PACK24, GRID_LONLAT },
-  { "nc2", FILETYPE_NC2, DATATYPE_FLT64, GRID_LONLAT },
-  { "nc4", FILETYPE_NC4, DATATYPE_FLT64, GRID_LONLAT },
-  { "ext", FILETYPE_EXT, DATATYPE_FLT64, GRID_GENERIC, },
-  { "svc", FILETYPE_SRV, DATATYPE_FLT64, GRID_GENERIC, },
-  { "ieg", FILETYPE_IEG, DATATYPE_FLT64, GRID_LONLAT },
+  { "nc", CDI_FILETYPE_NC, CDI_DATATYPE_FLT64, GRID_LONLAT },
+  { "grb",  CDI_FILETYPE_GRB, CDI_DATATYPE_PACK24, GRID_LONLAT },
+  { "nc2", CDI_FILETYPE_NC2, CDI_DATATYPE_FLT64, GRID_LONLAT },
+  { "nc4", CDI_FILETYPE_NC4, CDI_DATATYPE_FLT64, GRID_LONLAT },
+  { "ext", CDI_FILETYPE_EXT, CDI_DATATYPE_FLT64, GRID_GENERIC, },
+  { "svc", CDI_FILETYPE_SRV, CDI_DATATYPE_FLT64, GRID_GENERIC, },
+  { "ieg", CDI_FILETYPE_IEG, CDI_DATATYPE_FLT64, GRID_LONLAT },
 };
 #endif
 enum {
@@ -130,11 +130,11 @@ main(int argc, char *argv[])
 #ifndef TEST_CHUNK_WRITE
   const char *suffix = "grb", *prefix = "example";
   int grid = GRID_LONLAT;
-  int filetype = FILETYPE_GRB, datatype = DATATYPE_PACK24;
+  int filetype = CDI_FILETYPE_GRB, datatype = CDI_DATATYPE_PACK24;
 #else
   const char *suffix = "nc", *prefix = "example";
   int grid = GRID_LONLAT;
-  int filetype = FILETYPE_NC, datatype = DATATYPE_FLT64;
+  int filetype = CDI_FILETYPE_NC, datatype = CDI_DATATYPE_FLT64;
 #endif
   {
     int opt;
@@ -319,7 +319,7 @@ main(int argc, char *argv[])
                             / (lons[nlat-1] - lats[0]))
                       ) * mscale)) * mrscale;
 
-        if (filetype == FILETYPE_EXT)
+        if (filetype == CDI_FILETYPE_EXT)
           {
             /* EXTRA doesn't store time, only date
              * set the value to 0 before checksumming, because a
diff --git a/libcdi/tests/deco2d_model.c b/libcdi/tests/deco2d_model.c
index 838d318..12383a0 100644
--- a/libcdi/tests/deco2d_model.c
+++ b/libcdi/tests/deco2d_model.c
@@ -324,7 +324,7 @@ modelRun(struct model_config setup, MPI_Comm comm)
 	  taxisDefVdate(taxisID, vdatetime[1]);
 	  taxisDefVtime(taxisID, vdatetime[0]);
 	  streamDefTimestep ( streamID, tsID );
-          if (setup.filetype == FILETYPE_EXT)
+          if (setup.filetype == CDI_FILETYPE_EXT)
             {
               /* EXTRA doesn't store time, only date
                * set the value to 0 before checksumming, because a
diff --git a/libcdi/tests/pio_write.c b/libcdi/tests/pio_write.c
index 360f296..9d5af8f 100644
--- a/libcdi/tests/pio_write.c
+++ b/libcdi/tests/pio_write.c
@@ -30,10 +30,10 @@ typedef int MPI_Comm;
 
 static const struct model_config default_setup
 #ifdef __cplusplus
-= { 12, 6, 3, 5, 5, FILETYPE_GRB, DATATYPE_PACK24,1,"grb"};
+= { 12, 6, 3, 5, 5, CDI_FILETYPE_GRB, CDI_DATATYPE_PACK24,1,"grb"};
 #else
   = { .nlon = 12, .nts = 3, .nlat = 6, .nvars = 5,
-      .filetype = FILETYPE_GRB, .datatype = DATATYPE_PACK24,
+      .filetype = CDI_FILETYPE_GRB, .datatype = CDI_DATATYPE_PACK24,
       .compute_checksum = 1, .create_uuid = 0,
       .suffix = "grb",
       .max_nlev = 5,
@@ -44,13 +44,13 @@ static const struct {
   char suffix[4];
   int type, defaultDT, defaultGrid;
 } suffix2type[] = {
-  { "nc", FILETYPE_NC, DATATYPE_FLT64, GRID_LONLAT },
-  { "grb",  FILETYPE_GRB, DATATYPE_PACK24, GRID_LONLAT },
-  { "nc2", FILETYPE_NC2, DATATYPE_FLT64, GRID_LONLAT },
-  { "nc4", FILETYPE_NC4, DATATYPE_FLT64, GRID_LONLAT },
-  { "ext", FILETYPE_EXT, DATATYPE_FLT64, GRID_GENERIC, },
-  { "svc", FILETYPE_SRV, DATATYPE_FLT64, GRID_GENERIC, },
-  { "ieg", FILETYPE_IEG, DATATYPE_FLT64, GRID_LONLAT },
+  { "nc", CDI_FILETYPE_NC, CDI_DATATYPE_FLT64, GRID_LONLAT },
+  { "grb",  CDI_FILETYPE_GRB, CDI_DATATYPE_PACK24, GRID_LONLAT },
+  { "nc2", CDI_FILETYPE_NC2, CDI_DATATYPE_FLT64, GRID_LONLAT },
+  { "nc4", CDI_FILETYPE_NC4, CDI_DATATYPE_FLT64, GRID_LONLAT },
+  { "ext", CDI_FILETYPE_EXT, CDI_DATATYPE_FLT64, GRID_GENERIC, },
+  { "svc", CDI_FILETYPE_SRV, CDI_DATATYPE_FLT64, GRID_GENERIC, },
+  { "ieg", CDI_FILETYPE_IEG, CDI_DATATYPE_FLT64, GRID_LONLAT },
 };
 
 static void
diff --git a/libcdi/tests/simple_model.c b/libcdi/tests/simple_model.c
index 97222f1..3f6bed3 100644
--- a/libcdi/tests/simple_model.c
+++ b/libcdi/tests/simple_model.c
@@ -243,7 +243,7 @@ modelRun(struct model_config setup, MPI_Comm comm)
 	  taxisDefVdate(taxisID, vdatetime[1]);
 	  taxisDefVtime(taxisID, vdatetime[0]);
 	  streamDefTimestep ( streamID, tsID );
-          if (setup.filetype == FILETYPE_EXT)
+          if (setup.filetype == CDI_FILETYPE_EXT)
             {
               /* EXTRA doesn't store time, only date
                * set the value to 0 before checksumming, because a
diff --git a/libcdi/tests/simple_model_helper.c b/libcdi/tests/simple_model_helper.c
index 6744380..27b41f2 100644
--- a/libcdi/tests/simple_model_helper.c
+++ b/libcdi/tests/simple_model_helper.c
@@ -17,24 +17,24 @@ var_scale(int datatype, double *mscale, double *mrscale)
   int mant_bits;
   switch (datatype)
     {
-    case DATATYPE_PACK8:
+    case CDI_DATATYPE_PACK8:
       mant_bits = 7;
       break;
-    case DATATYPE_PACK16:
+    case CDI_DATATYPE_PACK16:
       mant_bits = 15;
       break;
-    case DATATYPE_PACK24:
+    case CDI_DATATYPE_PACK24:
       mant_bits = 23;
       break;
-    case DATATYPE_FLT32:
+    case CDI_DATATYPE_FLT32:
       mant_bits = 24;
       break;
-    case DATATYPE_FLT64:
+    case CDI_DATATYPE_FLT64:
       mant_bits = 53;
       break;
-    case DATATYPE_INT8:
-    case DATATYPE_INT16:
-    case DATATYPE_INT32:
+    case CDI_DATATYPE_INT8:
+    case CDI_DATATYPE_INT16:
+    case CDI_DATATYPE_INT32:
     default:
       fprintf(stderr, "Unexpected or unusable content format: %d\n",
               datatype);
diff --git a/libcdi/tests/test_cdf_read.c b/libcdi/tests/test_cdf_read.c
index a870617..a3e2c60 100644
--- a/libcdi/tests/test_cdf_read.c
+++ b/libcdi/tests/test_cdf_read.c
@@ -81,11 +81,11 @@ printAtts(int vlistID)
       int nAtts, attType, attLen;
       char attName[CDI_MAX_NAME + 1];
       int varID = (int)varIdx - 1;
-      vlistInqNatts(vlistID, varID, &nAtts);
+      cdiInqNatts(vlistID, varID, &nAtts);
       for (size_t attIdx = 0; attIdx < (size_t)nAtts; attIdx++ )
         {
-          int rc = vlistInqAtt(vlistID, varID, (int)attIdx,
-                               attName, &attType, &attLen);
+          int rc = cdiInqAtt(vlistID, varID, (int)attIdx,
+                             attName, &attType, &attLen);
           {
             const char *varDesc = varIdx > 0
               ? (sprintf((char *)buf, "%s%d", varDescPrefix,
@@ -102,13 +102,13 @@ printAtts(int vlistID)
           size_t elemSize = 0;
           switch (attType)
             {
-            case DATATYPE_TXT:
+            case CDI_DATATYPE_TXT:
               elemSize = 1;
               break;
-            case DATATYPE_FLT:
+            case CDI_DATATYPE_FLT:
               elemSize = sizeof (double);
               break;
-            case DATATYPE_INT:
+            case CDI_DATATYPE_INT:
               elemSize = sizeof (int);
               break;
             }
@@ -125,15 +125,15 @@ printAtts(int vlistID)
 
           switch (attType)
             {
-            case DATATYPE_TXT:
-              rc = vlistInqAttTxt(vlistID, (int)varID, attName,
-                                  attLen, (char *)buf);
+            case CDI_DATATYPE_TXT:
+              rc = cdiInqAttTxt(vlistID, (int)varID, attName,
+                                attLen, (char *)buf);
               if (rc == CDI_NOERR)
                 printf("\"%.*s\"", attLen, (char *)buf);
               break;
-            case DATATYPE_FLT:
-              rc = vlistInqAttFlt(vlistID, (int)varID, attName,
-                                  attLen + 1, (double *)buf);
+            case CDI_DATATYPE_FLT:
+              rc = cdiInqAttFlt(vlistID, (int)varID, attName,
+                                attLen + 1, (double *)buf);
               if (rc == CDI_NOERR && attLen)
                 {
                   const double *restrict dp = (const double*)buf;
@@ -142,9 +142,9 @@ printAtts(int vlistID)
                     printf(", %10g", dp[i]);
                 }
               break;
-            case DATATYPE_INT:
-              rc = vlistInqAttInt(vlistID, (int)varID, attName,
-                                  attLen + 1, (int *)buf);
+            case CDI_DATATYPE_INT:
+              rc = cdiInqAttInt(vlistID, (int)varID, attName,
+                                attLen + 1, (int *)buf);
               if (rc == CDI_NOERR && attLen)
                 {
                   const int *restrict ip = (const int *)buf;
diff --git a/libcdi/tests/test_cdf_write.c b/libcdi/tests/test_cdf_write.c
index 43e01b3..300621a 100644
--- a/libcdi/tests/test_cdf_write.c
+++ b/libcdi/tests/test_cdf_write.c
@@ -29,7 +29,7 @@ int main(int argc, const char **argv)
   const char *fname = "test.nc";
   if (argc > 1)
     fname = argv[1];
-  int streamID = streamOpenWrite(fname, FILETYPE_NC);
+  int streamID = streamOpenWrite(fname, CDI_FILETYPE_NC);
 
   if ( streamID < 0 )
     {
@@ -82,8 +82,8 @@ int main(int argc, const char **argv)
   vlistDefVarMissval(vlistID, varID, missValue);
   {
     static const char creatorText[] = "CDI test_cdf_write";
-    vlistDefAttTxt(vlistID, varID, "CDI Text Attribute test, created by",
-                   sizeof (creatorText) - 1, creatorText);
+    cdiDefAttTxt(vlistID, varID, "CDI Text Attribute test, created by",
+                 sizeof (creatorText) - 1, creatorText);
   }
 
   int taxisID = taxisCreate(TAXIS_ABSOLUTE);
diff --git a/libcdi/tests/test_grib.c b/libcdi/tests/test_grib.c
index 7f9fe33..f420278 100644
--- a/libcdi/tests/test_grib.c
+++ b/libcdi/tests/test_grib.c
@@ -12,7 +12,7 @@
 int main()
 {
   char fname[] = "test.grb";
-  int filetype = FILETYPE_GRB;
+  int filetype = CDI_FILETYPE_GRB;
   enum {
     nlat = 18,
     nlon = 2*nlat,
diff --git a/libcdi/tests/test_resource_copy.c b/libcdi/tests/test_resource_copy.c
index 9d09677..17f4c1e 100644
--- a/libcdi/tests/test_resource_copy.c
+++ b/libcdi/tests/test_resource_copy.c
@@ -62,22 +62,11 @@ static int defineGrid (void)
   gridDefYlongname ( gridID, "myYlongname" );
   gridDefYunits ( gridID, "myYunits" );
   gridDefPrec ( gridID, DOUBLE_PRECISION );
-  gridDefXpole ( gridID, 90.0 );
-  gridDefYpole ( gridID, 180.0 );
-  gridDefAngle ( gridID, 360.0 );
   gridDefTrunc ( gridID, 1 );
-  gridDefGMEnd ( gridID, 2 );
-  gridDefGMEni ( gridID, 3 );
-  gridDefGMEni2 ( gridID, 4 );
-  gridDefGMEni3 ( gridID, 5 );
+  gridDefParamGME ( gridID, 2, 3, 4, 5 );
   gridDefNumber ( gridID, 6 );
   gridDefPosition ( gridID, 7 );
   gridDefReference ( gridID, "myReference" );
-/* gridDefLCC ( gridID, double originLon, double originLat,  */
-/*         double lonParY, double lat1, double lat2, double xinc, double yinc, int projflag, int scanflag); */
-/* gridDefLcc2 ( gridID, double earth_radius, double lon_0,  */
-/*          double lat_0, double lat_1,double lat_2);*/
-/* gridDefLaea ( gridID, double earth_radius, double lon_0, double lat_0); */
   for ( i = 0; i < nlon*nlat; i++ )
     area_vec[i] = 0.1 * i;
   gridDefArea ( gridID, ap );
@@ -164,11 +153,10 @@ static struct idPair defineVlist ( int gridID, int zaxisID, int taxisID )
   vlistDefVarName(vlistID, varID1, "varname1");
   {
     int globfac[] = { 23, 42 };
-    vlistDefAttInt(vlistID, varID1, "seer's globule factors", DATATYPE_INT16,
-                   2, globfac);
+    cdiDefAttInt(vlistID, varID1, "seer's globule factors", CDI_DATATYPE_INT16, 2, globfac);
   }
   vlistDefVarName(vlistID, varID2, "varname2");
-  vlistDefAttTxt(vlistID, varID2, "txt demo", 6, "banana");
+  cdiDefAttTxt(vlistID, varID2, "txt demo", 6, "banana");
   vlistDefTaxis(vlistID, taxisID);
   int vlistID2 = vlistCreate();
   vlistDefVar(vlistID2, gridID, zaxisID, TIME_VARIABLE);
@@ -215,7 +203,7 @@ static int modelRun(MPI_Comm comm)
   {
     struct idPair temp = defineVlist(gridID, zaxisID, taxisID);
     vlistID = temp.id1;
-    streamID = streamOpenWrite("example.grb", FILETYPE_GRB);
+    streamID = streamOpenWrite("example.grb", CDI_FILETYPE_GRB);
     if ( streamID < 0 ) xabort ( "Could not open file" );
     defineStream ( streamID, vlistID );
     vlistDestroy(temp.id1);
diff --git a/m4/acx_options.m4 b/m4/acx_options.m4
index c1058ab..0b9a84a 100644
--- a/m4/acx_options.m4
+++ b/m4/acx_options.m4
@@ -132,6 +132,10 @@ AC_ARG_WITH([netcdf],
                             NETCDF_LIBS=" -lnetcdf"
                             AC_CHECK_PROG(NC_CONFIG,nc-config,nc-config)
                             AS_IF([test "x$NC_CONFIG" != "x"],
+                                  [AC_MSG_CHECKING([netcdf's OpenDAP support])
+                                   AS_IF([test "x$($NC_CONFIG --has-dap)" = "xyes"],
+                                         [AC_DEFINE([HAVE_LIBNC_DAP],[1],[Define to 1 for NetCDF OpenDAP])
+                                          AC_MSG_RESULT([yes])],[AC_MSG_RESULT([no])])]
                                   [AC_MSG_CHECKING([netcdf's nc2 support])
                                    AS_IF([test "x$($NC_CONFIG --has-nc2)" = "xyes"],
                                          [AC_DEFINE([HAVE_NETCDF2],[1],[Define to 1 for NetCDF2 support])
@@ -189,8 +193,7 @@ AC_ARG_WITH([netcdf],
 
 AS_IF([test "x$ENABLE_NC4HDF5" = "xyes"],
       [AC_SEARCH_LIBS([H5TS_mutex_lock], [netcdf],
-               [AC_DEFINE([HAVE_NC4HDF5_THREADSAFE],[1],[Define to 1 for NetCDF4/HDF5 threadsafe support])],,
-	       [-lhdf5_hl -lhdf5])])
+               [AC_DEFINE([HAVE_NC4HDF5_THREADSAFE],[1],[Define to 1 for NetCDF4/HDF5 threadsafe support])],,[-lhdf5])])
 
 AC_SUBST([ENABLE_NETCDF])
 AC_SUBST([ENABLE_NC2])
diff --git a/src/Adisit.c b/src/Adisit.c
index a4ece15..abc593a 100644
--- a/src/Adisit.c
+++ b/src/Adisit.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -22,7 +22,6 @@
       Adisit      adipot          compute potential from insitu temperature
 */
 
-#include <ctype.h>
 
 #include <cdi.h>
 #include "cdo.h"
@@ -54,26 +53,22 @@ double adisit_1(double tpot, double sal, double p)
          a_d = 4.1057E-9,
          a_e1 = 1.6056E-10, a_e2 = 5.0484E-12;
 
-  double dc, dv, dvs, fne, fst, qc, qn3, qnq, qv, qvs, t, tpo;
-
-  qc = p * (a_a1 + p * (a_c1 - a_e1 * p));
-  qv = p * (a_b1 - a_d * p);
-  dc = 1. + p * (-a_a2 + p * (a_c2 - a_e2 * p));
-  dv = a_b2 * p;
-  qnq  = -p * (-a_a3 + p * a_c3);
-  qn3  = -p * a_a4;
-
-    {
-      tpo = tpot;
-      qvs = qv*(sal - 35.) + qc;
-      dvs = dv*(sal - 35.) + dc;
-      t   = (tpo + qvs)/dvs;
-      fne = - qvs + t*(dvs + t*(qnq + t*qn3)) - tpo;
-      fst = dvs + t*(2.*qnq + 3.*qn3*t);
-      t = t - fne/fst;
-    }
-
-  return (t);
+  double qc = p * (a_a1 + p * (a_c1 - a_e1 * p));
+  double qv = p * (a_b1 - a_d * p);
+  double dc = 1. + p * (-a_a2 + p * (a_c2 - a_e2 * p));
+  double dv = a_b2 * p;
+  double qnq  = -p * (-a_a3 + p * a_c3);
+  double qn3  = -p * a_a4;
+
+  double tpo = tpot;
+  double qvs = qv*(sal - 35.) + qc;
+  double dvs = dv*(sal - 35.) + dc;
+  double t   = (tpo + qvs)/dvs;
+  double fne = - qvs + t*(dvs + t*(qnq + t*qn3)) - tpo;
+  double fst = dvs + t*(2.*qnq + 3.*qn3*t);
+  t = t - fne/fst;
+
+  return t;
 }
 
 /* compute potential temperature from insitu temperature */
@@ -87,39 +82,34 @@ double adipot(double t, double s, double p)
          a_d = 4.1057E-9,
          a_e1 = 1.6056E-10, a_e2 = 5.0484E-12;
 
-  double aa,bb,cc,cc1,dd,tpot,s_rel;
+  double s_rel = s - 35.0;
 
-  s_rel = s - 35.0;
+  double aa = (a_a1+ t*(a_a2 - t*(a_a3 - a_a4*t)));
+  double bb = s_rel*(a_b1 -a_b2*t)     ;
+  double cc = (a_c1 + t*(-a_c2 + a_c3*t));
+  double cc1 = a_d*s_rel;
+  double dd = (-a_e1 + a_e2*t);
 
-   aa = (a_a1+ t*(a_a2 - t*(a_a3 - a_a4*t)));
-   bb = s_rel*(a_b1 -a_b2*t)     ;
-   cc = (a_c1 + t*(-a_c2 + a_c3*t));
-  cc1 = a_d*s_rel;
-   dd = (-a_e1 + a_e2*t);
+  double tpot = t-p*(aa + bb + p*(cc - cc1 + p*dd));
 
-   tpot=t-p*(aa + bb + p*(cc - cc1 + p*dd));
-
-  return (tpot);
+  return tpot;
 }
 
 static
-void calc_adisit(long gridsize, long nlevel, double *pressure, field_t tho, field_t sao, field_t tis)
+void calc_adisit(long gridsize, long nlevel, double *pressure, field_type tho, field_type sao, field_type tis)
 {
   /* pressure units: hPa     */
   /* tho units:      Celsius */
   /* sao units:      psu     */
 
-  long i, levelID, offset;
-  double *tisptr, *thoptr, *saoptr;
-
-  for ( levelID = 0; levelID < nlevel; ++levelID )
+  for ( long levelID = 0; levelID < nlevel; ++levelID )
     {
-      offset = gridsize*levelID;
-      thoptr = tho.ptr + offset;
-      saoptr = sao.ptr + offset;
-      tisptr = tis.ptr + offset;
+      long offset = gridsize*levelID;
+      double *thoptr = tho.ptr + offset;
+      double *saoptr = sao.ptr + offset;
+      double *tisptr = tis.ptr + offset;
 
-      for ( i = 0; i < gridsize; ++i )
+      for ( long i = 0; i < gridsize; ++i )
 	{
 	  if ( DBL_IS_EQUAL(thoptr[i], tho.missval) ||
 	       DBL_IS_EQUAL(saoptr[i], sao.missval) )
@@ -135,23 +125,20 @@ void calc_adisit(long gridsize, long nlevel, double *pressure, field_t tho, fiel
 }
 
 static
-void calc_adipot(long gridsize, long nlevel, double *pressure, field_t t, field_t s, field_t tpot)
+void calc_adipot(long gridsize, long nlevel, double *pressure, field_type t, field_type s, field_type tpot)
 {
   /* pressure units: hPa     */
   /* t units:      Celsius */
   /* s units:      psu     */
 
-  long i, levelID, offset;
-  double *tpotptr, *tptr, *sptr;
-
-  for ( levelID = 0; levelID < nlevel; ++levelID )
+  for ( long levelID = 0; levelID < nlevel; ++levelID )
     {
-      offset = gridsize*levelID;
-      tptr = t.ptr + offset;
-      sptr = s.ptr + offset;
-      tpotptr = tpot.ptr + offset;
+      long offset = gridsize*levelID;
+      double *tptr = t.ptr + offset;
+      double *sptr = s.ptr + offset;
+      double *tpotptr = tpot.ptr + offset;
 
-      for ( i = 0; i < gridsize; ++i )
+      for ( long i = 0; i < gridsize; ++i )
 	{
 	  if ( DBL_IS_EQUAL(tptr[i], t.missval) ||
 	       DBL_IS_EQUAL(sptr[i], s.missval) )
@@ -169,46 +156,35 @@ void calc_adipot(long gridsize, long nlevel, double *pressure, field_t t, field_
 
 void *Adisit(void *argument)
 {
-  int operatorID, ADISIT, ADIPOT;
-  int streamID1, streamID2;
   int nrecs;
-  int tsID, recID, varID, levelID;
-  int nlevel1, nlevel2;
-  int gridsize;
-  int nvars, code, gridID, zaxisID;
-  int vlistID1, vlistID2;
+  int varID, levelID;
   int offset;
-  int nlevel;
   int i;
   int nmiss;
   int thoID = -1, saoID = -1;
-  int tisID2, saoID2;
   char varname[CDI_MAX_NAME], stdname[CDI_MAX_NAME];
-  int taxisID1, taxisID2;
   double pin = -1;
-  double *pressure;
   double *single;
-  field_t tho, sao, tis;
 
   cdoInitialize(argument);
-  ADISIT = cdoOperatorAdd("adisit", 1, 1, "");
-  ADIPOT = cdoOperatorAdd("adipot", 1, 1, "");
+  int ADISIT = cdoOperatorAdd("adisit", 1, 1, "");
+  int ADIPOT = cdoOperatorAdd("adipot", 1, 1, "");
 
   UNUSED(ADIPOT);
 
-  operatorID = cdoOperatorID();
+  int operatorID = cdoOperatorID();
 
   if ( operatorArgc() == 1 ) pin = parameter2double(operatorArgv()[0]);
   
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
+  int vlistID1 = streamInqVlist(streamID1);
 
-  nvars = vlistNvars(vlistID1);
+  int nvars = vlistNvars(vlistID1);
 
   for ( varID = 0; varID < nvars; varID++ )
     {
-      code = vlistInqVarCode(vlistID1, varID);
+      int code = vlistInqVarCode(vlistID1, varID);
 
       if ( code <= 0 )
 	{
@@ -236,19 +212,19 @@ void *Adisit(void *argument)
   if ( saoID == -1 ) cdoAbort("Sea water salinity not found!");
   if ( thoID == -1 ) cdoAbort("Potential or Insitu temperature not found!");
 
-  gridID = vlistGrid(vlistID1, 0);
-  gridsize = vlist_check_gridsize(vlistID1);
+  int gridID = vlistGrid(vlistID1, 0);
+  int gridsize = vlist_check_gridsize(vlistID1);
 
-  zaxisID = vlistInqVarZaxis(vlistID1, saoID);
-  nlevel1 = zaxisInqSize(zaxisID);
-  zaxisID = vlistInqVarZaxis(vlistID1, thoID);
-  nlevel2 = zaxisInqSize(zaxisID);
+  int zaxisID = vlistInqVarZaxis(vlistID1, saoID);
+  int nlevel1 = zaxisInqSize(zaxisID);
+      zaxisID = vlistInqVarZaxis(vlistID1, thoID);
+  int nlevel2 = zaxisInqSize(zaxisID);
 
   if ( nlevel1 != nlevel2 ) cdoAbort("temperature and salinity have different number of levels!");
-  nlevel = nlevel1;
+  int nlevel = nlevel1;
 
-  pressure = (double*) Malloc(nlevel*sizeof(double));
-  zaxisInqLevels(zaxisID, pressure);
+  double *pressure = (double*) Malloc(nlevel*sizeof(double));
+  cdoZaxisInqLevels(zaxisID, pressure);
 
   if ( pin >= 0 ) 
     for ( i = 0; i < nlevel; ++i ) pressure[i] = pin;
@@ -262,6 +238,7 @@ void *Adisit(void *argument)
 	cdoPrint("%5d  %g", i+1, pressure[i]);
     }
 
+  field_type tho, sao, tis;
   field_init(&tho);
   field_init(&sao);
   field_init(&tis);
@@ -277,11 +254,15 @@ void *Adisit(void *argument)
   sao.missval = vlistInqVarMissval(vlistID1, saoID);
   tis.missval = tho.missval;
 
+  int datatype = CDI_DATATYPE_FLT32;
+  if ( vlistInqVarDatatype(vlistID1, thoID) == CDI_DATATYPE_FLT64 &&
+       vlistInqVarDatatype(vlistID1, saoID) == CDI_DATATYPE_FLT64 )
+    datatype = CDI_DATATYPE_FLT64;
 
-  vlistID2 = vlistCreate();
+  int vlistID2 = vlistCreate();
 
-  tisID2 = vlistDefVar(vlistID2, gridID, zaxisID, TIME_VARIABLE);
-  if (operatorID == ADISIT)
+  int tisID2 = vlistDefVar(vlistID2, gridID, zaxisID, TIME_VARIABLE);
+  if ( operatorID == ADISIT )
     {
       vlistDefVarParam(vlistID2, tisID2, cdiEncodeParam(20, 255, 255));
       vlistDefVarName(vlistID2, tisID2, "to");
@@ -297,32 +278,34 @@ void *Adisit(void *argument)
     }
   vlistDefVarUnits(vlistID2, tisID2, "K");
   vlistDefVarMissval(vlistID2, tisID2, tis.missval);
+  vlistDefVarDatatype(vlistID2, tisID2, datatype);
 
-  saoID2 = vlistDefVar(vlistID2, gridID, zaxisID, TIME_VARIABLE);
+  int saoID2 = vlistDefVar(vlistID2, gridID, zaxisID, TIME_VARIABLE);
   vlistDefVarParam(vlistID2, saoID2, cdiEncodeParam(5, 255, 255));
   vlistDefVarName(vlistID2, saoID2, "s");
   vlistDefVarLongname(vlistID2, saoID2, "Sea water salinity");
   vlistDefVarStdname(vlistID2, saoID2, "sea_water_salinity");
   vlistDefVarUnits(vlistID2, saoID2, "psu");
   vlistDefVarMissval(vlistID2, saoID2, sao.missval);
+  vlistDefVarDatatype(vlistID2, saoID2, datatype);
 
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
 
       streamDefTimestep(streamID2, tsID);
 	       
-      for ( recID = 0; recID < nrecs; ++recID )
+      for ( int recID = 0; recID < nrecs; ++recID )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -340,14 +323,10 @@ void *Adisit(void *argument)
             }
         }
 
-      if (operatorID == ADISIT )
-        {
-          calc_adisit(gridsize, nlevel, pressure, tho, sao, tis); 
-        }
+      if ( operatorID == ADISIT )
+        calc_adisit(gridsize, nlevel, pressure, tho, sao, tis); 
       else
-        {
-          calc_adipot(gridsize, nlevel, pressure, tho, sao, tis); 
-        }
+        calc_adipot(gridsize, nlevel, pressure, tho, sao, tis); 
 
 
       for ( levelID = 0; levelID < nlevel; ++levelID )
diff --git a/src/Afterburner.c b/src/Afterburner.c
index 056b19d..f730fd0 100644
--- a/src/Afterburner.c
+++ b/src/Afterburner.c
@@ -64,7 +64,7 @@ int stdin_is_tty  = 0;  /* true if stdin  is character device */
 int stdout_is_tty = 0;  /* true if stdout is character device */
 #endif
 
-static int lstdout = 1;
+static bool lstdout = true;
  
 static int Source = 0;
 
@@ -89,11 +89,11 @@ static int oVertID = -1;
 
 static int Lhybrid2pressure = FALSE;
 
-int    TsID;
+static int TsID;
 #if  defined  (HAVE_LIBPTHREAD)
-int    ParallelRead = TRUE;
+static bool ParallelRead = true;
 #else
-int    ParallelRead = FALSE;
+static bool ParallelRead = false;
 #endif
 
 #define TIMESTEP_INTERVAL  -1
@@ -102,8 +102,8 @@ int    ParallelRead = FALSE;
 #define UNLIM_INTERVAL      2
 
 #define MaxHours  24
-int nrqh;
-int hours[MaxHours+1];
+static int nrqh;
+static int hours[MaxHours+1];
 
 static double *LevelFound;
 
@@ -182,7 +182,7 @@ void after_PostProcess(struct Control *globs)
 static
 void after_SwitchFile(struct Control *globs)
 {
-  int echam4 = FALSE;
+  bool echam4 = false;
   int i, n;
   char y3, y2, y1, y0;
   char         m1, m0;
@@ -201,7 +201,7 @@ void after_SwitchFile(struct Control *globs)
 
       if ( ifile[i-3] == '.' )
 	{
-	  echam4 = TRUE;
+	  echam4 = true;
 	  y3 = ifile[i-9]; y2 = ifile[i-8];
 	  y1 = ifile[i-7]; y0 = ifile[i-6];
 	  m1 = ifile[i-5]; m0 = ifile[i-4];
@@ -387,7 +387,7 @@ static
 void *after_readTimestep(void *arg)
 {
   int i;
-  int recID, varID, gridID, zaxisID, levelID, timeID;
+  int varID, gridID, zaxisID, levelID, timeID;
   int code, leveltype;
   int nmiss;
   RARG *rarg = (RARG *) arg;
@@ -402,7 +402,7 @@ void *after_readTimestep(void *arg)
   int level = 0;
   int levelOffset = 0;
 
-  for ( recID = 0; recID < nrecs; recID++ )
+  for ( int recID = 0; recID < nrecs; recID++ )
     {
       streamInqRecord(globs->istreamID, &varID, &levelID);
 
@@ -625,7 +625,7 @@ static
 void after_control(struct Control *globs, struct Variable *vars)
 {
   int i;
-  int tsFirst, nrecs;
+  int nrecs;
   int rdate, rtime;
   int vdate, vtime;
   int code;
@@ -688,7 +688,7 @@ void after_control(struct Control *globs, struct Variable *vars)
       rtime = after_getTime(globs->StartDate);
     }
 
-  if ( ofiletype == FILETYPE_NC || ofiletype == FILETYPE_NC2 || ofiletype == FILETYPE_NC4 )
+  if ( ofiletype == CDI_FILETYPE_NC || ofiletype == CDI_FILETYPE_NC2 || ofiletype == CDI_FILETYPE_NC4 )
     {
       taxisDefCalendar(globs->taxisID2, CALENDAR_PROLEPTIC);
       taxisDefType(globs->taxisID2, TAXIS_RELATIVE);
@@ -699,7 +699,7 @@ void after_control(struct Control *globs, struct Variable *vars)
 
   globs->OldDate = globs->NewDate;
 
-  tsFirst = TRUE;
+  bool tsFirst = true;
 
   while ( nrecs > 0 )
     {
@@ -708,9 +708,9 @@ void after_control(struct Control *globs, struct Variable *vars)
       rarg.vars  = vars;
       rarg.globs = globs;
 
-      if ( tsFirst || ParallelRead == FALSE )
+      if ( tsFirst || ParallelRead == false )
 	{
-	  if ( ParallelRead == FALSE )
+	  if ( ParallelRead == false )
 	    {
 	      statusp = after_readTimestep(&rarg);
 	    }
@@ -735,7 +735,7 @@ void after_control(struct Control *globs, struct Variable *vars)
 		Error("after_readTimestep error! (status = %d)", *(int *)statusp);
 	    }
 #endif
-	  tsFirst = FALSE;
+	  tsFirst = false;
 	}
 #if defined(HAVE_LIBPTHREAD)
       else
@@ -1350,29 +1350,29 @@ void after_parini(struct Control *globs, struct Variable *vars)
 #if defined(CDO)
     case -1: ofiletype = -1;            break;
 #else
-    case -1: ofiletype = FILETYPE_SRV;  break;
+    case -1: ofiletype = CDI_FILETYPE_SRV;  break;
 #endif
-    case  0: ofiletype = FILETYPE_SRV;  break;
-    case  1: ofiletype = FILETYPE_GRB;  break;
-    case  2: ofiletype = FILETYPE_NC;   break;
-    case  3: ofiletype = FILETYPE_EXT;  break;
-    case  4: ofiletype = FILETYPE_NC2;  break;
-    case  6: ofiletype = FILETYPE_NC4;  break;
+    case  0: ofiletype = CDI_FILETYPE_SRV;  break;
+    case  1: ofiletype = CDI_FILETYPE_GRB;  break;
+    case  2: ofiletype = CDI_FILETYPE_NC;   break;
+    case  3: ofiletype = CDI_FILETYPE_EXT;  break;
+    case  4: ofiletype = CDI_FILETYPE_NC2;  break;
+    case  6: ofiletype = CDI_FILETYPE_NC4;  break;
     default: Error( "unknown file format %d", fileFormat);
     }
 
-  if ( gribFormat )  ofiletype = FILETYPE_GRB;
-  if ( cdfFormat  )  ofiletype = FILETYPE_NC;
+  if ( gribFormat )  ofiletype = CDI_FILETYPE_GRB;
+  if ( cdfFormat  )  ofiletype = CDI_FILETYPE_NC;
 
   int precision = scan_par(globs->Verbose, namelist, "precision", 0);
   if ( precision )
     switch ( precision )
       {
-      case  8: DataType = DATATYPE_PACK8;  break;
-      case 16: DataType = DATATYPE_PACK16; break;
-      case 24: DataType = DATATYPE_PACK24; break;
-      case 32: DataType = DATATYPE_FLT32;  break;
-      case 64: DataType = DATATYPE_FLT64;  break;
+      case  8: DataType = CDI_DATATYPE_PACK8;  break;
+      case 16: DataType = CDI_DATATYPE_PACK16; break;
+      case 24: DataType = CDI_DATATYPE_PACK24; break;
+      case 32: DataType = CDI_DATATYPE_FLT32;  break;
+      case 64: DataType = CDI_DATATYPE_FLT64;  break;
       default: Error( "unsupported data precision %d", precision);
       }
 
@@ -1714,7 +1714,7 @@ void after_postcntl(struct Control *globs, struct Variable *vars)
   char histstring[99];
   int datatype;
 
-  sprintf(histstring, "afterburner version %s  type = %d", VERSION, globs->Type);
+  snprintf(histstring, sizeof(histstring), "afterburner version %s  type = %d", VERSION, globs->Type);
 
 #if defined(AFTERBURNER)
   afterInqHistory(globs->istreamID);
@@ -2084,7 +2084,7 @@ void after_processing(struct Control *globs, struct Variable *vars)
       if ( globs->ostreamID < 0 ) cdiError(globs->ostreamID, "Open failed on %s", ofile);
 #endif
 
-      if ( globs->Szip ) streamDefCompType(globs->ostreamID, COMPRESS_SZIP);
+      if ( globs->Szip ) streamDefCompType(globs->ostreamID, CDI_COMPRESS_SZIP);
 
       globs->ovlistID = vlistCreate();
     }
@@ -2094,7 +2094,7 @@ void after_processing(struct Control *globs, struct Variable *vars)
       globs->ostreamID2 = streamOpenWrite(ofile2, ofiletype);
       if ( globs->ostreamID2 < 0 ) cdiError(globs->ostreamID2, "Open failed on %s", ofile2);
 
-      if ( globs->Szip ) streamDefCompType(globs->ostreamID, COMPRESS_SZIP);
+      if ( globs->Szip ) streamDefCompType(globs->ostreamID, CDI_COMPRESS_SZIP);
 
       globs->ovlistID2 = vlistCreate();
     }
@@ -2117,7 +2117,7 @@ void after_processing(struct Control *globs, struct Variable *vars)
   if ( ! globs->AnalysisData )
     for (i = 0; i < globs->NumLevelRequest; i++)
       {
-	if ( (globs->LevelRequest[i] >= 65535) && globs->unitsel && ofiletype == FILETYPE_GRB )
+	if ( (globs->LevelRequest[i] >= 65535) && globs->unitsel && ofiletype == CDI_FILETYPE_GRB )
 	  {
 	    fprintf(stderr,"\n Level %9.2f out of range (max=65535)!\n", globs->LevelRequest[i]);
 	    exit(1);
@@ -2149,10 +2149,10 @@ void after_processing(struct Control *globs, struct Variable *vars)
 
   if ( globs->Type == 10 || globs->Type == 40 || globs->Type == 60 )
     {
-      if ( ofiletype == FILETYPE_GRB )
+      if ( ofiletype == CDI_FILETYPE_GRB )
 	Error("Can't write fourier coefficients to GRIB!");
-      else if ( ofiletype == FILETYPE_NC || ofiletype == FILETYPE_NC2 ||
-		ofiletype == FILETYPE_NC4 )
+      else if ( ofiletype == CDI_FILETYPE_NC || ofiletype == CDI_FILETYPE_NC2 ||
+		ofiletype == CDI_FILETYPE_NC4 )
 	Error("Can't write fourier coefficients to NetCDF!");
     }
 
@@ -2285,7 +2285,7 @@ int afterburner(int argc, char *argv[])
       fprintf(stderr, "byte size of type double %d\n", (int) sizeof(double));
       fprintf(stderr, "byte size of type int %d\n",    (int) sizeof(int));
       fprintf(stderr, "byte size of type size_t %d\n", (int) sizeof(size_t));
-      return(1);
+      return 1;
     }
 
   fp = fopen("/pf/m/m214003/doc/afterburner.doc","r");
@@ -2317,7 +2317,7 @@ int afterburner(int argc, char *argv[])
       case 'b': Message( "option -b not longer needed!"); break;
       case 'c': after_printCodes(); break;
       case 'd': globs->Debug = 1; break;
-      case 'p': ParallelRead = TRUE; break;
+      case 'p': ParallelRead = true; break;
       case 'P': numThreads = atoi(optarg); break;
       case 'V': after_version(); break;
       case 'v': Vctfile = optarg; break;
@@ -2326,7 +2326,7 @@ int afterburner(int argc, char *argv[])
       }
 
 #if defined (_OPENMP)
-  /* ParallelRead = TRUE; */
+  /* ParallelRead = true; */
 
   lprintf(stdout);
   if ( numThreads <= 0 ) numThreads = 1;
@@ -2338,7 +2338,7 @@ int afterburner(int argc, char *argv[])
   if ( numThreads > 0 )
     {
       fprintf(stderr, "Option -P failed, OpenMP support not compiled in!\n");
-      return(-1);
+      return -1;
     }
 #endif
 
@@ -2348,7 +2348,7 @@ int afterburner(int argc, char *argv[])
       fprintf(stdout, " Parallel read enabled\n");
 #else
       fprintf(stdout, " Parallel read disabled\n");
-      ParallelRead = FALSE;
+      ParallelRead = false;
 #endif
     }
 
@@ -2429,7 +2429,7 @@ int afterburner(int argc, char *argv[])
 
   Free(globs);
 
-  return(0);
+  return 0;
 }
 #endif
 
diff --git a/src/Arith.c b/src/Arith.c
index 56d601c..62ba000 100644
--- a/src/Arith.c
+++ b/src/Arith.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -38,15 +38,12 @@ void *Arith(void *argument)
   enum {FILL_NONE, FILL_TS, FILL_VAR, FILL_VARTS, FILL_FILE};
   int filltype = FILL_NONE;
   int nmiss;
-  int gridsize;
-  int nrecs, nrecs2, nvars = 0, nlev, recID;
+  int nrecs, nrecs2, nvars = 0, nlev;
   int nlevels2 = 1;
-  int tsID, tsID2;
   int varID, levelID;
   int varID2, levelID2;
   int offset;
   int lfill1, lfill2;
-  int streamID3, vlistID3, taxisID3;
   int *varnmiss2 = NULL;
   int **varnmiss = NULL;
   double *vardata2 = NULL;
@@ -72,9 +69,9 @@ void *Arith(void *argument)
   int streamIDx1 = streamID1;
   int streamIDx2 = streamID2;
 
-  field_t field1, field2;
-  field_t *fieldx1 = &field1;
-  field_t *fieldx2 = &field2;
+  field_type field1, field2;
+  field_type *fieldx1 = &field1;
+  field_type *fieldx2 = &field2;
 
   int vlistID1 = streamInqVlist(streamID1);
   int vlistID2 = streamInqVlist(streamID2);
@@ -144,7 +141,7 @@ void *Arith(void *argument)
 
   if ( filltype == FILL_NONE ) vlistCompare(vlistID1, vlistID2, CMP_ALL);
 
-  gridsize = vlistGridsizeMax(vlistIDx1);
+  int gridsize = vlistGridsizeMax(vlistIDx1);
 
   field_init(&field1);
   field_init(&field2);
@@ -193,7 +190,7 @@ void *Arith(void *argument)
 	}
     }
 
-  vlistID3 = vlistDuplicate(vlistIDx1);
+  int vlistID3 = vlistDuplicate(vlistIDx1);
   if ( filltype == FILL_TS && vlistIDx1 != vlistID1 )
     {
       nvars  = vlistNvars(vlistID1);
@@ -201,15 +198,15 @@ void *Arith(void *argument)
 	vlistDefVarMissval(vlistID3, varID, vlistInqVarMissval(vlistID1, varID));
     }
 
-  taxisID3 = taxisDuplicate(taxisIDx1);
+  int taxisID3 = taxisDuplicate(taxisIDx1);
   vlistDefTaxis(vlistID3, taxisID3);
 
-  streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
+  int streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
 
   streamDefVlist(streamID3, vlistID3);
 
-  tsID = 0;
-  tsID2 = 0;
+  int tsID = 0;
+  int tsID2 = 0;
   while ( (nrecs = streamInqTimestep(streamIDx1, tsID)) )
     {
       if ( tsID == 0 || filltype == FILL_NONE || filltype == FILL_FILE || filltype == FILL_VARTS )
@@ -248,7 +245,7 @@ void *Arith(void *argument)
 
       streamDefTimestep(streamID3, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamIDx1, &varID, &levelID);
 	  streamReadRecord(streamIDx1, fieldx1->ptr, &nmiss);
diff --git a/src/Arithc.c b/src/Arithc.c
index 350802d..3e53071 100644
--- a/src/Arithc.c
+++ b/src/Arithc.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -66,14 +66,14 @@ int *fill_vars(int vlistID)
       for ( varID = 0; varID < nvars; ++varID ) vars[varID] = 1;
     }
 
-  return (vars);
+  return vars;
 }
 
 
 void *Arithc(void *argument)
 {
   int nmiss;
-  int nrecs, recID;
+  int nrecs;
   int varID, levelID;
 
   cdoInitialize(argument);
@@ -108,7 +108,7 @@ void *Arithc(void *argument)
 
   int gridsize = vlistGridsizeMax(vlistID1);
 
-  field_t field;
+  field_type field;
   field_init(&field);
   field.ptr    = (double*) Malloc(gridsize*sizeof(double));
   field.weight = NULL;
@@ -120,7 +120,7 @@ void *Arithc(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, field.ptr, &nmiss);
diff --git a/src/Arithdays.c b/src/Arithdays.c
index 83c984b..39faecb 100644
--- a/src/Arithdays.c
+++ b/src/Arithdays.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -40,7 +40,6 @@ double dayofyear(int calendar, int vdate, int vtime)
   int month_365[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
   int month_366[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
   int *dpm;
-  int im, dpy;
   int year, month, day;
   int hour, minute, second;
   double doy = 0;
@@ -48,9 +47,9 @@ double dayofyear(int calendar, int vdate, int vtime)
   cdiDecodeDate(vdate, &year, &month, &day);
   cdiDecodeTime(vtime, &hour, &minute, &second);
 
-  dpy = days_per_year(calendar, year);
+  int dpy = days_per_year(calendar, year);
 
-  for ( im = 1; im < month; ++im )
+  for ( int im = 1; im < month; ++im )
     {
       if      ( dpy == 360 ) dpm = month_360;
       else if ( dpy == 365 ) dpm = month_365;
@@ -71,61 +70,51 @@ double dayofyear(int calendar, int vdate, int vtime)
 
 void *Arithdays(void *argument)
 {
-  int MULDOY;
-  int operatorID;
-  int operfunc, operfunc2;
-  int streamID1, streamID2;
-  int gridsize;
-  int nrecs, recID;
-  int tsID;
+  int nrecs;
   int varID, levelID;
-  int vlistID1, vlistID2;
-  int taxisID1, taxisID2;
-  int vdate, vtime;
   int year, month, day;
-  int calendar;
   int nmiss;
   double rconst;
-  field_t field;
 
   cdoInitialize(argument);
 
-           cdoOperatorAdd("muldpm", func_mul, func_month, NULL);
-           cdoOperatorAdd("divdpm", func_div, func_month, NULL);
-           cdoOperatorAdd("muldpy", func_mul, func_year,  NULL);
-           cdoOperatorAdd("divdpy", func_div, func_year,  NULL);
-  MULDOY = cdoOperatorAdd("muldoy", func_mul,         0,  NULL);
+               cdoOperatorAdd("muldpm", func_mul, func_month, NULL);
+               cdoOperatorAdd("divdpm", func_div, func_month, NULL);
+               cdoOperatorAdd("muldpy", func_mul, func_year,  NULL);
+               cdoOperatorAdd("divdpy", func_div, func_year,  NULL);
+  int MULDOY = cdoOperatorAdd("muldoy", func_mul,         0,  NULL);
 
-  operatorID = cdoOperatorID();
-  operfunc = cdoOperatorF1(operatorID);
-  operfunc2 = cdoOperatorF2(operatorID);
+  int operatorID = cdoOperatorID();
+  int operfunc = cdoOperatorF1(operatorID);
+  int operfunc2 = cdoOperatorF2(operatorID);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  calendar = taxisInqCalendar(taxisID1);
+  int calendar = taxisInqCalendar(taxisID1);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
 
+  field_type field;
   field_init(&field);
   field.ptr    = (double*) Malloc(gridsize*sizeof(double));
   field.weight = NULL;
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
-      vdate = taxisInqVdate(taxisID1);
-      vtime = taxisInqVtime(taxisID1);
+      int vdate = taxisInqVdate(taxisID1);
+      int vtime = taxisInqVtime(taxisID1);
 
       taxisCopyTimestep(taxisID2, taxisID1);
 
@@ -148,7 +137,7 @@ void *Arithdays(void *argument)
       if ( cdoVerbose )
 	cdoPrint("calendar %d  year %d  month %d  result %g", calendar, year, month, rconst);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, field.ptr, &nmiss);
diff --git a/src/Arithlat.c b/src/Arithlat.c
index f2a9827..51d5aa5 100644
--- a/src/Arithlat.c
+++ b/src/Arithlat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  Copyright (C) 2003-2017 Uwe Schulzweida, <uwe.schulzweida AT mpimet.m1pg.de>
   See COPYING file for copying and redistribution conditions.
 
   This program is free software; you can redistribute it and/or modify
@@ -32,60 +32,53 @@
 
 void *Arithlat(void *argument)
 {
-  int operatorID;
-  int operfunc;
-  int streamID1, streamID2;
   int gridtype;
-  int gridID, gridID0 = -1;
-  int nrecs, recID;
-  int tsID;
+  int gridID0 = -1;
+  int nrecs;
   int varID, levelID;
-  int vlistID1, vlistID2;
-  int taxisID1, taxisID2;
   int nmiss;
-  long gridsize, i;
+  long i;
   char units[CDI_MAX_NAME];
   double *scale = NULL;
-  double *array = NULL;
 
   cdoInitialize(argument);
 
   cdoOperatorAdd("mulcoslat", func_mul, 0, NULL);
   cdoOperatorAdd("divcoslat", func_div, 0, NULL);
 
-  operatorID = cdoOperatorID();
-  operfunc = cdoOperatorF1(operatorID);
+  int operatorID = cdoOperatorID();
+  int operfunc = cdoOperatorF1(operatorID);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  long gridsize = vlistGridsizeMax(vlistID1);
 
-  array = (double*) Malloc(gridsize*sizeof(double));
+  double *array = (double*) Malloc(gridsize*sizeof(double));
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
 
       streamDefTimestep(streamID2, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, array, &nmiss);
 	  
-	  gridID = vlistInqVarGrid(vlistID1, varID);
+	  int gridID = vlistInqVarGrid(vlistID1, varID);
 
 	  if ( gridID != gridID0 )
 	    {
diff --git a/src/CDIread.c b/src/CDIread.c
index 9561063..e8c4b9c 100644
--- a/src/CDIread.c
+++ b/src/CDIread.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -27,15 +27,15 @@ const char *filetypestr(int filetype)
 {
   switch ( filetype )
     {
-    case FILETYPE_GRB:  return ("GRIB");            break;
-    case FILETYPE_GRB2: return ("GRIB2");           break;
-    case FILETYPE_NC:   return ("NetCDF");          break;
-    case FILETYPE_NC2:  return ("NetCDF2");         break;
-    case FILETYPE_NC4:  return ("NetCDF4");         break;
-    case FILETYPE_NC4C: return ("NetCDF4 classic"); break;
-    case FILETYPE_SRV:  return ("SERVICE");         break;
-    case FILETYPE_EXT:  return ("EXTRA");           break;
-    case FILETYPE_IEG:  return ("IEG");             break;
+    case CDI_FILETYPE_GRB:  return ("GRIB");            break;
+    case CDI_FILETYPE_GRB2: return ("GRIB2");           break;
+    case CDI_FILETYPE_NC:   return ("NetCDF");          break;
+    case CDI_FILETYPE_NC2:  return ("NetCDF2");         break;
+    case CDI_FILETYPE_NC4:  return ("NetCDF4");         break;
+    case CDI_FILETYPE_NC4C: return ("NetCDF4 classic"); break;
+    case CDI_FILETYPE_SRV:  return ("SERVICE");         break;
+    case CDI_FILETYPE_EXT:  return ("EXTRA");           break;
+    case CDI_FILETYPE_IEG:  return ("IEG");             break;
     default:            return ("");
     }
 }
@@ -46,20 +46,20 @@ const char *datatypestr(int datatype)
   static char str[20];
 
   str[0] = 0;
-  sprintf(str, "%d bit packed", datatype);
+  snprintf(str, sizeof(str), "%d bit packed", datatype);
 
-  if      ( datatype == DATATYPE_PACK   ) return ("P0");
+  if      ( datatype == CDI_DATATYPE_PACK   ) return ("P0");
   else if ( datatype > 0 && datatype <= 32 ) return (str);
-  else if ( datatype == DATATYPE_CPX32  ) return ("C32");
-  else if ( datatype == DATATYPE_CPX64  ) return ("C64");
-  else if ( datatype == DATATYPE_FLT32  ) return ("32 bit floats");
-  else if ( datatype == DATATYPE_FLT64  ) return ("64 bit floats");
-  else if ( datatype == DATATYPE_INT8   ) return ("I8");
-  else if ( datatype == DATATYPE_INT16  ) return ("I16");
-  else if ( datatype == DATATYPE_INT32  ) return ("I32");
-  else if ( datatype == DATATYPE_UINT8  ) return ("U8");
-  else if ( datatype == DATATYPE_UINT16 ) return ("U16");
-  else if ( datatype == DATATYPE_UINT32 ) return ("U32");
+  else if ( datatype == CDI_DATATYPE_CPX32  ) return ("C32");
+  else if ( datatype == CDI_DATATYPE_CPX64  ) return ("C64");
+  else if ( datatype == CDI_DATATYPE_FLT32  ) return ("32 bit floats");
+  else if ( datatype == CDI_DATATYPE_FLT64  ) return ("64 bit floats");
+  else if ( datatype == CDI_DATATYPE_INT8   ) return ("I8");
+  else if ( datatype == CDI_DATATYPE_INT16  ) return ("I16");
+  else if ( datatype == CDI_DATATYPE_INT32  ) return ("I32");
+  else if ( datatype == CDI_DATATYPE_UINT8  ) return ("U8");
+  else if ( datatype == CDI_DATATYPE_UINT16 ) return ("U16");
+  else if ( datatype == CDI_DATATYPE_UINT32 ) return ("U32");
   else                                    return ("");
 }
 
@@ -81,13 +81,11 @@ void print_stat(const char *sinfo, int memtype, int datatype, int filetype, off_
 void *CDIread(void *argument)
 {
   int memtype = CDO_Memtype;
-  int streamID;
-  int tsID, varID, levelID;
-  int gridsize, nmiss;
-  int recID, nrecs;
-  int vlistID;
+  int varID, levelID;
+  int nmiss;
+  int nrecs;
   int filetype = -1, datatype = -1;
-  int irun, nruns = 1;
+  int nruns = 1;
   char sinfo[64];
   off_t nvalues = 0;
   double file_size = 0, data_size = 0;
@@ -112,31 +110,31 @@ void *CDIread(void *argument)
 
   // vlistDefNtsteps(vlistID, 1);
 
-  for ( irun = 0; irun < nruns; ++irun )
+  for ( int irun = 0; irun < nruns; ++irun )
     {
       tw0 = timer_val(timer_read);
       data_size = 0;
       nvalues = 0;
 
-      streamID = streamOpenRead(cdoStreamName(0));
+      int streamID = streamOpenRead(cdoStreamName(0));
 
-      vlistID = streamInqVlist(streamID);
+      int vlistID = streamInqVlist(streamID);
 
       filetype = streamInqFiletype(streamID);
       datatype = vlistInqVarDatatype(vlistID, 0);
 	  
-      gridsize = vlistGridsizeMax(vlistID);
+      int gridsize = vlistGridsizeMax(vlistID);
       
       if ( darray == NULL ) darray = (double*) Malloc(gridsize*sizeof(double));
       if ( farray == NULL && memtype == MEMTYPE_FLOAT ) farray = (float*) Malloc(gridsize*sizeof(float));
 
       t0 = timer_val(timer_read);
 
-      tsID = 0;
+      int tsID = 0;
       while ( (nrecs = streamInqTimestep(streamID, tsID)) )
 	{
 
-	  for ( recID = 0; recID < nrecs; recID++ )
+	  for ( int recID = 0; recID < nrecs; recID++ )
 	    {
 	      streamInqRecord(streamID, &varID, &levelID);
 
@@ -173,7 +171,7 @@ void *CDIread(void *argument)
 
       file_size = (double) fileSize(cdoStreamName(0)->args);
 
-      if ( nruns > 1 ) sprintf(sinfo, "(run %d)", irun+1);
+      if ( nruns > 1 ) snprintf(sinfo, sizeof(sinfo), "(run %d)", irun+1);
 
       print_stat(sinfo, memtype, datatype, filetype, nvalues, data_size, file_size, tw);
     }
diff --git a/src/CDItest.c b/src/CDItest.c
index 8d72bcf..613c415 100644
--- a/src/CDItest.c
+++ b/src/CDItest.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -29,7 +29,7 @@
 void *CDItest(void *argument)
 {
   int nrecs;
-  int recID, varID, levelID;
+  int varID, levelID;
   int nmiss;
   int max_copy = 3;
   double s_utime, s_stime;
@@ -78,7 +78,7 @@ void *CDItest(void *argument)
 
 	  streamDefTimestep(streamID2, tsID2);
 	       
-	  for ( recID = 0; recID < nrecs; recID++ )
+	  for ( int recID = 0; recID < nrecs; recID++ )
 	    {
 	      streamInqRecord(streamID1, &varID, &levelID);
 	      streamDefRecord(streamID2,  varID,  levelID);
diff --git a/src/CDIwrite.c b/src/CDIwrite.c
index 529a7a8..1c04daf 100644
--- a/src/CDIwrite.c
+++ b/src/CDIwrite.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -28,15 +28,15 @@ const char *filetypestr(int filetype)
 {
   switch ( filetype )
     {
-    case FILETYPE_GRB:  return ("GRIB");            break;
-    case FILETYPE_GRB2: return ("GRIB2");           break;
-    case FILETYPE_NC:   return ("NetCDF");          break;
-    case FILETYPE_NC2:  return ("NetCDF2");         break;
-    case FILETYPE_NC4:  return ("NetCDF4");         break;
-    case FILETYPE_NC4C: return ("NetCDF4 classic"); break;
-    case FILETYPE_SRV:  return ("SERVICE");         break;
-    case FILETYPE_EXT:  return ("EXTRA");           break;
-    case FILETYPE_IEG:  return ("IEG");             break;
+    case CDI_FILETYPE_GRB:  return ("GRIB");            break;
+    case CDI_FILETYPE_GRB2: return ("GRIB2");           break;
+    case CDI_FILETYPE_NC:   return ("NetCDF");          break;
+    case CDI_FILETYPE_NC2:  return ("NetCDF2");         break;
+    case CDI_FILETYPE_NC4:  return ("NetCDF4");         break;
+    case CDI_FILETYPE_NC4C: return ("NetCDF4 classic"); break;
+    case CDI_FILETYPE_SRV:  return ("SERVICE");         break;
+    case CDI_FILETYPE_EXT:  return ("EXTRA");           break;
+    case CDI_FILETYPE_IEG:  return ("IEG");             break;
     default:            return ("");
     }
 }
@@ -47,32 +47,30 @@ const char *datatypestr(int datatype)
   static char str[20];
 
   str[0] = 0;
-  sprintf(str, "%d bit packed", datatype);
-
-  if      ( datatype == DATATYPE_PACK   ) return ("P0");
-  else if ( datatype > 0 && datatype <= 32 ) return (str);
-  else if ( datatype == DATATYPE_CPX32  ) return ("C32");
-  else if ( datatype == DATATYPE_CPX64  ) return ("C64");
-  else if ( datatype == DATATYPE_FLT32  ) return ("32 bit floats");
-  else if ( datatype == DATATYPE_FLT64  ) return ("64 bit floats");
-  else if ( datatype == DATATYPE_INT8   ) return ("I8");
-  else if ( datatype == DATATYPE_INT16  ) return ("I16");
-  else if ( datatype == DATATYPE_INT32  ) return ("I32");
-  else if ( datatype == DATATYPE_UINT8  ) return ("U8");
-  else if ( datatype == DATATYPE_UINT16 ) return ("U16");
-  else if ( datatype == DATATYPE_UINT32 ) return ("U32");
-  else                                    return ("");
+  snprintf(str, sizeof(str), "%d bit packed", datatype);
+
+  if      ( datatype == CDI_DATATYPE_PACK   ) return ("P0");
+  else if ( datatype > 0 && datatype <= 32  ) return (str);
+  else if ( datatype == CDI_DATATYPE_CPX32  ) return ("C32");
+  else if ( datatype == CDI_DATATYPE_CPX64  ) return ("C64");
+  else if ( datatype == CDI_DATATYPE_FLT32  ) return ("32 bit floats");
+  else if ( datatype == CDI_DATATYPE_FLT64  ) return ("64 bit floats");
+  else if ( datatype == CDI_DATATYPE_INT8   ) return ("I8");
+  else if ( datatype == CDI_DATATYPE_INT16  ) return ("I16");
+  else if ( datatype == CDI_DATATYPE_INT32  ) return ("I32");
+  else if ( datatype == CDI_DATATYPE_UINT8  ) return ("U8");
+  else if ( datatype == CDI_DATATYPE_UINT16 ) return ("U16");
+  else if ( datatype == CDI_DATATYPE_UINT32 ) return ("U32");
+  else                                        return ("");
 }
 
 static
 void print_stat(const char *sinfo, int memtype, int datatype, int filetype, off_t nvalues, double data_size, double file_size, double tw)
 {
-  double rout;
-
   nvalues /= 1000000;
   data_size /= 1024.*1024.*1024.;
 
-  rout = 0;
+  double rout = 0;
   if ( tw > 0 ) rout = nvalues/tw;
 
   if ( memtype == MEMTYPE_FLOAT )
@@ -127,9 +125,8 @@ void *CDIwrite(void *argument)
   if ( operatorArgc() >= 4 ) ntimesteps = parameter2int(operatorArgv()[3]);
   if ( operatorArgc() >= 5 ) nvars = parameter2int(operatorArgv()[4]);
 
-  if ( nruns <  0 ) nruns = 0;
-  if ( nruns > 99 ) nruns = 99;
-
+  if ( nruns <    0 ) nruns = 0;
+  if ( nruns > 9999 ) nruns = 9999;
 
   if ( nlevs <= 0  ) nlevs = 1;
   if ( nlevs > 255 ) nlevs = 255;
@@ -224,6 +221,7 @@ void *CDIwrite(void *argument)
 
       filetype = streamInqFiletype(streamID);
       datatype = vlistInqVarDatatype(vlistID, 0);
+      if ( datatype == CDI_UNDEFID ) datatype = CDI_DATATYPE_FLT32;
 	  
       julday = date_to_julday(CALENDAR_PROLEPTIC, 19870101);
 
@@ -273,7 +271,7 @@ void *CDIwrite(void *argument)
 
       file_size = (double) fileSize(cdoStreamName(0)->args);
 
-      if ( nruns > 1 ) sprintf(sinfo, "(run %d)", irun+1);
+      if ( nruns > 1 ) snprintf(sinfo, sizeof(sinfo), "(run %d)", irun+1);
 
       print_stat(sinfo, memtype, datatype, filetype, nvalues, data_size, file_size, tw);
     }
diff --git a/src/CMOR.c b/src/CMOR.c
index 37dacd1..ea20c34 100644
--- a/src/CMOR.c
+++ b/src/CMOR.c
@@ -4,11 +4,13 @@
 #include "pstream.h"
 
 #if defined(HAVE_LIBCMOR)
-#include <ctype.h>
+#include <unistd.h>
 #include "uthash.h"
 #include "cmor.h"
 
-struct cc_var
+#define CMOR_UNDEFID (CMOR_MAX_AXES + 1)
+
+struct mapping
 {
   int cdi_varID;
   int cmor_varID;
@@ -23,14 +25,6 @@ struct kv
   UT_hash_handle hh;
 };
 
-static struct cc_var *find_var(int cdi_varID, struct cc_var vars[], int nvars)
-{
-  for ( int i = 0; i < nvars; i++ )
-    if ( cdi_varID == vars[i].cdi_varID )
-      return &vars[i];
-  return NULL;
-}
-
 static char *trim(char *s)
 {
   if (s == NULL) return s;
@@ -138,11 +132,12 @@ static char *get_val(struct kv **ht, char *key, char *def)
   return e ? e->value : def;
 }
 
-static char *substitute(struct kv **ht, char *word)
+static char *key_rename(struct kv **ht, char *word)
 {
   struct kv *e;
-  char *key = (char *) Malloc(strlen(word) + 12);
-  sprintf(key, "substitute_%s", word);
+  size_t len = strlen(word) + 12;
+  char *key = (char *) Malloc(len);
+  snprintf(key, len, "__rename_%s", word);
   HASH_FIND_STR(*ht, key, e);
   Free(key);
   return e ? e->value : word;
@@ -152,29 +147,29 @@ static void dump_global_attributes(struct kv **ht, int streamID)
 {
   int natts;
   int vlistID = streamInqVlist(streamID);
-  vlistInqNatts(vlistID, CDI_GLOBAL, &natts);
+  cdiInqNatts(vlistID, CDI_GLOBAL, &natts);
   for ( int i = 0; i < natts; i++ )
     {
       char name[CDI_MAX_NAME];
       char *value = NULL;
       char buffer[8];
       int type, len;
-      vlistInqAtt(vlistID, CDI_GLOBAL, i, name, &type, &len);
+      cdiInqAtt(vlistID, CDI_GLOBAL, i, name, &type, &len);
       switch ( type )
         {
-        case DATATYPE_TXT:
+        case CDI_DATATYPE_TXT:
           value = Malloc(len + 1);
-          vlistInqAttTxt(vlistID, CDI_GLOBAL, name, len, value);
+          cdiInqAttTxt(vlistID, CDI_GLOBAL, name, len, value);
           value[len] = '\0';
           break;
-        case DATATYPE_INT32:
+        case CDI_DATATYPE_INT32:
           value = Malloc(CDI_MAX_NAME);
-          vlistInqAttInt(vlistID, CDI_GLOBAL, name, len, (int *)buffer);
+          cdiInqAttInt(vlistID, CDI_GLOBAL, name, len, (int *)buffer);
           snprintf(value, CDI_MAX_NAME, "%i", *(int *)buffer);
           break;
-        case DATATYPE_FLT64:
+        case CDI_DATATYPE_FLT64:
           value = Malloc(CDI_MAX_NAME);
-          vlistInqAttFlt(vlistID, CDI_GLOBAL, name, len, (double *)buffer);
+          cdiInqAttFlt(vlistID, CDI_GLOBAL, name, len, (double *)buffer);
           snprintf(value, CDI_MAX_NAME, "%e", *(double *)buffer);
           break;
         default:
@@ -193,7 +188,7 @@ static void dump_special_attributes(struct kv **ht, int streamID)
   char *new_history = get_val(ht, "history", "");
   size_t historysize;
   int natts;
-  vlistInqNatts(vlistID, CDI_GLOBAL, &natts);
+  cdiInqNatts(vlistID, CDI_GLOBAL, &natts);
   if ( natts > 0 )
     old_historysize = (size_t) streamInqHistorySize(fileID);
   else
@@ -240,7 +235,7 @@ static void dump_special_attributes(struct kv **ht, int streamID)
 static void read_config_files(struct kv **ht)
 {
   /* Files from info key in command line. */
-  char *info = get_val(ht, "info", "");
+  char *info = get_val(ht, "__info", "");
   char *infoc = Malloc(strlen(info) + 1);
   strcpy(infoc, info);
   char *filename = strtok(infoc, ",");
@@ -263,139 +258,312 @@ static void read_config_files(struct kv **ht)
   parse_kv_file(ht, "/etc/cdocmor.info", 0);
 }
 
-static int in_list(char **list, const char *needle)
+static void register_cmor_calendar(struct kv **ht, int calendar)
 {
-  while ( *list )
-    if ( strcmp(*list++, needle) == 0 )
-      return 1;
-  return 0;
-}
-
-static void setup(struct kv **ht, int streamID, char *table)
-{
-  int netcdf_file_action;
-  char *chunk = get_val(ht, "chunk", "replace");
-  if ( strcasecmp(chunk, "replace") == 0 )
-    netcdf_file_action = CMOR_REPLACE;
-  else if ( strcasecmp(chunk, "append") == 0 )
-    netcdf_file_action = CMOR_APPEND;
-
-  int set_verbosity = CMOR_NORMAL;
-  if ( strcasecmp(get_val(ht, "set_verbosity", ""), "CMOR_QUIET") == 0 )
-    set_verbosity = CMOR_QUIET;
-
-  int exit_control = CMOR_NORMAL;
-  if ( strcasecmp(get_val(ht, "exit_control", ""), "CMOR_EXIT_ON_MAJOR") == 0 )
-    exit_control = CMOR_EXIT_ON_MAJOR;
-  if ( strcasecmp(get_val(ht, "exit_control", ""), "CMOR_EXIT_ON_WARNING")
-       == 0 )
-    exit_control = CMOR_EXIT_ON_WARNING;
-
-  char *logfile = get_val(ht, "logfile", NULL);
-  int create_subdirectories = atoi(get_val(ht, "create_subdirectories", "0"));
-  cmor_setup(get_val(ht, "inpath", "/usr/share/cmor/"),
-             &netcdf_file_action,
-             &set_verbosity,
-             &exit_control,
-             logfile,
-             &create_subdirectories);
-
-  char *calendar;
-  int taxisID = vlistInqTaxis(streamInqVlist(streamID));
-  switch ( taxisInqCalendar(taxisID) )
+  switch ( calendar )
     {
     case CALENDAR_STANDARD:
-      calendar = "gregorian";
+      hinsert(ht, "calendar", "gregorian");
       break;
     case CALENDAR_PROLEPTIC:
-      calendar = "proleptic_gregorian";
+      hinsert(ht, "calendar", "proleptic_gregorian");
       break;
     case CALENDAR_360DAYS:
-      calendar = "360_day";
+      hinsert(ht, "calendar", "360_day");
       break;
     case CALENDAR_365DAYS:
-      calendar = "noleap";
+      hinsert(ht, "calendar", "noleap");
       break;
     case CALENDAR_366DAYS:
-      calendar = "all_leap";
+      hinsert(ht, "calendar", "all_leap");
       break;
     default:
-      cdoAbort("Unsupported calendar type.");
+      cdoWarning("Unsupported calendar type %i.\n", calendar);
+    }
+}
+
+static char *dump_ht_to_json_file(struct kv **ht, char *filename)
+{
+  int fd = mkstemp(filename);
+  dprintf(fd, "{\n");
+  for ( struct kv *entry = *ht; entry != NULL; entry = entry->hh.next )
+    if ( strncmp(entry->key, "__", 2) != 0 )
+      dprintf(fd, "\t\"%s\":\t\t\"%s\",\n", entry->key, entry->value);
+  dprintf(fd, "}\n");
+  close(fd);
+  return filename;
+}
+
+static int get_netcdf_file_action(struct kv **ht)
+{
+  char *chunk = get_val(ht, "__chunk", "replace");
+  if ( strcasecmp(chunk, "append") == 0 )
+    return CMOR_APPEND;
+  else
+    return CMOR_REPLACE;
+}
+
+static int get_cmor_verbosity(struct kv **ht)
+{
+  if ( strcasecmp(get_val(ht, "__set_verbosity", ""), "CMOR_QUIET") == 0 )
+    return CMOR_QUIET;
+  else
+    return CMOR_NORMAL;
+}
+
+static int get_cmor_exit_control(struct kv **ht)
+{
+  if ( strcasecmp(get_val(ht, "__exit_control", ""),
+                  "CMOR_EXIT_ON_MAJOR") == 0 )
+    return CMOR_EXIT_ON_MAJOR;
+  else if ( strcasecmp(get_val(ht, "__exit_control", ""),
+                       "CMOR_EXIT_ON_WARNING")  == 0 )
+    return CMOR_EXIT_ON_WARNING;
+  else
+    return CMOR_NORMAL;
+}
+
+static char json_filename[20];
+static void unlink_json_filename(void) { unlink(json_filename); }
+
+static void feed_json_to_cmor_dataset(struct kv **ht)
+{
+  snprintf(json_filename, sizeof(json_filename), "dataset.json_XXXXXX");
+  atexit(unlink_json_filename);
+  cmor_dataset_json(dump_ht_to_json_file(ht, json_filename));
+  unlink(json_filename);
+}
+
+static void setup_dataset(struct kv **ht, int streamID)
+{
+  int netcdf_file_action = get_netcdf_file_action(ht);
+  int set_verbosity = get_cmor_verbosity(ht);
+  int exit_control = get_cmor_exit_control(ht);
+  char *logfile = get_val(ht, "__logfile", NULL);
+  int create_subdirectories = atoi(get_val(ht, "__create_subdirectories", "0"));
+
+  cmor_setup(get_val(ht, "__inpath", "/usr/share/cmor/"),
+             &netcdf_file_action, &set_verbosity, &exit_control,
+             logfile, &create_subdirectories);
+
+  int taxisID = vlistInqTaxis(streamInqVlist(streamID));
+  register_cmor_calendar(ht, taxisInqCalendar(taxisID));
+  feed_json_to_cmor_dataset(ht);
+}
+
+static int *new_axis_id(int *axis_ids)
+{
+  int i;
+  for ( i = 0; axis_ids[i] != CMOR_UNDEFID; i++ );
+  axis_ids[i + 1] = CMOR_UNDEFID;
+  return &axis_ids[i];
+}
+
+static int count_axis_ids(int *axis_ids)
+{
+  int i;
+  for ( i = 0; axis_ids[i] != CMOR_UNDEFID; i++ );
+  return i;
+}
+
+static void register_x_axis(int gridID, char* name, int *axis_ids)
+{
+  double *coord_vals;
+  char units[CDI_MAX_NAME];
+  gridInqXunits(gridID, units);
+  int length = gridInqXsize(gridID);
+  coord_vals = Malloc(length * sizeof(double));
+  gridInqXvals(gridID, coord_vals);
+  double *cell_bounds = Malloc(2 * length * sizeof(double));
+  int nbounds = gridInqXbounds(gridID, cell_bounds);
+  if ( nbounds != 2 * length )
+    {
+      Free(cell_bounds);
+      cell_bounds = NULL;
+    }
+  cmor_axis(new_axis_id(axis_ids), name, units, length, (void *)coord_vals,
+            'd', (void *)cell_bounds, 2, NULL);
+  Free(coord_vals);
+  if ( cell_bounds ) Free(cell_bounds);
+}
+
+static void register_y_axis(int gridID, char* name, int *axis_ids)
+{
+  double *coord_vals;
+  char units[CDI_MAX_NAME];
+  gridInqYunits(gridID, units);
+  int length = gridInqYsize(gridID);
+  coord_vals = Malloc(length * sizeof(double));
+  gridInqYvals(gridID, coord_vals);
+  double *cell_bounds = Malloc(2 * length * sizeof(double));
+  int nbounds = gridInqYbounds(gridID, cell_bounds);
+  if ( nbounds != 2 * length )
+    {
+      Free(cell_bounds);
+      cell_bounds = NULL;
+    }
+  cmor_axis(new_axis_id(axis_ids), name, units, length, (void *)coord_vals,
+            'd', (void *)cell_bounds, 2, NULL);
+  Free(coord_vals);
+  if ( cell_bounds ) Free(cell_bounds);
+}
+
+static void register_z_axis(int zaxisID, char *name, int *axis_ids)
+{
+  int levels = zaxisInqSize(zaxisID);
+  char units[CDI_MAX_NAME];
+  double *coord_vals;
+  if ( zaxisInqType(zaxisID) != ZAXIS_SURFACE )
+    {
+      coord_vals = Malloc(levels * sizeof(double));
+      cdoZaxisInqLevels(zaxisID, coord_vals);
+      zaxisInqUnits(zaxisID, units);
+      cmor_axis(new_axis_id(axis_ids), name, units, levels, (void *)coord_vals,
+                'd', NULL, 0, NULL);
+      Free(coord_vals);
     }
+}
+
+static void register_xy_only(int gridID, int *axis_ids)
+{
+  char name[CDI_MAX_NAME];
+  name[0] = 0; cdiGridInqKeyStr(gridID, CDI_KEY_YLONGNAME, CDI_MAX_NAME, name);
+  register_y_axis(gridID, name, axis_ids);
+  name[0] = 0; cdiGridInqKeyStr(gridID, CDI_KEY_XLONGNAME, CDI_MAX_NAME, name);
+  register_x_axis(gridID, name, axis_ids);
+}
+
+static void register_cmor_grid(int gridID, int *axis_ids, int *cmor_grid_id)
+{
+  int gridsize = gridInqSize(gridID);
+  double *latitude = Malloc(gridsize * sizeof(double));
+  gridInqYvals(gridID, latitude);
+  double *latitude_vertices = Malloc(4 * gridsize * sizeof(double));
+  gridInqYbounds(gridID, latitude_vertices);
+
+  double *longitude = Malloc(gridsize * sizeof(double));
+  gridInqXvals(gridID, longitude);
+  double *longitude_vertices = Malloc(4 * gridsize * sizeof(double));
+  gridInqXbounds(gridID, longitude_vertices);
+  cmor_grid(cmor_grid_id, count_axis_ids(axis_ids), axis_ids, 'd',
+            (void *)latitude, (void *)longitude, 4,
+            (void *)latitude_vertices, (void *)longitude_vertices
+            );
+  Free(latitude);
+  Free(latitude_vertices);
+  Free(longitude);
+  Free(longitude_vertices);
+}
+
+static void register_cmor_grid_mapping(int projID, int cmor_grid_id)
+{
+  char grid_mapping[CDI_MAX_NAME] = "";
+  cdiGridInqKeyStr(projID, CDI_KEY_MAPNAME, CDI_MAX_NAME, grid_mapping);
 
-  int *month_lengths;
-  char *ml = get_val(ht, "month_lengths", NULL);
-  if ( ml )
+  if ( grid_mapping[0] )
     {
-      char *mlc = Malloc(strlen(ml) + 1);
-      char *month_str = strtok(mlc, ",");
-      int month = 0;
-      month_lengths = Malloc(12 * sizeof(int));
-      while ( month < 12 && month_str != NULL )
+      int atttype, attlen;
+      char attname[CDI_MAX_NAME];
+      int natts, nparameters;
+      cdiInqNatts(projID, CDI_GLOBAL, &natts);
+      char parameter_names[natts][CDI_MAX_NAME];
+      double parameter_values[natts];
+      char parameter_units[natts][1];
+
+      nparameters = 0;
+      for ( int iatt = 0; iatt < natts; ++iatt )
         {
-          month_lengths[month++] = atoi(month_str);
-          month_str = strtok(NULL, ",");
+          cdiInqAtt(projID, CDI_GLOBAL, iatt, attname, &atttype, &attlen);
+          if ( atttype == CDI_DATATYPE_FLT32 || atttype == CDI_DATATYPE_FLT64 )
+            {
+              double attflt[attlen];
+              cdiInqAttFlt(projID, CDI_GLOBAL, attname, attlen, attflt);
+              strcpy(parameter_names[nparameters], attname);
+              parameter_values[nparameters] = attflt[0];
+              parameter_units[nparameters][0] = 0;
+              nparameters++;
+            }
         }
-      Free(mlc);
-      if ( month != 12 )
-        cdoAbort("Invalid format for month_lengths");
+      cmor_set_grid_mapping(cmor_grid_id, grid_mapping, nparameters,
+                            (char **)parameter_names, CDI_MAX_NAME,
+                            parameter_values,
+                            (char **)parameter_units, 1);
+    }
+}
+
+static void register_projected_grid(int gridID, int *axis_ids)
+{
+  char name[CDI_MAX_NAME];
+  int projID = gridInqProj(gridID);
+  int proj_axis_ids[3];
+  proj_axis_ids[0] = CMOR_UNDEFID;
+  gridInqYstdname(projID, name);
+  register_y_axis(projID, name, proj_axis_ids);
+  gridInqXstdname(projID, name);
+  register_x_axis(projID, name, proj_axis_ids);
+  int *cmor_grid_id = new_axis_id(axis_ids);
+  register_cmor_grid(gridID, proj_axis_ids, cmor_grid_id);
+  register_cmor_grid_mapping(projID, *cmor_grid_id);
+}
+
+static void register_xy_and_grid(int gridID, int table_id, int grid_table_id,
+                                 int *axis_ids)
+{
+  if ( gridInqProj(gridID) > 0 )
+    {
+      if ( grid_table_id == 0 )
+        cdoAbort("__grid_table not specified!");
+      cmor_set_table(grid_table_id);
+      register_projected_grid(gridID, axis_ids);
+      cmor_set_table(table_id);
     }
   else
     {
-      month_lengths = NULL;
+      register_xy_only(gridID, axis_ids);
     }
-
-  double branch_time = atof(get_val(ht, "branch_time", "0.0"));
-  cmor_dataset(get_val(ht, "outpath", "./"),
-               get_val(ht, "experiment_id", ""),
-               get_val(ht, "institution", ""),
-               get_val(ht, "source", ""),
-               calendar,
-               atoi(get_val(ht, "realization", "1")),
-               get_val(ht, "contact", ""),
-               get_val(ht, "history", ""),
-               get_val(ht, "comment", ""),
-               get_val(ht, "references", ""),
-               atoi(get_val(ht, "leap_year", "0")),
-               atoi(get_val(ht, "leap_month", "0")),
-               month_lengths,
-               get_val(ht, "model_id", ""),
-               get_val(ht, "forcing", ""),
-               atoi(get_val(ht, "initialization_method", "1")),
-               atoi(get_val(ht, "physics_version", "1")),
-               get_val(ht, "institute_id", ""),
-               get_val(ht, "parent_experiment_id", ""),
-               &branch_time,
-               get_val(ht, "parent_experiment_rip", ""));
-
-  int table_id;
-  cmor_load_table(table, &table_id);
-  cmor_set_table(table_id);
 }
 
-static void define_variables(struct kv **ht, int streamID,
-                             struct cc_var vars[], int *nvars)
+static void get_taxis_units(char *units, int taxisID)
 {
-  int vlistID = streamInqVlist(streamID);
-  int taxisID = vlistInqTaxis(vlistID);
-  char taxis_units[CMOR_MAX_STRING];
   int timeunit = taxisInqTunit(taxisID);
   int year, month, day, hour, minute, second;
   cdiDecodeDate(taxisInqRdate(taxisID), &year, &month, &day);
   cdiDecodeTime(taxisInqRtime(taxisID), &hour, &minute, &second);
   if ( timeunit == TUNIT_QUARTER || timeunit == TUNIT_30MINUTES )
     timeunit = TUNIT_MINUTE;
-  if ( timeunit == TUNIT_3HOURS ||
-       timeunit == TUNIT_6HOURS ||
+  if ( timeunit == TUNIT_3HOURS || timeunit == TUNIT_6HOURS ||
        timeunit == TUNIT_12HOURS )
     timeunit = TUNIT_HOUR;
 
-  sprintf(taxis_units, "%s since %d-%d-%d %02d:%02d:%02d",
-          tunitNamePtr(timeunit), year, month, day, hour,
-          minute, second);
+  snprintf(units, CMOR_MAX_STRING, "%s since %d-%d-%d %02d:%02d:%02d", tunitNamePtr(timeunit),
+          year, month, day, hour, minute, second);
+}
+
+static int get_table_id(char *table)
+{
+  int table_id;
+  cmor_load_table(table, &table_id);
+  return table_id;
+}
+
+static int get_grid_table_id(struct kv **ht)
+{
+  if ( get_val(ht, "__grid_table", NULL) )
+    {
+      return get_table_id(get_val(ht, "__grid_table", NULL));
+    }
+  else
+    {
+      cdoAbort("Grid table required but not defined. Set __grid_table!");
+      return 0;
+    }
+}
+
+static char **get_requested_variables(struct kv **ht)
+{
+  char **name_list = NULL;
+  char *select_vars = get_val(ht, "__var", NULL);
 
-  char **name_list;
-  char *select_vars = get_val(ht, "var", NULL);
   if ( select_vars )
     {
       name_list = Malloc((strlen(select_vars) + 1) * sizeof(char *));
@@ -408,225 +576,218 @@ static void define_variables(struct kv **ht, int streamID,
         }
       name_list[i] = NULL;
     }
+  return name_list;
+}
+
+static void register_variable(int vlistID, int varID, int *axis_ids,
+                              struct mapping *var)
+{
+  char name[CDI_MAX_NAME];
+  vlistInqVarName(vlistID, varID, name);
+  char units[CDI_MAX_NAME];
+  vlistInqVarUnits(vlistID, varID, units);
+  char missing_value[sizeof(double)];
+  double tolerance = 1e-4;
+  size_t gridsize = vlistGridsizeMax(vlistID);
+  int levels = zaxisInqSize(vlistInqVarZaxis(vlistID, varID));
+  var->cdi_varID = varID;
+  if ( vlistInqVarDatatype(vlistID, varID) == CDI_DATATYPE_FLT32 )
+    {
+      var->datatype = 'f';
+      *(float *) missing_value = vlistInqVarMissval(vlistID, varID);
+      var->data = Malloc(gridsize * levels * sizeof(float));
+    }
   else
     {
-      name_list = NULL;
+      var->datatype = 'd';
+      *(double *) missing_value = vlistInqVarMissval(vlistID, varID);
+      var->data = Malloc(gridsize * levels * sizeof(double));
     }
+  cmor_variable(&var->cmor_varID, name, units,
+                count_axis_ids(axis_ids), axis_ids,
+                var->datatype, (void *) missing_value, &tolerance,
+                NULL, NULL, NULL, NULL);
+}
+
+static struct mapping *new_var_mapping(struct mapping vars[])
+{
+  int i;
+  for ( i = 0; vars[i].cdi_varID != CDI_UNDEFID; i++ );
+  vars[i + 1].cdi_varID = CDI_UNDEFID;
+  return &vars[i];
+}
+
+static int in_list(char **list, const char *needle)
+{
+  for ( ; *list; list++ )
+    if ( strcmp(*list, needle) == 0 )
+      return 1;
+  return 0;
+}
+
+static void register_axes_and_variables(struct kv **ht, int table_id,
+                                        int streamID, struct mapping vars[])
+{
+  int vlistID = streamInqVlist(streamID);
+  int taxisID = vlistInqTaxis(vlistID);
+  char taxis_units[CMOR_MAX_STRING];
+  get_taxis_units(taxis_units, taxisID);
+  char **requested_variables = get_requested_variables(ht);
+  int grid_table_id = get_grid_table_id(ht);
+  cmor_set_table(table_id);
 
-  *nvars = 0;
   for ( int varID = 0; varID < vlistNvars(vlistID); varID++ )
     {
-      char name[CDI_MAX_NAME];
+      char var_name[CDI_MAX_NAME];
       int axis_ids[CMOR_MAX_AXES];
-      vlistInqVarName(vlistID, varID, name);
-      if ( name_list == NULL || in_list(name_list, name) )
+      axis_ids[0] = CMOR_UNDEFID;
+      vlistInqVarName(vlistID, varID, var_name);
+      if ( requested_variables == NULL ||
+           in_list(requested_variables, var_name) )
         {
-          int ndims = 0;
-          /* Time-Axis */
-          cmor_axis(&axis_ids[ndims++],
-                    substitute(ht, "time"),
-                    taxis_units,
-                    0,
-                    NULL,
-                    0,
-                    NULL,
-                    0,
-                    NULL);
-
-          /* Z-Axis */
+          cmor_axis(new_axis_id(axis_ids), "time", taxis_units, 0,
+                    NULL, 0, NULL, 0, NULL);
           int zaxisID = vlistInqVarZaxis(vlistID, varID);
-          int levels = zaxisInqSize(zaxisID);
-          char units[CDI_MAX_NAME];
-          double *coord_vals;
-          if ( zaxisInqType(zaxisID) != ZAXIS_SURFACE )
-            {
-              coord_vals = Malloc(levels * sizeof(double));
-              zaxisInqLevels(zaxisID, coord_vals);
-              zaxisInqName(zaxisID, name);
-              zaxisInqUnits(zaxisID, units);
-              cmor_axis(&axis_ids[ndims++],
-                        substitute(ht, name),
-                        units,
-                        levels,
-                        (void *)coord_vals,
-                        'd',
-                        NULL,
-                        0,
-                        NULL);
-            }
-
-          /* Y-Axis */
+          char z_name[CDI_MAX_NAME];
+          zaxisInqName(zaxisID, z_name);
+          register_z_axis(zaxisID, key_rename(ht, z_name), axis_ids);
           int gridID = vlistInqVarGrid(vlistID, varID);
-          gridInqYname(gridID, name);
-          gridInqYunits(gridID, units);
-          int length = gridInqYsize(gridID);
-          coord_vals = Malloc(length * sizeof(double));
-          gridInqYvals(gridID, coord_vals);
-          double *cell_bounds = Malloc(2 * length * sizeof(double));
-          int nbounds = gridInqYbounds(gridID, cell_bounds);
-          if ( nbounds != 2 * length )
-            {
-              Free(cell_bounds);
-              cell_bounds = NULL;
-            }
-          cmor_axis(&axis_ids[ndims++],
-                    substitute(ht, name),
-                    units,
-                    length,
-                    (void *)coord_vals,
-                    'd',
-                    (void *)cell_bounds,
-                    2,
-                    NULL);
-
-          /* X-Axis */
-          gridInqXname(gridID, name);
-          gridInqXunits(gridID, units);
-          length = gridInqXsize(gridID);
-          coord_vals = Malloc(length * sizeof(double));
-          gridInqXvals(gridID, coord_vals);
-          cell_bounds = Malloc(2 * length * sizeof(double));
-          nbounds = gridInqXbounds(gridID, cell_bounds);
-          if ( nbounds != 2 * length )
-            {
-              Free(cell_bounds);
-              cell_bounds = NULL;
-            }
-          cmor_axis(&axis_ids[ndims++],
-                    substitute(ht, name),
-                    units,
-                    length,
-                    (void *)coord_vals,
-                    'd',
-                    (void *)cell_bounds,
-                    2,
-                    NULL);
-
-          /* Variable */
-          vlistInqVarUnits(vlistID, varID, units);
-          vlistInqVarName(vlistID, varID, name);
-          char missing_value[sizeof(double)];
-          double tolerance = 1e-4;
-          size_t gridsize = vlistGridsizeMax(vlistID);
-          struct cc_var *var = &vars[(*nvars)++];
-          var->cdi_varID = varID;
-          if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_FLT32 )
-            {
-              var->datatype = 'f';
-              *(float *) missing_value = vlistInqVarMissval(vlistID, varID);
-              var->data = Malloc(gridsize * levels * sizeof(float));
-            }
-          else
-            {
-              var->datatype = 'd';
-              *(double *) missing_value = vlistInqVarMissval(vlistID, varID);
-              var->data = Malloc(gridsize * levels * sizeof(double));
-            }
-          cmor_variable(&var->cmor_varID,
-                        substitute(ht, name),
-                        units,
-                        ndims,
-                        axis_ids,
-                        var->datatype,
-                        (void *) missing_value,
-                        &tolerance,
-                        NULL,
-                        NULL,
-                        NULL,
-                        NULL);
+          register_xy_and_grid(gridID, table_id, grid_table_id, axis_ids);
+          register_variable(vlistID, varID, axis_ids, new_var_mapping(vars));
         }
     }
-  if ( name_list ) Free(name_list);
+  if ( requested_variables ) Free(requested_variables);
 }
 
-static void write_variables(int streamID, struct cc_var vars[], int nvars)
+static int time_unit_in_seconds(int taxisID)
 {
-  int vlistID = streamInqVlist(streamID);
-  int taxisID = vlistInqTaxis(vlistID);
-  int tunitsec;
   switch ( taxisInqTunit(taxisID) )
     {
-    case TUNIT_MINUTE: tunitsec = 60; break;
-    case TUNIT_HOUR: tunitsec = 3600; break;
-    case TUNIT_DAY: tunitsec = 86400; break;
-    default: tunitsec = 3600;
+    case TUNIT_MINUTE: return 60;
+    case TUNIT_HOUR: return 3600;
+    case TUNIT_DAY: return 86400;
+    default: return 3600;
     }
+}
 
+static double get_cmor_time_val(int taxisID, juldate_t ref_date)
+{
+  int tunitsec = time_unit_in_seconds(taxisID);
   int calendar = taxisInqCalendar(taxisID);
-  juldate_t r_juldate = juldate_encode(calendar,
-                                       taxisInqRdate(taxisID),
-                                       taxisInqRtime(taxisID));
-  size_t gridsize = vlistGridsizeMax(vlistID);
-  double *buffer = (double *) Malloc(gridsize * sizeof(double));
-  int tsID = 0;
-  int nrecs;
-  while ( (nrecs = streamInqTimestep(streamID, tsID++)) )
+  juldate_t juldate = juldate_encode(calendar, taxisInqVdate(taxisID),
+                                     taxisInqVtime(taxisID));
+  return juldate_to_seconds(juldate_sub(juldate, ref_date)) / tunitsec;
+}
+
+static double *get_cmor_time_bounds(int taxisID, juldate_t ref_date,
+                                    double *bounds)
+{
+  if ( taxisHasBounds(taxisID) )
     {
-      double time_bnds[2];
-      double *time_bndsp;
-      double time_val;
-      juldate_t juldate = juldate_encode(calendar,
-                                         taxisInqVdate(taxisID),
-                                         taxisInqVtime(taxisID));
-      time_val = juldate_to_seconds(juldate_sub(juldate, r_juldate))
-        / tunitsec;
-
-      if ( taxisHasBounds(taxisID) )
+      int vdate0b, vdate1b, vtime0b, vtime1b;
+      taxisInqVdateBounds(taxisID, &vdate0b, &vdate1b);
+      taxisInqVtimeBounds(taxisID, &vtime0b, &vtime1b);
+
+      int tunitsec = time_unit_in_seconds(taxisID);
+      int calendar = taxisInqCalendar(taxisID);
+      juldate_t date = juldate_encode(calendar, vdate0b, vtime0b);
+      bounds[0] = juldate_to_seconds(juldate_sub(date, ref_date)) / tunitsec;
+
+      date = juldate_encode(calendar, vdate1b, vtime1b);
+      bounds[1] = juldate_to_seconds(juldate_sub(date, ref_date)) / tunitsec;
+      return bounds;
+    }
+  else
+    {
+      return NULL;
+    }
+}
+
+static struct mapping *map_var(int cdi_varID, struct mapping vars[])
+{
+  for ( int i = 0; vars[i].cdi_varID != CDI_UNDEFID; i++ )
+    if ( cdi_varID == vars[i].cdi_varID )
+      return &vars[i];
+  return NULL;
+}
+
+static void read_record(int streamID, double *buffer, size_t gridsize,
+                        struct mapping vars[])
+{
+  int varID, levelID;
+  streamInqRecord(streamID, &varID, &levelID);
+  struct mapping *var = map_var(varID, vars);
+  if ( var )
+    {
+      int nmiss;
+      if ( var->datatype == 'f' )
         {
-          int vdate0b, vdate1b, vtime0b, vtime1b;
-          taxisInqVdateBounds(taxisID, &vdate0b, &vdate1b);
-          taxisInqVtimeBounds(taxisID, &vtime0b, &vtime1b);
-
-          juldate = juldate_encode(calendar, vdate0b, vtime0b);
-          time_bnds[0] = juldate_to_seconds(juldate_sub(juldate, r_juldate))
-            / tunitsec;
-
-          juldate = juldate_encode(calendar, vdate1b, vtime1b);
-          time_bnds[1] = juldate_to_seconds(juldate_sub(juldate, r_juldate))
-            / tunitsec;
-          time_bndsp = time_bnds;
+          streamReadRecord(streamID, buffer, &nmiss);
+          for ( size_t i = 0; i < gridsize; i++ )
+            ((float *)var->data)[gridsize * levelID + i] =
+              (float)buffer[i];
         }
       else
         {
-          time_bndsp = NULL;
+          streamReadRecord(streamID, (double *)var->data + gridsize * levelID,
+                           &nmiss);
         }
+    }
+}
 
+static void write_variables(int streamID, struct mapping vars[])
+{
+  int vlistID = streamInqVlist(streamID);
+  int taxisID = vlistInqTaxis(vlistID);
+  int calendar = taxisInqCalendar(taxisID);
+  juldate_t ref_date = juldate_encode(calendar, taxisInqRdate(taxisID),
+                                      taxisInqRtime(taxisID));
+  size_t gridsize = vlistGridsizeMax(vlistID);
+  double *buffer = (double *) Malloc(vlistGridsizeMax(vlistID) *
+                                     sizeof(double));
+  int tsID = 0;
+  int nrecs;
+  while ( (nrecs = streamInqTimestep(streamID, tsID++)) )
+    {
       while ( nrecs-- )
-        {
-          int varID, levelID;
-          streamInqRecord(streamID, &varID, &levelID);
-          struct cc_var *var = find_var(varID, vars, nvars);
-          if ( var )
-            {
-              int nmiss;
-              if ( var->datatype == 'f' )
-                {
-                  streamReadRecord(streamID, buffer, &nmiss);
-                  for ( size_t i = 0; i < gridsize; i++ )
-                    ((float *)var->data)[gridsize * levelID + i] =
-                      (float)buffer[i];
-                }
-              else
-                {
-                  streamReadRecord(streamID,
-                                   (double *)var->data + gridsize * levelID,
-                                   &nmiss);
-                }
-            }
-        }
+        read_record(streamID, buffer, gridsize, vars);
 
-      for ( int i = 0; i < nvars; i++ )
-        cmor_write(vars[i].cmor_varID,
-                   vars[i].data,
-                   vars[i].datatype,
-                   NULL,
-                   1,
-                   &time_val,
-                   time_bndsp,
-                   NULL);
+      double time_val = get_cmor_time_val(taxisID, ref_date);
+      double time_bnds[2];
+      for ( int i = 0; vars[i].cdi_varID != CDI_UNDEFID; i++ )
+        cmor_write(vars[i].cmor_varID, vars[i].data, vars[i].datatype,
+                   1, &time_val,
+                   get_cmor_time_bounds(taxisID, ref_date, time_bnds), NULL);
     }
   Free(buffer);
 }
+
+static void destruct_hash_table(struct kv **ht)
+{
+  struct kv *s, *tmp;
+  HASH_ITER(hh, *ht, s, tmp)
+    {
+      Free(s->key);
+      Free(s->value);
+      Free(s);
+    }
+}
+
+static void destruct_var_mapping(struct mapping vars[])
+{
+  for ( int i = 0; vars[i].cdi_varID != CDI_UNDEFID; i++ )
+    Free(vars[i].data);
+  Free(vars);
+}
+
+static struct mapping *construct_var_mapping(int streamID)
+{
+  int nvars_max = vlistNvars(streamInqVlist(streamID));
+  struct mapping *vars =
+    (struct mapping *) Malloc((nvars_max + 1) * sizeof(struct mapping));
+  vars[0].cdi_varID = CDI_UNDEFID;
+  return vars;
+}
 #endif
 
 void *CMOR(void *argument)
@@ -650,28 +811,19 @@ void *CMOR(void *argument)
   dump_global_attributes(&ht, streamID);
   dump_special_attributes(&ht, streamID);
 
-  int nvars;
-  int nvars_max = vlistNvars(streamInqVlist(streamID));
-  struct cc_var *vars = (struct cc_var *) Malloc(nvars_max
-                                                 * sizeof(struct cc_var));
-  setup(&ht, streamID, params[0]);
-  define_variables(&ht, streamID, vars, &nvars);
-  write_variables(streamID, vars, nvars);
+  setup_dataset(&ht, streamID);
+  int table_id = get_table_id(params[0]);
+  cmor_set_table(table_id);
+
+  struct mapping *vars = construct_var_mapping(streamID);
+  register_axes_and_variables(&ht, table_id, streamID, vars);
+  write_variables(streamID, vars);
+  destruct_var_mapping(vars);
+  destruct_hash_table(&ht);
 
   streamClose(streamID);
   cmor_close();
 
-  for ( int i = 0; i < nvars; i++ )
-    Free(vars[i].data);
-  Free(vars);
-
-  struct kv *s, *tmp;
-  HASH_ITER(hh, ht, s, tmp)
-    {
-      Free(s->key);
-      Free(s->value);
-      Free(s);
-    }
 #else
   cdoWarning("CMOR support not compiled in!");
 #endif
diff --git a/src/CMOR_lite.c b/src/CMOR_lite.c
new file mode 100644
index 0000000..48ca78a
--- /dev/null
+++ b/src/CMOR_lite.c
@@ -0,0 +1,573 @@
+/*
+  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.
+*/
+
+/*
+   This module contains the following operators:
+
+      Setpartab  setpartab       Set parameter table
+*/
+
+#if  defined(HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#if defined(HAVE_LIBUDUNITS2) && (defined(HAVE_UDUNITS2_H) || defined(HAVE_UDUNITS2_UDUNITS2_H))
+#define HAVE_UDUNITS2
+#endif
+
+#if defined(HAVE_UDUNITS2)
+#if defined(HAVE_UDUNITS2_UDUNITS2_H)
+#  include <udunits2/udunits2.h>
+#else
+#  include <udunits2.h>
+#endif
+#endif
+
+#include <errno.h>
+#include <cdi.h>
+#include "cdo.h"
+#include "cdo_int.h"
+#include "pstream.h"
+#include "util.h"
+#include "pmlist.h"
+#include "convert_units.h"
+
+int stringToParam(const char *paramstr);
+
+typedef struct
+{
+  bool convert;
+  bool remove;
+  // missing value
+  bool changemissval;
+  double missval_old;
+  //
+  bool lfactor;
+  double factor;
+  //
+  bool checkvalid;
+  double valid_min;
+  double valid_max;
+  //
+  bool check_min_mean_abs;
+  double ok_min_mean_abs;
+  //
+  bool check_max_mean_abs;
+  double ok_max_mean_abs;
+  // units
+  bool changeunits;
+  char units_old[CDI_MAX_NAME];
+  char units[CDI_MAX_NAME];
+  // varname
+  char name[CDI_MAX_NAME];
+  // converter
+  void *ut_converter;
+
+  double amean;
+  long nvals, n_lower_min, n_greater_max;
+} var_t;
+
+
+void cdo_define_var_units(var_t *var, int vlistID2, int varID, const char *units)
+{
+  char units_old[CDI_MAX_NAME];
+
+  vlistInqVarUnits(vlistID2, varID, units_old);
+  size_t len1 = strlen(units_old);
+  size_t len2 = strlen(units);
+
+  if ( strcmp(units, units_old) != 0 )
+    {
+      if ( len1 > 0 && len2 > 0 )
+	{
+	  var->changeunits = true;
+	  strcpy(var->units_old, units_old);
+	  strcpy(var->units, units);
+	}
+
+      vlistDefVarUnits(vlistID2, varID, units);
+      cdiDefAttTxt(vlistID2, varID, "original_units", (int)strlen(units_old), units_old);
+    }
+}
+
+
+void cmor_check_init(int nvars, var_t *vars)
+{
+  for ( int varID = 0; varID < nvars; ++varID )
+    {
+      var_t *var = &vars[varID];
+      if ( var->checkvalid || var->check_min_mean_abs || var->check_max_mean_abs )
+        {
+          var->amean = 0;
+          var->nvals = 0;
+          var->n_lower_min = 0;
+          var->n_greater_max = 0;
+        }
+    }
+}
+
+
+void cmor_check_eval(int vlistID, int nvars, var_t *vars)
+{
+  char varname[CDI_MAX_NAME];
+
+  for ( int varID = 0; varID < nvars; ++varID )
+    {
+      var_t *var = &vars[varID];
+      if ( var->checkvalid || var->check_min_mean_abs || var->check_max_mean_abs )
+        {
+          double amean = var->amean;
+          long nvals = var->nvals;
+
+          if ( nvals > 0 ) amean /= nvals;
+
+          long n_lower_min = var->n_lower_min;
+          long n_greater_max = var->n_greater_max;
+
+          vlistInqVarName(vlistID, varID, varname);
+
+          if ( n_lower_min > 0 )
+            cdoWarning("Invalid value(s) detected for variable '%s': %i values were lower than minimum valid value (%.4g).",
+                       varname, n_lower_min, var->valid_min);
+          if ( n_greater_max > 0 )
+            cdoWarning("Invalid value(s) detected for variable '%s': %i values were greater than maximum valid value (%.4g).",
+                       varname, n_greater_max, var->valid_max);
+
+          if ( var->check_min_mean_abs )
+            {
+              if ( amean < .1*var->ok_min_mean_abs )
+                cdoWarning("Invalid Absolute Mean for variable '%s' (%.5g) is lower by more than an order of magnitude than minimum allowed: %.4g",
+                           varname, amean, var->ok_min_mean_abs);
+
+              if ( amean < var->ok_min_mean_abs)
+                cdoWarning("Invalid Absolute Mean for variable '%s' (%.5g) is lower than minimum allowed: %.4g",
+                           varname, amean, var->ok_min_mean_abs);
+            }
+
+          if ( var->check_max_mean_abs )
+            {
+              if ( amean > 10.*var->ok_max_mean_abs )
+                cdoWarning("Invalid Absolute Mean for variable '%s' (%.5g) is greater by more than an order of magnitude than maximum allowed: %.4g",
+                           varname, amean, var->ok_max_mean_abs);
+      
+              if ( amean > var->ok_max_mean_abs )
+                cdoWarning("Invalid Absolute Mean for variable '%s' (%.5g) is greater than maximum allowed: %.4g",
+                           varname, amean, var->ok_max_mean_abs);
+            }
+        }
+    }
+}
+
+
+void cmor_check_prep(var_t *var, long gridsize, double missval, double *array)
+{
+  if ( var->checkvalid || var->check_min_mean_abs || var->check_max_mean_abs )
+    {
+      double aval;
+      double amean = 0;
+      long nvals = 0;
+  
+      for ( long i = 0; i < gridsize; ++i )
+        {
+          aval = array[i];
+          if ( !DBL_IS_EQUAL(aval, missval) )
+            {
+              amean += fabs(aval);
+              nvals++;
+            }
+        }
+
+      var->amean += amean;
+      var->nvals += nvals;
+
+      long n_lower_min = 0;
+      long n_greater_max = 0;
+
+      for ( long i = 0; i < gridsize; ++i )
+        {
+          aval = array[i];
+          if ( !DBL_IS_EQUAL(aval, missval) )
+            {
+              if ( aval < var->valid_min ) n_lower_min++;
+              if ( aval > var->valid_max ) n_greater_max++;
+            }
+        }
+
+      var->n_lower_min += n_lower_min;
+      var->n_greater_max += n_greater_max;
+    }
+}
+
+static
+void apply_cmorlist(list_t *pmlist, int nvars, int vlistID2, var_t *vars)
+{
+  const char *hentry[] = {"Header"};
+  const char *ventry[] = {"variable_entry", "parameter"};
+  int nventry = (int) sizeof(ventry)/sizeof(ventry[0]);
+  int nhentry = (int) sizeof(hentry)/sizeof(hentry[0]);
+  char varname[CDI_MAX_NAME];
+
+  // search for global missing value
+  bool lmissval = false;
+  double missval;
+  list_t *kvlist = pmlist_get_kvlist_ventry(pmlist, nhentry, hentry);
+  if ( kvlist )
+    {
+      for ( listNode_t *kvnode = kvlist->head; kvnode; kvnode = kvnode->next )
+        {
+          keyValues_t *kv = *(keyValues_t **)kvnode->data;
+          const char *key = kv->key;
+          const char *value = (kv->nvalues == 1) ? kv->values[0] : NULL;
+          if ( !value ) continue;
+
+          if ( STR_IS_EQ(key, "missing_value") )
+            {
+              lmissval = true;
+              missval = parameter2double(kv->values[0]);
+            }
+          else if ( STR_IS_EQ(key, "table_id") ||
+                    STR_IS_EQ(key, "modeling_realm") ||
+                    STR_IS_EQ(key, "realm") ||
+                    STR_IS_EQ(key, "project_id") ||
+                    STR_IS_EQ(key, "frequency") )
+            {
+              cdiDefAttTxt(vlistID2, CDI_GLOBAL, key, (int)strlen(value), value);
+            }
+        }
+    }
+
+  for ( int varID = 0; varID < nvars; varID++ )
+    {
+      var_t *var = &vars[varID];
+      vlistInqVarName(vlistID2, varID, varname);
+
+      strcpy(var->name, varname);
+      if ( lmissval )
+        {
+          double missval_old = vlistInqVarMissval(vlistID2, varID);
+          if ( ! DBL_IS_EQUAL(missval, missval_old) )
+            {
+              var->changemissval = true;
+              var->missval_old = missval_old;
+              vlistDefVarMissval(vlistID2, varID, missval);
+            }
+        }
+
+      list_t *kvlist = pmlist_search_kvlist_ventry(pmlist, "name", varname, nventry, ventry);
+      if ( kvlist )
+        {
+          bool lvalid_min = false, lvalid_max = false;
+
+          for ( listNode_t *kvnode = kvlist->head; kvnode; kvnode = kvnode->next )
+            {
+              keyValues_t *kv = *(keyValues_t **)kvnode->data;
+              const char *key = kv->key;
+              const char *value = (kv->nvalues == 1) ? kv->values[0] : NULL;
+              if ( !value ) continue;
+              
+              //printf("key=%s  value=%s\n", key, value);
+
+              if      ( STR_IS_EQ(key, "standard_name") ) vlistDefVarStdname(vlistID2, varID, value);
+              else if ( STR_IS_EQ(key, "long_name")     ) vlistDefVarLongname(vlistID2, varID, value);
+              else if ( STR_IS_EQ(key, "units")         ) cdo_define_var_units(var, vlistID2, varID, value);
+              else if ( STR_IS_EQ(key, "name")          ) /*vlistDefVarName(vlistID2, varID, parameter2word(value))*/;
+              else if ( STR_IS_EQ(key, "out_name")      )
+                {
+                  const char *outname = parameter2word(value);
+                  if ( !STR_IS_EQ(var->name, outname) )
+                    {
+                      vlistDefVarName(vlistID2, varID, outname);
+                      cdiDefAttTxt(vlistID2, varID, "original_name", (int)strlen(var->name), var->name);
+                    }
+                }
+              else if ( STR_IS_EQ(key, "param")         ) vlistDefVarParam(vlistID2, varID, stringToParam(parameter2word(value)));
+              else if ( STR_IS_EQ(key, "out_param")     ) vlistDefVarParam(vlistID2, varID, stringToParam(parameter2word(value)));
+              else if ( STR_IS_EQ(key, "comment")       ) cdiDefAttTxt(vlistID2, varID, key, (int)strlen(value), value);
+              else if ( STR_IS_EQ(key, "cell_methods")  ) cdiDefAttTxt(vlistID2, varID, key, (int)strlen(value), value);
+              else if ( STR_IS_EQ(key, "cell_measures") ) cdiDefAttTxt(vlistID2, varID, key, (int)strlen(value), value);
+              else if ( STR_IS_EQ(key, "delete")        ) var->remove = parameter2bool(value);
+              else if ( STR_IS_EQ(key, "convert")       ) var->convert = parameter2bool(value);
+              else if ( STR_IS_EQ(key, "factor")        )
+                {
+                  var->lfactor = true;
+                  var->factor = parameter2double(value);
+                  if ( cdoVerbose ) cdoPrint("%s - scale factor %g", varname, var->factor);
+                }
+              else if ( STR_IS_EQ(key, "missval") || STR_IS_EQ(key, "missing_value") )
+                {
+                  double missval = parameter2double(value);
+                  double missval_old = vlistInqVarMissval(vlistID2, varID);
+                  if ( ! DBL_IS_EQUAL(missval, missval_old) )
+                    {
+                      if ( cdoVerbose ) cdoPrint("%s - change missval from %g to %g", varname, missval_old, missval);
+                      var->changemissval = true;
+                      var->missval_old = missval_old;
+                      vlistDefVarMissval(vlistID2, varID, missval);
+                    }
+                }
+              else if ( STR_IS_EQ(key, "valid_min") )
+                {
+                  lvalid_min = true;
+                  var->valid_min = parameter2double(value);
+                }
+              else if ( STR_IS_EQ(key, "valid_max") )
+                {
+                  lvalid_max = true;
+                  var->valid_max = parameter2double(value);
+                }
+              else if ( STR_IS_EQ(key, "ok_min_mean_abs") )
+                {
+                  var->check_min_mean_abs = true;
+                  var->ok_min_mean_abs = parameter2double(value);
+                }
+              else if ( STR_IS_EQ(key, "ok_max_mean_abs") )
+                {
+                  var->check_max_mean_abs = true;
+                  var->ok_max_mean_abs = parameter2double(value);
+                }
+              else if ( STR_IS_EQ(key, "datatype") || STR_IS_EQ(key, "type") )
+                {
+                  int datatype = str2datatype(parameter2word(value));
+                  if ( datatype != -1 ) vlistDefVarDatatype(vlistID2, varID, datatype);
+                }
+              else
+                {
+                  if ( cdoVerbose ) cdoPrint("Attribute %s:%s not supported!", varname,  key);
+                }
+            }
+
+          if ( lvalid_min && lvalid_max ) var->checkvalid = true;
+        }
+      else
+        {
+          cdoPrint("Variable %s not found in CMOR table!", varname);
+        }
+    }
+}
+
+
+void *CMOR_lite(void *argument)
+{
+  int nrecs;
+  int varID, levelID;
+  int nmiss;
+  bool delvars = false;
+  double missval;
+
+  cdoInitialize(argument);
+
+  CDO_CMOR_Mode = 1;
+  if ( CDO_CMOR_Mode ) cdiDefGlobal("CMOR_MODE", CDO_CMOR_Mode);
+
+  cdoOperatorAdd("cmorlite",  0, 0, "parameter table name");
+
+  int operatorID = cdoOperatorID();
+
+  operatorInputArg(cdoOperatorEnter(operatorID));
+
+  if ( operatorArgc() < 1 ) cdoAbort("Too few arguments!");
+
+  bool convert_data = false;
+  if ( operatorArgc() == 2 )
+    {
+      if ( strcmp("convert", operatorArgv()[1]) == 0 ) convert_data = true;
+      else cdoAbort("Unknown parameter: >%s<", operatorArgv()[1]); 
+    }
+
+  if ( operatorArgc() > 2 ) cdoAbort("Too many arguments!");
+
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
+  /* vlistPrint(vlistID2);*/
+
+  int nvars = vlistNvars(vlistID2);
+  var_t *vars = (var_t *) Malloc(nvars*sizeof(var_t));
+  memset(vars, 0, nvars*sizeof(var_t));
+
+  if ( convert_data )
+    for ( varID = 0; varID < nvars; ++varID ) vars[varID].convert = true;
+
+  const char *filename = operatorArgv()[0];
+  FILE *fp = fopen(filename, "r");
+  if ( fp == NULL ) cdoAbort("Open failed on: %s\n", filename);
+      
+  list_t *pmlist = cmortable_to_pmlist(fp, filename);
+  fclose(fp);
+
+  apply_cmorlist(pmlist, nvars, vlistID2, vars);
+  list_destroy(pmlist);
+
+  for ( int varID = 0; varID < nvars; ++varID )
+    if ( vars[varID].remove )
+      {
+        delvars = true;
+        break;
+      }
+
+  if ( delvars )
+    {
+      vlistClearFlag(vlistID1);
+      vlistClearFlag(vlistID2);
+
+      for ( int varID = 0; varID < nvars; varID++ )
+        {
+          int zaxisID = vlistInqVarZaxis(vlistID2, varID);
+          int nlevs   = zaxisInqSize(zaxisID);
+          for ( int levID = 0; levID < nlevs; levID++ )
+            {
+              vlistDefFlag(vlistID1, varID, levID, TRUE);
+              vlistDefFlag(vlistID2, varID, levID, TRUE);
+              if ( vars[varID].remove )
+                {
+                  vlistDefFlag(vlistID1, varID, levID, FALSE);
+                  vlistDefFlag(vlistID2, varID, levID, FALSE);
+                }
+            }
+        }
+
+      int vlistIDx = vlistCreate();
+      vlistCopyFlag(vlistIDx, vlistID2);
+
+      vlistDestroy(vlistID2);
+    
+      vlistID2 = vlistIDx;
+      if ( vlistNvars(vlistID2) == 0 ) cdoAbort("No variable selected!");
+    }
+
+  for ( int varID = 0; varID < nvars; ++varID )
+    {
+      var_t *var = &vars[varID];
+      if ( var->convert == false ) var->changeunits = false;
+      if ( var->changeunits )
+        cdoConvertUnits(&var->ut_converter, &var->changeunits, (char*)&var->units, (char*)&var->units_old, var->name);
+    }
+
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
+  vlistDefTaxis(vlistID2, taxisID2);
+
+  /* vlistPrint(vlistID2);*/
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+
+  streamDefVlist(streamID2, vlistID2);
+
+  long gridsize = vlistGridsizeMax(vlistID1);
+  if ( vlistNumber(vlistID1) != CDI_REAL ) gridsize *= 2;
+  double *array = (double *) Malloc(gridsize*sizeof(double));
+
+  int tsID1 = 0;
+  while ( (nrecs = streamInqTimestep(streamID1, tsID1)) )
+    {
+      taxisCopyTimestep(taxisID2, taxisID1);
+
+      streamDefTimestep(streamID2, tsID1);
+
+      cmor_check_init(nvars, vars);
+
+      for ( int recID = 0; recID < nrecs; recID++ )
+	{
+	  streamInqRecord(streamID1, &varID, &levelID);
+
+          var_t *var = &vars[varID];
+	  int varID2 = varID;
+	  int levelID2 = levelID;
+
+	  if ( delvars )
+	    {
+	      if ( var->remove ) continue;
+
+	      if ( vlistInqFlag(vlistID1, varID, levelID) == TRUE )
+		{
+		  varID2   = vlistFindVar(vlistID2, varID);
+		  levelID2 = vlistFindLevel(vlistID2, varID, levelID);
+		}
+	    }
+
+	  streamDefRecord(streamID2,  varID2,  levelID2);
+
+	  streamReadRecord(streamID1, array, &nmiss);
+
+	  missval = vlistInqVarMissval(vlistID2, varID2);
+	  gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID2));
+	  if ( vlistInqVarNumber(vlistID2, varID2) != CDI_REAL ) gridsize *= 2;
+
+	  if ( nmiss > 0 && var->changemissval )
+	    {
+	      for ( long i = 0; i < gridsize; ++i )
+		{
+		  if ( DBL_IS_EQUAL(array[i], var->missval_old) ) array[i] = missval;
+		}
+	    }
+
+	  if ( var->lfactor )
+	    {
+	      for ( long i = 0; i < gridsize; ++i )
+		{
+		  if ( !DBL_IS_EQUAL(array[i], missval) ) array[i] *= var->factor;
+		}
+	    }
+
+#if defined(HAVE_UDUNITS2)
+	  if ( var->changeunits )
+	    {
+	      int nerr = 0;
+	      for ( long i = 0; i < gridsize; ++i )
+		{
+		  if ( !DBL_IS_EQUAL(array[i], missval) )
+		    {
+		      array[i] = cv_convert_double((const cv_converter*)var->ut_converter, array[i]);
+		      if ( ut_get_status() != UT_SUCCESS ) nerr++;
+		    }
+		}
+	      if ( nerr )
+		{
+		  cdoWarning("Udunits: Error converting units from [%s] to [%s], parameter: %s",
+			     var->units_old, var->units, var->name);
+		  var->changeunits = false;
+		}
+	    }
+#endif
+	  
+	  streamWriteRecord(streamID2, array, nmiss);
+
+          cmor_check_prep(var, gridsize, missval, array);
+	}
+
+      cmor_check_eval(vlistID2, nvars, vars);
+
+      tsID1++;
+    }
+
+  streamClose(streamID2);
+  streamClose(streamID1);
+
+#if defined(HAVE_UDUNITS2)
+  for ( int varID = 0; varID < nvars; varID++ )
+    if ( vars[varID].ut_converter ) cdoConvertFree(vars[varID].ut_converter);
+
+  cdoConvertDestroy();
+#endif
+
+  if ( array ) Free(array);
+  if ( vars  ) Free(vars);
+
+  cdoFinish();
+
+  return 0;
+}
diff --git a/src/CMOR_table.c b/src/CMOR_table.c
new file mode 100644
index 0000000..54f820a
--- /dev/null
+++ b/src/CMOR_table.c
@@ -0,0 +1,163 @@
+/*
+  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.
+*/
+
+/*
+   This module contains the following operators:
+
+*/
+
+#include "cdo.h"
+#include "cdo_int.h"
+#include "pmlist.h"
+
+
+static
+void dump_cmor_table(list_t *pmlist)
+{  
+  printf("# Number of lists: %d\n", list_size(pmlist));
+  int i = 0;
+  for ( listNode_t *pmnode = pmlist->head; pmnode; pmnode = pmnode->next )
+    {
+      list_t *kvlist = *(list_t **)pmnode->data;
+      printf("# list ID: %d;   Number of elements: %d\n", i, list_size(kvlist));
+      printf("&%s\n", list_name(kvlist));
+      for ( listNode_t *kvnode = kvlist->head; kvnode; kvnode = kvnode->next )
+        {
+          keyValues_t *kv = *(keyValues_t **)kvnode->data;
+          if ( kv ) printf("  %s = %s\n", kv->key, kv->values[0]);
+        }
+      printf("/\n");
+      ++i;
+    }
+}
+
+static
+void conv_cmor_table(list_t *pmlist)
+{
+  const char *hname = "Header";
+  const char *vname = "variable";
+  //const char *aname = "axis";
+
+  bool hasmissval = false;
+  double missval;
+
+  for ( listNode_t *pmnode = pmlist->head; pmnode; pmnode = pmnode->next )
+    {
+      list_t *kvlist = *(list_t **)pmnode->data;
+      const char *listname = list_name(kvlist);
+
+      if ( strncmp(listname, hname, strlen(hname)) == 0  )
+	{
+          for ( listNode_t *kvnode = kvlist->head; kvnode; kvnode = kvnode->next )
+	    {
+              keyValues_t *kv = *(keyValues_t **)kvnode->data;
+              const char *ename  = kv->key;
+	      const char *evalue = kv->values[0];
+              size_t len = strlen(ename);
+
+	      if ( strncmp("missing_value", ename, len) == 0 )
+		{
+		  missval = atof(evalue);
+		  hasmissval = true;
+		}
+	    }
+	}
+      else if ( strncmp(listname, vname, strlen(vname)) == 0 )
+	{
+	  printf("&%s\n", "parameter");
+          for ( listNode_t *kvnode = kvlist->head; kvnode; kvnode = kvnode->next )
+	    {
+              keyValues_t *kv = *(keyValues_t **)kvnode->data;
+              const char *ename  = kv->key;
+	      const char *evalue = kv->values[0];
+	      int len = strlen(ename);
+	      int vlen = strlen(evalue);
+
+	      if ( vlen > 1 && evalue[0] == '"' && evalue[vlen-1] == '"' ) 
+		{
+		  vlen -= 2;
+		  evalue++;
+		}
+
+	      char *ovalue = strdup(evalue);
+	      for ( int i = 1; i < vlen; ++i )
+		{
+		  if ( ovalue[i-1] == '"' && ovalue[i] == '"' )
+		    {
+		      ovalue [i-1] = '\'';
+		      for ( int j = i+1; j < vlen; ++j ) ovalue[j-1] = ovalue[j];
+		      vlen -= 1;
+		    }
+		}
+
+              if ( vlen )
+                {
+                  if ( strncmp("name", ename, len)            == 0 ||
+                       strncmp("standard_name", ename, len)   == 0 ||
+                       strncmp("out_name", ename, len)        == 0 ||
+                       strncmp("type", ename, len)            == 0 ||
+                       strncmp("valid_min", ename, len)       == 0 ||
+                       strncmp("valid_max", ename, len)       == 0 ||
+                       strncmp("ok_min_mean_abs", ename, len) == 0 ||
+                       strncmp("ok_max_mean_abs", ename, len) == 0 )
+                    printf("  %-15s = %s\n", ename, ovalue);
+                  else if ( strncmp("long_name", ename, len)  == 0 ||
+                            strncmp("units", ename, len)           == 0 ||
+                            strncmp("cell_methods", ename, len)    == 0 ||
+                            strncmp("cell_measures", ename, len)   == 0 ||
+                            strncmp("comment", ename, len)         == 0 )
+                    printf("  %-15s = \"%.*s\"\n", ename, vlen, ovalue);
+                }
+              
+	      Free(ovalue);
+	    }
+	  if ( hasmissval ) printf("  %-15s = %g\n", "missing_value", missval);
+	  printf("/\n");
+	}
+    }
+}
+
+
+void *CMOR_table(void *argument)
+{
+  cdoInitialize(argument);
+
+  int DUMP_CMOR_TABLE = cdoOperatorAdd("dump_cmor_table",   0,   0, NULL);
+  int CONV_CMOR_TABLE = cdoOperatorAdd("conv_cmor_table",   0,   0, NULL);
+
+  int operatorID = cdoOperatorID();
+
+  if ( operatorArgc() != 1 ) cdoAbort("Too few arguments!");
+  const char *filename = operatorArgv()[0];
+
+  if ( cdoVerbose ) cdoPrint("Parse file: %s", filename);
+  
+  FILE *fp = fopen(filename, "r");
+  if ( fp == NULL ) cdoAbort("Open failed on: %s\n", filename);
+      
+  list_t *pmlist = cmortable_to_pmlist(fp, filename);
+  fclose(fp);
+
+  if      ( operatorID == DUMP_CMOR_TABLE ) dump_cmor_table(pmlist);
+  else if ( operatorID == CONV_CMOR_TABLE ) conv_cmor_table(pmlist);
+
+  list_destroy(pmlist);
+
+  cdoFinish();
+
+  return 0;
+}
diff --git a/src/Cat.c b/src/Cat.c
index ed2cece..91b866e 100644
--- a/src/Cat.c
+++ b/src/Cat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -62,9 +62,17 @@ void *Cat(void *argument)
 
       if ( indf == 0 )
 	{
-	  int file_exists = fileExists(cdoStreamName(nfiles)->args);
-	  if ( cdoOverwriteMode ) file_exists = 0;
-
+          int ntsteps = vlistNtsteps(vlistID1);
+          int nvars   = vlistNvars(vlistID1);
+          if ( ntsteps == 1 )
+            {
+              for ( varID = 0; varID < nvars; ++varID )
+                if ( vlistInqVarTsteptype(vlistID1, varID) != TSTEP_CONSTANT ) break;
+		  
+              if ( varID == nvars ) ntsteps = 0;
+            }
+	      
+	  bool file_exists = (!cdoOverwriteMode) ? fileExists(cdoStreamName(nfiles)->args) : false;
 	  if ( file_exists )
 	    {
 	      streamID2 = streamOpenAppend(cdoStreamName(nfiles));
@@ -76,7 +84,9 @@ void *Cat(void *argument)
 
 	      tsID2 = vlistNtsteps(vlistID2);
 	      if ( tsID2 == 0 ) tsID2 = 1; /* bug fix for time constant data only */
-	    }
+
+              if ( ntsteps == 0 ) lconstvars = false;
+            }
 	  else
 	    {
 	      if ( cdoVerbose )
@@ -87,17 +97,6 @@ void *Cat(void *argument)
 	      vlistID2 = vlistDuplicate(vlistID1);
 	      taxisID2 = taxisDuplicate(taxisID1);
 	      vlistDefTaxis(vlistID2, taxisID2);
-	  
-	      int ntsteps = vlistNtsteps(vlistID1);
-	      int nvars   = vlistNvars(vlistID1);
-	      
-	      if ( ntsteps == 1 )
-		{
-		  for ( varID = 0; varID < nvars; ++varID )
-		    if ( vlistInqVarTsteptype(vlistID1, varID) != TSTEP_CONSTANT ) break;
-		  
-		  if ( varID == nvars ) ntsteps = 0;
-		}
 
 	      if ( ntsteps == 0 && nfiles > 1 )
 		{
@@ -125,11 +124,8 @@ void *Cat(void *argument)
       int tsID1 = 0;
       while ( (nrecs = streamInqTimestep(streamID1, tsID1)) )
 	{          
-	  {
-	    double fstatus = indf+1.;
-	    if ( ntsteps > 1 ) fstatus = indf+(tsID1+1.)/ntsteps;
-	    if ( !cdoVerbose ) progressStatus(0, 1, fstatus/nfiles);
-	  }
+          double fstatus = (ntsteps > 1) ? indf+(tsID1+1.)/ntsteps : indf+1.;
+          if ( !cdoVerbose ) progressStatus(0, 1, fstatus/nfiles);
 
 	  taxisCopyTimestep(taxisID2, taxisID1);
 
@@ -143,7 +139,7 @@ void *Cat(void *argument)
                 if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT )
                   continue;
 
-	      streamDefRecord(streamID2,  varID,  levelID);
+	      streamDefRecord(streamID2, varID, levelID);
 
 	      if ( lcopy )
 		{
diff --git a/src/Change.c b/src/Change.c
index 597f2ba..045d7ed 100644
--- a/src/Change.c
+++ b/src/Change.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -39,14 +39,9 @@ int stringToParam(const char *paramstr);
 
 void *Change(void *argument)
 {
-  int CHCODE, CHTABNUM, CHPARAM, CHNAME, CHUNIT, CHLEVEL, CHLEVELC, CHLEVELV, CHLTYPE;  
-  int operatorID;
-  int streamID1, streamID2 = CDI_UNDEFID;
   int nrecs, nvars;
-  int tsID1, recID, varID = 0, levelID;
-  int vlistID1, vlistID2;
-  int taxisID1, taxisID2;
-  int chints[MAXARG], nch = 0;
+  int varID = 0, levelID;
+  int chints[MAXARG];
   char *chnames[MAXARG];
   char varname[CDI_MAX_NAME];
   char *chname = NULL;
@@ -54,32 +49,30 @@ void *Change(void *argument)
   int param;
   int code, tabnum, i;
   int nmiss;
-  int gridsize;
   int nfound;
   int nzaxis, zaxisID1, zaxisID2, k, nlevs, index; 
   double chlevels[MAXARG];
   int  chltypes[MAXARG];              
   double *levels = NULL;
   double *newlevels = NULL;
-  double *array = NULL;
 
   cdoInitialize(argument);
 
-  CHCODE   = cdoOperatorAdd("chcode",   0, 0, "pairs of old and new code numbers");
-  CHTABNUM = cdoOperatorAdd("chtabnum", 0, 0, "pairs of old and new GRIB1 table numbers");
-  CHPARAM  = cdoOperatorAdd("chparam",  0, 0, "pairs of old and new parameter identifiers");
-  CHNAME   = cdoOperatorAdd("chname",   0, 0, "pairs of old and new variable names");
-  CHUNIT   = cdoOperatorAdd("chunit",   0, 0, "pairs of old and new variable units");
-  CHLEVEL  = cdoOperatorAdd("chlevel",  0, 0, "pairs of old and new levels");
-  CHLEVELC = cdoOperatorAdd("chlevelc", 0, 0, "code number, old and new level");
-  CHLEVELV = cdoOperatorAdd("chlevelv", 0, 0, "variable name, old and new level");
-  CHLTYPE  = cdoOperatorAdd("chltype",  0, 0, "pairs of old and new type");          
+  int CHCODE   = cdoOperatorAdd("chcode",   0, 0, "pairs of old and new code numbers");
+  int CHTABNUM = cdoOperatorAdd("chtabnum", 0, 0, "pairs of old and new GRIB1 table numbers");
+  int CHPARAM  = cdoOperatorAdd("chparam",  0, 0, "pairs of old and new parameter identifiers");
+  int CHNAME   = cdoOperatorAdd("chname",   0, 0, "pairs of old and new variable names");
+  int CHUNIT   = cdoOperatorAdd("chunit",   0, 0, "pairs of old and new variable units");
+  int CHLEVEL  = cdoOperatorAdd("chlevel",  0, 0, "pairs of old and new levels");
+  int CHLEVELC = cdoOperatorAdd("chlevelc", 0, 0, "code number, old and new level");
+  int CHLEVELV = cdoOperatorAdd("chlevelv", 0, 0, "variable name, old and new level");
+  int CHLTYPE  = cdoOperatorAdd("chltype",  0, 0, "pairs of old and new type");          
 
-  operatorID = cdoOperatorID();
+  int operatorID = cdoOperatorID();
 
   operatorInputArg(cdoOperatorEnter(operatorID));
 
-  nch = operatorArgc();
+  int nch = operatorArgc();
 
   if ( operatorID == CHCODE || operatorID == CHTABNUM )
     {
@@ -122,13 +115,13 @@ void *Change(void *argument)
 	chltypes[i] = parameter2int(operatorArgv()[i]);
     }
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
   if ( operatorID == CHCODE )
@@ -203,33 +196,36 @@ void *Change(void *argument)
       for ( index = 0; index < nzaxis; index++ )
 	{
 	  zaxisID1 = vlistZaxis(vlistID2, index);
-	  nlevs = zaxisInqSize(zaxisID1);
-	  levels = (double*) Malloc(nlevs*sizeof(double));
-	  newlevels = (double*) Malloc(nlevs*sizeof(double));
-	  zaxisInqLevels(zaxisID1, levels);
-
-	  for ( k = 0; k < nlevs; k++ ) newlevels[k] = levels[k];
-
-	  nfound = 0;
-	  for ( i = 0; i < nch; i += 2 )
-	    for ( k = 0; k < nlevs; k++ )
-	      if ( fabs(levels[k] - chlevels[i]) < 0.0001 ) nfound++;
-
-	  if ( nfound )
-	    {
-	      zaxisID2 = zaxisDuplicate(zaxisID1);
-	      for ( i = 0; i < nch; i += 2 )
-		for ( k = 0; k < nlevs; k++ )
-		  if ( fabs(levels[k] - chlevels[i]) < 0.001 )
-		    newlevels[k] = chlevels[i+1];
-
-	      zaxisDefLevels(zaxisID2, newlevels);
-	      vlistChangeZaxis(vlistID2, zaxisID1, zaxisID2);
-	    }
-
-	  Free(levels);
-	  Free(newlevels);
-	}
+          if ( zaxisInqLevels(zaxisID1, NULL) )
+            {
+              nlevs = zaxisInqSize(zaxisID1);
+              levels = (double*) Malloc(nlevs*sizeof(double));
+              newlevels = (double*) Malloc(nlevs*sizeof(double));
+              zaxisInqLevels(zaxisID1, levels);
+
+              for ( k = 0; k < nlevs; k++ ) newlevels[k] = levels[k];
+
+              nfound = 0;
+              for ( i = 0; i < nch; i += 2 )
+                for ( k = 0; k < nlevs; k++ )
+                  if ( fabs(levels[k] - chlevels[i]) < 0.0001 ) nfound++;
+
+              if ( nfound )
+                {
+                  zaxisID2 = zaxisDuplicate(zaxisID1);
+                  for ( i = 0; i < nch; i += 2 )
+                    for ( k = 0; k < nlevs; k++ )
+                      if ( fabs(levels[k] - chlevels[i]) < 0.001 )
+                        newlevels[k] = chlevels[i+1];
+
+                  zaxisDefLevels(zaxisID2, newlevels);
+                  vlistChangeZaxis(vlistID2, zaxisID1, zaxisID2);
+                }
+
+              Free(levels);
+              Free(newlevels);
+            }
+        }
     }
   else if ( operatorID == CHLEVELC || operatorID == CHLEVELV )
     {
@@ -254,27 +250,30 @@ void *Change(void *argument)
 	}
 
       zaxisID1 = vlistInqVarZaxis(vlistID2, varID);
-      nlevs = zaxisInqSize(zaxisID1);
-      levels = (double*) Malloc(nlevs*sizeof(double));
-      zaxisInqLevels(zaxisID1, levels);
-      nfound = 0;
-      for ( k = 0; k < nlevs; k++ )
-	if ( fabs(levels[k] - chlevels[0]) < 0.0001 ) nfound++;
-
-      if ( nfound )
-	{
-	  zaxisID2 = zaxisDuplicate(zaxisID1);
-	  for ( k = 0; k < nlevs; k++ )
-	    if ( fabs(levels[k] - chlevels[0]) < 0.001 )
-	      levels[k] = chlevels[1];
-
-	  zaxisDefLevels(zaxisID2, levels);
-	  vlistChangeVarZaxis(vlistID2, varID, zaxisID2);
-	}
-      else
-	cdoAbort("Level %g not found!", chlevels[0]);
-
-      Free(levels);
+      if ( zaxisInqLevels(zaxisID1, NULL) )
+        {
+          nlevs = zaxisInqSize(zaxisID1);
+          levels = (double*) Malloc(nlevs*sizeof(double));
+          zaxisInqLevels(zaxisID1, levels);
+          nfound = 0;
+          for ( k = 0; k < nlevs; k++ )
+            if ( fabs(levels[k] - chlevels[0]) < 0.0001 ) nfound++;
+
+          if ( nfound )
+            {
+              zaxisID2 = zaxisDuplicate(zaxisID1);
+              for ( k = 0; k < nlevs; k++ )
+                if ( fabs(levels[k] - chlevels[0]) < 0.001 )
+                  levels[k] = chlevels[1];
+
+              zaxisDefLevels(zaxisID2, levels);
+              vlistChangeVarZaxis(vlistID2, varID, zaxisID2);
+            }
+          else
+            cdoAbort("Level %g not found!", chlevels[0]);
+
+          Free(levels);
+        }
     }
   else if ( operatorID == CHLTYPE )                
     {
@@ -303,21 +302,21 @@ void *Change(void *argument)
 	}
     }
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  gridsize = vlistGridsizeMax(vlistID2);
-  array = (double*) Malloc(gridsize*sizeof(double));
+  int gridsize = vlistGridsizeMax(vlistID2);
+  double *array = (double*) Malloc(gridsize*sizeof(double));
 
-  tsID1 = 0;
+  int tsID1 = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID1)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
 
       streamDefTimestep(streamID2, tsID1);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamDefRecord(streamID2,  varID,  levelID);
diff --git a/src/Change_e5slm.c b/src/Change_e5slm.c
index d448fec..9cbcdc2 100644
--- a/src/Change_e5slm.c
+++ b/src/Change_e5slm.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -29,33 +29,24 @@
 
 void *Change_e5slm(void *argument)
 {
-  int streamIDslm, streamID1, streamID2;
-  const char *fn_slm;
   char name[CDI_MAX_NAME];
   int nrecs, code;
-  int tsID, recID, varID, levelID;
-  int gridsize;
-  int vlistIDslm, vlistID1, vlistID2 = -1;
-  int nmiss, nvars;
-  int taxisID1, taxisID2;
-  short *codes = NULL;
-  short *lsea = NULL;
+  int varID, levelID;
+  int nmiss;
   long i;
   double minval, maxval;
-  double *array = NULL;
-  double *cland = NULL;
 
   cdoInitialize(argument);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  taxisID1 = vlistInqTaxis(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
-  vlistID2 = vlistDuplicate(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
   streamDefVlist(streamID2, vlistID2);
@@ -64,20 +55,20 @@ void *Change_e5slm(void *argument)
   /* get filename of SLM */
   operatorInputArg("filename of the sea land mask");
   operatorCheckArgc(1);
-  fn_slm = operatorArgv()[0];
+  const char *fn_slm = operatorArgv()[0];
 
   /* read SLM */
   argument_t *fileargument = file_argument_new(fn_slm);
-  streamIDslm = streamOpenRead(fileargument);
+  int streamIDslm = streamOpenRead(fileargument);
   file_argument_free(fileargument);
 
-  vlistIDslm = streamInqVlist(streamIDslm);
+  int vlistIDslm = streamInqVlist(streamIDslm);
 
-  gridsize = gridInqSize(vlistInqVarGrid(vlistIDslm, 0));
+  int gridsize = gridInqSize(vlistInqVarGrid(vlistIDslm, 0));
 
-  array = (double*) Malloc(gridsize*sizeof(double));
-  cland = (double*) Malloc(gridsize*sizeof(double));
-  lsea  = (short*) Malloc(gridsize*sizeof(short));
+  double *array = (double*) Malloc(gridsize*sizeof(double));
+  double *cland = (double*) Malloc(gridsize*sizeof(double));
+  bool *lsea  = (bool*) Malloc(gridsize*sizeof(bool));
 
   streamInqTimestep(streamIDslm, 0);
 
@@ -95,14 +86,14 @@ void *Change_e5slm(void *argument)
   for ( i = 0; i < gridsize; ++i )
     {
       if ( cland[i] > 0 )
-	lsea[i] = FALSE;
+	lsea[i] = false;
       else
-	lsea[i] = TRUE;
+	lsea[i] = true;
     }
 
 
-  nvars = vlistNvars(vlistID1);
-  codes = (short*) Malloc(nvars*sizeof(short));
+  int nvars = vlistNvars(vlistID1);
+  short *codes = (short*) Malloc(nvars*sizeof(short));
 
   for ( varID = 0; varID < nvars; ++varID )
     {
@@ -132,14 +123,14 @@ void *Change_e5slm(void *argument)
     }
 
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
 
       streamDefTimestep(streamID2, tsID);
       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{ 
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, array, &nmiss);
diff --git a/src/Cloudlayer.c b/src/Cloudlayer.c
index a2c2aea..d397503 100644
--- a/src/Cloudlayer.c
+++ b/src/Cloudlayer.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -15,7 +15,6 @@
   GNU General Public License for more details.
 */
 
-#include <ctype.h>
 
 #include <cdi.h>
 #include "cdo.h"
@@ -123,9 +122,9 @@ void pl_index(int *kmax, int *kmin, double pmax, double pmin, long nlevs, double
 void *Cloudlayer(void *argument)
 {
   int gridID, zaxisID;
-  int nlevel, nlevs, nrecs, recID, code;
+  int nlevel, nlevs, nrecs, code;
   int varID, levelID;
-  int zrev = FALSE;
+  bool zrev = false;
   int i;
   int offset;
   int nmiss;
@@ -135,7 +134,6 @@ void *Cloudlayer(void *argument)
   int kmin[NVARS], kmax[NVARS];
   char varname[CDI_MAX_NAME];
   double sfclevel = 0;
-  double *plevs = NULL;
   double *cloud[NVARS];
   double pmin = 0, pmax = 0;
 
@@ -206,12 +204,12 @@ void *Cloudlayer(void *argument)
 
   if ( zaxisInqType(zaxisID) == ZAXIS_PRESSURE )
     {
-      plevs = (double*) Malloc(nlevel*sizeof(double));
+      double *plevs = (double*) Malloc(nlevel*sizeof(double));
       zaxisInqLevels(zaxisID, plevs);
       if ( plevs[0] > plevs[nlevel-1] )
 	{
 	  double ptmp;
-	  zrev = TRUE;
+	  zrev = true;
 	  for ( levelID = 0; levelID < nlevel/2; ++levelID )
 	    {
 	      ptmp = plevs[levelID];
@@ -240,18 +238,14 @@ void *Cloudlayer(void *argument)
     }
   else if ( zaxisInqType(zaxisID) == ZAXIS_HYBRID )
     {
-      int nvct;
-
-      nvct = zaxisInqVctSize(zaxisID);
+      int nvct = zaxisInqVctSize(zaxisID);
       if ( nlevel == (nvct/2 - 1) )
 	{
-	  double *vct;
-
-	  vct = (double*) Malloc(nvct*sizeof(double));
+	  double *vct = (double*) Malloc(nvct*sizeof(double));
 	  zaxisInqVct(zaxisID, vct);
 
 	  nlevs = nlevel + 1;
-	  plevs = (double*) Malloc(nlevs*sizeof(double));
+	  double *plevs = (double*) Malloc(nlevs*sizeof(double));
 	  vct2plev(vct, plevs, nlevs);
 	  Free(vct);
 
@@ -324,7 +318,7 @@ void *Cloudlayer(void *argument)
 
       streamDefTimestep(streamID2, tsID);
      
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
diff --git a/src/Collgrid.c b/src/Collgrid.c
index e5085bc..3ad02f6 100644
--- a/src/Collgrid.c
+++ b/src/Collgrid.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -15,12 +15,12 @@
   GNU General Public License for more details.
 */
 
-#include <ctype.h>
 
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
 #include "pstream.h"
+#include "grid.h"
 #include "util.h"
 
 
@@ -86,8 +86,6 @@ int genGrid(int nfiles, ens_file_t *ef, int **gridindex, int igrid, int nxblocks
   bool lregular = false;
   bool lcurvilinear = false;
   int gridID2 = -1;
-  int idx;
-  int ny, ix, iy, i, j, ij, offset;
   double *xvals2 = NULL, *yvals2 = NULL;
 
   int nx = -1;
@@ -107,7 +105,7 @@ int genGrid(int nfiles, ens_file_t *ef, int **gridindex, int igrid, int nxblocks
   for ( int fileID = 0; fileID < nfiles; fileID++ )
     {
       gridID   = vlistGrid(ef[fileID].vlistID, igrid);
-      gridtype = gridInqType(gridID);
+      int gridtype = gridInqType(gridID);
       if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN )
         lregular = true;
       else if ( gridtype == GRID_CURVILINEAR )
@@ -198,13 +196,13 @@ int genGrid(int nfiles, ens_file_t *ef, int **gridindex, int igrid, int nxblocks
       if ( nx <= 0 ) nx = nfiles;
     }
 
-  ny = nfiles/nx;
+  int ny = nfiles/nx;
   if ( nx*ny != nfiles ) cdoAbort("Number of input files (%d) and number of blocks (%dx%d) differ!", nfiles, nx, ny);
  
   int xsize2 = 0;
-  for ( i = 0; i < nx; ++i ) xsize2 += xsize[xyinfo[i].id];
+  for ( int i = 0; i < nx; ++i ) xsize2 += xsize[xyinfo[i].id];
   int ysize2 = 0;
-  for ( j = 0; j < ny; ++j ) ysize2 += ysize[xyinfo[j*nx].id];
+  for ( int j = 0; j < ny; ++j ) ysize2 += ysize[xyinfo[j*nx].id];
   if ( cdoVerbose ) cdoPrint("xsize2 %d  ysize2 %d", xsize2, ysize2);
 
   if ( lregular )
@@ -222,17 +220,17 @@ int genGrid(int nfiles, ens_file_t *ef, int **gridindex, int igrid, int nxblocks
   int *yoff = (int*) Malloc((ny+1)*sizeof(int));
 
   xoff[0] = 0;
-  for ( i = 0; i < nx; ++i )
+  for ( int i = 0; i < nx; ++i )
     {
-      idx = xyinfo[i].id;
+      int idx = xyinfo[i].id;
       if ( lregular ) memcpy(xvals2+xoff[i], xvals[idx], xsize[idx]*sizeof(double));
       xoff[i+1] = xoff[i] + xsize[idx];
     }
 
   yoff[0] = 0;
-  for ( j = 0; j < ny; ++j )
+  for ( int j = 0; j < ny; ++j )
     {
-      idx = xyinfo[j*nx].id;
+      int idx = xyinfo[j*nx].id;
       if ( lregular ) memcpy(yvals2+yoff[j], yvals[idx], ysize[idx]*sizeof(double));
       yoff[j+1] = yoff[j] + ysize[idx];
     }
@@ -241,18 +239,18 @@ int genGrid(int nfiles, ens_file_t *ef, int **gridindex, int igrid, int nxblocks
     {
       for ( int fileID = 0; fileID < nfiles; fileID++ )
 	{
-	  idx = xyinfo[fileID].id;
-	  iy = fileID/nx;
-	  ix = fileID - iy*nx;
+	  int idx = xyinfo[fileID].id;
+	  int iy = fileID/nx;
+	  int ix = fileID - iy*nx;
 
-          offset = yoff[iy]*xsize2 + xoff[ix];
+          int offset = yoff[iy]*xsize2 + xoff[ix];
 	  /*
 	  printf("fileID %d %d, iy %d, ix %d, offset %d\n",
 		 fileID, xyinfo[fileID].id, iy, ix, offset);
 	  */
-	  ij = 0;
-	  for ( j = 0; j < ysize[idx]; ++j )
-	    for ( i = 0; i < xsize[idx]; ++i )
+	  int ij = 0;
+	  for ( int j = 0; j < ysize[idx]; ++j )
+	    for ( int i = 0; i < xsize[idx]; ++i )
 	      {
                 if ( lcurvilinear )
                   {
@@ -289,21 +287,11 @@ int genGrid(int nfiles, ens_file_t *ef, int **gridindex, int igrid, int nxblocks
   Free(yvals);
   Free(xyinfo);
 
-  char string[1024];
-  string[0] = 0;
   gridID = vlistGrid(ef[0].vlistID, igrid);
-  gridInqXname(gridID, string);
-  gridDefXname(gridID2, string);
-  gridInqYname(gridID, string);
-  gridDefYname(gridID2, string);
-  gridInqXlongname(gridID, string);
-  gridDefXlongname(gridID2, string);
-  gridInqYlongname(gridID, string);
-  gridDefYlongname(gridID2, string);
-  gridInqXunits(gridID, string);
-  gridDefXunits(gridID2, string);
-  gridInqYunits(gridID, string);
-  gridDefYunits(gridID2, string);
+
+  grid_copy_attributes(gridID, gridID2);
+
+  if ( gridtype == GRID_PROJECTION ) grid_copy_mapping(gridID, gridID2);
 
   return gridID2;
 }
@@ -312,7 +300,7 @@ int genGrid(int nfiles, ens_file_t *ef, int **gridindex, int igrid, int nxblocks
 void *Collgrid(void *argument)
 {
   int nxblocks = -1;
-  int varID, recID;
+  int varID;
   int nrecs, nrecs0;
   int levelID;
   int nmiss;
@@ -512,7 +500,7 @@ void *Collgrid(void *argument)
 
       if ( nrecs0 > 0 ) streamDefTimestep(streamID2, tsID);
       
-      for ( recID = 0; recID < nrecs0; recID++ )
+      for ( int recID = 0; recID < nrecs0; recID++ )
 	{
 	  streamInqRecord(ef[0].streamID, &varID, &levelID);
 	  if ( cdoVerbose && tsID == 0 ) printf(" tsID, recID, varID, levelID %d %d %d %d\n", tsID, recID, varID, levelID);
diff --git a/src/Command.c b/src/Command.c
index bc7b431..296485d 100644
--- a/src/Command.c
+++ b/src/Command.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -19,7 +19,6 @@
    This module contains the following operators:
 */
 
-#include <ctype.h>  /* isspace */
 
 #include <cdi.h>
 #include "cdo.h"
@@ -88,7 +87,7 @@ int valid_argument (char *caller, char *arg)
       fprintf (stderr, "%s: Argument required.\n", caller);
       return 0;
     }
-  return (1);
+  return 1;
 }
 
 /* Print out help for ARG, or for all of the commands if ARG is not present. */
@@ -226,13 +225,11 @@ int com_vars(const char *arg)
    command. Return a NULL pointer if NAME isn't a command name. */
 command_t *find_command(char *name)
 {
-  int i;
-
-  for ( i = 0; commands[i].name; i++ )
+  for ( int i = 0; commands[i].name; i++ )
     if ( strcmp(name, commands[i].name) == 0)
-      return (&commands[i]);
+      return &commands[i];
 
-  return ((command_t *)NULL);
+  return (command_t *)NULL;
 }
 
 /* Execute a command line. */
@@ -261,7 +258,7 @@ int execute_line(char *line)
 
   word = line + i;
   /* Call the function. */
-  return ((*(command->func)) (word));
+  return (*(command->func)) (word);
 }
 
 /* Strip isspace from the start and end of STRING. Return a pointer into STRING. */
@@ -271,7 +268,7 @@ char *stripwhite(char *string)
   for (s = string; isspace(*s); s++)
     ;
   if (*s == 0)
-    return (s);
+    return s;
   t = s + strlen (s) - 1;
   while (t > s && isspace(*t))
     t--;
@@ -298,16 +295,14 @@ void readcmd(const char *prompt, char *line, int size)
 
 void command_init()
 {
-  int gridsize;
-  int taxisID;
   int varID;
 
   gl_vlistID = streamInqVlist(gl_streamID);
-  taxisID = vlistInqTaxis(gl_vlistID);
+  int taxisID = vlistInqTaxis(gl_vlistID);
 
   UNUSED(taxisID);
 
-  gridsize = vlistGridsizeMax(gl_vlistID);
+  int gridsize = vlistGridsizeMax(gl_vlistID);
   gl_data = (double*) Malloc(gridsize*sizeof(double));
 
   gl_nvars = vlistNvars(gl_vlistID);
diff --git a/src/Comp.c b/src/Comp.c
index ad4be40..be06873 100644
--- a/src/Comp.c
+++ b/src/Comp.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -34,69 +34,63 @@
 
 void *Comp(void *argument)
 {
-  int EQ, NE, LE, LT, GE, GT;
-  int operatorID;
   enum {FILL_NONE, FILL_TS, FILL_REC};
   int filltype = FILL_NONE;
-  int streamIDx1, streamIDx2, streamID1, streamID2, streamID3;
-  int gridsize, gridsize1, gridsize2;
-  int nrecs, nrecs2, nvars = 0, nlev, recID;
-  int tsID;
+  int gridsize1, gridsize2;
+  int nrecs, nrecs2, nvars = 0, nlev;
   int varID, levelID;
-  int offset;
-  int ntsteps1, ntsteps2;
-  int vlistIDx1, vlistIDx2, vlistID1, vlistID2, vlistID3;
-  int taxisIDx1, taxisID1, taxisID2, taxisID3;
-  int nmiss1, nmiss2, nmiss3;
-  int i;
   double missval1, missval2 = 0;
   double *missvalx1, *missvalx2;
-  double *arrayx1, *arrayx2, *array1, *array2, *array3;
   double **vardata = NULL;
 
   cdoInitialize(argument);
 
-  EQ = cdoOperatorAdd("eq", 0, 0, NULL);
-  NE = cdoOperatorAdd("ne", 0, 0, NULL);
-  LE = cdoOperatorAdd("le", 0, 0, NULL);
-  LT = cdoOperatorAdd("lt", 0, 0, NULL);
-  GE = cdoOperatorAdd("ge", 0, 0, NULL);
-  GT = cdoOperatorAdd("gt", 0, 0, NULL);
+  int EQ = cdoOperatorAdd("eq", 0, 0, NULL);
+  int NE = cdoOperatorAdd("ne", 0, 0, NULL);
+  int LE = cdoOperatorAdd("le", 0, 0, NULL);
+  int LT = cdoOperatorAdd("lt", 0, 0, NULL);
+  int GE = cdoOperatorAdd("ge", 0, 0, NULL);
+  int GT = cdoOperatorAdd("gt", 0, 0, NULL);
 
-  operatorID = cdoOperatorID();
+  int operatorID = cdoOperatorID();
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
-  streamID2 = streamOpenRead(cdoStreamName(1));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID2 = streamOpenRead(cdoStreamName(1));
 
-  streamIDx1 = streamID1;
-  streamIDx2 = streamID2;
+  int streamIDx1 = streamID1;
+  int streamIDx2 = streamID2;
 
   missvalx1 = &missval1;
   missvalx2 = &missval2;
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = streamInqVlist(streamID2);
-  vlistIDx1 = vlistID1;
-  vlistIDx2 = vlistID2;
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = streamInqVlist(streamID2);
+  int vlistIDx1 = vlistID1;
+  int vlistIDx2 = vlistID2;
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = vlistInqTaxis(vlistID2);
-  taxisIDx1 = taxisID1;
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = vlistInqTaxis(vlistID2);
+  int taxisIDx1 = taxisID1;
 
-  ntsteps1 = vlistNtsteps(vlistID1);
-  ntsteps2 = vlistNtsteps(vlistID2);
+  int ntsteps1 = vlistNtsteps(vlistID1);
+  int ntsteps2 = vlistNtsteps(vlistID2);
   if ( ntsteps1 == 0 ) ntsteps1 = 1;
   if ( ntsteps2 == 0 ) ntsteps2 = 1;
 
+  bool fillstream1 = false;
+
   if ( vlistNrecs(vlistID1) != 1 && vlistNrecs(vlistID2) == 1 )
     {
       filltype = FILL_REC;
       cdoPrint("Filling up stream2 >%s< by copying the first record.", cdoStreamName(1)->args);
+      if ( ntsteps2 != 1 ) cdoAbort("stream2 has more than 1 timestep!");
     }
   else if ( vlistNrecs(vlistID1) == 1 && vlistNrecs(vlistID2) != 1 )
     {
       filltype = FILL_REC;
       cdoPrint("Filling up stream1 >%s< by copying the first record.", cdoStreamName(0)->args);
+      if ( ntsteps1 != 1 ) cdoAbort("stream1 has more than 1 timestep!");
+      fillstream1 = true;
       streamIDx1 = streamID2;
       streamIDx2 = streamID1;
       vlistIDx1 = vlistID2;
@@ -110,14 +104,14 @@ void *Comp(void *argument)
   nospec(vlistID1);
   nospec(vlistID2);
 
-  gridsize = vlistGridsizeMax(vlistIDx1);
+  int gridsize = vlistGridsizeMax(vlistIDx1);
 
-  array1 = (double*) Malloc(gridsize*sizeof(double));
-  array2 = (double*) Malloc(gridsize*sizeof(double));
-  array3 = (double*) Malloc(gridsize*sizeof(double));
+  double *array1 = (double*) Malloc(gridsize*sizeof(double));
+  double *array2 = (double*) Malloc(gridsize*sizeof(double));
+  double *array3 = (double*) Malloc(gridsize*sizeof(double));
 
-  arrayx1 = array1;
-  arrayx2 = array2;
+  double *arrayx1 = array1;
+  double *arrayx2 = array2;
 
   if ( cdoVerbose )
     cdoPrint("Number of timesteps: file1 %d, file2 %d", ntsteps1, ntsteps2);
@@ -133,6 +127,7 @@ void *Comp(void *argument)
 	{
 	  filltype = FILL_TS;
 	  cdoPrint("Filling up stream1 >%s< by copying the first timestep.", cdoStreamName(0)->args);
+          fillstream1 = true;
 	  streamIDx1 = streamID2;
           streamIDx2 = streamID1;
 	  vlistIDx1 = vlistID2;
@@ -142,18 +137,18 @@ void *Comp(void *argument)
 
       if ( filltype == FILL_TS )
 	{
-	  nvars  = vlistNvars(vlistIDx2);
-	  vardata  = (double **) Malloc(nvars*sizeof(double *));
+	  nvars = vlistNvars(vlistIDx2);
+	  vardata = (double **) Malloc(nvars*sizeof(double *));
 	  for ( varID = 0; varID < nvars; varID++ )
 	    {
 	      gridsize = gridInqSize(vlistInqVarGrid(vlistIDx2, varID));
 	      nlev     = zaxisInqSize(vlistInqVarZaxis(vlistIDx2, varID));
-	      vardata[varID]  = (double*) Malloc(nlev*gridsize*sizeof(double));
+	      vardata[varID] = (double*) Malloc(nlev*gridsize*sizeof(double));
 	    }
 	}
     }
 
-  if ( filltype != FILL_NONE && ntsteps1 == 1 )
+  if ( fillstream1 )
     {
       arrayx1 = array2;
       arrayx2 = array1;
@@ -161,16 +156,16 @@ void *Comp(void *argument)
       missvalx2 = &missval1;
     }
 
-  vlistID3 = vlistDuplicate(vlistIDx1);
+  int vlistID3 = vlistDuplicate(vlistIDx1);
 
-  taxisID3 = taxisDuplicate(taxisIDx1);
+  int taxisID3 = taxisDuplicate(taxisIDx1);
   vlistDefTaxis(vlistID3, taxisID3);
 
-  streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
+  int streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
 
   streamDefVlist(streamID3, vlistID3);
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamIDx1, tsID)) )
     {
       if ( tsID == 0 || filltype == FILL_NONE )
@@ -184,8 +179,9 @@ void *Comp(void *argument)
 
       streamDefTimestep(streamID3, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
+          int nmiss1;
 	  streamInqRecord(streamIDx1, &varID, &levelID);
 	  streamReadRecord(streamIDx1, arrayx1, &nmiss1);
 
@@ -193,21 +189,22 @@ void *Comp(void *argument)
 	    {
 	      if ( recID == 0 || filltype != FILL_REC )
 		{
+                  int nmiss2;
 		  streamInqRecord(streamIDx2, &varID, &levelID);
 		  streamReadRecord(streamIDx2, arrayx2, &nmiss2);
 		}
 
 	      if ( filltype == FILL_TS )
 		{
-		  gridsize = gridInqSize(vlistInqVarGrid(vlistIDx2, varID));
-		  offset   = gridsize*levelID;
+		  int gridsize = gridInqSize(vlistInqVarGrid(vlistIDx2, varID));
+		  int offset = gridsize*levelID;
 		  memcpy(vardata[varID]+offset, arrayx2, gridsize*sizeof(double));
 		}
 	    }
 	  else if ( filltype == FILL_TS )
 	    {
-	      gridsize = gridInqSize(vlistInqVarGrid(vlistIDx2, varID));
-	      offset   = gridsize*levelID;
+	      int gridsize = gridInqSize(vlistInqVarGrid(vlistIDx2, varID));
+	      int offset = gridsize*levelID;
 	      memcpy(arrayx2, vardata[varID]+offset, gridsize*sizeof(double));
 	    }
 
@@ -232,37 +229,37 @@ void *Comp(void *argument)
 
 	  if ( operatorID == EQ )
 	    {
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( int 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]));
 	    }
 	  else if ( operatorID == NE )
 	    {
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( int 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]));
 	    }
 	  else if ( operatorID == LE )
 	    {
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( int 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 ( i = 0; i < gridsize; i++ )
+	      for ( int 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 ( i = 0; i < gridsize; i++ )
+	      for ( int 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 ( i = 0; i < gridsize; i++ )
+	      for ( int i = 0; i < gridsize; i++ )
 		array3[i] = (DBL_IS_EQUAL(array1[i], missval1) || DBL_IS_EQUAL(array2[i], missval2) ?
 			     missval1 : array1[i] > array2[i]);
 	    }
@@ -271,8 +268,8 @@ void *Comp(void *argument)
 	      cdoAbort("Operator not implemented!");
 	    }
 
-	  nmiss3 = 0;
-	  for ( i = 0; i < gridsize; i++ )
+	  int nmiss3 = 0;
+	  for ( int i = 0; i < gridsize; i++ )
 	    if ( DBL_IS_EQUAL(array3[i], missval1) ) nmiss3++;
 
 	  streamDefRecord(streamID3, varID, levelID);
diff --git a/src/Compc.c b/src/Compc.c
index cfdbc62..dfbcf56 100644
--- a/src/Compc.c
+++ b/src/Compc.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -35,64 +35,55 @@
 
 void *Compc(void *argument)
 {
-  int EQC, NEC, LEC, LTC, GEC, GTC;
-  int operatorID;
-  int streamID1, streamID2;
-  int gridsize;
-  int nrecs, recID;
-  int tsID;
+  int nrecs;
   int varID, levelID;
-  int vlistID1, vlistID2;
   int nmiss, nmiss2;
   int i;
   double missval;
-  double rc;
-  double *array1, *array2;
-  int taxisID1, taxisID2;
   int rc_is_missval;
 
   cdoInitialize(argument);
 
-  EQC = cdoOperatorAdd("eqc", 0, 0, NULL);
-  NEC = cdoOperatorAdd("nec", 0, 0, NULL);
-  LEC = cdoOperatorAdd("lec", 0, 0, NULL);
-  LTC = cdoOperatorAdd("ltc", 0, 0, NULL);
-  GEC = cdoOperatorAdd("gec", 0, 0, NULL);
-  GTC = cdoOperatorAdd("gtc", 0, 0, NULL);
+  int EQC = cdoOperatorAdd("eqc", 0, 0, NULL);
+  int NEC = cdoOperatorAdd("nec", 0, 0, NULL);
+  int LEC = cdoOperatorAdd("lec", 0, 0, NULL);
+  int LTC = cdoOperatorAdd("ltc", 0, 0, NULL);
+  int GEC = cdoOperatorAdd("gec", 0, 0, NULL);
+  int GTC = cdoOperatorAdd("gtc", 0, 0, NULL);
 
-  operatorID = cdoOperatorID();
+  int operatorID = cdoOperatorID();
 
   operatorInputArg("constant value");
-  rc = parameter2double(operatorArgv()[0]);
+  double rc = parameter2double(operatorArgv()[0]);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
   nospec(vlistID1);
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
 
-  array1 = (double*) Malloc(gridsize*sizeof(double));
-  array2 = (double*) Malloc(gridsize*sizeof(double));
+  double *array1 = (double*) Malloc(gridsize*sizeof(double));
+  double *array2 = (double*) Malloc(gridsize*sizeof(double));
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
 
       streamDefTimestep(streamID2, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, array1, &nmiss);
diff --git a/src/Complextorect.c b/src/Complextorect.c
index 04d432e..46c2587 100644
--- a/src/Complextorect.c
+++ b/src/Complextorect.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -24,61 +24,55 @@
 
 void *Complextorect(void *argument)
 {
-  // int COMPLEXTORECT;
-  // int operatorID;
-  int streamID1, streamID2, streamID3;
-  int tsID, nrecs;
-  int recID, varID, levelID;
-  int vlistID1, vlistID2, vlistID3;
-  int taxisID1, taxisID2, taxisID3;
-  int i, gridsize;
+  int nrecs;
+  int varID, levelID;
+  int i;
   int datatype;
-  int nmiss, nvars;
-  double *array1 = NULL, *array2 = NULL, *array3 = NULL;
+  int nmiss;
 
   cdoInitialize(argument);
 
-  //  COMPLEXTORECT = cdoOperatorAdd("complextorect", 0, 0, NULL);
+  // int COMPLEXTORECT = cdoOperatorAdd("complextorect", 0, 0, NULL);
 
-  //  operatorID = cdoOperatorID();
+  // int operatorID = cdoOperatorID();
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
-  vlistID3 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID3 = vlistDuplicate(vlistID1);
 
-  nvars = vlistNvars(vlistID2);
+  int nvars = vlistNvars(vlistID2);
   for ( varID = 0; varID < nvars; ++varID )
     {
       datatype = vlistInqVarDatatype(vlistID2, varID);
-      if ( datatype == DATATYPE_CPX64 )
-	datatype = DATATYPE_FLT64;
+      if ( datatype == CDI_DATATYPE_CPX64 )
+	datatype = CDI_DATATYPE_FLT64;
       else
-	datatype = DATATYPE_FLT32;
+	datatype = CDI_DATATYPE_FLT32;
 
       vlistDefVarDatatype(vlistID2, varID, datatype);
       vlistDefVarDatatype(vlistID3, varID, datatype);
     }
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
-  taxisID3 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID3 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
   vlistDefTaxis(vlistID3, taxisID3);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
-  streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
   streamDefVlist(streamID3, vlistID3);
 
-  gridsize = vlistGridsizeMax(vlistID1);
-  array1 = (double*) Malloc(2*gridsize*sizeof(double));
-  array2 = (double*) Malloc(gridsize*sizeof(double));
-  array3 = (double*) Malloc(gridsize*sizeof(double));
+  int gridsize = vlistGridsizeMax(vlistID1);
+  double *array1 = (double*) Malloc(2*gridsize*sizeof(double));
+  double *array2 = (double*) Malloc(gridsize*sizeof(double));
+  double *array3 = (double*) Malloc(gridsize*sizeof(double));
       
-  tsID  = 0;
+  int tsID  = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
@@ -87,7 +81,7 @@ void *Complextorect(void *argument)
       streamDefTimestep(streamID2, tsID);
       streamDefTimestep(streamID3, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamDefRecord(streamID2, varID, levelID);
diff --git a/src/Cond.c b/src/Cond.c
index 3233d09..bac53ae 100644
--- a/src/Cond.c
+++ b/src/Cond.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -30,47 +30,38 @@
 
 void *Cond(void *argument)
 {
-  int IFTHEN, IFNOTTHEN;
-  int operatorID;
   enum {FILL_NONE, FILL_TS, FILL_REC};
   int filltype = FILL_NONE;
-  int streamID1, streamID2, streamID3;
-  int gridsize;
-  int ntsteps1, ntsteps2;
-  int nrecs, nrecs2, nvars = 0, nlev, recID;
-  int tsID;
+  int nrecs, nrecs2, nvars = 0, nlev;
   int varID, levelID;
   int offset;
-  int vlistID1, vlistID2, vlistID3;
   int nmiss1, nmiss2, nmiss3;
   int i;
   double missval1 = -9.E33;
   double missval2 = -9.E33;
-  double *array1, *array2, *array3;
   int **varnmiss1 = NULL;
   double **vardata1 = NULL;
-  int taxisID2, taxisID3;
 
   cdoInitialize(argument);
 
-  IFTHEN    = cdoOperatorAdd("ifthen",    0, 0, NULL);
-  IFNOTTHEN = cdoOperatorAdd("ifnotthen", 0, 0, NULL);
+  int IFTHEN    = cdoOperatorAdd("ifthen",    0, 0, NULL);
+  int IFNOTTHEN = cdoOperatorAdd("ifnotthen", 0, 0, NULL);
 
-  operatorID = cdoOperatorID();
+  int operatorID = cdoOperatorID();
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
-  streamID2 = streamOpenRead(cdoStreamName(1));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID2 = streamOpenRead(cdoStreamName(1));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = streamInqVlist(streamID2);
-  vlistID3 = vlistDuplicate(vlistID2);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = streamInqVlist(streamID2);
+  int vlistID3 = vlistDuplicate(vlistID2);
 
-  taxisID2 = vlistInqTaxis(vlistID2);
-  taxisID3 = taxisDuplicate(taxisID2);
+  int taxisID2 = vlistInqTaxis(vlistID2);
+  int taxisID3 = taxisDuplicate(taxisID2);
   vlistDefTaxis(vlistID3, taxisID3);
 
-  ntsteps1 = vlistNtsteps(vlistID1);
-  ntsteps2 = vlistNtsteps(vlistID2);
+  int ntsteps1 = vlistNtsteps(vlistID1);
+  int ntsteps2 = vlistNtsteps(vlistID2);
   if ( ntsteps1 == 0 ) ntsteps1 = 1;
   if ( ntsteps2 == 0 ) ntsteps2 = 1;
 
@@ -86,18 +77,18 @@ void *Cond(void *argument)
   nospec(vlistID1);
   nospec(vlistID2);
 
-  streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
+  int streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
 
   streamDefVlist(streamID3, vlistID3);
 
-  gridsize = vlistGridsizeMax(vlistID2);
+  int gridsize = vlistGridsizeMax(vlistID2);
 
   if ( filltype == FILL_REC && gridsize != gridInqSize(vlistGrid(vlistID1, 0)) )
     cdoAbort("Stream1 >%s< has wrong gridsize!", cdoStreamName(0)->args);
 
-  array1 = (double*) Malloc(gridsize*sizeof(double));
-  array2 = (double*) Malloc(gridsize*sizeof(double));
-  array3 = (double*) Malloc(gridsize*sizeof(double));
+  double *array1 = (double*) Malloc(gridsize*sizeof(double));
+  double *array2 = (double*) Malloc(gridsize*sizeof(double));
+  double *array3 = (double*) Malloc(gridsize*sizeof(double));
 
   if ( cdoVerbose )
     cdoPrint("Number of timesteps: file1 %d, file2 %d", ntsteps1, ntsteps2);
@@ -122,7 +113,7 @@ void *Cond(void *argument)
 	}
     }
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID2, tsID)) )
     {
       if ( tsID == 0 || filltype == FILL_NONE )
@@ -136,7 +127,7 @@ void *Cond(void *argument)
 
       streamDefTimestep(streamID3, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID2, &varID, &levelID);
 	  streamReadRecord(streamID2, array2, &nmiss2);
diff --git a/src/Cond2.c b/src/Cond2.c
index 6e08f73..fd4a22a 100644
--- a/src/Cond2.c
+++ b/src/Cond2.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -29,48 +29,39 @@
 
 void *Cond2(void *argument)
 {
-  int IFTHENELSE;
-  int operatorID;
   enum {FILL_NONE, FILL_TS, FILL_REC};
   int filltype = FILL_NONE;
-  int streamID1, streamID2, streamID3, streamID4;
-  int gridsize;
-  int nrecs, nrecs2, nvars = 0, nlev, recID;
-  int tsID;
+  int nrecs, nrecs2, nvars = 0, nlev;
   int varID, levelID;
   int offset;
-  int ntsteps1, ntsteps2;
-  int vlistID1, vlistID2, vlistID3, vlistID4;
   int nmiss1, nmiss2, nmiss3, nmiss4;
   int i;
   double missval1 = -9.E33;
   double missval2 = -9.E33;
-  double *array1, *array2, *array3, *array4;
   int **varnmiss1 = NULL;
   double **vardata1 = NULL;
-  int taxisID2, taxisID4;
 
   cdoInitialize(argument);
 
-  IFTHENELSE = cdoOperatorAdd("ifthenelse",    0, 0, NULL);
+  int IFTHENELSE = cdoOperatorAdd("ifthenelse",    0, 0, NULL);
 
-  operatorID = cdoOperatorID();
+  int operatorID = cdoOperatorID();
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
-  streamID2 = streamOpenRead(cdoStreamName(1));
-  streamID3 = streamOpenRead(cdoStreamName(2));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID2 = streamOpenRead(cdoStreamName(1));
+  int streamID3 = streamOpenRead(cdoStreamName(2));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = streamInqVlist(streamID2);
-  vlistID3 = streamInqVlist(streamID3);
-  vlistID4 = vlistDuplicate(vlistID2);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = streamInqVlist(streamID2);
+  int vlistID3 = streamInqVlist(streamID3);
+  int vlistID4 = vlistDuplicate(vlistID2);
 
-  taxisID2 = vlistInqTaxis(vlistID2);
-  taxisID4 = taxisDuplicate(taxisID2);
+  int taxisID2 = vlistInqTaxis(vlistID2);
+  int taxisID4 = taxisDuplicate(taxisID2);
   vlistDefTaxis(vlistID4, taxisID4);
 
-  ntsteps1 = vlistNtsteps(vlistID1);
-  ntsteps2 = vlistNtsteps(vlistID2);
+  int ntsteps1 = vlistNtsteps(vlistID1);
+  int ntsteps2 = vlistNtsteps(vlistID2);
   if ( ntsteps1 == 0 ) ntsteps1 = 1;
   if ( ntsteps2 == 0 ) ntsteps2 = 1;
 
@@ -89,19 +80,19 @@ void *Cond2(void *argument)
   nospec(vlistID2);
   nospec(vlistID3);
 
-  streamID4 = streamOpenWrite(cdoStreamName(3), cdoFiletype());
+  int streamID4 = streamOpenWrite(cdoStreamName(3), cdoFiletype());
 
   streamDefVlist(streamID4, vlistID4);
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
 
   if ( filltype == FILL_REC && gridsize != gridInqSize(vlistGrid(vlistID1, 0)) )
     cdoAbort("Stream1 >%s< has wrong gridsize!", cdoStreamName(0)->args);
 
-  array1 = (double*) Malloc(gridsize*sizeof(double));
-  array2 = (double*) Malloc(gridsize*sizeof(double));
-  array3 = (double*) Malloc(gridsize*sizeof(double));
-  array4 = (double*) Malloc(gridsize*sizeof(double));
+  double *array1 = (double*) Malloc(gridsize*sizeof(double));
+  double *array2 = (double*) Malloc(gridsize*sizeof(double));
+  double *array3 = (double*) Malloc(gridsize*sizeof(double));
+  double *array4 = (double*) Malloc(gridsize*sizeof(double));
 
   if ( cdoVerbose )
     cdoPrint("Number of timesteps: file1 %d, file2 %d, file3 %d",
@@ -127,7 +118,7 @@ void *Cond2(void *argument)
 	}
     }
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID2, tsID)) )
     {
       nrecs = streamInqTimestep(streamID3, tsID);
@@ -144,7 +135,7 @@ void *Cond2(void *argument)
 
       streamDefTimestep(streamID4, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID2, &varID, &levelID);
 	  streamReadRecord(streamID2, array2, &nmiss2);
diff --git a/src/Condc.c b/src/Condc.c
index 3979662..9a0a9ae 100644
--- a/src/Condc.c
+++ b/src/Condc.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -31,59 +31,50 @@
 
 void *Condc(void *argument)
 {
-  int IFTHENC, IFNOTTHENC;
-  int operatorID;
-  int streamID1, streamID2;
-  int gridsize;
-  int nrecs, recID;
-  int tsID;
+  int nrecs;
   int varID, levelID;
-  int vlistID1, vlistID2;
   int nmiss, nmiss2;
   int i;
   double missval;
-  double rc;
-  double *array1, *array2;
-  int taxisID1, taxisID2;
 
   cdoInitialize(argument);
 
-  IFTHENC    = cdoOperatorAdd("ifthenc",    0, 0, NULL);
-  IFNOTTHENC = cdoOperatorAdd("ifnotthenc", 0, 0, NULL);
+  int IFTHENC    = cdoOperatorAdd("ifthenc",    0, 0, NULL);
+  int IFNOTTHENC = cdoOperatorAdd("ifnotthenc", 0, 0, NULL);
 
-  operatorID = cdoOperatorID();
+  int operatorID = cdoOperatorID();
 
   operatorInputArg("constant value");
-  rc = parameter2double(operatorArgv()[0]);
+  double rc = parameter2double(operatorArgv()[0]);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
   nospec(vlistID1);
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
 
-  array1 = (double*) Malloc(gridsize*sizeof(double));
-  array2 = (double*) Malloc(gridsize*sizeof(double));
+  double *array1 = (double*) Malloc(gridsize*sizeof(double));
+  double *array2 = (double*) Malloc(gridsize*sizeof(double));
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
 
       streamDefTimestep(streamID2, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, array1, &nmiss);
diff --git a/src/Consecstat.c b/src/Consecstat.c
index c48f4ed..029407e 100644
--- a/src/Consecstat.c
+++ b/src/Consecstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -38,9 +38,9 @@
 enum {CONSECSUM, CONSECTS};
 #define SWITCHWARN "Hit default case!This should never happen (%s).\n"
 
-static void selEndOfPeriod(field_t *periods, field_t history, field_t current, int isLastTimestep)
+static void selEndOfPeriod(field_type *periods, field_type history, field_type current, int isLastTimestep)
 {
-  long   i, len;
+  long   i;
   double pmissval = periods->missval;
   double  *parray = periods->ptr;
   double hmissval = history.missval;
@@ -48,7 +48,7 @@ static void selEndOfPeriod(field_t *periods, field_t history, field_t current, i
   double cmissval = current.missval;
   double  *carray = current.ptr;
 
-  len = gridInqSize(periods->grid);
+  long len = gridInqSize(periods->grid);
   if ( len != gridInqSize(current.grid) || (gridInqSize(current.grid) != gridInqSize(history.grid)) )
     cdoAbort("Fields have different gridsize (%s)", __func__);
 
@@ -119,43 +119,40 @@ static void selEndOfPeriod(field_t *periods, field_t history, field_t current, i
     if ( DBL_IS_EQUAL(parray[i], pmissval) ) periods->nmiss++;
 }
 
+
 void *Consecstat(void *argument)
 {
-  int operatorID;
-  int istreamID, itaxisID, ivlistID, itsID;
-  int ostreamID, otaxisID, ovlistID, otsID;
   int vdate = 0, vtime = 0;
   int histvdate = 0, histvtime = 0;
-  int recID, nrecs;
-  int varID, nvars;
+  int nrecs;
+  int varID;
   int levelID, nlevels;
   int nmiss;
   double refval = 0.0;
 
-  field_t **vars = NULL, **hist = NULL, **periods = NULL;
-  field_t field;
-
   cdoInitialize(argument);
   cdoOperatorAdd("consecsum",CONSECSUM, 0, "refval");
   cdoOperatorAdd("consects" ,CONSECTS , 0, NULL);
-  operatorID = cdoOperatorID();
+  int operatorID = cdoOperatorID();
 
   if ( operatorID == CONSECSUM )
     if ( operatorArgc() > 0 ) refval = parameter2double(operatorArgv()[0]);
 
-  istreamID = streamOpenRead(cdoStreamName(0));
+  int istreamID = streamOpenRead(cdoStreamName(0));
 
-  ivlistID = streamInqVlist(istreamID);
-  itaxisID = vlistInqTaxis(ivlistID);
-  ovlistID = vlistDuplicate(ivlistID);
-  otaxisID = taxisDuplicate(itaxisID);
+  int ivlistID = streamInqVlist(istreamID);
+  int itaxisID = vlistInqTaxis(ivlistID);
+  int ovlistID = vlistDuplicate(ivlistID);
+  int otaxisID = taxisDuplicate(itaxisID);
   vlistDefTaxis(ovlistID, otaxisID);
 
+  field_type field;
   field_init(&field);
   field.ptr = (double*) Malloc(vlistGridsizeMax(ovlistID)*sizeof(double));
 
-  nvars     = vlistNvars(ivlistID);
-  vars      = field_calloc(ivlistID, FIELD_PTR);
+  int nvars = vlistNvars(ivlistID);
+  field_type **vars = field_calloc(ivlistID, FIELD_PTR);
+  field_type **hist = NULL, **periods = NULL;
   if ( operatorID == CONSECTS )
     {
       hist      = field_malloc(ivlistID, FIELD_PTR);
@@ -167,12 +164,12 @@ void *Consecstat(void *argument)
       vlistDefVarUnits(ovlistID, varID, "steps"); /* TODO */
     }
 
-  ostreamID = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int ostreamID = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(ostreamID, ovlistID);
 
-  itsID = 0;
-  otsID = 0;
+  int itsID = 0;
+  int otsID = 0;
   while ( (nrecs = streamInqTimestep(istreamID, itsID)) )
   {
     vdate = taxisInqVdate(itaxisID);
@@ -197,7 +194,7 @@ void *Consecstat(void *argument)
         break;
     }
 
-    for ( recID = 0; recID < nrecs; recID++ )
+    for ( int recID = 0; recID < nrecs; recID++ )
     {
       streamInqRecord(istreamID, &varID, &levelID);
       streamReadRecord(istreamID, field.ptr, &nmiss);
diff --git a/src/Copy.c b/src/Copy.c
index 9ac842f..3e5e88a 100644
--- a/src/Copy.c
+++ b/src/Copy.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -35,7 +35,7 @@ void *Copy(void *argument)
   int vlistID2 = CDI_UNDEFID;
   int taxisID2 = CDI_UNDEFID;
   int nrecs;
-  int recID, varID, levelID;
+  int varID, levelID;
   int nmiss;
   int ntsteps, nvars;
   double *array = NULL;
@@ -53,7 +53,7 @@ void *Copy(void *argument)
 
   if ( operatorID == SZIP )
     {
-      cdoCompType  = COMPRESS_SZIP;
+      cdoCompType  = CDI_COMPRESS_SZIP;
       cdoCompLevel = 0;
     }
 
@@ -119,7 +119,7 @@ void *Copy(void *argument)
 
 	  streamDefTimestep(streamID2, tsID2);
 	       
-	  for ( recID = 0; recID < nrecs; recID++ )
+	  for ( int recID = 0; recID < nrecs; recID++ )
 	    { 
 	      if ( lcopy && (operatorID == SELALL || operatorID == SZIP) )
 		{
diff --git a/src/Timedt.c b/src/Deltat.c
similarity index 94%
rename from src/Timedt.c
rename to src/Deltat.c
index 7ecfdef..af7c402 100644
--- a/src/Timedt.c
+++ b/src/Deltat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -18,7 +18,7 @@
 /*
    This module contains the following operators:
 
-     Timedt    timedt         Delta t
+     Deltat    deltat         Delta t
 */
 
 
@@ -28,7 +28,7 @@
 #include "pstream.h"
 
 
-void *Timedt(void *argument)
+void *Deltat(void *argument)
 {
   int varID, levelID;
   int nmiss;
@@ -48,7 +48,7 @@ void *Timedt(void *argument)
 
   streamDefVlist(streamID2, vlistID2);
 
-  field_t **vars = field_malloc(vlistID1, FIELD_PTR);
+  field_type **vars = field_malloc(vlistID1, FIELD_PTR);
   
   int gridsizemax = vlistGridsizeMax(vlistID1);
   double *array1 = (double*) Malloc(gridsizemax*sizeof(double));
diff --git a/src/Deltime.c b/src/Deltime.c
index 2f1f7ed..3159098 100644
--- a/src/Deltime.c
+++ b/src/Deltime.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -15,7 +15,6 @@
   GNU General Public License for more details.
 */
 
-#include <ctype.h>
 
 #include <cdi.h>
 #include "cdo.h"
@@ -26,7 +25,7 @@
 void *Deltime(void *argument)
 {
   int nrecs;
-  int recID, varID, levelID;
+  int varID, levelID;
   int vdate /*, vtime */;
   int copytimestep;
   int gridsize;
@@ -125,7 +124,7 @@ void *Deltime(void *argument)
 
 	  streamDefTimestep(streamID2, tsID2++);
 
-	  for ( recID = 0; recID < nrecs; recID++ )
+	  for ( int recID = 0; recID < nrecs; recID++ )
 	    {
 	      streamInqRecord(streamID1, &varID, &levelID);
 	      streamDefRecord(streamID2, varID, levelID);
diff --git a/src/Derivepar.c b/src/Derivepar.c
index 3aa5261..b32a1e0 100644
--- a/src/Derivepar.c
+++ b/src/Derivepar.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -20,7 +20,6 @@
       Derivepar     gheight          geopotential height
 */
 
-#include <ctype.h>
 
 #include <cdi.h>
 #include "cdo.h"
@@ -38,7 +37,7 @@ void *Derivepar(void *argument)
 {
   int mode;
   enum {ECHAM_MODE, WMO_MODE};
-  int recID, nrecs;
+  int nrecs;
   int i, offset;
   int varID, levelID;
   int zaxisID;
@@ -293,7 +292,7 @@ void *Derivepar(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  zaxisID  = vlistInqVarZaxis(vlistID1, varID);
diff --git a/src/Detrend.c b/src/Detrend.c
index 6a1875d..56837d6 100644
--- a/src/Detrend.c
+++ b/src/Detrend.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -34,18 +34,15 @@
 static
 void detrend(long nts, double missval1, double *array1, double *array2)
 {
-  long n;
-  long j;
   double zj;
   double sumj, sumjj;
   double sumx, sumjx;
-  double work1, work2;
   double missval2 = missval1;
 
   sumx = sumjx = 0;
   sumj = sumjj = 0;
-  n = 0;
-  for ( j = 0; j < nts; j++ )
+  long n = 0;
+  for ( long j = 0; j < nts; j++ )
     if ( !DBL_IS_EQUAL(array1[j], missval1) )
       {
         zj = j;
@@ -56,11 +53,11 @@ void detrend(long nts, double missval1, double *array1, double *array2)
 	n++;
       }
 
-  work1 = DIVMN( SUBMN(sumjx, DIVMN( MULMN(sumx, sumj), n) ),
-	      SUBMN(sumjj, DIVMN( MULMN(sumj, sumj), n)) );
-  work2 = SUBMN( DIVMN(sumx, n), MULMN(work1, DIVMN(sumj, n)));
+  double work1 = DIVMN( SUBMN(sumjx, DIVMN( MULMN(sumx, sumj), n) ),
+                        SUBMN(sumjj, DIVMN( MULMN(sumj, sumj), n)) );
+  double work2 = SUBMN( DIVMN(sumx, n), MULMN(work1, DIVMN(sumj, n)));
 
-  for ( j = 0; j < nts; j++ )
+  for ( long j = 0; j < nts; j++ )
     array2[j] = SUBMN(array1[j], ADDMN(work2, MULMN(j, work1)));
 }
 
@@ -69,13 +66,13 @@ void *Detrend(void *argument)
 {
   int gridsize;
   int nrecs;
-  int gridID, varID, levelID, recID;
+  int gridID, varID, levelID;
   int i;
   int nalloc = 0;
   int nmiss;
   int nlevel;
   double missval;
-  field_t ***vars = NULL;
+  field_type ***vars = NULL;
   dtlist_type *dtlist = dtlist_new();
   typedef struct
   {
@@ -106,14 +103,14 @@ void *Detrend(void *argument)
       if ( tsID >= nalloc )
 	{
 	  nalloc += NALLOC_INC;
-	  vars   = (field_t ***) Realloc(vars, nalloc*sizeof(field_t **));
+	  vars   = (field_type ***) Realloc(vars, nalloc*sizeof(field_type **));
 	}
 
       dtlist_taxisInqTimestep(dtlist, taxisID1, tsID);
 
       vars[tsID] = field_malloc(vlistID1, FIELD_NONE);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  gridID   = vlistInqVarGrid(vlistID1, varID);
diff --git a/src/Diff.c b/src/Diff.c
index d20fece..1abc71d 100644
--- a/src/Diff.c
+++ b/src/Diff.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -177,9 +177,12 @@ void *Diff(void *argument)
 		  fprintf(stdout, ":");
 		  reset_text_color(stdout);
 		
-		  set_text_color(stdout, RESET, BLUE);
+		  set_text_color(stdout, RESET, MAGENTA);
 		  fprintf(stdout, "%s %s ", vdatestr, vtimestr);
-		  fprintf(stdout, "%7g ", zaxisInqLevel(zaxisID, levelID));
+		  reset_text_color(stdout);
+		  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, "%7d ", ndiff);
 		  reset_text_color(stdout);
@@ -188,6 +191,7 @@ void *Diff(void *argument)
 		  fprintf(stdout, ":");
 		  reset_text_color(stdout);
 		  fprintf(stdout, " %c %c ", dsgn ? 'T' : 'F', zero ? 'T' : 'F');
+		  set_text_color(stdout, RESET, BLUE);
 		  fprintf(stdout, "%#12.5g%#12.5g", absm, relm);
 		  set_text_color(stdout, RESET, BLACK);
 		  fprintf(stdout, " : ");
diff --git a/src/Distgrid.c b/src/Distgrid.c
index 7ea69a0..8e60cca 100644
--- a/src/Distgrid.c
+++ b/src/Distgrid.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -18,6 +18,7 @@
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
+#include "grid.h"
 #include "pstream.h"
 
 #define  MAX_BLOCKS  65536
@@ -26,26 +27,21 @@ static
 void genGrids(int gridID1, int *gridIDs, int nxvals, int nyvals, int nxblocks, int nyblocks,
 	      int **gridindex, int *ogridsize, int nsplit)
 {
-  int gridID2;
-  int gridsize2;
-  int i, j, ix, iy, offset;
-
+  double *xpvals = NULL, *ypvals = NULL;
   int gridtype = gridInqType(gridID1);
-  int lregular = TRUE;
+  bool lregular = true;
   if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN || gridtype == GRID_GENERIC )
-    lregular = TRUE;
+    lregular = true;
   else if ( gridtype == GRID_CURVILINEAR )
-    lregular = FALSE;
+    lregular = false;
   else
     cdoAbort("Unsupported grid type: %s!", gridNamePtr(gridtype));
 
   int nx = gridInqXsize(gridID1);
   int ny = gridInqYsize(gridID1);
 
-  bool lxcoord = true;
-  bool lycoord = true;
-  if ( gridInqXvals(gridID1, NULL) == 0 ) lxcoord = false;
-  if ( gridInqYvals(gridID1, NULL) == 0 ) lycoord = false;
+  bool lxcoord = gridInqXvals(gridID1, NULL) > 0;
+  bool lycoord = gridInqYvals(gridID1, NULL) > 0;
 
   double *xvals = NULL, *yvals = NULL;
   double *xvals2 = NULL, *yvals2 = NULL;
@@ -83,44 +79,49 @@ void genGrids(int gridID1, int *gridIDs, int nxvals, int nyvals, int nxblocks, i
   int *xlsize = (int*) Malloc(nxblocks*sizeof(int));
   int *ylsize = (int*) Malloc(nyblocks*sizeof(int));
 
-  for ( ix = 0; ix < nxblocks; ++ix ) xlsize[ix] = nxvals;
+  for ( int ix = 0; ix < nxblocks; ++ix ) xlsize[ix] = nxvals;
   if ( nx%nxblocks != 0 ) xlsize[nxblocks-1] = nx - (nxblocks-1)*nxvals;
-  if ( cdoVerbose ) for ( ix = 0; ix < nxblocks; ++ix ) cdoPrint("xblock %d: %d", ix, xlsize[ix]);
+  if ( cdoVerbose ) for ( int ix = 0; ix < nxblocks; ++ix ) cdoPrint("xblock %d: %d", ix, xlsize[ix]);
 
-  for ( iy = 0; iy < nyblocks; ++iy ) ylsize[iy] = nyvals;
+  for ( int iy = 0; iy < nyblocks; ++iy ) ylsize[iy] = nyvals;
   if ( ny%nyblocks != 0 ) ylsize[nyblocks-1] = ny - (nyblocks-1)*nyvals;
-  if ( cdoVerbose ) for ( iy = 0; iy < nyblocks; ++iy ) cdoPrint("yblock %d: %d", iy, ylsize[iy]);
+  if ( cdoVerbose ) for ( int iy = 0; iy < nyblocks; ++iy ) cdoPrint("yblock %d: %d", iy, ylsize[iy]);
 
   int index = 0;
-  for ( iy = 0; iy < nyblocks; ++iy )
-    for ( ix = 0; ix < nxblocks; ++ix )
+  for ( int iy = 0; iy < nyblocks; ++iy )
+    for ( int ix = 0; ix < nxblocks; ++ix )
       {
-	offset = iy*nyvals*nx + ix*nxvals;
+	int offset = iy*nyvals*nx + ix*nxvals;
 
-	gridsize2 = xlsize[ix]*ylsize[iy];
+	int gridsize2 = xlsize[ix]*ylsize[iy];
 	gridindex[index] = (int*) Malloc(gridsize2*sizeof(int));
 
 	gridsize2 = 0;
         // printf("iy %d, ix %d offset %d\n", iy, ix,  offset);
-	for ( j = 0; j < ylsize[iy]; ++j )
-	  {
-	    for ( i = 0; i < xlsize[ix]; ++i )
-	      {
-	       	// printf(">> %d %d %d\n", j, i, offset + j*nx + i);
-                if ( !lregular )
-                  {
-                    if ( lxcoord ) xvals2[gridsize2] = xvals[offset + j*nx + i];
-                    if ( lycoord ) yvals2[gridsize2] = yvals[offset + j*nx + i];
-                  }
-		gridindex[index][gridsize2++] = offset + j*nx + i;
-	      }
-	  }
+	for ( int j = 0; j < ylsize[iy]; ++j )
+          for ( int i = 0; i < xlsize[ix]; ++i )
+            {
+              // printf(">> %d %d %d\n", j, i, offset + j*nx + i);
+              if ( !lregular )
+                {
+                  if ( lxcoord ) xvals2[gridsize2] = xvals[offset + j*nx + i];
+                  if ( lycoord ) yvals2[gridsize2] = yvals[offset + j*nx + i];
+                }
+              gridindex[index][gridsize2++] = offset + j*nx + i;
+            }
 	// printf("gridsize2 %d\n", gridsize2);
 
-	gridID2 = gridCreate(gridtype, gridsize2);
+	int gridID2 = gridCreate(gridtype, gridsize2);
 	gridDefXsize(gridID2, xlsize[ix]);
 	gridDefYsize(gridID2, ylsize[iy]);
 
+        gridDefNP(gridID2, gridInqNP(gridID1));
+        gridDefPrec(gridID2, gridInqPrec(gridID1));
+
+        grid_copy_attributes(gridID1, gridID2);
+
+        if ( gridtype == GRID_PROJECTION ) grid_copy_mapping(gridID1, gridID2);
+
         if ( lregular )
           {
             if ( lxcoord ) gridDefXvals(gridID2, xvals+ix*nxvals);
@@ -131,7 +132,41 @@ void genGrids(int gridID1, int *gridIDs, int nxvals, int nyvals, int nxblocks, i
             if ( lxcoord ) gridDefXvals(gridID2, xvals2);
             if ( lycoord ) gridDefYvals(gridID2, yvals2);
           }
-        
+
+        int projID1 = gridInqProj(gridID1);
+        if ( projID1 != CDI_UNDEFID && gridInqType(projID1) == GRID_PROJECTION )
+          {
+            int projID2 = gridCreate(GRID_PROJECTION, gridsize2);
+            gridDefXsize(projID2, xlsize[ix]);
+            gridDefYsize(projID2, ylsize[iy]);
+
+            grid_copy_attributes(projID1, projID2);
+            grid_copy_mapping(projID1, projID2);
+
+            bool lxpcoord = gridInqXvals(projID1, NULL) > 0;
+            if ( lxpcoord )
+              {
+                if ( !xpvals )
+                  {
+                    xpvals = (double*) Malloc(nx*sizeof(double));
+                    gridInqXvals(projID1, xpvals);
+                  }
+                gridDefXvals(projID2, xpvals+ix*nxvals);
+              }
+            bool lypcoord = gridInqYvals(projID1, NULL) > 0;
+            if ( lypcoord )
+              {
+                if ( !ypvals )
+                  {
+                    ypvals = (double*) Malloc(ny*sizeof(double));
+                    gridInqYvals(projID1, ypvals);
+                  }
+                gridDefYvals(projID2, ypvals+iy*nyvals);
+              }
+
+            gridDefProj(gridID2, projID2);
+          }
+
 	gridIDs[index] = gridID2;
 	ogridsize[index] = gridsize2;
 
@@ -142,10 +177,12 @@ void genGrids(int gridID1, int *gridIDs, int nxvals, int nyvals, int nxblocks, i
 
   if ( xvals2 ) Free(xvals2);
   if ( yvals2 ) Free(yvals2);
-  Free(xvals);
-  Free(yvals);
-  Free(xlsize);
-  Free(ylsize);
+  if ( xvals ) Free(xvals);
+  if ( yvals ) Free(yvals);
+  if ( xpvals ) Free(xpvals);
+  if ( ypvals ) Free(ypvals);
+  if ( xlsize ) Free(xlsize);
+  if ( ylsize ) Free(ylsize);
 }
 
 static
@@ -167,17 +204,14 @@ typedef struct
 void *Distgrid(void *argument)
 {
   int gridID1;
-  int varID;
+  int varID, levelID;
   int nrecs;
-  int recID, levelID;
   char filesuffix[32];
   char filename[8192];
-  const char *refname;
   int index;
   int gridtype = -1;
   int nmiss;
   int i;
-  double missval;
 
   cdoInitialize(argument);
 
@@ -213,7 +247,7 @@ void *Distgrid(void *argument)
   int gridsize = gridInqSize(gridID1);
   int nx = gridInqXsize(gridID1);
   int ny = gridInqYsize(gridID1);
-  for ( i = 1; i < ngrids; i++ )
+  for ( int i = 1; i < ngrids; i++ )
     {
       gridID1 = vlistGrid(vlistID1, i);
       if ( gridsize != gridInqSize(gridID1) )
@@ -246,36 +280,36 @@ void *Distgrid(void *argument)
   int *streamIDs = (int*) Malloc(nsplit*sizeof(int));
 
   sgrid_t *grids = (sgrid_t*) Malloc(ngrids*sizeof(sgrid_t));
-  for ( i = 0; i < ngrids; i++ )
+  for ( int i = 0; i < ngrids; i++ )
     {  
       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*));
 
-      for ( index = 0; index < nsplit; index++ ) grids[i].gridindex[index] = NULL;
+      for ( int index = 0; index < nsplit; index++ ) grids[i].gridindex[index] = NULL;
     }
 
-  for ( index = 0; index < nsplit; index++ )
+  for ( int index = 0; index < nsplit; index++ )
     vlistIDs[index] = vlistDuplicate(vlistID1);
 
   if ( cdoVerbose ) cdoPrint("ngrids=%d  nsplit=%d", ngrids, nsplit);
 
-  for ( i = 0; i < ngrids; i++ )
+  for ( int i = 0; i < ngrids; i++ )
     {
       gridID1 = vlistGrid(vlistID1, i);
       genGrids(gridID1, grids[i].gridIDs, xinc, yinc, nxblocks, nyblocks, grids[i].gridindex, grids[i].gridsize, nsplit);
       /*
       if ( cdoVerbose )
-	for ( index = 0; index < nsplit; index++ )
+	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 ( index = 0; index < nsplit; index++ )
+      for ( int index = 0; index < nsplit; index++ )
 	vlistChangeGridIndex(vlistIDs[index], i, grids[i].gridIDs[index]);
     }
 
   int gridsize2max = 0;
-  for ( index = 0; index < nsplit; index++ )
+  for ( int index = 0; index < nsplit; index++ )
     if ( grids[0].gridsize[index] > gridsize2max ) gridsize2max = grids[0].gridsize[index];
 
   double *array2 = (double*) Malloc(gridsize2max*sizeof(double));
@@ -283,11 +317,11 @@ void *Distgrid(void *argument)
   strcpy(filename, cdoStreamName(1)->args);
   int nchars = strlen(filename);
 
-  refname = cdoStreamName(0)->argv[cdoStreamName(0)->argc-1];
+  const char *refname = cdoStreamName(0)->argv[cdoStreamName(0)->argc-1];
   filesuffix[0] = 0;
   cdoGenFileSuffix(filesuffix, sizeof(filesuffix), streamInqFiletype(streamID1), vlistID1, refname);
 
-  for ( index = 0; index < nsplit; index++ )
+  for ( int index = 0; index < nsplit; index++ )
     {
       sprintf(filename+nchars, "%05d", index);
       if ( filesuffix[0] )
@@ -300,21 +334,21 @@ void *Distgrid(void *argument)
       streamDefVlist(streamIDs[index], vlistIDs[index]);
     }
 
-  if ( ngrids > 1 ) cdoPrint("Bausstelle: number of different grids > 1!");
+  if ( ngrids > 1 ) cdoPrint("Baustelle: number of different grids > 1!");
   int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
-      for ( index = 0; index < nsplit; index++ )
+      for ( int index = 0; index < nsplit; index++ )
 	streamDefTimestep(streamIDs[index], tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, array1, &nmiss);
 
-	  missval = vlistInqVarMissval(vlistID1, varID);
+	  double missval = vlistInqVarMissval(vlistID1, varID);
 
-	  for ( index = 0; index < nsplit; index++ )
+	  for ( int index = 0; index < nsplit; index++ )
 	    {
 	      i = 0;
 	      window_cell(array1, array2, grids[i].gridsize[index], grids[i].gridindex[index]);
@@ -334,7 +368,7 @@ void *Distgrid(void *argument)
 
   streamClose(streamID1);
 
-  for ( index = 0; index < nsplit; index++ )
+  for ( int index = 0; index < nsplit; index++ )
     {
       streamClose(streamIDs[index]);
       vlistDestroy(vlistIDs[index]);
@@ -346,14 +380,14 @@ void *Distgrid(void *argument)
   if ( vlistIDs  ) Free(vlistIDs);
   if ( streamIDs ) Free(streamIDs);
 
-  for ( i = 0; i < ngrids; i++ )
+  for ( int i = 0; i < ngrids; i++ )
     {
-      for ( index = 0; index < nsplit; index++ )
+      for ( int index = 0; index < nsplit; index++ )
 	gridDestroy(grids[i].gridIDs[index]);
       Free(grids[i].gridIDs);
       Free(grids[i].gridsize);
 
-      for ( index = 0; index < nsplit; index++ )
+      for ( int index = 0; index < nsplit; index++ )
         Free(grids[i].gridindex[index]);
       Free(grids[i].gridindex);
     }
diff --git a/src/Duplicate.c b/src/Duplicate.c
index e582de9..257ff93 100644
--- a/src/Duplicate.c
+++ b/src/Duplicate.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -27,13 +27,12 @@
 void *Duplicate(void *argument)
 {
   int nrecs;
-  int gridID, varID, levelID;
+  int varID, levelID;
   int nalloc = 0;
   int nmiss;
-  int nlevel;
   int *vdate = NULL, *vtime = NULL;
   int ndup = 2;
-  field_t ***vars = NULL;
+  field_type ***vars = NULL;
 
   cdoInitialize(argument);
 
@@ -82,7 +81,7 @@ void *Duplicate(void *argument)
 	  nalloc += NALLOC_INC;
 	  vdate = (int*) Realloc(vdate, nalloc*sizeof(int));
 	  vtime = (int*) Realloc(vtime, nalloc*sizeof(int));
-	  vars  = (field_t***) Realloc(vars, nalloc*sizeof(field_t**));
+	  vars  = (field_type***) Realloc(vars, nalloc*sizeof(field_type**));
 	}
 
       vdate[tsID] = taxisInqVdate(taxisID1);
@@ -93,7 +92,7 @@ void *Duplicate(void *argument)
       for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
-	  gridID   = vlistInqVarGrid(vlistID1, varID);
+	  int gridID   = vlistInqVarGrid(vlistID1, varID);
 	  int gridsize = gridInqSize(gridID);
 	  vars[tsID][varID][levelID].ptr = (double*) Malloc(gridsize*sizeof(double));
 	  streamReadRecord(streamID1, vars[tsID][varID][levelID].ptr, &nmiss);
@@ -115,7 +114,7 @@ void *Duplicate(void *argument)
 
 	  for ( varID = 0; varID < nvars; varID++ )
 	    {
-	      nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
+	      int nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
 	      for ( levelID = 0; levelID < nlevel; levelID++ )
 		{
 		  if ( vars[tsID][varID][levelID].ptr )
diff --git a/src/EOFs.c b/src/EOFs.c
index 6e720f4..cb0992b 100644
--- a/src/EOFs.c
+++ b/src/EOFs.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -167,11 +167,9 @@ void *EOFs(void * argument)
 {
   enum {EOF_, EOF_TIME, EOF_SPATIAL};
 
-  int i, j, j1, j2;
   int nlevs = 0 ;
   int nmiss;
-  int tsID;
-  int varID, recID, levelID;
+  int varID, levelID;
   int nts = 0;
   int n = 0;
   int grid_space = 0, time_space = 0;
@@ -180,13 +178,11 @@ void *EOFs(void * argument)
   int calendar = CALENDAR_STANDARD;
   juldate_t juldate;
 
-  double sum;
   double missval = 0;
-  double xvals, yvals;
 
   typedef struct {
-    int init;
-    int first_call;
+    bool init;
+    bool first_call;
     double *eig_val;
     double *covar_array;
     double **covar;
@@ -210,7 +206,7 @@ void *EOFs(void * argument)
   int operfunc   = cdoOperatorF1(operatorID);
 
   operatorInputArg("Number of eigen functions to write out");
-  int n_eig      = parameter2int(operatorArgv()[0]);
+  int n_eig = parameter2int(operatorArgv()[0]);
   
   enum T_EIGEN_MODE eigen_mode = get_eigenmode();
   enum T_WEIGHT_MODE weight_mode = get_weightmode();
@@ -226,12 +222,10 @@ void *EOFs(void * argument)
   int ngrids = vlistNgrids(vlistID1);
   for ( int index = 1; index < ngrids; index++ )
     if ( vlistGrid(vlistID1, 0) != vlistGrid(vlistID1, index))
-      {
-	cdoAbort("Too many different grids!");
-      }
+      cdoAbort("Too many different grids!");
 
   double *weight = (double *) Malloc(gridsize*sizeof(double));
-  for ( i = 0; i < gridsize; ++i ) weight[i] = 1.;
+  for ( int i = 0; i < gridsize; ++i ) weight[i] = 1.;
 
   if ( weight_mode == WEIGHT_ON )
     {
@@ -245,8 +239,6 @@ void *EOFs(void * argument)
 
   /* eigenvalues */
 
-  tsID = 0;
-
   /* COUNT NUMBER OF TIMESTEPS if EOF_ or EOF_TIME */
   if ( operfunc == EOF_ || operfunc == EOF_TIME )
     {
@@ -255,16 +247,13 @@ void *EOFs(void * argument)
       nts = vlistNtsteps(vlistID1);
       if ( nts == -1 )
 	{
-	  while ( TRUE )
-	    {
-	      nrecs = streamInqTimestep(streamID1, tsID);
-	      if ( nrecs == 0 )  break;
-	      tsID++;
-	    }
+          nts = 0;
+	  while ( streamInqTimestep(streamID1, nts) ) nts++;
 
-	  nts = tsID;
 	  if ( cdoVerbose ) cdoPrint("Counted %i timeSteps", nts);
 	}
+      else
+        if ( cdoVerbose ) cdoPrint("Found %i timeSteps", nts);
 
       streamClose(streamID1);
 
@@ -296,7 +285,7 @@ void *EOFs(void * argument)
         {
           cdoWarning("Solving in time-space:");
           cdoWarning("Number of eigen-functions to write out is bigger than number of time-steps.");
-          cdoWarning("Setting n_eig to %i.", nts);
+          cdoWarning("Setting n_eig to %d.", nts);
           cdoWarning("If You want to force a solution in grid-space use operator eofspatial");
           n_eig = nts;
         }
@@ -310,7 +299,7 @@ void *EOFs(void * argument)
         {
           cdoWarning("Solving in spatial space");
           cdoWarning("Number of eigen-functions to write out is bigger than grid size");
-          cdoWarning("Setting n_eig to %i", gridsize);
+          cdoWarning("Setting n_eig to %d", gridsize);
           cdoWarning("If You want to force a solution in time-space use operator eoftime");
           n_eig = gridsize;
         }
@@ -318,8 +307,8 @@ void *EOFs(void * argument)
     }
 
   if ( cdoVerbose ) 
-    cdoPrint("Calculating %i eigenvectors and %i eigenvalues in %s",
-	     n_eig,n,grid_space==1?"grid_space" : "time_space");
+    cdoPrint("Calculating %d eigenvectors and %d eigenvalues in %s",
+	     n_eig, n, grid_space==1?"grid_space" : "time_space");
 
   /* allocation of temporary fields and output structures */
   int npack = -1;
@@ -337,8 +326,8 @@ void *EOFs(void * argument)
 
       for ( levelID = 0; levelID < nlevs; ++levelID )
         {
-	  eofdata[varID][levelID].init = 0;
-	  eofdata[varID][levelID].first_call = TRUE;
+	  eofdata[varID][levelID].init = false;
+	  eofdata[varID][levelID].first_call = true;
 	  eofdata[varID][levelID].eig_val = NULL;
 	  eofdata[varID][levelID].covar_array = NULL;
 	  eofdata[varID][levelID].covar = NULL;
@@ -350,14 +339,13 @@ void *EOFs(void * argument)
     }
 
   if ( cdoVerbose )
-    cdoPrint("Allocated eigenvalue/eigenvector structures with nts=%i gridsize=%i", nts, gridsize);
+    cdoPrint("Allocated eigenvalue/eigenvector structures with nts=%d gridsize=%d", nts, gridsize);
 
-  int ipack, jpack;
   double *covar_array = NULL;
   double **covar = NULL;
   double sum_w = 1.;
 
-  tsID = 0;
+  int tsID = 0;
 
   /* read the data and create covariance matrices for each var & level */
   while ( TRUE )
@@ -365,7 +353,7 @@ void *EOFs(void * argument)
       nrecs = streamInqTimestep(streamID1, tsID);
       if ( nrecs == 0 ) break;
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
         {
           streamInqRecord(streamID1, &varID, &levelID);
           streamReadRecord(streamID1, in, &nmiss);
@@ -375,31 +363,31 @@ void *EOFs(void * argument)
 	  if ( npack == -1 )
 	    {
 	      npack = 0;
-	      for ( i = 0; i < gridsize; ++i )
+	      for ( int i = 0; i < gridsize; ++i )
 		{
 		  if ( !DBL_IS_EQUAL(weight[i], 0.0) && !DBL_IS_EQUAL(weight[i], missval) &&
 		       !DBL_IS_EQUAL(in[i], missval) )
-		    pack[npack++] = i;
-		}
+                    {
+                      pack[npack] = i;
+                      npack++;
+                    }
+                }
 
 	      if ( weight_mode == WEIGHT_ON )
 		{
 		  sum_w = 0;
-		  for ( i = 0; i < npack; i++ )  sum_w += weight[pack[i]];
+		  for ( int i = 0; i < npack; i++ ) sum_w += weight[pack[i]];
 		}
 	    }
 
-	  ipack = 0;
-	  for ( i = 0; i < gridsize; ++i )
+	  int ipack = 0;
+	  for ( int i = 0; i < gridsize; ++i )
 	    {
 	      if ( !DBL_IS_EQUAL(weight[i], 0.0) && !DBL_IS_EQUAL(weight[i], missval) &&
-		   !DBL_IS_EQUAL(in[i], missval) && pack[ipack++] != i )
+		   !DBL_IS_EQUAL(in[i], missval) )
 		{
-		  cdoAbort("Missing values unsupported!");
-		}
-	      else if ( DBL_IS_EQUAL(in[i], missval) && pack[ipack] == i )
-		{
-		  cdoAbort("Missing values unsupported!");
+                  if ( pack[ipack] != i ) cdoAbort("Missing values unsupported!");
+                  ipack++;
 		}
 	    }
 
@@ -407,14 +395,12 @@ void *EOFs(void * argument)
             {
 	      if ( !eofdata[varID][levelID].init )
 		{
-		  n = npack;
-		  double *covar_array = (double *) Malloc(npack*npack*sizeof(double));
+                  n = npack;
+		  double *covar_array = (double *) Malloc(((size_t)npack)*npack*sizeof(double));
 		  covar = (double **) Malloc(npack*sizeof(double *));
-		  for ( i = 0; i < npack; ++i ) covar[i] = covar_array + npack*i;
-		  for ( i = 0; i < npack; ++i )
-		    {
-		      for ( j = 0; j < npack; ++j ) covar[i][j] = 0;
-		    }
+		  for ( int i = 0; i < npack; ++i ) covar[i] = covar_array + ((size_t)npack)*i;
+		  for ( int i = 0; i < npack; ++i )
+                    for ( int j = 0; j < npack; ++j ) covar[i][j] = 0;
 
 		  eofdata[varID][levelID].covar_array = covar_array;
 		  eofdata[varID][levelID].covar       = covar;
@@ -424,11 +410,11 @@ void *EOFs(void * argument)
 		  covar = eofdata[varID][levelID].covar;
 		}
 #if defined(_OPENMP)
-#pragma omp parallel for private(ipack, jpack) default(shared)
+#pragma omp parallel for default(shared)
 #endif
-	      for ( ipack = 0; ipack < npack; ++ipack )
+	      for ( int ipack = 0; ipack < npack; ++ipack )
 		{
-		  for ( jpack = ipack; jpack < npack; ++jpack )
+		  for ( int jpack = ipack; jpack < npack; ++jpack )
 		    covar[ipack][jpack] += in[pack[ipack]] * in[pack[jpack]];
 		}
 	    }
@@ -437,11 +423,11 @@ void *EOFs(void * argument)
 	      double *data = (double *) Malloc(npack*sizeof(double));
 	      eofdata[varID][levelID].data[tsID] = data;
 
-	      for ( ipack = 0; ipack < npack; ipack++ )
+	      for ( int ipack = 0; ipack < npack; ipack++ )
 		data[ipack] = in[pack[ipack]];
 	    }
 
-	  eofdata[varID][levelID].init = 1;
+	  eofdata[varID][levelID].init = true;
         }
 
       tsID++;
@@ -454,21 +440,21 @@ void *EOFs(void * argument)
   /* write files with eigenvalues (ID3) and eigenvectors (ID2) */
 
   /* eigenvalues */
-  int streamID2   = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
-  int vlistID2    = vlistDuplicate(vlistID1);
-  int taxisID2    = taxisDuplicate(taxisID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   taxisDefRdate(taxisID2, 0);
   taxisDefRtime(taxisID2, 0);
   vlistDefTaxis(vlistID2, taxisID2);
-  int gridID2     = gridCreate(GRID_LONLAT, 1);
+
+  int gridID2 = gridCreate(GRID_LONLAT, 1);
   gridDefXsize(gridID2, 1);
   gridDefYsize(gridID2, 1);
-  xvals    = 0;
-  yvals    = 0;
+  double xvals = 0, yvals = 0;
   gridDefXvals(gridID2, &xvals);
   gridDefYvals(gridID2, &yvals);
-  for ( i = 0; i < ngrids; i++ )
+  for ( int i = 0; i < ngrids; i++ )
     vlistChangeGridIndex(vlistID2, i, gridID2);
 
   /*  eigenvectors */
@@ -522,7 +508,7 @@ void *EOFs(void * argument)
 
 	      if ( eofdata[varID][levelID].first_call )
 		{
-		  eofdata[varID][levelID].first_call = FALSE;
+		  eofdata[varID][levelID].first_call = false;
 
 		  if ( cdoVerbose )
 		    cdoPrint("Calculating covar matrices for %i levels of var%i (%s)", nlevs, varID, vname);
@@ -541,10 +527,11 @@ void *EOFs(void * argument)
 
 		      covar = eofdata[varID][levelID].covar;
 
-		      for ( ipack = 0; ipack < npack; ++ipack )
+		      for ( int ipack = 0; ipack < npack; ++ipack )
 			{
-			  i = pack[ipack];
-			  for ( jpack = 0; jpack < npack; ++jpack)
+                          int j;
+			  int i = pack[ipack];
+			  for ( int jpack = 0; jpack < npack; ++jpack )
 			    {
 			      if ( jpack < ipack )
 				{
@@ -568,7 +555,7 @@ void *EOFs(void * argument)
 
 		      covar_array = (double *) Malloc(nts*nts*sizeof(double));
 		      covar = (double **) Malloc(nts*sizeof(double *));
-		      for ( i = 0; i < nts; ++i ) covar[i] = covar_array + nts*i;
+		      for ( int i = 0; i < nts; ++i ) covar[i] = covar_array + nts*i;
 
 		      eig_val = (double *) Malloc(nts*sizeof(double));
 		      eofdata[varID][levelID].eig_val     = eig_val;
@@ -576,17 +563,17 @@ void *EOFs(void * argument)
 		      eofdata[varID][levelID].covar       = covar;
 
 #if defined(_OPENMP)
-#pragma omp parallel for private(j1, j2, i, sum) default(shared) schedule(dynamic)
+#pragma omp parallel for default(shared) schedule(dynamic)
 #endif
-		      for ( j1 = 0; j1 < nts; j1++ )
+		      for ( int j1 = 0; j1 < nts; j1++ )
 			{
-			  for ( j2 = 0; j2 < j1; j2++ ) covar[j1][j2] = covar[j2][j1];
-			  for ( j2 = j1; j2 < nts; j2++ )
+                          double *df1p = data[j1];
+			  for ( int j2 = 0; j2 < j1; j2++ ) covar[j1][j2] = covar[j2][j1];
+			  for ( int j2 = j1; j2 < nts; j2++ )
 			    {
-			      sum = 0;
-			      double *df1p = data[j1];
 			      double *df2p = data[j2];
-			      for ( i = 0; i < npack; i++ )
+			      double sum = 0;
+			      for ( int i = 0; i < npack; i++ )
 				sum += weight[pack[i]]*df1p[i]*df2p[i];
 			      covar[j1][j2] = sum / sum_w / nts;
 			    }
@@ -610,9 +597,9 @@ void *EOFs(void * argument)
 		  if ( cdoTimer ) timer_stop(timer_eig);
 		  /* NOW: covar contains the eigenvectors, eig_val the eigenvalues */
 
-		  for ( i = 0; i < gridsize; ++i ) out[i] = missval;
+		  for ( int i = 0; i < gridsize; ++i ) out[i] = missval;
 	  
-		  // for ( i = 0; i < n; i++ ) eig_val[i] *= sum_w;
+		  // for ( int i = 0; i < n; i++ ) eig_val[i] *= sum_w;
 		} // first_call
 	      else
 		{
@@ -626,7 +613,7 @@ void *EOFs(void * argument)
 		  else if ( time_space ) scale_eigvec_time(out, tsID, nts, npack, pack, weight, covar, data, missval, sum_w);
 
                   nmiss = 0;
-                  for ( i = 0; i < gridsize; i++ ) if ( DBL_IS_EQUAL(out[i], missval) ) nmiss++;
+                  for ( int i = 0; i < gridsize; i++ ) if ( DBL_IS_EQUAL(out[i], missval) ) nmiss++;
 
                   streamDefRecord(streamID3, varID, levelID);
                   streamWriteRecord(streamID3, out, nmiss);
diff --git a/src/Echam5ini.c b/src/Echam5ini.c
index 7e5bb2b..7ea6dc5 100644
--- a/src/Echam5ini.c
+++ b/src/Echam5ini.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -271,7 +271,7 @@ int import_e5ml(const char *filename, VAR **vars)
   cdoAbort("NetCDF support not compiled in!");
 #endif
 
-  return (nvars);
+  return nvars;
 }
 
 static
@@ -1078,7 +1078,7 @@ int import_e5res(const char *filename, VAR **vars, ATTS *atts)
   cdoAbort("NetCDF support not compiled in!");
 #endif
 
-  return (nvars);
+  return nvars;
 }
 
 static
@@ -1427,13 +1427,9 @@ void export_e5res(const char *filename, VAR *vars, int nvars)
 
 void *Echam5ini(void *argument)
 {
-  int operatorID;
-  int operfunc;
-  int IMPORT_E5ML, IMPORT_E5RES;
-  int EXPORT_E5ML, EXPORT_E5RES;
   int streamID1, streamID2 = CDI_UNDEFID;
   int nrecs = 0;
-  int recID, varID, levelID;
+  int varID, levelID;
   int vlistID1, vlistID2;
   int nvars = 0;
   int iv, nlev;
@@ -1442,13 +1438,13 @@ void *Echam5ini(void *argument)
 
   cdoInitialize(argument);
 
-  IMPORT_E5ML  = cdoOperatorAdd("import_e5ml",  func_read,  0, NULL);
-  IMPORT_E5RES = cdoOperatorAdd("import_e5res", func_read,  0, NULL);
-  EXPORT_E5ML  = cdoOperatorAdd("export_e5ml",  func_write, 0, NULL);
-  EXPORT_E5RES = cdoOperatorAdd("export_e5res", func_write, 0, NULL);
+  int IMPORT_E5ML  = cdoOperatorAdd("import_e5ml",  func_read,  0, NULL);
+  int IMPORT_E5RES = cdoOperatorAdd("import_e5res", func_read,  0, NULL);
+  int EXPORT_E5ML  = cdoOperatorAdd("export_e5ml",  func_write, 0, NULL);
+  int EXPORT_E5RES = cdoOperatorAdd("export_e5res", func_write, 0, NULL);
 
-  operatorID = cdoOperatorID();
-  operfunc = cdoOperatorF1(operatorID);
+  int operatorID = cdoOperatorID();
+  int operfunc = cdoOperatorF1(operatorID);
 
   if ( operatorID == EXPORT_E5ML && processSelf() != 0 )
     cdoAbort("This operator can't be linked with other operators!");
@@ -1482,13 +1478,13 @@ void *Echam5ini(void *argument)
 	  if ( vars[iv].name )     vlistDefVarName(vlistID2, varID, vars[iv].name);
 	  if ( vars[iv].longname ) vlistDefVarLongname(vlistID2, varID, vars[iv].longname);
           if ( vars[iv].units )    vlistDefVarUnits(vlistID2, varID, vars[iv].units);
-	  vlistDefVarDatatype(vlistID2, varID, DATATYPE_FLT64);
+	  vlistDefVarDatatype(vlistID2, varID, CDI_DATATYPE_FLT64);
 	}
 
       for ( iatt = 0; iatt < atts.natxt; ++iatt )
 	{
 	  /* printf("%s: %s\n", atts.atxtname[iatt], atts.atxtentry[iatt]); */
-	  vlistDefAttTxt(vlistID2, CDI_GLOBAL, atts.atxtname[iatt],
+	  cdiDefAttTxt(vlistID2, CDI_GLOBAL, atts.atxtname[iatt],
 			 (int)strlen(atts.atxtentry[iatt])+1, atts.atxtentry[iatt]);
 	}
 
@@ -1496,7 +1492,7 @@ void *Echam5ini(void *argument)
       vlistDefTaxis(vlistID2, taxisID);
 
       if ( cdoDefaultFileType == CDI_UNDEFID )
-	cdoDefaultFileType = FILETYPE_NC;
+	cdoDefaultFileType = CDI_FILETYPE_NC;
 
       streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
@@ -1600,7 +1596,7 @@ void *Echam5ini(void *argument)
 	  vtime = 120000;
 	}
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
diff --git a/src/Enlarge.c b/src/Enlarge.c
index 3bfdc45..818db62 100644
--- a/src/Enlarge.c
+++ b/src/Enlarge.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -29,16 +29,8 @@
 
 void *Enlarge(void *argument)
 {
-  int i, index;
-  int recID, nrecs;
-  int varID, levelID;
-  int nmiss;
-  int gridsize1;
-  int gridID1;
-  int xsize1, ysize1;
-  int ix, iy;
-  int linfo = TRUE;
-  double missval;
+  int nrecs;
+  bool linfo = true;
 
   cdoInitialize(argument);
 
@@ -65,7 +57,7 @@ void *Enlarge(void *argument)
     cdoAbort("Gridsize of input stream is greater than new gridsize!");
 
   int ngrids = vlistNgrids(vlistID1);
-  for ( index = 0; index < ngrids; index++ )
+  for ( int index = 0; index < ngrids; index++ )
     {
       vlistChangeGridIndex(vlistID2, index, gridID2);
     }
@@ -84,16 +76,17 @@ void *Enlarge(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
+          int varID, levelID, nmiss;
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, array1, &nmiss);
 
-	  missval = vlistInqVarMissval(vlistID1, varID);
-	  gridID1 = vlistInqVarGrid(vlistID1, varID);
-	  xsize1 = gridInqXsize(gridID1);
-	  ysize1 = gridInqYsize(gridID1);
-	  gridsize1 = gridInqSize(gridID1);
+	  double missval = vlistInqVarMissval(vlistID1, varID);
+	  int gridID1 = vlistInqVarGrid(vlistID1, varID);
+	  int xsize1 = gridInqXsize(gridID1);
+	  int ysize1 = gridInqYsize(gridID1);
+	  int gridsize1 = gridInqSize(gridID1);
 
 	  if ( xsize1 == 0 ) xsize1 = 1;
 	  if ( ysize1 == 0 ) ysize1 = 1;
@@ -104,11 +97,11 @@ void *Enlarge(void *argument)
 	      if ( linfo )
 		{
 		  cdoPrint("Enlarge zonal");
-		  linfo = FALSE;
+		  linfo = false;
 		}
 	      
-	      for ( iy = 0; iy < ysize2; iy++ )
-		for ( ix = 0; ix < xsize2; ix++ )
+	      for ( int iy = 0; iy < ysize2; iy++ )
+		for ( int ix = 0; ix < xsize2; ix++ )
 		  array2[ix+iy*xsize2] = array1[iy];
 
 	      if ( nmiss ) nmiss *= xsize2;
@@ -118,11 +111,11 @@ void *Enlarge(void *argument)
 	      if ( linfo )
 		{
 		  cdoPrint("Enlarge meridional");
-		  linfo = FALSE;
+		  linfo = false;
 		}
 	      
-	      for ( iy = 0; iy < ysize2; iy++ )
-		for ( ix = 0; ix < xsize2; ix++ )
+	      for ( int iy = 0; iy < ysize2; iy++ )
+		for ( int ix = 0; ix < xsize2; ix++ )
 		  array2[ix+iy*xsize2] = array1[ix];
 
 	      if ( nmiss ) nmiss *= ysize2;
@@ -130,7 +123,7 @@ void *Enlarge(void *argument)
 	  else
 	    {
 	      memcpy(array2, array1, gridsize1*sizeof(double));
-	      for ( i = gridsize1; i < gridsize2; i++ )
+	      for ( int i = gridsize1; i < gridsize2; i++ )
 		{
 		  array2[i] = array1[gridsize1-1];
 		}
diff --git a/src/Enlargegrid.c b/src/Enlargegrid.c
index 3d791a6..8190e2a 100644
--- a/src/Enlargegrid.c
+++ b/src/Enlargegrid.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -31,37 +31,27 @@
 static
 void gen_index(int gridID1, int gridID2, int *index)
 {
-  int nlat1, nlon1;
-  int nlat2, nlon2;
-  int gridtype1, gridtype2;
-  int gridsize2;
-  int i, j, k, i1, i2;
-  int *xindex = NULL, *yindex = NULL;
-  double *xvals1 = NULL, *yvals1 = NULL;
-  double *xvals2 = NULL, *yvals2 = NULL;
+  int i1;
 
-  gridtype1 = gridInqType(gridID1);
-  gridtype2 = gridInqType(gridID2);
+  int gridtype1 = gridInqType(gridID1);
+  int gridtype2 = gridInqType(gridID2);
 
-  gridsize2 = gridInqSize(gridID2);
+  int gridsize2 = gridInqSize(gridID2);
 
   if ( gridtype1 != gridtype2 )
     cdoAbort("Input streams have different grid types!");
 
   if ( index == NULL ) cdoAbort("Internal problem, index not allocated!");
 
-  for ( i = 0; i < gridsize2; i++ ) index[i] = -1;
+  for ( int i = 0; i < gridsize2; i++ ) index[i] = -1;
 
   if ( gridtype1 == GRID_LONLAT || gridtype1 == GRID_GAUSSIAN )
     {
-      if ( gridIsRotated(gridID1) )
-	cdoAbort("Rotated grids unsupported!");
-
-      nlon1 = gridInqXsize(gridID1);
-      nlat1 = gridInqYsize(gridID1);
+      int nlon1 = gridInqXsize(gridID1);
+      int nlat1 = gridInqYsize(gridID1);
 
-      nlon2 = gridInqXsize(gridID2);
-      nlat2 = gridInqYsize(gridID2);
+      int nlon2 = gridInqXsize(gridID2);
+      int nlat2 = gridInqYsize(gridID2);
 
       if ( ! (gridInqXvals(gridID1, NULL) && gridInqYvals(gridID1, NULL)) )
 	cdoAbort("Grid 1 has no values!");
@@ -69,13 +59,13 @@ void gen_index(int gridID1, int gridID2, int *index)
       if ( ! (gridInqXvals(gridID2, NULL) && gridInqYvals(gridID2, NULL)) )
 	cdoAbort("Grid 2 has no values!");
 
-      xvals1 = (double*) Malloc(nlon1*sizeof(double));
-      yvals1 = (double*) Malloc(nlat1*sizeof(double));
-      xvals2 = (double*) Malloc(nlon2*sizeof(double));
-      yvals2 = (double*) Malloc(nlat2*sizeof(double));
+      double *xvals1 = (double*) Malloc(nlon1*sizeof(double));
+      double *yvals1 = (double*) Malloc(nlat1*sizeof(double));
+      double *xvals2 = (double*) Malloc(nlon2*sizeof(double));
+      double *yvals2 = (double*) Malloc(nlat2*sizeof(double));
 
-      xindex = (int*) Malloc(nlon2*sizeof(int));
-      yindex = (int*) Malloc(nlat2*sizeof(int));
+      int *xindex = (int*) Malloc(nlon2*sizeof(int));
+      int *yindex = (int*) Malloc(nlat2*sizeof(int));
 
       gridInqXvals(gridID1, xvals1);
       gridInqYvals(gridID1, yvals1);
@@ -101,7 +91,7 @@ void gen_index(int gridID1, int gridID2, int *index)
 	grid_to_degree(units, nlat2, yvals2, "grid2 center lat");
       }
 
-      for ( i2 = 0; i2 < nlat2; i2++ )
+      for ( int i2 = 0; i2 < nlat2; i2++ )
 	{
 	  for ( i1 = 0; i1 < nlat1; i1++ )
 	    if ( fabs(yvals2[i2]-yvals1[i1]) < 0.001 ) break;
@@ -112,7 +102,7 @@ void gen_index(int gridID1, int gridID2, int *index)
             yindex[i2] = i1;
 	}
 
-      for ( i2 = 0; i2 < nlon2; i2++ )
+      for ( int i2 = 0; i2 < nlon2; i2++ )
 	{
 	  for ( i1 = 0; i1 < nlon1; i1++ )
 	    if ( fabs(xvals2[i2]-xvals1[i1]) < 0.001 ) break;
@@ -143,9 +133,9 @@ void gen_index(int gridID1, int gridID2, int *index)
       for ( i2 = 0; i2 < nlat2; i2++ )
 	printf("y %d %d\n", i2, yindex[i2]);
       */
-      k = 0;
-      for ( j = 0; j < nlat2; j++ )
-	for ( i = 0; i < nlon2; i++ )
+      int k = 0;
+      for ( int j = 0; j < nlat2; j++ )
+	for ( int i = 0; i < nlon2; i++ )
 	  {
 	    if ( xindex[i] == -1 || yindex[j] == -1 )
 	      index[k++] = -1;
@@ -168,13 +158,7 @@ void gen_index(int gridID1, int gridID2, int *index)
 
 void *Enlargegrid(void *argument)
 {
-  int varID;
   int nrecs = 0;
-  int recID, levelID;
-  int nmiss1, nmiss2;
-  int index;
-  int i;
-  double missval1;
 
   cdoInitialize(argument);
 
@@ -191,7 +175,7 @@ void *Enlargegrid(void *argument)
   int taxisID2 = taxisDuplicate(taxisID1);
 
   int ndiffgrids = 0;
-  for ( index = 1; index < vlistNgrids(vlistID1); index++ )
+  for ( int index = 1; index < vlistNgrids(vlistID1); index++ )
     if ( vlistGrid(vlistID1, 0) != vlistGrid(vlistID1, index) )
       ndiffgrids++;
 
@@ -211,7 +195,7 @@ void *Enlargegrid(void *argument)
   int vlistID2 = vlistDuplicate(vlistID1);
 
   int ngrids = vlistNgrids(vlistID1);
-  for ( index = 0; index < ngrids; index++ )
+  for ( int index = 0; index < ngrids; index++ )
     {
       vlistChangeGridIndex(vlistID2, index, gridID2);
     }
@@ -228,20 +212,21 @@ void *Enlargegrid(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
+          int varID, levelID, nmiss1;
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, array1, &nmiss1);
 
-	  missval1 = vlistInqVarMissval(vlistID1, varID);
+	  double missval1 = vlistInqVarMissval(vlistID1, varID);
 
-	  for ( i = 0; i < gridsize2; i++ ) array2[i] = missval1;
-	  for ( i = 0; i < gridsize1; i++ )
+	  for ( int i = 0; i < gridsize2; i++ ) array2[i] = missval1;
+	  for ( int i = 0; i < gridsize1; i++ )
 	    if ( gindex[i] >= 0 )
 	      array2[gindex[i]] = array1[i];		
 
-	  nmiss2 = 0;
-	  for ( i = 0; i < gridsize2; i++ )
+	  int nmiss2 = 0;
+	  for ( int i = 0; i < gridsize2; i++ )
 	    if ( DBL_IS_EQUAL(array2[i], missval1) ) nmiss2++;
 
 	  streamDefRecord(streamID2, varID, levelID);
diff --git a/src/Ensstat.c b/src/Ensstat.c
index 39cff41..5bdd142 100644
--- a/src/Ensstat.c
+++ b/src/Ensstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -30,7 +30,6 @@
       Ensstat    enspctl         Ensemble percentiles
 */
 
-
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
@@ -40,14 +39,7 @@
 
 void *Ensstat(void *argument)
 {
-  int i;
-  int varID = 0, recID;
-  int gridID;
-  int nrecs, nrecs0;
-  int levelID = 0;
-  int streamID = 0;
-  int nmiss;
-  double missval;
+  int nrecs0;
   typedef struct
   {
     int streamID;
@@ -84,10 +76,10 @@ void *Ensstat(void *argument)
       argc--;
     }
 
-  int count_data = FALSE;
+  bool count_data = false;
   if ( argc == 1 )
     {
-      if ( strcmp("count", operatorArgv()[nargc-1]) == 0 ) count_data = TRUE;
+      if ( strcmp("count", operatorArgv()[nargc-1]) == 0 ) count_data = true;
       else cdoAbort("Unknown parameter: >%s<", operatorArgv()[nargc-1]); 
     }
     
@@ -102,8 +94,8 @@ void *Ensstat(void *argument)
 
   ens_file_t *ef = (ens_file_t *) Malloc(nfiles*sizeof(ens_file_t));
 
-  field_t *field = (field_t *) Malloc(ompNumThreads*sizeof(field_t));
-  for ( i = 0; i < ompNumThreads; i++ )
+  field_type *field = (field_type *) Malloc(ompNumThreads*sizeof(field_type));
+  for ( int i = 0; i < ompNumThreads; i++ )
     {
       field_init(&field[i]);
       field[i].size   = nfiles;
@@ -140,17 +132,17 @@ void *Ensstat(void *argument)
   if ( count_data )
     {
       count2 = (double *) Malloc(gridsize*sizeof(double));
-      for ( varID = 0; varID < nvars; ++varID )
+      for ( int varID = 0; varID < nvars; ++varID )
 	{
 	  char name[CDI_MAX_NAME];
 	  vlistInqVarName(vlistID2, varID, name);
 	  strcat(name, "_count");
-	  gridID = vlistInqVarGrid(vlistID2, varID);
+	  int gridID = vlistInqVarGrid(vlistID2, varID);
 	  int zaxisID = vlistInqVarZaxis(vlistID2, varID);
 	  int tsteptype = vlistInqVarTsteptype(vlistID2, varID);
 	  int cvarID = vlistDefVar(vlistID2, gridID, zaxisID, tsteptype);
 	  vlistDefVarName(vlistID2, cvarID, name);
-	  vlistDefVarDatatype(vlistID2, cvarID, DATATYPE_INT16);
+	  vlistDefVarDatatype(vlistID2, cvarID, CDI_DATATYPE_INT16);
 	  if ( cvarID != (varID+nvars) ) cdoAbort("Internal error, varIDs do not match!");
 	}
     }
@@ -159,21 +151,35 @@ void *Ensstat(void *argument)
 
   streamDefVlist(streamID2, vlistID2);
 
+  bool lwarning = false;
+  bool lerror = false;
   int tsID = 0;
   do
     {
       nrecs0 = streamInqTimestep(ef[0].streamID, tsID);
       for ( int fileID = 1; fileID < nfiles; fileID++ )
 	{
-	  streamID = ef[fileID].streamID;
-	  nrecs = streamInqTimestep(streamID, tsID);
+	  int streamID = ef[fileID].streamID;
+	  int nrecs = streamInqTimestep(streamID, tsID);
 	  if ( nrecs != nrecs0 )
 	    {
 	      if ( nrecs == 0 )
-		cdoAbort("Inconsistent ensemble file, too few time steps in %s!", cdoStreamName(fileID)->args);
+                {
+                  lwarning = true;
+                  cdoWarning("Inconsistent ensemble file, too few time steps in %s!", cdoStreamName(fileID)->args);
+                }
+	      else if ( nrecs0 == 0 )
+                {
+                  lwarning = true;
+                  cdoWarning("Inconsistent ensemble file, too few time steps in %s!", cdoStreamName(0)->args);
+                }
 	      else
-		cdoAbort("Inconsistent ensemble file, number of records at time step %d of %s and %s differ!",
-			 tsID+1, cdoStreamName(0)->args, cdoStreamName(fileID)->args);
+                {
+                  lerror = true;
+                  cdoWarning("Inconsistent ensemble file, number of records at time step %d of %s and %s differ!",
+                             tsID+1, cdoStreamName(0)->args, cdoStreamName(fileID)->args);
+                }
+              goto CLEANUP;
 	    }
 	}
 
@@ -183,30 +189,30 @@ void *Ensstat(void *argument)
 	  streamDefTimestep(streamID2, tsID);
 	}
 
-      for ( recID = 0; recID < nrecs0; recID++ )
+      for ( int recID = 0; recID < nrecs0; recID++ )
 	{
+          int varID = 0, levelID;
 #if defined(_OPENMP)
-#pragma omp parallel for default(none) shared(ef, nfiles)         \
-                                         private(streamID, nmiss) \
-                                     lastprivate(varID, levelID)
+#pragma omp parallel for default(none) shared(ef, nfiles) lastprivate(varID, levelID)
 #endif
 	  for ( int fileID = 0; fileID < nfiles; fileID++ )
 	    {
-	      streamID = ef[fileID].streamID;
+              int nmiss;
+	      int streamID = ef[fileID].streamID;
 	      streamInqRecord(streamID, &varID, &levelID);
 	      streamReadRecord(streamID, ef[fileID].array, &nmiss);
               ef[fileID].missval = vlistInqVarMissval(ef[fileID].vlistID, varID);
 	    }
 
-	  gridID   = vlistInqVarGrid(vlistID1, varID);
+	  int gridID = vlistInqVarGrid(vlistID1, varID);
 	  gridsize = gridInqSize(gridID);
-	  missval  = vlistInqVarMissval(vlistID1, varID);
+	  double missval = vlistInqVarMissval(vlistID1, varID);
 
-	  nmiss = 0;
+	  int nmiss = 0;
 #if defined(_OPENMP)
 #pragma omp parallel for default(shared)
 #endif
-	  for ( i = 0; i < gridsize; ++i )
+	  for ( int i = 0; i < gridsize; ++i )
 	    {
 	      int ompthID = cdo_omp_get_thread_num();
 
@@ -252,6 +258,11 @@ void *Ensstat(void *argument)
     }
   while ( nrecs0 > 0 );
 
+ CLEANUP:
+
+  if ( lwarning ) cdoWarning("Inconsistent ensemble, processed only the first %d timesteps!", tsID);
+  if ( lerror ) cdoAbort("Inconsistent ensemble, processed only the first %d timesteps!", tsID);
+
   for ( int fileID = 0; fileID < nfiles; fileID++ )
     streamClose(ef[fileID].streamID);
 
@@ -264,7 +275,7 @@ void *Ensstat(void *argument)
   if ( array2 ) Free(array2);
   if ( count2 ) Free(count2);
 
-  for ( i = 0; i < ompNumThreads; i++ )
+  for ( int i = 0; i < ompNumThreads; i++ )
     {
       if ( field[i].ptr    ) Free(field[i].ptr);
       if ( field[i].weight ) Free(field[i].weight);
diff --git a/src/Ensstat3.c b/src/Ensstat3.c
index 134761a..69c4546 100644
--- a/src/Ensstat3.c
+++ b/src/Ensstat3.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -51,33 +51,23 @@ double roc_curve_integrate(const double **roc, const int n);
 
 void *Ensstat3(void *argument)
 {
-  int operatorID;
-  int operfunc, datafunc;
   int i,j;
-  int nvars,nbins, nrecs = 0, nrecs0, nmiss, nens, nfiles;
+  int nrecs = 0, nrecs0, nmiss;
   int cum;
   int chksum;                  // for check of histogram population 
-  int levelID, varID, recID, tsID, binID = 0;
-  int gridsize = 0;
+  int levelID, varID, binID = 0;
+  int vlistID;
   int gridID, gridID2;
   int have_miss = 0;
   int streamID = 0, streamID2 = 0;
-  int vlistID, vlistID1, vlistID2;
-  int taxisID1, taxisID2;
-  int zaxisID2;
-  int *varID2;
-  int time_mode;
   int **array2 = NULL;
   int **ctg_tab = NULL, *hist = NULL;         // contingency table and histogram
   double missval;
-  double *levs;
   double *dat;                  // pointer to ensemble data for ROC
   double *uThresh = NULL, *lThresh = NULL;    // thresholds for histograms
   double **roc = NULL;                 // receiver operating characteristics table
   double val;
   int ival;
-  field_t *field;
-  const char *ofilename;
 
   typedef struct
   {
@@ -85,7 +75,6 @@ void *Ensstat3(void *argument)
     int vlistID;
     double *array;
   } ens_file_t;
-  ens_file_t *ef = NULL;
 
   cdoInitialize(argument);
 
@@ -93,35 +82,35 @@ void *Ensstat3(void *argument)
   cdoOperatorAdd("ensrkhist_space", func_rank, space_data, NULL);
   cdoOperatorAdd("ensrkhist_time",  func_rank, time_data,  NULL);
   
-  operatorID = cdoOperatorID();
-  operfunc = cdoOperatorF1(operatorID);
-  datafunc = cdoOperatorF2(operatorID);
-
+  int operatorID = cdoOperatorID();
+  int operfunc = cdoOperatorF1(operatorID);
+  int datafunc = cdoOperatorF2(operatorID);
 
+  int nbins = 0;
   if ( operfunc == func_roc ) {
     operatorInputArg("Number of eigen functions to write out");
-    nbins       = parameter2int(operatorArgv()[0]);
+    nbins = parameter2int(operatorArgv()[0]);
   }
   
-  nfiles = cdoStreamCnt() - 1;
-  nens = nfiles-1;
+  int nfiles = cdoStreamCnt() - 1;
+  int nens = nfiles-1;
 
   if ( cdoVerbose )
     cdoPrint("Ensemble over %d files.", nfiles);
 
-  ofilename = cdoStreamName(nfiles)->args;
+  const char *ofilename = cdoStreamName(nfiles)->args;
 
   if ( !cdoOverwriteMode && fileExists(ofilename) && !userFileOverwrite(ofilename) )
     cdoAbort("Outputfile %s already exists!", ofilename);
 
-  ef = (ens_file_t*) Malloc(nfiles*sizeof(ens_file_t));
+  ens_file_t *ef = (ens_file_t*) Malloc(nfiles*sizeof(ens_file_t));
 
   /* *************************************************** */
   /* should each thread be allocating memory locally???? */
   /* ("first touch strategy")                            */
   /* --> #pragma omp parallel for ...                    */
   /* *************************************************** */
-  field = (field_t*) Malloc(ompNumThreads*sizeof(field_t));
+  field_type *field = (field_type*) Malloc(ompNumThreads*sizeof(field_type));
   for ( i = 0; i < ompNumThreads; i++ )
     {
       field_init(&field[i]);
@@ -146,19 +135,19 @@ void *Ensstat3(void *argument)
   for ( int fileID = 1; fileID < nfiles; fileID++ )
     vlistCompare(ef[0].vlistID, ef[fileID].vlistID, CMP_ALL);
 
-  vlistID1 = ef[0].vlistID;
-  vlistID2 = vlistCreate();
-  nvars = vlistNvars(vlistID1);
-  varID2 = (int*) Malloc(nvars*sizeof(int));
+  int vlistID1 = ef[0].vlistID;
+  int vlistID2 = vlistCreate();
+  int nvars = vlistNvars(vlistID1);
+  int *varID2 = (int*) Malloc(nvars*sizeof(int));
 
-  levs = (double*) Calloc(nfiles, sizeof(double));
-  zaxisID2 = zaxisCreate(ZAXIS_GENERIC, nfiles);
+  double *levs = (double*) Calloc(nfiles, sizeof(double));
+  int zaxisID2 = zaxisCreate(ZAXIS_GENERIC, nfiles);
   for ( i=0; i<nfiles; i++ )
     levs[i] = i;
   zaxisDefLevels(zaxisID2,levs);
   zaxisDefName(zaxisID2, "histogram_binID");
 
-  time_mode = datafunc == TIME? TSTEP_INSTANT : TSTEP_CONSTANT;
+  int time_mode = datafunc == TIME? TSTEP_INSTANT : TSTEP_CONSTANT;
 
   for ( varID=0; varID<nvars; varID++) {
 
@@ -182,8 +171,8 @@ void *Ensstat3(void *argument)
     varID2[varID] = vlistDefVar(vlistID2, gridID2, zaxisID2, time_mode);
   }
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
   
   for ( varID=0; varID< nvars; varID++ ){
@@ -202,7 +191,7 @@ void *Ensstat3(void *argument)
       streamDefVlist(streamID2, vlistID2);
     }
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
 
   for ( int fileID = 0; fileID < nfiles; fileID++ )
     ef[fileID].array = (double*) Malloc(gridsize*sizeof(double));
@@ -239,7 +228,7 @@ void *Ensstat3(void *argument)
   }
   
   
-  tsID = 0;
+  int tsID = 0;
   do
     {
       nrecs0 = streamInqTimestep(ef[0].streamID, tsID);
@@ -265,7 +254,7 @@ void *Ensstat3(void *argument)
 
       //      fprintf(stderr,"TIMESTEP %i varID %i rec %i\n",tsID,varID,recID);
       
-      for ( recID = 0; recID < nrecs0; recID++ )
+      for ( int recID = 0; recID < nrecs0; recID++ )
 	{
 #if defined(_OPENMP)
 #pragma omp parallel for default(none) shared(ef, nfiles)      \
@@ -454,7 +443,6 @@ void *Ensstat3(void *argument)
     fprintf(stdout, "#             :     TP     FP     FN     TN         TPR        FPR\n");
     
     for ( i=0; i<= nbins; i++ )  {
-      int sum;
       int p = ctg_tab[i][TP] + ctg_tab[i][FN];
       int n = ctg_tab[i][FP] + ctg_tab[i][TN];
       double tpr = ctg_tab[i][TP]/(double) p;
@@ -464,7 +452,7 @@ void *Ensstat3(void *argument)
       roc[i][TPR] = tpr;
       roc[i][FPR] = fpr;
       
-      sum = ctg_tab[i][TP] + ctg_tab[i][TN] + ctg_tab[i][FP] + ctg_tab[i][FN];
+      int sum = ctg_tab[i][TP] + ctg_tab[i][TN] + ctg_tab[i][FP] + ctg_tab[i][FN];
 
       fprintf(stdout, "%3i %10.4g: %6i %6i %6i %6i (%6i): %10.4g %10.4g\n",
 	      i,i<nbins?lThresh[i]:1,
@@ -510,12 +498,11 @@ void *Ensstat3(void *argument)
 
 
 double roc_curve_integrate(const double **roc, const int n) {
-  double y1, y0, x1,x0, dx, dy, area;
+  double y1, y0, x1,x0, dx, dy;
   double step_area;
-  int i=0;
-  area = 0;
+  double area = 0;
 
-  for ( i=1; i<=n; i++ ) {
+  for ( int i = 1; i <= n; ++i ) {
     x1 = roc[i][FPR]; x0 = roc[i-1][FPR];
     y1 = roc[i][TPR]; y0 = roc[i-1][TPR];
     dx = x1-x0;
diff --git a/src/Ensval.c b/src/Ensval.c
index b36bce7..c368557 100644
--- a/src/Ensval.c
+++ b/src/Ensval.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -42,26 +42,20 @@ enum RESTYPE_CRPS { CRPS_RES,CRPS_RELI,CRPS_POT };
 
 void *Ensval(void *argument)
 {
-  int operatorID;
-  int operfunc;
   int i,k;
-  int nvars,nrecs = 0, nrecs0, nmiss, nens, nfiles, nostreams = 0, ngrids;
-  int levelID, varID, recID, tsID;
+  int nrecs = 0, nrecs0, nmiss, nostreams = 0, ngrids;
+  int levelID, varID;
   int gridsize = 0;
-  int gridID = -1, gridID2;
+  int vlistID;
+  int gridID = -1;
   int have_miss = 0;
-  int stream, streamID1 = -1, streamID = 0, *streamID2;
-  int vlistID, vlistID1, *vlistID2;
-  int taxisID1, *taxisID2;
-  int zaxisID1, *zaxisID2;
+  int stream, streamID = 0;
   //int xsize,ysize;
   double missval = 0;
   double *alpha, *beta, *alpha_weights, *beta_weights;
   double *brs_g, *brs_o, *brs_g_weights, *brs_o_weights;
-  double *r;                      // Pointer to hold results for single time step
   double xval=0; double yval=0;
   double xa, *x;
-  double *val;
   double *weights, sum_weights = 0;
   double crps_reli, crps_pot, crps;
   double heavyside0, heavysideN;
@@ -69,11 +63,8 @@ void *Ensval(void *argument)
   double g,o,p;
 
   int fileID;
-  const char *ofilebase;
-  char *ofilename;
   char file_suffix[32];
   char type_suffix[10];
-  const char *refname;
 
   typedef struct
   {
@@ -81,16 +72,12 @@ void *Ensval(void *argument)
     int vlistID;
     double *array;
   } ens_file_t;
-  ens_file_t *ef = NULL;
 
 
   // INITIALIZE POINTERS
-  streamID2 = NULL;
   alpha = NULL; beta = NULL; alpha_weights = NULL; beta_weights = NULL; 
   brs_g = NULL; brs_o = NULL; brs_g_weights = NULL; brs_o_weights = NULL;
-  r = NULL;
   x = NULL;
-  val = NULL;
   weights = NULL; 
   //int vlistCheck, gridsizeCheck;
   
@@ -99,11 +86,11 @@ void *Ensval(void *argument)
   cdoOperatorAdd("enscrps",   CRPS,  0,   NULL);
   cdoOperatorAdd("ensbrs",    BRS,   0,   NULL);
   
-  operatorID = cdoOperatorID();
-  operfunc = cdoOperatorF1(operatorID);
+  int operatorID = cdoOperatorID();
+  int operfunc = cdoOperatorF1(operatorID);
 
-  nfiles = cdoStreamCnt() - 1;
-  nens = nfiles-1;
+  int nfiles = cdoStreamCnt() - 1;
+  int nens = nfiles-1;
 
   if ( operfunc == CRPS ) {
     nostreams = 3;
@@ -118,16 +105,16 @@ void *Ensval(void *argument)
   }
 
   // allocate array to hold results 
-  r = (double*) Malloc( nostreams*sizeof(double));
+  double *r = (double*) Malloc( nostreams*sizeof(double));
   
 
   // one stream for each value of the decomposition
-  streamID2 = (int*) Malloc( nostreams*sizeof(int));
-  vlistID2 = (int*) Malloc( nostreams*sizeof(int));
-  taxisID2 = (int*) Malloc( nostreams*sizeof(int));
-  zaxisID2 = (int*) Malloc( nostreams*sizeof(int));
+  int *streamID2 = (int*) Malloc(nostreams*sizeof(int));
+  int *vlistID2 = (int*) Malloc(nostreams*sizeof(int));
+  int *taxisID2 = (int*) Malloc(nostreams*sizeof(int));
+  int *zaxisID2 = (int*) Malloc(nostreams*sizeof(int));
 
-  val = (double*) Calloc( nfiles,sizeof(double));
+  double *val = (double*) Calloc( nfiles,sizeof(double));
   
   if ( operfunc == CRPS ) {
     alpha= (double*) Calloc( nens+1,sizeof(double));
@@ -142,13 +129,11 @@ void *Ensval(void *argument)
   if ( cdoVerbose )
     cdoPrint("Ensemble over %d files (Ensstat5).", nfiles-1);
 
-  ef = (ens_file_t*) Malloc(nfiles*sizeof(ens_file_t));
+  ens_file_t *ef = (ens_file_t*) Malloc(nfiles*sizeof(ens_file_t));
   
   for ( fileID = 0; fileID < nfiles; fileID++ )
     {
       streamID = streamOpenRead(cdoStreamName(fileID));
-      if ( fileID == 0 ) streamID1 = streamID;
-
       vlistID = streamInqVlist(streamID);
       
       ef[fileID].streamID = streamID;
@@ -156,30 +141,32 @@ void *Ensval(void *argument)
       ef[fileID].array    = NULL;
     }
 
+  int streamID1 = ef[0].streamID;
+
   if ( cdoVerbose ) 
     cdoPrint("Opened %i Input Files for Ensemble Operator",nfiles);
   
   /* check for identical contents of all ensemble members */
-  nvars = vlistNvars(ef[0].vlistID);
+  int nvars = vlistNvars(ef[0].vlistID);
   if ( cdoVerbose ) 
     cdoPrint("nvars %i",nvars);
 
   for ( fileID = 1; fileID < nfiles; fileID++ )
     vlistCompare(ef[0].vlistID, ef[fileID].vlistID, CMP_ALL);
 
-  vlistID1 = ef[0].vlistID;
-  taxisID1 = vlistInqTaxis(vlistID1);
-  zaxisID1 = vlistInqVarZaxis(vlistID1,0);
+  int vlistID1 = ef[0].vlistID;
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int zaxisID1 = vlistInqVarZaxis(vlistID1,0);
 
-  gridID2 = gridCreate(GRID_LONLAT, 1);
+  int gridID2 = gridCreate(GRID_LONLAT, 1);
   gridDefXsize(gridID2, 1);
   gridDefYsize(gridID2, 1);
   gridDefXvals(gridID2, &xval);
   gridDefYvals(gridID2, &yval);
 
-  ofilebase = cdoStreamName(nfiles)->args;
+  const char *ofilebase = cdoStreamName(nfiles)->args;
 
-  refname = cdoStreamName(0)->argv[cdoStreamName(0)->argc-1];
+  const char *refname = cdoStreamName(0)->argv[cdoStreamName(0)->argc-1];
   memset(file_suffix, 0, sizeof(file_suffix) );
   cdoGenFileSuffix(file_suffix, sizeof(file_suffix), streamInqFiletype(streamID1), vlistID1, refname);
 
@@ -203,7 +190,7 @@ void *Ensval(void *argument)
       break;
     }
 
-    ofilename = (char*) Calloc(namelen, sizeof(char));
+    char *ofilename = (char*) Calloc(namelen, sizeof(char));
 
     sprintf(ofilename, "%s.%s%s", ofilebase, type_suffix, file_suffix);
     // fprintf(stderr, "StreamID %i: %s\n", stream, ofilename);
@@ -238,7 +225,7 @@ void *Ensval(void *argument)
   if ( cdoVerbose ) 
     cdoPrint(" sum_weights %10.6f",sum_weights);
   
-  tsID = 0;
+  int tsID = 0;
   do
     {
       nrecs0 = streamInqTimestep(ef[0].streamID, tsID);
@@ -255,7 +242,7 @@ void *Ensval(void *argument)
 	if ( nrecs0 > 0 ) streamDefTimestep(streamID2[stream], tsID);
       }
       
-      for ( recID = 0; recID < nrecs0; recID++ )
+      for ( int recID = 0; recID < nrecs0; recID++ )
 	{
 	  for ( fileID = 0; fileID < nfiles; fileID++ ) 
 	    {
@@ -493,7 +480,7 @@ void *Ensval(void *argument)
 	    memset(brs_g, 0, (nens+1)*sizeof(double) );
 	    break;
 	  }
-	}   // for ( recID = 0; recID < nrecs; recID++ ) 
+	}   // for ( int recID = 0; recID < nrecs; recID++ ) 
       tsID++;
     }  while ( nrecs );
       
diff --git a/src/Eof3d.c b/src/Eof3d.c
index b91c303..70b4bde 100644
--- a/src/Eof3d.c
+++ b/src/Eof3d.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -50,24 +50,20 @@ void *EOF3d(void * argument)
 {
   enum {EOF3D_, EOF3D_TIME, EOF3D_SPATIAL};
 
-  int temp_size = 0;
-  int i, i2, j, j1, j2, eofID, varID, recID, levelID, tsID;
-  int missval_warning=0;
-  int nmiss,ngrids,n=0,nlevs=0,npack=0,nts=0;
+  size_t temp_size = 0, npack = 0;
+  int i, varID, levelID;
+  int missval_warning = 0;
+  int nmiss, ngrids, n = 0, nlevs = 0;
   int offset;
   int timer_cov = 0, timer_eig = 0;
-  int *varID2;
 
   int calendar = CALENDAR_STANDARD;
   juldate_t juldate;
 
-  double missval=0;
-  double sum_w, sum;
+  double missval = 0;
+  double sum_w;
   double **cov = NULL;                                /* TODO: covariance matrix / eigenvectors after solving */
   double *eigv;
-  double *xvals, *yvals, *zvals;
-  double *df1p, *df2p;
-
 
   if ( cdoTimer )
     {
@@ -84,7 +80,7 @@ void *EOF3d(void * argument)
   int operfunc    = cdoOperatorF1(operatorID);
 
   operatorInputArg("Number of eigen functions to write out");
-  int n_eig       = parameter2int(operatorArgv()[0]);
+  int n_eig = parameter2int(operatorArgv()[0]);
 
   enum T_EIGEN_MODE eigen_mode = get_eigenmode();
   enum T_WEIGHT_MODE weight_mode = get_weightmode();
@@ -97,12 +93,12 @@ void *EOF3d(void * argument)
   int nrecs;
 
   double *weight = (double *) Malloc(gridsize*sizeof(double));
-  for ( i = 0; i < gridsize; ++i ) weight[i] = 1.;
+  for ( int i = 0; i < gridsize; ++i ) weight[i] = 1.;
 
   if ( weight_mode == WEIGHT_ON )
     {
       int wstatus = gridWeights(gridID1, weight);
-      if ( wstatus != 0  )
+      if ( wstatus != 0 )
 	{
 	  weight_mode = WEIGHT_OFF;
 	  cdoWarning("Using constant grid cell area weights!");
@@ -114,22 +110,17 @@ void *EOF3d(void * argument)
   if ( operfunc == EOF3D_SPATIAL )
     cdoAbort("Operator not Implemented - use eof3d or eof3dtime instead");
 
-  tsID = 0;
-
   /* COUNT NUMBER OF TIMESTEPS if EOF3D_ or EOF3D_TIME */
-  nts = vlistNtsteps(vlistID1);
+  int nts = vlistNtsteps(vlistID1);
   if ( nts == -1 )
     {
-      while ( TRUE )
-	{
-	  nrecs = streamInqTimestep(streamID1, tsID);
-	  if ( nrecs == 0 )  break;
-	  tsID++;
-	}
-      
-      nts = tsID;
+      nts = 0;
+      while ( streamInqTimestep(streamID1, nts) ) nts++;
+
       if ( cdoVerbose ) cdoPrint("Counted %i timeSteps", nts);
     }
+  else
+    if ( cdoVerbose ) cdoPrint("Found %i timeSteps", nts);
 
   streamClose(streamID1);
 
@@ -161,19 +152,19 @@ void *EOF3d(void * argument)
     {
       gridsize            = vlistGridsizeMax(vlistID1);
       nlevs               = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
-      temp_size           = gridsize * nlevs;
+      temp_size           = ((size_t)gridsize) * nlevs;
       missval             = vlistInqVarMissval(vlistID1, varID);
 
       datacounts[varID]   = (int*) Malloc(nlevs*sizeof(int));
       datafields[varID]   = (double **) Malloc(nts*sizeof(double *));
 
-      for ( tsID = 0; tsID < nts; tsID++ )
+      for ( int tsID = 0; tsID < nts; tsID++ )
 	{
 	  datafields[varID][tsID] = (double *) Malloc(temp_size*sizeof(double));
-	  for ( i = 0; i < temp_size; ++i ) datafields[varID][tsID][i] = 0;
+	  for ( size_t i = 0; i < temp_size; ++i ) datafields[varID][tsID][i] = 0;
 	}
       datacounts[varID] = (int *) Malloc(temp_size*sizeof(int));	      
-      for( i = 0; i < temp_size; i++) datacounts[varID][i] = 0;
+      for( size_t i = 0; i < temp_size; i++) datacounts[varID][i] = 0;
       
       eigenvectors[varID] = (double **) Malloc(n_eig*sizeof(double *));
       eigenvalues[varID]  = (double **) Malloc(nts*sizeof(double *));
@@ -183,7 +174,7 @@ void *EOF3d(void * argument)
 	  if ( i < n_eig )
 	    {
 	      eigenvectors[varID][i] = (double *) Malloc(temp_size*sizeof(double));
-	      for ( i2 = 0; i2 < temp_size; ++i2 )
+	      for ( size_t i2 = 0; i2 < temp_size; ++i2 )
 		eigenvectors[varID][i][i2] = missval;
 	    }
 	  
@@ -196,7 +187,7 @@ void *EOF3d(void * argument)
     cdoPrint("allocated eigenvalue/eigenvector with nts=%i, n=%i, gridsize=%i for processing in %s",
 	     nts,n,gridsize,"time_space");
   
-  tsID = 0;
+  int tsID = 0;
 
   /* read the data and create covariance matrices for each var & level */
   while ( TRUE )
@@ -204,7 +195,7 @@ void *EOF3d(void * argument)
       nrecs = streamInqTimestep(streamID1, tsID);
       if ( nrecs == 0 ) break;
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
         {
           streamInqRecord(streamID1, &varID, &levelID);
 
@@ -225,7 +216,7 @@ void *EOF3d(void * argument)
 		{
 		  if ( missval_warning == 0 )
 		    {
-		      cdoWarning("Missing Value Support not Checked for this Operator!");
+		      cdoWarning("Missing Value Support not checked for this Operator!");
 		      cdoWarning("Does not work with changing locations of missing values in time.");
 		      missval_warning = 1;
 		    }
@@ -244,23 +235,24 @@ void *EOF3d(void * argument)
   for ( varID = 0; varID < nvars; varID++ )
     {
       gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
-      nlevs               = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
-      temp_size = gridsize * nlevs;
+      nlevs    = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
+      temp_size = ((size_t)gridsize) * nlevs;
 
-      if ( cdoVerbose )  {
-	char vname[64];
-	vlistInqVarName(vlistID1,varID,&vname[0]);
-	cdoPrint("============================================================================");
-	cdoPrint("Calculating covariance matrix and SVD for var%i (%s)",varID,vname);
-      }
+      if ( cdoVerbose )
+        {
+          char vname[64];
+          vlistInqVarName(vlistID1,varID,&vname[0]);
+          cdoPrint("============================================================================");
+          cdoPrint("Calculating covariance matrix and SVD for var%i (%s)",varID,vname);
+        }
 
       npack = 0;    // TODO already set to 0
 
       if ( cdoTimer ) timer_start(timer_cov);
       
-      for ( i = 0; i < temp_size ; i++ )
+      for ( size_t i = 0; i < temp_size ; i++ )
 	{
-	  if ( datacounts[varID][i] > 1)
+	  if ( datacounts[varID][i] > 1 )
 	    {
 	      pack[npack] = i;
 	      npack++;
@@ -271,41 +263,45 @@ void *EOF3d(void * argument)
       if ( weight_mode == WEIGHT_ON )
 	{
 	  sum_w = 0;
-	  for ( i = 0; i < npack; i++ )  sum_w += weight[pack[i]];
+	  for ( size_t i = 0; i < npack; i++ )  sum_w += weight[pack[i]];
 	}
 
-      if ( npack < 1 ) {
-	char vname[64];
-	vlistInqVarName(vlistID1,varID,&vname[0]);
-	cdoWarning("Refusing to calculate EOF from a single time step for var%i (%s)",varID,&vname[0]);
-	continue;
-      }
+      if ( npack < 1 )
+        {
+          char vname[64];
+          vlistInqVarName(vlistID1,varID,&vname[0]);
+          cdoWarning("Refusing to calculate EOF from a single time step for var%i (%s)",varID,&vname[0]);
+          continue;
+        }
 
 	  
       cov = (double **) Malloc(nts*sizeof(double*));
-      for ( j1 = 0; j1 < nts; j1++)
+      for ( int j1 = 0; j1 < nts; j1++)
 	cov[j1] = (double *) Malloc(nts*sizeof(double));
       eigv = (double *) Malloc(n*sizeof(double));
 
-      if ( cdoVerbose )  {
-	cdoPrint("varID %i allocated eigv and cov with nts=%i and n=%i",varID,nts,n);
-	cdoPrint("   npack=%i, nts=%i temp_size=%i",npack,nts,temp_size);
-      }
+      if ( cdoVerbose )
+        {
+          cdoPrint("varID %i allocated eigv and cov with nts=%i and n=%i", varID, nts, n);
+          cdoPrint("   npack=%zu, nts=%i temp_size=%zu", npack, nts, temp_size);
+        }
 
 
 #if defined(_OPENMP)
-#pragma omp parallel for private(j1,j2,sum,df1p,df2p) default(shared) schedule(static,2000)
+#pragma omp parallel for default(shared) schedule(static,2000)
 #endif 
-      for ( j1 = 0; j1 < nts; j1++)
-	for ( j2 = j1; j2 < nts; j2++ )
-	  {
-	    sum = 0;
-	    df1p = datafields[varID][j1];
-	    df2p = datafields[varID][j2];
-	    for ( i = 0; i < npack; i++ )
-	      sum += weight[pack[i]%gridsize]*df1p[pack[i]]*df2p[pack[i]];
-	    cov[j2][j1] = cov[j1][j2] = sum / sum_w / nts;
-	  }
+      for ( int j1 = 0; j1 < nts; j1++ )
+        {
+          double *df1p = datafields[varID][j1];
+          for ( int j2 = j1; j2 < nts; j2++ )
+            {
+              double *df2p = datafields[varID][j2];
+              double sum = 0;
+              for ( size_t i = 0; i < npack; i++ )
+                sum += weight[pack[i]%gridsize]*df1p[pack[i]]*df2p[pack[i]];
+              cov[j2][j1] = cov[j1][j2] = sum / sum_w / nts;
+            }
+        }
       
       if ( cdoVerbose ) cdoPrint("calculated cov-matrix");
 
@@ -316,7 +312,7 @@ void *EOF3d(void * argument)
       if ( cdoTimer ) timer_start(timer_eig);
 
       if ( cdoVerbose ) 
-	cdoPrint("Processed correlation matrix for var %2i | npack: %4i",varID,n);
+	cdoPrint("Processed correlation matrix for var %2i | npack: %zu", varID, n);
 
       if ( eigen_mode == JACOBI ) 
 	parallel_eigen_solution_of_symmetric_matrix(cov, eigv, n, __func__);
@@ -327,33 +323,34 @@ void *EOF3d(void * argument)
       if ( cdoVerbose ) 
 	cdoPrint("Processed SVD decomposition for var %i from %i x %i matrix",varID,n,n);
 
-      for( eofID=0; eofID<n; eofID++ )
+      for( int eofID = 0; eofID < n; eofID++ )
 	eigenvalues[varID][eofID][0] = eigv[eofID];
       
       if ( cdoTimer ) timer_stop(timer_eig);
 
-      for ( eofID = 0; eofID < n_eig; eofID++ )
+      for ( int eofID = 0; eofID < n_eig; eofID++ )
 	{
 	  double *eigenvec = eigenvectors[varID][eofID];
 
 #if defined(_OPENMP)
-#pragma omp parallel for default(none) private(j,sum) shared(varID,nts,eofID,npack,pack,cov,datafields,eigenvec)
+#pragma omp parallel for default(none) shared(varID,nts,eofID,npack,pack,cov,datafields,eigenvec)
 #endif 
-	  for ( i = 0; i < npack; i++ )
+	  for ( size_t i = 0; i < npack; i++ )
 	    {
-	      sum = 0;
-	      for ( j = 0; j < nts; j++ )
+	      double sum = 0;
+	      for ( int j = 0; j < nts; j++ )
 		sum += datafields[varID][j][pack[i]] * cov[eofID][j];
 
 	      eigenvec[pack[i]] = sum;
 	    }
+
 	  // NORMALIZING
-	  sum = 0;
+	  double sum = 0;
 
 #if defined(_OPENMP)
 #pragma omp parallel for default(none)  shared(eigenvec,weight,pack,npack,gridsize) reduction(+:sum)
 #endif 
-	  for ( i = 0; i < npack; i++ )
+	  for ( size_t i = 0; i < npack; i++ )
 	    sum +=  weight[pack[i]%gridsize] *
 	            eigenvec[pack[i]] * eigenvec[pack[i]];
 
@@ -363,7 +360,7 @@ void *EOF3d(void * argument)
 #if defined(_OPENMP)
 #pragma omp parallel for default(none) shared(sum,npack,eigenvec,pack)
 #endif
-	      for( i = 0; i < npack; i++ )
+	      for ( size_t i = 0; i < npack; i++ )
 		eigenvec[pack[i]] /= sum;
 	    }
 	  else
@@ -371,57 +368,52 @@ void *EOF3d(void * argument)
 #if defined(_OPENMP)
 #pragma omp parallel for default(none) shared(eigenvec,pack,missval,npack)
 #endif
-	      for( i = 0; i < npack; i++ )
+	      for( size_t i = 0; i < npack; i++ )
 		eigenvec[pack[i]] = missval;
 	    }
 	}     /* for ( eofID = 0; eofID < n_eig; eofID++ )     */
 
       if ( eigv ) Free(eigv);
-      for ( i=0; i<n; i++ )
-	if ( cov[i] ) 
-	  Free(cov[i]);
+      for ( i = 0; i < n; i++ )
+	if ( cov[i] ) Free(cov[i]);
     }         /* for ( varID = 0; varID < nvars; varID++ )    */
 
   /* write files with eigenvalues (ID3) and eigenvectors (ID2) */
 
   /*  eigenvalues */
-  int streamID2   = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
-  int taxisID2    = taxisDuplicate(taxisID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
 
-  int gridID2     = gridCreate(GRID_LONLAT, 1);
+  int gridID2 = gridCreate(GRID_LONLAT, 1);
   gridDefXsize(gridID2, 1);
   gridDefYsize(gridID2, 1);
-  xvals       = (double*) Malloc(1*sizeof(double));
-  yvals       = (double*) Malloc(1*sizeof(double));
-  zvals       = (double*) Malloc(1*sizeof(double));
-  xvals[0]    = 0;
-  yvals[0]    = 0;
-  zvals[0]    = 0;
-  gridDefXvals(gridID2, xvals);
-  gridDefYvals(gridID2, yvals);
-
-  int zaxisID2 = zaxisCreate(ZAXIS_GENERIC,1);
-  zaxisDefLevels(zaxisID2,zvals);
-  zaxisDefName(zaxisID2,"zaxis_Reduced");
-  zaxisDefLongname(zaxisID2,"Reduced zaxis from EOF3D - only one eigen value per 3D eigen vector");
+  double xvals = 0, yvals = 0;
+  gridDefXvals(gridID2, &xvals);
+  gridDefYvals(gridID2, &yvals);
+
+  int zaxisID2 = zaxisCreate(ZAXIS_GENERIC, 1);
+  double zvals = 0;
+  zaxisDefLevels(zaxisID2, &zvals);
+  zaxisDefName(zaxisID2, "zaxis_Reduced");
+  zaxisDefLongname(zaxisID2, "Reduced zaxis from EOF3D - only one eigen value per 3D eigen vector");
 
   int vlistID2 = vlistCreate();
   taxisDefRdate(taxisID2, 0);
   taxisDefRtime(taxisID2, 0);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  varID2 = (int*) Malloc(nvars*sizeof(int));
+  int *varID2 = (int*) Malloc(nvars*sizeof(int));
   for ( varID=0; varID<nvars; varID++ )
     varID2[varID] = vlistDefVar(vlistID2, gridID2, zaxisID2, TSTEP_INSTANT);
-  ngrids      = vlistNgrids(vlistID2);
+  ngrids = vlistNgrids(vlistID2);
   for ( i = 0; i < ngrids; i++ )
     vlistChangeGridIndex(vlistID2, i, gridID2);
 
-  int streamID3   = streamOpenWrite(cdoStreamName(2), cdoFiletype());
+  int streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
 
-  int vlistID3    = vlistDuplicate(vlistID1);
-  int taxisID3    = taxisDuplicate(taxisID1);
+  int vlistID3 = vlistDuplicate(vlistID1);
+  int taxisID3 = taxisDuplicate(taxisID1);
   taxisDefRdate(taxisID3, 0);
   taxisDefRtime(taxisID3, 0);
   vlistDefTaxis(vlistID3, taxisID3);
@@ -473,9 +465,9 @@ void *EOF3d(void * argument)
 
   for ( varID = 0; varID < nvars; varID++)
     {
-      for( i = 0; i < nts; i++)
+      for ( i = 0; i < nts; i++)
 	{
-	  Free(datafields[varID][tsID]);
+	  Free(datafields[varID][i]);
 	  if ( i < n_eig )
 	    Free(eigenvectors[varID][i]);
 	  Free(eigenvalues[varID][i]);
@@ -492,6 +484,7 @@ void *EOF3d(void * argument)
   Free(eigenvectors);
   Free(eigenvalues);
   Free(in);
+  Free(varID2);
 
   Free(pack);
   Free(weight);
diff --git a/src/Eofcoeff.c b/src/Eofcoeff.c
index 96c066f..b4e259e 100644
--- a/src/Eofcoeff.c
+++ b/src/Eofcoeff.c
@@ -2,7 +2,7 @@
  This file is part of CDO. CDO is a collection of Operators to
  manipulate and analyse Climate model Data.
  
- Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+ 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
@@ -20,7 +20,6 @@
  
  Eofcoeff             eofcoeff             process eof coefficients
 */
-#define WEIGHTS 1
 
 #include <cdi.h>
 #include "cdo.h"
@@ -34,89 +33,69 @@
 void *Eofcoeff(void * argument)
 {
   char eof_name[8], oname[1024], filesuffix[32];
-  const char *refname;
-  //double *w;
   double missval1 = -999, missval2;
-  double *xvals, *yvals;  
-  field_t ***eof;  
-  field_t in;  
-  field_t out;
-  //int operatorID;  
-  int gridsize;
-  int i, varID, recID, levelID, tsID, eofID;    
-  int gridID1, gridID3;
-  int nrecs, nvars, nlevs, neof, nchars, nmiss, ngrids; 
-  int streamID1, streamID2, *streamIDs;
-  int taxisID2, taxisID3;
-  int vlistID1, vlistID2, vlistID3;
+  field_type in;  
+  field_type out;
+  int i, varID, levelID;    
+  int nrecs, nmiss; 
    
   cdoInitialize(argument);
-  cdoOperatorAdd("eofcoeff",  0,       0, NULL);
-  //operatorID = cdoOperatorID();
+
+  if ( processSelf() != 0 ) cdoAbort("This operator can't be combined with other operators!");
+
+  cdoOperatorAdd("eofcoeff",  0,  0, NULL);
      
-  streamID1 = streamOpenRead(cdoStreamName(0));
-  streamID2 = streamOpenRead(cdoStreamName(1));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID2 = streamOpenRead(cdoStreamName(1));
   
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = streamInqVlist(streamID2);
-  vlistID3 = vlistDuplicate(vlistID2);   
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = streamInqVlist(streamID2);
+  int vlistID3 = vlistDuplicate(vlistID2);   
   
   //taxisID1 = vlistInqTaxis(vlistID1);  
-  taxisID2 = vlistInqTaxis(vlistID2); 
-  taxisID3 = taxisDuplicate(taxisID2);
+  int taxisID2 = vlistInqTaxis(vlistID2); 
+  int taxisID3 = taxisDuplicate(taxisID2);
   
-  gridID1 = vlistInqVarGrid(vlistID1, 0);
-  //gridID2 = vlistInqVarGrid(vlistID2, 0);
+  int gridID1 = vlistInqVarGrid(vlistID1, 0);
+  int gridID2 = vlistInqVarGrid(vlistID2, 0);
   
-  if ( vlistGridsizeMax(vlistID1)==vlistGridsizeMax(vlistID2) )
-    gridsize = vlistGridsizeMax(vlistID1);  
-  else
-    {
-      gridsize = -1;
-      cdoAbort ("Gridsize of input files does not match");
-    }
+  int gridsize = vlistGridsizeMax(vlistID1);  
+  if ( gridsize != vlistGridsizeMax(vlistID2) )
+    cdoAbort("Gridsize of input files does not match!");
       
-  
   if ( vlistNgrids(vlistID2) > 1 || vlistNgrids(vlistID1) > 1 )
-    cdoAbort("Too many grids in input");
-  
-  nvars = vlistNvars(vlistID1)==vlistNvars(vlistID2) ? vlistNvars(vlistID1) : -1;
-  nlevs = zaxisInqSize(vlistInqVarZaxis(vlistID1, 0));
-  //w = (double*) Malloc(gridsize*sizeof(double));
-  //gridWeights(gridID2, w);
+    cdoAbort("Too many different grids in input!");
   
-  
-  
-  if (vlistGridsizeMax(vlistID2)   != gridsize ||
-      vlistInqVarGrid(vlistID2, 0) != gridID1 )
-    cdoAbort("EOFs (%s) and data (%s) defined on different grids", cdoStreamName(0)->args, cdoStreamName(1)->args);    
- 
+  int nvars = vlistNvars(vlistID1)==vlistNvars(vlistID2) ? vlistNvars(vlistID1) : -1;
+  int nlevs = zaxisInqSize(vlistInqVarZaxis(vlistID1, 0));  
+
+  if ( gridID1 != gridID2 ) cdoCompareGrids(gridID1, gridID2);
   
   strcpy(oname, cdoStreamName(2)->args);
-  nchars = strlen(oname);
+  int nchars = strlen(oname);
   
-  refname = cdoStreamName(0)->argv[cdoStreamName(0)->argc-1];
+  const char *refname = cdoStreamName(0)->argv[cdoStreamName(0)->argc-1];
   filesuffix[0] = 0;
   cdoGenFileSuffix(filesuffix, sizeof(filesuffix), streamInqFiletype(streamID1), vlistID1, refname);
   
-  eof = (field_t***) Malloc(nvars * sizeof(field_t**));
-  for ( varID=0; varID<nvars; varID++)
-    eof[varID] = (field_t**) Malloc(nlevs*sizeof(field_t*));
+  field_type ***eof = (field_type***) Malloc(nvars * sizeof(field_type**));
+  for ( varID=0; varID<nvars; varID++ )
+    eof[varID] = (field_type**) Malloc(nlevs*sizeof(field_type*));
 
-  eofID = 0;
+  int eofID = 0;
   while ( 1 )       
    {     
      nrecs = streamInqTimestep(streamID1, eofID);
      if ( nrecs == 0) break;
 
-     for ( recID = 0; recID < nrecs; recID++ )
+     for ( int recID = 0; recID < nrecs; recID++ )
        {         
          streamInqRecord(streamID1, &varID, &levelID);
          missval1 = vlistInqVarMissval(vlistID1, varID);
          if ( eofID == 0 )
-           eof[varID][levelID] = (field_t*) Malloc(1*sizeof(field_t));
+           eof[varID][levelID] = (field_type*) Malloc(1*sizeof(field_type));
          else
-           eof[varID][levelID] = (field_t*) Realloc(eof[varID][levelID], (eofID+1)*sizeof(field_t));
+           eof[varID][levelID] = (field_type*) Realloc(eof[varID][levelID], (eofID+1)*sizeof(field_type));
          eof[varID][levelID][eofID].grid   = gridID1;
          eof[varID][levelID][eofID].nmiss  = 0;
          eof[varID][levelID][eofID].missval= missval1;
@@ -132,15 +111,15 @@ void *Eofcoeff(void * argument)
        }
      eofID++;
    }
-  neof = eofID;  
+  int neof = eofID;  
   
   if ( cdoVerbose ) cdoPrint("%s contains %i eof's", cdoStreamName(0)->args, neof);
   // Create 1x1 Grid for output
-  gridID3 = gridCreate(GRID_LONLAT, 1);
+  int gridID3 = gridCreate(GRID_LONLAT, 1);
   gridDefXsize(gridID3, 1);
   gridDefYsize(gridID3, 1);
-  xvals= (double*) Malloc(1*sizeof(double));
-  yvals= (double*) Malloc(1*sizeof(double));
+  double *xvals = (double*) Malloc(1*sizeof(double));
+  double *yvals = (double*) Malloc(1*sizeof(double));
   xvals[0]=0;
   yvals[0]=0;
   gridDefXvals(gridID3, xvals);
@@ -148,7 +127,7 @@ void *Eofcoeff(void * argument)
   
   // Create var-list and time-axis for output
       
-  ngrids = vlistNgrids(vlistID3);
+  int ngrids = vlistNgrids(vlistID3);
   
   for ( i = 0; i < ngrids; i++ )
     vlistChangeGridIndex(vlistID3, i, gridID3);     
@@ -158,7 +137,7 @@ void *Eofcoeff(void * argument)
     vlistDefVarTsteptype(vlistID3, varID, TSTEP_INSTANT);
   
   // open streams for eofcoeff output
-  streamIDs = (int*) Malloc(neof*sizeof(int)); 
+  int *streamIDs = (int*) Malloc(neof*sizeof(int)); 
   for ( eofID = 0; eofID < neof; eofID++)
     {
       oname[nchars] = '\0';                       
@@ -176,7 +155,6 @@ void *Eofcoeff(void * argument)
         cdoPrint("opened %s ('w')  as stream%i for %i. eof", oname, streamIDs[eofID], eofID+1);
       
       streamDefVlist(streamIDs[eofID], vlistID3);
-    
     }
   
   // ALLOCATE temporary fields for data read and write
@@ -186,7 +164,7 @@ void *Eofcoeff(void * argument)
   out.nmiss = 0;
   out.ptr = (double*) Malloc(1*sizeof(double));
  
-  tsID=0;
+  int tsID = 0;
   while ( 1 )
     {      
       nrecs = streamInqTimestep(streamID2, tsID);
@@ -199,14 +177,14 @@ void *Eofcoeff(void * argument)
           streamDefTimestep(streamIDs[eofID],tsID);
         }
       */
-      for ( recID =0; recID< nrecs; recID++ )
+      for ( int recID = 0; recID< nrecs; recID++ )
         {
           streamInqRecord(streamID2, &varID, &levelID);
           missval2 = vlistInqVarMissval(vlistID2, varID);
           streamReadRecord(streamID2, in.ptr, &nmiss);  
           in.nmiss = (size_t) nmiss;
           
-          for (eofID = 0; eofID < neof; eofID++ )
+          for ( eofID = 0; eofID < neof; eofID++ )
             {
               if ( recID == 0 ) streamDefTimestep(streamIDs[eofID],tsID);
               //if ( recID == 0 ) fprintf(stderr, "ts%i rec%i eof%i\n", tsID, recID, eofID);
@@ -235,6 +213,7 @@ void *Eofcoeff(void * argument)
           if ( levelID >= nlevs )
             cdoAbort("Internal error - too high levelID");                              
         }
+
       tsID++;
     }
   
diff --git a/src/Eofcoeff3d.c b/src/Eofcoeff3d.c
index db1d24f..02b7d55 100644
--- a/src/Eofcoeff3d.c
+++ b/src/Eofcoeff3d.c
@@ -2,7 +2,7 @@
  This file is part of CDO. CDO is a collection of Operators to
  manipulate and analyse Climate model Data.
  
- Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+ 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
@@ -20,7 +20,6 @@
  
  Eofcoeff             eofcoeff             process eof coefficients
 */
-#define WEIGHTS 1
 
 #include "cdi.h"
 #include "cdo.h"
@@ -34,88 +33,67 @@
 void *Eofcoeff3d(void * argument)
 {
   char eof_name[6], oname[1024], filesuffix[32];
-  const char *refname;
-  //double *w;
   double missval1 = -999, missval2 = -999;
-  double *xvals, *yvals, *zvals;  
-  field_t ***eof;  
-  field_t in;  
-  field_t **out;
-  //int operatorID, operfunc;  
-  int gridsize;
-  int i, varID, recID, levelID, tsID, eofID, *varID3;    
-  int gridID1,gridID3;
-  int nrecs, nvars, nlevs, neof, nchars, nmiss; 
-  int streamID1, streamID2, *streamIDs;
-  int taxisID2, taxisID3;
-  int vlistID1, vlistID2, vlistID3;
-  int zaxisID3;
+  field_type in;  
+  int i, varID, levelID;    
+  int nrecs, nmiss; 
    
   cdoInitialize(argument);
-  cdoOperatorAdd("eofcoeff3d",  0,       0, NULL);
-  //  operatorID = cdoOperatorID();
-  //  operfunc = cdoOperatorFunc(operatorID);
+
+  if ( processSelf() != 0 ) cdoAbort("This operator can't be combined with other operators!");
+
+  cdoOperatorAdd("eofcoeff3d",  0,  0, NULL);
      
-  streamID1 = streamOpenRead(cdoStreamName(0));
-  streamID2 = streamOpenRead(cdoStreamName(1));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID2 = streamOpenRead(cdoStreamName(1));
   
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = streamInqVlist(streamID2);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = streamInqVlist(streamID2);
   
   //taxisID1 = vlistInqTaxis(vlistID1);  
-  taxisID2 = vlistInqTaxis(vlistID2); 
-  taxisID3 = taxisDuplicate(taxisID2);
+  int taxisID2 = vlistInqTaxis(vlistID2); 
+  int taxisID3 = taxisDuplicate(taxisID2);
   
-  gridID1 = vlistInqVarGrid(vlistID1, 0);
-  //gridID2 = vlistInqVarGrid(vlistID2, 0);
+  int gridID1 = vlistInqVarGrid(vlistID1, 0);
+  int gridID2 = vlistInqVarGrid(vlistID2, 0);
   
-  if ( vlistGridsizeMax(vlistID1)==vlistGridsizeMax(vlistID2) )
-    gridsize = vlistGridsizeMax(vlistID1);  
-  else 
-    {
-      gridsize = -1;
-      cdoAbort("Gridsize of input files does not match");
-    }
-      
+  int gridsize = vlistGridsizeMax(vlistID1);  
+  if ( gridsize != vlistGridsizeMax(vlistID2) )
+    cdoAbort("Gridsize of input files does not match!");     
   
   if ( vlistNgrids(vlistID2) > 1 || vlistNgrids(vlistID1) > 1 )
     cdoAbort("Too many grids in input");
   
-  nvars = vlistNvars(vlistID1)==vlistNvars(vlistID2) ? vlistNvars(vlistID1) : -1;
-  nlevs = zaxisInqSize(vlistInqVarZaxis(vlistID1, 0));
-  //w = (double*) Malloc(gridsize*sizeof(double));
-  //gridWeights(gridID2, w);
-  
+  int nvars = vlistNvars(vlistID1)==vlistNvars(vlistID2) ? vlistNvars(vlistID1) : -1;
+  int nlevs = zaxisInqSize(vlistInqVarZaxis(vlistID1, 0));
   
-  if (vlistGridsizeMax(vlistID2)   != gridsize ||
-      vlistInqVarGrid(vlistID2, 0) != gridID1 )
-    cdoAbort("EOFs (%s) and data (%s) defined on different grids", cdoStreamName(0)->args, cdoStreamName(1)->args);    
+  if ( gridID1 != gridID2 ) cdoCompareGrids(gridID1, gridID2);
  
   strcpy(oname, cdoStreamName(2)->args);
-  nchars = strlen(oname);
+  int nchars = strlen(oname);
   
-  refname = cdoStreamName(0)->argv[cdoStreamName(0)->argc-1];
+  const char *refname = cdoStreamName(0)->argv[cdoStreamName(0)->argc-1];
   filesuffix[0] = 0;
   cdoGenFileSuffix(filesuffix, sizeof(filesuffix), streamInqFiletype(streamID1), vlistID1, refname);
  
-  eof = (field_t***) Malloc(nvars * sizeof(field_t**));
-  for ( varID=0; varID<nvars; varID++)
-    eof[varID] = (field_t**) Malloc(nlevs*sizeof(field_t*));
+  field_type ***eof = (field_type***) Malloc(nvars * sizeof(field_type**));
+  for ( varID=0; varID<nvars; varID++ )
+    eof[varID] = (field_type**) Malloc(nlevs*sizeof(field_type*));
 
-  eofID = 0;
+  int eofID = 0;
   while ( 1 )       
    {     
      nrecs = streamInqTimestep(streamID1, eofID);
      if ( nrecs == 0) break;
 
-     for ( recID = 0; recID < nrecs; recID++ )
+     for ( int recID = 0; recID < nrecs; recID++ )
        {         
          streamInqRecord(streamID1, &varID, &levelID);
          missval1 = vlistInqVarMissval(vlistID1, varID);
          if ( eofID == 0 )
-           eof[varID][levelID] = (field_t*) Malloc(1*sizeof(field_t));
+           eof[varID][levelID] = (field_type*) Malloc(1*sizeof(field_type));
          else
-           eof[varID][levelID] = (field_t*) Realloc(eof[varID][levelID], (eofID+1)*sizeof(field_t));
+           eof[varID][levelID] = (field_type*) Realloc(eof[varID][levelID], (eofID+1)*sizeof(field_type));
          eof[varID][levelID][eofID].grid   = gridID1;
          eof[varID][levelID][eofID].nmiss  = 0;
          eof[varID][levelID][eofID].missval= missval1;
@@ -132,35 +110,35 @@ void *Eofcoeff3d(void * argument)
        }
      eofID++;
    }
-  neof = eofID;  
+  int neof = eofID;  
   
   if ( cdoVerbose ) cdoPrint("%s contains %i eof's", cdoStreamName(0)->args, neof);
   // Create 1x1 Grid for output
-  gridID3 = gridCreate(GRID_LONLAT, 1);
+  int gridID3 = gridCreate(GRID_LONLAT, 1);
   gridDefXsize(gridID3, 1);
   gridDefYsize(gridID3, 1);
-  xvals= (double*) Malloc(1*sizeof(double));
-  yvals= (double*) Malloc(1*sizeof(double));
+  double *xvals= (double*) Malloc(1*sizeof(double));
+  double *yvals= (double*) Malloc(1*sizeof(double));
   xvals[0]=0;
   yvals[0]=0;
   gridDefXvals(gridID3, xvals);
   gridDefYvals(gridID3, yvals);
   
-  zvals = (double *) Malloc( 1* sizeof(double ));
+  double *zvals = (double *) Malloc( 1* sizeof(double ));
   zvals[0] = 0.;
-  zaxisID3 = zaxisCreate(ZAXIS_GENERIC,1);
+  int zaxisID3 = zaxisCreate(ZAXIS_GENERIC,1);
   zaxisDefLevels(zaxisID3,zvals);
   zaxisDefName(zaxisID3,"zaxis_Reduced");
   zaxisDefLongname(zaxisID3,"Reduced zaxis from EOF3D - only one coefficient per 3D eigenvector and time step");
   
-  vlistID3 = vlistCreate();
+  int vlistID3 = vlistCreate();
   vlistDefTaxis(vlistID3,taxisID3);
-  varID3 = (int*) Malloc( nvars * sizeof(int));
+  int *varID3 = (int*) Malloc(nvars * sizeof(int));
   for ( varID=0; varID<nvars; varID++ )
     varID3[varID] = vlistDefVar(vlistID3, gridID3, zaxisID3, TSTEP_INSTANT);
   
   // open streams for eofcoeff output
-  streamIDs = (int*) Malloc(neof*sizeof(int)); 
+  int *streamIDs = (int*) Malloc(neof*sizeof(int)); 
   for ( eofID = 0; eofID < neof; eofID++)
     {
       oname[nchars] = '\0';                       
@@ -183,9 +161,9 @@ void *Eofcoeff3d(void * argument)
   // ALLOCATE temporary fields for data read and write
   in.ptr = (double*) Malloc(gridsize*sizeof(double));
   in.grid = gridID1;  
-  out = (field_t**) Malloc(nvars*sizeof(field_t*));
+  field_type **out = (field_type**) Malloc(nvars*sizeof(field_type*));
   for ( varID = 0; varID < nvars; varID++ ) {
-    out[varID] = (field_t*) Malloc( neof * sizeof(field_t));
+    out[varID] = (field_type*) Malloc( neof * sizeof(field_type));
     for ( eofID=0; eofID<neof; eofID++ ) {
       out[varID][eofID].missval = missval1;
       out[varID][eofID].nmiss = 0;
@@ -193,7 +171,7 @@ void *Eofcoeff3d(void * argument)
     }
   }
 
-  tsID=0;
+  int tsID = 0;
   while ( 1 )
     {      
       nrecs = streamInqTimestep(streamID2, tsID);
@@ -208,19 +186,19 @@ void *Eofcoeff3d(void * argument)
 
       taxisCopyTimestep(taxisID3, taxisID2);
 
-      for ( recID =0; recID< nrecs; recID++ )
+      for ( int recID = 0; recID< nrecs; recID++ )
         {
           streamInqRecord(streamID2, &varID, &levelID);
           missval2 = vlistInqVarMissval(vlistID2, varID);
           streamReadRecord(streamID2, in.ptr, &nmiss);  
           in.nmiss = (size_t) nmiss;
           
-          for (eofID = 0; eofID < neof; eofID++ )
+          for ( eofID = 0; eofID < neof; eofID++ )
             {
               if ( recID == 0 ) streamDefTimestep(streamIDs[eofID],tsID);
 
 	      nmiss = 0;
-              for(i=0;i<gridsize;i++)
+              for( i=0; i<gridsize; i++ )
                 {                  
                   if (! DBL_IS_EQUAL(in.ptr[i],missval2) && 
                       ! DBL_IS_EQUAL(eof[varID][levelID][eofID].ptr[i],missval1 ) )
@@ -255,7 +233,7 @@ void *Eofcoeff3d(void * argument)
       tsID++;
     }
   
-  for ( eofID = 0; eofID < neof; eofID++) streamClose(streamIDs[eofID]);
+  for ( eofID = 0; eofID < neof; eofID++ ) streamClose(streamIDs[eofID]);
 
   streamClose(streamID2);
   streamClose(streamID1);
diff --git a/src/Exprf.c b/src/Exprf.c
index 545492c..45ec76e 100644
--- a/src/Exprf.c
+++ b/src/Exprf.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -41,16 +41,16 @@ Constansts: M_PI, M_E
 #include "grid.h"
 #include "expr.h"
 
+
 void grid_cell_area(int gridID, double *array);
 int getSurfaceID(int vlistID);
 
+
 static
 char *exprs_from_arg(const char *arg)
-{
-  char *exprs = NULL;
-  
+{  
   size_t slen = strlen(arg);
-  exprs = (char*) Malloc(slen+2);
+  char *exprs = (char*) Malloc(slen+2);
   strcpy(exprs, operatorArgv()[0]);
   if ( exprs[slen-1] != ';' )
     {
@@ -63,9 +63,7 @@ char *exprs_from_arg(const char *arg)
 
 static
 char *exprs_from_file(const char *exprf)
-{
-  char *exprs = NULL;
-  
+{  
   /* Open expr script file for reading */
   FILE *fp = fopen(exprf, "r");
   if( fp == NULL ) cdoAbort("Open failed on %s", exprf);
@@ -74,7 +72,7 @@ char *exprs_from_file(const char *exprf)
   if ( stat(exprf, &filestat) != 0 ) cdoAbort("Stat failed on %s", exprf);
 
   size_t fsize = (size_t) filestat.st_size;
-  exprs = (char*) Malloc(fsize+1);
+  char *exprs = (char*) Malloc(fsize+1);
 
   int ichar, ipos = 0;
   while ( (ichar = fgetc(fp)) != EOF ) exprs[ipos++] = ichar;
@@ -101,6 +99,7 @@ paramType *params_new(int vlistID)
   char name[CDI_MAX_NAME];
   char longname[CDI_MAX_NAME];
   char units[CDI_MAX_NAME];
+
   for ( int varID = 0; varID < nvars1; varID++ )
     {
       int gridID     = vlistInqVarGrid(vlistID, varID);
@@ -175,6 +174,7 @@ void params_add_coordinates(int vlistID, parse_param_t *parse_arg)
 {
   char longname[CDI_MAX_NAME];
   char units[CDI_MAX_NAME];
+
   int ngrids = vlistNgrids(vlistID);
   for ( int index = 0; index < ngrids; ++index )
     {
@@ -188,6 +188,7 @@ void params_add_coordinates(int vlistID, parse_param_t *parse_arg)
       params_add_coord(parse_arg, 'a', gridID, size, "m^2", "grid cell area");
       params_add_coord(parse_arg, 'w', gridID, size, NULL, "grid cell area weights");
     }
+
   int nzaxis = vlistNzaxis(vlistID);
   for ( int index = 0; index < nzaxis; ++index )
     {
@@ -239,6 +240,7 @@ void params_delete(paramType *params)
     }
 }
 
+
 void *Expr(void *argument)
 {
   cdoInitialize(argument);
@@ -301,7 +303,7 @@ void *Expr(void *argument)
     parse_arg.needed[varID] = ! REPLACES_VARIABLES(operatorID);
 
   int vartsID = params_add_ts(&parse_arg);
-  parse_arg.tsID       = vartsID;
+  parse_arg.tsID = vartsID;
   params_add_coordinates(vlistID1, &parse_arg);
                   
   CDO_parser_errorno = 0;
@@ -319,7 +321,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",
-               varID, params[varID].name, params[varID].ngp, params[varID].nlev, params[varID].coord);
+               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));
 
@@ -431,7 +433,7 @@ void *Expr(void *argument)
               size_t nlev = parse_arg.coords[i].size;
               double *data = (double*) Malloc(nlev*sizeof(double));
               parse_arg.coords[i].data = data;
-              zaxisInqLevels(zaxisID, data);
+              cdoZaxisInqLevels(zaxisID, data);
             }
           else
             cdoAbort("Computation of coordinate %c not implemented!", coord);
diff --git a/src/FC.c b/src/FC.c
index e8cac9f..2c4dfd3 100644
--- a/src/FC.c
+++ b/src/FC.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -28,20 +28,20 @@
 #include "cdo.h"
 #include "cdo_int.h"
 #include "pstream.h"
+#include "grid.h"
 #include "specspace.h"
-#include "list.h"
+#include "listarray.h"
 
 
 void *FC(void *argument)
 {
-  int nrecs, nvars;
-  int recID, varID, levelID;
+  int nrecs;
+  int varID, levelID;
   int index;
   int gridIDsp = -1, gridIDgp = -1, gridIDfc = -1;
   int gridID1 = -1, gridID2 = -1;
   int gridID;
   int nmiss;
-  int *vars;
   int nlon = 0, nlat = 0, ntr = 0;
   int nsp = 0, nfc = 0;
   double *array2 = NULL;
@@ -110,7 +110,7 @@ void *FC(void *argument)
 	{
 	  nfc  = gridInqSize(gridID1);
 	  ntr  = gridInqTrunc(gridID1);
-	  nlat = nfc2nlat(nfc, ntr);
+	  nlat = nfc_to_nlat(nfc, ntr);
 
 	  if ( gridIDsp != -1 )
 	    if ( ntr != gridInqTrunc(gridIDsp) ) gridIDsp = -1;
@@ -139,7 +139,7 @@ void *FC(void *argument)
       if ( gridID1 != -1 )
 	{
 	  ntr  = gridInqTrunc(gridID1);
-	  nlat = ntr2nlat(ntr);
+	  nlat = ntr_to_nlat(ntr);
 
 	  if ( gridIDfc != -1 )
 	    {
@@ -169,7 +169,7 @@ void *FC(void *argument)
 	{
 	  nlon = gridInqXsize(gridID1);
 	  nlat = gridInqYsize(gridID1);
-	  ntr  = nlat2ntr(nlat);
+	  ntr  = nlat_to_ntr(nlat);
 
 	  if ( gridIDfc != -1 )
 	    if ( ntr != gridInqTrunc(gridIDfc) ) gridIDfc = -1;
@@ -195,7 +195,7 @@ void *FC(void *argument)
 	{
 	  nfc  = gridInqSize(gridID1);
 	  ntr  = gridInqTrunc(gridID1);
-	  nlat = nfc2nlat(nfc, ntr);
+	  nlat = nfc_to_nlat(nfc, ntr);
 
 	  if ( gridIDgp != -1 )
 	    {
@@ -205,9 +205,9 @@ void *FC(void *argument)
 	  if ( gridIDgp == -1 )
 	    {
 	      char gridname[20];
-	      sprintf(gridname, "t%dgrid", ntr);
+	      snprintf(gridname, sizeof(gridname), "t%dgrid", ntr);
 
-	      gridIDgp = gridFromName(gridname);
+	      gridIDgp = grid_from_name(gridname);
 	    }
 
 	  gridID2 = gridIDgp;
@@ -220,8 +220,8 @@ void *FC(void *argument)
 
   // printf("nfc %d, ntr %d, nlat %d, nlon %d\n", nfc, ntr, nlat, nlon);
 
-  nvars = vlistNvars(vlistID2);
-  vars  = (int*) Malloc(nvars*sizeof(int));
+  int nvars = vlistNvars(vlistID2);
+  int *vars  = (int*) Malloc(nvars*sizeof(int));
   for ( varID = 0; varID < nvars; varID++ )
     {
       if ( gridID1 == vlistInqVarGrid(vlistID1, varID) )
@@ -252,7 +252,7 @@ void *FC(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
diff --git a/src/Filedes.c b/src/Filedes.c
index 342f4d3..0cbecc0 100644
--- a/src/Filedes.c
+++ b/src/Filedes.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -30,52 +30,63 @@
 #include "util.h"
 
 
-static
-void printAtts(FILE *fp, int vlistID, int varID)
+void cdo_print_grid(int gridID, int opt);
+void cdo_print_zaxis(int zaxisID);
+
+void cdo_print_attributes(FILE *fp, int cdiID, int varID, int nblanks)
 {
 #define MAXATT 8192
-  int natts, ia;
-  char attname[1024];
+  int natts;
+  char attname[CDI_MAX_NAME];
   int atttype, attlen;
   char atttxt[MAXATT];
   int attint[MAXATT];
   double attflt[MAXATT];
-  int i;
+  char fltstr[128];
 
-  vlistInqNatts(vlistID, varID, &natts);
+  cdiInqNatts(cdiID, varID, &natts);
 
-  for ( ia = 0; ia < natts; ++ia )
+  for ( int ia = 0; ia < natts; ++ia )
     {
-      vlistInqAtt(vlistID, varID, ia, attname, &atttype, &attlen);
-      if ( atttype == DATATYPE_INT )
-	{
+      cdiInqAtt(cdiID, varID, ia, attname, &atttype, &attlen);
+
+      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 )
+        {
 	  if ( attlen > MAXATT ) attlen = MAXATT;
-	  vlistInqAttInt(vlistID, varID, attname, attlen, attint);
-	  fprintf(fp, "  %s=", attname);
-	  for ( i = 0; i < attlen; ++i)
+	  cdiInqAttInt(cdiID, varID, attname, attlen, attint);
+          fprintf(fp, "%*s", nblanks, "");
+	  fprintf(fp, "%s = ", attname);
+	  for ( int i = 0; i < attlen; ++i )
 	    {
 	      if ( i > 0 ) fprintf(fp, ", ");
 	      fprintf(fp, "%d", attint[i]);
 	    }
 	  fprintf(fp, "\n");
 	}
-      else if ( atttype == DATATYPE_FLT )
+      else if ( atttype == CDI_DATATYPE_FLT32 || atttype == CDI_DATATYPE_FLT64 )
 	{
 	  if ( attlen > MAXATT ) attlen = MAXATT;
-	  vlistInqAttFlt(vlistID, varID, attname, MAXATT, attflt);
-	  fprintf(fp, "  %s=", attname);
-	  for ( i = 0; i < attlen; ++i)
+	  cdiInqAttFlt(cdiID, varID, attname, MAXATT, attflt);
+          fprintf(fp, "%*s", nblanks, "");
+	  fprintf(fp, "%s = ", attname);
+	  for ( int i = 0; i < attlen; ++i )
 	    {
 	      if ( i > 0 ) fprintf(fp, ", ");
-	      fprintf(fp, "%g", attflt[i]);
+              if ( atttype == CDI_DATATYPE_FLT32 )
+                fprintf(fp, "%sf", double_to_attstr(CDO_flt_digits, fltstr, sizeof(fltstr), attflt[i]));
+              else
+                fprintf(fp, "%s", double_to_attstr(CDO_dbl_digits, fltstr, sizeof(fltstr), attflt[i]));
 	    }
 	  fprintf(fp, "\n");
 	}
-      else if ( atttype == DATATYPE_TXT )
+      else if ( atttype == CDI_DATATYPE_TXT )
 	{
-	  vlistInqAttTxt(vlistID, varID, attname, sizeof(atttxt), atttxt);
+	  cdiInqAttTxt(cdiID, varID, attname, sizeof(atttxt), atttxt);
 	  atttxt[attlen] = 0;
-	  fprintf(fp, "  %s=\"%s\"\n", attname, atttxt);
+          fprintf(fp, "%*s", nblanks, "");
+	  fprintf(fp, "%s = \"%s\"\n", attname, atttxt);
 	}
     }
 }
@@ -90,7 +101,8 @@ void printHistory(FILE *fp, int streamID)
       char *history = (char*) Malloc(historysize+1);
       history[historysize] = 0;
       streamInqHistoryString(fileID, history);
-      fprintf(fp, "  history=%s\n", history);
+      fprintf(fp, "  history = %s\n", history);
+      Free(history);
     }
 }
 
@@ -99,11 +111,11 @@ void printSource(FILE *fp, int vlistID, int varID)
 {
   /* institute info */
   const char *instptr = institutInqLongnamePtr(vlistInqVarInstitut(vlistID, varID));
-  if ( instptr ) fprintf(fp, "  institution=%s\n", instptr);
+  if ( instptr ) fprintf(fp, "  institution = %s\n", instptr);
 
   /* source info */
   const char *modelptr = modelInqNamePtr(vlistInqVarModel(vlistID, varID));
-  if ( modelptr ) fprintf(fp, "  source=%s\n", modelptr);
+  if ( modelptr ) fprintf(fp, "  source = %s\n", modelptr);
 }
 
 static
@@ -111,28 +123,24 @@ void partab(FILE *fp, int streamID, int option)
 {
   int vlistID = streamInqVlist(streamID);
   int varID, datatype = -1;
-  int param;
   char pstr[32];
   char paramstr[32];
   char varname[CDI_MAX_NAME], varlongname[CDI_MAX_NAME], varstdname[CDI_MAX_NAME], varunits[CDI_MAX_NAME];
-  int natts;
-  int chunktype;
-  int linebreak = 1;
-  double missval;
       
   int nvars = vlistNvars(vlistID);
-  if ( option == 4 ) linebreak = 0;
+  bool linebreak = ( option == 4 ) ? false : true;
 
   if ( option == 2 )
     {
-      vlistInqNatts(vlistID, CDI_GLOBAL, &natts);
+      int natts;
+      cdiInqNatts(vlistID, CDI_GLOBAL, &natts);
       if ( natts > 0 )
 	{
 	  fprintf(fp, "&parameter\n");
-	  fprintf(fp, "  name=_GLOBAL_\n");
+	  fprintf(fp, "  name = _GLOBAL_\n");
           printHistory(fp, streamID);
           printSource(fp, vlistID, 0);
-	  printAtts(fp, vlistID, CDI_GLOBAL);
+	  cdo_print_attributes(fp, vlistID, CDI_GLOBAL, 2);
 	  fprintf(fp, "/\n");
 	}
     }
@@ -153,11 +161,11 @@ void partab(FILE *fp, int streamID, int option)
 	{
 	  fprintf(fp, "&parameter");
 	  if ( linebreak ) fprintf(fp, "\n");
-	  fprintf(fp, "  name=_default_");
+	  fprintf(fp, "  name = _default_");
 	  if ( linebreak ) fprintf(fp, "\n");
 	  if ( datatype2str(datatype, pstr) == 0 )
 	    {
-	      fprintf(fp, "  datatype=%s", pstr);
+	      fprintf(fp, "  datatype = %s", pstr);
 	      if ( linebreak ) fprintf(fp, "\n");
 	    }
 	  fprintf(fp, "/\n");
@@ -172,17 +180,14 @@ void partab(FILE *fp, int streamID, int option)
       varname[0]     = 0;
       varlongname[0] = 0;
       varunits[0]    = 0;
-      param    = vlistInqVarParam(vlistID, varID);
-      missval  = vlistInqVarMissval(vlistID, varID);
+      int param = vlistInqVarParam(vlistID, varID);
+      double missval = vlistInqVarMissval(vlistID, varID);
       vlistInqVarName(vlistID, varID, varname);
-      /* printf("1>%s<\n", varname); */
       vlistInqVarStdname(vlistID, varID, varstdname);
-      /* printf("2>%s<\n", varname); */
       vlistInqVarLongname(vlistID, varID, varlongname);
-      /* printf("3>%s<\n", varname); */
       vlistInqVarUnits(vlistID, varID, varunits);
             
-      fprintf(fp, "  name=%s", varname);
+      fprintf(fp, "  name = %s", varname);
       if ( linebreak ) fprintf(fp, "\n");
       // if ( code   > 0 ) fprintf(fp, "  code=%d\n", code);
       // if ( tabnum > 0 ) fprintf(fp, "  table=%d\n", tabnum);
@@ -194,47 +199,47 @@ void partab(FILE *fp, int streamID, int option)
 	}
       if ( strlen(varstdname) )
 	{
-	  fprintf(fp, "  standard_name=%s", varstdname);
+	  fprintf(fp, "  standard_name = %s", varstdname);
 	  if ( linebreak ) fprintf(fp, "\n");
 	}
       if ( strlen(varlongname) )
 	{
-	  fprintf(fp, "  long_name=\"%s\"", varlongname);
+	  fprintf(fp, "  long_name = \"%s\"", varlongname);
 	  if ( linebreak ) fprintf(fp, "\n");
 	}
       if ( strlen(varunits) )
 	{
-	  fprintf(fp, "  units=\"%s\"", varunits);
+	  fprintf(fp, "  units = \"%s\"", varunits);
 	  if ( linebreak ) fprintf(fp, "\n");
 	}
 
       if ( datatype == -1 )
 	if ( datatype2str(vlistInqVarDatatype(vlistID, varID), pstr) == 0 )
 	  {
-	    fprintf(fp, "  datatype=%s", pstr);
+	    fprintf(fp, "  datatype = %s", pstr);
 	    if ( linebreak ) fprintf(fp, "\n");
 	  }
 
-      chunktype = vlistInqVarChunkType(vlistID, varID);
-      if ( chunktype == CHUNK_AUTO )
+      int chunktype = vlistInqVarChunkType(vlistID, varID);
+      if ( chunktype == CDI_CHUNK_AUTO )
 	{
-	  fprintf(fp, "  chunktype=auto");
+	  fprintf(fp, "  chunktype = auto");
 	  if ( linebreak ) fprintf(fp, "\n");
 	}
-      else if ( chunktype == CHUNK_GRID )
+      else if ( chunktype == CDI_CHUNK_GRID )
 	{
-	  fprintf(fp, "  chunktype=grid");
+	  fprintf(fp, "  chunktype = grid");
 	  if ( linebreak ) fprintf(fp, "\n");
 	}
-      if ( chunktype == CHUNK_LINES )
+      if ( chunktype == CDI_CHUNK_LINES )
 	{
-	  fprintf(fp, "  chunktype=lines");
+	  fprintf(fp, "  chunktype = lines");
 	  if ( linebreak ) fprintf(fp, "\n");
 	}
       
-      if ( option == 2 ) printAtts(fp, vlistID, varID);
+      if ( option == 2 ) cdo_print_attributes(fp, vlistID, varID, 2);
       if ( option == 2 ) 
-	fprintf(fp, "  missing_value=%g\n", missval);
+	fprintf(fp, "  missing_value = %g\n", missval);
       
       if ( !linebreak ) fprintf(fp, "  ");
       fprintf(fp, "/\n");
@@ -244,70 +249,36 @@ void partab(FILE *fp, int streamID, int option)
 static
 void filedes(int streamID)
 {
-  int filetype;
-
   printf("\n");
-  filetype = streamInqFiletype(streamID);
+  int filetype = streamInqFiletype(streamID);
   switch ( filetype )
     {
-    case FILETYPE_GRB:
-      printf("  GRIB data\n");
-      break;
-    case FILETYPE_GRB2:
-      printf("  GRIB2 data\n");
-      break;
-    case FILETYPE_NC:
-      printf("  NetCDF data\n");
-      break;
-    case FILETYPE_NC2:
-      printf("  NetCDF2 data\n");
-      break;
-    case FILETYPE_NC4:
-      printf("  NetCDF4 data\n");
-      break;
-    case FILETYPE_NC4C:
-      printf("  NetCDF4 classic data\n");
-      break;
-    case FILETYPE_SRV:
-      printf("  SERVICE data\n");
-      switch ( streamInqByteorder(streamID) )
-	{
-	case CDI_BIGENDIAN:
-	  printf("  byteorder is BIGENDIAN\n"); break;
-	case CDI_LITTLEENDIAN:
-	  printf("  byteorder is LITTLEENDIAN\n"); break;
-	default:
-	  printf("  byteorder %d undefined\n", streamInqByteorder(streamID)); break;
-	}
-      break;
-    case FILETYPE_EXT:
-      printf("  EXTRA data\n");
-      switch ( streamInqByteorder(streamID) )
-	{
-	case CDI_BIGENDIAN:
-	  printf("  byteorder is BIGENDIAN\n"); break;
-	case CDI_LITTLEENDIAN:
-	  printf("  byteorder is LITTLEENDIAN\n"); break;
-	default:
-	  printf("  byteorder %d undefined\n", streamInqByteorder(streamID)); break;
-	}
-      break;
-    case FILETYPE_IEG:
-      printf("  IEG data\n");
-      switch ( streamInqByteorder(streamID) )
-	{
-	case CDI_BIGENDIAN:
-	  printf("  byteorder is BIGENDIAN\n"); break;
-	case CDI_LITTLEENDIAN:
-	  printf("  byteorder is LITTLEENDIAN\n"); break;
-	default:
-	  printf("  byteorder %d undefined\n", streamInqByteorder(streamID)); break;
-	}
-      break;
-    default:
-      printf("  unsupported filetype %d\n" , filetype);
-      break;
+    case CDI_FILETYPE_GRB:  printf("  GRIB data\n"); break;
+    case CDI_FILETYPE_GRB2: printf("  GRIB2 data\n"); break;
+    case CDI_FILETYPE_NC:   printf("  NetCDF data\n"); break;
+    case CDI_FILETYPE_NC2:  printf("  NetCDF2 data\n"); break;
+    case CDI_FILETYPE_NC4:  printf("  NetCDF4 data\n"); break;
+    case CDI_FILETYPE_NC4C: printf("  NetCDF4 classic data\n"); break;
+    case CDI_FILETYPE_SRV:  printf("  SERVICE data\n"); break;
+    case CDI_FILETYPE_EXT:  printf("  EXTRA data\n"); break;
+    case CDI_FILETYPE_IEG:  printf("  IEG data\n"); break;
+    default: printf("  unsupported filetype %d\n" , filetype);
     }
+
+  switch ( filetype )
+    {
+    case CDI_FILETYPE_SRV:
+    case CDI_FILETYPE_EXT:
+    case CDI_FILETYPE_IEG:
+      {
+        switch ( streamInqByteorder(streamID) )
+          {
+          case CDI_BIGENDIAN:    printf("  byteorder is BIGENDIAN\n"); break;
+          case CDI_LITTLEENDIAN: printf("  byteorder is LITTLEENDIAN\n"); break;
+          default:  printf("  byteorder %d undefined\n", streamInqByteorder(streamID)); break;
+          }
+       }
+    }  
   
   printf("\n");
 }
@@ -315,13 +286,6 @@ void filedes(int streamID)
 
 void *Filedes(void *argument)
 {
-  int operatorID;
-  int streamID = 0;
-  int zaxisID;
-  int nvars, ngrids, nzaxis;
-  int type, index;
-  int vlistID;
-
   cdoInitialize(argument);
 
   int GRIDDES  = cdoOperatorAdd("griddes",   0, 0, NULL);
@@ -336,57 +300,58 @@ void *Filedes(void *argument)
   int PARTAB   = cdoOperatorAdd("partab",    0, 0, NULL);
   int PARTAB2  = cdoOperatorAdd("partab2",   0, 0, NULL);
 
-  operatorID = cdoOperatorID();
+  int operatorID = cdoOperatorID();
 
-  streamID = streamOpenRead(cdoStreamName(0));
+  int streamID = streamOpenRead(cdoStreamName(0));
 
-  vlistID = streamInqVlist(streamID);
+  int vlistID = streamInqVlist(streamID);
 
-  nvars  = vlistNvars(vlistID);
-  ngrids = vlistNgrids(vlistID);
-  nzaxis = vlistNzaxis(vlistID);
+  int nvars  = vlistNvars(vlistID);
+  int ngrids = vlistNgrids(vlistID);
+  int nzaxis = vlistNzaxis(vlistID);
 
   if ( operatorID == GRIDDES || operatorID == GRIDDES2 )
     {
-      int opt = 0;
-      if ( operatorID == GRIDDES ) opt = 1;
-      for ( index = 0; index < ngrids; index++ )
-	gridPrint(vlistGrid(vlistID, index), index+1, opt);
+      int opt = (operatorID == GRIDDES) ? 1 : 0;
+      for ( int index = 0; index < ngrids; index++ )
+        {
+          printf("#\n" "# gridID %d\n" "#\n", index+1);
+          cdo_print_grid(vlistGrid(vlistID, index), opt);
+        }
     }
   else if ( operatorID == ZAXISDES )
     {
-      for ( index = 0; index < nzaxis; index++ )
-	zaxisPrint(vlistZaxis(vlistID, index), index+1);
+      for ( int index = 0; index < nzaxis; index++ )
+        {
+          printf("#\n" "# zaxisID %d\n" "#\n", index+1);
+          cdo_print_zaxis(vlistZaxis(vlistID, index));
+        }
     }
   else if ( operatorID == VCT || operatorID == VCT2 )
     {
-      for ( index = 0; index < nzaxis; index++)
+      for ( int index = 0; index < nzaxis; index++ )
 	{
-	  zaxisID = vlistZaxis(vlistID, index);
-	  type = zaxisInqType(zaxisID);
+	  int zaxisID = vlistZaxis(vlistID, index);
+	  int type = zaxisInqType(zaxisID);
 	  if ( type == ZAXIS_HYBRID || type == ZAXIS_HYBRID_HALF )
 	    {
-	      int i, vctsize;
-	      const double *vct;
-
-	      vctsize = zaxisInqVctSize(zaxisID);
-	      vct     = zaxisInqVctPtr(zaxisID);
+	      int vctsize = zaxisInqVctSize(zaxisID);
+	      const double *vct = zaxisInqVctPtr(zaxisID);
 		
 	      if ( vctsize%2 == 0 )
 		{
 		  if ( operatorID == VCT )
 		    {
 		      fprintf(stdout, "#   k         vct_a(k) [Pa]             vct_b(k) []\n");
-		      for ( i = 0; i < vctsize/2; i++ )
+		      for ( int i = 0; i < vctsize/2; i++ )
 			fprintf(stdout, "%5d %25.17f %25.17f\n", i, vct[i], vct[vctsize/2+i]);
 		    }
 		  else
 		    {
-		      int nbyte0, nbyte;
 		      fprintf(stdout, "vctsize   = %d\n", vctsize);
-		      nbyte0 = fprintf(stdout, "vct       = ");
-		      nbyte = nbyte0;
-		      for ( i = 0; i < vctsize; i++ )
+		      int nbyte0 = fprintf(stdout, "vct       = ");
+		      int nbyte = nbyte0;
+		      for ( int i = 0; i < vctsize; i++ )
 			{
 			  if ( nbyte > 70 || i == vctsize/2 )
 			    {
@@ -399,7 +364,7 @@ void *Filedes(void *argument)
 		    }
 		}
 	      else
-		for ( i = 0; i < vctsize; i++ )
+		for ( int i = 0; i < vctsize; i++ )
 		  fprintf(stdout, "%5d %25.17f\n", i, vct[i]);
 
 	      break;
@@ -412,23 +377,22 @@ void *Filedes(void *argument)
     }
   else if ( operatorID == CODETAB )
     {
-      int varID, code;
       char varname[CDI_MAX_NAME], varlongname[CDI_MAX_NAME], varunits[CDI_MAX_NAME];
 
-      for ( varID = 0; varID < nvars; varID++ )
+      for ( int varID = 0; varID < nvars; varID++ )
 	{
 	  varname[0]     = 0;
 	  varlongname[0] = 0;
 	  varunits[0]    = 0;
-	  code     = vlistInqVarCode(vlistID, varID);
+	  int code = vlistInqVarCode(vlistID, varID);
 	  vlistInqVarName(vlistID, varID, varname);
 	  vlistInqVarLongname(vlistID, varID, varlongname);
 	  vlistInqVarUnits(vlistID, varID, varunits);
 	  fprintf(stdout, "%4d  %-12s", code, varname);
-	  if ( strlen(varlongname) )
+	  if ( varlongname[0] )
 	    {
 	      fprintf(stdout, "  %s", varlongname);
-	      if ( strlen(varunits) )
+	      if ( varunits[0] )
 		fprintf(stdout, " [%s]", varunits);
 	    }
 	  fprintf(stdout, "\n");
diff --git a/src/Fillmiss.c b/src/Fillmiss.c
index 43a9334..2f940bf 100644
--- a/src/Fillmiss.c
+++ b/src/Fillmiss.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -32,7 +32,7 @@
 #include "clipping/geometry.h"
 
 
-void fillmiss(field_t *field1, field_t *field2, int nfill)
+void fillmiss(field_type *field1, field_type *field2, int nfill)
 {
   int nx, ny, i, j;
   int nmiss2 = 0;
@@ -147,7 +147,7 @@ void fillmiss(field_t *field1, field_t *field2, int nfill)
 }
 
 
-void fillmiss_one_step(field_t *field1, field_t *field2, int maxfill)
+void fillmiss_one_step(field_type *field1, field_type *field2, int maxfill)
 {
   int gridID, nx, ny, i, j;
   int nmiss2 = 0;
@@ -276,7 +276,7 @@ double nbr_compute_weights(unsigned num_neighbors, const int *restrict src_grid_
 unsigned nbr_normalize_weights(unsigned num_neighbors, double dist_tot, const int *restrict nbr_mask, int *restrict nbr_add, double *restrict nbr_dist);
 
 static
-void setmisstodis(field_t *field1, field_t *field2, int num_neighbors)
+void setmisstodis(field_type *field1, field_type *field2, int num_neighbors)
 {
   int gridID = field1->grid;
   int gridID0 = gridID;
@@ -413,8 +413,8 @@ void setmisstodis(field_t *field1, field_t *field2, int num_neighbors)
 void *Fillmiss(void *argument)
 {
   int nmiss;
-  int nrecs, recID, varID, levelID;
-  void (*fill_method) (field_t *fin , field_t *fout , int) = NULL;
+  int nrecs, varID, levelID;
+  void (*fill_method) (field_type *fin , field_type *fout , int) = NULL;
 
   cdoInitialize(argument);
 
@@ -476,7 +476,7 @@ void *Fillmiss(void *argument)
 
   int gridsize = vlistGridsizeMax(vlistID1);
 
-  field_t field1, field2;
+  field_type field1, field2;
   field_init(&field1);
   field_init(&field2);
   field1.ptr = (double*) Malloc(gridsize*sizeof(double));
@@ -489,7 +489,7 @@ void *Fillmiss(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, field1.ptr, &nmiss);
diff --git a/src/Filter.c b/src/Filter.c
index 2b4e055..71eec28 100644
--- a/src/Filter.c
+++ b/src/Filter.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -84,12 +84,11 @@ void filter_fftw(int nts, const int *fmasc, fftw_complex *fft_out, fftw_plan *p_
 static
 void filter_intrinsic(int nts, const int *fmasc, double *array1, double *array2)
 {  
-  int lpower2 = FALSE;
+  bool lpower2 = ((nts&(nts-1)) == 0);
+
   double *work_r = NULL;
   double *work_i = NULL;
 
-  if ( (nts&(nts-1)) == 0 ) lpower2 = TRUE;
-
   if ( !lpower2 )
     {
       work_r = (double*) Malloc(nts*sizeof(double));
@@ -122,18 +121,16 @@ void *Filter(void *argument)
   enum {BANDPASS, HIGHPASS, LOWPASS};
   const char *tunits[] = {"second", "minute", "hour", "day", "month", "year"};
   int iunits[] = {31536000, 525600, 8760, 365, 12, 1};
-  int gridsize;
   int nrecs;
-  int gridID, varID, levelID, recID;
+  int varID, levelID;
   int nalloc = 0;
   int nmiss;
-  int nlevel;
   int incperiod0, incunit0, incunit;
   int year0, month0, day0;
-  double fdata = 0;
-  field_t ***vars = NULL;
+  bool use_fftw = false;
   double fmin = 0, fmax = 0;
-  int use_fftw = FALSE;
+  double fdata = 0;
+  field_type ***vars = NULL;
   dtlist_type *dtlist = dtlist_new();
   typedef struct
   {
@@ -161,13 +158,13 @@ void *Filter(void *argument)
     {
 #if defined(HAVE_LIBFFTW3) 
       if ( cdoVerbose ) cdoPrint("Using fftw3 lib");
-      use_fftw = TRUE;
+      use_fftw = true;
 #else
       if ( cdoVerbose ) cdoPrint("LIBFFTW3 support not compiled in!");
 #endif
     }
       
-  if ( cdoVerbose && use_fftw  == FALSE ) cdoPrint("Using intrinsic FFT function!");
+  if ( cdoVerbose && !use_fftw ) cdoPrint("Using intrinsic FFT function!");
   
   int streamID1 = streamOpenRead(cdoStreamName(0));
 
@@ -188,18 +185,18 @@ void *Filter(void *argument)
       if ( tsID >= nalloc )
         {
           nalloc += NALLOC_INC;
-          vars   = (field_t ***) Realloc(vars, nalloc*sizeof(field_t **));
+          vars   = (field_type ***) Realloc(vars, nalloc*sizeof(field_type **));
         }
                        
       dtlist_taxisInqTimestep(dtlist, taxisID1, tsID);
    
       vars[tsID] = field_malloc(vlistID1, FIELD_NONE);
            
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
         {
           streamInqRecord(streamID1, &varID, &levelID);
-          gridID   = vlistInqVarGrid(vlistID1, varID);
-          gridsize = gridInqSize(gridID);
+          int gridID   = vlistInqVarGrid(vlistID1, varID);
+          int gridsize = gridInqSize(gridID);
           vars[tsID][varID][levelID].ptr = (double*) Malloc(gridsize*sizeof(double));
           streamReadRecord(streamID1, vars[tsID][varID][levelID].ptr, &nmiss);
           vars[tsID][varID][levelID].nmiss = nmiss;
@@ -309,25 +306,25 @@ void *Filter(void *argument)
   int *fmasc = (int*) Calloc(nts, sizeof(int));
   create_fmasc(nts, fdata, fmin, fmax, fmasc);
 
-  for ( varID = 0; varID < nvars; varID++ )
+  for ( int varID = 0; varID < nvars; varID++ )
     {
-      gridID   = vlistInqVarGrid(vlistID1, varID);
-      gridsize = gridInqSize(gridID);
-      nlevel   = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
+      int gridID   = vlistInqVarGrid(vlistID1, varID);
+      int gridsize = gridInqSize(gridID);
+      int nlevel   = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
       
-      for ( levelID = 0; levelID < nlevel; levelID++ )
+      for ( int levelID = 0; levelID < nlevel; levelID++ )
         {
           if ( use_fftw )
             {
 #if defined(HAVE_LIBFFTW3) 
 #if defined(_OPENMP)
-#pragma omp parallel for default(shared) private(tsID)
+#pragma omp parallel for default(shared)
 #endif
               for ( int i = 0; i < gridsize; i++ )
                 {
             	  int ompthID = cdo_omp_get_thread_num();
 
-                  for ( tsID = 0; tsID < nts; tsID++ )                              
+                  for ( int tsID = 0; tsID < nts; tsID++ )                              
                     {
                       ompmem[ompthID].in_fft[tsID][0] = vars[tsID][varID][levelID].ptr[i];
                       ompmem[ompthID].in_fft[tsID][1] = 0;
@@ -335,30 +332,28 @@ void *Filter(void *argument)
 
                   filter_fftw(nts, fmasc, ompmem[ompthID].out_fft, &ompmem[ompthID].p_T2S, &ompmem[ompthID].p_S2T);
                   
-                  for ( tsID = 0; tsID < nts; tsID++ )
-                    {
-                      vars[tsID][varID][levelID].ptr[i] = ompmem[ompthID].in_fft[tsID][0] / nts;  
-                    }
+                  for ( int tsID = 0; tsID < nts; tsID++ )
+                    vars[tsID][varID][levelID].ptr[i] = ompmem[ompthID].in_fft[tsID][0] / nts;  
                 }
 #endif
             }
           else
             {
 #if defined(_OPENMP)
-#pragma omp parallel for default(shared) private(tsID)
+#pragma omp parallel for default(shared)
 #endif
               for ( int i = 0; i < gridsize; i++ )  
                 {
             	  int ompthID = cdo_omp_get_thread_num();
 
-                  for ( tsID = 0; tsID < nts; tsID++ )
+                  for ( int tsID = 0; tsID < nts; tsID++ )
                     ompmem[ompthID].array1[tsID] = vars[tsID][varID][levelID].ptr[i];
 
                   memset(ompmem[ompthID].array2, 0, nts*sizeof(double));
 
                   filter_intrinsic(nts, fmasc, ompmem[ompthID].array1, ompmem[ompthID].array2);
 
-                  for ( tsID = 0; tsID < nts; tsID++ )
+                  for ( int tsID = 0; tsID < nts; tsID++ )
                     vars[tsID][varID][levelID].ptr[i] = ompmem[ompthID].array1[tsID];
                 }
             }
@@ -390,19 +385,19 @@ void *Filter(void *argument)
   
   streamDefVlist(streamID2, vlistID2);
  
-  for ( tsID = 0; tsID < nts; tsID++ )
+  for ( int tsID = 0; tsID < nts; tsID++ )
     {
       dtlist_taxisDefTimestep(dtlist, taxisID2, tsID);
       streamDefTimestep(streamID2, tsID);
     
-      for ( varID = 0; varID < nvars; varID++ )
+      for ( int varID = 0; varID < nvars; varID++ )
         {
-          nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
-          for ( levelID = 0; levelID < nlevel; levelID++ )
+          int nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
+          for ( int levelID = 0; levelID < nlevel; levelID++ )
             {
               if ( vars[tsID][varID][levelID].ptr )
                 {
-                  nmiss = vars[tsID][varID][levelID].nmiss;
+                  int nmiss = vars[tsID][varID][levelID].nmiss;
                   streamDefRecord(streamID2, varID, levelID);
                   streamWriteRecord(streamID2, vars[tsID][varID][levelID].ptr, nmiss);
 
diff --git a/src/Fldrms.c b/src/Fldrms.c
index 982c249..ab060e4 100644
--- a/src/Fldrms.c
+++ b/src/Fldrms.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -30,53 +30,45 @@
 
 void *Fldrms(void *argument)
 {
-  int streamID1, streamID2, streamID3;
-  int vlistID1, vlistID2, vlistID3;
-  int gridID1, gridID2, gridID3, lastgrid = -1;
-  int index, ngrids;
-  int recID, nrecs;
-  int tsID, varID, levelID;
-  int lim;
+  int lastgrid = -1;
+  int index;
+  int nrecs;
+  int varID, levelID;
   int nmiss;
-  int ndiffgrids;
-  int needWeights = FALSE;
-  double slon, slat;
   double sglval;
-  field_t field1, field2, field3;
-  int taxisID1, taxisID3;
 
   cdoInitialize(argument);
 
-  needWeights = TRUE;
+  bool needWeights = true;
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
-  streamID2 = streamOpenRead(cdoStreamName(1));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID2 = streamOpenRead(cdoStreamName(1));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = streamInqVlist(streamID2);
-  vlistID3 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = streamInqVlist(streamID2);
+  int vlistID3 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID3 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID3 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID3, taxisID3);
 
-  slon = 0;
-  slat = 0;
-  gridID3 = gridCreate(GRID_LONLAT, 1);
+  double slon = 0;
+  double slat = 0;
+  int gridID3 = gridCreate(GRID_LONLAT, 1);
   gridDefXsize(gridID3, 1);
   gridDefYsize(gridID3, 1);
   gridDefXvals(gridID3, &slon);
   gridDefYvals(gridID3, &slat);
 
-  ngrids = vlistNgrids(vlistID1);
-  ndiffgrids = 0;
+  int ngrids = vlistNgrids(vlistID1);
+  int ndiffgrids = 0;
   for ( index = 1; index < ngrids; index++ )
     if ( vlistGrid(vlistID1, 0) != vlistGrid(vlistID1, index))
       ndiffgrids++;
 
   index = 0;
-  gridID1 = vlistGrid(vlistID1, index);
-  gridID2 = vlistGrid(vlistID2, index);
+  int gridID1 = vlistGrid(vlistID1, index);
+  int gridID2 = vlistGrid(vlistID2, index);
 
   if ( gridInqSize(gridID1) != gridInqSize(gridID2) )
     cdoAbort("Fields have different grid size!");
@@ -91,15 +83,16 @@ void *Fldrms(void *argument)
 
   if ( ndiffgrids > 0 ) cdoAbort("Too many different grids!");
 
-  streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
+  int streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
 
   streamDefVlist(streamID3, vlistID3);
 
+  field_type field1, field2, field3;
   field_init(&field1);
   field_init(&field2);
   field_init(&field3);
 
-  lim = vlistGridsizeMax(vlistID1);
+  int lim = vlistGridsizeMax(vlistID1);
   field1.ptr    = (double*) Malloc(lim*sizeof(double));
   field1.weight = NULL;
   if ( needWeights )
@@ -111,7 +104,7 @@ void *Fldrms(void *argument)
   field3.ptr  = &sglval;
   field3.grid = gridID3;
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       nrecs = streamInqTimestep(streamID2, tsID);
@@ -120,7 +113,7 @@ void *Fldrms(void *argument)
 
       streamDefTimestep(streamID3, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, field1.ptr, &nmiss);
diff --git a/src/Fldstat.c b/src/Fldstat.c
index 69bc186..ef880d4 100644
--- a/src/Fldstat.c
+++ b/src/Fldstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -18,6 +18,7 @@
 /*
    This module contains the following operators:
 
+      Fldstat    fldrange        Field range (max-min)
       Fldstat    fldmin          Field minimum
       Fldstat    fldmax          Field maximum
       Fldstat    fldsum          Field sum
@@ -41,48 +42,42 @@ static
 void print_location_LL(int operfunc, int vlistID, int varID, int levelID, int gridID, double sglval, double *fieldptr,
 		       int vdate, int vtime)
 {
-  static int showHeader = TRUE;
-  int year, month, day, hour, minute, second;
-  int code;
-
-  code = vlistInqVarCode(vlistID, varID);
+  static bool showHeader = true;
+  int code = vlistInqVarCode(vlistID, varID);
 
+  int year, month, day, hour, minute, second;
   cdiDecodeDate(vdate, &year, &month, &day);
   cdiDecodeTime(vtime, &hour, &minute, &second);
 
   if ( gridInqType(gridID) == GRID_GAUSSIAN ||
        gridInqType(gridID) == GRID_LONLAT )
     {
-      int i = 0, j, nlon, nlat;
-      double level;
-      level = zaxisInqLevel(vlistInqVarZaxis(vlistID, varID), levelID);
-      nlon  = gridInqXsize(gridID);
-      nlat  = gridInqYsize(gridID);
-      for ( j = 0; j < nlat; ++j )
-	{
-	  for ( i = 0; i < nlon; ++i )
-	    {
-	      if ( DBL_IS_EQUAL(fieldptr[j*nlon+i], sglval) )
-		{
-		  double xval, yval;
-		  xval = gridInqXval(gridID,i);
-		  yval = gridInqYval(gridID,j);
-		  if ( showHeader )
-		    {
-		      if ( operfunc == func_min )
-			fprintf(stdout, "  Date     Time     Code  Level   Lon      Lat          Minval\n");
-		      else
-			fprintf(stdout, "  Date     Time     Code  Level   Lon      Lat          Maxval\n");
-		      
-		      showHeader = FALSE;
-		    }
+      int zaxisID = vlistInqVarZaxis(vlistID, varID);
+      double level = cdoZaxisInqLevel(zaxisID, levelID);
+      int nlon  = gridInqXsize(gridID);
+      int nlat  = gridInqYsize(gridID);
+      for ( int j = 0; j < nlat; ++j )
+        for ( int i = 0; i < nlon; ++i )
+          {
+            if ( DBL_IS_EQUAL(fieldptr[j*nlon+i], sglval) )
+              {
+                double xval, yval;
+                xval = gridInqXval(gridID,i);
+                yval = gridInqYval(gridID,j);
+                if ( showHeader )
+                  {
+                    if ( operfunc == func_min )
+                      fprintf(stdout, "  Date     Time     Code  Level   Lon      Lat          Minval\n");
+                    else
+                      fprintf(stdout, "  Date     Time     Code  Level   Lon      Lat          Maxval\n");
+                    
+                    showHeader = false;
+                  }
 		  
-		  fprintf(stdout, "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d %3d %7g %9.7g %9.7g %12.5g\n",
-			  year, month, day, hour, minute, second,
-			  code, level, xval, yval, sglval);
-		}
-	    }
-	}
+                fprintf(stdout, "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d %3d %7g %9.7g %9.7g %12.5g\n",
+                        year, month, day, hour, minute, second, code, level, xval, yval, sglval);
+              }
+          }
     }
 }
 
@@ -91,28 +86,29 @@ void *Fldstat(void *argument)
 {
   int gridID2, lastgrid = -1;
   int index;
-  int recID, nrecs;
+  int nrecs;
   int varID, levelID;
   int nmiss;
   double sglval;
-  field_t field;
+  field_type field;
 
   cdoInitialize(argument);
 
-  cdoOperatorAdd("fldmin",  func_min,  0, NULL);
-  cdoOperatorAdd("fldmax",  func_max,  0, NULL);
-  cdoOperatorAdd("fldsum",  func_sum,  0, NULL);
-  cdoOperatorAdd("fldmean", func_mean, 1, NULL);
-  cdoOperatorAdd("fldavg",  func_avg,  1, NULL);
-  cdoOperatorAdd("fldstd",  func_std,  1, NULL);
-  cdoOperatorAdd("fldstd1", func_std1, 1, NULL);
-  cdoOperatorAdd("fldvar",  func_var,  1, NULL);
-  cdoOperatorAdd("fldvar1", func_var1, 1, NULL);
-  cdoOperatorAdd("fldpctl", func_pctl, 0, NULL);
+  cdoOperatorAdd("fldrange", func_range, 0, NULL);
+  cdoOperatorAdd("fldmin",   func_min,   0, NULL);
+  cdoOperatorAdd("fldmax",   func_max,   0, NULL);
+  cdoOperatorAdd("fldsum",   func_sum,   0, NULL);
+  cdoOperatorAdd("fldmean",  func_mean,  1, NULL);
+  cdoOperatorAdd("fldavg",   func_avg,   1, NULL);
+  cdoOperatorAdd("fldstd",   func_std,   1, NULL);
+  cdoOperatorAdd("fldstd1",  func_std1,  1, NULL);
+  cdoOperatorAdd("fldvar",   func_var,   1, NULL);
+  cdoOperatorAdd("fldvar1",  func_var1,  1, NULL);
+  cdoOperatorAdd("fldpctl",  func_pctl,  0, NULL);
 
   int operatorID  = cdoOperatorID();
   int operfunc    = cdoOperatorF1(operatorID);
-  int needWeights = cdoOperatorF2(operatorID);
+  bool needWeights = cdoOperatorF2(operatorID) != 0;
 
   double pn = 0;
   if ( operfunc == func_pctl )
@@ -122,7 +118,7 @@ void *Fldstat(void *argument)
       percentile_check_number(pn);
     }
 
-  int useweights = TRUE;
+  bool useweights = true;
 
   if ( needWeights )
     {
@@ -135,7 +131,7 @@ void *Fldstat(void *argument)
 	    for ( unsigned i = 0; i < npar; i++ )
 	      cdoPrint("key %u = %s", i+1, parnames[i]);
 
-	  if ( strcmp(parnames[0], "noweights") == 0 ) useweights = FALSE;
+	  if ( strcmp(parnames[0], "noweights") == 0 ) useweights = false;
 	  else cdoAbort("Parameter >%s< unsupported! Supported parameter are: noweights", parnames[0]);
 	}
     }
@@ -207,7 +203,7 @@ void *Fldstat(void *argument)
             }
         }
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, field.ptr, &nmiss);
@@ -222,7 +218,7 @@ void *Fldstat(void *argument)
 	      field.weight[0] = 1;
 	      if ( useweights && field.size > 1 )
 		{
-		  int wstatus = gridWeights(field.grid, field.weight);
+		  bool wstatus = gridWeights(field.grid, field.weight) != 0;
 		  if ( wstatus && tsID == 0 && levelID == 0 )
 		    {
 		      char varname[CDI_MAX_NAME];
diff --git a/src/Fldstat2.c b/src/Fldstat2.c
index b644138..4a16abe 100644
--- a/src/Fldstat2.c
+++ b/src/Fldstat2.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -35,14 +35,11 @@ static
 double correlation_s(const double * restrict in0, const double * restrict in1,
 		     const double * restrict weight, double missval1, double missval2, long gridsize)
 {
-  long i;
   double sum0, sum1, sum00, sum01, sum11, wsum0;
-  double out;
-
   sum0 = sum1 = sum00 = sum01 = sum11 = 0;
   wsum0 = 0;
 	
-  for ( i = 0; i < gridsize; ++i )
+  for ( long i = 0; i < gridsize; ++i )
     {
       if ( IS_NOT_EQUAL(weight[i], missval1) && IS_NOT_EQUAL(in0[i], missval1) && IS_NOT_EQUAL(in1[i], missval2) )
 	    {
@@ -55,12 +52,12 @@ double correlation_s(const double * restrict in0, const double * restrict in1,
 	    }
     }
 
-  out = IS_NOT_EQUAL(wsum0, 0) ?
-        DIVMN((sum01 * wsum0 - sum0 * sum1),
-	     SQRTMN((sum00 * wsum0 - sum0 * sum0) *
-	          (sum11 * wsum0 - sum1 * sum1))) : missval1;
+  double out = IS_NOT_EQUAL(wsum0, 0) ?
+               DIVMN((sum01 * wsum0 - sum0 * sum1),
+	            SQRTMN((sum00 * wsum0 - sum0 * sum0) *
+	                 (sum11 * wsum0 - sum1 * sum1))) : missval1;
 
-  return (out);
+  return out;
 }
 
 /* covariance in space */
@@ -68,14 +65,11 @@ static
 double covariance_s(const double * restrict in0, const double * restrict in1,
 		    const double * restrict weight, double missval1, double missval2, long gridsize)
 {
-  long i;
   double sum0, sum1, sum01, wsum0, wsum00;
-  double out;
-
   sum0 = sum1 = sum01 = 0;
   wsum0 = wsum00 = 0;
 
-  for ( i = 0; i < gridsize; ++i )
+  for ( long i = 0; i < gridsize; ++i )
     {
       if ( IS_NOT_EQUAL(weight[i], missval1) && IS_NOT_EQUAL(in0[i], missval1) && IS_NOT_EQUAL(in1[i], missval2) )
 	{
@@ -87,10 +81,10 @@ double covariance_s(const double * restrict in0, const double * restrict in1,
 	}
     }
 
-  out = IS_NOT_EQUAL(wsum0, 0) ?
-        (sum01 * wsum0 - sum0 * sum1) / (wsum0 * wsum0) : missval1;
+  double out = IS_NOT_EQUAL(wsum0, 0) ?
+               (sum01 * wsum0 - sum0 * sum1) / (wsum0 * wsum0) : missval1;
 
-  return (out);
+  return out;
 }
 
 
@@ -98,12 +92,12 @@ void *Fldstat2(void *argument)
 {
   int gridID, lastgridID = -1;
   int gridID3;
-  int wstatus = FALSE;
   int index;
-  int recID, nrecs, nrecs2;
+  int nrecs, nrecs2;
   int varID, levelID;
-  int needWeights = TRUE;
   int nmiss1, nmiss2, nmiss3;
+  bool wstatus = false;
+  bool needWeights = true;
   double missval1, missval2;
   double sglval = 0;
   char varname[CDI_MAX_NAME];
@@ -178,7 +172,7 @@ void *Fldstat2(void *argument)
 
       streamDefTimestep(streamID3, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamInqRecord(streamID2, &varID, &levelID);
@@ -190,9 +184,9 @@ void *Fldstat2(void *argument)
 	  if ( needWeights && gridID != lastgridID )
 	    {
 	      lastgridID = gridID;
-	      wstatus = gridWeights(gridID, weight);
+	      wstatus = gridWeights(gridID, weight) != 0;
 	    }
-	  if ( wstatus != 0 && tsID == 0 && levelID == 0 )
+	  if ( wstatus && tsID == 0 && levelID == 0 )
 	    {
 	      vlistInqVarName(vlistID1, varID, varname);
 	      cdoWarning("Using constant grid cell area weights for variable %s!", varname);
diff --git a/src/Fourier.c b/src/Fourier.c
index c160373..69ceacb 100644
--- a/src/Fourier.c
+++ b/src/Fourier.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -28,20 +28,16 @@
 
 void *Fourier(void *argument)
 {
-  int bit, sign;
+  int bit;
   int gridsize;
   int nrecs;
-  int gridID, varID, levelID, recID;
-  int tsID;
-  int nts;
+  int gridID, varID, levelID;
   int nalloc = 0;
-  int streamID1, streamID2;
-  int vlistID1, vlistID2, taxisID1, taxisID2;
   int nmiss;
-  int nvars, nlevel;
+  int nlevel;
   int *vdate = NULL, *vtime = NULL;
   double missval;
-  field_t ***vars = NULL;
+  field_type ***vars = NULL;
   typedef struct
   {
     double *real;
@@ -49,30 +45,29 @@ void *Fourier(void *argument)
     double *work_r;
     double *work_i;
   } memory_t;
-  memory_t *ompmem = NULL;
 
 
   cdoInitialize(argument);
 
   operatorInputArg("the sign of the exponent (-1 for normal or 1 for reverse transformation)!");
-  sign = parameter2int(operatorArgv()[0]);
+  int sign = parameter2int(operatorArgv()[0]);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  nvars = vlistNvars(vlistID1);
+  int nvars = vlistNvars(vlistID1);
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       if ( tsID >= nalloc )
@@ -80,7 +75,7 @@ void *Fourier(void *argument)
 	  nalloc += NALLOC_INC;
 	  vdate = (int*) Realloc(vdate, nalloc*sizeof(int));
 	  vtime = (int*) Realloc(vtime, nalloc*sizeof(int));
-	  vars  = (field_t ***) Realloc(vars, nalloc*sizeof(field_t **));
+	  vars  = (field_type ***) Realloc(vars, nalloc*sizeof(field_type **));
 	}
 
       vdate[tsID] = taxisInqVdate(taxisID1);
@@ -88,7 +83,7 @@ void *Fourier(void *argument)
 
       vars[tsID] = field_malloc(vlistID1, FIELD_NONE);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  gridID   = vlistInqVarGrid(vlistID1, varID);
@@ -101,11 +96,11 @@ void *Fourier(void *argument)
       tsID++;
     }
 
-  nts = tsID;
+  int nts = tsID;
 
   for ( bit = nts; !(bit & 1); bit >>= 1 );
 
-  ompmem = (memory_t*) Malloc(ompNumThreads*sizeof(memory_t));
+  memory_t *ompmem = (memory_t*) Malloc(ompNumThreads*sizeof(memory_t));
   for ( int i = 0; i < ompNumThreads; i++ )
     {
       ompmem[i].real = (double*) Malloc(nts*sizeof(double));
diff --git a/src/Gengrid.c b/src/Gengrid.c
index 31cc633..16a74a9 100644
--- a/src/Gengrid.c
+++ b/src/Gengrid.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -29,55 +29,45 @@
 
 void *Gengrid(void *argument)
 {
-  int streamID1, streamID2, streamID3;
-  int vlistID1, vlistID2, vlistID3;
-  int gridID1, gridID2, gridID3;
-  int zaxisID3;
-  int datatype;
-  int tsID, varID, levelID;
-  int gridsize, i;
-  int xsize, ysize;
+  int varID, levelID;
   int nmiss1, nmiss2;
-  int taxisID3;
-  double *array1, *array2, *array3;
   double missval = 0;
-  double xminval, xmaxval, yminval, ymaxval;
 
   cdoInitialize(argument);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
-  streamID2 = streamOpenRead(cdoStreamName(1));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID2 = streamOpenRead(cdoStreamName(1));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = streamInqVlist(streamID2);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = streamInqVlist(streamID2);
 
-  gridID1 = vlistGrid(vlistID1, 0);
-  gridID2 = vlistGrid(vlistID2, 0);
+  int gridID1 = vlistGrid(vlistID1, 0);
+  int gridID2 = vlistGrid(vlistID2, 0);
 
   if ( gridInqSize(gridID1) != gridInqSize(gridID2) )
     cdoAbort("Arrays have different grid size!");
 
-  gridsize = gridInqSize(gridID1);
-  xsize = gridInqXsize(gridID1);
-  ysize = gridInqYsize(gridID1);
+  int gridsize = gridInqSize(gridID1);
+  int xsize = gridInqXsize(gridID1);
+  int ysize = gridInqYsize(gridID1);
 
-  array1 = (double*) Malloc(gridsize*sizeof(double));
-  array2 = (double*) Malloc(gridsize*sizeof(double));
-  array3 = (double*) Malloc(gridsize*sizeof(double));
+  double *array1 = (double*) Malloc(gridsize*sizeof(double));
+  double *array2 = (double*) Malloc(gridsize*sizeof(double));
+  double *array3 = (double*) Malloc(gridsize*sizeof(double));
 
   streamInqRecord(streamID1, &varID, &levelID);
   streamReadRecord(streamID1, array1, &nmiss1);
   streamInqRecord(streamID2, &varID, &levelID);
   streamReadRecord(streamID2, array2, &nmiss2);
 
-  datatype = vlistInqVarDatatype(vlistID1, 0);
+  int datatype = vlistInqVarDatatype(vlistID1, 0);
 
   streamClose(streamID2);
   streamClose(streamID1);
 
   if ( nmiss1 || nmiss2 ) cdoAbort("Missing values unsupported!");
 
-  gridID3 = gridCreate(GRID_CURVILINEAR, gridsize);
+  int gridID3 = gridCreate(GRID_CURVILINEAR, gridsize);
 
   if ( cdoVerbose ) cdoPrint("xsize %d  ysize %d", xsize, ysize);
   if ( xsize*ysize != gridsize )
@@ -88,16 +78,16 @@ void *Gengrid(void *argument)
   gridDefXvals(gridID3, array1);
   gridDefYvals(gridID3, array2);
 
-  if ( datatype == DATATYPE_FLT64 )
-    gridDefPrec(gridID3, DATATYPE_FLT64);
+  if ( datatype == CDI_DATATYPE_FLT64 )
+    gridDefPrec(gridID3, CDI_DATATYPE_FLT64);
   else
-    gridDefPrec(gridID3, DATATYPE_FLT32);
+    gridDefPrec(gridID3, CDI_DATATYPE_FLT32);
 
-  xminval = array1[0];
-  xmaxval = array1[0];
-  yminval = array2[0];
-  ymaxval = array2[0];
-  for ( i = 1; i < gridsize; ++i )
+  double xminval = array1[0];
+  double xmaxval = array1[0];
+  double yminval = array2[0];
+  double ymaxval = array2[0];
+  for ( int i = 1; i < gridsize; ++i )
     {
       if ( array1[i] < xminval ) xminval = array1[i];
       if ( array1[i] > xmaxval ) xmaxval = array1[i];
@@ -124,26 +114,26 @@ void *Gengrid(void *argument)
       cdoAbort("Units undefined!");
     }
 
-  zaxisID3 = zaxisCreate(ZAXIS_SURFACE, 1);
+  int zaxisID3 = zaxisCreate(ZAXIS_SURFACE, 1);
 
-  vlistID3 = vlistCreate();
+  int vlistID3 = vlistCreate();
   vlistDefVar(vlistID3, gridID3, zaxisID3, TSTEP_CONSTANT);
   vlistDefVarMissval(vlistID3, 0, missval);
   vlistDefVarName(vlistID3, 0, "dummy");
-  vlistDefVarDatatype(vlistID3, 0, DATATYPE_INT8);
+  vlistDefVarDatatype(vlistID3, 0, CDI_DATATYPE_INT8);
 
-  taxisID3 = taxisCreate(TAXIS_ABSOLUTE);
+  int taxisID3 = taxisCreate(TAXIS_ABSOLUTE);
 
   vlistDefTaxis(vlistID3, taxisID3);
 
-  streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
+  int streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
 
   streamDefVlist(streamID3, vlistID3);
 
-  tsID = 0;
+  int tsID = 0;
   streamDefTimestep(streamID3, tsID);
 
-  for ( i = 0; i < gridsize; ++i ) array3[i] = missval;
+  for ( int i = 0; i < gridsize; ++i ) array3[i] = missval;
 
   streamDefRecord(streamID3, 0, 0);
   streamWriteRecord(streamID3, array3, gridsize);
diff --git a/src/Gradsdes.c b/src/Gradsdes.c
index fce7bdb..57ff45c 100644
--- a/src/Gradsdes.c
+++ b/src/Gradsdes.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -29,8 +29,8 @@
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
-#include "pstream.h"
 #include "grid.h"
+#include "pstream.h"
 
 
 /*
@@ -405,7 +405,7 @@ void dumpmap()
 }
 
 static
-void ctl_xydef(FILE *gdp, int gridID, int *yrev)
+void ctl_xydef(FILE *gdp, int gridID, bool *yrev)
 {
   int gridtype;
   int i, j;
@@ -413,7 +413,7 @@ void ctl_xydef(FILE *gdp, int gridID, int *yrev)
   double xfirst, yfirst, xinc, yinc;
   double *xvals, *yvals;
 
-  *yrev = FALSE;
+  *yrev = false;
 
   xsize  = gridInqXsize(gridID);
   ysize  = gridInqYsize(gridID);
@@ -431,7 +431,7 @@ void ctl_xydef(FILE *gdp, int gridID, int *yrev)
       int nx, ny, ni;
       double inc[] = { 1, 0.5, 0.2, 0.1, 0.05, 0.02, 0.01, 0.005, 0.002, 0.001 };
 
-      gridInqLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
+      gridInqParamLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
                  &projflag, &scanflag);
       fprintf(gdp, "PDEF %d %d LCCR %g %g 1 1 %g %g %g %g %g\n",
               xsize, ysize, originLat, originLon, lat1, lat2, lonParY, xincm, yincm);
@@ -521,7 +521,7 @@ void ctl_xydef(FILE *gdp, int gridID, int *yrev)
           j = 0;
           if ( yvals[0] > yvals[ysize-1] )
             {
-              *yrev = TRUE;
+              *yrev = true;
               for ( i = ysize-1; i >= 0; i-- )
                 {
                   fprintf(gdp, "%7.3f ", yvals[i]);
@@ -558,7 +558,7 @@ void ctl_xydef(FILE *gdp, int gridID, int *yrev)
           if ( IS_EQUAL(yinc, 0) ) yinc = 180.0/ysize;
           if ( yinc < 0)
             {
-              *yrev = TRUE;
+              *yrev = true;
               fprintf(gdp, "YDEF %d LINEAR %f %f\n", ysize, yfirst + yinc * (ysize-1 ), -yinc);
             }
           else
@@ -568,18 +568,17 @@ void ctl_xydef(FILE *gdp, int gridID, int *yrev)
 }
 
 static
-void ctl_zdef(FILE *gdp, int vlistID, int *zrev)
+void ctl_zdef(FILE *gdp, int vlistID, bool *zrev)
 {
   int i, j, index;
-  int zaxisIDmax = -1, nlevmax;
-  int nzaxis, zaxisID, nlev;
-  int lplev = FALSE;
-  double *levels, level0, levinc = 0;
+  int zaxisIDmax = -1;
+  int zaxisID, nlev;
+  double levinc = 0;
 
-  *zrev = FALSE;
-  nzaxis  = vlistNzaxis(vlistID);
+  *zrev = false;
+  int nzaxis  = vlistNzaxis(vlistID);
 
-  nlevmax = 0;
+  int nlevmax = 0;
   for ( index = 0; index < nzaxis; index++ )
     {
       zaxisID = vlistZaxis(vlistID, index);
@@ -591,18 +590,18 @@ void ctl_zdef(FILE *gdp, int vlistID, int *zrev)
         }
     }
 
-  levels = (double*) Malloc(nlevmax*sizeof(double));
-  zaxisInqLevels(zaxisIDmax, levels);
-  if ( zaxisInqType(zaxisIDmax) == ZAXIS_PRESSURE ) lplev = TRUE;
-  level0 = levels[0];
+  double *levels = (double*) Malloc(nlevmax*sizeof(double));
+  cdoZaxisInqLevels(zaxisIDmax, levels);
+  bool lplev = (zaxisInqType(zaxisIDmax) == ZAXIS_PRESSURE);
+  double level0 = levels[0];
   if ( nlevmax > 1 )
     {
       if ( levels[0] < levels[1] && zaxisInqType(zaxisIDmax) != ZAXIS_HYBRID )
-        *zrev = TRUE;
+        *zrev = true;
 
       levinc = levels[1] - levels[0];
 
-      if ( IS_EQUAL(levinc, 1) ) *zrev = FALSE;
+      if ( IS_EQUAL(levinc, 1) ) *zrev = false;
 
       for ( i = 1; i < nlevmax; i++ )
         {
@@ -659,9 +658,9 @@ void ctl_zdef(FILE *gdp, int vlistID, int *zrev)
 }
 
 static
-void ctl_options(FILE *gdp, int yrev, int zrev, int sequential, int bigendian, int littleendian, int flt64, int cal365day)
+void ctl_options(FILE *gdp, bool yrev, bool zrev, bool sequential, bool bigendian, bool littleendian, bool flt64, bool cal365day)
 {
-  /* if ( filetype == FILETYPE_GRB ) zrev = FALSE; */
+  /* if ( filetype == CDI_FILETYPE_GRB ) zrev = false; */
 
   if ( yrev || zrev || sequential || bigendian || littleendian || flt64 )
     {
@@ -722,7 +721,7 @@ void ctl_vars(FILE *gdp, int filetype, int vlistID, int nvarsout, int *vars)
 
           fprintf(gdp, "  %3d", nlev);
 
-          if ( filetype == FILETYPE_GRB )
+          if ( filetype == CDI_FILETYPE_GRB )
             {
               code = vlistInqVarCode(vlistID, varID);
               /*
@@ -733,7 +732,7 @@ void ctl_vars(FILE *gdp, int filetype, int vlistID, int nvarsout, int *vars)
               */
               fprintf(gdp, "  %d,%d", code, ltype);
             }
-          else if ( filetype == FILETYPE_NC )
+          else if ( filetype == CDI_FILETYPE_NC )
             {
               int xyz = vlistInqVarXYZ(vlistID, varID);
 
@@ -945,19 +944,18 @@ void *Gradsdes(void *argument)
   int gridtype = -1;
   int index;
   int varID;
-  int recID, levelID;
+  int levelID;
   int nrecs;
   int vdate, vtime;
   char *idxfile = NULL;
   char varname[CDI_MAX_NAME];
-  int yrev = FALSE;
-  int zrev = FALSE;
+  bool yrev = false;
+  bool zrev = false;
   int xyheader = 0;
   int nrecords = 0;
-  int bigendian = FALSE, littleendian = FALSE;
-  int flt64 = 0;
-  int cal365day = 0;
-  int sequential = FALSE;
+  bool bigendian = false, littleendian = false;
+  bool sequential = false;
+  bool flt64 = false;
   char Time[30], Incr[10] = {"1mn"};
   const char *IncrKey[] = {"mn","hr","dy","mo","yr"};
   int isd, imn, ihh, iyy, imm, idd;
@@ -1032,17 +1030,17 @@ void *Gradsdes(void *argument)
   int filetype  = streamInqFiletype(streamID);
   int byteorder = streamInqByteorder(streamID);
 
-  if ( filetype == FILETYPE_NC2 || filetype == FILETYPE_NC4 ) filetype = FILETYPE_NC;
+  if ( filetype == CDI_FILETYPE_NC2 || filetype == CDI_FILETYPE_NC4 ) filetype = CDI_FILETYPE_NC;
 
-  if ( filetype != FILETYPE_SRV &&
-       filetype != FILETYPE_EXT &&
-       filetype != FILETYPE_IEG &&
-       filetype != FILETYPE_GRB )
+  if ( filetype != CDI_FILETYPE_SRV &&
+       filetype != CDI_FILETYPE_EXT &&
+       filetype != CDI_FILETYPE_IEG &&
+       filetype != CDI_FILETYPE_GRB )
     {
-      if ( filetype == FILETYPE_NC )
+      if ( filetype == CDI_FILETYPE_NC )
         //        cdoAbort("Unsupported file format: NetCDF");
         ;
-      else if ( filetype == FILETYPE_GRB2 )
+      else if ( filetype == CDI_FILETYPE_GRB2 )
         //cdoAbort("Unsupported file format: GRIB2");
         ;
       else
@@ -1071,12 +1069,12 @@ void *Gradsdes(void *argument)
     {
       if ( vlistInqVarGrid(vlistID, varID) == gridID )
         {
-          if ( filetype == FILETYPE_SRV ||
-               filetype == FILETYPE_EXT ||
-               filetype == FILETYPE_IEG )
+          if ( filetype == CDI_FILETYPE_SRV ||
+               filetype == CDI_FILETYPE_EXT ||
+               filetype == CDI_FILETYPE_IEG )
             {
               prec = vlistInqVarDatatype(vlistID, varID);
-              if ( prec == DATATYPE_FLT64 ) flt64 = 1;
+              if ( prec == CDI_DATATYPE_FLT64 ) flt64 = true;
             }
           vars[varID] = TRUE;
           recoffset[varID] = nrecsout;
@@ -1095,34 +1093,34 @@ void *Gradsdes(void *argument)
         }
     }
 
-  if ( filetype != FILETYPE_GRB && nvars != nvarsout )
+  if ( filetype != CDI_FILETYPE_GRB && nvars != nvarsout )
     cdoAbort("Too many different grids!");
 
-  if ( filetype == FILETYPE_SRV )
+  if ( filetype == CDI_FILETYPE_SRV )
     {
       xyheader = 40;
       if ( flt64 ) xyheader = 72;
-      sequential = TRUE;
-      if ( byteorder == CDI_BIGENDIAN )    bigendian = TRUE;
-      if ( byteorder == CDI_LITTLEENDIAN ) littleendian = TRUE;
+      sequential = true;
+      if ( byteorder == CDI_BIGENDIAN )    bigendian = true;
+      if ( byteorder == CDI_LITTLEENDIAN ) littleendian = true;
     }
 
-  if ( filetype == FILETYPE_EXT )
+  if ( filetype == CDI_FILETYPE_EXT )
     {
       xyheader = 24;
       if ( flt64 ) xyheader = 40;
-      sequential = TRUE;
-      if ( byteorder == CDI_BIGENDIAN )    bigendian = TRUE;
-      if ( byteorder == CDI_LITTLEENDIAN ) littleendian = TRUE;
+      sequential = true;
+      if ( byteorder == CDI_BIGENDIAN )    bigendian = true;
+      if ( byteorder == CDI_LITTLEENDIAN ) littleendian = true;
     }
 
-  if ( filetype == FILETYPE_IEG )
+  if ( filetype == CDI_FILETYPE_IEG )
     {
       xyheader = 644;
       if ( flt64 ) xyheader = 1048;
-      sequential = TRUE;
-      if ( byteorder == CDI_BIGENDIAN )    bigendian = TRUE;
-      if ( byteorder == CDI_LITTLEENDIAN ) littleendian = TRUE;
+      sequential = true;
+      if ( byteorder == CDI_BIGENDIAN )    bigendian = true;
+      if ( byteorder == CDI_LITTLEENDIAN ) littleendian = true;
     }
 
   /* ctl file name */
@@ -1156,19 +1154,19 @@ void *Gradsdes(void *argument)
    * DTYPE Print file type
    * INDEX Print filename of the control/index file .ctl/.idx
    */
-  if ( filetype == FILETYPE_GRB ||  filetype == FILETYPE_GRB2 )
+  if ( filetype == CDI_FILETYPE_GRB ||  filetype == CDI_FILETYPE_GRB2 )
     {
       idxfile = strdup(ctlfile);
       char *pidxfile = idxfile;
 
       // print GRIB[12] file type
       // generate the index file
-      if ( filetype == FILETYPE_GRB )
+      if ( filetype == CDI_FILETYPE_GRB )
         {
           fprintf(gdp, "DTYPE  GRIB\n");
           repl_filetypeext(idxfile, ".ctl", ".gmp");
         }
-      else if ( filetype == FILETYPE_GRB2 )
+      else if ( filetype == CDI_FILETYPE_GRB2 )
         {
           fprintf(gdp, "DTYPE  GRIB2\n");
           repl_filetypeext(pidxfile, ".ctl", ".idx");
@@ -1188,7 +1186,7 @@ void *Gradsdes(void *argument)
       gridsize = vlistGridsizeMax(vlistID);
       array = (double*) Malloc(gridsize*sizeof(double));
     }
-  else if ( filetype == FILETYPE_NC )
+  else if ( filetype == CDI_FILETYPE_NC )
     {
       fprintf(gdp, "DTYPE  NetCDF\n");
     }
@@ -1200,7 +1198,7 @@ void *Gradsdes(void *argument)
 
   int taxisID = vlistInqTaxis(vlistID);
 
-  if ( taxisInqCalendar(taxisID) == CALENDAR_365DAYS ) cal365day = 1;
+  bool cal365day = (taxisInqCalendar(taxisID) == CALENDAR_365DAYS);
 
   int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID, tsID)) )
@@ -1296,7 +1294,7 @@ void *Gradsdes(void *argument)
           iyys = iyy;
         }
 
-      if ( filetype == FILETYPE_GRB )
+      if ( filetype == CDI_FILETYPE_GRB )
         {
           nrecords += nrecsout;
           if ( nrecords >= maxrecs )
@@ -1307,7 +1305,7 @@ void *Gradsdes(void *argument)
               bignum = (off_t*) Realloc(bignum, 2*maxrecs*sizeof(off_t));
             }
 
-          for ( recID = 0; recID < nrecs; recID++ )
+          for ( int recID = 0; recID < nrecs; recID++ )
             {
               streamInqRecord(streamID, &varID, &levelID);
               if ( vars[varID] == TRUE )
@@ -1358,18 +1356,18 @@ void *Gradsdes(void *argument)
         }
     }
 
-  sprintf(Time, "%02d:%02dZ%02d%s%04d", ihh0, imn0, idd0, cmons[imm0-1], iyy0);
-  sprintf(Incr, "%d%s", dt, IncrKey[iik]);
+  snprintf(Time, sizeof(Time), "%02d:%02dZ%02d%s%04d", ihh0, imn0, idd0, cmons[imm0-1], iyy0);
+  snprintf(Incr, sizeof(Incr), "%d%s", dt, IncrKey[iik]);
 
   fprintf(gdp, "TDEF %d LINEAR %s %s\n", tsID, Time, Incr);
 
   /* TITLE */
 
-  int xsize  = gridInqXsize(gridID);
-  int ysize  = gridInqYsize(gridID);
+  int xsize = gridInqXsize(gridID);
+  int ysize = gridInqYsize(gridID);
 
   int res = 0;
-  if ( gridtype == GRID_GAUSSIAN ) res = nlat2ntr(ysize);
+  if ( gridtype == GRID_GAUSSIAN ) res = nlat_to_ntr(ysize);
 
   if ( res )
     fprintf(gdp, "TITLE  %s  T%d grid\n", datfile, res);
@@ -1387,11 +1385,11 @@ void *Gradsdes(void *argument)
 
 
   /* INDEX file */
-  if ( filetype == FILETYPE_GRB )
+  if ( filetype == CDI_FILETYPE_GRB )
     {
       write_map_grib1(idxfile, map_version, nrecords, intnum, fltnum, bignum);
     }
-  if ( filetype == FILETYPE_GRB2 )
+  if ( filetype == CDI_FILETYPE_GRB2 )
     {
       cdoAbort("The fileformat GRIB2 is not fully supported yet for the gradsdes operator.\n"
                "The .ctl file %s was generated. You can add the necessary .idx file by running\n\tgribmap -i %s", ctlfile, ctlfile);
diff --git a/src/Gridboxstat.c b/src/Gridboxstat.c
index 76b84d0..92b5578 100644
--- a/src/Gridboxstat.c
+++ b/src/Gridboxstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -41,24 +41,22 @@ static
 int genBoxGrid(int gridID1, int xinc, int yinc)
 {
   int i, j, i1;
-  int gridID2 = -1, gridtype;
-  int gridsize1 = 0, nlon1 = 0, nlat1 = 0;
+  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;
   int circular = gridIsCircular(gridID1) ;
-  int gridHasBounds = FALSE;
-  double *xvals1, *yvals1, *xvals2, *yvals2;
   double *grid1_corner_lon = NULL, *grid1_corner_lat = NULL;
   double *grid2_corner_lon = NULL, *grid2_corner_lat = NULL;
   double on_up, on_lo, ox_up, ox_lo, an_le, an_ri, ax_le, ax_ri;
   double xvals2_0 = 0;
   double area_norm;  
 
-  gridtype  = gridInqType(gridID1);
-  gridsize1 = gridInqSize(gridID1);
+  int gridtype  = gridInqType(gridID1);
+  int gridsize1 = gridInqSize(gridID1);
 
   if ( xinc < 1 || yinc < 1 )
     cdoAbort("xinc and yinc must not be smaller than 1!");
@@ -90,13 +88,12 @@ int genBoxGrid(int gridID1, int xinc, int yinc)
   
   if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_LONLAT )
     {
-      if ( gridInqXbounds(gridID1, NULL) && gridInqYbounds(gridID1, NULL) )
-        gridHasBounds = TRUE;
+      bool gridHasBounds = (gridInqXbounds(gridID1, NULL) && gridInqYbounds(gridID1, NULL));
 
-      xvals1 = (double*) Malloc(nlon1*sizeof(double));
-      yvals1 = (double*) Malloc(nlat1*sizeof(double));
-      xvals2 = (double*) Malloc(nlon2*sizeof(double));
-      yvals2 = (double*) Malloc(nlat2*sizeof(double));
+      double *xvals1 = (double*) Malloc(nlon1*sizeof(double));
+      double *yvals1 = (double*) Malloc(nlat1*sizeof(double));
+      double *xvals2 = (double*) Malloc(nlon2*sizeof(double));
+      double *yvals2 = (double*) Malloc(nlat2*sizeof(double));
       gridInqXvals(gridID1, xvals1);
       gridInqYvals(gridID1, yvals1);
 
@@ -163,14 +160,12 @@ int genBoxGrid(int gridID1, int xinc, int yinc)
     }
   else if ( gridtype == GRID_CURVILINEAR )
     {
+      bool gridHasBounds = (gridInqXbounds(gridID1, NULL) && gridInqYbounds(gridID1, NULL));
       
-      if ( gridInqXbounds(gridID1, NULL) && gridInqYbounds(gridID1, NULL) )
-        gridHasBounds = TRUE;
-      
-      xvals1 = (double*) Malloc(nlon1*nlat1*sizeof(double));
-      yvals1 = (double*) Malloc(nlon1*nlat1*sizeof(double));
-      xvals2 = (double*) Malloc(nlon2*nlat2*sizeof(double));
-      yvals2 = (double*) Malloc(nlon2*nlat2*sizeof(double));
+      double *xvals1 = (double*) Malloc(nlon1*nlat1*sizeof(double));
+      double *yvals1 = (double*) Malloc(nlon1*nlat1*sizeof(double));
+      double *xvals2 = (double*) Malloc(nlon2*nlat2*sizeof(double));
+      double *yvals2 = (double*) Malloc(nlon2*nlat2*sizeof(double));
       gridInqXvals(gridID1, xvals1);
       gridInqYvals(gridID1, yvals1);
 
@@ -450,30 +445,19 @@ int genBoxGrid(int gridID1, int xinc, int yinc)
 }
 
 static
-void gridboxstat(field_t *field1, field_t *field2, int xinc, int yinc, int statfunc)
+void gridboxstat(field_type *field1, field_type *field2, int xinc, int yinc, int statfunc)
 {
-  int nlon1, nlat1;
-  int nlon2, nlat2;
-  int ilat, ilon;
-  int gridID1, gridID2;
-  int nmiss;
-  double *array1, *array2;
-  double missval;
-  long i, j, ii, jj, index;
-  long gridsize;
-  field_t *field;
-  int isize;
-  int useWeight = FALSE;
+  bool useWeight = false;
   /*
   double findex = 0;
 
   progressInit();
   */
-  if ( field1->weight ) useWeight = TRUE;
+  if ( field1->weight ) useWeight = true;
 
-  gridsize = xinc*yinc;
-  field = (field_t*) Malloc(ompNumThreads*sizeof(field_t));
-  for ( i = 0; i < ompNumThreads; i++ )
+  int gridsize = xinc*yinc;
+  field_type *field = (field_type*) Malloc(ompNumThreads*sizeof(field_type));
+  for ( int i = 0; i < ompNumThreads; i++ )
     {
       field[i].size    = gridsize;
       field[i].ptr     = (double*) Malloc(gridsize*sizeof(double));
@@ -484,22 +468,22 @@ void gridboxstat(field_t *field1, field_t *field2, int xinc, int yinc, int statf
       field[i].nmiss   = 0;
     }
   
-  gridID1 = field1->grid;
-  gridID2 = field2->grid;
-  array1  = field1->ptr;
-  array2  = field2->ptr;
-  missval = field1->missval;
+  int gridID1 = field1->grid;
+  int gridID2 = field2->grid;
+  double *array1  = field1->ptr;
+  double *array2  = field2->ptr;
+  double missval = field1->missval;
 
-  nlon1 = gridInqXsize(gridID1);
-  nlat1 = gridInqYsize(gridID1);
+  int nlon1 = gridInqXsize(gridID1);
+  int nlat1 = gridInqYsize(gridID1);
 
-  nlon2 = gridInqXsize(gridID2);
-  nlat2 = gridInqYsize(gridID2);
+  int nlon2 = gridInqXsize(gridID2);
+  int nlat2 = gridInqYsize(gridID2);
 
 #if defined(_OPENMP)
-#pragma omp parallel for default(shared) private(ilat, ilon, j, jj, i, ii, index, isize)
+#pragma omp parallel for default(shared)
 #endif
-  for ( long ig = 0; ig < nlat2*nlon2; ++ig )
+  for ( int ig = 0; ig < nlat2*nlon2; ++ig )
     {
       int ompthID = cdo_omp_get_thread_num();
 
@@ -514,19 +498,19 @@ void gridboxstat(field_t *field1, field_t *field2, int xinc, int yinc, int statf
       findex++;
       if ( lprogress ) progressStatus(0, 1, findex/nlat2*nlon2);
       */
-      ilat = ig/nlon2;
-      ilon = ig - ilat*nlon2;
+      int ilat = ig/nlon2;
+      int ilon = ig - ilat*nlon2;
 
-      isize = 0;
+      int isize = 0;
       field[ompthID].nmiss = 0;
-      for ( j = 0; j < yinc; ++j )
+      for ( int j = 0; j < yinc; ++j )
 	{
-	  jj = ilat*yinc+j;
+	  int jj = ilat*yinc+j;
 	  if ( jj >= nlat1 ) break;
-	  for ( i = 0; i < xinc; ++i )
+	  for ( int i = 0; i < xinc; ++i )
 	    {
-	      ii = ilon*xinc+i;
-	      index = jj*nlon1 + ii;
+	      int ii = ilon*xinc+i;
+	      int index = jj*nlon1 + ii;
 	      if ( ii >= nlon1 ) break;
 	      field[ompthID].ptr[isize] = array1[index];
 	      if ( useWeight ) field[ompthID].weight[isize] = field1->weight[index];
@@ -539,13 +523,13 @@ void gridboxstat(field_t *field1, field_t *field2, int xinc, int yinc, int statf
       field2->ptr[ig] = fldfun(field[ompthID], statfunc);
     }
   
-  nmiss = 0;
-  for ( i = 0; i < nlat2*nlon2; i++ )
+  int nmiss = 0;
+  for ( int i = 0; i < nlat2*nlon2; i++ )
     if ( DBL_IS_EQUAL(array2[i], missval) ) nmiss++;
   
   field2->nmiss = nmiss;
   
-  for ( i = 0; i < ompNumThreads; i++ )
+  for ( int i = 0; i < ompNumThreads; i++ )
     {
       if ( field[i].ptr    ) Free(field[i].ptr);
       if ( field[i].weight ) Free(field[i].weight);
@@ -557,13 +541,10 @@ void gridboxstat(field_t *field1, field_t *field2, int xinc, int yinc, int statf
 
 void *Gridboxstat(void *argument)
 {
-  int nmiss;
   int lastgrid = -1;
-  int wstatus = FALSE;
-  int index;
-  int recID, nrecs;
+  int nrecs;
   int varID, levelID;
-  int needWeights = FALSE;
+  bool wstatus = false;
   char varname[CDI_MAX_NAME];
 
   cdoInitialize(argument);
@@ -586,10 +567,9 @@ void *Gridboxstat(void *argument)
   int operatorID = cdoOperatorID();
   int operfunc = cdoOperatorF1(operatorID);
 
-  if ( operfunc == func_mean || operfunc == func_avg ||
-       operfunc == func_var  || operfunc == func_std ||
-       operfunc == func_var1 || operfunc == func_std1 )
-    needWeights = TRUE;
+  bool needWeights = (operfunc == func_mean || operfunc == func_avg ||
+                      operfunc == func_var  || operfunc == func_std ||
+                      operfunc == func_var1 || operfunc == func_std1);
 
   int streamID1 = streamOpenRead(cdoStreamName(0));
 
@@ -608,14 +588,14 @@ void *Gridboxstat(void *argument)
     cdoAbort("Gaussian reduced grid found. Use option -R to convert it to a regular grid!");
 
   int gridID2 = genBoxGrid(gridID1, xinc, yinc);
-  for ( index = 0; index < ngrids; index++ )
+  for ( int index = 0; index < ngrids; index++ )
     vlistChangeGridIndex(vlistID2, index, gridID2);
 
   int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  field_t field1, field2;
+  field_type field1, field2;
   field_init(&field1);
   field_init(&field2);
 
@@ -636,8 +616,9 @@ void *Gridboxstat(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
         {
+          int nmiss;
           streamInqRecord(streamID1, &varID, &levelID);
           streamReadRecord(streamID1, field1.ptr, &nmiss);
           field1.nmiss = (size_t) nmiss;
diff --git a/src/Gridcell.c b/src/Gridcell.c
index 666f3eb..c86ab6e 100644
--- a/src/Gridcell.c
+++ b/src/Gridcell.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -41,8 +41,14 @@ double orthodrome(double px1, double py1, double px2, double py2)
 void grid_cell_area(int gridID, double *array)
 {
   int gridtype = gridInqType(gridID);
+  int projtype = (gridtype == GRID_PROJECTION) ? gridInqProjType(gridID) : -1;
+
   if ( gridtype == GRID_LONLAT      ||
        gridtype == GRID_GAUSSIAN    ||
+       projtype == CDI_PROJ_RLL     ||
+       projtype == CDI_PROJ_LAEA    ||
+       projtype == CDI_PROJ_SINU    ||
+       projtype == CDI_PROJ_LCC     ||
        gridtype == GRID_LCC         ||
        gridtype == GRID_GME         ||
        gridtype == GRID_CURVILINEAR ||
@@ -78,31 +84,19 @@ void grid_cell_area(int gridID, double *array)
 
 void *Gridcell(void *argument)
 {
-  int GRIDAREA, GRIDWGTS, GRIDMASK, GRIDDX, GRIDDY;
-  int operatorID;
-  int streamID1, streamID2;
-  int vlistID1, vlistID2;
-  int gridID, zaxisID;
-  int gridtype;
   int status;
-  int ngrids;
-  int need_radius;
-  int tsID, varID, levelID, taxisID;
-  long i, gridsize;
-  double *array = NULL;
 
   cdoInitialize(argument);
 
-  GRIDAREA = cdoOperatorAdd("gridarea",     1,  0, NULL);
-  GRIDWGTS = cdoOperatorAdd("gridweights",  1,  0, NULL);
-  GRIDMASK = cdoOperatorAdd("gridmask",     0,  0, NULL);
-  GRIDDX   = cdoOperatorAdd("griddx",       1,  0, NULL);
-  GRIDDY   = cdoOperatorAdd("griddy",       1,  0, NULL);
-
-  operatorID = cdoOperatorID();
+  int GRIDAREA = cdoOperatorAdd("gridarea",     1,  0, NULL);
+  int GRIDWGTS = cdoOperatorAdd("gridweights",  1,  0, NULL);
+  int GRIDMASK = cdoOperatorAdd("gridmask",     0,  0, NULL);
+  int GRIDDX   = cdoOperatorAdd("griddx",       1,  0, NULL);
+  int GRIDDY   = cdoOperatorAdd("griddy",       1,  0, NULL);
 
-  need_radius = cdoOperatorF1(operatorID);
+  int operatorID = cdoOperatorID();
 
+  bool need_radius = cdoOperatorF1(operatorID) > 0;
   if ( need_radius )
     {
       char *envstr = getenv("PLANET_RADIUS");
@@ -115,21 +109,21 @@ void *Gridcell(void *argument)
 
   if ( cdoVerbose ) cdoPrint("PlanetRadius: %g", PlanetRadius);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
+  int vlistID1 = streamInqVlist(streamID1);
 
-  ngrids = vlistNgrids(vlistID1);
+  int ngrids = vlistNgrids(vlistID1);
 
   if ( ngrids > 1 )
     cdoWarning("Found more than 1 grid, using the first one!");
 
-  gridID  = vlistGrid(vlistID1, 0);
+  int gridID  = vlistGrid(vlistID1, 0);
 
-  zaxisID = zaxisCreate(ZAXIS_SURFACE, 1);
+  int zaxisID = zaxisCreate(ZAXIS_SURFACE, 1);
 
-  vlistID2 = vlistCreate();
-  varID    = vlistDefVar(vlistID2, gridID, zaxisID, TSTEP_CONSTANT);
+  int vlistID2 = vlistCreate();
+  int varID    = vlistDefVar(vlistID2, gridID, zaxisID, TSTEP_CONSTANT);
   vlistDefNtsteps(vlistID2, 0);
 
   if ( operatorID == GRIDAREA )
@@ -138,17 +132,17 @@ void *Gridcell(void *argument)
       vlistDefVarStdname(vlistID2, varID, "area");
       vlistDefVarLongname(vlistID2, varID, "area of grid cell");
       vlistDefVarUnits(vlistID2, varID, "m2");
-      vlistDefVarDatatype(vlistID2, varID, DATATYPE_FLT64);
+      vlistDefVarDatatype(vlistID2, varID, CDI_DATATYPE_FLT64);
     }
   else if ( operatorID == GRIDWGTS )
     {
       vlistDefVarName(vlistID2, varID, "cell_weights");
-      vlistDefVarDatatype(vlistID2, varID, DATATYPE_FLT64);
+      vlistDefVarDatatype(vlistID2, varID, CDI_DATATYPE_FLT64);
     }
   else if ( operatorID == GRIDMASK )
     {
       vlistDefVarName(vlistID2, varID, "grid_mask");
-      vlistDefVarDatatype(vlistID2, varID, DATATYPE_UINT8);
+      vlistDefVarDatatype(vlistID2, varID, CDI_DATATYPE_UINT8);
     }
   else if ( operatorID == GRIDDX )
     {
@@ -163,12 +157,12 @@ void *Gridcell(void *argument)
       vlistDefVarUnits(vlistID2, varID, "m");
     }
 
-  taxisID = taxisCreate(TAXIS_ABSOLUTE);
+  int taxisID = taxisCreate(TAXIS_ABSOLUTE);
   vlistDefTaxis(vlistID2, taxisID);
 
 
-  gridsize = gridInqSize(gridID);
-  array = (double*) Malloc(gridsize*sizeof(double));
+  long gridsize = gridInqSize(gridID);
+  double *array = (double*) Malloc(gridsize*sizeof(double));
 
 
   if ( operatorID == GRIDAREA )
@@ -178,8 +172,7 @@ void *Gridcell(void *argument)
   else if ( operatorID == GRIDWGTS )
     {
       status = gridWeights(gridID, array);
-      if ( status != 0 )
-	  cdoWarning("Using constant grid cell area weights!");
+      if ( status != 0 ) cdoWarning("Using constant grid cell area weights!");
     }
   else if ( operatorID == GRIDMASK )
     {
@@ -191,22 +184,20 @@ void *Gridcell(void *argument)
 	}
       else
 	{
-	  for ( i = 0; i < gridsize; ++i ) mask[i] = 1;
+	  for ( int i = 0; i < gridsize; ++i ) mask[i] = 1;
 	}
 
-      for ( i = 0; i < gridsize; ++i ) array[i] = mask[i];
+      for ( int i = 0; i < gridsize; ++i ) array[i] = mask[i];
       Free(mask);
     }
   else if ( operatorID == GRIDDX || operatorID == GRIDDY )
     {
-      gridtype = gridInqType(gridID);
+      int gridtype = gridInqType(gridID);
       if ( gridtype == GRID_LONLAT      ||
 	   gridtype == GRID_GAUSSIAN    ||
 	   gridtype == GRID_LCC         ||
 	   gridtype == GRID_CURVILINEAR )
 	{
-	  long i, j, xsize, ysize;
-	  double *xv, *yv;
 	  double len1 = 0, len2 = 0;
 	  char units[CDI_MAX_NAME];
 
@@ -214,11 +205,11 @@ void *Gridcell(void *argument)
 	    gridID = gridToCurvilinear(gridID, 1);
 
 	  gridsize = gridInqSize(gridID);
-	  xsize = gridInqXsize(gridID);
-	  ysize = gridInqYsize(gridID);
+	  long xsize = gridInqXsize(gridID);
+	  long ysize = gridInqYsize(gridID);
 
-	  xv = (double*) Malloc(gridsize*sizeof(double));
-	  yv = (double*) Malloc(gridsize*sizeof(double));
+	  double *xv = (double*) Malloc(gridsize*sizeof(double));
+	  double *yv = (double*) Malloc(gridsize*sizeof(double));
 
 	  gridInqXvals(gridID, xv);
 	  gridInqYvals(gridID, yv);
@@ -227,13 +218,13 @@ void *Gridcell(void *argument)
 
 	  gridInqXunits(gridID, units);
 
-	  grid_to_radian(units, gridsize, yv, "grid longitudes");
+	  grid_to_radian(units, gridsize, xv, "grid longitudes");
 	  grid_to_radian(units, gridsize, yv, "grid latitudes");
 
 	  if ( operatorID == GRIDDX )
 	    {
-	      for ( j = 0; j < ysize; ++j )
-		for ( i = 0; i < xsize; ++i )
+	      for ( long j = 0; j < ysize; ++j )
+		for ( long i = 0; i < xsize; ++i )
 		  {
 		    if ( i == 0 )
 		      {
@@ -256,8 +247,8 @@ void *Gridcell(void *argument)
 	    }
 	  else
 	    {
-	      for ( i = 0; i < xsize; ++i )
-	        for ( j = 0; j < ysize; ++j )
+	      for ( long i = 0; i < xsize; ++i )
+	        for ( long j = 0; j < ysize; ++j )
 		  {
 		    if ( j == 0 )
 		      {
@@ -293,15 +284,15 @@ void *Gridcell(void *argument)
     }
 
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  tsID = 0;
+  int tsID = 0;
   streamDefTimestep(streamID2, tsID);
 
-  varID   = 0;
-  levelID = 0;
+  varID = 0;
+  int levelID = 0;
   streamDefRecord(streamID2, varID, levelID);
   streamWriteRecord(streamID2, array, 0);
 
diff --git a/src/Gridsearch.c b/src/Gridsearch.c
index 4993765..737a9ee 100644
--- a/src/Gridsearch.c
+++ b/src/Gridsearch.c
@@ -1,40 +1,258 @@
-/*
-  This file is part of CDO. CDO is a collection of Operators to
-  manipulate and analyse Climate model Data.
-
-  Copyright (C) 2003-2016 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 <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
 #include "pstream.h"
+#include "grid.h"
 
+void check_lon_range(long nlons, double *lons);
+void check_lat_range(long nlats, double *lats);
 
+typedef struct
+{
+  int gridID;
+  long size;
+  long num_cell_corners;
+  double *cell_corner_lon;
+  double *cell_corner_lat;
+} grid_type;
 
-void *Gridsearch(void *argument)
+typedef struct
+{
+  grid_type *src_grid;
+  grid_type *tgt_grid;
+  float *src_cell_bound_box;
+} cellsearch_type;
+
+
+static
+grid_type *grid_new(int gridID, const char *txt)
 {
-  int gridID1, gridID2;
+  bool lgrid_destroy = false;
+
+  if ( gridInqType(gridID) == GRID_GME )
+    {
+      lgrid_destroy = true;
+      int gridID_gme = gridToUnstructured(gridID, 1);
+      gridCompress(gridID_gme);
+      gridID = gridID_gme;
+    }
+
+  if ( gridInqType(gridID) != GRID_UNSTRUCTURED && gridInqType(gridID) != GRID_CURVILINEAR )
+    {
+      lgrid_destroy = true;
+      gridID = gridToCurvilinear(gridID, 1);
+    }
+
+  if ( gridInqYvals(gridID, NULL) == 0 || gridInqXvals(gridID, NULL) == 0 )
+    cdoAbort("%s grid corner missing!", txt);
+
+  grid_type *grid = (grid_type*) Malloc(sizeof(grid_type));
+
+  grid->gridID = gridID;
+  grid->size = gridInqSize(grid->gridID);
+  grid->num_cell_corners = (gridInqType(grid->gridID) == GRID_UNSTRUCTURED) ? gridInqNvertex(grid->gridID) : 4;
+
+  printf("%s grid size %ld nv %ld\n", txt, grid->size, grid->num_cell_corners);
+  grid->cell_corner_lon = (double*) Malloc(grid->num_cell_corners*grid->size*sizeof(double));
+  grid->cell_corner_lat = (double*) Malloc(grid->num_cell_corners*grid->size*sizeof(double));
+  gridInqXbounds(grid->gridID, grid->cell_corner_lon);
+  gridInqYbounds(grid->gridID, grid->cell_corner_lat);
+
+  char xunits[CDI_MAX_NAME]; xunits[0] = 0;
+  char yunits[CDI_MAX_NAME]; yunits[0] = 0;
+  cdiGridInqKeyStr(gridID, CDI_KEY_XUNITS, CDI_MAX_NAME, xunits);
+  cdiGridInqKeyStr(gridID, CDI_KEY_YUNITS, CDI_MAX_NAME, yunits);
+
+  grid_to_radian(xunits, grid->num_cell_corners*grid->size, grid->cell_corner_lon, "grid corner lon"); 
+  grid_to_radian(yunits, grid->num_cell_corners*grid->size, grid->cell_corner_lat, "grid corner lat"); 
+
+  // check_lon_range(grid->num_cell_corners*grid->size, grid->cell_corner_lon);
+  // check_lat_range(grid->num_cell_corners*grid->size, grid->cell_corner_lat);
 
+  if ( lgrid_destroy ) gridDestroy(gridID);
+
+  return grid;
+}
+
+static
+void grid_delete(grid_type *grid)
+{
+  if ( grid->cell_corner_lon ) Free(grid->cell_corner_lon);
+  if ( grid->cell_corner_lat ) Free(grid->cell_corner_lat);
+  if ( grid ) Free(grid);
+}
+
+void boundbox_from_corners1r(long ic, long nc, const double *restrict corner_lon,
+			     const double *restrict corner_lat, float *restrict bound_box)
+{
+  long inc = ic*nc;
+
+  float clat = corner_lat[inc];
+  float clon = corner_lon[inc];
+
+  bound_box[0] = clat;
+  bound_box[1] = clat;
+  bound_box[2] = clon;
+  bound_box[3] = clon;
+
+  for ( long j = 1; j < nc; ++j )
+    {
+      clat = corner_lat[inc+j];
+      clon = corner_lon[inc+j];
+
+      if ( clat < bound_box[0] ) bound_box[0] = clat;
+      if ( clat > bound_box[1] ) bound_box[1] = clat;
+      if ( clon < bound_box[2] ) bound_box[2] = clon;
+      if ( clon > bound_box[3] ) bound_box[3] = clon;
+    }
+
+  /*
+  if ( fabs(bound_box[3] - bound_box[2]) > PI )
+    {
+      bound_box[2] = 0;
+      bound_box[3] = PI2;
+    }
+  */
+}
+
+void boundbox_from_corners(long size, long nc, const double *restrict corner_lon,
+			   const double *restrict corner_lat, float *restrict bound_box)
+{
+  long i4, inc, j;
+  double clon, clat;
+
+  for ( long i = 0; i < size; ++i )
+    {
+      i4 = i<<2; // *4
+      inc = i*nc;
+      clat = corner_lat[inc];
+      clon = corner_lon[inc];
+      bound_box[i4  ] = clat;
+      bound_box[i4+1] = clat;
+      bound_box[i4+2] = clon;
+      bound_box[i4+3] = clon;
+      for ( j = 1; j < nc; ++j )
+	{
+	  clat = corner_lat[inc+j];
+	  clon = corner_lon[inc+j];
+	  if ( clat < bound_box[i4  ] ) bound_box[i4  ] = clat;
+	  if ( clat > bound_box[i4+1] ) bound_box[i4+1] = clat;
+	  if ( clon < bound_box[i4+2] ) bound_box[i4+2] = clon;
+	  if ( clon > bound_box[i4+3] ) bound_box[i4+3] = clon;
+	}
+    }
+}
+
+static
+cellsearch_type *cellsearch_new(grid_type *src_grid, grid_type *tgt_grid)
+{
+  cellsearch_type *cellsearch = (cellsearch_type*) Malloc(sizeof(cellsearch_type));
+
+  cellsearch->src_grid = src_grid;
+  cellsearch->tgt_grid = tgt_grid;
+
+  float *src_cell_bound_box = (float*) Malloc(4*src_grid->size*sizeof(double));
+
+  boundbox_from_corners(src_grid->size, src_grid->num_cell_corners, 
+                        src_grid->cell_corner_lon, src_grid->cell_corner_lat, src_cell_bound_box);
+
+  cellsearch->src_cell_bound_box = src_cell_bound_box;
+
+  return cellsearch;
+}
+
+static
+void cellsearch_delete(cellsearch_type *cellsearch)
+{
+  if ( cellsearch ) Free(cellsearch);
+}
+
+static
+long search_cells(cellsearch_type *cellsearch, long tgt_cell_add, long *srch_add)
+{
+  grid_type *src_grid = cellsearch->src_grid;
+  grid_type *tgt_grid = cellsearch->tgt_grid;
+  float *src_cell_bound_box = cellsearch->src_cell_bound_box;
+  float tgt_cell_bound_box[4];
+
+  boundbox_from_corners1r(tgt_cell_add, tgt_grid->num_cell_corners, tgt_grid->cell_corner_lon, tgt_grid->cell_corner_lat, tgt_cell_bound_box);
+
+  long src_cell_addm4;
+
+  float bound_box_lat1 = tgt_cell_bound_box[0];
+  float bound_box_lat2 = tgt_cell_bound_box[1];
+  float bound_box_lon1 = tgt_cell_bound_box[2];
+  float bound_box_lon2 = tgt_cell_bound_box[3];
+
+  long num_srch_cells = 0;
+  for ( long src_cell_add = 0; src_cell_add < src_grid->size; ++src_cell_add )
+    {
+      src_cell_addm4 = src_cell_add<<2;
+      if ( (src_cell_bound_box[src_cell_addm4+2] <= bound_box_lon2)  &&
+	   (src_cell_bound_box[src_cell_addm4+3] >= bound_box_lon1) )
+	{
+	  if ( (src_cell_bound_box[src_cell_addm4  ] <= bound_box_lat2)  &&
+	       (src_cell_bound_box[src_cell_addm4+1] >= bound_box_lat1) )
+	    {
+	      srch_add[num_srch_cells] = src_cell_add;
+	      num_srch_cells++;
+	    }
+	}
+    }
+
+  return num_srch_cells;
+}      
+
+static
+void cell_search(int gridIDsrc, int gridIDtgt)
+{
+  grid_type *src_grid = grid_new(gridIDsrc, "source");
+  grid_type *tgt_grid = grid_new(gridIDtgt, "target");
+
+  long *srch_add = (long*) Malloc(src_grid->size*sizeof(long));
+
+  cellsearch_type *cellsearch = cellsearch_new(src_grid, tgt_grid);
+  
+  for ( long tgt_cell_add = 0; tgt_cell_add < tgt_grid->size; ++tgt_cell_add )
+    {
+      long num_srch_cells = search_cells(cellsearch, tgt_cell_add, srch_add);
+
+      if ( cdoVerbose && num_srch_cells > 0 )
+        {
+          printf("tgt cell %ld: found %ld src cells\n", tgt_cell_add, num_srch_cells);
+          for ( long n = 0; n < num_srch_cells; ++n ) printf("   %ld: %ld\n", n+1, srch_add[n]);
+        }
+    }
+
+  cellsearch_delete(cellsearch);
+  grid_delete(src_grid);
+  grid_delete(tgt_grid);
+  Free(srch_add);
+}
+
+static
+void point_search(int gridIDsrc, int gridIDtgt)
+{
+}
+
+
+void *Gridsearch(void *argument)
+{
   cdoInitialize(argument);
 
-  cdoOperatorAdd("testpointsearch",  0,   0, NULL);
-  cdoOperatorAdd("testcellsearch",   0,   0, NULL);
+  int PSEARCH = cdoOperatorAdd("testpointsearch",  0,   0, NULL);
+  int CSEARCH = cdoOperatorAdd("testcellsearch",   0,   0, NULL);
+
+  int operatorID = cdoOperatorID();
 
   operatorInputArg("source and target grid description file or name");
   operatorCheckArgc(2);
-  gridID1 = cdoDefineGrid(operatorArgv()[0]);
-  gridID2 = cdoDefineGrid(operatorArgv()[1]);
+  
+  int gridID1 = cdoDefineGrid(operatorArgv()[0]);
+  int gridID2 = cdoDefineGrid(operatorArgv()[1]);
+
+  if      ( operatorID == CSEARCH ) cell_search(gridID1, gridID2);
+  else if ( operatorID == CSEARCH ) point_search(gridID1, gridID2);
 
   cdoFinish();
 
diff --git a/src/Harmonic.c b/src/Harmonic.c
index 261b724..42819d0 100644
--- a/src/Harmonic.c
+++ b/src/Harmonic.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -31,26 +31,15 @@ void *Harmonic(void *argument)
 {
   int gridsize;
   int nrecs;
-  int varID, levelID, recID;
-  int tsID;
-  int i, j;
-  int nts;
-  int streamID1, streamID2;
-  int *streamIDs;
-  int vlistID1, vlistID2, taxisID1, taxisID2;
+  int varID, levelID;
   int nmiss;
-  int nchars;
   int offset;
-  int nvars, nlevel;
+  int nlevel;
   int vdate = 0, vtime = 0;
-  int n_out, nout, n;
   char filesuffix[32];
   char filename[8192];
   const char *refname;
   double missval;
-  double sine, cosine;
-  double *array;
-  double ***work, ***out;
 
   cdoInitialize(argument);
 
@@ -58,8 +47,8 @@ void *Harmonic(void *argument)
 
   operatorCheckArgc(2);
 
-  n_out = parameter2int(operatorArgv()[0]);
-  n     = parameter2int(operatorArgv()[1]);
+  int n_out = parameter2int(operatorArgv()[0]);
+  int n     = parameter2int(operatorArgv()[1]);
 
   if ( n_out > 9 ) cdoAbort("Maximum number of wave numbers is 9!");
 
@@ -67,32 +56,32 @@ void *Harmonic(void *argument)
     cdoAbort("The wave length must be positive and smaller than "
 	     "2 times the number of requested harmonics (=%d)!", n_out);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisCreate(TAXIS_ABSOLUTE);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisCreate(TAXIS_ABSOLUTE);
   vlistDefTaxis(vlistID2, taxisID2);
 
   refname = cdoStreamName(0)->argv[cdoStreamName(0)->argc-1];
   filesuffix[0] = 0;
   cdoGenFileSuffix(filesuffix, sizeof(filesuffix), streamInqFiletype(streamID1), vlistID1, refname);
 
-  streamIDs = (int*) Malloc(n_out*sizeof(int));
+  int *streamIDs = (int*) Malloc(n_out*sizeof(int));
 
   strcpy(filename, cdoStreamName(1)->args);
-  nchars = strlen(filename);
+  int nchars = strlen(filename);
 
-  for ( j = 0; j < n_out; ++j )
+  for ( int j = 0; j < n_out; ++j )
     {
       sprintf(filename+nchars, "%1d", j+1);
       if ( filesuffix[0] )
 	sprintf(filename+nchars+1, "%s", filesuffix);
 
       argument_t *fileargument = file_argument_new(filename);
-      streamID2 = streamOpenWrite(fileargument, cdoFiletype());
+      int streamID2 = streamOpenWrite(fileargument, cdoFiletype());
       file_argument_free(fileargument);
 
       streamIDs[j] = streamID2;
@@ -100,12 +89,12 @@ void *Harmonic(void *argument)
       streamDefVlist(streamID2, vlistID2);
     }
 
-  nvars = vlistNvars(vlistID1);
+  int nvars = vlistNvars(vlistID1);
 
-  out  = (double ***) Malloc(n_out*sizeof(double **));
-  work = (double ***) Malloc(2*n_out*sizeof(double **));
+  double ***out  = (double ***) Malloc(n_out*sizeof(double **));
+  double ***work = (double ***) Malloc(2*n_out*sizeof(double **));
 
-  for ( j = 0; j < n_out; ++j )
+  for ( int j = 0; j < n_out; ++j )
     {
       out[j] = (double **) Malloc(nvars*sizeof(double *));
       for ( varID = 0; varID < nvars; ++varID )
@@ -116,7 +105,7 @@ void *Harmonic(void *argument)
 	}
     }
 
-  for ( j = 0; j < n_out*2; ++j )
+  for ( int j = 0; j < n_out*2; ++j )
     {
       work[j] = (double **) Malloc(nvars*sizeof(double *));
       for ( varID = 0; varID < nvars; ++varID )
@@ -130,9 +119,9 @@ void *Harmonic(void *argument)
 
 
   gridsize = vlistGridsizeMax(vlistID1);
-  array = (double*) Malloc(gridsize*sizeof(double));
+  double *array = (double*) Malloc(gridsize*sizeof(double));
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       if ( tsID == 0 )
@@ -141,7 +130,7 @@ void *Harmonic(void *argument)
 	  vtime = taxisInqVtime(taxisID1);
 	}
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
@@ -151,11 +140,11 @@ void *Harmonic(void *argument)
 
 	  if ( nmiss > 0 ) cdoAbort("Missing values are not allowed!");
 
-	  for ( j = 0; j < n_out; ++j )
+	  for ( int j = 0; j < n_out; ++j )
 	    {
-	      sine   = sin (2 * M_PI * (((j + 1) * (tsID+1)) % n) / n);
-	      cosine = cos (2 * M_PI * (((j + 1) * (tsID+1)) % n) / n);
-	      for ( i = 0; i < gridsize; i++ )
+	      double sine   = sin (2 * M_PI * (((j + 1) * (tsID+1)) % n) / n);
+	      double cosine = cos (2 * M_PI * (((j + 1) * (tsID+1)) % n) / n);
+	      for ( int i = 0; i < gridsize; i++ )
 		{
 		  work[j][varID][i+offset]         += array[i] * sine;
 		  work[n_out + j][varID][i+offset] += array[i] * cosine;
@@ -166,7 +155,7 @@ void *Harmonic(void *argument)
       tsID++;
     }
 
-  nts = tsID;
+  int nts = tsID;
 
   if ( array ) Free(array);
 
@@ -179,7 +168,7 @@ void *Harmonic(void *argument)
 	       " does not divide the number of timesteps (=%d)!", n, nts);
     }
 
-  for ( j = 0; j < n_out && 2*(j+1) < n; j++ )
+  for ( int j = 0; j < n_out && 2*(j+1) < n; j++ )
     {
       for ( varID = 0; varID < nvars; varID++ )
 	{
@@ -188,7 +177,7 @@ void *Harmonic(void *argument)
 	  for ( levelID = 0; levelID < nlevel; levelID++ )
 	    {
 	      offset = gridsize*levelID;
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( int i = 0; i < gridsize; i++ )
 		out[j][varID][i+offset] = sqrt(work[j][varID][i+offset] * work[j][varID][i+offset] +
 					work[n_out+j][varID][i+offset] * work[n_out+j][varID][i+offset]) * 2 / nts;
 	    }
@@ -204,19 +193,19 @@ void *Harmonic(void *argument)
 	  for ( levelID = 0; levelID < nlevel; levelID++ )
 	    {
 	      offset = gridsize*levelID;
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( int i = 0; i < gridsize; i++ )
 		out[n_out - 1][varID][i+offset] = work[2 * n_out - 1][varID][i+offset] / nts;
 	    }
 	}
     }
 
-  nout = n_out;
+  int nout = n_out;
 
   taxisDefVdate(taxisID2, vdate);
   taxisDefVtime(taxisID2, vtime);
-  for ( j = 0; j < nout; j++ )
+  for ( int j = 0; j < nout; j++ )
     {
-      streamID2 = streamIDs[j];
+      int streamID2 = streamIDs[j];
       streamDefTimestep(streamID2, 0);
 
       for ( varID = 0; varID < nvars; varID++ )
@@ -232,7 +221,7 @@ void *Harmonic(void *argument)
 	}
     }
 
-  for ( j = 0; j < n_out && 2 * (j + 1) < n; j++ )
+  for ( int j = 0; j < n_out && 2 * (j + 1) < n; j++ )
     {
       for ( varID = 0; varID < nvars; varID++ )
 	{
@@ -242,7 +231,7 @@ void *Harmonic(void *argument)
 	  for ( levelID = 0; levelID < nlevel; levelID++ )
 	    {
 	      offset = gridsize*levelID;
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( int i = 0; i < gridsize; i++ )
 		{
 		  out[j][varID][i+offset] = work[j][varID][i+offset] || work[n_out+j][varID][i+offset]
 		              ? atan2 (work[j][varID][i+offset], work[n_out+j][varID][i+offset]) *
@@ -260,9 +249,9 @@ void *Harmonic(void *argument)
 
   taxisDefVdate(taxisID2, vdate);
   taxisDefVtime(taxisID2, vtime);
-  for ( j = 0; j < nout; j++ )
+  for ( int j = 0; j < nout; j++ )
     {
-      streamID2 = streamIDs[j];
+      int streamID2 = streamIDs[j];
       streamDefTimestep(streamID2, 1);
 
       for ( varID = 0; varID < nvars; varID++ )
@@ -275,22 +264,22 @@ void *Harmonic(void *argument)
 	      offset = gridsize*levelID;
 	      streamDefRecord(streamID2, varID, levelID);
 	      nmiss = 0;
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( int i = 0; i < gridsize; i++ )
 		if ( DBL_IS_EQUAL(out[j][varID][i+offset], missval) ) nmiss++;
 	      streamWriteRecord(streamID2, out[j][varID]+offset, nmiss);
 	    }
 	}
     }
 
-  for ( j = 0; j < n_out; j++ )
+  for ( int j = 0; j < n_out; j++ )
     {
-      streamID2 = streamIDs[j];
+      int streamID2 = streamIDs[j];
       streamClose(streamID2);
     }
 
   Free(streamIDs);
 
-  for ( j = 0; j < n_out; ++j )
+  for ( int j = 0; j < n_out; ++j )
     {
       for ( varID = 0; varID < nvars; ++varID )
         Free(out[j][varID]);
@@ -300,7 +289,7 @@ void *Harmonic(void *argument)
 
   Free(out);
 
-  for ( j = 0; j < n_out*2; ++j )
+  for ( int j = 0; j < n_out*2; ++j )
     {
       for ( varID = 0; varID < nvars; ++varID )
         Free(work[j][varID]);
diff --git a/src/Hi.c b/src/Hi.c
old mode 100755
new mode 100644
index 1a93ce0..b44d486
--- a/src/Hi.c
+++ b/src/Hi.c
@@ -46,9 +46,8 @@ static double humidityIndex(double t, double e, double r, double missval)
 }
 
 
-static void farexpr(field_t *field1, field_t field2, field_t field3, double (*expression)(double, double, double, double))
+static void farexpr(field_type *field1, field_type field2, field_type field3, double (*expression)(double, double, double, double))
 {
-  int   i, len;
   const int     grid1    = field1->grid;
   const int     nmiss1   = field1->nmiss;
   const double  missval1 = field1->missval;
@@ -62,14 +61,14 @@ static void farexpr(field_t *field1, field_t field2, field_t field3, double (*ex
   const double  missval3 = field3.missval;
   const double *array3   = field3.ptr;
 
-  len = gridInqSize(grid1);
+  int 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 ( i = 0; i < len; i++ )
+      for ( int 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
@@ -77,50 +76,44 @@ static void farexpr(field_t *field1, field_t field2, field_t field3, double (*ex
     }
   else
     {
-      for ( i = 0; i < len; i++ )
+      for ( int i = 0; i < len; i++ )
         array1[i] = expression(array1[i], array2[i], array3[i], missval1);  
     }
 
   field1->nmiss = 0;
-  for ( i = 0; i < len; i++ )
+  for ( int i = 0; i < len; i++ )
     if ( DBL_IS_EQUAL(array1[i], missval1) ) field1->nmiss++;
 }
 
    
 void *Hi(void *argument)
 {
-  int streamID1, streamID2, streamID3, streamID4;
-  int gridsize;
   int nmiss;
-  int nrecs, nrecs2, nrecs3, recID;
-  int tsID;
-  int gridID, zaxisID;
-  int varID1, varID2, varID3, varID4;
+  int nrecs;
+  int varID1, varID2, varID3;
   int levelID1, levelID2, levelID3;
-  int vlistID1, vlistID2, vlistID3, vlistID4;
-  int taxisID1, /*taxisID2, taxisID3,*/ taxisID4;
-  field_t field1, field2, field3;
 
   cdoInitialize(argument);
   cdoOperatorAdd("hi", 0, 0, NULL);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
-  streamID2 = streamOpenRead(cdoStreamName(1));
-  streamID3 = streamOpenRead(cdoStreamName(2));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID2 = streamOpenRead(cdoStreamName(1));
+  int streamID3 = streamOpenRead(cdoStreamName(2));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = streamInqVlist(streamID2);
-  vlistID3 = streamInqVlist(streamID3);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = streamInqVlist(streamID2);
+  int vlistID3 = streamInqVlist(streamID3);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
   //taxisID2 = vlistInqTaxis(vlistID2);
   //taxisID3 = vlistInqTaxis(vlistID3);
 
   vlistCompare(vlistID1, vlistID2, CMP_DIM);
   vlistCompare(vlistID1, vlistID3, CMP_DIM);
   
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
 
+  field_type field1, field2, field3;
   field_init(&field1);
   field_init(&field2);
   field_init(&field3);
@@ -132,12 +125,12 @@ void *Hi(void *argument)
     cdoPrint("Number of timesteps: file1 %d, file2 %d, file3 %d",
 	     vlistNtsteps(vlistID1), vlistNtsteps(vlistID2), vlistNtsteps(vlistID3));
 
-  vlistID4 = vlistCreate();
-  gridID   = vlistInqVarGrid(vlistID1, FIRST_VAR);
-  zaxisID  = vlistInqVarZaxis(vlistID1, FIRST_VAR);
-  varID4   = vlistDefVar(vlistID4, gridID, zaxisID, TSTEP_INSTANT);
+  int vlistID4 = vlistCreate();
+  int gridID   = vlistInqVarGrid(vlistID1, FIRST_VAR);
+  int zaxisID  = vlistInqVarZaxis(vlistID1, FIRST_VAR);
+  int varID4   = vlistDefVar(vlistID4, gridID, zaxisID, TSTEP_INSTANT);
 
-  taxisID4 = taxisCreate(TAXIS_RELATIVE);
+  int taxisID4 = taxisCreate(TAXIS_RELATIVE);
   taxisDefTunit(taxisID4, TUNIT_MINUTE);
   taxisDefCalendar(taxisID4, CALENDAR_STANDARD);
   taxisDefRdate(taxisID4, 19550101);
@@ -148,22 +141,22 @@ void *Hi(void *argument)
   vlistDefVarLongname(vlistID4, varID4, HI_LONGNAME);
   vlistDefVarUnits(vlistID4, varID4, HI_UNITS);
 
-  streamID4 = streamOpenWrite(cdoStreamName(3), cdoFiletype());
+  int streamID4 = streamOpenWrite(cdoStreamName(3), cdoFiletype());
 
   streamDefVlist(streamID4, vlistID4);
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
-      nrecs2 = streamInqTimestep(streamID2, tsID);
-      nrecs3 = streamInqTimestep(streamID3, tsID);
+      int nrecs2 = streamInqTimestep(streamID2, tsID);
+      int nrecs3 = streamInqTimestep(streamID3, tsID);
       if ( nrecs2 == 0 || nrecs3 == 0 )
         cdoAbort("Input streams have different number of timesteps!");
 
       taxisCopyTimestep(taxisID4, taxisID1);
       streamDefTimestep(streamID4, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID1, &levelID1);
 	  streamReadRecord(streamID1, field1.ptr, &nmiss);
diff --git a/src/Histogram.c b/src/Histogram.c
index 1805dc1..9d5c3f9 100644
--- a/src/Histogram.c
+++ b/src/Histogram.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -24,69 +24,54 @@
 #include "cdo.h"
 #include "cdo_int.h"
 #include "pstream.h"
-#include "list.h"
+#include "listarray.h"
 
 
 void *Histogram(void *argument)
 {
-  int HISTCOUNT, HISTSUM, HISTMEAN, HISTFREQ;
-  int operatorID;
-  int streamID1, streamID2;
-  int nrecs;
-  int tsID1, recID, varID, levelID;
-  int gridsize;
-  int vlistID1, vlistID2;
+  int nrecs, varID, levelID;
   int nmiss;
-  int taxisID1, taxisID2 = CDI_UNDEFID;
-  int nbins;
-  int i, nvars;
   int offset;
-  int nzaxis, nlevel, zaxisID, zaxisID2, index;
-  double *array = NULL;
-  double *fltarr = NULL;
-  double *bins;
+  int nlevel, zaxisID;
   double missval;
-  LIST *flist = listNew(FLT_LIST);
-  double **vardata = NULL;
-  double **varcount = NULL;
-  double **vartcount = NULL;
 
   cdoInitialize(argument);
 
-  HISTCOUNT = cdoOperatorAdd("histcount", 0, 0, NULL);
-  HISTSUM   = cdoOperatorAdd("histsum",   0, 0, NULL);
-  HISTMEAN  = cdoOperatorAdd("histmean",  0, 0, NULL);
-  HISTFREQ  = cdoOperatorAdd("histfreq",  0, 0, NULL);
+  int HISTCOUNT = cdoOperatorAdd("histcount", 0, 0, NULL);
+  int HISTSUM   = cdoOperatorAdd("histsum",   0, 0, NULL);
+  int HISTMEAN  = cdoOperatorAdd("histmean",  0, 0, NULL);
+  int HISTFREQ  = cdoOperatorAdd("histfreq",  0, 0, NULL);
 
   UNUSED(HISTSUM);
 
-  operatorID = cdoOperatorID();
+  int operatorID = cdoOperatorID();
 
   operatorInputArg("bins");
 
-  nbins = args2fltlist(operatorArgc(), operatorArgv(), flist) - 1;
+  lista_t *flista = lista_new(FLT_LISTA);
+  int nbins = args2flt_lista(operatorArgc(), operatorArgv(), flista) - 1;
   if ( nbins < 1 ) cdoAbort("Too few arguments!");
-  fltarr = (double *) listArrayPtr(flist);
+  double *fltarr = (double *) lista_dataptr(flista);
 
   if ( cdoVerbose )
     {
       printf("nbins = %d\n", nbins);
-      for ( i = 0; i < nbins; i++ )
+      for ( int i = 0; i < nbins; i++ )
 	printf("flt %d = %g\n", i+1, fltarr[i]);
     }
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  taxisID1 = vlistInqTaxis(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
 
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
   /* create zaxis for output bins */
-  zaxisID2 = zaxisCreate(ZAXIS_GENERIC, nbins);
-  bins = (double*) Malloc(nbins*sizeof(double));
-  /* for ( i = 0; i < nbins; i++ ) bins[i] = (fltarr[i]+fltarr[i+1])/2; */
-  for ( i = 0; i < nbins; i++ ) bins[i] = fltarr[i];
+  int zaxisID2 = zaxisCreate(ZAXIS_GENERIC, nbins);
+  double *bins = (double*) Malloc(nbins*sizeof(double));
+  /* for ( int i = 0; i < nbins; i++ ) bins[i] = (fltarr[i]+fltarr[i+1])/2; */
+  for ( int i = 0; i < nbins; i++ ) bins[i] = fltarr[i];
   zaxisDefLevels(zaxisID2, bins);
   Free(bins);
   zaxisDefLbounds(zaxisID2, fltarr);
@@ -96,8 +81,8 @@ void *Histogram(void *argument)
   zaxisDefUnits(zaxisID2, "level");
 
   /* check zaxis: only 2D fields allowed */
-  nzaxis = vlistNzaxis(vlistID1);
-  for ( index = 0; index < nzaxis; index++ )
+  int nzaxis = vlistNzaxis(vlistID1);
+  for ( int index = 0; index < nzaxis; index++ )
     {
       zaxisID = vlistZaxis(vlistID1, index);
       nlevel = zaxisInqSize(zaxisID);
@@ -106,20 +91,20 @@ void *Histogram(void *argument)
       vlistChangeZaxisIndex(vlistID2, index, zaxisID2);
     }
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
   streamDefVlist(streamID2, vlistID2);
 
-  nvars = vlistNvars(vlistID2);
-  vardata   = (double **) Malloc(nvars*sizeof(double *));
-  varcount  = (double **) Malloc(nvars*sizeof(double *));
-  vartcount = (double **) Malloc(nvars*sizeof(double *));
+  int nvars = vlistNvars(vlistID2);
+  double **vardata   = (double **) Malloc(nvars*sizeof(double *));
+  double **varcount  = (double **) Malloc(nvars*sizeof(double *));
+  double **vartcount = (double **) Malloc(nvars*sizeof(double *));
   for ( varID = 0; varID < nvars; varID++ )
     {
-      gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
+      int gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
       vardata[varID]  = (double*) Malloc(nbins*gridsize*sizeof(double));
       varcount[varID] = (double*) Malloc(nbins*gridsize*sizeof(double));
       vartcount[varID] = (double*) Malloc(gridsize*sizeof(double));
@@ -128,15 +113,15 @@ void *Histogram(void *argument)
       memset(vartcount[varID], 0, gridsize*sizeof(double));
     }
 
-  gridsize = vlistGridsizeMax(vlistID1);
-  array = (double*) Malloc(gridsize*sizeof(double));
+  int gridsize = vlistGridsizeMax(vlistID1);
+  double *array = (double*) Malloc(gridsize*sizeof(double));
 
-  tsID1 = 0;
+  int tsID1 = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID1)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, array, &nmiss);
@@ -145,12 +130,12 @@ void *Histogram(void *argument)
 	  gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
 
 	  nmiss=0;
-	  for ( i = 0; i < gridsize; i++ )
+	  for ( int i = 0; i < gridsize; i++ )
 	    {
 	      if ( !DBL_IS_EQUAL(array[i], missval) )
 		{
 		  vartcount[varID][i] += 1;
-		  index = 0;
+		  int index = 0;
 		  while( index < nbins )
 		    {
 		      offset = gridsize*index;
@@ -182,12 +167,12 @@ void *Histogram(void *argument)
 
       /* fix mising values */
       
-      for ( index = 0; index < nbins; index++ )
+      for ( int index = 0; index < nbins; index++ )
 	{
 	  nmiss = 0;
 	  offset = gridsize*index;
 
-	  for ( i = 0; i < gridsize; i++ )
+	  for ( int i = 0; i < gridsize; i++ )
 	    {
 	      if ( vartcount[varID][i] > 0 )
 		{
@@ -238,7 +223,7 @@ void *Histogram(void *argument)
 
   if ( array ) Free(array);
 
-  listDelete(flist);
+  lista_destroy(flista);
 
   cdoFinish();
 
diff --git a/src/Importamsr.c b/src/Importamsr.c
index 9217c6e..c83d972 100644
--- a/src/Importamsr.c
+++ b/src/Importamsr.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -56,7 +56,7 @@ void init_amsr_day(int vlistID, int gridID, int zaxisID, int nvars)
       varID = vlistDefVar(vlistID, gridID, zaxisID, TSTEP_INSTANT);
       vlistDefVarName(vlistID, varID, name[i]);
       vlistDefVarUnits(vlistID, varID, units[i]);
-      vlistDefVarDatatype(vlistID, varID, DATATYPE_INT16);
+      vlistDefVarDatatype(vlistID, varID, CDI_DATATYPE_INT16);
       vlistDefVarMissval(vlistID, varID, 254);
       vlistDefVarScalefactor(vlistID, varID, xscale[i]);
       vlistDefVarAddoffset(vlistID, varID, xminval[i]);
@@ -103,7 +103,7 @@ void init_amsr_averaged(int vlistID, int gridID, int zaxisID, int nvars)
       varID = vlistDefVar(vlistID, gridID, zaxisID, TSTEP_INSTANT);
       vlistDefVarName(vlistID, varID, name[i]);
       vlistDefVarUnits(vlistID, varID, units[i]);
-      vlistDefVarDatatype(vlistID, varID, DATATYPE_INT16);
+      vlistDefVarDatatype(vlistID, varID, CDI_DATATYPE_INT16);
       vlistDefVarMissval(vlistID, varID, 254);
       vlistDefVarScalefactor(vlistID, varID, xscale[i]);
       vlistDefVarAddoffset(vlistID, varID, xminval[i]);
@@ -150,9 +150,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)
 {
-  int varID;
-
-  for ( varID = 0; varID < nvars; ++varID )
+  for ( int varID = 0; varID < nvars; ++varID )
     {
       streamDefRecord(streamID, varID, 0);
       streamWriteRecord(streamID, data[varID], nmiss[varID]);
@@ -163,69 +161,61 @@ static
 int getDate(const char *name)
 {
   int date = 0;
-  char *pname;
-
-  pname = (char *)strchr(name, '_');
+  char *pname = (char *)strchr(name, '_');
 
   if ( pname ) date = atoi(pname+1);
 
-  return(date);
+  return date;
 }
 
 
 void *Importamsr(void *argument)
 {
-  int streamID;
   int tsID;
-  int gridID, zaxisID, taxisID, vlistID;
-  int gridsize;
-  int i;
   int nvars;
-  int vdate = 0, vtime = 0;
+  int vtime = 0;
   double xvals[NLON], yvals[NLAT];
   double *data[MAX_VARS];
   int nmiss[MAX_VARS];
-  FILE *fp;
-  size_t fsize;
 
   cdoInitialize(argument);
 
-  fp = fopen(cdoStreamName(0)->args, "r");
+  FILE *fp = fopen(cdoStreamName(0)->args, "r");
   if ( fp == NULL ) { perror(cdoStreamName(0)->args); exit(EXIT_FAILURE); }
 
   fseek(fp, 0L, SEEK_END);
-  fsize = (size_t) ftell(fp);
+  size_t fsize = (size_t) ftell(fp);
   fseek(fp, 0L, SEEK_SET);
 
-  vdate = getDate(cdoStreamName(0)->args);
+  int vdate = getDate(cdoStreamName(0)->args);
   if ( vdate <= 999999 ) vdate = vdate*100 + 1;
 
-  streamID = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   /*
     Longitude  is 0.25*xdim-0.125    degrees east
     Latitude   is 0.25*ydim-90.125
   */
-  gridsize = NLON*NLAT;
-  gridID = gridCreate(GRID_LONLAT, gridsize);
+  int gridsize = NLON*NLAT;
+  int gridID = gridCreate(GRID_LONLAT, gridsize);
   gridDefXsize(gridID, NLON);
   gridDefYsize(gridID, NLAT);
-  for ( i = 0; i < NLON; ++i ) xvals[i] = 0.25*(i+1) - 0.125;
-  for ( i = 0; i < NLAT; ++i ) yvals[i] = 0.25*(i+1) - 90.125;
+  for ( int i = 0; i < NLON; ++i ) xvals[i] = 0.25*(i+1) - 0.125;
+  for ( int i = 0; i < NLAT; ++i ) yvals[i] = 0.25*(i+1) - 90.125;
   gridDefXvals(gridID, xvals);
   gridDefYvals(gridID, yvals);
 
-  zaxisID = zaxisCreate(ZAXIS_SURFACE, 1);
+  int zaxisID = zaxisCreate(ZAXIS_SURFACE, 1);
 
-  taxisID = taxisCreate(TAXIS_ABSOLUTE);
+  int taxisID = taxisCreate(TAXIS_ABSOLUTE);
 
-  vlistID = vlistCreate();
+  int vlistID = vlistCreate();
   vlistDefTaxis(vlistID, taxisID);
 
   if ( fsize == 12441600 )
     {
       nvars = 6;
-      for ( i = 0; i < nvars; ++i ) data[i] = (double*) Malloc(gridsize*sizeof(double));
+      for ( int i = 0; i < nvars; ++i ) data[i] = (double*) Malloc(gridsize*sizeof(double));
 
       init_amsr_day(vlistID, gridID, zaxisID, nvars);
 
@@ -245,12 +235,12 @@ void *Importamsr(void *argument)
 	  write_data(streamID, nvars, data, nmiss);
 	}
 
-      for ( i = 0; i < nvars; ++i ) Free(data[i]);
+      for ( int i = 0; i < nvars; ++i ) Free(data[i]);
     }
   else if ( fsize == 5184000 )
     {
       nvars = 5;
-      for ( i = 0; i < nvars; ++i ) data[i] = (double*) Malloc(gridsize*sizeof(double));
+      for ( int i = 0; i < nvars; ++i ) data[i] = (double*) Malloc(gridsize*sizeof(double));
 
       init_amsr_averaged(vlistID, gridID, zaxisID, nvars);
 
@@ -267,7 +257,7 @@ void *Importamsr(void *argument)
 
       write_data(streamID, nvars, data, nmiss);
 
-      for ( i = 0; i < nvars; ++i ) Free(data[i]);
+      for ( int i = 0; i < nvars; ++i ) Free(data[i]);
     }
   else
     cdoAbort("Unexpected file size for AMSR data!");
diff --git a/src/Importbinary.c b/src/Importbinary.c
index 91dc656..dcaeee5 100644
--- a/src/Importbinary.c
+++ b/src/Importbinary.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -23,7 +23,6 @@
 #define _XOPEN_SOURCE 600 /* fseeko */
 #endif
 
-#include <ctype.h>
 
 #include <cdi.h>
 #include "cdo.h"
@@ -70,10 +69,9 @@ void get_dim_vals(dsets_t *pfi, double *vals, int dimlen, int dim)
 static
 void rev_vals(double *vals, int n)
 {
-  int i;
   double dum;
 
-  for ( i = 0; i < n/2; ++i )
+  for ( int i = 0; i < n/2; ++i )
     {
       dum = vals[i];
       vals[i] = vals[n-1-i];
@@ -116,22 +114,20 @@ int y_is_gauss(double *gridyvals, int ysize)
       Free(yvals);
     }
 
-  return (lgauss);
+  return lgauss;
 }
 
 static
 int define_grid(dsets_t *pfi)
 {
   int gridID, gridtype;
-  int nx, ny;
-  double *xvals, *yvals;
   int lgauss = FALSE;
 
-  nx = pfi->dnum[0];
-  ny = pfi->dnum[1];
+  int nx = pfi->dnum[0];
+  int ny = pfi->dnum[1];
 
-  xvals = (double*) Malloc(nx*sizeof(double));
-  yvals = (double*) Malloc(ny*sizeof(double));
+  double *xvals = (double*) Malloc(nx*sizeof(double));
+  double *yvals = (double*) Malloc(ny*sizeof(double));
 
   get_dim_vals(pfi, xvals, nx, 0);
   get_dim_vals(pfi, yvals, ny, 1);
@@ -153,22 +149,18 @@ int define_grid(dsets_t *pfi)
   Free(xvals);
   Free(yvals);
   
-  return (gridID);
+  return gridID;
 }
 
 static
 int define_level(dsets_t *pfi, int nlev)
 {
   int zaxisID = -1;
-  int nz;
-
-  nz = pfi->dnum[2];
+  int nz = pfi->dnum[2];
 
   if ( nz )
     {
-      double *zvals = NULL;
-
-      zvals = (double*) Malloc(nz*sizeof(double));
+      double *zvals = (double*) Malloc(nz*sizeof(double));
 
       get_dim_vals(pfi, zvals, nz, 2);
 
@@ -193,75 +185,64 @@ int define_level(dsets_t *pfi, int nlev)
       zaxisDefLevels(zaxisID, &level);
     }
 
-  return (zaxisID);
+  return zaxisID;
 }
 
 
 void *Importbinary(void *argument)
 {
-  int streamID;
-  int gridID = -1, zaxisID, zaxisIDsfc, taxisID, vlistID;
   int i;
   int nmiss = 0, n_nan;
   int ivar;
   int varID = -1, levelID, tsID;
   int gridsize;
-  int  status;
   int datatype;
   dsets_t pfi;
   int vdate, vtime;
   int tcur, told,fnum;
   int tmin=0,tmax=0;
   char *ch = NULL;
-  int nvars, nlevels, nrecs;
-  int recID;
+  int nlevels;
   int e, flag;
   size_t rc, recsize;
   int recoffset;
   char *rec = NULL;
-  struct gavar *pvar;
   struct dt dtim, dtimi;
   double missval;
   double fmin, fmax;
   double *array;
   double sfclevel = 0;
-  int *recVarID, *recLevelID;
-  int *var_zaxisID;
-  int *var_dfrm = NULL;
   char vdatestr[32], vtimestr[32];	  
 
   cdoInitialize(argument);
 
   dsets_init(&pfi);
 
-  status = read_gradsdes(cdoStreamName(0)->args, &pfi);
+  int status = read_gradsdes(cdoStreamName(0)->args, &pfi);
   if ( cdoVerbose ) fprintf(stderr, "status %d\n", status);
   //if ( status ) cdoAbort("Open failed on %s!", pfi.name);
   if ( status ) cdoAbort("Open failed!");
 
-  nrecs = pfi.trecs;
-  nvars = pfi.vnum;
-  pvar  = pfi.pvar1;
+  int nrecs = pfi.trecs;
+  int nvars = pfi.vnum;
+  struct gavar *pvar  = pfi.pvar1;
 
   if ( nvars == 0 ) cdoAbort("No variables found!");
 
-  gridID = define_grid(&pfi);
-  if ( cdoVerbose ) gridPrint(gridID, gridID, 1);
-
-  zaxisID = define_level(&pfi, 0);
-  if ( cdoVerbose ) zaxisPrint(zaxisID, zaxisID);
+  int gridID = define_grid(&pfi);
+  int zaxisID = define_level(&pfi, 0);
 
-  zaxisIDsfc = zaxisCreate(ZAXIS_SURFACE, 1);
+  int zaxisIDsfc = zaxisCreate(ZAXIS_SURFACE, 1);
   zaxisDefLevels(zaxisIDsfc, &sfclevel);
 
-  vlistID = vlistCreate();
+  int vlistID = vlistCreate();
 
-  var_zaxisID = (int*) Malloc(nvars*sizeof(int));
-  recVarID    = (int*) Malloc(nrecs*sizeof(int));
-  recLevelID  = (int*) Malloc(nrecs*sizeof(int));
-  var_dfrm    = (int*) Malloc(nrecs*sizeof(int));
+  int *var_zaxisID = (int*) Malloc(nvars*sizeof(int));
+  int *recVarID    = (int*) Malloc(nrecs*sizeof(int));
+  int *recLevelID  = (int*) Malloc(nrecs*sizeof(int));
+  int *var_dfrm    = (int*) Malloc(nrecs*sizeof(int));
 
-  recID = 0;
+  int recID = 0;
   for ( ivar = 0; ivar < nvars; ++ivar )
     {
       /*
@@ -313,26 +294,26 @@ void *Importbinary(void *argument)
       }
 
       missval  = pfi.undef;
-      datatype = DATATYPE_FLT32;
+      datatype = CDI_DATATYPE_FLT32;
 
       if      ( pvar->dfrm ==  1 ) {
-	datatype = DATATYPE_UINT8;
+	datatype = CDI_DATATYPE_UINT8;
 	if ( missval < 0 || missval > 255 ) missval = 255;
       }
       else if ( pvar->dfrm ==  2 )  {
-	datatype = DATATYPE_UINT16;
+	datatype = CDI_DATATYPE_UINT16;
 	if ( missval < 0 || missval > 65535 ) missval = 65535;
       }
       else if ( pvar->dfrm == -2 )  {
-	datatype = DATATYPE_INT16;
+	datatype = CDI_DATATYPE_INT16;
 	if ( missval < -32768 || missval > 32767 ) missval = -32768;
       }
       else if ( pvar->dfrm ==  4 )  {
-	datatype = DATATYPE_INT32;
+	datatype = CDI_DATATYPE_INT32;
 	if ( missval < -2147483648 || missval > 2147483647 ) missval = -2147483646;
       }
       else if ( pfi.flt64 )
-	datatype = DATATYPE_FLT64;
+	datatype = CDI_DATATYPE_FLT64;
       
       vlistDefVarDatatype(vlistID, varID, datatype);
       vlistDefVarMissval(vlistID, varID, missval);
@@ -351,13 +332,13 @@ void *Importbinary(void *argument)
 
   int calendar = CALENDAR_STANDARD;
 
-  taxisID = taxisCreate(TAXIS_RELATIVE);
+  int taxisID = taxisCreate(TAXIS_RELATIVE);
 
   taxisDefCalendar(taxisID, calendar);
 
   vlistDefTaxis(vlistID, taxisID);
 
-  streamID = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID, vlistID);
 
@@ -480,7 +461,7 @@ void *Importbinary(void *argument)
 	  taxisDefVtime(taxisID, vtime);
 	  streamDefTimestep(streamID, tsID);
 
-	  for ( recID = 0; recID < nrecs; ++recID )
+	  for ( int recID = 0; recID < nrecs; ++recID )
 	    {
 	      /* record size depends on data type */
 	      if (var_dfrm[recID] == 1) {
diff --git a/src/Importcmsaf.c b/src/Importcmsaf.c
index 50fea96..c27b4f4 100644
--- a/src/Importcmsaf.c
+++ b/src/Importcmsaf.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -25,11 +25,11 @@
 #  include "hdf5.h"
 #endif
 
-#include <ctype.h>
 
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
+#include "grid.h"
 #include "pstream.h"
 
 
@@ -133,25 +133,22 @@ static
 double det_lon_atovs(double r, double r0, double lts, double c, double re)
 {
   const double pi = M_PI;
-  double xla;
 
-  xla=(r-r0)*c/re/cos(lts*pi/180.); /* longitude */
+  double xla=(r-r0)*c/re/cos(lts*pi/180.); /* longitude */
   xla=180.*xla/pi;
 
-  return (xla);
+  return xla;
 }
 
 static
 double det_lat_atovs(double s, double s0, double lts, double c, double re)
 {
   const double pi = M_PI;
-  double siphi;
-  double phi;
 
-  siphi=(s-s0)*c*cos(lts*pi/180.)/re;
-  phi=180.*asin(siphi)/pi; /* latitude */
+  double siphi=(s-s0)*c*cos(lts*pi/180.)/re;
+  double phi=180.*asin(siphi)/pi; /* latitude */
 
-  return (phi);
+  return phi;
 }
 
 static
@@ -163,20 +160,19 @@ int defLonLatGrid(int nx, int ny, double c0, double lts, double re)
   double r0, s0;
   double r, s;
   double xla, phi;
-  double *xvals, *yvals, *xbounds, *ybounds;
 
   get_grid_info(c0, re, &nrx, &nry, &r0, &s0, &c);
 
   if ( nx != nrx || ny != nry )
     {
       printf("nrx=%d nry=%d\n", nrx, nry);
-      return(-1);
+      return -1;
     }
 
-  xvals = (double*) Malloc(nx*sizeof(double));
-  yvals = (double*) Malloc(ny*sizeof(double));
-  xbounds = (double*) Malloc(nx*2*sizeof(double));
-  ybounds = (double*) Malloc(nx*2*sizeof(double));
+  double *xvals = (double*) Malloc(nx*sizeof(double));
+  double *yvals = (double*) Malloc(ny*sizeof(double));
+  double *xbounds = (double*) Malloc(nx*2*sizeof(double));
+  double *ybounds = (double*) Malloc(nx*2*sizeof(double));
 
   for ( i = 0; i < nx; ++i )
     {
@@ -216,7 +212,7 @@ int defLonLatGrid(int nx, int ny, double c0, double lts, double re)
   Free(xbounds);
   Free(ybounds);
 
-  return (gridID);
+  return gridID;
 }
 
 static
@@ -233,18 +229,15 @@ int defSinusoidalGrid(int nx, int ny, double xmin, double xmax, double ymin, dou
   double *yvals = (double*) Malloc(ny*sizeof(double));
 
   for ( int i = 0; i < nx; ++i )
-    {
-      xvals[i] = xmin + i*dx + dx/2;
-      /* printf("x[%d]=%g\n", i, xvals[i]); */
-    }
+    xvals[i] = xmin + i*dx + dx/2;
 
   for ( int i = 0; i < ny; ++i )
-    {
-      yvals[i] = ymax - i*dy - dy/2;
-      /* printf("y[%d]=%g\n", i, yvals[i]); */
-    }
+    yvals[i] = ymax - i*dy - dy/2;
+
+  int gridID = gridCreate(GRID_PROJECTION, nx*ny);
+
+  grid_def_param_sinu(gridID);
 
-  int gridID = gridCreate(GRID_SINUSOIDAL, nx*ny);
   gridDefXsize(gridID, nx);
   gridDefYsize(gridID, ny);
   gridDefXvals(gridID, xvals);
@@ -253,7 +246,7 @@ int defSinusoidalGrid(int nx, int ny, double xmin, double xmax, double ymin, dou
   Free(xvals);
   Free(yvals);
 
-  return (gridID);
+  return gridID;
 }
 
 static
@@ -266,29 +259,24 @@ int defLaeaGrid(int nx, int ny, double xmin, double xmax, double ymin, double ym
   double *yvals = (double*) Malloc(ny*sizeof(double));
 
   for ( int i = 0; i < nx; ++i )
-    {
-      xvals[i] = xmin + i*dx + dx/2;
-      /* printf("x[%d]=%g\n", i, xvals[i]); */
-    }
+    xvals[i] = xmin + i*dx + dx/2;
 
   for ( int i = 0; i < ny; ++i )
-    {
-      yvals[i] = ymax - i*dy - dy/2;
-      /* printf("y[%d]=%g\n", i, yvals[i]); */
-    }
+    yvals[i] = ymax - i*dy - dy/2;
+
+  int gridID = gridCreate(GRID_PROJECTION, nx*ny);
 
-  int gridID = gridCreate(GRID_LAEA, nx*ny);
   gridDefXsize(gridID, nx);
   gridDefYsize(gridID, ny);
   gridDefXvals(gridID, xvals);
   gridDefYvals(gridID, yvals);
 
-  gridDefLaea(gridID, a, lon0, lat0);
+  grid_def_param_laea(gridID, a, lon0, lat0);
 
   Free(xvals);
   Free(yvals);
 
-  return (gridID);
+  return gridID;
 }
 
 static
@@ -342,7 +330,7 @@ int scan_pcs_def(char *pcs_def, char proj[128], double *a, double *lon0, double
 	}
     }
 
-  return (nfound);
+  return nfound;
 }
 
 static
@@ -606,7 +594,7 @@ int read_geolocation(hid_t loc_id, int nx, int ny, int lprojtype)
       gridID = defLonLatGrid(nx, ny, c0, lts, re);
     }
 
-  return (gridID);
+  return gridID;
 }
 
 static
@@ -747,7 +735,7 @@ int read_region(hid_t loc_id, int nx, int ny)
 			   dx, dy, a, lon0, lat0);
     }
 
-  return (gridID);
+  return gridID;
 }
 
 static
@@ -776,7 +764,7 @@ void read_dataset(hid_t loc_id, const char *name, void *opdata)
   int i, k;
   int ftype = 0;
   int len;
-  int dtype = DATATYPE_FLT32;
+  int dtype = CDI_DATATYPE_FLT32;
   char attstring[4096];     /* Buffer to read string attribute back */
   char varname[CDI_MAX_NAME];
   short *mask = NULL;
@@ -813,14 +801,14 @@ void read_dataset(hid_t loc_id, const char *name, void *opdata)
   }
   */
   native_type = H5Tget_native_type(type_id, H5T_DIR_ASCEND);
-  if      ( H5Tequal(native_type, H5T_NATIVE_SCHAR)  > 0 ) {ftype=0; dtype = DATATYPE_INT8;}
-  else if ( H5Tequal(native_type, H5T_NATIVE_UCHAR)  > 0 ) {ftype=0; dtype = DATATYPE_UINT8;}
-  else if ( H5Tequal(native_type, H5T_NATIVE_SHORT)  > 0 ) {ftype=0; dtype = DATATYPE_INT16;}
-  else if ( H5Tequal(native_type, H5T_NATIVE_USHORT) > 0 ) {ftype=0; dtype = DATATYPE_UINT16;}
-  else if ( H5Tequal(native_type, H5T_NATIVE_INT)    > 0 ) {ftype=0; dtype = DATATYPE_INT32;}
-  else if ( H5Tequal(native_type, H5T_NATIVE_UINT)   > 0 ) {ftype=0; dtype = DATATYPE_UINT32;}
-  else if ( H5Tequal(native_type, H5T_NATIVE_FLOAT)  > 0 ) {ftype=1; dtype = DATATYPE_FLT32;}
-  else if ( H5Tequal(native_type, H5T_NATIVE_DOUBLE) > 0 ) {ftype=1; dtype = DATATYPE_FLT64;}
+  if      ( H5Tequal(native_type, H5T_NATIVE_SCHAR)  > 0 ) {ftype=0; dtype = CDI_DATATYPE_INT8;}
+  else if ( H5Tequal(native_type, H5T_NATIVE_UCHAR)  > 0 ) {ftype=0; dtype = CDI_DATATYPE_UINT8;}
+  else if ( H5Tequal(native_type, H5T_NATIVE_SHORT)  > 0 ) {ftype=0; dtype = CDI_DATATYPE_INT16;}
+  else if ( H5Tequal(native_type, H5T_NATIVE_USHORT) > 0 ) {ftype=0; dtype = CDI_DATATYPE_UINT16;}
+  else if ( H5Tequal(native_type, H5T_NATIVE_INT)    > 0 ) {ftype=0; dtype = CDI_DATATYPE_INT32;}
+  else if ( H5Tequal(native_type, H5T_NATIVE_UINT)   > 0 ) {ftype=0; dtype = CDI_DATATYPE_UINT32;}
+  else if ( H5Tequal(native_type, H5T_NATIVE_FLOAT)  > 0 ) {ftype=1; dtype = CDI_DATATYPE_FLT32;}
+  else if ( H5Tequal(native_type, H5T_NATIVE_DOUBLE) > 0 ) {ftype=1; dtype = CDI_DATATYPE_FLT64;}
   else
     {
       cdoWarning("Dataset %s skipped, unsupported native datatype!", varname);
@@ -1063,7 +1051,7 @@ void read_dataset(hid_t loc_id, const char *name, void *opdata)
 
       if ( ftype )
 	{
-	  if ( dtype == DATATYPE_FLT32 )
+	  if ( dtype == CDI_DATATYPE_FLT32 )
 	    {
 	      float *farray;
 	      int i;
@@ -1137,13 +1125,13 @@ void read_dataset(hid_t loc_id, const char *name, void *opdata)
 	cdoPrint("Dataset %s: dtype = %d  minval = %g  maxval = %g  missval = %g",
 		 varname, dtype,  minval, maxval, missval);
 
-      if ( dtype == DATATYPE_UINT8 )
+      if ( dtype == CDI_DATATYPE_UINT8 )
 	{
-	  if ( minval >= 0 && maxval <= 127 ) dtype = DATATYPE_INT8;
+	  if ( minval >= 0 && maxval <= 127 ) dtype = CDI_DATATYPE_INT8;
 	}
-      else if ( dtype == DATATYPE_UINT16 )
+      else if ( dtype == CDI_DATATYPE_UINT16 )
 	{
-	  if ( minval >= 0 && maxval <= 32767 ) dtype = DATATYPE_INT16;
+	  if ( minval >= 0 && maxval <= 32767 ) dtype = CDI_DATATYPE_INT16;
 	}
 
       laddoffset   = IS_NOT_EQUAL(addoffset,   0);
@@ -1183,10 +1171,10 @@ void read_dataset(hid_t loc_id, const char *name, void *opdata)
 	{
 	  if ( ! (missval < minval || missval > maxval) )
 	    {
-	      if ( DBL_IS_EQUAL(missval, 255.) && dtype == DATATYPE_UINT8 )
+	      if ( DBL_IS_EQUAL(missval, 255.) && dtype == CDI_DATATYPE_UINT8 )
 		{
 		  missval = -255;
-		  dtype   = DATATYPE_INT16;
+		  dtype   = CDI_DATATYPE_INT16;
 		  cdoPrint("Dataset %s: changed missval to %g and datatype to INT16!",
 			   varname, missval);
 
@@ -1317,17 +1305,17 @@ void get_global_att(hid_t file_id, const char *obj_path, int vlistID)
       if ( type_class == H5T_STRING )
 	{
 	  H5Aread(attr, atype_mem, attstring);
-	  vlistDefAttTxt(vlistID, CDI_GLOBAL, attname, (int)strlen(attstring), attstring);
+	  cdiDefAttTxt(vlistID, CDI_GLOBAL, attname, (int)strlen(attstring), attstring);
 	}
       else if ( type_class == H5T_INTEGER )
 	{
 	  H5Aread(attr, H5T_NATIVE_INT, &attint);
-	  vlistDefAttInt(vlistID, CDI_GLOBAL, attname, DATATYPE_INT32, 1, &attint);
+	  cdiDefAttInt(vlistID, CDI_GLOBAL, attname, CDI_DATATYPE_INT32, 1, &attint);
 	}
       else if ( type_class == H5T_FLOAT )
 	{
 	  H5Aread(attr, H5T_NATIVE_DOUBLE, &attflt);
-	  vlistDefAttFlt(vlistID, CDI_GLOBAL, attname, DATATYPE_FLT64, 1, &attflt);
+	  cdiDefAttFlt(vlistID, CDI_GLOBAL, attname, CDI_DATATYPE_FLT64, 1, &attflt);
 	}
       H5Tclose(atype_mem);
       H5Aclose(attr);
@@ -1347,17 +1335,17 @@ int get_vdate(int vlistID)
   char name[CDI_MAX_NAME];
   char attstr[CDI_MAX_NAME];
 
-  vlistInqNatts(vlistID, CDI_GLOBAL, &natts);
+  cdiInqNatts(vlistID, CDI_GLOBAL, &natts);
 
   for ( i = 0; i < natts; ++i )
     {
-      vlistInqAtt(vlistID, CDI_GLOBAL, i, name, &type, &len);
-      if ( type == DATATYPE_TXT )
+      cdiInqAtt(vlistID, CDI_GLOBAL, i, name, &type, &len);
+      if ( type == CDI_DATATYPE_TXT )
 	{
 	  if ( strcmp(name, "DateAndTime") == 0 ||
 	       strcmp(name, "Date_Time") == 0 )
 	    {
-	      vlistInqAttTxt(vlistID, CDI_GLOBAL, name, CDI_MAX_NAME, attstr);
+	      cdiInqAttTxt(vlistID, CDI_GLOBAL, name, CDI_MAX_NAME, attstr);
 	      if ( len > 8 ) len = 8;
 	      attstr[len] = 0;
 	      vdate = atoi(attstr);
@@ -1366,7 +1354,7 @@ int get_vdate(int vlistID)
 	}
     }
 
-  return (vdate);
+  return vdate;
 }
 
 static
@@ -1423,7 +1411,7 @@ void *Importcmsaf(void *argument)
   cdoInitialize(argument);
 
   if ( cdoDefaultFileType == CDI_UNDEFID )
-    cdoDefaultFileType = FILETYPE_NC;
+    cdoDefaultFileType = CDI_FILETYPE_NC;
 
 #if defined(HAVE_LIBHDF5)
   dsets_init(&dsets);
@@ -1540,7 +1528,7 @@ void *Importcmsaf(void *argument)
       if ( dsets.obj[ivar].units )
 	vlistDefVarUnits(vlistID, varID,  dsets.obj[ivar].units);
       if ( dsets.obj[ivar].title )
-	vlistDefAttTxt(vlistID, varID, "title", (int)strlen(dsets.obj[ivar].title),
+	cdiDefAttTxt(vlistID, varID, "title", (int)strlen(dsets.obj[ivar].title),
 		       dsets.obj[ivar].title);
 
       /*
diff --git a/src/Importobs.c b/src/Importobs.c
index fd38bec..91605f5 100644
--- a/src/Importobs.c
+++ b/src/Importobs.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -15,7 +15,6 @@
   GNU General Public License for more details.
 */
 
-#include <ctype.h>
 
 #include <cdi.h>
 #include "cdo.h"
@@ -41,20 +40,17 @@ void init_vars(int vlistID, int gridID, int zaxisID, int nvars)
       vlistDefVarParam(vlistID, varID, cdiEncodeParam(code[i], 255, 255));
       vlistDefVarName(vlistID, varID, name[i]);
       vlistDefVarUnits(vlistID, varID, units[i]);
-      vlistDefVarDatatype(vlistID, varID, DATATYPE_FLT32);
+      vlistDefVarDatatype(vlistID, varID, CDI_DATATYPE_FLT32);
     }
 }
 
 static
 void init_data(int vlistID, int nvars, double *data[])
 {
-  int gridsize;
-  double missval;
-
   for ( int varID = 0; varID < nvars; ++varID )
     {
-      gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
-      missval  = vlistInqVarMissval(vlistID, varID);
+      int gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
+      double missval  = vlistInqVarMissval(vlistID, varID);
       
       for ( int i = 0; i < gridsize; ++i ) data[varID][i] = missval;
     } 
@@ -63,18 +59,14 @@ void init_data(int vlistID, int nvars, double *data[])
 static
 void write_data(int streamID, int vlistID, int nvars, double *data[])
 {
-  int nmiss;
-  int gridsize;
-  double missval;
-
   for ( int varID = 0; varID < nvars; ++varID )
     {
-      gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
-      missval  = vlistInqVarMissval(vlistID, varID);
+      int gridsize = gridInqSize(vlistInqVarGrid(vlistID, varID));
+      double missval  = vlistInqVarMissval(vlistID, varID);
       
       streamDefRecord(streamID, varID, 0);
 
-      nmiss = 0;
+      int nmiss = 0;
       for ( int i = 0; i < gridsize; ++i )
 	if ( DBL_IS_EQUAL(data[varID][i], missval) ) nmiss++;
       
@@ -90,7 +82,7 @@ int getDate(const char *name)
   int date = 0;
   if ( pname ) date = atoi(pname+1);
 
-  return(date);
+  return date;
 }
 
 #define  MAX_LINE_LEN  4096
diff --git a/src/Info.c b/src/Info.c
index e8eb901..f14adb4 100644
--- a/src/Info.c
+++ b/src/Info.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -34,13 +34,12 @@ void printMap(int nlon, int nlat, double *array, double missval, double min, dou
   /* source code from PINGO */
   int ilon, ilat, i;
   double x, a, b;
-  double step;
   double level[10];
   int min_n, max_n;
   int bmin = 1, bmax = 1;
   unsigned char c;
 
-  step = (max - min) / 10;
+  double step = (max - min) / 10;
 
   if ( IS_NOT_EQUAL(step, 0) )
     {
@@ -242,22 +241,15 @@ void printMap(int nlon, int nlat, double *array, double missval, double min, dou
 
 void *Info(void *argument)
 {
-  int i;
-  int varID, recID;
-  int gridsize = 0;
-  int gridID, zaxisID;
-  int code, param;
+  int fpeRaised = 0;
+  int varID, levelID;
   int nrecs;
-  int levelID;
   int nmiss;
-  int number;
   int ivals = 0, nvals = 0;
   int imiss = 0;
   char varname[CDI_MAX_NAME];
   char paramstr[32];
   char vdatestr[32], vtimestr[32];
-  double missval;
-  double level;
   double arrmin = 0, arrmax = 0, arrmean = 0;
   // double arrvar = 0;
 
@@ -285,10 +277,10 @@ void *Info(void *argument)
 
       if ( vlistNvars(vlistID) == 0 ) continue;
 
-      gridsize = vlistGridsizeMax(vlistID);
-      if ( vlistNumber(vlistID) != CDI_REAL ) gridsize *= 2;
+      int gridsizemax = vlistGridsizeMax(vlistID);
+      if ( vlistNumber(vlistID) != CDI_REAL ) gridsizemax *= 2;
 
-      double *array = (double*) Malloc(gridsize*sizeof(double));
+      double *array = (double*) Malloc(gridsizemax*sizeof(double));
 
       int indg = 0;
       int tsID = 0;
@@ -301,7 +293,7 @@ void *Info(void *argument)
 	  date2str(vdate, vdatestr, sizeof(vdatestr));
 	  time2str(vtime, vtimestr, sizeof(vtimestr));
 
-	  for ( recID = 0; recID < nrecs; recID++ )
+	  for ( int recID = 0; recID < nrecs; recID++ )
 	    {
 	      if ( (tsID == 0 && recID == 0) || operatorID == MAP )
 		{
@@ -322,13 +314,14 @@ void *Info(void *argument)
 	      streamReadRecord(streamID, array, &nmiss);
 
 	      indg += 1;
-	      param    = vlistInqVarParam(vlistID, varID);
-	      code     = vlistInqVarCode(vlistID, varID);
-	      gridID   = vlistInqVarGrid(vlistID, varID);
-	      zaxisID  = vlistInqVarZaxis(vlistID, varID);
-	      missval  = vlistInqVarMissval(vlistID, varID);
-	      gridsize = gridInqSize(gridID);
-	      number   = vlistInqVarNumber(vlistID, varID);
+	      int param    = vlistInqVarParam(vlistID, varID);
+	      int code     = vlistInqVarCode(vlistID, varID);
+	      int gridID   = vlistInqVarGrid(vlistID, varID);
+	      int zaxisID  = vlistInqVarZaxis(vlistID, varID);
+	      int gridsize = gridInqSize(gridID);
+	      int number   = vlistInqVarNumber(vlistID, varID);
+	      double level = cdoZaxisInqLevel(zaxisID, levelID);
+	      double missval = vlistInqVarMissval(vlistID, varID);
 
 	      cdiParamToString(param, paramstr, sizeof(paramstr));
 
@@ -341,20 +334,23 @@ void *Info(void *argument)
 	      fprintf(stdout, ":");
 	      reset_text_color(stdout);
 	      
-	      set_text_color(stdout, RESET, BLUE);
+              set_text_color(stdout, RESET, MAGENTA);
 	      fprintf(stdout, "%s %s ", vdatestr, vtimestr);
-	      level = zaxisInqLevel(zaxisID, levelID);
+	      reset_text_color(stdout);
+
+	      set_text_color(stdout, RESET, GREEN);
 	      fprintf(stdout, "%7g ", level);
 	      fprintf(stdout, "%8d %7d ", gridsize, nmiss);
-	      reset_text_color(stdout);
 		
 	      set_text_color(stdout, RESET, BLACK);
 	      fprintf(stdout, ":");
 	      reset_text_color(stdout);
 
+              set_text_color(stdout, RESET, BLUE);
 	      if ( /* gridInqType(gridID) == GRID_SPECTRAL || */
 		   (gridsize == 1 && nmiss == 0 && number == CDI_REAL) )
 		{
+                  //fpeRaised = array_minmaxmean_val(gridsize, array, NULL, NULL, NULL);
 		  fprintf(stdout, "            %#12.5g            ", array[0]);
 		}
 	      else
@@ -368,7 +364,7 @@ void *Info(void *argument)
 			  //arrvar  = 0;
 			  arrmin  =  1.e300;
 			  arrmax  = -1.e300;
-			  for ( i = 0; i < gridsize; ++i )
+			  for ( int i = 0; i < gridsize; ++i )
 			    {
 			      if ( !DBL_IS_EQUAL(array[i], missval) )
 				{
@@ -379,30 +375,19 @@ void *Info(void *argument)
 				  ivals++;
 				}
 			    }
+                          fpeRaised = 0;
 			  imiss = gridsize - ivals;
 			  nvals = ivals;
+                          if ( nvals ) arrmean /= nvals;
 			}
 		      else
 			{
-			  arrmean = array[0];
-			  //arrvar  = array[0];
-			  arrmin  = array[0];
-			  arrmax  = array[0];
-                          // #pragma omp parallel for default(none) shared(arrmin, arrmax, array, gridsize) reduction(+:arrmean, arrvar)
-                          // #pragma omp simd reduction(+:arrmean) reduction(min:arrmin) reduction(max:arrmax) aligned(array:16)
-			  for ( i = 1; i < gridsize; i++ )
-			    {
-			      if ( array[i] < arrmin ) arrmin = array[i];
-			      if ( array[i] > arrmax ) arrmax = array[i];
-			      arrmean += array[i];
-			      // arrvar  += array[i]*array[i];
-			    }
+                          fpeRaised = array_minmaxmean_val(gridsize, array, &arrmin, &arrmax, &arrmean);
 			  nvals = gridsize;
 			}
 
 		      if ( nvals )
 			{
-			  arrmean = arrmean/nvals;
 			  // arrvar  = arrvar/nvals - arrmean*arrmean;
 			  fprintf(stdout, "%#12.5g%#12.5g%#12.5g", arrmin, arrmean, arrmax);
 			}
@@ -418,7 +403,7 @@ void *Info(void *argument)
 		      arrsum_r = 0;
 		      arrsum_i = 0;
 		      
-		      for ( i = 0; i < gridsize; i++ )
+		      for ( int i = 0; i < gridsize; i++ )
 			{
 			  if ( !DBL_IS_EQUAL(array[i*2],   missval) && 
 			       !DBL_IS_EQUAL(array[i*2+1], missval) )
@@ -429,6 +414,7 @@ void *Info(void *argument)
 			      nvals_i++;
 			    }
 			}
+                      fpeRaised = 0;
 
 		      imiss = gridsize - nvals_r;
 
@@ -437,6 +423,7 @@ void *Info(void *argument)
 		      fprintf(stdout, "   -  (%#12.5g,%#12.5g)  -", arrmean_r, arrmean_i);
 		    }
 		}
+	      reset_text_color(stdout);
 
 	      set_text_color(stdout, RESET, BLACK);
 	      fprintf(stdout, " : ");
@@ -461,14 +448,14 @@ void *Info(void *argument)
 	      fprintf(stdout, "\n");
 
 	      if ( imiss != nmiss && nmiss > 0 )
-		fprintf(stdout, "Found %d of %d missing values!\n", imiss, nmiss);
+		cdoPrint("Found %d of %d missing values!", imiss, nmiss);
+
+              if ( fpeRaised > 0 ) cdoWarning("floating-point exception reported: %s!", fpe_errstr(fpeRaised));
 
 	      if ( operatorID == MAP )
-		{
-		  int nlon, nlat;
-		  
-		  nlon = gridInqXsize(gridID);
-		  nlat = gridInqYsize(gridID);
+		{		  
+		  int nlon = gridInqXsize(gridID);
+		  int nlat = gridInqYsize(gridID);
 
 		  if ( gridInqType(gridID) == GRID_GAUSSIAN    ||
 		       gridInqType(gridID) == GRID_LONLAT      ||
diff --git a/src/Input.c b/src/Input.c
index 4f632e0..d7714d4 100644
--- a/src/Input.c
+++ b/src/Input.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -58,7 +58,7 @@ void *Input(void *argument)
   int vlistID = -1;
   int i;
   int code = 0, level = 0, date = 0, time = 0, nlon = 0, nlat = 0;
-  int output_filetype = FILETYPE_GRB;
+  int output_filetype = CDI_FILETYPE_GRB;
   int ihead[8];
   double missval = 0;
   double levels[1];
@@ -102,7 +102,6 @@ void *Input(void *argument)
 	  gridsize = gridInqSize(gridID);
 	  date     = 0;
 	  time     = 0;
-
 	  
 	  if ( nrecs == 0 )
 	    array = (double*) Malloc(gridsize*nlevs*sizeof(double));
@@ -121,7 +120,7 @@ void *Input(void *argument)
       else if ( operatorID == INPUTEXT )
 	{
 	  output_filetype = cdoDefaultFileType;
-	  if ( output_filetype == CDI_UNDEFID ) output_filetype = FILETYPE_EXT;
+	  if ( output_filetype == CDI_UNDEFID ) output_filetype = CDI_FILETYPE_EXT;
 
 	  cdoPrint("Enter header (code,level,date,time,nlon,nlat,dispo1,dispo2)"
 		   " of record %d (or EOF(=^D))!", nrecs+1);
@@ -165,7 +164,7 @@ void *Input(void *argument)
       else if ( operatorID == INPUTSRV )
 	{
 	  output_filetype = cdoDefaultFileType;
-	  if ( output_filetype == CDI_UNDEFID ) output_filetype = FILETYPE_SRV;
+	  if ( output_filetype == CDI_UNDEFID ) output_filetype = CDI_FILETYPE_SRV;
 	  
 	  cdoPrint("Enter header (code,level,date,time,nlon,nlat,dispo1,dispo2)"
 		   " of record %d (or EOF(=^D))!", nrecs+1);
diff --git a/src/Intgrid.c b/src/Intgrid.c
index ccdfccc..0d2a9e9 100644
--- a/src/Intgrid.c
+++ b/src/Intgrid.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -32,44 +32,38 @@
 
 int genThinoutGrid(int gridID1, int xinc, int yinc)
 {
-  int ilon, ilat, olon, olat;
-  int gridID2, gridtype;
-  int nlon1, nlat1;
-  int gridsize2, nlon2, nlat2;
-  double *xvals1, *yvals1, *xvals2, *yvals2;
-
-  gridtype = gridInqType(gridID1);
-  nlon1 = gridInqXsize(gridID1);
-  nlat1 = gridInqYsize(gridID1);
-
-  nlon2 = nlon1/xinc;
-  nlat2 = nlat1/yinc;
+  int gridtype = gridInqType(gridID1);
+  int nlon1 = gridInqXsize(gridID1);
+  int nlat1 = gridInqYsize(gridID1);
+
+  int nlon2 = nlon1/xinc;
+  int nlat2 = nlat1/yinc;
   if ( nlon1%xinc ) nlon2++;
   if ( nlat1%yinc ) nlat2++;
-  gridsize2 = nlon2*nlat2;
+  int gridsize2 = nlon2*nlat2;
 
-  gridID2 = gridCreate(GRID_LONLAT, gridsize2);
+  int gridID2 = gridCreate(GRID_LONLAT, gridsize2);
   gridDefXsize(gridID2, nlon2);
   gridDefYsize(gridID2, nlat2);
 
   if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_LONLAT )
     {
-      xvals1 = (double*) Malloc(nlon1*sizeof(double));
-      yvals1 = (double*) Malloc(nlat1*sizeof(double));
-      xvals2 = (double*) Malloc(nlon2*sizeof(double));
-      yvals2 = (double*) Malloc(nlat2*sizeof(double));
+      double *xvals1 = (double*) Malloc(nlon1*sizeof(double));
+      double *yvals1 = (double*) Malloc(nlat1*sizeof(double));
+      double *xvals2 = (double*) Malloc(nlon2*sizeof(double));
+      double *yvals2 = (double*) Malloc(nlat2*sizeof(double));
       gridInqXvals(gridID1, xvals1);
       gridInqYvals(gridID1, yvals1);
 
-      olat = 0;
-      for ( ilat = 0; ilat < nlat1; ilat+=yinc )
+      int olat = 0;
+      for ( int ilat = 0; ilat < nlat1; ilat+=yinc )
 	{
 	  yvals2[olat] = yvals1[ilat];
 	  olat++;
 	}
 
-      olon = 0;
-      for ( ilon = 0; ilon < nlon1; ilon+=xinc )
+      int olon = 0;
+      for ( int ilon = 0; ilon < nlon1; ilon+=xinc )
 	{
 	  xvals2[olon] = xvals1[ilon];
 	  olon++;
@@ -77,6 +71,11 @@ int genThinoutGrid(int gridID1, int xinc, int yinc)
 
       gridDefXvals(gridID2, xvals2);
       gridDefYvals(gridID2, yvals2);
+
+      Free(xvals1);
+      Free(yvals1);
+      Free(xvals2);
+      Free(yvals2);
     }
   else
     {
@@ -90,33 +89,29 @@ int genThinoutGrid(int gridID1, int xinc, int yinc)
 int genBoxavgGrid(int gridID1, int xinc, int yinc)
 {
   int i, j, i1;
-  int gridID2, gridtype;
-  int nlon1, nlat1;
-  int gridsize2, nlon2, nlat2;
-  double *xvals1, *yvals1, *xvals2, *yvals2;
-  double *grid1_corner_lon = NULL, *grid1_corner_lat = NULL;
-  double *grid2_corner_lon = NULL, *grid2_corner_lat = NULL;
-
-  gridtype = gridInqType(gridID1);
-  nlon1 = gridInqXsize(gridID1);
-  nlat1 = gridInqYsize(gridID1);
-
-  nlon2 = nlon1/xinc;
-  nlat2 = nlat1/yinc;
+
+  int gridtype = gridInqType(gridID1);
+  int nlon1 = gridInqXsize(gridID1);
+  int nlat1 = gridInqYsize(gridID1);
+
+  int nlon2 = nlon1/xinc;
+  int nlat2 = nlat1/yinc;
   if ( nlon1%xinc ) nlon2++;
   if ( nlat1%yinc ) nlat2++;
-  gridsize2 = nlon2*nlat2;
+  int gridsize2 = nlon2*nlat2;
 
-  gridID2 = gridCreate(GRID_LONLAT, gridsize2);
+  int gridID2 = gridCreate(GRID_LONLAT, gridsize2);
   gridDefXsize(gridID2, nlon2);
   gridDefYsize(gridID2, nlat2);
 
   if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_LONLAT )
     {
-      xvals1 = (double*) Malloc(nlon1*sizeof(double));
-      yvals1 = (double*) Malloc(nlat1*sizeof(double));
-      xvals2 = (double*) Malloc(nlon2*sizeof(double));
-      yvals2 = (double*) Malloc(nlat2*sizeof(double));
+      double *grid1_corner_lon = NULL, *grid1_corner_lat = NULL;
+      double *grid2_corner_lon = NULL, *grid2_corner_lat = NULL;
+      double *xvals1 = (double*) Malloc(nlon1*sizeof(double));
+      double *yvals1 = (double*) Malloc(nlat1*sizeof(double));
+      double *xvals2 = (double*) Malloc(nlon2*sizeof(double));
+      double *yvals2 = (double*) Malloc(nlat2*sizeof(double));
       gridInqXvals(gridID1, xvals1);
       gridInqYvals(gridID1, yvals1);
 
@@ -160,6 +155,11 @@ int genBoxavgGrid(int gridID1, int xinc, int yinc)
       gridDefXvals(gridID2, xvals2);
       gridDefYvals(gridID2, yvals2);
 
+      Free(xvals1);
+      Free(yvals1);
+      Free(xvals2);
+      Free(yvals2);
+
       if ( grid2_corner_lon && grid2_corner_lat )
 	{
 	  gridDefNvertex(gridID2, 2);
@@ -178,57 +178,44 @@ int genBoxavgGrid(int gridID1, int xinc, int yinc)
   return gridID2;
 }
 
-
-void boxavg(field_t *field1, field_t *field2, int xinc, int yinc)
+static
+void boxavg(field_type *field1, field_type *field2, int xinc, int yinc)
 {
-  int nlon1, nlat1;
-  int nlon2, nlat2;
-  int ilat, ilon;
-  int gridID1, gridID2;
-  int nmiss;
-  double **xfield1;
-  double *array1, *array2;
-  double missval;
-  int i, j, ii, jj, in;
-  double **xfield2;
-  /* static int index = 0; */
+  int gridID1 = field1->grid;
+  int gridID2 = field2->grid;
+  double *array1  = field1->ptr;
+  double *array2  = field2->ptr;
+  double missval = field1->missval;
 
-  gridID1 = field1->grid;
-  gridID2 = field2->grid;
-  array1  = field1->ptr;
-  array2  = field2->ptr;
-  missval = field1->missval;
+  int nlon1 = gridInqXsize(gridID1);
+  int nlat1 = gridInqYsize(gridID1);
 
-  nlon1 = gridInqXsize(gridID1);
-  nlat1 = gridInqYsize(gridID1);
+  int nlon2 = gridInqXsize(gridID2);
+  int nlat2 = gridInqYsize(gridID2);
 
-  nlon2 = gridInqXsize(gridID2);
-  nlat2 = gridInqYsize(gridID2);
+  double **xfield1 = (double **) Malloc(nlat1*sizeof(double *));
 
-  xfield1 = (double **) Malloc(nlat1*sizeof(double *));
-
-  for ( ilat = 0; ilat < nlat1; ilat++ )
+  for ( int ilat = 0; ilat < nlat1; ilat++ )
     xfield1[ilat] = array1 + ilat*nlon1;
 
+  double **xfield2 = (double **) Malloc(nlat2 * sizeof(double *));
 
-  xfield2 = (double **) Malloc(nlat2 * sizeof(double *));
-
-  for ( ilat = 0; ilat < nlat2; ilat++ )
+  for ( int ilat = 0; ilat < nlat2; ilat++ )
     xfield2[ilat] = array2 + ilat*nlon2;
 
-  for ( ilat = 0; ilat < nlat2; ilat++ )
-    for ( ilon = 0; ilon < nlon2; ilon++ )
+  for ( int ilat = 0; ilat < nlat2; ilat++ )
+    for ( int ilon = 0; ilon < nlon2; ilon++ )
       {
 	xfield2[ilat][ilon] = 0;
 
-	in = 0;
-	for ( j = 0; j < yinc; ++j )
+	int in = 0;
+	for ( int j = 0; j < yinc; ++j )
 	  {
-	    jj = ilat*yinc+j;
+	    int jj = ilat*yinc+j;
 	    if ( jj >= nlat1 ) break;
-	    for ( i = 0; i < xinc; ++i )
+	    for ( int i = 0; i < xinc; ++i )
 	      {
-		ii = ilon*xinc+i;
+		int ii = ilon*xinc+i;
 		if ( ii >= nlon1 ) break;
 		in++;
 		xfield2[ilat][ilon] += xfield1[jj][ii];
@@ -237,8 +224,8 @@ void boxavg(field_t *field1, field_t *field2, int xinc, int yinc)
 	xfield2[ilat][ilon] /= in;
       }
 
-  nmiss = 0;
-  for ( i = 0; i < nlat2*nlon2; i++ )
+  int nmiss = 0;
+  for ( int i = 0; i < nlat2*nlon2; i++ )
     if ( DBL_IS_EQUAL(array2[i], missval) ) nmiss++;
 
   field2->nmiss = nmiss;
@@ -247,47 +234,36 @@ void boxavg(field_t *field1, field_t *field2, int xinc, int yinc)
   Free(xfield1);
 }
 
-
-void thinout(field_t *field1, field_t *field2, int xinc, int yinc)
+static
+void thinout(field_type *field1, field_type *field2, int xinc, int yinc)
 {
-  int nlon1, nlat1;
-  int nlon2, nlat2;
-  int ilat, ilon, olat, olon;
-  int gridID1, gridID2;
-  int nmiss;
-  double **xfield1;
-  double *array1, *array2;
-  double missval;
-  int i;
-  double **xfield2;
-
-  gridID1 = field1->grid;
-  gridID2 = field2->grid;
-  array1  = field1->ptr;
-  array2  = field2->ptr;
-  missval = field1->missval;
+  int gridID1 = field1->grid;
+  int gridID2 = field2->grid;
+  double *array1  = field1->ptr;
+  double *array2  = field2->ptr;
+  double missval = field1->missval;
 
-  nlon1 = gridInqXsize(gridID1);
-  nlat1 = gridInqYsize(gridID1);
+  int nlon1 = gridInqXsize(gridID1);
+  int nlat1 = gridInqYsize(gridID1);
 
-  nlon2 = gridInqXsize(gridID2);
-  nlat2 = gridInqYsize(gridID2);
+  int nlon2 = gridInqXsize(gridID2);
+  int nlat2 = gridInqYsize(gridID2);
 
-  xfield1 = (double **) Malloc(nlat1*sizeof(double *));
+  double **xfield1 = (double **) Malloc(nlat1*sizeof(double *));
 
-  for ( ilat = 0; ilat < nlat1; ilat++ )
+  for ( int ilat = 0; ilat < nlat1; ilat++ )
     xfield1[ilat] = array1 + ilat*nlon1;
 
-  xfield2 = (double **) Malloc(nlat2*sizeof(double *));
+  double **xfield2 = (double **) Malloc(nlat2*sizeof(double *));
 
-  for ( ilat = 0; ilat < nlat2; ilat++ )
+  for ( int ilat = 0; ilat < nlat2; ilat++ )
     xfield2[ilat] = array2 + ilat*nlon2;
 
-  olat = 0;
-  for ( ilat = 0; ilat < nlat1; ilat+=yinc )
+  int olat = 0;
+  for ( int ilat = 0; ilat < nlat1; ilat+=yinc )
     {
-      olon = 0;
-      for ( ilon = 0; ilon < nlon1; ilon+=xinc )
+      int olon = 0;
+      for ( int ilon = 0; ilon < nlon1; ilon+=xinc )
 	{
 	  xfield2[olat][olon] = xfield1[ilat][ilon];
 	  olon++;
@@ -295,8 +271,8 @@ void thinout(field_t *field1, field_t *field2, int xinc, int yinc)
       olat++;
     }
 
-  nmiss = 0;
-  for ( i = 0; i < nlat2*nlon2; i++ )
+  int nmiss = 0;
+  for ( int i = 0; i < nlat2*nlon2; i++ )
     if ( DBL_IS_EQUAL(array2[i], missval) ) nmiss++;
   
   field2->nmiss = nmiss;
@@ -310,19 +286,15 @@ void thinout(field_t *field1, field_t *field2, int xinc, int yinc)
 void *Intgrid(void *argument)
 {
   int nrecs;
-  int index;
-  int recID, varID, levelID;
+  int varID, levelID;
   int gridID1 = -1, gridID2 = -1;
   int nmiss;
   int xinc = 0, yinc = 0;
   double missval;
-  double slon, slat;
-  field_t field1, field2;
 
   cdoInitialize(argument);
 
   int INTGRIDBIL  = cdoOperatorAdd("intgridbil",  0, 0, NULL);
-  int INTGRIDCON  = cdoOperatorAdd("intgridcon",  0, 0, NULL);
   int INTPOINT    = cdoOperatorAdd("intpoint",    0, 0, NULL);
   int INTERPOLATE = cdoOperatorAdd("interpolate", 0, 0, NULL);
   int BOXAVG      = cdoOperatorAdd("boxavg",      0, 0, NULL);
@@ -332,7 +304,7 @@ void *Intgrid(void *argument)
 
   int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  if ( operatorID == INTGRIDBIL || operatorID == INTGRIDCON || operatorID == INTERPOLATE )
+  if ( operatorID == INTGRIDBIL || operatorID == INTERPOLATE )
     {
       operatorInputArg("grid description file or name");
       gridID2 = cdoDefineGrid(operatorArgv()[0]);
@@ -341,8 +313,8 @@ void *Intgrid(void *argument)
     {
       operatorInputArg("longitude and latitude");
       operatorCheckArgc(2);
-      slon = parameter2double(operatorArgv()[0]);
-      slat = parameter2double(operatorArgv()[1]);
+      double slon = parameter2double(operatorArgv()[0]);
+      double slat = parameter2double(operatorArgv()[1]);
       gridID2 = gridCreate(GRID_LONLAT, 1);
       gridDefXsize(gridID2, 1);
       gridDefYsize(gridID2, 1);
@@ -365,7 +337,7 @@ void *Intgrid(void *argument)
   vlistDefTaxis(vlistID2, taxisID2);
 
   int ngrids = vlistNgrids(vlistID1);
-  for ( index = 0; index < ngrids; index++ )
+  for ( int index = 0; index < ngrids; index++ )
     {
       gridID1 = vlistGrid(vlistID1, index);
 
@@ -392,9 +364,6 @@ void *Intgrid(void *argument)
           
 	  if ( !ldistgen && gridInqType(gridID1) != GRID_LONLAT && gridInqType(gridID1) != GRID_GAUSSIAN )
 	    cdoAbort("Interpolation of %s data unsupported!", gridNamePtr(gridInqType(gridID1)) );
-
-	  if ( gridIsRotated(gridID1) )
-	    cdoAbort("Rotated grids not supported!");
 	}
 
       vlistChangeGridIndex(vlistID2, index, gridID2);
@@ -410,6 +379,7 @@ void *Intgrid(void *argument)
   gridsize = gridInqSize(gridID2);
   double *array2   = (double*) Malloc(gridsize*sizeof(double));
 
+  field_type field1, field2;
   field_init(&field1);
   field_init(&field2);
 
@@ -420,7 +390,7 @@ void *Intgrid(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, array1, &nmiss);
@@ -438,8 +408,6 @@ void *Intgrid(void *argument)
 
 	  if ( operatorID == INTGRIDBIL || operatorID == INTPOINT )
 	    intgridbil(&field1, &field2);
-	  if ( operatorID == INTGRIDCON )
-	    intgridcon(&field1, &field2);
 	  else if ( operatorID == INTERPOLATE )
 	    interpolate(&field1, &field2);
 	  else if ( operatorID == BOXAVG )
diff --git a/src/Intgridtraj.c b/src/Intgridtraj.c
index 9cd9823..36e4e34 100644
--- a/src/Intgridtraj.c
+++ b/src/Intgridtraj.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -20,7 +20,6 @@
 
 */
 
-#include <ctype.h>
 
 #include <cdi.h>
 #include "cdo.h"
@@ -32,7 +31,6 @@
 int readnextpos(FILE *fp, int calendar, juldate_t *juldate, double *xpos, double *ypos)
 {
   int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
-  int date, time;
   int stat;
 
   *xpos = 0;
@@ -43,71 +41,61 @@ int readnextpos(FILE *fp, int calendar, juldate_t *juldate, double *xpos, double
 
   if ( stat != EOF )
     {
-      date = cdiEncodeDate(year, month, day);
-      time = cdiEncodeTime(hour, minute, second);
+      int date = cdiEncodeDate(year, month, day);
+      int time = cdiEncodeTime(hour, minute, second);
       *juldate = juldate_encode(calendar, date, time);
     }
 
-  return (stat);
+  return stat;
 }
 
 
 void *Intgridtraj(void *argument)
 {
-  int streamID1, streamID2;
-  int nrecs, nvars, nlevel;
-  int index, ngrids;
-  int i, nrecords;
-  int tsID, tsIDo, recID, varID, levelID;
-  int gridsize;
-  int vlistID1, vlistID2;
-  int gridID1, gridID2;
-  int taxisID1, taxisID2;
+  int gridID1;
+  int nlevel;
+  int varID, levelID;
   int vdate, vtime;
   int offset;
   int nmiss;
-  int *recVarID, *recLevelID;
-  juldate_t juldate1, juldate2, juldate;
-  double fac1, fac2;
   double point;
-  double *array, *single1, *single2;
-  double **vardata1, **vardata2, *vardatap;
+  double *single1, *single2;
+  double *vardatap;
   double xpos, ypos;
-  char *posfile;
   double missval;
   int calendar = CALENDAR_STANDARD;
-  field_t field1, field2;
-  FILE *fp;
 
   cdoInitialize(argument);
 
   operatorInputArg("filename with grid trajectories");
   operatorCheckArgc(1);
 
-  posfile = operatorArgv()[0];
-  fp = fopen(posfile, "r");
+  char *posfile = operatorArgv()[0];
+  FILE *fp = fopen(posfile, "r");
   if ( fp == NULL ) cdoAbort("Open failed on %s!", posfile);
 
+  juldate_t juldate;
   readnextpos(fp, calendar, &juldate, &xpos, &ypos);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
+  int vlistID1 = streamInqVlist(streamID1);
 
+  field_type field1, field2;
   field_init(&field1);
   field_init(&field2);
 
-  nvars    = vlistNvars(vlistID1);
-  nrecords = vlistNrecs(vlistID1);
+  int nvars    = vlistNvars(vlistID1);
+  int nrecords = vlistNrecs(vlistID1);
 
-  recVarID   = (int*) Malloc(nrecords*sizeof(int));
-  recLevelID = (int*) Malloc(nrecords*sizeof(int));
+  int *recVarID   = (int*) Malloc(nrecords*sizeof(int));
+  int *recLevelID = (int*) Malloc(nrecords*sizeof(int));
 
-  gridsize = vlistGridsizeMax(vlistID1);
-  array = (double*) Malloc(gridsize*sizeof(double));
+  int gridsize = vlistGridsizeMax(vlistID1);
+  double *array = (double*) Malloc(gridsize*sizeof(double));
 
-  vardata1 = (double**) Malloc(nvars*sizeof(double*));
-  vardata2 = (double**) Malloc(nvars*sizeof(double*));
+  double **vardata1 = (double**) Malloc(nvars*sizeof(double*));
+  double **vardata2 = (double**) Malloc(nvars*sizeof(double*));
 
   for ( varID = 0; varID < nvars; varID++ )
     {
@@ -117,16 +105,16 @@ void *Intgridtraj(void *argument)
       vardata2[varID] = (double*) Malloc(gridsize*nlevel*sizeof(double));
     }
 
-  gridID2 = gridCreate(GRID_TRAJECTORY, 1);
+  int gridID2 = gridCreate(GRID_TRAJECTORY, 1);
   gridDefXsize(gridID2, 1);
   gridDefYsize(gridID2, 1);
   gridDefXvals(gridID2, &xpos);
   gridDefYvals(gridID2, &ypos);
 
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  ngrids = vlistNgrids(vlistID1);
-  for ( index = 0; index < ngrids; index++ )
+  int ngrids = vlistNgrids(vlistID1);
+  for ( int index = 0; index < ngrids; index++ )
     {
       gridID1 = vlistGrid(vlistID1, index);
 
@@ -137,18 +125,18 @@ void *Intgridtraj(void *argument)
       vlistChangeGridIndex(vlistID2, index, gridID2);
     }
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  tsID = 0;
-  nrecs = streamInqTimestep(streamID1, tsID++);
-  juldate1 = juldate_encode(calendar, taxisInqVdate(taxisID1), taxisInqVtime(taxisID1));
-  for ( recID = 0; recID < nrecs; recID++ )
+  int tsID = 0;
+  int nrecs = streamInqTimestep(streamID1, tsID++);
+  juldate_t juldate1 = juldate_encode(calendar, taxisInqVdate(taxisID1), taxisInqVtime(taxisID1));
+  for ( int recID = 0; recID < nrecs; recID++ )
     {
       streamInqRecord(streamID1, &varID, &levelID);
       gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
@@ -158,14 +146,14 @@ void *Intgridtraj(void *argument)
       if ( nmiss ) cdoAbort("Missing values unsupported for this operator!");
     }
 
-  tsIDo = 0;
+  int tsIDo = 0;
   while ( juldate_to_seconds(juldate1) <= juldate_to_seconds(juldate) )
     {
       nrecs = streamInqTimestep(streamID1, tsID++);
       if ( nrecs == 0 ) break;
-      juldate2 = juldate_encode(calendar, taxisInqVdate(taxisID1), taxisInqVtime(taxisID1));
+      juldate_t juldate2 = juldate_encode(calendar, taxisInqVdate(taxisID1), taxisInqVtime(taxisID1));
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -189,16 +177,16 @@ void *Intgridtraj(void *argument)
 	      taxisDefVtime(taxisID2, vtime);
 	      streamDefTimestep(streamID2, tsIDo++);
 
-	      fac1 = juldate_to_seconds(juldate_sub(juldate2, juldate)) / 
-		     juldate_to_seconds(juldate_sub(juldate2, juldate1));
-	      fac2 = juldate_to_seconds(juldate_sub(juldate, juldate1)) / 
-	   	     juldate_to_seconds(juldate_sub(juldate2, juldate1));
+	      double fac1 = juldate_to_seconds(juldate_sub(juldate2, juldate)) / 
+		            juldate_to_seconds(juldate_sub(juldate2, juldate1));
+	      double fac2 = juldate_to_seconds(juldate_sub(juldate, juldate1)) / 
+	   	            juldate_to_seconds(juldate_sub(juldate2, juldate1));
 	      /*
 	      printf("      %f %f %f %f %f\n", juldate_to_seconds(juldate),
 	                                       juldate_to_seconds(juldate1), 
 					       juldate_to_seconds(juldate2), fac1, fac2);
 	      */
-	      for ( recID = 0; recID < nrecs; recID++ )
+	      for ( int recID = 0; recID < nrecs; recID++ )
 		{
 		  varID    = recVarID[recID];
 		  levelID  = recLevelID[recID];
@@ -209,7 +197,7 @@ void *Intgridtraj(void *argument)
 		  single1  = vardata1[varID] + offset;
 		  single2  = vardata2[varID] + offset;
 
-		  for ( i = 0; i < gridsize; i++ )
+		  for ( int i = 0; i < gridsize; i++ )
 		    array[i] = single1[i]*fac1 + single2[i]*fac2;
 
 		  field1.grid    = gridID1;
diff --git a/src/Intlevel.c b/src/Intlevel.c
index f487648..7aae25d 100644
--- a/src/Intlevel.c
+++ b/src/Intlevel.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -22,45 +22,38 @@
       Intlevel   intlevel3d      Linear level interpolation on a 3d vertical coordinates variable
 */
 
-#include <ctype.h>
 
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
 #include "pstream.h"
-#include "list.h"
+#include "listarray.h"
 
 
 static
 void vert_interp_lev(int gridsize, double missval, double *vardata1, double *vardata2,
 		     int nlev2, int *lev_idx1, int *lev_idx2, double *lev_wgt1, double *lev_wgt2)
 {
-  int i;
-  int idx1, idx2;
-  double wgt1, wgt2;
-  double w1, w2;
-  double *var1L1, *var1L2, *var2;
-
   for ( int ilev = 0; ilev < nlev2; ++ilev )
     {
-      idx1 = lev_idx1[ilev];
-      idx2 = lev_idx2[ilev];
-      wgt1 = lev_wgt1[ilev];
-      wgt2 = lev_wgt2[ilev];
-      var2 = vardata2+gridsize*ilev;
+      int idx1 = lev_idx1[ilev];
+      int idx2 = lev_idx2[ilev];
+      double wgt1 = lev_wgt1[ilev];
+      double wgt2 = lev_wgt2[ilev];
+      double *var2 = vardata2+gridsize*ilev;
 
       if ( cdoVerbose ) cdoPrint("level %d: idx1=%d idx2=%d wgt1=%g wgt2=%g", ilev, idx1, idx2, wgt1, wgt2);
 
-      var1L1 = vardata1+gridsize*idx1;
-      var1L2 = vardata1+gridsize*idx2;
+      double *var1L1 = vardata1+gridsize*idx1;
+      double *var1L2 = vardata1+gridsize*idx2;
 
 #if defined(_OPENMP)
-#pragma omp parallel for default(none) shared(gridsize, var2, var1L1, var1L2, wgt1, wgt2, missval) private(w1, w2)
+#pragma omp parallel for default(none) shared(gridsize, var2, var1L1, var1L2, wgt1, wgt2, missval)
 #endif
-      for ( i = 0; i < gridsize; ++i )
+      for ( int i = 0; i < gridsize; ++i )
 	{
-	  w1 = wgt1;
-	  w2 = wgt2;
+	  double w1 = wgt1;
+	  double w2 = wgt2;
 	  if ( DBL_IS_EQUAL(var1L1[i], missval) ) w1 = 0;
 	  if ( DBL_IS_EQUAL(var1L2[i], missval) ) w2 = 0;
 
@@ -163,7 +156,7 @@ void vert_gen_weights(int expol, int nlev1, double *lev1, int nlev2, double *lev
 void *Intlevel(void *argument)
 {
   int gridsize;
-  int recID, nrecs;
+  int nrecs;
   int i, offset;
   int varID, levelID;
   int nmiss;
@@ -187,9 +180,9 @@ void *Intlevel(void *argument)
 
   operatorInputArg("levels");
 
-  LIST *flist = listNew(FLT_LIST);
-  int nlev2 = args2fltlist(operatorArgc(), operatorArgv(), flist);
-  double *lev2  = (double *) listArrayPtr(flist);
+  lista_t *flista = lista_new(FLT_LISTA);
+  int nlev2 = args2flt_lista(operatorArgc(), operatorArgv(), flista);
+  double *lev2  = (double *) lista_dataptr(flista);
 
   if ( cdoVerbose ) for ( i = 0; i < nlev2; ++i ) printf("lev2 %d: %g\n", i, lev2[i]);
 
@@ -219,7 +212,7 @@ void *Intlevel(void *argument)
 
   int nlev1 = nlevel;
   double *lev1 = (double*) Malloc((nlev1+2)*sizeof(double));
-  zaxisInqLevels(zaxisID1, lev1+1);
+  cdoZaxisInqLevels(zaxisID1, lev1+1);
 
   bool lup = false;
   bool ldown = false;
@@ -270,7 +263,7 @@ void *Intlevel(void *argument)
   int zaxisID2 = zaxisCreate(zaxisInqType(zaxisID1), nlev2);
   zaxisDefLevels(zaxisID2, lev2);
   {
-    char str[256];
+    char str[CDI_MAX_NAME];
     str[0] = 0;
     zaxisInqName(zaxisID1, str);
     zaxisDefName(zaxisID2, str);
@@ -284,7 +277,7 @@ void *Intlevel(void *argument)
     zaxisDefPrec(zaxisID2, zaxisInqPrec(zaxisID1));
   }
 
-  for ( i = 0; i < nzaxis; i++ )
+  for ( int i = 0; i < nzaxis; i++ )
     if ( zaxisID1 == vlistZaxis(vlistID1, i) )
       vlistChangeZaxisIndex(vlistID2, i, zaxisID2);
 
@@ -336,7 +329,7 @@ void *Intlevel(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
@@ -364,7 +357,7 @@ void *Intlevel(void *argument)
 		  offset   = gridsize*levelID;
 		  single2  = vardata2[varID] + offset;
 		  nmiss    = 0;
-		  for ( i = 0; i < gridsize; ++i )
+		  for ( int i = 0; i < gridsize; ++i )
 		    if ( DBL_IS_EQUAL(single2[i], missval) ) nmiss++;
 		  varnmiss[varID][levelID] = nmiss;
 		}
@@ -413,7 +406,7 @@ void *Intlevel(void *argument)
 
   Free(lev1);
 
-  listDelete(flist);
+  lista_destroy(flista);
 
   cdoFinish();
 
diff --git a/src/Intlevel3d.c b/src/Intlevel3d.c
index 372529b..9c038a7 100644
--- a/src/Intlevel3d.c
+++ b/src/Intlevel3d.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -22,21 +22,20 @@
       Intlevel   intlevelx3d     Linear level interpolation on a 3d vertical coordinates variable with extrapolation
 */
 
-#include <ctype.h>
 
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
 #include "pstream.h"
-#include "list.h"
+#include "listarray.h"
 #include "after_vertint.h"
 
 
 
 void *Intlevel3d(void *argument)
 {
-  int gridsize,gridSize,gridsizei,gridsizeo;
-  int recID, nrecs;
+  int gridsize, gridSize, gridsizei, gridsizeo;
+  int nrecs;
   int i, offset;
   int tsID, varID, levelID;
   int nvars,nvct;
@@ -114,7 +113,7 @@ void *Intlevel3d(void *argument)
     nrecs      = streamInqTimestep(streamID0, 0);
     if (cdoVerbose) cdoPrint("%d records input 3d vertical height",nrecs);
 
-    for ( recID = 0; recID < nrecs; recID++ )
+    for ( int recID = 0; recID < nrecs; recID++ )
       {
         streamInqRecord(streamID0, &varID, &levelID);
         gridsize = gridInqSize(vlistInqVarGrid(vlistID0, varID));
@@ -150,7 +149,7 @@ void *Intlevel3d(void *argument)
     nrecs       = streamInqTimestep(streamID2, 0);
     if (cdoVerbose) cdoPrint("%d records target 3d vertical height and gridsize %d",nrecs,gridsize);
 
-    for ( recID = 0; recID < nrecs; recID++ )
+    for ( int recID = 0; recID < nrecs; recID++ )
       {
 	streamInqRecord(streamID2, &varID, &levelID);
 	gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
@@ -390,13 +389,12 @@ void *Intlevel3d(void *argument)
       for ( varID = 0; varID < nvars; ++varID ) vars[varID] = false;
 
       taxisCopyTimestep(taxisID3, taxisID1);
-
       streamDefTimestep(streamID3, tsID);
 
       /*
        * Read the whole 3d data field
        */
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
           vlistInqVarName(vlistID1, varID, varname); 
diff --git a/src/Intntime.c b/src/Intntime.c
index a28e400..7886d11 100644
--- a/src/Intntime.c
+++ b/src/Intntime.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -31,53 +31,39 @@
 
 void *Intntime(void *argument)
 {
-  int streamID1, streamID2;
-  int nrecs, nvars, nlevel;
-  int i, nrecords;
-  int tsID, tsIDo, recID, varID, levelID;
-  int gridsize;
-  int vlistID1, vlistID2;
-  int taxisID1, taxisID2;
+  int nlevel;
+  int varID, levelID;
   int vdate, vtime;
-  int vdate1, vtime1;
-  int vdate2, vtime2;
   int offset;
-  int calendar;
-  int numts, it;
-  int *recVarID, *recLevelID;
-  int **nmiss1, **nmiss2, nmiss3;
-  double missval1, missval2;
-  juldate_t juldate1, juldate2, juldate;
-  double fac1, fac2;
-  double *array, *single1, *single2;
-  double **vardata1, **vardata2, *vardatap;
+  double *single1, *single2;
+  double *vardatap;
 
   cdoInitialize(argument);
 
   operatorInputArg("number of timesteps between 2 timesteps");
   if ( operatorArgc() < 1 ) cdoAbort("Too few arguments!");
 
-  numts = parameter2int(operatorArgv()[0]);
+  int numts = parameter2int(operatorArgv()[0]);
   if ( numts < 2 ) cdoAbort("parameter must be greater than 1!");
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  nvars    = vlistNvars(vlistID1);
-  nrecords = vlistNrecs(vlistID1);
+  int nvars    = vlistNvars(vlistID1);
+  int nrecords = vlistNrecs(vlistID1);
 
-  recVarID   = (int*) Malloc(nrecords*sizeof(int));
-  recLevelID = (int*) Malloc(nrecords*sizeof(int));
+  int *recVarID   = (int*) Malloc(nrecords*sizeof(int));
+  int *recLevelID = (int*) Malloc(nrecords*sizeof(int));
 
-  gridsize = vlistGridsizeMax(vlistID1);
-  array = (double*) Malloc(gridsize*sizeof(double));
+  int gridsize = vlistGridsizeMax(vlistID1);
+  double *array = (double*) Malloc(gridsize*sizeof(double));
 
-  nmiss1   = (int **) Malloc(nvars*sizeof(int *));
-  nmiss2   = (int **) Malloc(nvars*sizeof(int *));
-  vardata1 = (double **) Malloc(nvars*sizeof(double *));
-  vardata2 = (double **) Malloc(nvars*sizeof(double *));
+  int **nmiss1   = (int **) Malloc(nvars*sizeof(int *));
+  int **nmiss2   = (int **) Malloc(nvars*sizeof(int *));
+  double **vardata1 = (double **) Malloc(nvars*sizeof(double *));
+  double **vardata2 = (double **) Malloc(nvars*sizeof(double *));
 
   for ( varID = 0; varID < nvars; varID++ )
     {
@@ -89,27 +75,27 @@ void *Intntime(void *argument)
       vardata2[varID] = (double*) Malloc(gridsize*nlevel*sizeof(double));
     }
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   if ( taxisHasBounds(taxisID2) ) taxisDeleteBounds(taxisID2);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  calendar = taxisInqCalendar(taxisID1);
+  int calendar = taxisInqCalendar(taxisID1);
 
-  tsID = 0;
-  tsIDo = 0;
-  nrecs = streamInqTimestep(streamID1, tsID++);
-  vdate1 = taxisInqVdate(taxisID1);
-  vtime1 = taxisInqVtime(taxisID1);
-  juldate1 = juldate_encode(calendar, vdate1, vtime1);
+  int tsID = 0;
+  int tsIDo = 0;
+  int nrecs = streamInqTimestep(streamID1, tsID++);
+  int vdate1 = taxisInqVdate(taxisID1);
+  int vtime1 = taxisInqVtime(taxisID1);
+  juldate_t juldate1 = juldate_encode(calendar, vdate1, vtime1);
 
   taxisCopyTimestep(taxisID2, taxisID1);
   streamDefTimestep(streamID2, tsIDo++);
-  for ( recID = 0; recID < nrecs; recID++ )
+  for ( int recID = 0; recID < nrecs; recID++ )
     {
       streamInqRecord(streamID1, &varID, &levelID);
       gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
@@ -123,11 +109,11 @@ void *Intntime(void *argument)
 
   while ( (nrecs = streamInqTimestep(streamID1, tsID++)) )
     {
-      vdate2 = taxisInqVdate(taxisID1);
-      vtime2 = taxisInqVtime(taxisID1);
-      juldate2 = juldate_encode(calendar, vdate2, vtime2);
+      int vdate2 = taxisInqVdate(taxisID1);
+      int vtime2 = taxisInqVtime(taxisID1);
+      juldate_t juldate2 = juldate_encode(calendar, vdate2, vtime2);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -140,10 +126,10 @@ void *Intntime(void *argument)
 	  streamReadRecord(streamID1, single2, &nmiss2[varID][levelID]);
 	}
 
-      for ( it = 1; it < numts; it++ )
+      for ( int it = 1; it < numts; it++ )
 	{
 	  double seconds = it * juldate_to_seconds(juldate_sub(juldate2, juldate1)) / numts;
-	  juldate = juldate_add_seconds((int)lround(seconds), juldate1);
+	  juldate_t juldate = juldate_add_seconds((int)lround(seconds), juldate1);
 
 	  juldate_decode(calendar, juldate, &vdate, &vtime);
 
@@ -164,12 +150,12 @@ void *Intntime(void *argument)
 	  taxisDefVtime(taxisID2, vtime);
 	  streamDefTimestep(streamID2, tsIDo++);
 
-	  fac1 = juldate_to_seconds(juldate_sub(juldate2, juldate)) / 
-	         juldate_to_seconds(juldate_sub(juldate2, juldate1));
-	  fac2 = juldate_to_seconds(juldate_sub(juldate,  juldate1)) / 
-	         juldate_to_seconds(juldate_sub(juldate2, juldate1));
+	  double fac1 = juldate_to_seconds(juldate_sub(juldate2, juldate)) / 
+	                juldate_to_seconds(juldate_sub(juldate2, juldate1));
+	  double fac2 = juldate_to_seconds(juldate_sub(juldate,  juldate1)) / 
+	                juldate_to_seconds(juldate_sub(juldate2, juldate1));
 
-	  for ( recID = 0; recID < nrecs; recID++ )
+	  for ( int recID = 0; recID < nrecs; recID++ )
 	    {
 	      varID    = recVarID[recID];
 	      levelID  = recLevelID[recID];
@@ -178,14 +164,14 @@ void *Intntime(void *argument)
 	      single1  = vardata1[varID] + offset;
 	      single2  = vardata2[varID] + offset;
 
-	      nmiss3 = 0;
+	      int nmiss3 = 0;
 
 	      if ( nmiss1[varID][levelID] > 0 || nmiss2[varID][levelID] > 0 )
 		{
-		  missval1 = vlistInqVarMissval(vlistID1, varID);
-		  missval2 = vlistInqVarMissval(vlistID2, varID);
+		  double missval1 = vlistInqVarMissval(vlistID1, varID);
+		  double missval2 = vlistInqVarMissval(vlistID2, varID);
 
-		  for ( i = 0; i < gridsize; i++ )
+		  for ( int i = 0; i < gridsize; i++ )
 		    {
 		      if ( !DBL_IS_EQUAL(single1[i], missval1) &&
 			   !DBL_IS_EQUAL(single2[i], missval2) )
@@ -205,7 +191,7 @@ void *Intntime(void *argument)
 		}
 	      else
 		{
-		  for ( i = 0; i < gridsize; i++ )
+		  for ( int i = 0; i < gridsize; i++ )
 		    array[i] = single1[i]*fac1 + single2[i]*fac2;
 		}
 
@@ -217,7 +203,7 @@ void *Intntime(void *argument)
       taxisDefVdate(taxisID2, vdate2);
       taxisDefVtime(taxisID2, vtime2);
       streamDefTimestep(streamID2, tsIDo++);
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  varID   = recVarID[recID];
 	  levelID = recLevelID[recID];
diff --git a/src/Inttime.c b/src/Inttime.c
index fc9b8ea..dcd9b27 100644
--- a/src/Inttime.c
+++ b/src/Inttime.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -21,7 +21,6 @@
       Inttime    inttime         Time interpolation
 */
 
-#include <ctype.h>  /* isdigit */
 
 #include <cdi.h>
 #include "cdo.h"
@@ -35,35 +34,24 @@ int get_tunits(const char *unit, int *incperiod, int *incunit, int *tunit);
 
 void *Inttime(void *argument)
 {
-  int streamID1, streamID2 = -1;
-  int nrecs, nvars, nlevel;
-  int i, nrecords;
-  int tsID, tsIDo, recID, varID, levelID;
-  int gridsize;
-  int vlistID1, vlistID2;
-  int taxisID1, taxisID2;
+  int streamID2 = -1;
+  int nlevel;
+  int varID, levelID;
   int vdate, vtime;
   int offset;
-  int ijulinc, incperiod = 0, incunit = 3600, tunit = TUNIT_HOUR;
-  int calendar;
+  int incperiod = 0, incunit = 3600, tunit = TUNIT_HOUR;
   int year, month, day, hour, minute, second;
-  int *recVarID, *recLevelID;
-  int **nmiss1, **nmiss2, nmiss3;
-  const char *datestr, *timestr;
   char *rstr;
-  double missval1, missval2;
-  juldate_t juldate1, juldate2, juldate;
-  double fac1, fac2;
-  double *array, *single1, *single2;
-  double **vardata1, **vardata2, *vardatap;
+  double *single1, *single2;
+  double *vardatap;
 
   cdoInitialize(argument);
 
   operatorInputArg("date,time<,increment> (format YYYY-MM-DD,hh:mm:ss)");
   if ( operatorArgc() < 2 ) cdoAbort("Too few arguments!");
 
-  datestr = operatorArgv()[0];
-  timestr = operatorArgv()[1];
+  const char *datestr = operatorArgv()[0];
+  const char *timestr = operatorArgv()[1];
 
   if ( strchr(datestr, '-') )
     {
@@ -99,28 +87,28 @@ void *Inttime(void *argument)
       get_tunits(timeunits, &incperiod, &incunit, &tunit);
     }
   /* increment in seconds */
-  ijulinc = incperiod * incunit;
+  int ijulinc = incperiod * incunit;
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
   if ( ijulinc == 0 ) vlistDefNtsteps(vlistID2, 1);
 
-  nvars    = vlistNvars(vlistID1);
-  nrecords = vlistNrecs(vlistID1);
+  int nvars    = vlistNvars(vlistID1);
+  int nrecords = vlistNrecs(vlistID1);
 
-  recVarID   = (int*) Malloc(nrecords*sizeof(int));
-  recLevelID = (int*) Malloc(nrecords*sizeof(int));
+  int *recVarID   = (int*) Malloc(nrecords*sizeof(int));
+  int *recLevelID = (int*) Malloc(nrecords*sizeof(int));
 
-  gridsize = vlistGridsizeMax(vlistID1);
-  array = (double*) Malloc(gridsize*sizeof(double));
+  int gridsize = vlistGridsizeMax(vlistID1);
+  double *array = (double*) Malloc(gridsize*sizeof(double));
 
-  nmiss1   = (int **) Malloc(nvars*sizeof(int *));
-  nmiss2   = (int **) Malloc(nvars*sizeof(int *));
-  vardata1 = (double **) Malloc(nvars*sizeof(double *));
-  vardata2 = (double **) Malloc(nvars*sizeof(double *));
+  int **nmiss1   = (int **) Malloc(nvars*sizeof(int *));
+  int **nmiss2   = (int **) Malloc(nvars*sizeof(int *));
+  double **vardata1 = (double **) Malloc(nvars*sizeof(double *));
+  double **vardata2 = (double **) Malloc(nvars*sizeof(double *));
 
   for ( varID = 0; varID < nvars; varID++ )
     {
@@ -132,14 +120,14 @@ void *Inttime(void *argument)
       vardata2[varID] = (double*) Malloc(gridsize*nlevel*sizeof(double));
     }
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   if ( taxisHasBounds(taxisID2) ) taxisDeleteBounds(taxisID2);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  calendar = taxisInqCalendar(taxisID1);
+  int calendar = taxisInqCalendar(taxisID1);
 
-  juldate = juldate_encode(calendar, vdate, vtime);
+  juldate_t juldate = juldate_encode(calendar, vdate, vtime);
 
   if ( cdoVerbose )
     {
@@ -148,10 +136,10 @@ void *Inttime(void *argument)
       cdoPrint("ijulinc = %d", ijulinc);
     }
 
-  tsID = 0;
-  nrecs = streamInqTimestep(streamID1, tsID++);
-  juldate1 = juldate_encode(calendar, taxisInqVdate(taxisID1), taxisInqVtime(taxisID1));
-  for ( recID = 0; recID < nrecs; recID++ )
+  int tsID = 0;
+  int nrecs = streamInqTimestep(streamID1, tsID++);
+  juldate_t juldate1 = juldate_encode(calendar, taxisInqVdate(taxisID1), taxisInqVtime(taxisID1));
+  for ( int recID = 0; recID < nrecs; recID++ )
     {
       streamInqRecord(streamID1, &varID, &levelID);
       gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
@@ -169,20 +157,20 @@ void *Inttime(void *argument)
   if ( juldate_to_seconds(juldate1) > juldate_to_seconds(juldate) )
     cdoWarning("start time %d %d out of range!", vdate, vtime);
 
-  tsIDo = 0;
+  int tsIDo = 0;
   while ( juldate_to_seconds(juldate1) <= juldate_to_seconds(juldate) )
     {
       nrecs = streamInqTimestep(streamID1, tsID++);
       if ( nrecs == 0 ) break;
 
-      juldate2 = juldate_encode(calendar, taxisInqVdate(taxisID1), taxisInqVtime(taxisID1));
+      juldate_t juldate2 = juldate_encode(calendar, taxisInqVdate(taxisID1), taxisInqVtime(taxisID1));
       if ( cdoVerbose )
 	{
 	  cdoPrint("date %d  time %d", taxisInqVdate(taxisID1), taxisInqVtime(taxisID1));
 	  cdoPrint("juldate2  = %f", juldate_to_seconds(juldate2));
 	}
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -225,12 +213,12 @@ void *Inttime(void *argument)
 	      taxisDefVtime(taxisID2, vtime);
 	      streamDefTimestep(streamID2, tsIDo++);
 
-	      fac1 = juldate_to_seconds(juldate_sub(juldate2, juldate)) / 
-		     juldate_to_seconds(juldate_sub(juldate2, juldate1));
-	      fac2 = juldate_to_seconds(juldate_sub(juldate, juldate1)) / 
-	   	     juldate_to_seconds(juldate_sub(juldate2, juldate1));
+	      double fac1 = juldate_to_seconds(juldate_sub(juldate2, juldate)) / 
+                            juldate_to_seconds(juldate_sub(juldate2, juldate1));
+	      double fac2 = juldate_to_seconds(juldate_sub(juldate, juldate1)) / 
+	   	            juldate_to_seconds(juldate_sub(juldate2, juldate1));
 
-	      for ( recID = 0; recID < nrecs; recID++ )
+	      for ( int recID = 0; recID < nrecs; recID++ )
 		{
 		  varID    = recVarID[recID];
 		  levelID  = recLevelID[recID];
@@ -239,14 +227,14 @@ void *Inttime(void *argument)
 		  single1  = vardata1[varID] + offset;
 		  single2  = vardata2[varID] + offset;
 
-		  nmiss3 = 0;
+		  int nmiss3 = 0;
 
 		  if ( nmiss1[varID][levelID] > 0 || nmiss2[varID][levelID] > 0 )
 		    {
-		      missval1 = vlistInqVarMissval(vlistID1, varID);
-		      missval2 = vlistInqVarMissval(vlistID2, varID);
+		      double missval1 = vlistInqVarMissval(vlistID1, varID);
+		      double missval2 = vlistInqVarMissval(vlistID2, varID);
 
-		      for ( i = 0; i < gridsize; i++ )
+		      for ( int i = 0; i < gridsize; i++ )
 			{
 			  if ( !DBL_IS_EQUAL(single1[i], missval1) &&
 			       !DBL_IS_EQUAL(single2[i], missval2) )
@@ -266,7 +254,7 @@ void *Inttime(void *argument)
 		    }
 		  else
 		    {
-		      for ( i = 0; i < gridsize; i++ )
+		      for ( int i = 0; i < gridsize; i++ )
 			array[i] = single1[i]*fac1 + single2[i]*fac2;
 		    }
 
diff --git a/src/Intyear.c b/src/Intyear.c
index bbf83e6..bb5fa30 100644
--- a/src/Intyear.c
+++ b/src/Intyear.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -21,75 +21,62 @@
       Intyear    intyear         Year interpolation
 */
 
-#include <ctype.h>
 
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
 #include "pstream.h"
 #include "interpol.h"
-#include "list.h"
+#include "listarray.h"
 
 
 void *Intyear(void *argument)
 {
-  int streamID1, streamID2;
   int nrecs;
-  int i, iy;
-  int tsID, recID, varID, levelID;
-  int gridsize;
-  int vlistID1, vlistID2, vlistID3;
-  int taxisID1, taxisID2, taxisID3;
-  int vtime, vdate1, vdate2, vdate3, year1, year2;
+  int varID, levelID;
   int nmiss1, nmiss2, nmiss3;
-  int *iyears, nyears = 0, *streamIDs = NULL;
-  int nchars;
   char filesuffix[32];
   char filename[8192];
-  const char *refname;
-  double fac1, fac2;
-  double missval1, missval2;
-  double *array1, *array2, *array3;
-  LIST *ilist = listNew(INT_LIST);
 
   cdoInitialize(argument);
 
   operatorInputArg("years");
 
-  nyears = args2intlist(operatorArgc(), operatorArgv(), ilist);
+  lista_t *ilist = lista_new(INT_LISTA);
+  int nyears = args2int_lista(operatorArgc(), operatorArgv(), ilist);
 
-  iyears = (int *) listArrayPtr(ilist);
+  int *iyears = (int *) lista_dataptr(ilist);
 
-  streamIDs = (int*) Malloc(nyears*sizeof(int));
+  int *streamIDs = (int*) Malloc(nyears*sizeof(int));
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
-  streamID2 = streamOpenRead(cdoStreamName(1));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID2 = streamOpenRead(cdoStreamName(1));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = streamInqVlist(streamID2);
-  vlistID3 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = streamInqVlist(streamID2);
+  int vlistID3 = vlistDuplicate(vlistID1);
 
   vlistCompare(vlistID1, vlistID2, CMP_ALL);
 
-  gridsize = vlistGridsizeMax(vlistID1);
-  array1 = (double*) Malloc(gridsize*sizeof(double));
-  array2 = (double*) Malloc(gridsize*sizeof(double));
-  array3 = (double*) Malloc(gridsize*sizeof(double));
+  int gridsize = vlistGridsizeMax(vlistID1);
+  double *array1 = (double*) Malloc(gridsize*sizeof(double));
+  double *array2 = (double*) Malloc(gridsize*sizeof(double));
+  double *array3 = (double*) Malloc(gridsize*sizeof(double));
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = vlistInqTaxis(vlistID2);
-  taxisID3 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = vlistInqTaxis(vlistID2);
+  int taxisID3 = taxisDuplicate(taxisID1);
   if ( taxisHasBounds(taxisID3) ) taxisDeleteBounds(taxisID3);
   vlistDefTaxis(vlistID3, taxisID3);
 
   strcpy(filename, cdoStreamName(2)->args);
-  nchars = strlen(filename);
+  int nchars = strlen(filename);
 
-  refname = cdoStreamName(0)->argv[cdoStreamName(0)->argc-1];
+  const char *refname = cdoStreamName(0)->argv[cdoStreamName(0)->argc-1];
   filesuffix[0] = 0;
   cdoGenFileSuffix(filesuffix, sizeof(filesuffix), streamInqFiletype(streamID1), vlistID1, refname);
 
-  for ( iy = 0; iy < nyears; iy++ )
+  for ( int iy = 0; iy < nyears; iy++ )
     {
       sprintf(filename+nchars, "%04d", iyears[iy]);
       if ( filesuffix[0] )
@@ -102,7 +89,7 @@ void *Intyear(void *argument)
       streamDefVlist(streamIDs[iy], vlistID3);
     }
 
-  tsID = 0;
+  int tsID = 0;
   while ( TRUE )
     {
       nrecs = streamInqTimestep(streamID1, tsID);
@@ -110,24 +97,24 @@ void *Intyear(void *argument)
       nrecs = streamInqTimestep(streamID2, tsID);
       if ( nrecs == 0 ) cdoAbort("Too few timesteps in second inputfile!");
 
-      vtime  = taxisInqVtime(taxisID1);
-      vdate1 = taxisInqVdate(taxisID1);
-      year1  = vdate1/10000;
-      vdate2 = taxisInqVdate(taxisID2);
-      year2  = vdate2/10000;
+      int vtime  = taxisInqVtime(taxisID1);
+      int vdate1 = taxisInqVdate(taxisID1);
+      int year1  = vdate1/10000;
+      int vdate2 = taxisInqVdate(taxisID2);
+      int year2  = vdate2/10000;
 
-      for ( iy = 0; iy < nyears; iy++ )
+      for ( int iy = 0; iy < nyears; iy++ )
 	{
 	  if ( iyears[iy] < year1 || iyears[iy] > year2 )
 	    cdoAbort("Year %d out of bounds (first year %d; last year %d)!",
 		     iyears[iy], year1, year2);
-	  vdate3 = vdate1 - year1*10000 + iyears[iy]*10000;
+	  int vdate3 = vdate1 - year1*10000 + iyears[iy]*10000;
 	  taxisDefVdate(taxisID3, vdate3);
 	  taxisDefVtime(taxisID3, vtime);
 	  streamDefTimestep(streamIDs[iy], tsID);
 	}
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamInqRecord(streamID2, &varID, &levelID);
@@ -137,19 +124,19 @@ void *Intyear(void *argument)
 
 	  gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
 
-	  for ( iy = 0; iy < nyears; iy++ )
+	  for ( int iy = 0; iy < nyears; iy++ )
 	    {
-	      fac1 = ((double) year2-iyears[iy]) / (year2-year1);
-	      fac2 = ((double) iyears[iy]-year1) / (year2-year1);
+	      double fac1 = ((double) year2-iyears[iy]) / (year2-year1);
+	      double fac2 = ((double) iyears[iy]-year1) / (year2-year1);
 
 	      nmiss3 = 0;
 
 	      if ( nmiss1 > 0 || nmiss2 > 0 )
 		{
-		  missval1 = vlistInqVarMissval(vlistID1, varID);
-		  missval2 = vlistInqVarMissval(vlistID2, varID);
+		  double missval1 = vlistInqVarMissval(vlistID1, varID);
+		  double missval2 = vlistInqVarMissval(vlistID2, varID);
 
-		  for ( i = 0; i < gridsize; i++ )
+		  for ( int i = 0; i < gridsize; i++ )
 		    {
 		      if ( !DBL_IS_EQUAL(array1[i], missval1) &&
 			   !DBL_IS_EQUAL(array2[i], missval2) )
@@ -171,7 +158,7 @@ void *Intyear(void *argument)
 		}
 	      else
 		{
-		  for ( i = 0; i < gridsize; i++ )
+		  for ( int i = 0; i < gridsize; i++ )
 		    array3[i] = array1[i]*fac1 + array2[i]*fac2;
 		}
 
@@ -183,7 +170,7 @@ void *Intyear(void *argument)
       tsID++;
     }
 
-  for ( iy = 0; iy < nyears; iy++ )
+  for ( int iy = 0; iy < nyears; iy++ )
     streamClose(streamIDs[iy]);
   
   streamClose(streamID2);
@@ -195,7 +182,7 @@ void *Intyear(void *argument)
 
   Free(streamIDs);
 
-  listDelete(ilist);
+  lista_destroy(ilist);
 
   cdoFinish();
 
diff --git a/src/Invert.c b/src/Invert.c
index fdad71c..39f04d2 100644
--- a/src/Invert.c
+++ b/src/Invert.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -36,21 +36,13 @@
 static
 void invertLonDes(int vlistID)
 {
-  int index, ngrids;
-  int gridID1, gridID2;
-  int nlat, nlon, size;
-  int ilat, ilon;
-  int gridtype, nv, iv;
-  double *xv1, *xv2;
-  double *xb1, *xb2;
-
-  ngrids = vlistNgrids(vlistID);
-  for ( index = 0; index < ngrids; index++ )
+  int ngrids = vlistNgrids(vlistID);
+  for ( int index = 0; index < ngrids; index++ )
     {
-      gridID1 = vlistGrid(vlistID, index);
-      gridID2 = gridDuplicate(gridID1);
+      int gridID1 = vlistGrid(vlistID, index);
+      int gridID2 = gridDuplicate(gridID1);
 
-      gridtype = gridInqType(gridID1);
+      int gridtype = gridInqType(gridID1);
 
       if ( gridtype != GRID_GENERIC && gridtype != GRID_GAUSSIAN &&
 	   gridtype != GRID_LONLAT  && gridtype != GRID_CURVILINEAR )
@@ -58,28 +50,24 @@ void invertLonDes(int vlistID)
 
       if ( gridInqXvals(gridID1, NULL) )
 	{
-	  nlon  = gridInqXsize(gridID1);
-	  nlat  = gridInqYsize(gridID1);
-
-	  if ( gridtype == GRID_CURVILINEAR )
-	    size = nlon*nlat;
-	  else
-            size = nlon;
+	  int nlon = gridInqXsize(gridID1);
+	  int nlat = gridInqYsize(gridID1);
+	  int size = (gridtype == GRID_CURVILINEAR) ? nlon*nlat : nlon;
 
-	  xv1 = (double*) Malloc(size*sizeof(double));
-	  xv2 = (double*) Malloc(size*sizeof(double));
+	  double *xv1 = (double*) Malloc(size*sizeof(double));
+	  double *xv2 = (double*) Malloc(size*sizeof(double));
 
 	  gridInqXvals(gridID1, xv1);
 
 	  if ( gridtype == GRID_CURVILINEAR )
 	    {
-	      for ( ilat = 0; ilat < nlat; ilat++ )
-		for ( ilon = 0; ilon < nlon; ilon++ )
+	      for ( int ilat = 0; ilat < nlat; ilat++ )
+		for ( int ilon = 0; ilon < nlon; ilon++ )
 		  xv2[ilat*nlon + nlon-ilon-1] = xv1[ilat*nlon + ilon];
 	    }
 	  else
 	    {
-	      for ( ilon = 0; ilon < nlon; ilon++ )
+	      for ( int ilon = 0; ilon < nlon; ilon++ )
 		xv2[nlon-ilon-1] = xv1[ilon];
 	    }
 
@@ -91,31 +79,26 @@ void invertLonDes(int vlistID)
 
       if ( gridInqXbounds(gridID1, NULL) )
 	{
-	  nlon  = gridInqXsize(gridID1);
-	  nlat  = gridInqYsize(gridID1);
+	  int nlon = gridInqXsize(gridID1);
+	  int nlat = gridInqYsize(gridID1);
+	  int nv   = gridInqNvertex(gridID1);
+	  int size = (gridtype == GRID_CURVILINEAR) ? nv*nlon*nlat : nv*nlon;
 
-	  nv = gridInqNvertex(gridID1);
-
-	  if ( gridtype == GRID_CURVILINEAR )
-	    size = nv*nlon*nlat;
-	  else
-            size = nv*nlon;
-
-	  xb1 = (double*) Malloc(size*sizeof(double));
-	  xb2 = (double*) Malloc(size*sizeof(double));
+	  double *xb1 = (double*) Malloc(size*sizeof(double));
+	  double *xb2 = (double*) Malloc(size*sizeof(double));
 
 	  gridInqXbounds(gridID1, xb1);
 
 	  if ( gridtype == GRID_CURVILINEAR )
 	    {
-	      for ( ilat = 0; ilat < nlat; ilat++ )
-		for ( ilon = 0; ilon < nlon; ilon++ )
-		  for ( iv = 0; iv < nv; iv++ )
+	      for ( int ilat = 0; ilat < nlat; ilat++ )
+		for ( int ilon = 0; ilon < nlon; ilon++ )
+		  for ( int iv = 0; iv < nv; iv++ )
 		    xb2[ilat*nlon*nv + (nlon-ilon-1)*nv + iv] = xb1[ilat*nlon*nv + ilon*nv + iv];
 	    }
 	  else
 	    {
-		for ( ilon = 0; ilon < nlon; ilon++ )
+		for ( int ilon = 0; ilon < nlon; ilon++ )
 		  {
 		    xb2[nlon*2-ilon*2-1] = xb1[ilon*2];
 		    xb2[nlon*2-ilon*2-2] = xb1[ilon*2+1];
@@ -149,11 +132,9 @@ void invertLatDes(int vlistID)
 
       if ( gridInqYvals(gridID1, NULL) )
 	{
-	  int nlon  = gridInqXsize(gridID1);
-	  int nlat  = gridInqYsize(gridID1);
-
-          int size = nlat;
-	  if ( gridtype == GRID_CURVILINEAR ) size = nlon*nlat;
+	  int nlon = gridInqXsize(gridID1);
+	  int nlat = gridInqYsize(gridID1);
+	  int size = (gridtype == GRID_CURVILINEAR) ? nlon*nlat : nlat;
 
 	  double *yv1 = (double*) Malloc(size*sizeof(double));
 	  double *yv2 = (double*) Malloc(size*sizeof(double));
@@ -193,13 +174,10 @@ void invertLatDes(int vlistID)
 
       if ( gridInqYbounds(gridID1, NULL) )
 	{
-	  int nlon  = gridInqXsize(gridID1);
-	  int nlat  = gridInqYsize(gridID1);
-
-	  int nv = gridInqNvertex(gridID1);
-
-          int size = nlat;
-	  if ( gridtype == GRID_CURVILINEAR ) size = nlon*nlat;
+	  int nlon = gridInqXsize(gridID1);
+	  int nlat = gridInqYsize(gridID1);
+	  int nv   = gridInqNvertex(gridID1);
+	  int size = (gridtype == GRID_CURVILINEAR) ? nv*nlon*nlat : nv*nlat;
 
 	  double *yb1 = (double*) Malloc(size*sizeof(double));
 	  double *yb2 = (double*) Malloc(size*sizeof(double));
@@ -235,26 +213,22 @@ void invertLatDes(int vlistID)
 static
 void invertLonData(double *array1, double *array2, int gridID1)
 {
-  int nlat, nlon;
-  int ilat, ilon;
-  double **field1, **field2;
-
-  nlon = gridInqXsize(gridID1);
-  nlat = gridInqYsize(gridID1);
+  int nlon = gridInqXsize(gridID1);
+  int nlat = gridInqYsize(gridID1);
 
   if ( nlat > 0 )
     {
-      field1 = (double **) Malloc(nlat*sizeof(double *));
-      field2 = (double **) Malloc(nlat*sizeof(double *));
+      double **field1 = (double **) Malloc(nlat*sizeof(double *));
+      double **field2 = (double **) Malloc(nlat*sizeof(double *));
   
-      for ( ilat = 0; ilat < nlat; ilat++ )
+      for ( int ilat = 0; ilat < nlat; ilat++ )
 	{
 	  field1[ilat] = array1 + ilat*nlon;
 	  field2[ilat] = array2 + ilat*nlon;
 	}
 
-      for ( ilat = 0; ilat < nlat; ilat++ )
-	for ( ilon = 0; ilon < nlon; ilon++ )
+      for ( int ilat = 0; ilat < nlat; ilat++ )
+	for ( int ilon = 0; ilon < nlon; ilon++ )
 	  field2[ilat][nlon-ilon-1] = field1[ilat][ilon];
   
       if ( field1 ) Free(field1);
@@ -269,25 +243,21 @@ void invertLonData(double *array1, double *array2, int gridID1)
 static
 void invertLatData(double *array1, double *array2, int gridID1)
 {
-  int nlat, nlon;
-  int ilat;
-  double **field1, **field2;
-
-  nlon = gridInqXsize(gridID1);
-  nlat = gridInqYsize(gridID1);
+  int nlon = gridInqXsize(gridID1);
+  int nlat = gridInqYsize(gridID1);
 
   if ( nlat > 0 )
     {
-      field1 = (double **) Malloc(nlat*sizeof(double *));
-      field2 = (double **) Malloc(nlat*sizeof(double *));
+      double **field1 = (double **) Malloc(nlat*sizeof(double *));
+      double **field2 = (double **) Malloc(nlat*sizeof(double *));
   
-      for ( ilat = 0; ilat < nlat; ilat++ )
+      for ( int ilat = 0; ilat < nlat; ilat++ )
 	{
 	  field1[ilat] = array1 + ilat*nlon;
 	  field2[ilat] = array2 + ilat*nlon;
 	}
 
-      for ( ilat = 0; ilat < nlat; ilat++ )
+      for ( int ilat = 0; ilat < nlat; ilat++ )
 	memcpy(field2[nlat-ilat-1], field1[ilat], nlon*sizeof(double));
       
       if ( field1 ) Free(field1);
@@ -303,7 +273,7 @@ void invertLatData(double *array1, double *array2, int gridID1)
 void *Invert(void *argument)
 {
   int nrecs;
-  int recID, varID, levelID;
+  int varID, levelID;
   int gridID1;
   int nmiss;
 
@@ -353,7 +323,7 @@ void *Invert(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, array1, &nmiss);
diff --git a/src/Invertlev.c b/src/Invertlev.c
index fd3310a..068f4a8 100644
--- a/src/Invertlev.c
+++ b/src/Invertlev.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -41,7 +41,7 @@ void invertLevDes(int vlistID)
       int nlev = zaxisInqSize(zaxisID1);
       if ( nlev <= 1 ) continue;
 
-      /* if ( zaxisInqLevels(zaxisID1, NULL) ) */
+      if ( zaxisInqLevels(zaxisID1, NULL) )
 	{
 	  double yv1[nlev], yv2[nlev];
 	  zaxisInqLevels(zaxisID1, yv1);
@@ -86,7 +86,7 @@ void invertLevDes(int vlistID)
 void *Invertlev(void *argument)
 {
   int nrecs;
-  int recID, varID, levelID;
+  int varID, levelID;
   int nmiss;
   int nlev, nlevel;
   int gridID, zaxisID, offset;
@@ -154,7 +154,7 @@ void *Invertlev(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
diff --git a/src/Isosurface.c b/src/Isosurface.c
index 1b13e71..76c17d5 100644
--- a/src/Isosurface.c
+++ b/src/Isosurface.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -24,27 +24,24 @@
 double intlin(double x, double y1, double x1, double y2, double x2);
 
 static
-void isosurface(double isoval, long nlev1, double *lev1, field_t *field3D, field_t *field2D)
+void isosurface(double isoval, long nlev1, double *lev1, field_type *field3D, field_type *field2D)
 {
-  long i, k, gridsize, nmiss;
-  int lmiss1, lmiss2;
-  double missval, val1, val2;
-  double *data2D, *data3D;
-
-  gridsize = gridInqSize(field3D->grid);
-  nmiss    = field3D->nmiss;
-  missval  = field3D->missval;
-  data3D   = field3D->ptr;
-  data2D   = field2D->ptr;
-
-  for ( i = 0; i < gridsize; ++i )
+  bool lmiss1, lmiss2;
+
+  long gridsize = gridInqSize(field3D->grid);
+  long nmiss    = field3D->nmiss;
+  double missval  = field3D->missval;
+  double *data3D   = field3D->ptr;
+  double *data2D   = field2D->ptr;
+
+  for ( long i = 0; i < gridsize; ++i )
     {
       data2D[i] = missval;
 
-      for ( k = 0; k < (nlev1-1); ++k )
+      for ( long k = 0; k < (nlev1-1); ++k )
 	{
-	  val1 = data3D[k*gridsize+i];
-	  val2 = data3D[(k+1)*gridsize+i];
+	  double val1 = data3D[k*gridsize+i];
+	  double val2 = data3D[(k+1)*gridsize+i];
 
 	  if ( nmiss > 0 )
 	    {
@@ -69,7 +66,7 @@ void isosurface(double isoval, long nlev1, double *lev1, field_t *field3D, field
     }
 
   nmiss = 0;
-  for ( i = 0; i < gridsize; ++i )
+  for ( long i = 0; i < gridsize; ++i )
     if ( DBL_IS_EQUAL(data2D[i], missval) ) nmiss++;
 
   field2D->missval = missval;
@@ -79,25 +76,15 @@ void isosurface(double isoval, long nlev1, double *lev1, field_t *field3D, field
 
 void *Isosurface(void *argument)
 {
-  int streamID1, streamID2;
-  int vlistID1, vlistID2;
-  int gridsize, nlevel = 0;
-  int recID, nrecs;
+  int nlevel = 0;
+  int nrecs;
   int gridID;
-  int nlev1;
   int i, offset;
-  int tsID, varID, levelID;
-  int nmiss, nvars;
-  int zaxisID, zaxisID1 = -1, zaxisIDsfc, nzaxis;
+  int varID, levelID;
+  int nmiss;
+  int zaxisID, zaxisID1 = -1;
   double missval;
-  double isoval = 0;
-  int *vars = NULL;
-  int *liso = NULL;
-  field_t *vars1 = NULL;
-  field_t field;
-  double *lev1;
   double *single;
-  int taxisID1, taxisID2;
 
   cdoInitialize(argument);
 
@@ -105,21 +92,21 @@ void *Isosurface(void *argument)
 
   operatorCheckArgc(1);
 
-  isoval = parameter2double(operatorArgv()[0]);
+  double isoval = parameter2double(operatorArgv()[0]);
 
   if ( cdoVerbose ) cdoPrint("Isoval: %g", isoval);
 
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  nzaxis  = vlistNzaxis(vlistID1);
+  int nzaxis = vlistNzaxis(vlistID1);
   for ( i = 0; i < nzaxis; i++ )
     {
       zaxisID = vlistZaxis(vlistID1, i);
@@ -134,29 +121,30 @@ void *Isosurface(void *argument)
 
   if ( i == nzaxis ) cdoAbort("No processable variable found!");
 
-  nlev1 = nlevel;
-  lev1  = (double*) Malloc((nlev1)*sizeof(double));
-  zaxisInqLevels(zaxisID1, lev1);
+  int nlev1 = nlevel;
+  double *lev1  = (double*) Malloc(nlev1*sizeof(double));
+  cdoZaxisInqLevels(zaxisID1, lev1);
 
-  zaxisIDsfc = zaxisCreate(ZAXIS_SURFACE, 1);
+  int zaxisIDsfc = zaxisCreate(ZAXIS_SURFACE, 1);
   for ( i = 0; i < nzaxis; i++ )
     if ( zaxisID1 == vlistZaxis(vlistID1, i) )
       vlistChangeZaxisIndex(vlistID2, i, zaxisIDsfc);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
 
+  field_type field;
   field_init(&field);
   field.ptr = (double*) Malloc(gridsize*sizeof(double));
 
-  nvars = vlistNvars(vlistID1);
+  int nvars = vlistNvars(vlistID1);
 
-  liso  = (int*)     Malloc(nvars*sizeof(int));
-  vars  = (int*)     Malloc(nvars*sizeof(int));
-  vars1 = (field_t*) Malloc(nvars*sizeof(field_t));
+  bool *liso = (bool*)     Malloc(nvars*sizeof(bool));
+  int *vars  = (int*)     Malloc(nvars*sizeof(int));
+  field_type *vars1 = (field_type*) Malloc(nvars*sizeof(field_type));
 
   for ( varID = 0; varID < nvars; varID++ )
     {
@@ -166,10 +154,7 @@ void *Isosurface(void *argument)
       nlevel   = zaxisInqSize(zaxisID);
       missval  = vlistInqVarMissval(vlistID1, varID);
 
-      if ( zaxisID == zaxisID1 )
-	liso[varID] = TRUE;
-      else 
-	liso[varID] = FALSE;
+      liso[varID] = (zaxisID == zaxisID1);
 
       field_init(&vars1[varID]);
       vars1[varID].grid    = gridID;
@@ -179,7 +164,7 @@ void *Isosurface(void *argument)
       vars1[varID].ptr     = (double*) Malloc(gridsize*nlevel*sizeof(double));
     }
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
@@ -192,7 +177,7 @@ void *Isosurface(void *argument)
 	  vars1[varID].nmiss = 0;
 	}
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
diff --git a/src/Kvl.c b/src/Kvl.c
deleted file mode 100644
index 5d1a9a5..0000000
--- a/src/Kvl.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
-  This file is part of CDO. CDO is a collection of Operators to
-  manipulate and analyse Climate model Data.
-
-  Copyright (C) 2003-2016 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.
-*/
-
-/*
-   This module contains the following operators:
-
-*/
-
-#include "cdo.h"
-#include "cdo_int.h"
-#include "kvlist.h"
-
-
-static
-int read_cmor_table(const char *filename)
-{
-  void *kvlist;
-  int nlists, listID;
-  int nelements, elemID;
-  const char *listname;
-  const char *ename;
-  const char *evalue;
-
-  kvlist = kvlParseFile(filename);
-  nlists = kvlGetNumLists(kvlist);
-  printf("# Number of lists: %d\n", nlists);
-  for ( listID = 0; listID < nlists; ++listID )
-    {
-      listname = kvlGetListName(kvlist, listID);
-      nelements = kvlGetListNumElements(kvlist, listID);
-      printf("# list ID: %d;   Number of elements: %d\n", listID, nelements);
-      printf("&%s\n", listname);
-      for ( elemID = 0; elemID < nelements; ++elemID )
-	{
-	  ename  = kvlGetListElementName(kvlist, listID, elemID);
-	  evalue = kvlGetListElementValue(kvlist, listID, elemID);
-	  printf("  %s = %s\n", ename, evalue);
-	}
-      printf("/\n");
-    }
-
-  kvlDelete(kvlist);
-
-  return 0;
-}
-
-static
-int conv_cmor_table(const char *filename)
-{
-  void *kvlist;
-  int nlists, listID;
-  int nelements, elemID;
-  int len;
-  int hasmissval = FALSE;
-  double missval;
-  const char *listname;
-  const char *ename;
-  const char *evalue;
-  char *ovalue;
-
-  kvlist = kvlParseFile(filename);
-  nlists = kvlGetNumLists(kvlist);
-  //printf("# Number of lists: %d\n", nlists);
-  for ( listID = 0; listID < nlists; ++listID )
-    {
-      listname = kvlGetListName(kvlist, listID);
-      nelements = kvlGetListNumElements(kvlist, listID);
-      //printf("# list ID: %d;   Number of elements: %d\n", listID, nelements);
-      if ( strncmp("global", listname, strlen(listname)) == 0 )
-	{
-	  for ( elemID = 0; elemID < nelements; ++elemID )
-	    {
-	      ename  = kvlGetListElementName(kvlist, listID, elemID);
-	      evalue = kvlGetListElementValue(kvlist, listID, elemID);
-	      len = strlen(ename);
-
-	      if ( strncmp("missing_value", ename, len) == 0 )
-		{
-		  missval = atof(evalue);
-		  hasmissval = TRUE;
-		}
-	    }
-	}
-      else if ( strncmp("variable", listname, strlen(listname)) == 0 )
-	{
-	  int vlen;
-	  printf("&%s\n", "parameter");
-	  for ( elemID = 0; elemID < nelements; ++elemID )
-	    {
-	      ename  = kvlGetListElementName(kvlist, listID, elemID);
-	      evalue = kvlGetListElementValue(kvlist, listID, elemID);
-	      len = strlen(ename);
-	      vlen = strlen(evalue);
-
-	      if ( vlen > 1 && evalue[0] == '"' && evalue[vlen-1] == '"' ) 
-		{
-		  vlen -= 2;
-		  evalue++;
-		}
-
-	      ovalue = strdup(evalue);
-	      for ( int i = 1; i < vlen; ++i )
-		{
-		  if ( ovalue[i-1] == '"' && ovalue[i] == '"' )
-		    {
-		      ovalue [i-1] = '\'';
-		      for ( int j = i+1; j < vlen; ++j ) ovalue[j-1] = ovalue[j];
-		      vlen -= 1;
-		    }
-		}
-
-	      if ( strncmp("name", ename, len)            == 0 ||
-		   strncmp("standard_name", ename, len)   == 0 ||
-		   strncmp("out_name", ename, len)        == 0 ||
-		   strncmp("type", ename, len)            == 0 ||
-		   strncmp("valid_min", ename, len)       == 0 ||
-		   strncmp("valid_max", ename, len)       == 0 ||
-		   strncmp("ok_min_mean_abs", ename, len) == 0 ||
-		   strncmp("ok_max_mean_abs", ename, len) == 0 )
-		printf("  %-15s = %s\n", ename, ovalue);
-	      else if ( strncmp("long_name", ename, len)  == 0 ||
-		   strncmp("units", ename, len)           == 0 ||
-		   strncmp("cell_methods", ename, len)    == 0 ||
-		   strncmp("cell_measures", ename, len)   == 0 ||
-		   strncmp("comment", ename, len)         == 0 )
-		printf("  %-15s = \"%.*s\"\n", ename, vlen, ovalue);
-
-	      Free(ovalue);
-	    }
-	  if ( hasmissval ) printf("  %-15s = %g\n", "missing_value", missval);
-	  printf("/\n");
-	}
-    }
-
-  kvlDelete(kvlist);
-
-  return 0;
-}
-
-
-void *Kvl(void *argument)
-{
-  int READ_CMOR_TABLE, CONV_CMOR_TABLE, CONV_PARTAB;
-  int operatorID;
-  const char *filename;
-
-  cdoInitialize(argument);
-
-  READ_CMOR_TABLE = cdoOperatorAdd("read_cmor_table",   0,   0, NULL);
-  CONV_CMOR_TABLE = cdoOperatorAdd("conv_cmor_table",   0,   0, NULL);
-  CONV_PARTAB     = cdoOperatorAdd("conv_partab",   0,   0, NULL);
-
-  operatorID = cdoOperatorID();
-
-  if ( operatorID == READ_CMOR_TABLE )
-    {
-      if ( operatorArgc() != 1 ) cdoAbort("Too few arguments!");
-      filename = operatorArgv()[0];
-
-      if ( cdoVerbose ) cdoPrint("Parse file: %s", filename);
-
-      read_cmor_table(filename);
-    }
-  else if ( operatorID == CONV_CMOR_TABLE )
-    {
-      if ( operatorArgc() != 1 ) cdoAbort("Too few arguments!");
-      filename = operatorArgv()[0];
-
-      if ( cdoVerbose ) cdoPrint("Parse file: %s", filename);
-
-      conv_cmor_table(filename);
-    }
-  else if ( operatorID == CONV_PARTAB )
-    {
-      if ( operatorArgc() != 1 ) cdoAbort("Too few arguments!");
-      filename = operatorArgv()[0];
-
-      if ( cdoVerbose ) cdoPrint("Parse file: %s", filename);
-
-      // conv_partab(filename);
-    }
-
-  cdoFinish();
-
-  return 0;
-}
diff --git a/src/Log.c b/src/Log.c
index 27a180b..b6de15b 100644
--- a/src/Log.c
+++ b/src/Log.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -26,25 +26,21 @@ void dumplogo(const char *logfilename, int dumptype);
 
 void *Log(void *argument)
 {
-  int DUMPLOGS, DAYLOGS, MONLOGS;
-  int operatorID, operfunc;
-  int dumptype;
-
   cdoInitialize(argument);
 
-  DUMPLOGS  = cdoOperatorAdd("dumplogs",   0, 0, NULL);
-  DAYLOGS   = cdoOperatorAdd("daylogs",    0, 0, NULL);
-  MONLOGS   = cdoOperatorAdd("monlogs",    0, 0, NULL);
-              cdoOperatorAdd("dumplogo",   1, 0, NULL);
-              cdoOperatorAdd("snamelogo",  1, 1, NULL);
-              cdoOperatorAdd("scalllogo",  1, 2, NULL);
-              cdoOperatorAdd("smemlogo",   1, 3, NULL);
-              cdoOperatorAdd("stimelogo",  1, 4, NULL);
-              cdoOperatorAdd("sperclogo",  1, 5, NULL);
+  int DUMPLOGS  = cdoOperatorAdd("dumplogs",   0, 0, NULL);
+  int DAYLOGS   = cdoOperatorAdd("daylogs",    0, 0, NULL);
+  int MONLOGS   = cdoOperatorAdd("monlogs",    0, 0, NULL);
+                  cdoOperatorAdd("dumplogo",   1, 0, NULL);
+                  cdoOperatorAdd("snamelogo",  1, 1, NULL);
+                  cdoOperatorAdd("scalllogo",  1, 2, NULL);
+                  cdoOperatorAdd("smemlogo",   1, 3, NULL);
+                  cdoOperatorAdd("stimelogo",  1, 4, NULL);
+                  cdoOperatorAdd("sperclogo",  1, 5, NULL);
 
-  operatorID = cdoOperatorID();
-  operfunc   = cdoOperatorF1(operatorID);
-  dumptype   = cdoOperatorF2(operatorID);
+  int operatorID = cdoOperatorID();
+  int operfunc   = cdoOperatorF1(operatorID);
+  int dumptype   = cdoOperatorF2(operatorID);
 
   if ( cdoStreamName(0)->args[0] == '-' )
     cdoAbort("This operator does not work with pipes!");
diff --git a/src/Makefile.am b/src/Makefile.am
index 0b26ecf..08a87de 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,6 +1,8 @@
 ## Process this file with automake to produce Makefile.in
 noinst_LTLIBRARIES = libcdo.la
 libcdo_la_SOURCES =            \
+               array.h         \
+               array.c         \
                cdo_int.h       \
                compare.h       \
                cdo_pthread.c   \
@@ -11,6 +13,7 @@ libcdo_la_SOURCES =            \
                cdo_task.h      \
                cdo_history.c   \
                cdi_uuid.h      \
+               cmortable_parser.c   \
                after_sptrans.c \
                after_fctrans.c \
                after_dvtrans.c \
@@ -27,6 +30,8 @@ libcdo_la_SOURCES =            \
                color.h         \
                commandline.c   \
                const.h         \
+               convert_units.c \
+               convert_units.h \
                counter.h       \
                datetime.c      \
                datetime.h      \
@@ -64,6 +69,10 @@ libcdo_la_SOURCES =            \
                grid_gme.c      \
                grid_lcc.c      \
                grid_rot.c      \
+               grid_from_name.c   \
+               grid_read.c        \
+               grid_read_pingo.c  \
+               grid_print.c    \
                gridreference.c \
                griddes.c       \
                griddes.h       \
@@ -78,22 +87,26 @@ libcdo_la_SOURCES =            \
                juldate.c       \
                grid_search.c   \
                grid_search.h   \
-               kvlist.c        \
-               kvlist.h        \
+               listarray.c     \
+               listarray.h     \
                list.c          \
                list.h          \
+               listbuf.c       \
+               listbuf.h       \
 	       merge_sort2.c   \
 	       merge_sort2.h   \
                modules.c       \
                modules.h       \
                namelist.c      \
                namelist.h      \
+               namelist_parser.c     \
                normal.c        \
                nth_element.c   \
                nth_element.h   \
                operator_help.h \
                par_io.c        \
                par_io.h        \
+               parse_literal.c      \
                percentiles_hist.c   \
                percentiles_hist.h   \
                percentiles.c   \
@@ -102,6 +115,8 @@ libcdo_la_SOURCES =            \
                pipe.h          \
                pmlist.c        \
                pmlist.h        \
+               sellist.c       \
+               sellist.h       \
                pragma_omp_atomic_update.h \
                printinfo.h     \
                process.c       \
@@ -144,12 +159,17 @@ libcdo_la_SOURCES =            \
                uthash.h        \
                util.c          \
                util.h          \
+               zaxis_print.c   \
                zaxis.c
 libcdo_la_SOURCES +=           \
+               json/jsmn.h     \
+               json/jsmn.c
+libcdo_la_SOURCES +=           \
                kdtreelib/kdtree.h            \
                kdtreelib/kdtree_cartesian.c  \
                kdtreelib/kdtree_common.c     \
                kdtreelib/kdtree_spherical.c  \
+               kdtreelib/qsort.c             \
                kdtreelib/pmergesort.c        \
                kdtreelib/pqueue.c            \
                kdtreelib/pqueue.h
@@ -187,6 +207,8 @@ cdo_SOURCES += Adisit.c        \
                Change_e5slm.c  \
                Cloudlayer.c    \
                CMOR.c          \
+               CMOR_lite.c     \
+               CMOR_table.c    \
                Collgrid.c      \
                Command.c       \
                Comp.c          \
@@ -197,6 +219,7 @@ cdo_SOURCES += Adisit.c        \
                Condc.c         \
                Consecstat.c    \
                Copy.c          \
+               Deltat.c        \
                Deltime.c       \
                Derivepar.c     \
                Detrend.c       \
@@ -247,7 +270,6 @@ cdo_SOURCES += Adisit.c        \
                Invert.c        \
                Invertlev.c     \
                Isosurface.c    \
-               Kvl.c           \
                Log.c           \
 	       MapReduce.c     \
                Maskbox.c       \
@@ -261,7 +283,7 @@ cdo_SOURCES += Adisit.c        \
                Mrotuv.c        \
                Mrotuvb.c       \
                Ninfo.c         \
-               Nmltest.c       \
+               Nmldump.c       \
                Output.c        \
                Outputgmt.c     \
                Pack.c          \
@@ -281,12 +303,14 @@ cdo_SOURCES += Adisit.c        \
                Seaspctl.c      \
                Seasstat.c      \
                Selbox.c        \
+               Selindex.c      \
                Select.c        \
                Seloperator.c   \
                Selrec.c        \
                Seltime.c       \
                Selvar.c        \
                Set.c           \
+               Setattribute.c  \
                Setbox.c        \
                Setgatt.c       \
                Setgrid.c       \
@@ -296,6 +320,7 @@ cdo_SOURCES += Adisit.c        \
                Setrcaname.c    \
                Settime.c       \
                Setzaxis.c      \
+               Shiftxy.c       \
                Showinfo.c      \
                Sinfo.c         \
                Smooth.c        \
@@ -314,8 +339,8 @@ cdo_SOURCES += Adisit.c        \
                Templates.c     \
                Test.c          \
                Tests.c         \
-               Timedt.c        \
                Timcount.c      \
+               Timcumsum.c     \
                Timpctl.c       \
                Timselpctl.c    \
                Timselstat.c    \
diff --git a/src/Makefile.in b/src/Makefile.in
index 2f333f6..c17641c 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -102,36 +102,43 @@ CONFIG_CLEAN_VPATH_FILES =
 LTLIBRARIES = $(noinst_LTLIBRARIES)
 libcdo_la_LIBADD =
 am__dirstamp = $(am__leading_dot)dirstamp
-am_libcdo_la_OBJECTS = libcdo_la-cdo_pthread.lo libcdo_la-cdo_vlist.lo \
-	libcdo_la-cdo_getopt.lo libcdo_la-cdo_task.lo \
-	libcdo_la-cdo_history.lo libcdo_la-after_sptrans.lo \
+am_libcdo_la_OBJECTS = libcdo_la-array.lo libcdo_la-cdo_pthread.lo \
+	libcdo_la-cdo_vlist.lo libcdo_la-cdo_getopt.lo \
+	libcdo_la-cdo_task.lo libcdo_la-cdo_history.lo \
+	libcdo_la-cmortable_parser.lo libcdo_la-after_sptrans.lo \
 	libcdo_la-after_fctrans.lo libcdo_la-after_dvtrans.lo \
 	libcdo_la-after_vertint.lo libcdo_la-after_namelist.lo \
 	libcdo_la-afterburnerlib.lo libcdo_la-constants.lo \
 	libcdo_la-color.lo libcdo_la-commandline.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-grid_area.lo libcdo_la-grid_gme.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-grid_area.lo libcdo_la-grid_gme.lo \
 	libcdo_la-grid_lcc.lo libcdo_la-grid_rot.lo \
+	libcdo_la-grid_from_name.lo libcdo_la-grid_read.lo \
+	libcdo_la-grid_read_pingo.lo libcdo_la-grid_print.lo \
 	libcdo_la-gridreference.lo libcdo_la-griddes.lo \
 	libcdo_la-griddes_h5.lo libcdo_la-griddes_nc.lo \
 	libcdo_la-hetaeta.lo libcdo_la-institution.lo \
 	libcdo_la-interpol.lo libcdo_la-job.lo libcdo_la-juldate.lo \
-	libcdo_la-grid_search.lo libcdo_la-kvlist.lo libcdo_la-list.lo \
+	libcdo_la-grid_search.lo libcdo_la-listarray.lo \
+	libcdo_la-list.lo libcdo_la-listbuf.lo \
 	libcdo_la-merge_sort2.lo libcdo_la-modules.lo \
-	libcdo_la-namelist.lo libcdo_la-normal.lo \
-	libcdo_la-nth_element.lo libcdo_la-par_io.lo \
+	libcdo_la-namelist.lo libcdo_la-namelist_parser.lo \
+	libcdo_la-normal.lo libcdo_la-nth_element.lo \
+	libcdo_la-par_io.lo libcdo_la-parse_literal.lo \
 	libcdo_la-percentiles_hist.lo libcdo_la-percentiles.lo \
-	libcdo_la-pipe.lo libcdo_la-pmlist.lo libcdo_la-process.lo \
-	libcdo_la-pstream.lo libcdo_la-pthread_debug.lo \
-	libcdo_la-readline.lo libcdo_la-realtime.lo \
-	libcdo_la-remaplib.lo libcdo_la-remapsort.lo \
-	libcdo_la-remap_scrip_io.lo libcdo_la-remap_search_reg2d.lo \
+	libcdo_la-pipe.lo libcdo_la-pmlist.lo libcdo_la-sellist.lo \
+	libcdo_la-process.lo libcdo_la-pstream.lo \
+	libcdo_la-pthread_debug.lo libcdo_la-readline.lo \
+	libcdo_la-realtime.lo libcdo_la-remaplib.lo \
+	libcdo_la-remapsort.lo libcdo_la-remap_scrip_io.lo \
+	libcdo_la-remap_search_reg2d.lo \
 	libcdo_la-remap_search_latbins.lo \
 	libcdo_la-remap_store_link.lo \
 	libcdo_la-remap_store_link_cnsrv.lo libcdo_la-remap_conserv.lo \
@@ -140,11 +147,12 @@ am_libcdo_la_OBJECTS = libcdo_la-cdo_pthread.lo libcdo_la-cdo_vlist.lo \
 	libcdo_la-remap_bilinear_scrip.lo libcdo_la-stdnametable.lo \
 	libcdo_la-specspace.lo libcdo_la-statistic.lo \
 	libcdo_la-table.lo libcdo_la-text.lo libcdo_la-timer.lo \
-	libcdo_la-userlog.lo libcdo_la-util.lo libcdo_la-zaxis.lo \
-	kdtreelib/libcdo_la-kdtree_cartesian.lo \
+	libcdo_la-userlog.lo libcdo_la-util.lo \
+	libcdo_la-zaxis_print.lo libcdo_la-zaxis.lo \
+	json/libcdo_la-jsmn.lo kdtreelib/libcdo_la-kdtree_cartesian.lo \
 	kdtreelib/libcdo_la-kdtree_common.lo \
 	kdtreelib/libcdo_la-kdtree_spherical.lo \
-	kdtreelib/libcdo_la-pmergesort.lo \
+	kdtreelib/libcdo_la-qsort.lo kdtreelib/libcdo_la-pmergesort.lo \
 	kdtreelib/libcdo_la-pqueue.lo clipping/libcdo_la-clipping.lo \
 	clipping/libcdo_la-area.lo \
 	clipping/libcdo_la-ensure_array_size.lo \
@@ -164,15 +172,16 @@ am_cdo_OBJECTS = cdo-cdo.$(OBJEXT) cdo-Adisit.$(OBJEXT) \
 	cdo-CDIread.$(OBJEXT) cdo-CDIwrite.$(OBJEXT) cdo-Cat.$(OBJEXT) \
 	cdo-Change.$(OBJEXT) cdo-Change_e5slm.$(OBJEXT) \
 	cdo-Cloudlayer.$(OBJEXT) cdo-CMOR.$(OBJEXT) \
+	cdo-CMOR_lite.$(OBJEXT) cdo-CMOR_table.$(OBJEXT) \
 	cdo-Collgrid.$(OBJEXT) cdo-Command.$(OBJEXT) \
 	cdo-Comp.$(OBJEXT) cdo-Compc.$(OBJEXT) \
 	cdo-Complextorect.$(OBJEXT) cdo-Cond.$(OBJEXT) \
 	cdo-Cond2.$(OBJEXT) cdo-Condc.$(OBJEXT) \
 	cdo-Consecstat.$(OBJEXT) cdo-Copy.$(OBJEXT) \
-	cdo-Deltime.$(OBJEXT) cdo-Derivepar.$(OBJEXT) \
-	cdo-Detrend.$(OBJEXT) cdo-Diff.$(OBJEXT) \
-	cdo-Distgrid.$(OBJEXT) cdo-Duplicate.$(OBJEXT) \
-	cdo-EOFs.$(OBJEXT) cdo-Eof3d.$(OBJEXT) \
+	cdo-Deltat.$(OBJEXT) cdo-Deltime.$(OBJEXT) \
+	cdo-Derivepar.$(OBJEXT) cdo-Detrend.$(OBJEXT) \
+	cdo-Diff.$(OBJEXT) cdo-Distgrid.$(OBJEXT) \
+	cdo-Duplicate.$(OBJEXT) cdo-EOFs.$(OBJEXT) cdo-Eof3d.$(OBJEXT) \
 	cdo-EcaIndices.$(OBJEXT) cdo-Echam5ini.$(OBJEXT) \
 	cdo-Enlarge.$(OBJEXT) cdo-Enlargegrid.$(OBJEXT) \
 	cdo-Ensstat.$(OBJEXT) cdo-Ensstat3.$(OBJEXT) \
@@ -193,13 +202,13 @@ am_cdo_OBJECTS = cdo-cdo.$(OBJEXT) cdo-Adisit.$(OBJEXT) \
 	cdo-Intntime.$(OBJEXT) cdo-Inttime.$(OBJEXT) \
 	cdo-Intyear.$(OBJEXT) cdo-Invert.$(OBJEXT) \
 	cdo-Invertlev.$(OBJEXT) cdo-Isosurface.$(OBJEXT) \
-	cdo-Kvl.$(OBJEXT) cdo-Log.$(OBJEXT) cdo-MapReduce.$(OBJEXT) \
+	cdo-Log.$(OBJEXT) cdo-MapReduce.$(OBJEXT) \
 	cdo-Maskbox.$(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-Nmltest.$(OBJEXT) cdo-Output.$(OBJEXT) \
+	cdo-Nmldump.$(OBJEXT) cdo-Output.$(OBJEXT) \
 	cdo-Outputgmt.$(OBJEXT) cdo-Pack.$(OBJEXT) \
 	cdo-Pardup.$(OBJEXT) cdo-Pinfo.$(OBJEXT) \
 	cdo-Pressure.$(OBJEXT) cdo-Regres.$(OBJEXT) \
@@ -208,14 +217,16 @@ am_cdo_OBJECTS = cdo-cdo.$(OBJEXT) cdo-Adisit.$(OBJEXT) \
 	cdo-Rhopot.$(OBJEXT) cdo-Rotuv.$(OBJEXT) cdo-Runpctl.$(OBJEXT) \
 	cdo-Runstat.$(OBJEXT) cdo-Seascount.$(OBJEXT) \
 	cdo-Seaspctl.$(OBJEXT) cdo-Seasstat.$(OBJEXT) \
-	cdo-Selbox.$(OBJEXT) cdo-Select.$(OBJEXT) \
-	cdo-Seloperator.$(OBJEXT) cdo-Selrec.$(OBJEXT) \
-	cdo-Seltime.$(OBJEXT) cdo-Selvar.$(OBJEXT) cdo-Set.$(OBJEXT) \
-	cdo-Setbox.$(OBJEXT) cdo-Setgatt.$(OBJEXT) \
-	cdo-Setgrid.$(OBJEXT) cdo-Sethalo.$(OBJEXT) \
-	cdo-Setmiss.$(OBJEXT) cdo-Setpartab.$(OBJEXT) \
-	cdo-Setrcaname.$(OBJEXT) cdo-Settime.$(OBJEXT) \
-	cdo-Setzaxis.$(OBJEXT) cdo-Showinfo.$(OBJEXT) \
+	cdo-Selbox.$(OBJEXT) cdo-Selindex.$(OBJEXT) \
+	cdo-Select.$(OBJEXT) cdo-Seloperator.$(OBJEXT) \
+	cdo-Selrec.$(OBJEXT) cdo-Seltime.$(OBJEXT) \
+	cdo-Selvar.$(OBJEXT) cdo-Set.$(OBJEXT) \
+	cdo-Setattribute.$(OBJEXT) cdo-Setbox.$(OBJEXT) \
+	cdo-Setgatt.$(OBJEXT) cdo-Setgrid.$(OBJEXT) \
+	cdo-Sethalo.$(OBJEXT) cdo-Setmiss.$(OBJEXT) \
+	cdo-Setpartab.$(OBJEXT) cdo-Setrcaname.$(OBJEXT) \
+	cdo-Settime.$(OBJEXT) cdo-Setzaxis.$(OBJEXT) \
+	cdo-Shiftxy.$(OBJEXT) cdo-Showinfo.$(OBJEXT) \
 	cdo-Sinfo.$(OBJEXT) cdo-Smooth.$(OBJEXT) cdo-Sort.$(OBJEXT) \
 	cdo-Sorttimestamp.$(OBJEXT) cdo-Specinfo.$(OBJEXT) \
 	cdo-Spectral.$(OBJEXT) cdo-Spectrum.$(OBJEXT) \
@@ -223,8 +234,8 @@ am_cdo_OBJECTS = cdo-cdo.$(OBJEXT) cdo-Adisit.$(OBJEXT) \
 	cdo-Splitsel.$(OBJEXT) cdo-Splittime.$(OBJEXT) \
 	cdo-Splityear.$(OBJEXT) cdo-Subtrend.$(OBJEXT) \
 	cdo-Tee.$(OBJEXT) cdo-Templates.$(OBJEXT) cdo-Test.$(OBJEXT) \
-	cdo-Tests.$(OBJEXT) cdo-Timedt.$(OBJEXT) \
-	cdo-Timcount.$(OBJEXT) cdo-Timpctl.$(OBJEXT) \
+	cdo-Tests.$(OBJEXT) cdo-Timcount.$(OBJEXT) \
+	cdo-Timcumsum.$(OBJEXT) cdo-Timpctl.$(OBJEXT) \
 	cdo-Timselpctl.$(OBJEXT) cdo-Timselstat.$(OBJEXT) \
 	cdo-Timsort.$(OBJEXT) cdo-Timstat.$(OBJEXT) \
 	cdo-Timstat2.$(OBJEXT) cdo-Timstat3.$(OBJEXT) \
@@ -495,44 +506,49 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 noinst_LTLIBRARIES = libcdo.la
-libcdo_la_SOURCES = cdo_int.h compare.h cdo_pthread.c cdo_vlist.c \
-	cdo_getopt.c cdo_getopt.h cdo_task.c cdo_task.h cdo_history.c \
-	cdi_uuid.h after_sptrans.c after_fctrans.c after_dvtrans.c \
-	after_vertint.c after_vertint.h after_namelist.c \
-	afterburnerlib.c afterburner.h vct_l191.h calendar.h \
-	constants.h constants.c color.c color.h commandline.c const.h \
-	counter.h datetime.c datetime.h dmemory.h ecacore.c ecacore.h \
-	ecautil.c ecautil.h error.h etopo.h temp.h mask.h exception.c \
-	expr.c expr.h expr_fun.c expr_fun.h expr_lex.c expr_yacc.c \
-	expr_yacc.h features.c field.c field.h field2.c fieldc.c \
-	fieldmem.c fieldmer.c fieldzon.c functs.h gradsdeslib.c \
-	gradsdeslib.h grid.c grid.h grid_area.c grid_gme.c grid_lcc.c \
-	grid_rot.c gridreference.c griddes.c griddes.h griddes_h5.c \
-	griddes_nc.c hetaeta.c hetaeta.h institution.c interpol.c \
-	interpol.h job.c juldate.c grid_search.c grid_search.h \
-	kvlist.c kvlist.h list.c list.h merge_sort2.c merge_sort2.h \
-	modules.c modules.h namelist.c namelist.h normal.c \
-	nth_element.c nth_element.h operator_help.h par_io.c par_io.h \
-	percentiles_hist.c percentiles_hist.h percentiles.c \
-	percentiles.h pipe.c pipe.h pmlist.c pmlist.h \
-	pragma_omp_atomic_update.h printinfo.h process.c process.h \
-	pstream.c pstream.h pstream_write.h pstream_int.h \
-	pthread_debug.c pthread_debug.h readline.c realtime.c remap.h \
-	remaplib.c remapsort.c remap_scrip_io.c remap_search_reg2d.c \
-	remap_search_latbins.c remap_store_link.c remap_store_link.h \
-	remap_store_link_cnsrv.c remap_store_link_cnsrv.h \
-	remap_conserv.c remap_conserv_scrip.c remap_distwgt.c \
-	remap_bicubic_scrip.c remap_bilinear_scrip.c stdnametable.c \
-	stdnametable.h specspace.c specspace.h statistic.c statistic.h \
-	table.c text.c text.h timebase.h timer.c userlog.c uthash.h \
-	util.c util.h zaxis.c kdtreelib/kdtree.h \
+libcdo_la_SOURCES = array.h array.c cdo_int.h compare.h cdo_pthread.c \
+	cdo_vlist.c cdo_getopt.c cdo_getopt.h cdo_task.c cdo_task.h \
+	cdo_history.c cdi_uuid.h cmortable_parser.c after_sptrans.c \
+	after_fctrans.c after_dvtrans.c after_vertint.c \
+	after_vertint.h after_namelist.c afterburnerlib.c \
+	afterburner.h vct_l191.h calendar.h constants.h constants.c \
+	color.c color.h commandline.c const.h convert_units.c \
+	convert_units.h counter.h datetime.c datetime.h dmemory.h \
+	ecacore.c ecacore.h ecautil.c ecautil.h error.h etopo.h temp.h \
+	mask.h exception.c expr.c expr.h expr_fun.c expr_fun.h \
+	expr_lex.c expr_yacc.c expr_yacc.h features.c field.c field.h \
+	field2.c fieldc.c fieldmem.c fieldmer.c fieldzon.c functs.h \
+	gradsdeslib.c gradsdeslib.h grid.c grid.h grid_area.c \
+	grid_gme.c grid_lcc.c grid_rot.c grid_from_name.c grid_read.c \
+	grid_read_pingo.c grid_print.c gridreference.c griddes.c \
+	griddes.h griddes_h5.c griddes_nc.c hetaeta.c hetaeta.h \
+	institution.c interpol.c interpol.h job.c juldate.c \
+	grid_search.c grid_search.h listarray.c listarray.h list.c \
+	list.h listbuf.c listbuf.h merge_sort2.c merge_sort2.h \
+	modules.c modules.h namelist.c namelist.h namelist_parser.c \
+	normal.c nth_element.c nth_element.h operator_help.h par_io.c \
+	par_io.h parse_literal.c percentiles_hist.c percentiles_hist.h \
+	percentiles.c percentiles.h pipe.c pipe.h pmlist.c pmlist.h \
+	sellist.c sellist.h pragma_omp_atomic_update.h printinfo.h \
+	process.c process.h pstream.c pstream.h pstream_write.h \
+	pstream_int.h pthread_debug.c pthread_debug.h readline.c \
+	realtime.c remap.h remaplib.c remapsort.c remap_scrip_io.c \
+	remap_search_reg2d.c remap_search_latbins.c remap_store_link.c \
+	remap_store_link.h remap_store_link_cnsrv.c \
+	remap_store_link_cnsrv.h remap_conserv.c remap_conserv_scrip.c \
+	remap_distwgt.c remap_bicubic_scrip.c remap_bilinear_scrip.c \
+	stdnametable.c stdnametable.h specspace.c specspace.h \
+	statistic.c statistic.h table.c text.c text.h timebase.h \
+	timer.c userlog.c uthash.h util.c util.h zaxis_print.c zaxis.c \
+	json/jsmn.h json/jsmn.c kdtreelib/kdtree.h \
 	kdtreelib/kdtree_cartesian.c kdtreelib/kdtree_common.c \
-	kdtreelib/kdtree_spherical.c kdtreelib/pmergesort.c \
-	kdtreelib/pqueue.c kdtreelib/pqueue.h clipping/clipping.c \
-	clipping/clipping.h clipping/area.c clipping/area.h \
-	clipping/ensure_array_size.c clipping/ensure_array_size.h \
-	clipping/geometry.h clipping/grid.h clipping/points.h \
-	clipping/dep_list.h clipping/grid_cell.c clipping/grid_cell.h \
+	kdtreelib/kdtree_spherical.c kdtreelib/qsort.c \
+	kdtreelib/pmergesort.c kdtreelib/pqueue.c kdtreelib/pqueue.h \
+	clipping/clipping.c clipping/clipping.h clipping/area.c \
+	clipping/area.h clipping/ensure_array_size.c \
+	clipping/ensure_array_size.h clipping/geometry.h \
+	clipping/grid.h clipping/points.h clipping/dep_list.h \
+	clipping/grid_cell.c clipping/grid_cell.h \
 	clipping/intersection.c clipping/utils.c clipping/utils.h
 #
 #if ENABLE_NEARPT3
@@ -546,32 +562,32 @@ libcdo_la_SOURCES = cdo_int.h compare.h cdo_pthread.c cdo_vlist.c \
 #if ENABLE_MAGICS
 cdo_SOURCES = cdo.c Adisit.c Afterburner.c Arith.c Arithc.c \
 	Arithdays.c Arithlat.c CDItest.c CDIread.c CDIwrite.c Cat.c \
-	Change.c Change_e5slm.c Cloudlayer.c CMOR.c Collgrid.c \
-	Command.c Comp.c Compc.c Complextorect.c Cond.c Cond2.c \
-	Condc.c Consecstat.c Copy.c Deltime.c Derivepar.c Detrend.c \
-	Diff.c Distgrid.c Duplicate.c EOFs.c Eof3d.c EcaIndices.c \
-	Echam5ini.c Enlarge.c Enlargegrid.c Ensstat.c Ensstat3.c \
-	Ensval.c Eofcoeff.c Eofcoeff3d.c Exprf.c FC.c Filedes.c \
-	Fillmiss.c Filter.c Fldrms.c Fldstat.c Fldstat2.c Fourier.c \
-	Gengrid.c Gradsdes.c Gridboxstat.c Gridcell.c Gridsearch.c \
-	Harmonic.c Hi.c Histogram.c Importamsr.c Importbinary.c \
-	Importcmsaf.c Importobs.c Info.c Input.c Intgrid.c \
-	Intgridtraj.c Intlevel.c Intlevel3d.c Intntime.c Inttime.c \
-	Intyear.c Invert.c Invertlev.c Isosurface.c Kvl.c Log.c \
-	MapReduce.c Maskbox.c Mastrfu.c Math.c Merge.c Mergegrid.c \
-	Mergetime.c Merstat.c Monarith.c Mrotuv.c Mrotuvb.c Ninfo.c \
-	Nmltest.c Output.c Outputgmt.c Pack.c Pardup.c Pinfo.c \
-	Pressure.c Regres.c Remap.c Remapeta.c Replace.c \
-	Replacevalues.c Rhopot.c Rotuv.c Runpctl.c Runstat.c \
-	Seascount.c Seaspctl.c Seasstat.c Selbox.c Select.c \
-	Seloperator.c Selrec.c Seltime.c Selvar.c Set.c Setbox.c \
-	Setgatt.c Setgrid.c Sethalo.c Setmiss.c Setpartab.c \
-	Setrcaname.c Settime.c Setzaxis.c Showinfo.c Sinfo.c Smooth.c \
-	Sort.c Sorttimestamp.c Specinfo.c Spectral.c Spectrum.c \
-	Split.c Splitrec.c Splitsel.c Splittime.c Splityear.c \
-	Subtrend.c Tee.c Templates.c Test.c Tests.c Timedt.c \
-	Timcount.c Timpctl.c Timselpctl.c Timselstat.c Timsort.c \
-	Timstat.c Timstat2.c Timstat3.c Tinfo.c Tocomplex.c \
+	Change.c Change_e5slm.c Cloudlayer.c CMOR.c CMOR_lite.c \
+	CMOR_table.c Collgrid.c Command.c Comp.c Compc.c \
+	Complextorect.c Cond.c Cond2.c Condc.c Consecstat.c Copy.c \
+	Deltat.c Deltime.c Derivepar.c Detrend.c Diff.c Distgrid.c \
+	Duplicate.c EOFs.c Eof3d.c EcaIndices.c Echam5ini.c Enlarge.c \
+	Enlargegrid.c Ensstat.c Ensstat3.c Ensval.c Eofcoeff.c \
+	Eofcoeff3d.c Exprf.c FC.c Filedes.c Fillmiss.c Filter.c \
+	Fldrms.c Fldstat.c Fldstat2.c Fourier.c Gengrid.c Gradsdes.c \
+	Gridboxstat.c Gridcell.c Gridsearch.c Harmonic.c Hi.c \
+	Histogram.c Importamsr.c Importbinary.c Importcmsaf.c \
+	Importobs.c Info.c Input.c Intgrid.c Intgridtraj.c Intlevel.c \
+	Intlevel3d.c Intntime.c Inttime.c Intyear.c Invert.c \
+	Invertlev.c Isosurface.c Log.c MapReduce.c Maskbox.c Mastrfu.c \
+	Math.c Merge.c Mergegrid.c Mergetime.c Merstat.c Monarith.c \
+	Mrotuv.c Mrotuvb.c Ninfo.c Nmldump.c Output.c Outputgmt.c \
+	Pack.c Pardup.c Pinfo.c Pressure.c Regres.c Remap.c Remapeta.c \
+	Replace.c Replacevalues.c Rhopot.c Rotuv.c Runpctl.c Runstat.c \
+	Seascount.c Seaspctl.c Seasstat.c Selbox.c Selindex.c Select.c \
+	Seloperator.c Selrec.c Seltime.c Selvar.c Set.c Setattribute.c \
+	Setbox.c Setgatt.c Setgrid.c Sethalo.c Setmiss.c Setpartab.c \
+	Setrcaname.c Settime.c Setzaxis.c Shiftxy.c Showinfo.c Sinfo.c \
+	Smooth.c Sort.c Sorttimestamp.c Specinfo.c Spectral.c \
+	Spectrum.c Split.c Splitrec.c Splitsel.c Splittime.c \
+	Splityear.c Subtrend.c Tee.c Templates.c Test.c Tests.c \
+	Timcount.c Timcumsum.c Timpctl.c Timselpctl.c Timselstat.c \
+	Timsort.c Timstat.c Timstat2.c Timstat3.c Tinfo.c Tocomplex.c \
 	Transpose.c Trend.c Trms.c Tstepcount.c Vargen.c Varrms.c \
 	Vertintml.c Vertintap.c Vertstat.c Vertcum.c Vertwind.c \
 	Verifygrid.c Wct.c Wind.c Writegrid.c Writerandom.c XTimstat.c \
@@ -662,6 +678,14 @@ clean-noinstLTLIBRARIES:
 	  echo rm -f $${locs}; \
 	  rm -f $${locs}; \
 	}
+json/$(am__dirstamp):
+	@$(MKDIR_P) json
+	@: > json/$(am__dirstamp)
+json/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) json/$(DEPDIR)
+	@: > json/$(DEPDIR)/$(am__dirstamp)
+json/libcdo_la-jsmn.lo: json/$(am__dirstamp) \
+	json/$(DEPDIR)/$(am__dirstamp)
 kdtreelib/$(am__dirstamp):
 	@$(MKDIR_P) kdtreelib
 	@: > kdtreelib/$(am__dirstamp)
@@ -674,6 +698,8 @@ kdtreelib/libcdo_la-kdtree_common.lo: kdtreelib/$(am__dirstamp) \
 	kdtreelib/$(DEPDIR)/$(am__dirstamp)
 kdtreelib/libcdo_la-kdtree_spherical.lo: kdtreelib/$(am__dirstamp) \
 	kdtreelib/$(DEPDIR)/$(am__dirstamp)
+kdtreelib/libcdo_la-qsort.lo: kdtreelib/$(am__dirstamp) \
+	kdtreelib/$(DEPDIR)/$(am__dirstamp)
 kdtreelib/libcdo_la-pmergesort.lo: kdtreelib/$(am__dirstamp) \
 	kdtreelib/$(DEPDIR)/$(am__dirstamp)
 kdtreelib/libcdo_la-pqueue.lo: kdtreelib/$(am__dirstamp) \
@@ -770,6 +796,8 @@ mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
 	-rm -f clipping/*.$(OBJEXT)
 	-rm -f clipping/*.lo
+	-rm -f json/*.$(OBJEXT)
+	-rm -f json/*.lo
 	-rm -f kdtreelib/*.$(OBJEXT)
 	-rm -f kdtreelib/*.lo
 
@@ -786,6 +814,8 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-CDItest.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-CDIwrite.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-CMOR.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-CMOR_lite.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-CMOR_table.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Cat.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-CdoMagicsMapper.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Change.Po at am__quote@
@@ -801,6 +831,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Condc.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Consecstat.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Copy.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Deltat.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Deltime.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Derivepar.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Detrend.Po at am__quote@
@@ -851,7 +882,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Invert.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Invertlev.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Isosurface.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Kvl.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Log.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Maggraph.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Magplot.Po at am__quote@
@@ -868,7 +898,7 @@ distclean-compile:
 @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@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Ninfo.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Nmltest.Po at am__quote@
+ at 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@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Outputgmt.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Pack.Po at am__quote@
@@ -889,11 +919,13 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Seasstat.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Selbox.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Select.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Selindex.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Seloperator.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Selrec.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Seltime.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Selvar.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Set.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Setattribute.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Setbox.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Setgatt.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Setgrid.Po at am__quote@
@@ -903,6 +935,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Setrcaname.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Settime.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Setzaxis.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Shiftxy.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Showinfo.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Sinfo.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Smooth.Po at am__quote@
@@ -923,7 +956,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Test.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Tests.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Timcount.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Timedt.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Timcumsum.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Timpctl.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Timselpctl.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/cdo-Timselstat.Po at am__quote@
@@ -976,14 +1009,17 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-after_sptrans.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-after_vertint.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-afterburnerlib.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-array.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@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-cdo_task.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-cdo_vlist.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-cmortable_parser.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-color.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-commandline.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-constants.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-convert_units.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-datetime.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-ecacore.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-ecautil.Plo at am__quote@
@@ -1002,8 +1038,12 @@ distclean-compile:
 @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@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-grid_from_name.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-grid_gme.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-grid_lcc.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-grid_print.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-grid_read.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-grid_read_pingo.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-grid_rot.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-grid_search.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-griddes.Plo at am__quote@
@@ -1015,14 +1055,17 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-interpol.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-job.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-juldate.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-kvlist.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-list.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-listarray.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-listbuf.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-merge_sort2.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-modules.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-namelist.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-namelist_parser.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-normal.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-nth_element.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-par_io.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-parse_literal.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-percentiles.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-percentiles_hist.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-pipe.Plo at am__quote@
@@ -1044,6 +1087,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-remap_store_link_cnsrv.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-remaplib.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-remapsort.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-sellist.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-specspace.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-statistic.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-stdnametable.Plo at am__quote@
@@ -1053,17 +1097,20 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-userlog.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-util.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-zaxis.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libcdo_la-zaxis_print.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at clipping/$(DEPDIR)/libcdo_la-area.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at clipping/$(DEPDIR)/libcdo_la-clipping.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at clipping/$(DEPDIR)/libcdo_la-ensure_array_size.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at clipping/$(DEPDIR)/libcdo_la-grid_cell.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at clipping/$(DEPDIR)/libcdo_la-intersection.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at clipping/$(DEPDIR)/libcdo_la-utils.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at json/$(DEPDIR)/libcdo_la-jsmn.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at kdtreelib/$(DEPDIR)/libcdo_la-kdtree_cartesian.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at kdtreelib/$(DEPDIR)/libcdo_la-kdtree_common.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at kdtreelib/$(DEPDIR)/libcdo_la-kdtree_spherical.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at kdtreelib/$(DEPDIR)/libcdo_la-pmergesort.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at kdtreelib/$(DEPDIR)/libcdo_la-pqueue.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at kdtreelib/$(DEPDIR)/libcdo_la-qsort.Plo at am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
@@ -1089,6 +1136,13 @@ 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-array.lo: array.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-array.lo -MD -MP -MF $(DEPDIR)/libcdo_la-array.Tpo -c -o libcdo_la-array.lo `test -f 'array.c' || echo '$(srcdir)/'`array.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-array.Tpo $(DEPDIR)/libcdo_la-array.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='array.c' object='libcdo_la-array.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-array.lo `test -f 'array.c' || echo '$(srcdir)/'`array.c
+
 libcdo_la-cdo_pthread.lo: cdo_pthread.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 libcdo_la-cdo_pthread.lo -MD -MP -MF $(DEPDIR)/libcdo_la-cdo_pthread.Tpo -c -o libcdo_la-cdo_pthread.lo `test -f 'cdo_pthread.c' || echo '$(srcdir)/'`cdo_pthread.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-cdo_pthread.Tpo $(DEPDIR)/libcdo_la-cdo_pthread.Plo
@@ -1124,6 +1178,13 @@ libcdo_la-cdo_history.lo: cdo_history.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @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-cdo_history.lo `test -f 'cdo_history.c' || echo '$(srcdir)/'`cdo_history.c
 
+libcdo_la-cmortable_parser.lo: cmortable_parser.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-cmortable_parser.lo -MD -MP -MF $(DEPDIR)/libcdo_la-cmortable_parser.Tpo -c -o libcdo_la-cmortable_parser.lo `test -f 'cmortable_parser.c' || echo '$(srcdir)/'`cmortable_parser.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-cmortable_parser.Tpo $(DEPDIR)/libcdo_la-cmortable_parser.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='cmortable_parser.c' object='libcdo_la-cmortable_parser.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-cmortable_parser.lo `test -f 'cmortable_parser.c' || echo '$(srcdir)/'`cmortable_parser.c
+
 libcdo_la-after_sptrans.lo: after_sptrans.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 libcdo_la-after_sptrans.lo -MD -MP -MF $(DEPDIR)/libcdo_la-after_sptrans.Tpo -c -o libcdo_la-after_sptrans.lo `test -f 'after_sptrans.c' || echo '$(srcdir)/'`after_sptrans.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-after_sptrans.Tpo $(DEPDIR)/libcdo_la-after_sptrans.Plo
@@ -1187,6 +1248,13 @@ libcdo_la-commandline.lo: commandline.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @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-commandline.lo `test -f 'commandline.c' || echo '$(srcdir)/'`commandline.c
 
+libcdo_la-convert_units.lo: convert_units.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-convert_units.lo -MD -MP -MF $(DEPDIR)/libcdo_la-convert_units.Tpo -c -o libcdo_la-convert_units.lo `test -f 'convert_units.c' || echo '$(srcdir)/'`convert_units.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-convert_units.Tpo $(DEPDIR)/libcdo_la-convert_units.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='convert_units.c' object='libcdo_la-convert_units.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-convert_units.lo `test -f 'convert_units.c' || echo '$(srcdir)/'`convert_units.c
+
 libcdo_la-datetime.lo: datetime.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 libcdo_la-datetime.lo -MD -MP -MF $(DEPDIR)/libcdo_la-datetime.Tpo -c -o libcdo_la-datetime.lo `test -f 'datetime.c' || echo '$(srcdir)/'`datetime.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-datetime.Tpo $(DEPDIR)/libcdo_la-datetime.Plo
@@ -1334,6 +1402,34 @@ libcdo_la-grid_rot.lo: grid_rot.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @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-grid_rot.lo `test -f 'grid_rot.c' || echo '$(srcdir)/'`grid_rot.c
 
+libcdo_la-grid_from_name.lo: grid_from_name.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-grid_from_name.lo -MD -MP -MF $(DEPDIR)/libcdo_la-grid_from_name.Tpo -c -o libcdo_la-grid_from_name.lo `test -f 'grid_from_name.c' || echo '$(srcdir)/'`grid_from_name.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-grid_from_name.Tpo $(DEPDIR)/libcdo_la-grid_from_name.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='grid_from_name.c' object='libcdo_la-grid_from_name.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-grid_from_name.lo `test -f 'grid_from_name.c' || echo '$(srcdir)/'`grid_from_name.c
+
+libcdo_la-grid_read.lo: grid_read.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-grid_read.lo -MD -MP -MF $(DEPDIR)/libcdo_la-grid_read.Tpo -c -o libcdo_la-grid_read.lo `test -f 'grid_read.c' || echo '$(srcdir)/'`grid_read.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-grid_read.Tpo $(DEPDIR)/libcdo_la-grid_read.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='grid_read.c' object='libcdo_la-grid_read.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-grid_read.lo `test -f 'grid_read.c' || echo '$(srcdir)/'`grid_read.c
+
+libcdo_la-grid_read_pingo.lo: grid_read_pingo.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-grid_read_pingo.lo -MD -MP -MF $(DEPDIR)/libcdo_la-grid_read_pingo.Tpo -c -o libcdo_la-grid_read_pingo.lo `test -f 'grid_read_pingo.c' || echo '$(srcdir)/'`grid_read_pingo.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-grid_read_pingo.Tpo $(DEPDIR)/libcdo_la-grid_read_pingo.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='grid_read_pingo.c' object='libcdo_la-grid_read_pingo.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-grid_read_pingo.lo `test -f 'grid_read_pingo.c' || echo '$(srcdir)/'`grid_read_pingo.c
+
+libcdo_la-grid_print.lo: grid_print.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-grid_print.lo -MD -MP -MF $(DEPDIR)/libcdo_la-grid_print.Tpo -c -o libcdo_la-grid_print.lo `test -f 'grid_print.c' || echo '$(srcdir)/'`grid_print.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-grid_print.Tpo $(DEPDIR)/libcdo_la-grid_print.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='grid_print.c' object='libcdo_la-grid_print.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-grid_print.lo `test -f 'grid_print.c' || echo '$(srcdir)/'`grid_print.c
+
 libcdo_la-gridreference.lo: gridreference.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 libcdo_la-gridreference.lo -MD -MP -MF $(DEPDIR)/libcdo_la-gridreference.Tpo -c -o libcdo_la-gridreference.lo `test -f 'gridreference.c' || echo '$(srcdir)/'`gridreference.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-gridreference.Tpo $(DEPDIR)/libcdo_la-gridreference.Plo
@@ -1404,12 +1500,12 @@ libcdo_la-grid_search.lo: grid_search.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @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-grid_search.lo `test -f 'grid_search.c' || echo '$(srcdir)/'`grid_search.c
 
-libcdo_la-kvlist.lo: kvlist.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-kvlist.lo -MD -MP -MF $(DEPDIR)/libcdo_la-kvlist.Tpo -c -o libcdo_la-kvlist.lo `test -f 'kvlist.c' || echo '$(srcdir)/'`kvlist.c
- at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-kvlist.Tpo $(DEPDIR)/libcdo_la-kvlist.Plo
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='kvlist.c' object='libcdo_la-kvlist.lo' libtool=yes @AMDEPBACKSLASH@
+libcdo_la-listarray.lo: listarray.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-listarray.lo -MD -MP -MF $(DEPDIR)/libcdo_la-listarray.Tpo -c -o libcdo_la-listarray.lo `test -f 'listarray.c' || echo '$(srcdir)/'`listarray.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-listarray.Tpo $(DEPDIR)/libcdo_la-listarray.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='listarray.c' object='libcdo_la-listarray.lo' libtool=yes @AMDEPBACKSLASH@
 @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-kvlist.lo `test -f 'kvlist.c' || echo '$(srcdir)/'`kvlist.c
+ 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-listarray.lo `test -f 'listarray.c' || echo '$(srcdir)/'`listarray.c
 
 libcdo_la-list.lo: list.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 libcdo_la-list.lo -MD -MP -MF $(DEPDIR)/libcdo_la-list.Tpo -c -o libcdo_la-list.lo `test -f 'list.c' || echo '$(srcdir)/'`list.c
@@ -1418,6 +1514,13 @@ libcdo_la-list.lo: list.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @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-list.lo `test -f 'list.c' || echo '$(srcdir)/'`list.c
 
+libcdo_la-listbuf.lo: listbuf.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-listbuf.lo -MD -MP -MF $(DEPDIR)/libcdo_la-listbuf.Tpo -c -o libcdo_la-listbuf.lo `test -f 'listbuf.c' || echo '$(srcdir)/'`listbuf.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-listbuf.Tpo $(DEPDIR)/libcdo_la-listbuf.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='listbuf.c' object='libcdo_la-listbuf.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-listbuf.lo `test -f 'listbuf.c' || echo '$(srcdir)/'`listbuf.c
+
 libcdo_la-merge_sort2.lo: merge_sort2.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 libcdo_la-merge_sort2.lo -MD -MP -MF $(DEPDIR)/libcdo_la-merge_sort2.Tpo -c -o libcdo_la-merge_sort2.lo `test -f 'merge_sort2.c' || echo '$(srcdir)/'`merge_sort2.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-merge_sort2.Tpo $(DEPDIR)/libcdo_la-merge_sort2.Plo
@@ -1439,6 +1542,13 @@ libcdo_la-namelist.lo: namelist.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @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-namelist.lo `test -f 'namelist.c' || echo '$(srcdir)/'`namelist.c
 
+libcdo_la-namelist_parser.lo: namelist_parser.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-namelist_parser.lo -MD -MP -MF $(DEPDIR)/libcdo_la-namelist_parser.Tpo -c -o libcdo_la-namelist_parser.lo `test -f 'namelist_parser.c' || echo '$(srcdir)/'`namelist_parser.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-namelist_parser.Tpo $(DEPDIR)/libcdo_la-namelist_parser.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='namelist_parser.c' object='libcdo_la-namelist_parser.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-namelist_parser.lo `test -f 'namelist_parser.c' || echo '$(srcdir)/'`namelist_parser.c
+
 libcdo_la-normal.lo: normal.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 libcdo_la-normal.lo -MD -MP -MF $(DEPDIR)/libcdo_la-normal.Tpo -c -o libcdo_la-normal.lo `test -f 'normal.c' || echo '$(srcdir)/'`normal.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-normal.Tpo $(DEPDIR)/libcdo_la-normal.Plo
@@ -1460,6 +1570,13 @@ libcdo_la-par_io.lo: par_io.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @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-par_io.lo `test -f 'par_io.c' || echo '$(srcdir)/'`par_io.c
 
+libcdo_la-parse_literal.lo: parse_literal.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-parse_literal.lo -MD -MP -MF $(DEPDIR)/libcdo_la-parse_literal.Tpo -c -o libcdo_la-parse_literal.lo `test -f 'parse_literal.c' || echo '$(srcdir)/'`parse_literal.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-parse_literal.Tpo $(DEPDIR)/libcdo_la-parse_literal.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='parse_literal.c' object='libcdo_la-parse_literal.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-parse_literal.lo `test -f 'parse_literal.c' || echo '$(srcdir)/'`parse_literal.c
+
 libcdo_la-percentiles_hist.lo: percentiles_hist.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 libcdo_la-percentiles_hist.lo -MD -MP -MF $(DEPDIR)/libcdo_la-percentiles_hist.Tpo -c -o libcdo_la-percentiles_hist.lo `test -f 'percentiles_hist.c' || echo '$(srcdir)/'`percentiles_hist.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-percentiles_hist.Tpo $(DEPDIR)/libcdo_la-percentiles_hist.Plo
@@ -1488,6 +1605,13 @@ libcdo_la-pmlist.lo: pmlist.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @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-pmlist.lo `test -f 'pmlist.c' || echo '$(srcdir)/'`pmlist.c
 
+libcdo_la-sellist.lo: sellist.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-sellist.lo -MD -MP -MF $(DEPDIR)/libcdo_la-sellist.Tpo -c -o libcdo_la-sellist.lo `test -f 'sellist.c' || echo '$(srcdir)/'`sellist.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-sellist.Tpo $(DEPDIR)/libcdo_la-sellist.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='sellist.c' object='libcdo_la-sellist.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-sellist.lo `test -f 'sellist.c' || echo '$(srcdir)/'`sellist.c
+
 libcdo_la-process.lo: process.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 libcdo_la-process.lo -MD -MP -MF $(DEPDIR)/libcdo_la-process.Tpo -c -o libcdo_la-process.lo `test -f 'process.c' || echo '$(srcdir)/'`process.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-process.Tpo $(DEPDIR)/libcdo_la-process.Plo
@@ -1663,6 +1787,13 @@ libcdo_la-util.lo: util.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @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-util.lo `test -f 'util.c' || echo '$(srcdir)/'`util.c
 
+libcdo_la-zaxis_print.lo: zaxis_print.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-zaxis_print.lo -MD -MP -MF $(DEPDIR)/libcdo_la-zaxis_print.Tpo -c -o libcdo_la-zaxis_print.lo `test -f 'zaxis_print.c' || echo '$(srcdir)/'`zaxis_print.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-zaxis_print.Tpo $(DEPDIR)/libcdo_la-zaxis_print.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='zaxis_print.c' object='libcdo_la-zaxis_print.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-zaxis_print.lo `test -f 'zaxis_print.c' || echo '$(srcdir)/'`zaxis_print.c
+
 libcdo_la-zaxis.lo: zaxis.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 libcdo_la-zaxis.lo -MD -MP -MF $(DEPDIR)/libcdo_la-zaxis.Tpo -c -o libcdo_la-zaxis.lo `test -f 'zaxis.c' || echo '$(srcdir)/'`zaxis.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-zaxis.Tpo $(DEPDIR)/libcdo_la-zaxis.Plo
@@ -1670,6 +1801,13 @@ libcdo_la-zaxis.lo: zaxis.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @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-zaxis.lo `test -f 'zaxis.c' || echo '$(srcdir)/'`zaxis.c
 
+json/libcdo_la-jsmn.lo: json/jsmn.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 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
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) json/$(DEPDIR)/libcdo_la-jsmn.Tpo json/$(DEPDIR)/libcdo_la-jsmn.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='json/jsmn.c' object='json/libcdo_la-jsmn.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 json/libcdo_la-jsmn.lo `test -f 'json/jsmn.c' || echo '$(srcdir)/'`json/jsmn.c
+
 kdtreelib/libcdo_la-kdtree_cartesian.lo: kdtreelib/kdtree_cartesian.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 kdtreelib/libcdo_la-kdtree_cartesian.lo -MD -MP -MF kdtreelib/$(DEPDIR)/libcdo_la-kdtree_cartesian.Tpo -c -o kdtreelib/libcdo_la-kdtree_cartesian.lo `test -f 'kdtreelib/kdtree_cartesian.c' || echo '$(srcdir)/'`kdtreelib/kdtree_cartesian.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) kdtreelib/$(DEPDIR)/libcdo_la-kdtree_cartesian.Tpo kdtreelib/$(DEPDIR)/libcdo_la-kdtree_cartesian.Plo
@@ -1691,6 +1829,13 @@ kdtreelib/libcdo_la-kdtree_spherical.lo: kdtreelib/kdtree_spherical.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @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 kdtreelib/libcdo_la-kdtree_spherical.lo `test -f 'kdtreelib/kdtree_spherical.c' || echo '$(srcdir)/'`kdtreelib/kdtree_spherical.c
 
+kdtreelib/libcdo_la-qsort.lo: kdtreelib/qsort.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 kdtreelib/libcdo_la-qsort.lo -MD -MP -MF kdtreelib/$(DEPDIR)/libcdo_la-qsort.Tpo -c -o kdtreelib/libcdo_la-qsort.lo `test -f 'kdtreelib/qsort.c' || echo '$(srcdir)/'`kdtreelib/qsort.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) kdtreelib/$(DEPDIR)/libcdo_la-qsort.Tpo kdtreelib/$(DEPDIR)/libcdo_la-qsort.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='kdtreelib/qsort.c' object='kdtreelib/libcdo_la-qsort.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 kdtreelib/libcdo_la-qsort.lo `test -f 'kdtreelib/qsort.c' || echo '$(srcdir)/'`kdtreelib/qsort.c
+
 kdtreelib/libcdo_la-pmergesort.lo: kdtreelib/pmergesort.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 kdtreelib/libcdo_la-pmergesort.lo -MD -MP -MF kdtreelib/$(DEPDIR)/libcdo_la-pmergesort.Tpo -c -o kdtreelib/libcdo_la-pmergesort.lo `test -f 'kdtreelib/pmergesort.c' || echo '$(srcdir)/'`kdtreelib/pmergesort.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) kdtreelib/$(DEPDIR)/libcdo_la-pmergesort.Tpo kdtreelib/$(DEPDIR)/libcdo_la-pmergesort.Plo
@@ -1957,6 +2102,34 @@ cdo-CMOR.obj: CMOR.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-CMOR.obj `if test -f 'CMOR.c'; then $(CYGPATH_W) 'CMOR.c'; else $(CYGPATH_W) '$(srcdir)/CMOR.c'; fi`
 
+cdo-CMOR_lite.o: CMOR_lite.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-CMOR_lite.o -MD -MP -MF $(DEPDIR)/cdo-CMOR_lite.Tpo -c -o cdo-CMOR_lite.o `test -f 'CMOR_lite.c' || echo '$(srcdir)/'`CMOR_lite.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-CMOR_lite.Tpo $(DEPDIR)/cdo-CMOR_lite.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='CMOR_lite.c' object='cdo-CMOR_lite.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-CMOR_lite.o `test -f 'CMOR_lite.c' || echo '$(srcdir)/'`CMOR_lite.c
+
+cdo-CMOR_lite.obj: CMOR_lite.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-CMOR_lite.obj -MD -MP -MF $(DEPDIR)/cdo-CMOR_lite.Tpo -c -o cdo-CMOR_lite.obj `if test -f 'CMOR_lite.c'; then $(CYGPATH_W) 'CMOR_lite.c'; else $(CYGPATH_W) '$(srcdir)/CMOR_lite.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-CMOR_lite.Tpo $(DEPDIR)/cdo-CMOR_lite.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='CMOR_lite.c' object='cdo-CMOR_lite.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-CMOR_lite.obj `if test -f 'CMOR_lite.c'; then $(CYGPATH_W) 'CMOR_lite.c'; else $(CYGPATH_W) '$(srcdir)/CMOR_lite.c'; fi`
+
+cdo-CMOR_table.o: CMOR_table.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-CMOR_table.o -MD -MP -MF $(DEPDIR)/cdo-CMOR_table.Tpo -c -o cdo-CMOR_table.o `test -f 'CMOR_table.c' || echo '$(srcdir)/'`CMOR_table.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-CMOR_table.Tpo $(DEPDIR)/cdo-CMOR_table.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='CMOR_table.c' object='cdo-CMOR_table.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-CMOR_table.o `test -f 'CMOR_table.c' || echo '$(srcdir)/'`CMOR_table.c
+
+cdo-CMOR_table.obj: CMOR_table.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-CMOR_table.obj -MD -MP -MF $(DEPDIR)/cdo-CMOR_table.Tpo -c -o cdo-CMOR_table.obj `if test -f 'CMOR_table.c'; then $(CYGPATH_W) 'CMOR_table.c'; else $(CYGPATH_W) '$(srcdir)/CMOR_table.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-CMOR_table.Tpo $(DEPDIR)/cdo-CMOR_table.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='CMOR_table.c' object='cdo-CMOR_table.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-CMOR_table.obj `if test -f 'CMOR_table.c'; then $(CYGPATH_W) 'CMOR_table.c'; else $(CYGPATH_W) '$(srcdir)/CMOR_table.c'; fi`
+
 cdo-Collgrid.o: Collgrid.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Collgrid.o -MD -MP -MF $(DEPDIR)/cdo-Collgrid.Tpo -c -o cdo-Collgrid.o `test -f 'Collgrid.c' || echo '$(srcdir)/'`Collgrid.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Collgrid.Tpo $(DEPDIR)/cdo-Collgrid.Po
@@ -2097,6 +2270,20 @@ cdo-Copy.obj: Copy.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Copy.obj `if test -f 'Copy.c'; then $(CYGPATH_W) 'Copy.c'; else $(CYGPATH_W) '$(srcdir)/Copy.c'; fi`
 
+cdo-Deltat.o: Deltat.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Deltat.o -MD -MP -MF $(DEPDIR)/cdo-Deltat.Tpo -c -o cdo-Deltat.o `test -f 'Deltat.c' || echo '$(srcdir)/'`Deltat.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Deltat.Tpo $(DEPDIR)/cdo-Deltat.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Deltat.c' object='cdo-Deltat.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Deltat.o `test -f 'Deltat.c' || echo '$(srcdir)/'`Deltat.c
+
+cdo-Deltat.obj: Deltat.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Deltat.obj -MD -MP -MF $(DEPDIR)/cdo-Deltat.Tpo -c -o cdo-Deltat.obj `if test -f 'Deltat.c'; then $(CYGPATH_W) 'Deltat.c'; else $(CYGPATH_W) '$(srcdir)/Deltat.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Deltat.Tpo $(DEPDIR)/cdo-Deltat.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Deltat.c' object='cdo-Deltat.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Deltat.obj `if test -f 'Deltat.c'; then $(CYGPATH_W) 'Deltat.c'; else $(CYGPATH_W) '$(srcdir)/Deltat.c'; fi`
+
 cdo-Deltime.o: Deltime.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Deltime.o -MD -MP -MF $(DEPDIR)/cdo-Deltime.Tpo -c -o cdo-Deltime.o `test -f 'Deltime.c' || echo '$(srcdir)/'`Deltime.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Deltime.Tpo $(DEPDIR)/cdo-Deltime.Po
@@ -2797,20 +2984,6 @@ cdo-Isosurface.obj: Isosurface.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Isosurface.obj `if test -f 'Isosurface.c'; then $(CYGPATH_W) 'Isosurface.c'; else $(CYGPATH_W) '$(srcdir)/Isosurface.c'; fi`
 
-cdo-Kvl.o: Kvl.c
- at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Kvl.o -MD -MP -MF $(DEPDIR)/cdo-Kvl.Tpo -c -o cdo-Kvl.o `test -f 'Kvl.c' || echo '$(srcdir)/'`Kvl.c
- at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Kvl.Tpo $(DEPDIR)/cdo-Kvl.Po
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Kvl.c' object='cdo-Kvl.o' libtool=no @AMDEPBACKSLASH@
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Kvl.o `test -f 'Kvl.c' || echo '$(srcdir)/'`Kvl.c
-
-cdo-Kvl.obj: Kvl.c
- at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Kvl.obj -MD -MP -MF $(DEPDIR)/cdo-Kvl.Tpo -c -o cdo-Kvl.obj `if test -f 'Kvl.c'; then $(CYGPATH_W) 'Kvl.c'; else $(CYGPATH_W) '$(srcdir)/Kvl.c'; fi`
- at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Kvl.Tpo $(DEPDIR)/cdo-Kvl.Po
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Kvl.c' object='cdo-Kvl.obj' libtool=no @AMDEPBACKSLASH@
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Kvl.obj `if test -f 'Kvl.c'; then $(CYGPATH_W) 'Kvl.c'; else $(CYGPATH_W) '$(srcdir)/Kvl.c'; fi`
-
 cdo-Log.o: Log.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Log.o -MD -MP -MF $(DEPDIR)/cdo-Log.Tpo -c -o cdo-Log.o `test -f 'Log.c' || echo '$(srcdir)/'`Log.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Log.Tpo $(DEPDIR)/cdo-Log.Po
@@ -2993,19 +3166,19 @@ cdo-Ninfo.obj: Ninfo.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Ninfo.obj `if test -f 'Ninfo.c'; then $(CYGPATH_W) 'Ninfo.c'; else $(CYGPATH_W) '$(srcdir)/Ninfo.c'; fi`
 
-cdo-Nmltest.o: Nmltest.c
- at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Nmltest.o -MD -MP -MF $(DEPDIR)/cdo-Nmltest.Tpo -c -o cdo-Nmltest.o `test -f 'Nmltest.c' || echo '$(srcdir)/'`Nmltest.c
- at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Nmltest.Tpo $(DEPDIR)/cdo-Nmltest.Po
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Nmltest.c' object='cdo-Nmltest.o' libtool=no @AMDEPBACKSLASH@
+cdo-Nmldump.o: Nmldump.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Nmldump.o -MD -MP -MF $(DEPDIR)/cdo-Nmldump.Tpo -c -o cdo-Nmldump.o `test -f 'Nmldump.c' || echo '$(srcdir)/'`Nmldump.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Nmldump.Tpo $(DEPDIR)/cdo-Nmldump.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Nmldump.c' object='cdo-Nmldump.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Nmltest.o `test -f 'Nmltest.c' || echo '$(srcdir)/'`Nmltest.c
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Nmldump.o `test -f 'Nmldump.c' || echo '$(srcdir)/'`Nmldump.c
 
-cdo-Nmltest.obj: Nmltest.c
- at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Nmltest.obj -MD -MP -MF $(DEPDIR)/cdo-Nmltest.Tpo -c -o cdo-Nmltest.obj `if test -f 'Nmltest.c'; then $(CYGPATH_W) 'Nmltest.c'; else $(CYGPATH_W) '$(srcdir)/Nmltest.c'; fi`
- at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Nmltest.Tpo $(DEPDIR)/cdo-Nmltest.Po
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Nmltest.c' object='cdo-Nmltest.obj' libtool=no @AMDEPBACKSLASH@
+cdo-Nmldump.obj: Nmldump.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Nmldump.obj -MD -MP -MF $(DEPDIR)/cdo-Nmldump.Tpo -c -o cdo-Nmldump.obj `if test -f 'Nmldump.c'; then $(CYGPATH_W) 'Nmldump.c'; else $(CYGPATH_W) '$(srcdir)/Nmldump.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Nmldump.Tpo $(DEPDIR)/cdo-Nmldump.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Nmldump.c' object='cdo-Nmldump.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Nmltest.obj `if test -f 'Nmltest.c'; then $(CYGPATH_W) 'Nmltest.c'; else $(CYGPATH_W) '$(srcdir)/Nmltest.c'; fi`
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Nmldump.obj `if test -f 'Nmldump.c'; then $(CYGPATH_W) 'Nmldump.c'; else $(CYGPATH_W) '$(srcdir)/Nmldump.c'; fi`
 
 cdo-Output.o: Output.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Output.o -MD -MP -MF $(DEPDIR)/cdo-Output.Tpo -c -o cdo-Output.o `test -f 'Output.c' || echo '$(srcdir)/'`Output.c
@@ -3273,6 +3446,20 @@ cdo-Selbox.obj: Selbox.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Selbox.obj `if test -f 'Selbox.c'; then $(CYGPATH_W) 'Selbox.c'; else $(CYGPATH_W) '$(srcdir)/Selbox.c'; fi`
 
+cdo-Selindex.o: Selindex.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Selindex.o -MD -MP -MF $(DEPDIR)/cdo-Selindex.Tpo -c -o cdo-Selindex.o `test -f 'Selindex.c' || echo '$(srcdir)/'`Selindex.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Selindex.Tpo $(DEPDIR)/cdo-Selindex.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Selindex.c' object='cdo-Selindex.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Selindex.o `test -f 'Selindex.c' || echo '$(srcdir)/'`Selindex.c
+
+cdo-Selindex.obj: Selindex.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Selindex.obj -MD -MP -MF $(DEPDIR)/cdo-Selindex.Tpo -c -o cdo-Selindex.obj `if test -f 'Selindex.c'; then $(CYGPATH_W) 'Selindex.c'; else $(CYGPATH_W) '$(srcdir)/Selindex.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Selindex.Tpo $(DEPDIR)/cdo-Selindex.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Selindex.c' object='cdo-Selindex.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Selindex.obj `if test -f 'Selindex.c'; then $(CYGPATH_W) 'Selindex.c'; else $(CYGPATH_W) '$(srcdir)/Selindex.c'; fi`
+
 cdo-Select.o: Select.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Select.o -MD -MP -MF $(DEPDIR)/cdo-Select.Tpo -c -o cdo-Select.o `test -f 'Select.c' || echo '$(srcdir)/'`Select.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Select.Tpo $(DEPDIR)/cdo-Select.Po
@@ -3357,6 +3544,20 @@ cdo-Set.obj: Set.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Set.obj `if test -f 'Set.c'; then $(CYGPATH_W) 'Set.c'; else $(CYGPATH_W) '$(srcdir)/Set.c'; fi`
 
+cdo-Setattribute.o: Setattribute.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Setattribute.o -MD -MP -MF $(DEPDIR)/cdo-Setattribute.Tpo -c -o cdo-Setattribute.o `test -f 'Setattribute.c' || echo '$(srcdir)/'`Setattribute.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Setattribute.Tpo $(DEPDIR)/cdo-Setattribute.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Setattribute.c' object='cdo-Setattribute.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Setattribute.o `test -f 'Setattribute.c' || echo '$(srcdir)/'`Setattribute.c
+
+cdo-Setattribute.obj: Setattribute.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Setattribute.obj -MD -MP -MF $(DEPDIR)/cdo-Setattribute.Tpo -c -o cdo-Setattribute.obj `if test -f 'Setattribute.c'; then $(CYGPATH_W) 'Setattribute.c'; else $(CYGPATH_W) '$(srcdir)/Setattribute.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Setattribute.Tpo $(DEPDIR)/cdo-Setattribute.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Setattribute.c' object='cdo-Setattribute.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Setattribute.obj `if test -f 'Setattribute.c'; then $(CYGPATH_W) 'Setattribute.c'; else $(CYGPATH_W) '$(srcdir)/Setattribute.c'; fi`
+
 cdo-Setbox.o: Setbox.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Setbox.o -MD -MP -MF $(DEPDIR)/cdo-Setbox.Tpo -c -o cdo-Setbox.o `test -f 'Setbox.c' || echo '$(srcdir)/'`Setbox.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Setbox.Tpo $(DEPDIR)/cdo-Setbox.Po
@@ -3483,6 +3684,20 @@ cdo-Setzaxis.obj: Setzaxis.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Setzaxis.obj `if test -f 'Setzaxis.c'; then $(CYGPATH_W) 'Setzaxis.c'; else $(CYGPATH_W) '$(srcdir)/Setzaxis.c'; fi`
 
+cdo-Shiftxy.o: Shiftxy.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Shiftxy.o -MD -MP -MF $(DEPDIR)/cdo-Shiftxy.Tpo -c -o cdo-Shiftxy.o `test -f 'Shiftxy.c' || echo '$(srcdir)/'`Shiftxy.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Shiftxy.Tpo $(DEPDIR)/cdo-Shiftxy.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Shiftxy.c' object='cdo-Shiftxy.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Shiftxy.o `test -f 'Shiftxy.c' || echo '$(srcdir)/'`Shiftxy.c
+
+cdo-Shiftxy.obj: Shiftxy.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Shiftxy.obj -MD -MP -MF $(DEPDIR)/cdo-Shiftxy.Tpo -c -o cdo-Shiftxy.obj `if test -f 'Shiftxy.c'; then $(CYGPATH_W) 'Shiftxy.c'; else $(CYGPATH_W) '$(srcdir)/Shiftxy.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Shiftxy.Tpo $(DEPDIR)/cdo-Shiftxy.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Shiftxy.c' object='cdo-Shiftxy.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Shiftxy.obj `if test -f 'Shiftxy.c'; then $(CYGPATH_W) 'Shiftxy.c'; else $(CYGPATH_W) '$(srcdir)/Shiftxy.c'; fi`
+
 cdo-Showinfo.o: Showinfo.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Showinfo.o -MD -MP -MF $(DEPDIR)/cdo-Showinfo.Tpo -c -o cdo-Showinfo.o `test -f 'Showinfo.c' || echo '$(srcdir)/'`Showinfo.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Showinfo.Tpo $(DEPDIR)/cdo-Showinfo.Po
@@ -3735,20 +3950,6 @@ cdo-Tests.obj: Tests.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Tests.obj `if test -f 'Tests.c'; then $(CYGPATH_W) 'Tests.c'; else $(CYGPATH_W) '$(srcdir)/Tests.c'; fi`
 
-cdo-Timedt.o: Timedt.c
- at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Timedt.o -MD -MP -MF $(DEPDIR)/cdo-Timedt.Tpo -c -o cdo-Timedt.o `test -f 'Timedt.c' || echo '$(srcdir)/'`Timedt.c
- at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Timedt.Tpo $(DEPDIR)/cdo-Timedt.Po
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Timedt.c' object='cdo-Timedt.o' libtool=no @AMDEPBACKSLASH@
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Timedt.o `test -f 'Timedt.c' || echo '$(srcdir)/'`Timedt.c
-
-cdo-Timedt.obj: Timedt.c
- at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Timedt.obj -MD -MP -MF $(DEPDIR)/cdo-Timedt.Tpo -c -o cdo-Timedt.obj `if test -f 'Timedt.c'; then $(CYGPATH_W) 'Timedt.c'; else $(CYGPATH_W) '$(srcdir)/Timedt.c'; fi`
- at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Timedt.Tpo $(DEPDIR)/cdo-Timedt.Po
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Timedt.c' object='cdo-Timedt.obj' libtool=no @AMDEPBACKSLASH@
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Timedt.obj `if test -f 'Timedt.c'; then $(CYGPATH_W) 'Timedt.c'; else $(CYGPATH_W) '$(srcdir)/Timedt.c'; fi`
-
 cdo-Timcount.o: Timcount.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Timcount.o -MD -MP -MF $(DEPDIR)/cdo-Timcount.Tpo -c -o cdo-Timcount.o `test -f 'Timcount.c' || echo '$(srcdir)/'`Timcount.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Timcount.Tpo $(DEPDIR)/cdo-Timcount.Po
@@ -3763,6 +3964,20 @@ cdo-Timcount.obj: Timcount.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Timcount.obj `if test -f 'Timcount.c'; then $(CYGPATH_W) 'Timcount.c'; else $(CYGPATH_W) '$(srcdir)/Timcount.c'; fi`
 
+cdo-Timcumsum.o: Timcumsum.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Timcumsum.o -MD -MP -MF $(DEPDIR)/cdo-Timcumsum.Tpo -c -o cdo-Timcumsum.o `test -f 'Timcumsum.c' || echo '$(srcdir)/'`Timcumsum.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Timcumsum.Tpo $(DEPDIR)/cdo-Timcumsum.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Timcumsum.c' object='cdo-Timcumsum.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Timcumsum.o `test -f 'Timcumsum.c' || echo '$(srcdir)/'`Timcumsum.c
+
+cdo-Timcumsum.obj: Timcumsum.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Timcumsum.obj -MD -MP -MF $(DEPDIR)/cdo-Timcumsum.Tpo -c -o cdo-Timcumsum.obj `if test -f 'Timcumsum.c'; then $(CYGPATH_W) 'Timcumsum.c'; else $(CYGPATH_W) '$(srcdir)/Timcumsum.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Timcumsum.Tpo $(DEPDIR)/cdo-Timcumsum.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='Timcumsum.c' object='cdo-Timcumsum.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o cdo-Timcumsum.obj `if test -f 'Timcumsum.c'; then $(CYGPATH_W) 'Timcumsum.c'; else $(CYGPATH_W) '$(srcdir)/Timcumsum.c'; fi`
+
 cdo-Timpctl.o: Timpctl.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(cdo_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT cdo-Timpctl.o -MD -MP -MF $(DEPDIR)/cdo-Timpctl.Tpo -c -o cdo-Timpctl.o `test -f 'Timpctl.c' || echo '$(srcdir)/'`Timpctl.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/cdo-Timpctl.Tpo $(DEPDIR)/cdo-Timpctl.Po
@@ -4469,6 +4684,7 @@ mostlyclean-libtool:
 clean-libtool:
 	-rm -rf .libs _libs
 	-rm -rf clipping/.libs clipping/_libs
+	-rm -rf json/.libs json/_libs
 	-rm -rf kdtreelib/.libs kdtreelib/_libs
 
 ID: $(am__tagged_files)
@@ -4589,6 +4805,8 @@ distclean-generic:
 	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
 	-rm -f clipping/$(DEPDIR)/$(am__dirstamp)
 	-rm -f clipping/$(am__dirstamp)
+	-rm -f json/$(DEPDIR)/$(am__dirstamp)
+	-rm -f json/$(am__dirstamp)
 	-rm -f kdtreelib/$(DEPDIR)/$(am__dirstamp)
 	-rm -f kdtreelib/$(am__dirstamp)
 
@@ -4601,7 +4819,7 @@ clean-am: clean-binPROGRAMS clean-generic clean-libtool clean-local \
 	clean-noinstLTLIBRARIES clean-noinstPROGRAMS mostlyclean-am
 
 distclean: distclean-am
-	-rm -rf ./$(DEPDIR) clipping/$(DEPDIR) kdtreelib/$(DEPDIR)
+	-rm -rf ./$(DEPDIR) clipping/$(DEPDIR) json/$(DEPDIR) kdtreelib/$(DEPDIR)
 	-rm -f Makefile
 distclean-am: clean-am distclean-compile distclean-generic \
 	distclean-hdr distclean-tags
@@ -4647,7 +4865,7 @@ install-ps-am:
 installcheck-am:
 
 maintainer-clean: maintainer-clean-am
-	-rm -rf ./$(DEPDIR) clipping/$(DEPDIR) kdtreelib/$(DEPDIR)
+	-rm -rf ./$(DEPDIR) clipping/$(DEPDIR) json/$(DEPDIR) kdtreelib/$(DEPDIR)
 	-rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
 
diff --git a/src/MapReduce.c b/src/MapReduce.c
index 1f6de22..3cf8bed 100644
--- a/src/MapReduce.c
+++ b/src/MapReduce.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -36,7 +36,7 @@
  * pointer */
 /* DON'T MOVE IT! is necessary to have the pstream.h file included AFTER this
  * function definition */
-void read_first_record(char *filename, int gridSize, double *field)
+void read_first_record(char *filename, double *field)
 {
   int nmiss,varID,levelID;
   int streamID = streamOpenRead(filename);
@@ -71,8 +71,7 @@ int countMask(double *maskField, int gridSize, double falseVal)
 void *MapReduce(void *argument)
 {
   int nrecs;
-  int tsID;
-  int varID, levelID, recID;
+  int varID, levelID;
   int nmiss;
   int nobounds = FALSE;
   int nocoords = FALSE;
@@ -90,9 +89,8 @@ void *MapReduce(void *argument)
   if ( cdoDebug ) cdoPrint("MapReduce: input gridSize:%d", inputGridSize);
 
   /* creata an index list of the relevant locations  {{{ */
-  tsID = 0;
   double *inputMaskField = (double*) Malloc(inputGridSize*sizeof(double));
-  read_first_record(operatorArgv()[0],inputGridSize, inputMaskField);
+  read_first_record(operatorArgv()[0], inputMaskField);
 
   /* non-zero values mark the relevant points */
   int maskSize = countMask(inputMaskField, inputGridSize, 0.0);
@@ -166,13 +164,13 @@ void *MapReduce(void *argument)
   double *arrayIn  = (double *)Malloc(inputGridSize*sizeof(double));
   double *arrayOut = (double *)Malloc(maskSize*sizeof(double));
 
-  tsID = 0; 
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
       streamDefTimestep(streamID2, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
         {
           streamInqRecord(streamID1, &varID, &levelID);
           if (TRUE == vars[varID])
diff --git a/src/Maskbox.c b/src/Maskbox.c
index 781c2ef..99242af 100644
--- a/src/Maskbox.c
+++ b/src/Maskbox.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -23,7 +23,6 @@
       Maskbox    maskregion      Mask regions
 */
 
-#include <ctype.h>
 
 #include <cdi.h>
 #include "cdo.h"
@@ -37,15 +36,12 @@
 static
 int ReadCoords(double *xvals, double *yvals, const char *polyfile, FILE *fp)
 {
-  double xcoord, ycoord;
   int z = 0, number = 0, jumpedlines = 0;
-  int i = 0;
   char line[MAX_LINE];
-  char *linep;
 
   while ( readline(fp, line, MAX_LINE) )
     {
-      i = 0;
+      int i = 0;
       if ( line[0] == '#' ) 
          { 
            jumpedlines++;
@@ -58,14 +54,11 @@ int ReadCoords(double *xvals, double *yvals, const char *polyfile, FILE *fp)
          }  
       if ( line[0] == '&' ) break;
 	 
-      linep = &line[0];
+      char *linep = &line[0];
      
-      xcoord = strtod(linep, &linep);
+      double xcoord = strtod(linep, &linep);
       
-      if ( ! (fabs(xcoord) > 0) ) 
-	{
-	  jumpedlines++;
-	}
+      if ( ! (fabs(xcoord) > 0) ) jumpedlines++;
       
       while( ( ( isdigit( (int) *linep ) == FALSE ) && ( *linep!='-' )) && ( i < 64) )
 	{	  
@@ -82,7 +75,7 @@ int ReadCoords(double *xvals, double *yvals, const char *polyfile, FILE *fp)
 	}    
       if ( ( i >= 63 ) && ( number != 0 ) ) cdoAbort( "Wrong value format in file %s at line %d", polyfile, (number+jumpedlines+1) );
     
-      ycoord = strtod(linep, NULL);
+      double ycoord = strtod(linep, NULL);
      
       xvals[number] = xcoord;
       yvals[number] = ycoord;
@@ -114,8 +107,7 @@ void genindexbox(int argc_offset, int gridID1, int *lat1, int *lat2, int *lon11,
 
 
 static
-void maskbox(int *mask, int gridID,
-	     int lat1, int lat2, int lon11, int lon12, int lon21, int lon22)
+void maskbox(bool *mask, int gridID, int lat1, int lat2, int lon11, int lon12, int lon21, int lon22)
 {
   int nlon = gridInqXsize(gridID);
   int nlat = gridInqYsize(gridID);
@@ -124,25 +116,18 @@ void maskbox(int *mask, int gridID,
     for ( int ilon = 0; ilon < nlon; ilon++ )
       if (  (lat1 <= ilat && ilat <= lat2 && 
 	      ((lon11 <= ilon && ilon <= lon12) || (lon21 <= ilon && ilon <= lon22))) )
-	mask[nlon*ilat + ilon] = 0;
+	mask[nlon*ilat + ilon] = false;
 }
 
 void getlonlatparams(int argc_offset, double *xlon1, double *xlon2, double *xlat1, double *xlat2);
-void genlonlatbox_curv(int gridID, double xlon1, double xlon2, double xlat1, double xlat2,
-                       int *lat1, int *lat2, int *lon11, int *lon12, int *lon21, int *lon22);
 
 static
-void maskbox_curv(int *mask, int gridID)
+void maskbox_cell(bool *mask, int gridID)
 {
   double xlon1 = 0, xlon2 = 0, xlat1 = 0, xlat2 = 0;
   getlonlatparams(0, &xlon1, &xlon2, &xlat1, &xlat2);
 
-  int nlon = gridInqXsize(gridID);
-  int nlat = gridInqYsize(gridID);
-
-  int gridsize = nlon*nlat;
-
-  int grid_is_circular = gridIsCircular(gridID);
+  int gridsize = gridInqSize(gridID);
 
   double *xvals = (double *) Malloc(gridsize*sizeof(double));
   double *yvals = (double *) Malloc(gridsize*sizeof(double));
@@ -159,9 +144,6 @@ void maskbox_curv(int *mask, int gridID)
   if ( strncmp(xunits, "radian", 6) == 0 ) xfact = RAD2DEG;
   if ( strncmp(yunits, "radian", 6) == 0 ) yfact = RAD2DEG;
 
-  double xval, yval, xfirst, xlast, ylast;
-  int lp2 = FALSE;
-
   if ( xlon1 > xlon2 ) 
     cdoAbort("The second longitude have to be greater than the first one!");
 
@@ -171,60 +153,20 @@ void maskbox_curv(int *mask, int gridID)
       xlat1 = xlat2;
       xlat2 = xtemp;
     }
-
-  int ilat, ilon;
   
-  for ( ilat = 0; ilat < nlat; ilat++ )
+  for ( int i = 0; i < gridsize; ++i )
     {
-      xlast = xfact * xvals[ilat*nlon + nlon-1];
-      ylast = yfact * yvals[ilat*nlon + nlon-1];
-      if ( ylast >= xlat1 && ylast <= xlat2 )
-        if ( grid_is_circular && xlon1 <= xlast && xlon2 > xlast && (xlon2-xlon1) < 360 )
-          {
-            lp2 = TRUE;
-          }
-    }
+      mask[i] = true;
 
-  for ( ilat = 0; ilat < nlat; ilat++ )
-    {
-      for ( ilon = 0; ilon < nlon; ilon++ )
+      double xval = xfact*xvals[i];
+      double yval = yfact*yvals[i];
+      if ( yval >= xlat1 && yval <= xlat2 )
         {
-          mask[nlon*ilat + ilon] = 1;
-
-          xval = xvals[ilat*nlon + ilon];
-          yval = yvals[ilat*nlon + ilon];
-
-          xval *= xfact;
-          yval *= yfact;
-
-          if ( yval >= xlat1 && yval <= xlat2 )
+          if ( ((xval     >= xlon1 && xval     <= xlon2) ||
+                (xval-360 >= xlon1 && xval-360 <= xlon2) ||
+                (xval+360 >= xlon1 && xval+360 <= xlon2)) )
             {
-              if ( lp2 )
-                {
-                  xfirst = xfact * xvals[ilat*nlon];
-                  if ( xfirst < xlon1 ) xfirst = xlon1;
-                  
-                  xlast = xfact * xvals[ilat*nlon + nlon-1];
-                  if ( xlast > xlon2 ) xlast = xlon2;
-
-                  if ( xval >= xlon1 && xval <= xlast )
-                    {
-                      mask[nlon*ilat + ilon] = 0;
-                    }
-                  else if ( xval >= xfirst && xval <= xlon2 )
-                    {
-                      mask[nlon*ilat + ilon] = 0;
-                    }
-                }
-              else
-                {
-                  if ( ((xval     >= xlon1 && xval     <= xlon2) ||
-                        (xval-360 >= xlon1 && xval-360 <= xlon2) ||
-                        (xval+360 >= xlon1 && xval+360 <= xlon2)) )
-                    {
-                      mask[nlon*ilat + ilon] = 0;
-                    }
-                }
+              mask[i] = false;
             }
         }
     }
@@ -234,21 +176,13 @@ void maskbox_curv(int *mask, int gridID)
 }
 
 static
-void maskregion(int *mask, int gridID, double *xcoords, double *ycoords, int nofcoords)
+void maskregion(bool *mask, int gridID, double *xcoords, double *ycoords, int nofcoords)
 {
-  int i, j;
-  int nlon, nlat;
-  int ilat, ilon;
-  int c;
-  double *xvals, *yvals;
-  double xval, yval;
-  double xmin, xmax, ymin, ymax;
-
-  nlon = gridInqXsize(gridID);
-  nlat = gridInqYsize(gridID);
+  int nlon = gridInqXsize(gridID);
+  int nlat = gridInqYsize(gridID);
 
-  xvals = (double*) Malloc(nlon*sizeof(double));
-  yvals = (double*) Malloc(nlat*sizeof(double));
+  double *xvals = (double*) Malloc(nlon*sizeof(double));
+  double *yvals = (double*) Malloc(nlat*sizeof(double));
 
   gridInqXvals(gridID, xvals);
   gridInqYvals(gridID, yvals);  
@@ -262,35 +196,36 @@ void maskregion(int *mask, int gridID, double *xcoords, double *ycoords, int nof
     grid_to_degree(units, nlat, yvals, "grid center lat");
   }
 
-  xmin = xvals[0];
-  xmax = xvals[0];
-  ymin = yvals[0];
-  ymax = yvals[0];
+  double xmin = xvals[0];
+  double xmax = xvals[0];
+  double ymin = yvals[0];
+  double ymax = yvals[0];
 
-  for ( i = 1; i < nlon; i++ )
+  for ( int i = 1; i < nlon; i++ )
     {
       if ( xvals[i] < xmin ) xmin = xvals[i];
       if ( xvals[i] > xmax ) xmax = xvals[i];
     }
 
-  for ( i = 1; i < nlat; i++ )
+  for ( int i = 1; i < nlat; i++ )
     {
       if ( yvals[i] < ymin ) ymin = yvals[i];
       if ( yvals[i] > ymax ) ymax = yvals[i];
     }
 
-  for ( ilat = 0; ilat < nlat; ilat++ )
+  for ( int ilat = 0; ilat < nlat; ilat++ )
     {
-      yval = yvals[ilat];
-      for ( ilon = 0; ilon < nlon; ilon++ )
+      double yval = yvals[ilat];
+      for ( int ilon = 0; ilon < nlon; ilon++ )
 	{
-          c = 0;
-	  xval = xvals[ilon];
+          int i, j;
+          int c = 0;
+	  double xval = xvals[ilon];
 	  if (!( ( ( xval > xmin ) || ( xval < xmax ) ) || ( (yval > ymin) || (yval < ymax) ) ) ) c = !c;
 	  	  
           if ( c == 0 )
 	    {
-	      for (i = 0, j = nofcoords-1; i < nofcoords; j = i++)
+	      for ( i = 0, j = nofcoords-1; i < nofcoords; j = i++ )
 	    
 	      if ((((ycoords[i]<=yval) && (yval<ycoords[j])) ||
 		   ((ycoords[j]<=yval) && (yval<ycoords[i]))) &&
@@ -300,7 +235,7 @@ void maskregion(int *mask, int gridID, double *xcoords, double *ycoords, int nof
 
 	  if ( c == 0 )
 	    {
-	      for (i = 0, j = nofcoords-1; i < nofcoords; j = i++)
+	      for ( i = 0, j = nofcoords-1; i < nofcoords; j = i++ )
 		{
 		  if ( xvals[ilon] > 180 )
 		    {
@@ -314,9 +249,9 @@ void maskregion(int *mask, int gridID, double *xcoords, double *ycoords, int nof
  
 	  if ( c == 0 )
 	    {
-	      for ( i = 0, j = nofcoords-1; i< nofcoords; j = i++)
+	      for ( i = 0, j = nofcoords-1; i< nofcoords; j = i++ )
 		{		
-		  if ( xval<0 )
+		  if ( xval < 0 )
 		    {
 		      if ((((ycoords[i]<=yval) && (yval<ycoords[j])) ||
 			   ((ycoords[j]<=yval) && (yval<ycoords[i]))) &&
@@ -326,7 +261,7 @@ void maskregion(int *mask, int gridID, double *xcoords, double *ycoords, int nof
 		}
 	    }
 	     
-	  if( c != 0 ) mask[nlon*ilat+ilon] =  0;
+	  if ( c != 0 ) mask[nlon*ilat+ilon] =  false;
 	}
     }
       
@@ -338,17 +273,10 @@ void maskregion(int *mask, int gridID, double *xcoords, double *ycoords, int nof
 void *Maskbox(void *argument)
 {
   int nrecs;
-  int recID, varID, levelID;
+  int varID, levelID;
   int gridID = -1;
   int index, gridtype = -1;
-  int nmiss;
-  int i, i2;
   int lat1, lat2, lon11, lon12, lon21, lon22;
-  int number = 0, nfiles;
-  double missval;
-  double *xcoords, *ycoords;
-  FILE *fp;
-  const char *polyfile;
 
   cdoInitialize(argument);
 
@@ -376,15 +304,16 @@ void *Maskbox(void *argument)
       gridtype = gridInqType(gridID);
 
       if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN ) break;
-      if ( gridtype == GRID_CURVILINEAR ) break;
+      if ( operatorID != MASKREGION && gridtype == GRID_CURVILINEAR ) break;
+      if ( operatorID != MASKREGION && gridtype == GRID_UNSTRUCTURED ) break;
       if ( operatorID == MASKINDEXBOX && gridtype == GRID_GENERIC &&
 	  gridInqXsize(gridID) > 0 && gridInqYsize(gridID) > 0 ) break;
     }
 
-  if ( gridInqType(gridID) == GRID_GAUSSIAN_REDUCED )
+  if ( gridtype == GRID_GAUSSIAN_REDUCED )
     cdoAbort("Gaussian reduced grid found. Use option -R to convert it to a regular grid!");
 
-  if ( index == ngrids ) cdoAbort("No regular grid found!");
+  if ( index == ngrids ) cdoAbort("No regular lon/lat grid found!");
   if ( ndiffgrids > 0 )  cdoAbort("Too many different grids!");
 
   operatorInputArg(cdoOperatorEnter(operatorID));
@@ -396,13 +325,13 @@ void *Maskbox(void *argument)
   vlistDefTaxis(vlistID2, taxisID2);
 
   int nvars = vlistNvars(vlistID1);
-  int *vars = (int *) Malloc(nvars*sizeof(int));
+  bool *vars = (bool*) Malloc(nvars*sizeof(bool));
   for ( varID = 0; varID < nvars; varID++ )
     {
       if ( gridID == vlistInqVarGrid(vlistID1, varID) )
-	vars[varID] = TRUE;
+	vars[varID] = true;
       else
-	vars[varID] = FALSE;
+	vars[varID] = false;
     }
 
   int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
@@ -411,14 +340,15 @@ void *Maskbox(void *argument)
 
   int gridsize = gridInqSize(gridID);
   double *array = (double *) Malloc(gridsize*sizeof(double));
-  int *mask  = (int *) Malloc(gridsize*sizeof(int));
-  for ( i = 0;  i < gridsize; ++i ) mask[i] = 1;
+  bool *mask = (bool*) Malloc(gridsize*sizeof(bool));
+  for ( int i = 0;  i < gridsize; ++i ) mask[i] = true;
  
   if ( operatorID == MASKLONLATBOX )
     {
-      if ( gridtype == GRID_CURVILINEAR )
+      if ( gridtype == GRID_CURVILINEAR ||
+           gridtype == GRID_UNSTRUCTURED )
         {
-          maskbox_curv(mask, gridID);
+          maskbox_cell(mask, gridID);
         }
       else
         {
@@ -426,26 +356,26 @@ void *Maskbox(void *argument)
           maskbox(mask, gridID, lat1, lat2, lon11, lon12, lon21, lon22);
         }
     }
-  if ( operatorID == MASKINDEXBOX )
+  else if ( operatorID == MASKINDEXBOX )
     {
       genindexbox(0, gridID, &lat1, &lat2, &lon11, &lon12, &lon21, &lon22);
       maskbox(mask, gridID, lat1, lat2, lon11, lon12, lon21, lon22);
     }
-  if ( operatorID == MASKREGION )
+  else if ( operatorID == MASKREGION )
     {
-      xcoords = (double*) Malloc( MAX_VALS*sizeof(double));
-      ycoords = (double*) Malloc( MAX_VALS*sizeof(double));
-      nfiles = operatorArgc();
+      double *xcoords = (double*) Malloc(MAX_VALS*sizeof(double));
+      double *ycoords = (double*) Malloc(MAX_VALS*sizeof(double));
+      int nfiles = operatorArgc();
      
-      for ( i2 = 0; i2 < nfiles; i2++ )
+      for ( int i = 0; i < nfiles; i++ )
 	{
-	  polyfile = operatorArgv()[i2];
-	  fp = fopen(polyfile, "r");
+	  const char *polyfile = operatorArgv()[i];
+	  FILE *fp = fopen(polyfile, "r");
 	 
 	  if ( fp == 0 ) cdoAbort("Open failed on %s", polyfile);   
 	  while ( TRUE )
 	    {
-	      number = ReadCoords (xcoords, ycoords, polyfile, fp );
+	      int number = ReadCoords(xcoords, ycoords, polyfile, fp );
 	      if ( number == 0 ) break;
 	      if ( number < 3 ) cdoAbort( "Too less values in file %s", polyfile );
 	      maskregion(mask, gridID, xcoords, ycoords, number);
@@ -460,26 +390,23 @@ void *Maskbox(void *argument)
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
-
       streamDefTimestep(streamID2, tsID);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
 	  if ( vars[varID] )
 	    {
+              int nmiss;
 	      streamReadRecord(streamID1, array, &nmiss);
-              missval = vlistInqVarMissval(vlistID1, varID);
-             
-	      for ( i = 0; i < gridsize; i++ )
-		{
-		  if ( mask[i] ) array[i] = missval;
-		}
+
+              double missval = vlistInqVarMissval(vlistID1, varID);             
+	      for ( int i = 0; i < gridsize; i++ )
+                if ( mask[i] ) array[i] = missval;
 		
 	      nmiss = 0;
-
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( int i = 0; i < gridsize; i++ )
 		if ( DBL_IS_EQUAL(array[i], missval) ) nmiss++;
 
 	      streamDefRecord(streamID2, varID, levelID);
diff --git a/src/Mastrfu.c b/src/Mastrfu.c
index 6ab75b8..03607e6 100644
--- a/src/Mastrfu.c
+++ b/src/Mastrfu.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -45,7 +45,7 @@ void mastrfu(int gridID, int zaxisID, double *array1, double *array2, int nmiss,
   double **field1 = (double**) Malloc(nlev*sizeof(double*));
   double **field2 = (double**) Malloc(nlev*sizeof(double*));
 
-  zaxisInqLevels(zaxisID, plevel);
+  cdoZaxisInqLevels(zaxisID, plevel);
 
   // gaussaw(phi, dummy, nlat);
   
@@ -107,7 +107,7 @@ void mastrfu(int gridID, int zaxisID, double *array1, double *array2, int nmiss,
 void *Mastrfu(void *argument)
 {
   int nrecs;
-  int recID, varID, levelID;
+  int varID, levelID;
   int offset;
   int nmiss, nmiss1;
 
@@ -150,7 +150,7 @@ void *Mastrfu(void *argument)
   vlistDefVarName(vlistID2, 0, "mastrfu");
   vlistDefVarLongname(vlistID2, 0, "mass stream function");
   vlistDefVarUnits(vlistID2, 0, "kg/s");
-  vlistDefVarDatatype(vlistID2, 0, DATATYPE_FLT32);
+  vlistDefVarDatatype(vlistID2, 0, CDI_DATATYPE_FLT32);
 
   int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
@@ -167,7 +167,7 @@ void *Mastrfu(void *argument)
       streamDefTimestep(streamID2, tsID);
 
       nmiss = 0;
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  offset  = gridsize*levelID;
@@ -177,7 +177,7 @@ void *Mastrfu(void *argument)
 
       mastrfu(gridID, zaxisID, array1, array2, nmiss, missval);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  varID = 0;
 	  levelID = recID;
diff --git a/src/Math.c b/src/Math.c
index 7412d42..a6db764 100644
--- a/src/Math.c
+++ b/src/Math.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
diff --git a/src/Merge.c b/src/Merge.c
index efa638f..4e099c4 100644
--- a/src/Merge.c
+++ b/src/Merge.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -34,47 +34,39 @@ void checkDupEntry(int vlistID1, int vlistID2, const char *filename)
 {
   char vname1[CDI_MAX_NAME], vname2[CDI_MAX_NAME];
   int k;
-  int gridID1, gridID2;
-  int zaxisID1, zaxisID2;
-  int varID1, varID2;
-  int param1, param2;
-  int ztype1, ztype2;
-  int gtype1, gtype2;
-  int nlev1,  nlev2;
-  int gsize1, gsize2;
   int mlev1 = 0, mlev2 = 0;
   double *lev1 = NULL, *lev2 = NULL;
 
   int nvars1 = vlistNvars(vlistID1);
   int nvars2 = vlistNvars(vlistID2);
 
-  for ( varID1 = 0; varID1 < nvars1; ++varID1 )
+  for ( int varID1 = 0; varID1 < nvars1; ++varID1 )
     {
       vlistInqVarName(vlistID1, varID1, vname1);
-      param1   = vlistInqVarParam(vlistID1, varID1);
-      gridID1  = vlistInqVarGrid(vlistID1, varID1);
-      zaxisID1 = vlistInqVarZaxis(vlistID1, varID1);
-      gtype1   = gridInqType(gridID1);
-      gsize1   = gridInqSize(gridID1);
-      ztype1   = zaxisInqType(zaxisID1);
-      nlev1    = zaxisInqSize(zaxisID1);
+      int param1   = vlistInqVarParam(vlistID1, varID1);
+      int gridID1  = vlistInqVarGrid(vlistID1, varID1);
+      int zaxisID1 = vlistInqVarZaxis(vlistID1, varID1);
+      int gtype1   = gridInqType(gridID1);
+      int gsize1   = gridInqSize(gridID1);
+      int ztype1   = zaxisInqType(zaxisID1);
+      int nlev1    = zaxisInqSize(zaxisID1);
       if ( nlev1 > mlev1 )
 	{
 	  mlev1 = nlev1;
 	  lev1 = (double*) Realloc(lev1, mlev1*sizeof(double));
 	}
-      zaxisInqLevels(zaxisID1, lev1);
+      cdoZaxisInqLevels(zaxisID1, lev1);
 
-      for ( varID2 = 0; varID2 < nvars2; ++varID2 )
+      for ( int varID2 = 0; varID2 < nvars2; ++varID2 )
 	{
 	  vlistInqVarName(vlistID2, varID2, vname2);
-	  param2   = vlistInqVarParam(vlistID2, varID2);
-	  gridID2  = vlistInqVarGrid(vlistID2, varID2);
-	  zaxisID2 = vlistInqVarZaxis(vlistID2, varID2);
-	  gtype2   = gridInqType(gridID2);
-	  gsize2   = gridInqSize(gridID2);
-	  ztype2   = zaxisInqType(zaxisID2);
-	  nlev2    = zaxisInqSize(zaxisID2);
+	  int param2   = vlistInqVarParam(vlistID2, varID2);
+	  int gridID2  = vlistInqVarGrid(vlistID2, varID2);
+	  int zaxisID2 = vlistInqVarZaxis(vlistID2, varID2);
+	  int gtype2   = gridInqType(gridID2);
+	  int gsize2   = gridInqSize(gridID2);
+	  int ztype2   = zaxisInqType(zaxisID2);
+	  int nlev2    = zaxisInqSize(zaxisID2);
 	  if ( gtype1 == gtype2 && gsize1 == gsize2 && ztype1 == ztype2 && nlev1 == nlev2 )
 	    {
 	      if ( nlev2 > mlev2 )
@@ -82,29 +74,30 @@ void checkDupEntry(int vlistID1, int vlistID2, const char *filename)
 		  mlev2 = nlev2;
 		  lev2 = (double*) Realloc(lev2, mlev2*sizeof(double));
 		}
-	      zaxisInqLevels(zaxisID2, lev2);
-
-	      for ( k = 0; k < nlev2; ++k )
-		if ( !IS_EQUAL(lev1[k], lev2[k]) ) break;
-
-	      if ( k == nlev2 )
-		{
-		  if ( param1 < 0 || param2 < 0 )
-		    {
-		      if ( strcmp(vname1, vname2) == 0 )
-			{
-			  cdoWarning("Duplicate entry of parameter %s in %s!", vname2, filename);
-			}
-		    }
-		  else
-		    {
-		      if ( param1 == param2 )
-			{
-			  char paramstr[32];
-			  cdiParamToString(param2, paramstr, sizeof(paramstr));
-			  cdoWarning("Duplicate entry of parameter %s in %s!", paramstr, filename);
-			}
-		    }
+	      cdoZaxisInqLevels(zaxisID2, lev2);
+
+              if ( zaxisInqLevels(zaxisID1, NULL) && zaxisInqLevels(zaxisID2, NULL) )
+                {
+                  for ( k = 0; k < nlev2; ++k )
+                    if ( !IS_EQUAL(lev1[k], lev2[k]) ) break;
+
+                  if ( k == nlev2 )
+                    {
+                      if ( param1 < 0 || param2 < 0 )
+                        {
+                          if ( strcmp(vname1, vname2) == 0 )
+                            cdoWarning("Duplicate entry of parameter %s in %s!", vname2, filename);
+                        }
+                      else
+                        {
+                          if ( param1 == param2 )
+                            {
+                              char paramstr[32];
+                              cdiParamToString(param2, paramstr, sizeof(paramstr));
+                              cdoWarning("Duplicate entry of parameter %s in %s!", paramstr, filename);
+                            }
+                        }
+                    }
 		}
 	    }
 	}
@@ -122,7 +115,7 @@ int vlistConstVars(int vlistID)
   for ( int varID = 0; varID < nvars; ++varID )
     if ( vlistInqVarTsteptype(vlistID, varID) != TSTEP_CONSTANT ) return 0;
 
-  return (1);
+  return 1;
 }
 */
 
@@ -131,34 +124,15 @@ void *Merge(void *argument)
   int streamID1 = -1;
   int varID, varID2;
   int nrecs = 0;
-  int recID, levelID, levelID2;
+  int levelID, levelID2;
   int index;
   int gridsize;
   int nmiss;
-  //int skip_same_var = FALSE;
 
   cdoInitialize(argument);
 
   bool lcopy = UNCHANGED_RECORD;
 
-  /*
-  {
-    char *envstr;
-    envstr = getenv("SKIP_SAME_VAR");
-    if ( envstr )
-      {
-	int ival;
-	ival = atoi(envstr);
-	if ( ival == 1 )
-	  {
-	    skip_same_var = TRUE;
-	    if ( cdoVerbose )
-	      cdoPrint("Set SKIP_SAME_VAR to %d", ival);
-	  }
-      }
-  }
-  */
-
   int streamCnt = cdoStreamCnt();
   int nmerge    = streamCnt - 1;
 
@@ -310,7 +284,7 @@ void *Merge(void *argument)
 
 	  if ( vlistID1 == -1 ) continue;
 
-	  for ( recID = 0; recID < nrecs; recID++ )
+	  for ( int recID = 0; recID < nrecs; recID++ )
 	    {
 	      streamInqRecord(streamID1, &varID, &levelID);
 
diff --git a/src/Mergegrid.c b/src/Mergegrid.c
index 0b5963b..282d02f 100644
--- a/src/Mergegrid.c
+++ b/src/Mergegrid.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -31,19 +31,12 @@
 static
 void gen_index(int gridID1, int gridID2, int *index)
 {
-  int nlat1, nlon1;
-  int nlat2, nlon2;
-  int gridtype1, gridtype2;
-  int gridsize2;
   int i, j, k, i1, i2;
-  int *xindex = NULL, *yindex = NULL;
-  double *xvals1 = NULL, *yvals1 = NULL;
-  double *xvals2 = NULL, *yvals2 = NULL;
 
-  gridtype1 = gridInqType(gridID1);
-  gridtype2 = gridInqType(gridID2);
+  int gridtype1 = gridInqType(gridID1);
+  int gridtype2 = gridInqType(gridID2);
 
-  gridsize2 = gridInqSize(gridID2);
+  int gridsize2 = gridInqSize(gridID2);
 
   if ( gridtype1 != gridtype2 )
     cdoAbort("Input streams have different grid types!");
@@ -54,15 +47,11 @@ void gen_index(int gridID1, int gridID2, int *index)
 
   if ( gridtype1 == GRID_LONLAT || gridtype1 == GRID_GAUSSIAN )
     {
-      /*
-      if ( gridIsRotated(gridID1) )
-	cdoAbort("Rotated grids unsupported!");
-      */
-      nlon1 = gridInqXsize(gridID1);
-      nlat1 = gridInqYsize(gridID1);
+      int nlon1 = gridInqXsize(gridID1);
+      int nlat1 = gridInqYsize(gridID1);
 
-      nlon2 = gridInqXsize(gridID2);
-      nlat2 = gridInqYsize(gridID2);
+      int nlon2 = gridInqXsize(gridID2);
+      int nlat2 = gridInqYsize(gridID2);
 
       if ( ! (gridInqXvals(gridID1, NULL) && gridInqYvals(gridID1, NULL)) )
 	cdoAbort("Grid 1 has no values!");
@@ -70,13 +59,13 @@ void gen_index(int gridID1, int gridID2, int *index)
       if ( ! (gridInqXvals(gridID2, NULL) && gridInqYvals(gridID2, NULL)) )
 	cdoAbort("Grid 2 has no values!");
 
-      xvals1 = (double*) Malloc(nlon1*sizeof(double));
-      yvals1 = (double*) Malloc(nlat1*sizeof(double));
-      xvals2 = (double*) Malloc(nlon2*sizeof(double));
-      yvals2 = (double*) Malloc(nlat2*sizeof(double));
+      double *xvals1 = (double*) Malloc(nlon1*sizeof(double));
+      double *yvals1 = (double*) Malloc(nlat1*sizeof(double));
+      double *xvals2 = (double*) Malloc(nlon2*sizeof(double));
+      double *yvals2 = (double*) Malloc(nlat2*sizeof(double));
 
-      xindex = (int*) Malloc(nlon2*sizeof(int));
-      yindex = (int*) Malloc(nlat2*sizeof(int));
+      int *xindex = (int*) Malloc(nlon2*sizeof(int));
+      int *yindex = (int*) Malloc(nlat2*sizeof(int));
 
       gridInqXvals(gridID1, xvals1);
       gridInqYvals(gridID1, yvals1);
@@ -169,37 +158,26 @@ void gen_index(int gridID1, int gridID2, int *index)
 
 void *Mergegrid(void *argument)
 {
-  int varID;
+  int varID, levelID;
   int nrecs = 0;
-  int tsID, recID, levelID;
-  int nrecs2;
-  int streamID1, streamID2, streamID3;
-  int vlistID1 , vlistID2, vlistID3;
   int nmiss1, nmiss2;
-  int gridsize1, gridsize2;
-  int gridID1, gridID2;
-  int taxisID1, taxisID3;
   int index;
-  int i, *gindex = NULL;
-  int ndiffgrids;
-  double missval1, missval2;
-  double *array1, *array2;
 
   cdoInitialize(argument);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID3 = taxisDuplicate(taxisID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID3 = taxisDuplicate(taxisID1);
 
-  streamID2 = streamOpenRead(cdoStreamName(1));
+  int streamID2 = streamOpenRead(cdoStreamName(1));
 
-  vlistID2 = streamInqVlist(streamID2);
+  int vlistID2 = streamInqVlist(streamID2);
 
   vlistCompare(vlistID1, vlistID2, CMP_NAME | CMP_NLEVEL);
 
-  ndiffgrids = 0;
+  int ndiffgrids = 0;
   for ( index = 1; index < vlistNgrids(vlistID1); index++ )
     if ( vlistGrid(vlistID1, 0) != vlistGrid(vlistID1, index) )
       ndiffgrids++;
@@ -213,31 +191,31 @@ void *Mergegrid(void *argument)
 
   if ( ndiffgrids > 0 ) cdoAbort("Too many different grids in %s!", cdoStreamName(1)->args);
 
-  gridID1 = vlistGrid(vlistID1, 0);
-  gridID2 = vlistGrid(vlistID2, 0);
+  int gridID1 = vlistGrid(vlistID1, 0);
+  int gridID2 = vlistGrid(vlistID2, 0);
 
-  gridsize1 = gridInqSize(gridID1);
-  gridsize2 = gridInqSize(gridID2);
+  int gridsize1 = gridInqSize(gridID1);
+  int gridsize2 = gridInqSize(gridID2);
 
-  array1 = (double*) Malloc(gridsize1*sizeof(double));
-  array2 = (double*) Malloc(gridsize2*sizeof(double));
-  gindex = (int*) Malloc(gridsize2*sizeof(int));
+  double *array1 = (double*) Malloc(gridsize1*sizeof(double));
+  double *array2 = (double*) Malloc(gridsize2*sizeof(double));
+  int *gindex = (int*) Malloc(gridsize2*sizeof(int));
 
   gen_index(gridID1, gridID2, gindex);
 
-  vlistID3 = vlistDuplicate(vlistID1);
+  int vlistID3 = vlistDuplicate(vlistID1);
 
-  streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
+  int streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
 
   vlistDefTaxis(vlistID3, taxisID3);
   streamDefVlist(streamID3, vlistID3);
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID3, taxisID1);
 
-      nrecs2 = streamInqTimestep(streamID2, tsID);
+      int nrecs2 = streamInqTimestep(streamID2, tsID);
       if ( nrecs2 == 0 )
 	cdoAbort("Input streams have different number of timesteps!");
 
@@ -246,19 +224,19 @@ void *Mergegrid(void *argument)
 
       streamDefTimestep(streamID3, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID2, &varID, &levelID);
 	  streamReadRecord(streamID2, array2, &nmiss2);
 
-	  missval2 = vlistInqVarMissval(vlistID2, varID);
+	  double missval2 = vlistInqVarMissval(vlistID2, varID);
 
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, array1, &nmiss1);
 
-	  missval1 = vlistInqVarMissval(vlistID1, varID);
+	  double missval1 = vlistInqVarMissval(vlistID1, varID);
 
-	  for ( i = 0; i < gridsize2; i++ )
+	  for ( int i = 0; i < gridsize2; i++ )
 	    {
 	      if ( gindex[i] >= 0 && !DBL_IS_EQUAL(array2[i], missval2) )
 		{
@@ -269,7 +247,7 @@ void *Mergegrid(void *argument)
 	  if ( nmiss1 )
 	    {
 	      nmiss1 = 0;
-	      for ( i = 0; i < gridsize1; i++ )
+	      for ( int i = 0; i < gridsize1; i++ )
 		if ( DBL_IS_EQUAL(array1[i], missval1) ) nmiss1++;
 	    }
 
diff --git a/src/Mergetime.c b/src/Mergetime.c
index 19c8a05..b35ad18 100644
--- a/src/Mergetime.c
+++ b/src/Mergetime.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -32,7 +32,7 @@
 void *Mergetime(void *argument)
 {
   int streamID1;
-  int tsID2 = 0, recID, varID, levelID;
+  int tsID2 = 0, varID, levelID;
   int vlistID1, vlistID2;
   int fileID;
   int taxisID1, taxisID2 = CDI_UNDEFID;
@@ -56,8 +56,7 @@ void *Mergetime(void *argument)
   cdoInitialize(argument);
 
   {
-    char *envstr;
-    envstr = getenv("SKIP_SAME_TIME");
+    char *envstr = getenv("SKIP_SAME_TIME");
     if ( envstr )
       {
 	int ival;
@@ -183,7 +182,7 @@ void *Mergetime(void *argument)
 
 	  streamDefTimestep(streamID2, tsID2);
 	       
-	  for ( recID = 0; recID < sf[fileID].nrecs; recID++ )
+	  for ( int recID = 0; recID < sf[fileID].nrecs; recID++ )
 	    {
 	      streamInqRecord(sf[fileID].streamID, &varID, &levelID);
 
diff --git a/src/Merstat.c b/src/Merstat.c
index cab72a0..1613604 100644
--- a/src/Merstat.c
+++ b/src/Merstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -44,9 +44,9 @@ void *Merstat(void *argument)
   int wstatus = FALSE;
   int index;
   int nmiss;
-  int recID, nrecs;
+  int nrecs;
   int varID, levelID;
-  int needWeights = FALSE;
+  bool needWeights = false;
   char varname[CDI_MAX_NAME];
 
   cdoInitialize(argument);
@@ -76,7 +76,7 @@ void *Merstat(void *argument)
   if ( operfunc == func_mean || operfunc == func_avg ||
        operfunc == func_var  || operfunc == func_std ||
        operfunc == func_var1 || operfunc == func_std1 )
-    needWeights = TRUE;
+    needWeights = true;
 
   int streamID1 = streamOpenRead(cdoStreamName(0));
 
@@ -119,7 +119,7 @@ void *Merstat(void *argument)
   int nlonmax = gridInqXsize(gridID1); /* max nlon ? */
   int lim = vlistGridsizeMax(vlistID1);
 
-  field_t field1, field2;
+  field_type field1, field2;
   field_init(&field1);
   field_init(&field2);
 
@@ -138,7 +138,7 @@ void *Merstat(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, field1.ptr, &nmiss);
diff --git a/src/Monarith.c b/src/Monarith.c
index a15717a..5aeba88 100644
--- a/src/Monarith.c
+++ b/src/Monarith.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -32,22 +32,11 @@
 
 void *Monarith(void *argument)
 {
-  int operatorID;
-  int operfunc;
-  int streamID1, streamID2, streamID3;
-  int gridsize;
-  int nrecs, nrecs2, nvars, nlev, recID;
-  int tsID, tsID2;
+  int nrecs, nrecs2, nlev;
   int varID, levelID;
   int offset;
   int nmiss;
-  int vlistID1, vlistID2, vlistID3;
-  int taxisID1, taxisID2, taxisID3;
-  int vdate;
-  int yearmon1, yearmon2 = -1;
-  field_t field1, field2;
-  int **varnmiss2;
-  double **vardata2;
+  int yearmon2 = -1;
 
   cdoInitialize(argument);
 
@@ -56,39 +45,39 @@ void *Monarith(void *argument)
   cdoOperatorAdd("monmul", func_mul, 0, NULL);
   cdoOperatorAdd("mondiv", func_div, 0, NULL);
 
-  operatorID = cdoOperatorID();
-  operfunc = cdoOperatorF1(operatorID);
+  int operatorID = cdoOperatorID();
+  int operfunc = cdoOperatorF1(operatorID);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
-  streamID2 = streamOpenRead(cdoStreamName(1));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID2 = streamOpenRead(cdoStreamName(1));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = streamInqVlist(streamID2);
-  vlistID3 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = streamInqVlist(streamID2);
+  int vlistID3 = vlistDuplicate(vlistID1);
 
   vlistCompare(vlistID1, vlistID2, CMP_ALL);
   
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
 
+  field_type field1, field2;
   field_init(&field1);
   field_init(&field2);
-
   field1.ptr = (double*) Malloc(gridsize*sizeof(double));
   field2.ptr = (double*) Malloc(gridsize*sizeof(double));
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = vlistInqTaxis(vlistID2);
-  taxisID3 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = vlistInqTaxis(vlistID2);
+  int taxisID3 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID3, taxisID3);
 
-  streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
+  int streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
 
   streamDefVlist(streamID3, vlistID3);
 
-  nvars  = vlistNvars(vlistID2);
+  int nvars  = vlistNvars(vlistID2);
 
-  vardata2  = (double **) Malloc(nvars*sizeof(double *));
-  varnmiss2 = (int **) Malloc(nvars*sizeof(int *));
+  double **vardata2  = (double **) Malloc(nvars*sizeof(double *));
+  int **varnmiss2 = (int **) Malloc(nvars*sizeof(int *));
 
   for ( varID = 0; varID < nvars; varID++ )
     {
@@ -98,13 +87,12 @@ void *Monarith(void *argument)
       varnmiss2[varID] = (int*) Malloc(nlev*sizeof(int));
     }
 
-  tsID  = 0;
-  tsID2 = 0;
+  int tsID  = 0;
+  int tsID2 = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
-      vdate = taxisInqVdate(taxisID1);
-
-      yearmon1 = vdate / 100;
+      int vdate = taxisInqVdate(taxisID1);
+      int yearmon1 = vdate / 100;
 
       if ( yearmon1 != yearmon2 )
 	{
@@ -120,21 +108,17 @@ void *Monarith(void *argument)
 	    cdoAbort("Missing year=%4d mon=%2d in %s!", year1, mon1, cdoStreamName(1)->args);
 
 	  vdate = taxisInqVdate(taxisID2);
-
 	  yearmon2 = vdate / 100;
 
 	  if ( yearmon1 != yearmon2 )
 	    {
-	      int year2, mon2;
-
-	      year2 = yearmon2/100;
-	      mon2  = yearmon2 - (yearmon2/100)*100;
-
+	      int year2 = yearmon2/100;
+	      int mon2  = yearmon2 - (yearmon2/100)*100;
 	      cdoAbort("Timestep %d in %s has wrong date! Current year=%4d mon=%2d, expected year=%4d mon=%2d",
 		       tsID2+1, cdoStreamName(1)->args, year2, mon2, year1, mon1);
 	    }
 
-	  for ( recID = 0; recID < nrecs2; recID++ )
+	  for ( int recID = 0; recID < nrecs2; recID++ )
 	    {
 	      streamInqRecord(streamID2, &varID, &levelID);
 
@@ -152,7 +136,7 @@ void *Monarith(void *argument)
 
       streamDefTimestep(streamID3, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, field1.ptr, &nmiss);
diff --git a/src/Mrotuv.c b/src/Mrotuv.c
index 4042276..e23a258 100644
--- a/src/Mrotuv.c
+++ b/src/Mrotuv.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -40,13 +40,12 @@ void rotate_uv(double *u_i, double *v_j, int ix, int iy,
   double lat_factor;
   double absold, absnew;  /* velocity vector lengths */
   int  i, j, ip1, im1, jp1, jm1;
-  int  change_sign_u, change_sign_v;
   double pi = 3.14159265359;
 
 
   /* specification whether change in sign is needed for the input arrays */
-  change_sign_u = FALSE;
-  change_sign_v = TRUE;
+  bool change_sign_u = false;
+  bool change_sign_v = true;
 
   /* initialization */
   for ( i = 0; i < ix*iy; i++ )
@@ -147,7 +146,6 @@ void p_to_uv_grid(int nlon, int nlat, double *grid1x, double *grid1y,
 {
   int i, j, jp1, ip1;
 
-  
   /* interpolate scalar to u points */
   for ( j = 0; j < nlat; j++ )
     for ( i = 0; i < nlon; i++ )
@@ -193,37 +191,22 @@ void p_to_uv_grid(int nlon, int nlat, double *grid1x, double *grid1y,
 
 void *Mrotuv(void *argument)
 {
-  int streamID1, streamID2, streamID3;
   int nrecs;
-  int tsID, recID, levelID;
+  int levelID;
   int varID, varid;
-  int lid, nlevs, code;
-  int nvars;
-  int gridID1, gridID2, gridIDu, gridIDv;
-  int gridsize, gridsizex;
-  int nlon, nlat;
-  int vlistID1, vlistID2, vlistID3;
-  int i, j;
-  int taxisID1, taxisID2, taxisID3;
   int nmiss1, nmiss2;
   int uid = -1, vid = -1;
-  double missval1, missval2;
-  double *ufield = NULL, *vfield = NULL;
-  double **urfield = NULL, **vrfield = NULL;
-  double *uhelp = NULL, *vhelp = NULL;
-  double *grid1x = NULL, *gridux = NULL, *gridvx = NULL;
-  double *grid1y = NULL, *griduy = NULL, *gridvy = NULL;
 
   cdoInitialize(argument);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
+  int vlistID1 = streamInqVlist(streamID1);
 
-  nvars = vlistNvars(vlistID1);
+  int nvars = vlistNvars(vlistID1);
   for ( varid = 0; varid < nvars; varid++ )
     {
-      code = vlistInqVarCode(vlistID1, varid);
+      int code = vlistInqVarCode(vlistID1, varid);
       if ( code == 3 || code == 131 ) uid = varid;
       if ( code == 4 || code == 132 ) vid = varid;
     }
@@ -239,13 +222,13 @@ void *Mrotuv(void *argument)
 	cdoAbort("U and V not found in %s",  cdoStreamName(0)->args);
     }
 
-  nlevs = zaxisInqSize(vlistInqVarZaxis(vlistID1, uid));
+  int nlevs = zaxisInqSize(vlistInqVarZaxis(vlistID1, uid));
   if ( nlevs != zaxisInqSize(vlistInqVarZaxis(vlistID1, vid)) )
     cdoAbort("U and V have different number of levels!");
 
-  gridID1 = vlistInqVarGrid(vlistID1, uid);
-  gridID2 = vlistInqVarGrid(vlistID1, vid);
-  gridsize = gridInqSize(gridID1);
+  int gridID1 = vlistInqVarGrid(vlistID1, uid);
+  int gridID2 = vlistInqVarGrid(vlistID1, vid);
+  int gridsize = gridInqSize(gridID1);
   if ( gridID1 != gridID2 ) cdoAbort("Input grids differ!");
 
   if ( gridInqType(gridID1) != GRID_LONLAT      &&
@@ -258,17 +241,17 @@ void *Mrotuv(void *argument)
 
   if ( gridsize != gridInqSize(gridID1) ) cdoAbort("Internal problem: gridsize changed!");
 
-  nlon    = gridInqXsize(gridID1);
-  nlat    = gridInqYsize(gridID1);
+  int nlon    = gridInqXsize(gridID1);
+  int nlat    = gridInqYsize(gridID1);
 
-  grid1x  = (double*) Malloc(gridsize*sizeof(double));
-  grid1y  = (double*) Malloc(gridsize*sizeof(double));
-  gridux  = (double*) Malloc(gridsize*sizeof(double));
-  griduy  = (double*) Malloc(gridsize*sizeof(double));
-  gridvx  = (double*) Malloc(gridsize*sizeof(double));
-  gridvy  = (double*) Malloc(gridsize*sizeof(double));
+  double *grid1x  = (double*) Malloc(gridsize*sizeof(double));
+  double *grid1y  = (double*) Malloc(gridsize*sizeof(double));
+  double *gridux  = (double*) Malloc(gridsize*sizeof(double));
+  double *griduy  = (double*) Malloc(gridsize*sizeof(double));
+  double *gridvx  = (double*) Malloc(gridsize*sizeof(double));
+  double *gridvy  = (double*) Malloc(gridsize*sizeof(double));
 
-  gridsizex = (nlon+2)*nlat;
+  int gridsizex = (nlon+2)*nlat;
 
   gridInqXvals(gridID1, grid1x);
   gridInqYvals(gridID1, grid1y);
@@ -284,68 +267,68 @@ void *Mrotuv(void *argument)
 
   p_to_uv_grid(nlon, nlat, grid1x, grid1y, gridux, griduy, gridvx, gridvy);
 
-  gridIDu = gridCreate(GRID_CURVILINEAR, nlon*nlat);
+  int gridIDu = gridCreate(GRID_CURVILINEAR, nlon*nlat);
   gridDefPrec(gridIDu, gridInqPrec(gridID1));
   gridDefXsize(gridIDu, nlon);
   gridDefYsize(gridIDu, nlat);
   gridDefXvals(gridIDu, gridux);
   gridDefYvals(gridIDu, griduy);
 
-  gridIDv = gridCreate(GRID_CURVILINEAR, nlon*nlat);
+  int gridIDv = gridCreate(GRID_CURVILINEAR, nlon*nlat);
   gridDefPrec(gridIDv, gridInqPrec(gridID1));
   gridDefXsize(gridIDv, nlon);
   gridDefYsize(gridIDv, nlat);
   gridDefXvals(gridIDv, gridvx);
   gridDefYvals(gridIDv, gridvy);
 
-  for ( i = 0; i < gridsize; i++ )
+  for ( int i = 0; i < gridsize; i++ )
     {
       grid1x[i] *= DEG2RAD;
       grid1y[i] *= DEG2RAD;
     }
 
   vlistClearFlag(vlistID1);
-  for ( lid = 0; lid < nlevs; lid++ ) vlistDefFlag(vlistID1, uid, lid, TRUE);
-  vlistID2 = vlistCreate();
+  for ( int lid = 0; lid < nlevs; lid++ ) vlistDefFlag(vlistID1, uid, lid, TRUE);
+  int vlistID2 = vlistCreate();
   vlistCopyFlag(vlistID2, vlistID1);
   vlistChangeVarGrid(vlistID2, 0, gridIDu);
 
   vlistClearFlag(vlistID1);
-  for ( lid = 0; lid < nlevs; lid++ ) vlistDefFlag(vlistID1, vid, lid, TRUE);
-  vlistID3 = vlistCreate();
+  for ( int lid = 0; lid < nlevs; lid++ ) vlistDefFlag(vlistID1, vid, lid, TRUE);
+  int vlistID3 = vlistCreate();
   vlistCopyFlag(vlistID3, vlistID1);
   vlistChangeVarGrid(vlistID3, 0, gridIDv);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
-  taxisID3 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID3 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
   vlistDefTaxis(vlistID3, taxisID3);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
-  streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
   streamDefVlist(streamID3, vlistID3);
 
-  missval1 = vlistInqVarMissval(vlistID1, uid);
-  missval2 = vlistInqVarMissval(vlistID1, vid);
+  double missval1 = vlistInqVarMissval(vlistID1, uid);
+  double missval2 = vlistInqVarMissval(vlistID1, vid);
 
-  ufield  = (double*) Malloc(gridsize*sizeof(double));
-  vfield  = (double*) Malloc(gridsize*sizeof(double));
+  double *ufield = (double*) Malloc(gridsize*sizeof(double));
+  double *vfield = (double*) Malloc(gridsize*sizeof(double));
 
-  urfield  = (double**) Malloc(nlevs*sizeof(double*));
-  vrfield  = (double**) Malloc(nlevs*sizeof(double*));
-  for ( lid = 0; lid < nlevs; lid++ )
+  double **urfield = (double**) Malloc(nlevs*sizeof(double*));
+  double **vrfield = (double**) Malloc(nlevs*sizeof(double*));
+  for ( int lid = 0; lid < nlevs; lid++ )
     {
       urfield[lid] = (double*) Malloc(gridsize*sizeof(double));
       vrfield[lid] = (double*) Malloc(gridsize*sizeof(double));
     }
 
-  uhelp   = (double*) Malloc(gridsizex*sizeof(double));
-  vhelp   = (double*) Malloc(gridsizex*sizeof(double));
+  double *uhelp = (double*) Malloc(gridsizex*sizeof(double));
+  double *vhelp = (double*) Malloc(gridsizex*sizeof(double));
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
@@ -353,7 +336,7 @@ void *Mrotuv(void *argument)
       taxisCopyTimestep(taxisID3, taxisID1);
       streamDefTimestep(streamID3, tsID);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -366,7 +349,7 @@ void *Mrotuv(void *argument)
 	  /* remove missing values */
 	  if ( nmiss1 || nmiss2 )
 	    {
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( int 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;
@@ -378,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 ( j = 0; j < nlat; j++ )
-	    for ( i = 0; i < nlon; i++ )
+	  for ( int j = 0; j < nlat; j++ )
+	    for ( int 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 ( j = 0; j < nlat; j++ )
+	  for ( int 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)];
@@ -395,19 +378,19 @@ void *Mrotuv(void *argument)
 	    }
 
 	  /* interpolate on u/v points */
-	  for ( j = 0; j < nlat; j++ )
-	    for ( i = 0; i < nlon; i++ )
+	  for ( int j = 0; j < nlat; j++ )
+	    for ( int 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 ( j = 0; j < nlat-1; j++ )
-	    for ( i = 0; i < nlon; i++ )
+	  for ( int j = 0; j < nlat-1; j++ )
+	    for ( int 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 ( i = 0; i < nlon; i++ )
+	  for ( int i = 0; i < nlon; i++ )
 	    {
 	      vfield[IX2D(nlat-1,i,nlon)] = vhelp[IX2D(nlat-1,i+1,nlon+2)];
 	    }
diff --git a/src/Mrotuvb.c b/src/Mrotuvb.c
index b1337a4..3bd7e02 100644
--- a/src/Mrotuvb.c
+++ b/src/Mrotuvb.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -63,13 +63,12 @@ void rotate_uv2(double *u_i, double *v_j, int ix, int iy,
   double lat_factor;
   double absold, absnew;  /* velocity vector lengths */
   int  i, j, ip1, im1, jp1, jm1;
-  bool change_sign_u, change_sign_v;
   double pi = 3.14159265359;
 
 
   /* specification whether change in sign is needed for the input arrays */
-  change_sign_u = false;
-  change_sign_v = true;
+  bool change_sign_u = false;
+  bool change_sign_v = true;
 
   /* initialization */
   for ( i = 0; i < ix*iy; i++ )
@@ -155,26 +154,23 @@ static
 void uv_to_p_grid(int nlon, int nlat, double *grid1x, double *grid1y, 
 		  double *grid2x, double *grid2y, double *grid3x, double *grid3y)
 {
-  int gridsizex;
-  int i, j;
   double gx, gy;
   double gx2, gy2;
-  double *gxhelp, *gyhelp;
 
-  gridsizex = (nlon+2)*nlat;
-  gxhelp  = (double*) Malloc(gridsizex*sizeof(double));
-  gyhelp  = (double*) Malloc(gridsizex*sizeof(double));
+  int gridsizex = (nlon+2)*nlat;
+  double *gxhelp = (double*) Malloc(gridsizex*sizeof(double));
+  double *gyhelp = (double*) Malloc(gridsizex*sizeof(double));
 
   /* load to a help field */
-  for ( j = 0; j < nlat; j++ )
-    for ( i = 0; i < nlon; i++ )
+  for ( int j = 0; j < nlat; j++ )
+    for ( int 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 ( j = 0; j < nlat; j++ )
+  for ( int 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)];
@@ -183,8 +179,8 @@ void uv_to_p_grid(int nlon, int nlat, double *grid1x, double *grid1y,
     }
 
   /* interpolate u to scalar points */
-  for ( j = 0; j < nlat; j++ )
-    for ( i = 0; i < nlon; i++ )
+  for ( int j = 0; j < nlat; j++ )
+    for ( int 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) ||
@@ -200,15 +196,15 @@ void uv_to_p_grid(int nlon, int nlat, double *grid1x, double *grid1y,
       }
 
   /* load to a help field */
-  for ( j = 0; j < nlat; j++ )
-    for ( i = 0; i < nlon; i++ )
+  for ( int j = 0; j < nlat; j++ )
+    for ( int 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 ( j = 0; j < nlat; j++ )
+  for ( int 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)];
@@ -217,8 +213,8 @@ void uv_to_p_grid(int nlon, int nlat, double *grid1x, double *grid1y,
     }
 
   /* interpolate v to scalar points */
-  for ( j = 1; j < nlat-1; j++ )
-    for ( i = 0; i < nlon; i++ )
+  for ( int j = 1; j < nlat-1; j++ )
+    for ( int 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) ||
@@ -306,12 +302,12 @@ void *Mrotuvb(void *argument)
   int nlon    = gridInqXsize(gridID1);
   int nlat    = gridInqYsize(gridID1);
 
-  double *grid1x  = (double*) Malloc(gridsize*sizeof(double));
-  double *grid1y  = (double*) Malloc(gridsize*sizeof(double));
-  double *grid2x  = (double*) Malloc(gridsize*sizeof(double));
-  double *grid2y  = (double*) Malloc(gridsize*sizeof(double));
-  double *grid3x  = (double*) Malloc(gridsize*sizeof(double));
-  double *grid3y  = (double*) Malloc(gridsize*sizeof(double));
+  double *grid1x = (double*) Malloc(gridsize*sizeof(double));
+  double *grid1y = (double*) Malloc(gridsize*sizeof(double));
+  double *grid2x = (double*) Malloc(gridsize*sizeof(double));
+  double *grid2y = (double*) Malloc(gridsize*sizeof(double));
+  double *grid3x = (double*) Malloc(gridsize*sizeof(double));
+  double *grid3y = (double*) Malloc(gridsize*sizeof(double));
 
   gridInqXvals(gridID1, grid1x);
   gridInqYvals(gridID1, grid1y);
diff --git a/src/Ninfo.c b/src/Ninfo.c
index 7d9f503..fc2e299 100644
--- a/src/Ninfo.c
+++ b/src/Ninfo.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -38,18 +38,10 @@
 void *Ninfo(void *argument)
 {
   enum {NYEAR, NMON, NDATE, NTIME, NPAR, NLEVEL, NGRIDPOINTS, NGRIDS};
-  int operatorID;
-  int operfunc;
-  int varID, zaxisID, gridID;
-  int vdate;
-  int nrecs, nvars, ntsteps, ngrids;
-  int levelsize;
-  int gridsize;
-  int tsID, ndate, date0 = 0;
-  int day, mon0 = 0, mon, nmon, year0 = 0, year, nyear;
-  int taxisID;
-  int streamID;
-  int vlistID;
+  int varID;
+  int nrecs;
+  int date0 = 0;
+  int day, mon0 = 0, mon, year0 = 0, year;
 
   cdoInitialize(argument);
 
@@ -62,28 +54,28 @@ void *Ninfo(void *argument)
   cdoOperatorAdd("ngridpoints" , NGRIDPOINTS , 0 , NULL);
   cdoOperatorAdd("ngrids"      , NGRIDS      , 0 , NULL);
 
-  operatorID = cdoOperatorID();
-  operfunc   = cdoOperatorF1(operatorID);
+  int operatorID = cdoOperatorID();
+  int operfunc   = cdoOperatorF1(operatorID);
 
-  streamID = streamOpenRead(cdoStreamName(0));
+  int streamID = streamOpenRead(cdoStreamName(0));
 
-  vlistID = streamInqVlist(streamID);
+  int vlistID = streamInqVlist(streamID);
 
-  nvars   = vlistNvars(vlistID);
-  taxisID = vlistInqTaxis(vlistID);
-  ntsteps = vlistNtsteps(vlistID);
-  ngrids  = vlistNgrids(vlistID);
+  int nvars   = vlistNvars(vlistID);
+  int taxisID = vlistInqTaxis(vlistID);
+  int ntsteps = vlistNtsteps(vlistID);
+  int ngrids  = vlistNgrids(vlistID);
 
   switch ( operfunc )
     {
     case NYEAR:
-      nyear = 0;
-      tsID = 0;
+      {
+      int nyear = 0;
+      int tsID = 0;
       if ( ntsteps != 0 )
 	while ( (nrecs = streamInqTimestep(streamID, tsID)) )
 	  {
-	    vdate = taxisInqVdate(taxisID);
-
+	    int vdate = taxisInqVdate(taxisID);
 	    cdiDecodeDate(vdate, &year, &mon, &day);
 	 
 	    if ( tsID == 0 || year0 != year )
@@ -96,14 +88,15 @@ void *Ninfo(void *argument)
 	  }
       fprintf(stdout, "%d\n", nyear);
       break;
+      }
     case NMON:
-      nmon = 0;
-      tsID = 0;
+      {
+      int nmon = 0;
+      int tsID = 0;
       if ( ntsteps != 0 )
 	while ( (nrecs = streamInqTimestep(streamID, tsID)) )
 	  {
-	    vdate = taxisInqVdate(taxisID);
-	    
+	    int vdate = taxisInqVdate(taxisID);
 	    cdiDecodeDate(vdate, &year, &mon, &day);
 	 
 	    if ( tsID == 0 || mon0 != mon )
@@ -116,13 +109,15 @@ void *Ninfo(void *argument)
 	  }
       fprintf(stdout, "%d\n", nmon);
       break;
+      }
     case NDATE:
-      ndate = 0;
-      tsID = 0;
+      {
+      int ndate = 0;
+      int tsID = 0;
       if ( ntsteps != 0 )
 	while ( (nrecs = streamInqTimestep(streamID, tsID)) )
 	  {
-	    vdate = taxisInqVdate(taxisID);
+	    int vdate = taxisInqVdate(taxisID);
 	    
 	    if ( tsID == 0 || date0 != vdate )
 	      {
@@ -134,28 +129,31 @@ void *Ninfo(void *argument)
 	  }
       fprintf(stdout, "%d\n", ndate);
       break;
+      }
     case NTIME:
-      tsID = 0;
+      {
+      int tsID = 0;
       if ( ntsteps != 0 )
 	while ( (nrecs = streamInqTimestep(streamID, tsID)) ) tsID++;
       fprintf(stdout, "%d\n", tsID);
       break;
+      }
     case NPAR:
       fprintf(stdout, "%d\n", nvars);
       break;
     case NLEVEL:
       for ( varID = 0; varID < nvars; varID++ )
 	{
-	  zaxisID = vlistInqVarZaxis(vlistID, varID);
-	  levelsize = zaxisInqSize(zaxisID);
+	  int zaxisID = vlistInqVarZaxis(vlistID, varID);
+	  int levelsize = zaxisInqSize(zaxisID);
 	  fprintf(stdout, "%d\n", levelsize);
 	}
       break;
     case NGRIDPOINTS:
       for ( varID = 0; varID < nvars; varID++ )
 	{
-	  gridID = vlistInqVarGrid(vlistID, varID);
-	  gridsize = gridInqSize(gridID);
+	  int gridID = vlistInqVarGrid(vlistID, varID);
+	  int gridsize = gridInqSize(gridID);
 	  fprintf(stdout, "%d\n", gridsize);
 	}
       break;
diff --git a/src/Nmldump.c b/src/Nmldump.c
new file mode 100644
index 0000000..1f50a45
--- /dev/null
+++ b/src/Nmldump.c
@@ -0,0 +1,103 @@
+/*
+  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.
+*/
+
+/*
+   This module contains the following operators:
+
+*/
+
+#include "cdi.h"
+#include "cdo.h"
+#include "cdo_int.h"
+
+
+static
+void print_values(int nvalues, char **values)
+{
+  char fltstr[128];
+  if ( nvalues && values )
+    {
+      int dtype = literals_find_datatype(nvalues, values);
+      for ( int i = 0; i < nvalues; ++i )
+        {
+          if ( i ) printf(", ");
+          switch (dtype)
+            {
+            case CDI_DATATYPE_INT8:  printf("%db", literal_to_int(values[i])); break;
+            case CDI_DATATYPE_INT16: printf("%ds", literal_to_int(values[i])); break;
+            case CDI_DATATYPE_INT32: printf("%d",  literal_to_int(values[i])); break;
+            case CDI_DATATYPE_FLT32: printf("%sf", double_to_attstr(CDO_flt_digits, fltstr, sizeof(fltstr), literal_to_double(values[i]))); break;
+            case CDI_DATATYPE_FLT64: printf("%s",  double_to_attstr(CDO_dbl_digits, fltstr, sizeof(fltstr), literal_to_double(values[i]))); break;
+            default: printf("\"%s\"", values[i]);
+            }
+        }
+    }
+}
+
+
+void kvldump(list_t *pmlist)
+{
+  if ( pmlist )
+    {
+      for ( listNode_t *pmnode = pmlist->head; pmnode; pmnode = pmnode->next )
+        {
+          if ( pmnode->data )
+            {
+              list_t *kvlist = *(list_t **)pmnode->data;
+              if ( kvlist )
+                {
+                  const char *listname = list_name(kvlist);
+                  if ( listname ) printf("&%s\n", list_name(kvlist));
+                  for ( listNode_t *kvnode = kvlist->head; kvnode; kvnode = kvnode->next )
+                    {
+                      keyValues_t *kv = *(keyValues_t **)kvnode->data;
+                      const char *key = kv->key;
+                      if ( listname ) printf("  ");
+                      printf("%s = ", key);
+                      print_values(kv->nvalues, kv->values);
+                      printf("\n");
+                    }
+                  if ( listname ) printf("/\n");
+                }
+            }
+        }
+    }
+}
+
+
+void *Nmldump(void *argument)
+{
+  cdoInitialize(argument);
+
+  int NMLDUMP = cdoOperatorAdd("nmldump",  0, 0, NULL);
+  int KVLDUMP = cdoOperatorAdd("kvldump",  0, 0, NULL);
+
+  int operatorID = cdoOperatorID();
+
+  list_t *pmlist = namelist_to_pmlist(stdin, "STDIN");
+
+  if ( operatorID == NMLDUMP )
+    list_for_each(pmlist, pmlist_print_iter);
+  else if ( operatorID == KVLDUMP )
+    kvldump(pmlist);
+
+  list_destroy(pmlist);
+
+  cdoFinish();
+
+  return 0;
+}
diff --git a/src/Nmltest.c b/src/Nmltest.c
deleted file mode 100644
index 5294c84..0000000
--- a/src/Nmltest.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
-  This file is part of CDO. CDO is a collection of Operators to
-  manipulate and analyse Climate model Data.
-
-  Copyright (C) 2003-2016 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.
-*/
-
-/*
-   This module contains the following operators:
-
-*/
-
-
-#include "cdo.h"
-#include "cdo_int.h"
-#include "namelist.h"
-
-
-void *Nmltest(void *argument)
-{
-  namelist_t *nml;
-  int i1[5] = {-99, -99, -99, -99, -99};
-  int i2    = -99;
-  char lop[99] = "";
-  double dm = 0;
-  char *var[3];
-
-  cdoInitialize(argument);
-
-  nml = namelistNew("SELECT");
-
-  namelistAdd(nml, "i1",  NML_INT,    0, i1,   sizeof(i1)/sizeof(int));
-  namelistAdd(nml, "i2",  NML_INT,    1, &i2,  sizeof(i2)/sizeof(int));
-  namelistAdd(nml, "lop", NML_TEXT,   2, lop,  sizeof(lop)/sizeof(char));
-  namelistAdd(nml, "dm",  NML_FLT, 1, &dm,  sizeof(dm)/sizeof(double));
-  namelistAdd(nml, "var", NML_WORD,   0, var,  sizeof(var)/sizeof(char *));
-
-  namelistRead(stdin, nml);
-
-  namelistPrint(nml);
-
-  namelistDelete(nml);
-
-  cdoFinish();
-
-  return 0;
-}
diff --git a/src/Output.c b/src/Output.c
index e954d57..bf4f46d 100644
--- a/src/Output.c
+++ b/src/Output.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -26,7 +26,7 @@
       Output     outputtab       Table output
 */
 
-#include <ctype.h>
+
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
@@ -36,37 +36,18 @@
 
 void *Output(void *argument)
 {
-  int OUTPUT, OUTPUTINT, OUTPUTSRV, OUTPUTEXT, OUTPUTF, OUTPUTTS, OUTPUTFLD, OUTPUTARR, OUTPUTXYZ, OUTPUTTAB;
-  int operatorID;
-  int i;
-  int indf;
-  int varID, recID;
-  int gridsize = 0;
-  int gridID, zaxisID, code, vdate, vtime;
-  int param;
-  int gridtype;
-  int ngrids;
+  int varID;
+  int gridID;
   int nrecs;
   int levelID;
-  int tsID, taxisID;
-  int streamID = 0;
-  int vlistID;
-  int nmiss, nout;
-  int nlon, nlat;
+  int nmiss;
   int nelem = 1;
   int len;
   int index;
-  int ndiffgrids;
-  int lhead = TRUE;
   const char *format = NULL;
   char paramstr[32];
   char vdatestr[32], vtimestr[32];
-  double level;
   double *grid_center_lon = NULL, *grid_center_lat = NULL;
-  double *array = NULL;
-  double xdate;
-  double missval;
-  double lon, lat;
   char name[CDI_MAX_NAME];
   int year, month, day;
   int *keys = NULL, nkeys = 0, k;
@@ -78,20 +59,20 @@ void *Output(void *argument)
 
   cdoInitialize(argument);
 
-  OUTPUT    = cdoOperatorAdd("output",    0, 0, NULL);
-  OUTPUTINT = cdoOperatorAdd("outputint", 0, 0, NULL);
-  OUTPUTSRV = cdoOperatorAdd("outputsrv", 0, 0, NULL);
-  OUTPUTEXT = cdoOperatorAdd("outputext", 0, 0, NULL);
-  OUTPUTF   = cdoOperatorAdd("outputf",   0, 0, NULL);
-  OUTPUTTS  = cdoOperatorAdd("outputts",  0, 0, NULL);
-  OUTPUTFLD = cdoOperatorAdd("outputfld", 0, 0, NULL);
-  OUTPUTARR = cdoOperatorAdd("outputarr", 0, 0, NULL);
-  OUTPUTXYZ = cdoOperatorAdd("outputxyz", 0, 0, NULL);
-  OUTPUTTAB = cdoOperatorAdd("outputtab", 0, 0, NULL);
+  int OUTPUT    = cdoOperatorAdd("output",    0, 0, NULL);
+  int OUTPUTINT = cdoOperatorAdd("outputint", 0, 0, NULL);
+  int OUTPUTSRV = cdoOperatorAdd("outputsrv", 0, 0, NULL);
+  int OUTPUTEXT = cdoOperatorAdd("outputext", 0, 0, NULL);
+  int OUTPUTF   = cdoOperatorAdd("outputf",   0, 0, NULL);
+  int OUTPUTTS  = cdoOperatorAdd("outputts",  0, 0, NULL);
+  int OUTPUTFLD = cdoOperatorAdd("outputfld", 0, 0, NULL);
+  int OUTPUTARR = cdoOperatorAdd("outputarr", 0, 0, NULL);
+  int OUTPUTXYZ = cdoOperatorAdd("outputxyz", 0, 0, NULL);
+  int OUTPUTTAB = cdoOperatorAdd("outputtab", 0, 0, NULL);
 
   UNUSED(OUTPUT);
 
-  operatorID = cdoOperatorID();
+  int operatorID = cdoOperatorID();
 
   if ( operatorID == OUTPUTF )
     {
@@ -104,19 +85,21 @@ void *Output(void *argument)
     }
   else if ( operatorID == OUTPUTTAB )
     {
+      bool lhead = true;
+
       operatorInputArg("keys to print");
  
       int npar = operatorArgc();
       char **parnames = operatorArgv();
 
       if ( cdoVerbose )
-	for ( i = 0; i < npar; i++ )
+	for ( int i = 0; i < npar; i++ )
 	  cdoPrint("key %d = %s", i+1, parnames[i]);
 
       keys = (int*) Malloc(npar*sizeof(int));
       nkeys = 0;
       nKeys = sizeof(Keynames)/sizeof(char *);
-      for ( i = 0; i < npar; i++ )
+      for ( int i = 0; i < npar; i++ )
 	{
 	  for ( k = 0; k < nKeys; ++k )
 	    {
@@ -125,7 +108,7 @@ void *Output(void *argument)
 	      if ( len < 3 ) len = 3;
 	      if ( strncmp(parnames[i], Keynames[k], len) == 0 )
 		{
-		  if ( k == knohead ) lhead = FALSE;
+		  if ( k == knohead ) lhead = false;
 		  else
 		    {
 		      keys[nkeys++] = k;
@@ -155,14 +138,14 @@ void *Output(void *argument)
 	}
     }
 
-  for ( indf = 0; indf < cdoStreamCnt(); indf++ )
+  for ( int indf = 0; indf < cdoStreamCnt(); indf++ )
     {
-      streamID = streamOpenRead(cdoStreamName(indf));
+      int streamID = streamOpenRead(cdoStreamName(indf));
 
-      vlistID = streamInqVlist(streamID);
+      int vlistID = streamInqVlist(streamID);
 
-      ngrids = vlistNgrids(vlistID);
-      ndiffgrids = 0;
+      int ngrids = vlistNgrids(vlistID);
+      int ndiffgrids = 0;
       for ( index = 1; index < ngrids; index++ )
 	if ( vlistGrid(vlistID, 0) != vlistGrid(vlistID, index) )
 	  ndiffgrids++;
@@ -170,10 +153,10 @@ void *Output(void *argument)
       if ( ndiffgrids > 0 ) cdoAbort("Too many different grids!");
 
       gridID   = vlistGrid(vlistID, 0);
-      gridsize = gridInqSize(gridID);
-      gridtype = gridInqType(gridID);
+      int gridsize = gridInqSize(gridID);
+      int gridtype = gridInqType(gridID);
 
-      array = (double*) Malloc(gridsize*sizeof(double));
+      double *array = (double*) Malloc(gridsize*sizeof(double));
 
       if ( operatorID == OUTPUTFLD || operatorID == OUTPUTXYZ || operatorID == OUTPUTTAB )
 	{
@@ -199,32 +182,32 @@ void *Output(void *argument)
 	  }
 	}
 
-      tsID = 0;
-      taxisID = vlistInqTaxis(vlistID);
+      int tsID = 0;
+      int taxisID = vlistInqTaxis(vlistID);
       while ( (nrecs = streamInqTimestep(streamID, tsID)) )
 	{
-	  vdate = taxisInqVdate(taxisID);
-	  vtime = taxisInqVtime(taxisID);
+	  int vdate = taxisInqVdate(taxisID);
+	  int vtime = taxisInqVtime(taxisID);
 	  date2str(vdate, vdatestr, sizeof(vdatestr));
 	  time2str(vtime, vtimestr, sizeof(vtimestr));
 
 	  cdiDecodeDate(vdate, &year, &month, &day);
 
-	  for ( recID = 0; recID < nrecs; recID++ )
+	  for ( int recID = 0; recID < nrecs; recID++ )
 	    {
 	      streamInqRecord(streamID, &varID, &levelID);
 
 	      vlistInqVarName(vlistID, varID, name);
-	      param    = vlistInqVarParam(vlistID, varID);
-	      code     = vlistInqVarCode(vlistID, varID);
-	      gridID   = vlistInqVarGrid(vlistID, varID);
-	      zaxisID  = vlistInqVarZaxis(vlistID, varID);
-	      missval  = vlistInqVarMissval(vlistID, varID);
-	      gridsize = gridInqSize(gridID);
-	      nlon     = gridInqXsize(gridID);
-	      nlat     = gridInqYsize(gridID);
-	      level    = zaxisInqLevel(zaxisID, levelID);
-	      
+	      int param    = vlistInqVarParam(vlistID, varID);
+	      int code     = vlistInqVarCode(vlistID, varID);
+	      int gridID   = vlistInqVarGrid(vlistID, varID);
+	      int zaxisID  = vlistInqVarZaxis(vlistID, varID);
+	      int gridsize = gridInqSize(gridID);
+	      int nlon     = gridInqXsize(gridID);
+	      int nlat     = gridInqYsize(gridID);
+	      double level   = cdoZaxisInqLevel(zaxisID, levelID);
+              double missval = vlistInqVarMissval(vlistID, varID);
+   
 	      cdiParamToString(param, paramstr, sizeof(paramstr));
 
 	      if ( nlon*nlat != gridsize ) { nlon = gridsize; nlat = 1; }
@@ -239,8 +222,8 @@ void *Output(void *argument)
 		
 	      if ( operatorID == OUTPUTINT )
 		{
-		  nout = 0;
-		  for ( i = 0; i < gridsize; i++ )
+		  int nout = 0;
+		  for ( int i = 0; i < gridsize; i++ )
 		    {
 		      if ( nout == 8 )
 			{
@@ -254,8 +237,8 @@ void *Output(void *argument)
 		}
 	      else if ( operatorID == OUTPUTF )
 		{
-		  nout = 0;
-		  for ( i = 0; i < gridsize; i++ )
+		  int nout = 0;
+		  for ( int i = 0; i < gridsize; i++ )
 		    {
 		      if ( nout == nelem )
 			{
@@ -283,28 +266,26 @@ void *Output(void *argument)
 		{
 		  int hour, minute, second;
 		  cdiDecodeTime(vtime, &hour, &minute, &second);
-		  xdate  = vdate - (vdate/100)*100 + (hour*3600 + minute*60 + second)/86400.;
-		  for ( i = 0; i < gridsize; i++ )
+		  double xdate = vdate - (vdate/100)*100 + (hour*3600 + minute*60 + second)/86400.;
+		  for ( int i = 0; i < gridsize; i++ )
 		    if ( !DBL_IS_EQUAL(array[i], missval) )
 		      fprintf(stdout, "%g\t%g\t%g\t%g\n", xdate, 
 			      grid_center_lat[i], grid_center_lon[i], array[i]);
 		}
 	      else if ( operatorID == OUTPUTTAB )
 		{
-		  int xind, yind;
-		  int l2d = FALSE;
-
+		  bool l2d = false;
 		  int xsize = gridInqXsize(gridID);
 		  // int ysize = gridInqYsize(gridID);
-		  if ( gridtype == GRID_CURVILINEAR ) l2d = TRUE;
+		  if ( gridtype == GRID_CURVILINEAR ) l2d = true;
 		      
-		  for ( i = 0; i < gridsize; i++ )
+		  for ( int i = 0; i < gridsize; i++ )
 		    {
-		      yind = i;
-		      xind = i;
+		      int yind = i;
+		      int xind = i;
 		      if ( l2d ) { yind /= xsize; xind -= yind*xsize; }
-		      lon = grid_center_lon[i];
-		      lat = grid_center_lat[i];
+		      double lon = grid_center_lon[i];
+		      double lat = grid_center_lat[i];
 
 		      for ( k = 0; k < nkeys; ++k )
 			{
@@ -337,25 +318,24 @@ void *Output(void *argument)
 		  if ( tsID == 0 && recID == 0 )
 		    {
 		      const char *fname = "frontplane.xyz";
-		      FILE *fp;
 		      double fmin = 0;
-		      double dx, x0, y0, z0, x, y, z;
-		      for ( i = 0; i < gridsize; i++ )
+		      double x, y, z;
+		      for ( int i = 0; i < gridsize; i++ )
 			if ( !DBL_IS_EQUAL(array[i], missval) )
 			  {
 			    if ( array[i] < fmin ) fmin = array[i];
 			    fprintf(stdout, "%g\t%g\t%g\t%g\n",
 				    grid_center_lon[i], grid_center_lat[i], array[i], array[i]);
 			  }
-		      fp = fopen(fname, "w");
+		      FILE *fp = fopen(fname, "w");
 		      if ( fp == NULL ) cdoAbort("Open failed on %s", fname);
 		      // first front plane
-		      dx = (grid_center_lon[1] - grid_center_lon[0]);
-		      x0 = grid_center_lon[0]-dx/2;
-		      y0 = grid_center_lat[0]-dx/2;
-		      z0 = fmin;
+		      double dx = (grid_center_lon[1] - grid_center_lon[0]);
+		      double x0 = grid_center_lon[0]-dx/2;
+		      double y0 = grid_center_lat[0]-dx/2;
+                      double z0 = fmin;
 		      fprintf(fp, ">\n");
-		      for ( i = 0; i < nlon; ++i )
+		      for ( int i = 0; i < nlon; ++i )
 			{
 			  x = x0;  y = y0; z = z0;
 			  fprintf(fp, "%g %g %g\n", x, y, z);
@@ -375,7 +355,7 @@ void *Output(void *argument)
 		      y0 = grid_center_lat[0]-dx/2;
 		      z0 = fmin;
 		      fprintf(fp, ">\n");
-		      for ( i = 0; i < nlat; ++i )
+		      for ( int i = 0; i < nlat; ++i )
 			{
 			  x = x0;  y = y0; z = z0;
 			  fprintf(fp, "%g %g %g\n", x, y, z);
@@ -395,10 +375,9 @@ void *Output(void *argument)
 		}
 	      else if ( operatorID == OUTPUTARR )
 		{
-		  for ( i = 0; i < gridsize; i++ )
+		  for ( int i = 0; i < gridsize; i++ )
 		    {
 		      fprintf(stdout, "  arr[%d] = %12.6g;\n", i, array[i]);
-		      nout++;
 		    }
 		}
 	      else
@@ -408,7 +387,7 @@ void *Output(void *argument)
 		  maxval = array[0];
 		  if ( gridInqType(gridID) == GRID_SPECTRAL && gridsize <= 156 )
 		    {
-		      for ( i = 1; i < gridsize; i++ )
+		      for ( int i = 1; i < gridsize; i++ )
 			{
 			  if ( array[i] < minval ) minval = array[i];
 			  if ( array[i] > maxval ) maxval = array[i];
@@ -418,9 +397,9 @@ void *Output(void *argument)
 		  if ( gridInqType(gridID) == GRID_SPECTRAL && gridsize <= 156 /* T11 */ &&
 		       minval >= -1 && maxval <= 12 )
 		    {
-		      long m, n, ntr;
+		      long m, n;
 		      double *spc = array;
-		      ntr = gridInqTrunc(gridID);
+		      long ntr = gridInqTrunc(gridID);
 		      for ( m = 0; m <= ntr; m++ )
 			{
 			  for ( n = m; n <= ntr; n++ )
@@ -433,8 +412,8 @@ void *Output(void *argument)
 		    }
 		  else
 		    {
-		      nout = 0;
-		      for ( i = 0; i < gridsize; i++ )
+		      int nout = 0;
+		      for ( int i = 0; i < gridsize; i++ )
 			{
 			  if ( nout == 6 )
 			    {
diff --git a/src/Outputgmt.c b/src/Outputgmt.c
index 0735f58..6fd1802 100644
--- a/src/Outputgmt.c
+++ b/src/Outputgmt.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -45,7 +45,7 @@ int check_ncorner(int ncorner, const double *lon_bounds, const double *lat_bound
   int ncorner_new = ncorner;
   int k;
 
-  for ( k=ncorner-1; k>0; --k )
+  for ( k = ncorner-1; k > 0; --k )
     if ( IS_NOT_EQUAL(lon_bounds[k], lon_bounds[k-1]) ||
 	 IS_NOT_EQUAL(lat_bounds[k], lat_bounds[k-1]) ) break;
 
@@ -57,20 +57,17 @@ int check_ncorner(int ncorner, const double *lon_bounds, const double *lat_bound
 
 void make_cyclic(double *array1, double *array2, int nlon, int nlat)
 {
-  int i, j;
   int ij1, ij2;
 
-  for ( j = 0; j < nlat; ++j )
-    {
-      for ( i = 0; i < nlon; ++i )
-	{
-	  ij1 = j*nlon+i;
-	  ij2 = j*(nlon+1)+i;
-	  array2[ij2] = array1[ij1];
-	}
-    }
+  for ( int j = 0; j < nlat; ++j )
+    for ( int i = 0; i < nlon; ++i )
+      {
+        ij1 = j*nlon+i;
+        ij2 = j*(nlon+1)+i;
+        array2[ij2] = array1[ij1];
+      }
 
-  for ( j = 0; j < nlat; ++j )
+  for ( int j = 0; j < nlat; ++j )
     {
       ij2 = j*(nlon+1);
       array2[ij2+nlon] = array2[ij2];
@@ -203,25 +200,20 @@ void output_vrml(int nlon, int nlat, int ngp, double *restrict array, double mis
 
 void *Outputgmt(void *argument)
 {
-  int i, j;
-  int varID0, recID;
+  int varID0;
   int gridsize2 = 0;
   int nrecs;
   int levelID;
   int nmiss;
-  int lzon = FALSE, lmer = FALSE, lhov = FALSE;
-  int ncorner = 0, ic;
-  int status;
-  int lgrid_gen_bounds = FALSE, luse_grid_corner = FALSE;
   int ninc = 1;
+  bool lzon = false, lmer = false, lhov = false;
+  bool lgrid_gen_bounds = false, luse_grid_corner = false;
   char varname[CDI_MAX_NAME];
-  double level;
   double *array2 = NULL;
   double *uf = NULL, *vf = NULL, *alpha = NULL, *auv = NULL;
   double *grid_center_lat2 = NULL, *grid_center_lon2 = NULL;
   double *grid_corner_lat = NULL, *grid_corner_lon = NULL;
   int *grid_mask = NULL;
-  FILE *cpt_fp;
   CPT cpt;
   char units[CDI_MAX_NAME];
   char vdatestr[32], vtimestr[32];	  
@@ -248,17 +240,18 @@ void *Outputgmt(void *argument)
     }
 
   if ( operatorID == OUTPUTBOUNDS || operatorID == OUTPUTBOUNDSCPT )
-    luse_grid_corner = TRUE;
+    luse_grid_corner = true;
 
   if ( operatorID == OUTPUTCENTERCPT || operatorID == OUTPUTBOUNDSCPT || operatorID == OUTPUTVRML )
     {
        operatorCheckArgc(1);
        char *cpt_file = operatorArgv()[0];
 
-      if ( (cpt_fp = fopen (cpt_file, "r")) == NULL )
+       FILE *cpt_fp = fopen(cpt_file, "r");
+       if ( cpt_fp == NULL )
 	cdoAbort("Open failed on color palette table %s", cpt_file);
 
-      status = cptRead(cpt_fp, &cpt);
+      int status = cptRead(cpt_fp, &cpt);
       if ( status != 0 )
 	cdoAbort("Error during read of color palette table %s", cpt_file);
       
@@ -282,7 +275,7 @@ void *Outputgmt(void *argument)
   if ( gridInqType(gridID) != GRID_UNSTRUCTURED && gridInqType(gridID) != GRID_CURVILINEAR )
     {
       gridID = gridToCurvilinear(gridID, 1);
-      lgrid_gen_bounds = TRUE;
+      lgrid_gen_bounds = true;
     }
 
   int gridsize = gridInqSize(gridID);
@@ -298,9 +291,9 @@ void *Outputgmt(void *argument)
 
   if ( gridInqType(gridID) != GRID_UNSTRUCTURED )
     {
-      if ( nlon == 1 && nlat  > 1 && nlev == 1 ) lhov = TRUE;
-      if ( nlon == 1 && nlat  > 1 && nlev  > 1 ) lzon = TRUE;
-      if ( nlon  > 1 && nlat == 1 && nlev  > 1 ) lmer = TRUE;
+      if ( nlon == 1 && nlat  > 1 && nlev == 1 ) lhov = true;
+      if ( nlon == 1 && nlat  > 1 && nlev  > 1 ) lzon = true;
+      if ( nlon  > 1 && nlat == 1 && nlev  > 1 ) lmer = true;
     }
   else
     {
@@ -323,12 +316,9 @@ void *Outputgmt(void *argument)
 	cdoAbort("Bounds not available hovmoeller data!");
     }
 
-  if ( gridInqType(gridID) == GRID_UNSTRUCTURED )
-    ncorner = gridInqNvertex(gridID);
-  else
-    ncorner = 4;
+  int ncorner = (gridInqType(gridID) == GRID_UNSTRUCTURED) ? gridInqNvertex(gridID) : 4;
 
-  int grid_is_circular = gridIsCircular(gridID);
+  bool grid_is_circular = gridIsCircular(gridID);
 
   double *grid_center_lat = (double*) Malloc(gridsize*sizeof(double));
   double *grid_center_lon = (double*) Malloc(gridsize*sizeof(double));
@@ -348,8 +338,6 @@ void *Outputgmt(void *argument)
 
   if ( operatorID == OUTPUTCENTER2 && grid_is_circular )
     {
-      int ij2;
-
       gridsize2 = nlat*(nlon+1);
 
       grid_center_lat2 = (double*) Malloc(gridsize2*sizeof(double));
@@ -358,9 +346,9 @@ void *Outputgmt(void *argument)
       make_cyclic(grid_center_lat, grid_center_lat2, nlon, nlat);
       make_cyclic(grid_center_lon, grid_center_lon2, nlon, nlat);
 
-      for ( j = 0; j < nlat; ++j )
+      for ( int j = 0; j < nlat; ++j )
 	{
-	  ij2 = j*(nlon+1);
+	  int ij2 = j*(nlon+1);
 	  grid_center_lon2[ij2+nlon] += 360;
 	}
 
@@ -373,7 +361,7 @@ void *Outputgmt(void *argument)
   double *zaxis_lower_lev  = (double*) Malloc(nlev*sizeof(double));
   double *zaxis_upper_lev  = (double*) Malloc(nlev*sizeof(double));
 
-  zaxisInqLevels(zaxisID, zaxis_center_lev);
+  cdoZaxisInqLevels(zaxisID, zaxis_center_lev);
 
   if ( luse_grid_corner )
     {
@@ -415,15 +403,15 @@ void *Outputgmt(void *argument)
       else
 	{
 	  zaxis_lower_lev[0] = zaxis_center_lev[0];
-	  for ( i = 1; i < nlev; ++i )
+	  for ( int i = 1; i < nlev; ++i )
 	    zaxis_lower_lev[i] = 0.5*(zaxis_center_lev[i] + zaxis_center_lev[i-1]);
 
 	  zaxis_upper_lev[nlev-1] = zaxis_center_lev[nlev-1];
-	  for ( i = 0; i < nlev-1; ++i )
+	  for ( int i = 0; i < nlev-1; ++i )
 	    zaxis_upper_lev[i] = zaxis_lower_lev[i+1];
 
 	  if ( cdoVerbose )
-	    for ( i = 0; i < nlev; ++i )
+	    for ( int i = 0; i < nlev; ++i )
 	      fprintf(stderr, "level: %d %g %g %g\n",
 		     i+1, zaxis_lower_lev[i], zaxis_center_lev[i], zaxis_upper_lev[i]);
 	}
@@ -481,7 +469,7 @@ void *Outputgmt(void *argument)
 
       varID0 = varID;
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID, &varID, &levelID);
 
@@ -493,7 +481,7 @@ void *Outputgmt(void *argument)
 	  if ( operatorID == OUTPUTCENTER2 && grid_is_circular )
 	    make_cyclic(array, array2, nlon, nlat);
 
-	  level = zaxis_center_lev[levelID];
+	  double level = zaxis_center_lev[levelID];
 
 	  if ( (tsID == 0 || lzon || lmer) && operatorID != OUTPUTTRI )
 	    fprintf(stdout, "# Level = %g\n", level);
@@ -514,10 +502,9 @@ void *Outputgmt(void *argument)
                   fprintf(stderr, "pscoast -O -J -R -Dc -W -B40g20 >> gmtplot.ps\n");
                 }
 
-	      for ( i = 0; i < nvals; i++ )
+	      for ( int i = 0; i < nvals; i++ )
 		{
-		  if ( grid_mask )
-		    if ( grid_mask[i] == 0 ) continue;
+		  if ( grid_mask && grid_mask[i] == 0 ) continue;
 
 		  if ( operatorID == OUTPUTCENTER )
 		    {
@@ -549,27 +536,25 @@ void *Outputgmt(void *argument)
 	  else if ( operatorID == OUTPUTTRI )
 	    {
 	      int c1, c2, c3;
-	      int mlon, ip1;
+	      int ip1;
 	      if ( gridInqType(gridID) != GRID_CURVILINEAR ) cdoAbort("Unsupported grid!");
 
-	      mlon = nlon-1;
+	      int mlon = nlon-1;
 	      /* if ( gridIsCircular(gridID) ) mlon = nlon; */
-	      for ( j = 0; j < nlat-1; ++j )
-		{
-		  for ( i = 0; i < mlon; ++i )
-		    {
-		      ip1 = i+1;
-		      if ( i == nlon-1 ) ip1 = 0;
-		      c1 = (j)*nlon+ip1;
-		      c2 = (j)*nlon+i;
-		      c3 = (j+1)*nlon+i;
-		      fprintf(stdout, "%d   %d   %d\n", c1, c2, c3);
-		      c1 = (j)*nlon+i+1;
-		      c2 = (j+1)*nlon+i;
-		      c3 = (j+1)*nlon+ip1;
-		      fprintf(stdout, "%d   %d   %d\n", c1, c2, c3);
-		    }
-		}
+	      for ( int j = 0; j < nlat-1; ++j )
+                for ( int i = 0; i < mlon; ++i )
+                  {
+                    ip1 = i+1;
+                    if ( i == nlon-1 ) ip1 = 0;
+                    c1 = (j)*nlon+ip1;
+                    c2 = (j)*nlon+i;
+                    c3 = (j+1)*nlon+i;
+                    fprintf(stdout, "%d   %d   %d\n", c1, c2, c3);
+                    c1 = (j)*nlon+i+1;
+                    c2 = (j+1)*nlon+i;
+                    c3 = (j+1)*nlon+ip1;
+                    fprintf(stdout, "%d   %d   %d\n", c1, c2, c3);
+                  }
 	    }
 	  else if ( operatorID == OUTPUTVECTOR )
 	    {
@@ -579,8 +564,8 @@ void *Outputgmt(void *argument)
 	      streamInqRecord(streamID, &varID, &levelID);
 	      streamReadRecord(streamID, vf, &nmiss);
 
-	      for ( j = 0; j < nlat; j += ninc )
-		for ( i = 0; i < nlon; i += ninc )
+	      for ( int j = 0; j < nlat; j += ninc )
+		for ( int i = 0; i < nlon; i += ninc )
 		  {
 		    /* compute length of velocity vector */
 		    auv[IX2D(j,i,nlon)] = sqrt(uf[IX2D(j,i,nlon)]*uf[IX2D(j,i,nlon)] + 
@@ -620,7 +605,7 @@ void *Outputgmt(void *argument)
                   fprintf(stderr, "ps2pdf gmtplot.ps\n");
                 }
 
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( int i = 0; i < gridsize; i++ )
 		{
 		  if ( grid_mask && grid_mask[i] == 0 ) continue;
 
@@ -664,7 +649,7 @@ void *Outputgmt(void *argument)
 		      double levmax = zaxis_upper_lev[levelID];
 		      double latmin = grid_corner_lat[i*4];
 		      double latmax = grid_corner_lat[i*4];
-		      for ( ic = 1; ic < 4; ic++ )
+		      for ( int ic = 1; ic < 4; ic++ )
 			{
 			  if ( grid_corner_lat[i*4+ic] < latmin ) latmin = grid_corner_lat[i*4+ic];
 			  if ( grid_corner_lat[i*4+ic] > latmax ) latmax = grid_corner_lat[i*4+ic];
@@ -677,7 +662,7 @@ void *Outputgmt(void *argument)
 		      xlat[1] = latmin;
 		      xlat[2] = latmax;
 		      xlat[3] = latmax;
-		      for ( ic = 0; ic < 4; ic++ )
+		      for ( int ic = 0; ic < 4; ic++ )
 			fprintf(stdout, "   %g  %g\n", xlat[ic], xlev[ic]);
 		      fprintf(stdout, "   %g  %g\n", xlat[0], xlev[0]);
 		    }
@@ -688,7 +673,7 @@ void *Outputgmt(void *argument)
 		      double levmax = zaxis_upper_lev[levelID];
 		      double lonmin = grid_corner_lon[i*4];
 		      double lonmax = grid_corner_lon[i*4];
-		      for ( ic = 1; ic < 4; ic++ )
+		      for ( int ic = 1; ic < 4; ic++ )
 			{
 			  if ( grid_corner_lon[i*4+ic] < lonmin ) lonmin = grid_corner_lon[i*4+ic];
 			  if ( grid_corner_lon[i*4+ic] > lonmax ) lonmax = grid_corner_lon[i*4+ic];
@@ -701,7 +686,7 @@ void *Outputgmt(void *argument)
 		      xlon[1] = lonmax;
 		      xlon[2] = lonmax;
 		      xlon[3] = lonmin;
-		      for ( ic = 0; ic < 4; ic++ )
+		      for ( int ic = 0; ic < 4; ic++ )
 			fprintf(stdout, "   %g  %g\n", xlon[ic], xlev[ic]);
 		      fprintf(stdout, "   %g  %g\n", xlon[0], xlev[0]);
 		    }
@@ -715,7 +700,7 @@ void *Outputgmt(void *argument)
 		      const double *lat_bounds = grid_corner_lat+i*ncorner;
 		      int ncorner_new = check_ncorner(ncorner, lon_bounds, lat_bounds);
 
-		      for ( ic = 0; ic < ncorner_new; ic++ )
+		      for ( int ic = 0; ic < ncorner_new; ic++ )
 			fprintf(stdout, "   %g  %g\n", lon_bounds[ic], lat_bounds[ic]);
 		      fprintf(stdout, "   %g  %g\n", lon_bounds[0], lat_bounds[0]);
 		    }
diff --git a/src/Pack.c b/src/Pack.c
index 8b0f44a..a807128 100644
--- a/src/Pack.c
+++ b/src/Pack.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -43,12 +43,12 @@ int get_type_values(int datatype, double *tmin, double *tmax)
 
   switch (datatype)
     {
-    case DATATYPE_INT8:    *tmin = -SCHAR_MAX+1; *tmax = SCHAR_MAX;   break;
-    case DATATYPE_UINT8:   *tmin = 0;            *tmax = UCHAR_MAX-1; break;
-    case DATATYPE_INT16:   *tmin = -SHRT_MAX+1;  *tmax = SHRT_MAX;    break;
-    case DATATYPE_UINT16:  *tmin = 0;            *tmax = USHRT_MAX-1; break;
-    case DATATYPE_INT32:   *tmin = -INT_MAX+1;   *tmax = INT_MAX;     break;
-    case DATATYPE_UINT32:  *tmin = 0;            *tmax = UINT_MAX-1;  break;
+    case CDI_DATATYPE_INT8:    *tmin = -SCHAR_MAX+1; *tmax = SCHAR_MAX;   break;
+    case CDI_DATATYPE_UINT8:   *tmin = 0;            *tmax = UCHAR_MAX-1; break;
+    case CDI_DATATYPE_INT16:   *tmin = -SHRT_MAX+1;  *tmax = SHRT_MAX;    break;
+    case CDI_DATATYPE_UINT16:  *tmin = 0;            *tmax = USHRT_MAX-1; break;
+    case CDI_DATATYPE_INT32:   *tmin = -INT_MAX+1;   *tmax = INT_MAX;     break;
+    case CDI_DATATYPE_UINT32:  *tmin = 0;            *tmax = UINT_MAX-1;  break;
     default: status = 1; break;
     }
 
@@ -64,7 +64,7 @@ int compute_scale(int datatype, double fmin, double fmax, double *scale_factor,
   *scale_factor = sf;
   *add_offset = ao;
 
-  if ( get_type_values(datatype, &tmin, &tmax) ) return (1);
+  if ( get_type_values(datatype, &tmin, &tmax) ) return 1;
 
   if ( IS_NOT_EQUAL(fmin, fmax) )
     {
@@ -83,16 +83,14 @@ void *Pack(void *argument)
 {
   int gridsize;
   int nrecs;
-  int gridID, varID, levelID, recID;
-  int i;
-  int nts;
+  int gridID, varID, levelID;
   int nalloc = 0;
   int nmiss;
   int nlevel;
-  int datatype = DATATYPE_INT16;
+  int datatype = CDI_DATATYPE_INT16;
   dtlist_type *dtlist = dtlist_new();
   double missval1, missval2;
-  field_t ***vars = NULL;
+  field_type ***vars = NULL;
 
   cdoInitialize(argument);
 
@@ -113,14 +111,14 @@ void *Pack(void *argument)
       if ( tsID >= nalloc )
 	{
 	  nalloc += NALLOC_INC;
-	  vars   = (field_t ***) Realloc(vars, nalloc*sizeof(field_t **));
+	  vars   = (field_type ***) Realloc(vars, nalloc*sizeof(field_type **));
 	}
 
       dtlist_taxisInqTimestep(dtlist, taxisID1, tsID);
 
       vars[tsID] = field_malloc(vlistID1, FIELD_NONE);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  gridID   = vlistInqVarGrid(vlistID1, varID);
@@ -133,11 +131,11 @@ void *Pack(void *argument)
       tsID++;
     }
 
-  nts = tsID;
+  int nts = tsID;
 
   if ( cdoDefaultDataType != CDI_UNDEFID )
     {
-      if ( cdoDefaultDataType == DATATYPE_FLT64 || cdoDefaultDataType == DATATYPE_FLT32 )
+      if ( cdoDefaultDataType == CDI_DATATYPE_FLT64 || cdoDefaultDataType == CDI_DATATYPE_FLT32 )
 	{
 	  cdoWarning("Changed default output datatype to int16");
 	  cdoDefaultDataType = datatype;
@@ -173,7 +171,7 @@ void *Pack(void *argument)
 	      if ( nmiss > 0 )
 		{
 		  nmisspv += nmiss;
-		  for ( i = 0; i < gridsize; ++i )
+		  for ( int i = 0; i < gridsize; ++i )
 		    {
 		      if ( !DBL_IS_EQUAL(array[i], missval1) )
 			{
@@ -185,7 +183,7 @@ void *Pack(void *argument)
 		}
 	      else
 		{
-		  for ( i = 0; i < gridsize; ++i )
+		  for ( int i = 0; i < gridsize; ++i )
 		    {
 		      if ( array[i] < fmin ) fmin = array[i];
 		      if ( array[i] > fmax ) fmax = array[i];
@@ -213,7 +211,7 @@ void *Pack(void *argument)
 		      double *array =  vars[tsID][varID][levelID].ptr;
 		      nmiss = vars[tsID][varID][levelID].nmiss;
 		      if ( nmiss > 0 )
-			for ( i = 0; i < gridsize; ++i )
+			for ( int i = 0; i < gridsize; ++i )
 			  if ( DBL_IS_EQUAL(array[i], missval1) ) array[i] = missval2;
 		    }
 		}	  
diff --git a/src/Pardup.c b/src/Pardup.c
index 0fa1cfc..35541d2 100644
--- a/src/Pardup.c
+++ b/src/Pardup.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -31,8 +31,7 @@
 void *Pardup(void *argument)
 {
   int nrecs;
-  int recID, varID, varID2, levelID;
-  int i;
+  int varID, varID2, levelID;
   long offset;
   int nmul = 0;
   int nmiss;
@@ -86,7 +85,7 @@ void *Pardup(void *argument)
       varnmiss[varID] = (int*) Malloc(nlevel*sizeof(int));
     }
 
-  for ( i = 1; i < nmul; i++ )
+  for ( int i = 1; i < nmul; i++ )
     {
       vlistCat(vlistID2, vlistID1);
       for ( varID = 0; varID < nvars; varID++ )
@@ -104,7 +103,7 @@ void *Pardup(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -119,8 +118,8 @@ void *Pardup(void *argument)
 	  varnmiss[varID][levelID] = nmiss;
 	}
 
-      for ( i = 0; i < nmul; i++ )
-	for ( recID = 0; recID < nrecs; recID++ )
+      for ( int i = 0; i < nmul; i++ )
+	for ( int recID = 0; recID < nrecs; recID++ )
 	  {
 	    varID    = recVarID[recID];
 	    varID2   = varID + i*nvars;
diff --git a/src/Pinfo.c b/src/Pinfo.c
index 4adfd5b..efa5389 100644
--- a/src/Pinfo.c
+++ b/src/Pinfo.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -29,62 +29,50 @@
 
 void *Pinfo(void *argument)
 {
-  int PINFO, PINFOV;
-  int operatorID;
   int i;
-  int indg;
-  int varID, recID;
-  int gridsize = 0;
-  int gridID, zaxisID, code;
+  int varID;
   int nrecs;
   int levelID;
-  int tsID;
-  int taxisID1, taxisID2;
-  int streamID1, streamID2;
-  int vlistID1, vlistID2;
   int nmiss;
   int ivals = 0, imiss = 0;
-  int vdate, vtime;
   char varname[CDI_MAX_NAME];
   char vdatestr[32], vtimestr[32];	  
-  double missval;
-  double *array1 = NULL, *array2 = NULL;
   double level;
   double arrmin, arrmax, arrmean, arrvar;
 
   cdoInitialize(argument);
 
-  PINFO  = cdoOperatorAdd("pinfo",  0, 0, NULL);
-  PINFOV = cdoOperatorAdd("pinfov", 0, 0, NULL);
+  int PINFO  = cdoOperatorAdd("pinfo",  0, 0, NULL);
+  int PINFOV = cdoOperatorAdd("pinfov", 0, 0, NULL);
 
   UNUSED(PINFO);
 
-  operatorID = cdoOperatorID();
+  int operatorID = cdoOperatorID();
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
 
-  array1 = (double*) Malloc(gridsize*sizeof(double));
-  array2 = (double*) Malloc(gridsize*sizeof(double));
+  double *array1 = (double*) Malloc(gridsize*sizeof(double));
+  double *array2 = (double*) Malloc(gridsize*sizeof(double));
 
-  indg = 0;
-  tsID = 0;
+  int indg = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
-      vdate = taxisInqVdate(taxisID1);
-      vtime = taxisInqVtime(taxisID1);
+      int vdate = taxisInqVdate(taxisID1);
+      int vtime = taxisInqVtime(taxisID1);
 
       taxisCopyTimestep(taxisID2, taxisID1);
 
@@ -93,7 +81,7 @@ void *Pinfo(void *argument)
       date2str(vdate, vdatestr, sizeof(vdatestr));
       time2str(vtime, vtimestr, sizeof(vtimestr));
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  if ( tsID == 0 && recID == 0 )
 	    {
@@ -109,11 +97,11 @@ void *Pinfo(void *argument)
 	  streamReadRecord(streamID1, array1, &nmiss);
 
 	  indg += 1;
-	  code     = vlistInqVarCode(vlistID1, varID);
-	  gridID   = vlistInqVarGrid(vlistID1, varID);
-	  zaxisID  = vlistInqVarZaxis(vlistID1, varID);
-	  missval  = vlistInqVarMissval(vlistID1, varID);
-	  gridsize = gridInqSize(gridID);
+	  int code     = vlistInqVarCode(vlistID1, varID);
+	  int gridID   = vlistInqVarGrid(vlistID1, varID);
+	  int zaxisID  = vlistInqVarZaxis(vlistID1, varID);
+	  int gridsize = gridInqSize(gridID);
+	  double missval = vlistInqVarMissval(vlistID1, varID);
 
 	  if ( operatorID == PINFOV ) vlistInqVarName(vlistID1, varID, varname);
 
@@ -122,7 +110,7 @@ void *Pinfo(void *argument)
 	  else
 	    fprintf(stdout, "%6d :%s %s %3d", indg, vdatestr, vtimestr, code);
 
-	  level = zaxisInqLevel(zaxisID, levelID);
+	  level = cdoZaxisInqLevel(zaxisID, levelID);
 	  fprintf(stdout, " %7g ", level);
 
 	  fprintf(stdout, "%7d %7d :", gridsize, nmiss);
diff --git a/src/Pressure.c b/src/Pressure.c
index 9579aa5..39a6193 100644
--- a/src/Pressure.c
+++ b/src/Pressure.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -23,14 +23,13 @@
       Pressure    deltap               Difference of two half hybrid levels
 */
 
-#include <ctype.h>
 
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
 #include "pstream.h"
 #include "after_vertint.h"
-#include "list.h"
+#include "listarray.h"
 #include "stdnametable.h"
 
 
@@ -39,26 +38,19 @@ void *Pressure(void *argument)
   int mode;
   enum {ECHAM_MODE, WMO_MODE};
   int ps_code = 0, lsp_code = 0;
-  int streamID2;
-  int vlistID2;
-  int recID, nrecs;
+  int nrecs;
   int i, k, offset;
-  int tsID, varID, levelID;
+  int varID, levelID;
   int zaxisIDp, zaxisIDh = -1;
-  int gridID, zaxisID;
   int nhlevf = 0, nhlevh = 0, nlevel = 0;
   int nvct = 0;
-  int psID = -1, lnpsID = -1, pvarID = -1;
-  int code, param;
+  int nmiss;
+  int psID = -1, lnpsID = -1;
   char paramstr[32];
   char varname[CDI_MAX_NAME];
   double minval, maxval;
   double *ps_prog = NULL, *full_press = NULL, *half_press = NULL, *deltap = NULL;
   double *pout = NULL;
-  double *pdata = NULL;
-  int taxisID1, taxisID2;
-  int nmiss;
-  int instNum, tableNum;
 
   cdoInitialize(argument);
 
@@ -104,8 +96,7 @@ void *Pressure(void *argument)
   bool useTable = false;
   for ( varID = 0; varID < nvars; varID++ )
     {
-      tableNum = tableInqNum(vlistInqVarTable(vlistID1, varID));
-
+      int tableNum = tableInqNum(vlistInqVarTable(vlistID1, varID));
       if ( tableNum > 0 && tableNum != 255 )
 	{
 	  useTable = true;
@@ -117,14 +108,13 @@ void *Pressure(void *argument)
 
   for ( varID = 0; varID < nvars; varID++ )
     {
-      gridID   = vlistInqVarGrid(vlistID1, varID);
-      zaxisID  = vlistInqVarZaxis(vlistID1, varID);
-      nlevel   = zaxisInqSize(zaxisID);
-      instNum  = institutInqCenter(vlistInqVarInstitut(vlistID1, varID));
-      tableNum = tableInqNum(vlistInqVarTable(vlistID1, varID));
+      int zaxisID  = vlistInqVarZaxis(vlistID1, varID);
+      int nlevel   = zaxisInqSize(zaxisID);
+      int instNum  = institutInqCenter(vlistInqVarInstitut(vlistID1, varID));
+      int tableNum = tableInqNum(vlistInqVarTable(vlistID1, varID));
 
-      code     = vlistInqVarCode(vlistID1, varID);
-      param    = vlistInqVarParam(vlistID1, varID);
+      int code     = vlistInqVarCode(vlistID1, varID);
+      int param    = vlistInqVarParam(vlistID1, varID);
 
       cdiParamToString(param, paramstr, sizeof(paramstr));
 
@@ -181,10 +171,10 @@ void *Pressure(void *argument)
 	}
     }
 
-  pvarID = lnpsID;
+  int pvarID = lnpsID;
   if ( zaxisIDh != -1 && lnpsID != -1 )
     {
-      gridID = vlistInqVarGrid(vlistID1, lnpsID);
+      int gridID = vlistInqVarGrid(vlistID1, lnpsID);
       if ( gridInqType(gridID) == GRID_SPECTRAL )
 	{
 	  lnpsID = -1;
@@ -199,37 +189,35 @@ void *Pressure(void *argument)
 	cdoAbort("%s not found!", var_stdname(surface_air_pressure));
     }
 
-  gridID = vlistInqVarGrid(vlistID1, pvarID);
+  int gridID = vlistInqVarGrid(vlistID1, pvarID);
   if ( gridInqType(gridID) == GRID_SPECTRAL )
     cdoAbort("%s on spectral representation not supported!", var_stdname(surface_air_pressure));
 
-  pdata = (double*) Malloc(gridsize*sizeof(double));
+  double *pdata = (double*) Malloc(gridsize*sizeof(double));
 
-
-  vlistID2 = vlistCreate();
+  int vlistID2 = vlistCreate();
   varID = vlistDefVar(vlistID2, gridID, zaxisIDp, TSTEP_INSTANT);
   vlistDefVarParam(vlistID2, varID, cdiEncodeParam(1, 255, 255));
   vlistDefVarName(vlistID2, varID, "pressure");
   vlistDefVarStdname(vlistID2, varID, "air_pressure");
   vlistDefVarUnits(vlistID2, varID, "Pa");
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
 
       streamDefTimestep(streamID2, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
diff --git a/src/Regres.c b/src/Regres.c
index fa557cf..55219fd 100644
--- a/src/Regres.c
+++ b/src/Regres.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -31,59 +31,52 @@
 /* Same code as Trend ! */
 void *Regres(void *argument)
 {
-  int gridsize;
-  int vdate = 0, vtime = 0;
-  int nrecs, nrecords;
-  int gridID, varID, levelID, recID;
-  int tsID;
-  int i, w;
-  int streamID1,/* streamID2, */streamID3;
-  int vlistID1, vlistID2, taxisID1, taxisID2;
+  int nrecs;
+  int varID, levelID;
   int nmiss;
-  int *recVarID, *recLevelID;
-  int nwork = 5;
   double temp1, temp2;
-  double missval, missval1, missval2;
-  field_t **work[5];
-  field_t field1, field2;
+  enum {nwork = 5};
+  field_type **work[nwork];
 
   cdoInitialize(argument);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
   vlistDefNtsteps(vlistID2, 1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
   /*
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
   */
-  streamID3 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID3 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID3, vlistID2);
 
-  nrecords = vlistNrecs(vlistID1);
+  int nrecords = vlistNrecs(vlistID1);
 
-  recVarID   = (int*) Malloc(nrecords*sizeof(int));
-  recLevelID = (int*) Malloc(nrecords*sizeof(int));
+  int *recVarID   = (int*) Malloc(nrecords*sizeof(int));
+  int *recLevelID = (int*) Malloc(nrecords*sizeof(int));
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
 
+  field_type field1, field2;
   field_init(&field1);
   field_init(&field2);
   field1.ptr = (double*) Malloc(gridsize*sizeof(double));
   field2.ptr = (double*) Malloc(gridsize*sizeof(double));
 
-  for ( w = 0; w < nwork; w++ )
+  for ( int w = 0; w < nwork; w++ )
     work[w] = field_calloc(vlistID1, FIELD_PTR);
 
-  tsID    = 0;
+  int vdate = 0, vtime = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       vdate = taxisInqVdate(taxisID1);
@@ -91,7 +84,7 @@ void *Regres(void *argument)
 
       tsID++; /* don't move this line !!! */
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -103,11 +96,11 @@ void *Regres(void *argument)
 
 	  streamReadRecord(streamID1, field1.ptr, &nmiss);
 
-	  missval  = vlistInqVarMissval(vlistID1, varID);
-	  gridID   = vlistInqVarGrid(vlistID1, varID);
-	  gridsize = gridInqSize(gridID);
+	  double missval = vlistInqVarMissval(vlistID1, varID);
+	  int gridID   = vlistInqVarGrid(vlistID1, varID);
+	  int gridsize = gridInqSize(gridID);
 
-	  for ( i = 0; i < gridsize; i++ )
+	  for ( int i = 0; i < gridsize; i++ )
 	    if ( !DBL_IS_EQUAL(field1.ptr[i], missval) )
 	      {
 		work[0][varID][levelID].ptr[i] += tsID;
@@ -125,19 +118,19 @@ void *Regres(void *argument)
   /* streamDefTimestep(streamID2, 0); */
   streamDefTimestep(streamID3, 0);
 
-  for ( recID = 0; recID < nrecords; recID++ )
+  for ( int recID = 0; recID < nrecords; recID++ )
     {
       varID   = recVarID[recID];
       levelID = recLevelID[recID];
 
-      missval  = vlistInqVarMissval(vlistID1, varID);
-      gridID   = vlistInqVarGrid(vlistID1, varID);
-      gridsize = gridInqSize(gridID);
+      double missval = vlistInqVarMissval(vlistID1, varID);
+      int gridID   = vlistInqVarGrid(vlistID1, varID);
+      int gridsize = gridInqSize(gridID);
 
-      missval1  = missval;
-      missval2  = missval;
+      double missval1  = missval;
+      double missval2  = missval;
 
-      for ( i = 0; i < gridsize; i++ )
+      for ( int i = 0; i < gridsize; i++ )
 	{
 	  temp1 = SUBMN(work[2][varID][levelID].ptr[i],
 		      DIVMN( MULMN(work[0][varID][levelID].ptr[i], work[3][varID][levelID].ptr[i]), work[4][varID][levelID].ptr[i]));
@@ -158,7 +151,7 @@ void *Regres(void *argument)
       streamWriteRecord(streamID2, field1.ptr, nmiss);
       */
       nmiss = 0;
-      for ( i = 0; i < gridsize; i++ )
+      for ( int i = 0; i < gridsize; i++ )
 	if ( DBL_IS_EQUAL(field2.ptr[i], missval) ) nmiss++;
 
       streamDefRecord(streamID3, varID, levelID);
@@ -166,7 +159,7 @@ void *Regres(void *argument)
     }
 
 
-  for ( w = 0; w < nwork; w++ ) field_free(work[w], vlistID1);
+  for ( int w = 0; w < nwork; w++ ) field_free(work[w], vlistID1);
 
   if ( field1.ptr ) Free(field1.ptr);
   if ( field2.ptr ) Free(field2.ptr);
diff --git a/src/Remap.c b/src/Remap.c
index 4fe0388..edf1aa3 100644
--- a/src/Remap.c
+++ b/src/Remap.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -186,22 +186,22 @@ void print_remap_info(int operfunc, int remap_genweights, remapgrid_t *src_grid,
 
   strcat(line, gridNamePtr(gridInqType(src_grid->gridID)));
   if ( src_grid->rank == 2 )
-    sprintf(tmpstr, " (%dx%d)", src_grid->dims[0], src_grid->dims[1]);
+    snprintf(tmpstr, sizeof(tmpstr), " (%dx%d)", src_grid->dims[0], src_grid->dims[1]);
   else
-    sprintf(tmpstr, " (%d)", src_grid->dims[0]);
+    snprintf(tmpstr, sizeof(tmpstr), " (%d)", src_grid->dims[0]);
   strcat(line, tmpstr);
   strcat(line, " to ");
   strcat(line, gridNamePtr(gridInqType(tgt_grid->gridID)));
   if ( tgt_grid->rank == 2 )
-    sprintf(tmpstr, " (%dx%d)", tgt_grid->dims[0], tgt_grid->dims[1]);
+    snprintf(tmpstr, sizeof(tmpstr), " (%dx%d)", tgt_grid->dims[0], tgt_grid->dims[1]);
   else
-    sprintf(tmpstr, " (%d)", tgt_grid->dims[0]);
+    snprintf(tmpstr, sizeof(tmpstr), " (%d)", tgt_grid->dims[0]);
   strcat(line, tmpstr);
   strcat(line, " grid");
 
   if ( nmiss > 0 )
     {
-      sprintf(tmpstr, ", with source mask (%d)", gridInqSize(src_grid->gridID)-nmiss);
+      snprintf(tmpstr, sizeof(tmpstr), ", with source mask (%d)", gridInqSize(src_grid->gridID)-nmiss);
       strcat(line, tmpstr);
     }
 
@@ -215,6 +215,7 @@ void print_remap_warning(const char *remap_file, int operfunc, remapgrid_t *src_
   char tmpstr[256];
 
   line[0] = 0;
+  (void)operfunc;
   /*
   if      ( operfunc == REMAPBIL  || operfunc == GENBIL  )  strcpy(line, "SCRIP bilinear");
   else if ( operfunc == REMAPBIC  || operfunc == GENBIC  )  strcpy(line, "SCRIP bicubic");
@@ -233,15 +234,15 @@ void print_remap_warning(const char *remap_file, int operfunc, remapgrid_t *src_
   strcat(line, " not used, ");
   strcat(line, gridNamePtr(gridInqType(src_grid->gridID)));
   if ( src_grid->rank == 2 )
-    sprintf(tmpstr, " (%dx%d)", src_grid->dims[0], src_grid->dims[1]);
+    snprintf(tmpstr, sizeof(tmpstr), " (%dx%d)", src_grid->dims[0], src_grid->dims[1]);
   else
-    sprintf(tmpstr, " (%d)", src_grid->dims[0]);
+    snprintf(tmpstr, sizeof(tmpstr), " (%d)", src_grid->dims[0]);
   strcat(line, tmpstr);
   strcat(line, " grid");
 
   if ( nmiss > 0 )
     {
-      sprintf(tmpstr, " with mask (%d)", gridInqSize(src_grid->gridID)-nmiss);
+      snprintf(tmpstr, sizeof(tmpstr), " with mask (%d)", gridInqSize(src_grid->gridID)-nmiss);
       strcat(line, tmpstr);
     }
 
@@ -273,8 +274,7 @@ void get_remap_env(void)
   envstr = getenv("MAX_REMAPS");
   if ( envstr )
     {
-      int ival;
-      ival = atoi(envstr);
+      int ival = atoi(envstr);
       if ( ival > 0 )
 	{
 	  max_remaps = ival;
@@ -286,8 +286,7 @@ void get_remap_env(void)
   envstr = getenv("REMAP_MAX_ITER");
   if ( envstr )
     {
-      int ival;
-      ival = atoi(envstr);
+      int ival = atoi(envstr);
       if ( ival > 0 )
 	{
 	  remap_set_int(REMAP_MAX_ITER, ival);
@@ -299,8 +298,7 @@ void get_remap_env(void)
   envstr = getenv("REMAP_ORDER");
   if ( envstr )
     {
-      int ival;
-      ival = atoi(envstr);
+      int ival = atoi(envstr);
       if ( ival > 0 )
 	{
 	  remap_order = ival;
@@ -315,8 +313,7 @@ void get_remap_env(void)
   envstr = getenv("REMAP_TEST");
   if ( envstr )
     {
-      int ival;
-      ival = atoi(envstr);
+      int ival = atoi(envstr);
       if ( ival > 0 )
 	{
 	  remap_test = ival;
@@ -350,8 +347,7 @@ void get_remap_env(void)
   envstr = getenv("REMAP_THRESHHOLD");
   if ( envstr )
     {
-      double fval;
-      fval = atof(envstr);
+      double fval = atof(envstr);
       if ( fval > 0 )
 	{
 	  remap_threshhold = fval;
@@ -365,45 +361,28 @@ void get_remap_env(void)
   envstr = getenv("CDO_REMAP_RADIUS");
   if ( envstr )
     {
-      double fval;
-      fval = atof(envstr);
-      if ( fval < 0 || fval > 180 )
-	{
-	  cdoAbort("CDO_REMAP_RADIUS=%g out of bounds (0-180)", fval);
-	}
-      else
-	{
-	  gridsearch_radius = fval;
-	  if ( cdoVerbose )
-	    cdoPrint("Set CDO_REMAP_RADIUS to %g", gridsearch_radius);
-	}
+      double fval = radius_str_to_deg(envstr);
+      if ( fval < 0 || fval > 180 ) cdoAbort("%s=%g out of bounds (0-180 deg)!", "CDO_REMAP_RADIUS", fval);
+      gridsearch_radius = fval;
+      if ( cdoVerbose ) cdoPrint("Set CDO_REMAP_RADIUS to %g", gridsearch_radius);
     }
 
   envstr = getenv("CDO_GRIDSEARCH_RADIUS");
   if ( envstr )
     {
-      double fval;
-      fval = atof(envstr);
-      if ( fval < 0 || fval > 180 )
-	{
-	  cdoAbort("CDO_GRIDSEARCH_RADIUS=%g out of bounds (0-180)", fval);
-	}
-      else
-	{
-	  gridsearch_radius = fval;
-	  if ( cdoVerbose )
-	    cdoPrint("Set CDO_GRIDSEARCH_RADIUS to %g", gridsearch_radius);
-	}
+      double fval = radius_str_to_deg(envstr);
+      if ( fval < 0 || fval > 180 ) cdoAbort("%s=%g out of bounds (0-180 deg)!", "CDO_GRIDSEARCH_RADIUS", fval);
+      gridsearch_radius = fval;
+      if ( cdoVerbose ) cdoPrint("Set CDO_GRIDSEARCH_RADIUS to %g", gridsearch_radius);
     }
   
   if ( cdoVerbose )
-    cdoPrint("remap_radius = %g", gridsearch_radius);
+    cdoPrint("remap_radius = %g deg", gridsearch_radius);
 
   envstr = getenv("REMAP_AREA_MIN");
   if ( envstr )
     {
-      double fval;
-      fval = atof(envstr);
+      double fval = atof(envstr);
       if ( fval > 0 )
 	{
 	  remap_frac_min = fval;
@@ -415,8 +394,7 @@ void get_remap_env(void)
   envstr = getenv("REMAP_NUM_SRCH_BINS");
   if ( envstr )
     {
-      int ival;
-      ival = atoi(envstr);
+      int ival = atoi(envstr);
       if ( ival > 0 )
 	{
 	  remap_num_srch_bins = ival;
@@ -429,8 +407,7 @@ void get_remap_env(void)
   envstr = getenv("REMAP_NON_GLOBAL");
   if ( envstr )
     {
-      int ival;
-      ival = atoi(envstr);
+      int ival = atoi(envstr);
       if ( ival >= 0 )
 	{
 	  remap_non_global = ival;
@@ -444,8 +421,7 @@ void get_remap_env(void)
   envstr = getenv("REMAP_STORE_LINK_FAST");
   if ( envstr )
     {
-      int ival;
-      ival = atoi(envstr);
+      int ival = atoi(envstr);
       if ( ival >= 0 )
 	{
 	  remap_store_link_fast = ival;
@@ -529,13 +505,15 @@ bool is_global_grid(int gridID)
 {
   bool global_grid = true;
   bool non_global = remap_non_global || !gridIsCircular(gridID);
-  int gridtype = gridInqType(gridID);
 
-  if ( (gridtype == GRID_LONLAT && gridIsRotated(gridID)) ||
+  int gridtype = gridInqType(gridID);
+  int projtype = (gridtype == GRID_PROJECTION) ? gridInqProjType(gridID) : -1;
+  if ( (projtype == CDI_PROJ_RLL)  ||
+       (projtype == CDI_PROJ_LAEA) ||
+       (projtype == CDI_PROJ_SINU) ||
+       (projtype == CDI_PROJ_LCC)  ||
        (gridtype == GRID_LONLAT && non_global) ||
        (gridtype == GRID_LCC) ||
-       (gridtype == GRID_LAEA) ||
-       (gridtype == GRID_SINUSOIDAL) ||
        (gridtype == GRID_CURVILINEAR && non_global) ) global_grid = false;
 
   return global_grid;
@@ -544,20 +522,15 @@ bool is_global_grid(int gridID)
 static
 void scale_gridbox_area(long gridsize, const double *restrict array1, long gridsize2, double *restrict array2, const double *restrict grid2_area)
 {
-  static bool lgridboxinfo = true;
-  long i;
   double array1sum = 0;
-  double array2sum = 0;
+  for ( long i = 0; i < gridsize; i++ ) array1sum += array1[i];
 
-  for ( i = 0; i < gridsize; i++ )
-    array1sum += array1[i];
-
-  for ( i = 0; i < gridsize2; i++ )
-    array2sum += grid2_area[i];
+  double array2sum = 0;
+  for ( long i = 0; i < gridsize2; i++ ) array2sum += grid2_area[i];
 
-  for ( i = 0; i < gridsize2; i++ )
-    array2[i] = grid2_area[i]/array2sum*array1sum;
+  for ( long i = 0; i < gridsize2; i++ ) array2[i] = grid2_area[i]/array2sum*array1sum;
 
+  static bool lgridboxinfo = true;
   if ( lgridboxinfo )
     {
       cdoPrint("gridbox_area replaced and scaled to %g", array1sum);
@@ -566,36 +539,38 @@ void scale_gridbox_area(long gridsize, const double *restrict array1, long grids
 }
 
 static
-int set_remapgrids(int filetype, int vlistID, int ngrids, int *remapgrids)
+int set_remapgrids(int filetype, int vlistID, int ngrids, bool *remapgrids)
 {
-  int index, gridID, gridtype;
-
+  int index;
   for ( index = 0; index < ngrids; index++ )
     {
-      remapgrids[index] = TRUE;
-
-      gridID = vlistGrid(vlistID, index);
-      gridtype = gridInqType(gridID);
+      remapgrids[index] = true;
 
+      int gridID = vlistGrid(vlistID, index);
+      int gridtype = gridInqType(gridID);
+      int projtype = (gridtype == GRID_PROJECTION) ? gridInqProjType(gridID) : -1;
+  
       if ( gridtype != GRID_LONLAT      &&
+           projtype != CDI_PROJ_RLL     &&
+           projtype != CDI_PROJ_LAEA    &&
+           projtype != CDI_PROJ_SINU    &&
+           projtype != CDI_PROJ_LCC     &&
 	   gridtype != GRID_GAUSSIAN    &&
 	   gridtype != GRID_LCC         &&
-	   gridtype != GRID_LAEA        &&
-	   gridtype != GRID_SINUSOIDAL  &&
 	   gridtype != GRID_GME         &&
 	   gridtype != GRID_CURVILINEAR &&
 	   gridtype != GRID_UNSTRUCTURED )
 	{
 	  if ( gridtype == GRID_GAUSSIAN_REDUCED )
 	    {
-	      if ( !cdoRegulargrid && filetype == FILETYPE_GRB )
+	      if ( !cdoRegulargrid && filetype == CDI_FILETYPE_GRB )
 		cdoAbort("Unsupported grid type: %s, use CDO option -R to convert reduced to regular grid!", gridNamePtr(gridtype));
 	      else
 		cdoAbort("Unsupported grid type: %s, use CDO operator -setgridtype,regular to convert reduced to regular grid!", gridNamePtr(gridtype));
 	    }
 	  else if ( gridtype == GRID_GENERIC && gridInqSize(gridID) <= 2 )
             {
-              remapgrids[index] = FALSE;
+              remapgrids[index] = false;
             }
 	  else
             {
@@ -611,7 +586,7 @@ int set_remapgrids(int filetype, int vlistID, int ngrids, int *remapgrids)
     }
 
   for ( index = 0; index < ngrids; index++ )
-    if ( remapgrids[index] == TRUE ) break;
+    if ( remapgrids[index] ) break;
 
   if ( index == ngrids ) cdoAbort("No remappable grid found!");
 
@@ -645,9 +620,8 @@ static
 int get_norm_opt(void)
 {
   int norm_opt = NORM_OPT_FRACAREA;
-  char *envstr;
 
-  envstr = getenv("CDO_REMAP_NORMALIZE_OPT"); // obsolate
+  char *envstr = getenv("CDO_REMAP_NORMALIZE_OPT"); // obsolate
   if ( envstr && *envstr )
     {
       if      ( memcmp(envstr, "frac", 4) == 0 ) norm_opt = NORM_OPT_FRACAREA;
@@ -743,6 +717,37 @@ void init_remap_timer(void)
 }
 
 static
+void links_per_value(remapvars_t *remapvars)
+{
+  long num_links = remapvars->num_links;
+  const int *restrict dst_add = remapvars->tgt_cell_add;
+
+  int lpv = 1;
+  int ival = dst_add[0];
+  for ( long n = 1; n < num_links; ++n )
+    if ( dst_add[n] == ival ) lpv++;
+    else break;
+
+  if ( num_links%lpv != 0 ) lpv = -1;
+  else if ( lpv > 1 )
+    {
+      for ( long n = 1; n < num_links/lpv; ++n )
+        {
+          ival = dst_add[n*lpv];
+          for ( int k = 1; k < lpv; ++k )
+            if ( dst_add[n*lpv+k] != ival )
+              {
+                lpv = -1;
+                break;
+              }
+          if ( lpv == -1 ) break;
+        }
+    }
+
+  remapvars->links_per_value = lpv;
+}
+
+static
 void sort_remap_add(remapvars_t *remapvars)
 {
   if ( cdoTimer ) timer_start(timer_remap_sort);
@@ -771,21 +776,18 @@ void *Remap(void *argument)
   int streamID2 = -1;
   int nrecs;
   int index;
-  int tsID, recID, varID, levelID;
+  int varID, levelID;
   int gridsize, gridsize2;
   int gridID1 = -1, gridID2;
   int nmiss1, nmiss2, i, j, r = -1;
-  int *imask = NULL;
   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;
-  int grid1sizemax;
   char varname[CDI_MAX_NAME];
   double missval;
-  double *array1 = NULL, *array2 = NULL;
   double *grad1_lat = NULL, *grad1_lon = NULL, *grad1_latlon = NULL;
   remap_t *remaps = NULL;
   char *remap_file = NULL;
@@ -872,7 +874,7 @@ void *Remap(void *argument)
   vlistDefTaxis(vlistID2, taxisID2);
 
   int ngrids = vlistNgrids(vlistID1);
-  int remapgrids[ngrids];
+  bool remapgrids[ngrids];
   index = set_remapgrids(filetype, vlistID1, ngrids, remapgrids);
   gridID1 = vlistGrid(vlistID1, index);
 
@@ -903,6 +905,9 @@ void *Remap(void *argument)
 
       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 == -1 ) links_per_value(&remaps[0].vars);
+            
       nremaps = 1;
       gridsize = remaps[0].src_grid.size;
       remaps[0].gridID   = gridID1;
@@ -911,7 +916,7 @@ void *Remap(void *argument)
       if ( map_type == MAP_TYPE_DISTWGT && !lextrapolate ) remap_extrapolate = true;
       if ( gridIsCircular(gridID1)      && !lextrapolate ) remap_extrapolate = true;
 
-      if ( map_type == MAP_TYPE_DISTWGT && !remap_extrapolate && gridInqSize(gridID1) > 1 &&  !is_global_grid(gridID1) )
+      if ( map_type == MAP_TYPE_DISTWGT && !remap_extrapolate && gridInqSize(gridID1) > 1 && !is_global_grid(gridID1) )
 	{
 	  remaps[0].gridsize += 4*(gridInqXsize(gridID1)+2) + 4*(gridInqYsize(gridID1)+2);
 	  remaps[0].src_grid.non_global = true;
@@ -965,7 +970,7 @@ void *Remap(void *argument)
 
   if ( map_type == MAP_TYPE_CONSERV || map_type == MAP_TYPE_CONSERV_YAC ) norm_opt = get_norm_opt();
 
-  grid1sizemax = vlistGridsizeMax(vlistID1);
+  int grid1sizemax = vlistGridsizeMax(vlistID1);
 
   if ( map_type == MAP_TYPE_BICUBIC ) need_gradiants = TRUE;
   if ( map_type == MAP_TYPE_CONSERV && remap_order == 2 )
@@ -983,11 +988,11 @@ void *Remap(void *argument)
       grad1_latlon = (double*) Malloc(grid1sizemax*sizeof(double));
     }
 
-  array1 = (double*) Malloc(grid1sizemax*sizeof(double));
-  imask  = (int*) Malloc(grid1sizemax*sizeof(int));
+  double *array1 = (double*) Malloc(grid1sizemax*sizeof(double));
+  int *imask = (int*) Malloc(grid1sizemax*sizeof(int));
 
   gridsize = gridInqSize(gridID2);
-  array2   = (double*) Malloc(gridsize*sizeof(double));
+  double *array2 = (double*) Malloc(gridsize*sizeof(double));
 
   if ( ! lwrite_remap )
     {
@@ -995,7 +1000,7 @@ void *Remap(void *argument)
       streamDefVlist(streamID2, vlistID2);
     }
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
@@ -1003,14 +1008,14 @@ void *Remap(void *argument)
       if ( ! lwrite_remap ) 
 	streamDefTimestep(streamID2, tsID);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, array1, &nmiss1);
 
 	  gridID1 = vlistInqVarGrid(vlistID1, varID);
 
-	  if ( remapgrids[vlistGridIndex(vlistID1, gridID1)] == FALSE )
+	  if ( !remapgrids[vlistGridIndex(vlistID1, gridID1)] )
 	    {
 	      if ( lwrite_remap ) continue;
 	      else
@@ -1024,21 +1029,16 @@ void *Remap(void *argument)
 	  if ( map_type != MAP_TYPE_CONSERV && map_type != MAP_TYPE_CONSERV_YAC && 
 	       gridInqType(gridID1) == GRID_GME && gridInqType(gridID2) == GRID_GME )
 	    cdoAbort("Only conservative remapping is available to remap between GME grids!");
-	  /*
-	  if ( gridIsRotated(gridID1) && map_type != MAP_TYPE_CONSERV )
-	    cdoAbort("Only conservative remapping is available for rotated grids!");
-	  */
+
 	  missval = vlistInqVarMissval(vlistID1, varID);
 	  gridsize = gridInqSize(gridID1);
 
 	  if ( gridIsCircular(gridID1) && !lextrapolate ) remap_extrapolate = true;
 	  if ( map_type == MAP_TYPE_DISTWGT && !remap_extrapolate && gridInqSize(gridID1) > 1 && !is_global_grid(gridID1) )
 	    {
-	      int gridsize_new;
-	      int nx, ny;
-	      nx = gridInqXsize(gridID1);
-	      ny = gridInqYsize(gridID1);
-	      gridsize_new = gridsize + 4*(nx+2) + 4*(ny+2);
+	      int nx = gridInqXsize(gridID1);
+	      int ny = gridInqYsize(gridID1);
+	      int gridsize_new = gridsize + 4*(nx+2) + 4*(ny+2);
 	      if ( gridsize_new > grid1sizemax )
 		{
 		  grid1sizemax = gridsize_new;
@@ -1142,7 +1142,7 @@ void *Remap(void *argument)
 		  remap_set_int(REMAP_NUM_SRCH_BINS, remap_num_srch_bins);
 
 		  remaps[r].vars.norm_opt = norm_opt;
-		  remaps[r].vars.pinit = FALSE;
+		  remaps[r].vars.pinit = false;
 		  
 		  if ( (map_type == MAP_TYPE_BILINEAR || map_type == MAP_TYPE_BICUBIC) &&
 		       (gridInqType(gridID1) == GRID_GME || gridInqType(gridID1) == GRID_UNSTRUCTURED) )
@@ -1193,6 +1193,7 @@ void *Remap(void *argument)
 		    resize_remap_vars(&remaps[r].vars, remaps[r].vars.num_links-remaps[r].vars.max_links);
 		  
 		  if ( remaps[r].vars.sort_add ) sort_remap_add(&remaps[r].vars);
+		  if ( remaps[r].vars.links_per_value == -1 ) links_per_value(&remaps[r].vars);
 
 		  if ( lwrite_remap ) goto WRITE_REMAP;
 
@@ -1228,7 +1229,7 @@ void *Remap(void *argument)
 	      else
 		remap(array2, missval, gridInqSize(gridID2), remaps[r].vars.num_links, remaps[r].vars.wts,
 		      remaps[r].vars.num_wts, remaps[r].vars.tgt_cell_add, remaps[r].vars.src_cell_add,
-		      array1, grad1_lat, grad1_lon, grad1_latlon, remaps[r].vars.links);
+		      array1, grad1_lat, grad1_lon, grad1_latlon, remaps[r].vars.links, remaps[r].vars.links_per_value);
 	    }
 	  else
 	    {
@@ -1250,16 +1251,15 @@ void *Remap(void *argument)
 
 	  if ( operfunc == REMAPSUM )
 	    {
-	      double array1sum = 0;
-	      double array2sum = 0;
-   
 	      for ( i = 0; i < gridsize; i++ )
 		printf("1 %d %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++ )
 		array1sum += remaps[r].src_grid.cell_area[i];
 
 	      for ( i = 0; i < gridsize2; i++ )
 		printf("2 %d %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++ )
 		array2sum += remaps[r].tgt_grid.cell_area[i];
 
@@ -1279,9 +1279,8 @@ void *Remap(void *argument)
 
 	  if ( gridInqType(gridID2) == GRID_GME )
 	    {
-	      int ni, nd;
- 	      ni = gridInqGMEni(gridID2);
-	      nd = gridInqGMEnd(gridID2);
+	      int nd, ni, ni2, ni3;
+ 	      gridInqParamGME(gridID2, &nd, &ni, &ni2, &ni3);
 	      j = remaps[r].tgt_grid.size;
 
 	      for ( i = gridsize2-1; i >=0 ; i-- )
diff --git a/src/Remapeta.c b/src/Remapeta.c
index 93d9ab6..4106c85 100644
--- a/src/Remapeta.c
+++ b/src/Remapeta.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -20,7 +20,6 @@
       Remapeta     remapeta          Model to model level interpolation
 */
 
-#include <ctype.h>
 
 #include "hetaeta.h"
 #include <cdi.h>
@@ -28,7 +27,7 @@
 #include "cdo_int.h"
 #include "pstream.h"
 #include "after_vertint.h"
-#include "list.h"
+#include "listarray.h"
 #include "stdnametable.h"
 
 
@@ -220,27 +219,24 @@ double *vlist_hybrid_vct(int vlistID, int *rzaxisIDh, int *rnvct, int *rnhlevf)
 void *Remapeta(void *argument)
 {
   int nfis2gp = 0;
-  int recID, nrecs;
-  int i, offset, iv;
+  int nrecs;
+  int i, iv;
   int varID, levelID;
   int nvars3D = 0;
-  int zaxisID;
-  int nlevel;
-  int sgeopotID = -1, tempID = -1, sqID = -1, psID = -1, lnpsID = -1, presID = -1;
-  int code;
+  int sgeopotID = -1, tempID = -1, sqID = -1, psID = -1, lnpsID = -1;
   char varname[CDI_MAX_NAME], stdname[CDI_MAX_NAME];
   double *single2;
-  double *fis1 = NULL, *ps1 = NULL, *t1 = NULL, *q1 = NULL;
-  double *fis2 = NULL, *ps2 = NULL, *t2 = NULL, *q2 = NULL;
+  double *fis2 = NULL;
+  double *t1 = NULL, *q1 = NULL;
+  double *t2 = NULL, *q2 = NULL;
   double *tscor = NULL, *pscor = NULL, *secor = NULL;
   int nmiss, nmissout = 0;
-  int ltq = FALSE;
-  int lfis2 = FALSE;
+  bool ltq = false;
+  bool lfis2 = false;
   int varids[MAX_VARS3D];
   int *imiss = NULL;
   int timer_hetaeta = 0;
   long nctop = 0;
-  double *array = NULL;
   double *deltap1 = NULL, *deltap2 = NULL;
   double *half_press1 = NULL, *half_press2 = NULL;
   double *sum1 = NULL, *sum2 = NULL;
@@ -248,7 +244,6 @@ void *Remapeta(void *argument)
   double minval, maxval;
   double missval = 0;
   double cconst = 1.E-6;
-  const char *fname;
   double cptop  = 0; /* min. pressure level for cond. */
 
   if ( cdoTimer ) timer_hetaeta = timer_new("Remapeta_hetaeta");
@@ -290,13 +285,11 @@ void *Remapeta(void *argument)
 
   if ( operatorArgc() == 2 )
     {
-      int streamID;
+      lfis2 = true;
 
-      lfis2 = TRUE;
-      fname = operatorArgv()[1];
-      
+      const char *fname = operatorArgv()[1];
       argument_t *fileargument = file_argument_new(fname);
-      streamID = streamOpenRead(fileargument);
+      int streamID = streamOpenRead(fileargument);
       file_argument_free(fileargument);
 
       int vlistID1 = streamInqVlist(streamID);
@@ -394,11 +387,11 @@ void *Remapeta(void *argument)
 
   for ( varID = 0; varID < nvars; varID++ )
     {
-      gridID  = vlistInqVarGrid(vlistID1, varID);
-      zaxisID = vlistInqVarZaxis(vlistID1, varID);
-      nlevel  = zaxisInqSize(zaxisID);
+      int gridID  = vlistInqVarGrid(vlistID1, varID);
+      int zaxisID = vlistInqVarZaxis(vlistID1, varID);
+      int nlevel  = zaxisInqSize(zaxisID);
 
-      code = vlistInqVarCode(vlistID1, varID);
+      int code = vlistInqVarCode(vlistID1, varID);
       /* code = -1; */
       if ( code <= 0 || code == 255 )
 	{
@@ -457,7 +450,7 @@ void *Remapeta(void *argument)
 
   if ( tempID != -1 && sqID != -1 )
     {
-      ltq = TRUE;
+      ltq = true;
     }
   else
     {
@@ -465,14 +458,14 @@ void *Remapeta(void *argument)
       if ( sqID   != -1 ) cdoAbort("Humidity without temperature unsupported!");
     }
   /*
-  if ( ltq == FALSE )
+  if ( ltq == false )
     {
       cdoWarning("Temperature and Humidity not found!");
     }
   */
   if ( operatorID == REMAPETA ) {}
 
-  if ( operatorID == REMAPETAS || operatorID == REMAPETAZ)
+  if ( operatorID == REMAPETAS || operatorID == REMAPETAZ )
     {
       sum1 = (double*) Malloc(gridsize*sizeof(double));
       sum2 = (double*) Malloc(gridsize*sizeof(double));
@@ -486,15 +479,15 @@ void *Remapeta(void *argument)
       half_press2 = (double*) Malloc(gridsize*(nhlevf2+1)*sizeof(double));
     }
 
-  array = (double*) Malloc(gridsize*sizeof(double));
+  double *array = (double*) Malloc(gridsize*sizeof(double));
 
-  fis1  = (double*) Malloc(gridsize*sizeof(double));
-  ps1   = (double*) Malloc(gridsize*sizeof(double));
+  double *fis1  = (double*) Malloc(gridsize*sizeof(double));
+  double *ps1   = (double*) Malloc(gridsize*sizeof(double));
 
-  if ( lfis2 == FALSE ) fis2  = (double*) Malloc(gridsize*sizeof(double));
-  if ( lfis2 == TRUE && gridsize != nfis2gp ) cdoAbort("Orographies have different grid size!");
+  if ( lfis2 == false ) fis2 = (double*) Malloc(gridsize*sizeof(double));
+  if ( lfis2 == true && gridsize != nfis2gp ) cdoAbort("Orographies have different grid size!");
 
-  ps2   = (double*) Malloc(gridsize*sizeof(double));
+  double *ps2   = (double*) Malloc(gridsize*sizeof(double));
 
   if ( ltq )
     {
@@ -529,7 +522,7 @@ void *Remapeta(void *argument)
       memset(fis1, 0, gridsize*sizeof(double));
     }
 
-  presID = lnpsID;
+  int presID = lnpsID;
   if ( zaxisIDh != -1 && lnpsID == -1 )
     {
       if ( psID == -1 )
@@ -546,21 +539,20 @@ void *Remapeta(void *argument)
 	cdoPrint("using %s", var_stdname(surface_air_pressure));
     }
 
-  if ( cdoVerbose ) cdoPrint("nvars3D = %d   ltq = %d", nvars3D, ltq);
+  if ( cdoVerbose ) cdoPrint("nvars3D = %d   ltq = %d", nvars3D, (int)ltq);
 
   int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
-
       streamDefTimestep(streamID2, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
-	  zaxisID  = vlistInqVarZaxis(vlistID1, varID);
-	  nlevel   = zaxisInqSize(zaxisID);
-	  offset   = gridsize*levelID;
+	  int zaxisID = vlistInqVarZaxis(vlistID1, varID);
+	  int nlevel  = zaxisInqSize(zaxisID);
+	  int offset = gridsize*levelID;
 	  streamReadRecord(streamID1, array, &nmiss);
 
 	  if ( zaxisIDh != -1 )
@@ -614,16 +606,16 @@ void *Remapeta(void *argument)
 	    cdoWarning("Orography out of range (min=%g max=%g)!", minval, maxval);
 	}
 
-      if ( lfis2 == FALSE )
-	for ( i = 0; i < gridsize; i++ ) fis2[i] = fis1[i];
+      if ( lfis2 == false )
+	for ( int i = 0; i < gridsize; i++ ) fis2[i] = fis1[i];
 
       if ( ltq )
 	{
 	  varID = tempID;
-	  nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
+	  int nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
 	  for ( levelID = 0; levelID < nlevel; levelID++ )
 	    {
-	      offset   = gridsize*levelID;
+	      int offset = gridsize*levelID;
 	      single2  = t1 + offset;
 
 	      minmaxval(gridsize, single2, imiss, &minval, &maxval);
@@ -636,7 +628,7 @@ void *Remapeta(void *argument)
 	  nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
 	  for ( levelID = 0; levelID < nlevel; levelID++ )
 	    {
-	      offset   = gridsize*levelID;
+	      int offset = gridsize*levelID;
 	      single2  = q1 + offset;
 
 	      corr_hum(gridsize, single2, MIN_Q);
@@ -690,10 +682,10 @@ void *Remapeta(void *argument)
       if ( ltq )
 	{
 	  varID = tempID;
-	  nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
+	  int nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
 	  for ( levelID = 0; levelID < nlevel; levelID++ )
 	    {
-	      offset   = gridsize*levelID;
+	      int offset = gridsize*levelID;
 	      single2  = t2 + offset;
 
 	      minmaxval(gridsize, single2, imiss, &minval, &maxval);
@@ -710,7 +702,7 @@ void *Remapeta(void *argument)
 	  nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
 	  for ( levelID = 0; levelID < nlevel; levelID++ )
 	    {
-	      offset   = gridsize*levelID;
+	      int offset = gridsize*levelID;
 	      single2  = q2 + offset;
 
 	      corr_hum(gridsize, single2, MIN_Q);
@@ -733,7 +725,7 @@ void *Remapeta(void *argument)
 	{
 	  varID = varids[iv];
 
-	  nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
+	  int nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
 
 	  if ( operatorID == REMAPETAS )
 	    {
@@ -765,7 +757,7 @@ void *Remapeta(void *argument)
 
 	  for ( levelID = 0; levelID < nlevel; levelID++ )
 	    {
-	      offset   = gridsize*levelID;
+	      int offset = gridsize*levelID;
 	      single2  = vars2[iv] + offset;
 
 	      if ( operatorID == REMAPETAS || operatorID == REMAPETAZ )
diff --git a/src/Replace.c b/src/Replace.c
index 2782114..d3ae813 100644
--- a/src/Replace.c
+++ b/src/Replace.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -33,15 +33,12 @@ void *Replace(void *argument)
 {
   int varID, varID1, varID2;
   int nrecs = 0;
-  int recID, levelID, levelID2;
+  int levelID, levelID2;
   int nrecs2;
   int nchvars = 0;
   int idx;
-  int nlevel1, nlevel2;
   char varname1[CDI_MAX_NAME], varname2[CDI_MAX_NAME];
   int nmiss;
-  int gridsize;
-  int offset;
   int varlist1[MAX_VARS], varlist2[MAX_VARS];
   int **varlevel = NULL;
   int **varnmiss2 = NULL;
@@ -77,13 +74,11 @@ void *Replace(void *argument)
 
       if ( varID1 < nvars1 )
 	{
-	  int gridsize1, gridsize2, nlevel1, nlevel2;
+	  int gridsize1 = gridInqSize(vlistInqVarGrid(vlistID1, varID1));
+	  int nlevel1   = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID1));
 
-	  gridsize1 = gridInqSize(vlistInqVarGrid(vlistID1, varID1));
-	  nlevel1   = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID1));
-
-	  gridsize2 = gridInqSize(vlistInqVarGrid(vlistID2, varID2));
-	  nlevel2   = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID2));
+	  int gridsize2 = gridInqSize(vlistInqVarGrid(vlistID2, varID2));
+	  int nlevel2   = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID2));
 
 	  if ( gridsize1 != gridsize2 )
 	    cdoAbort("Variables have different gridsize!");
@@ -113,9 +108,9 @@ void *Replace(void *argument)
 	{
 	  varID1 = varlist1[idx];
 	  varID2 = varlist2[idx];
-	  nlevel1  = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID1));
-	  nlevel2  = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID2));
-	  gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID2));
+	  int nlevel1  = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID1));
+	  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));
 	  varlevel[idx] = (int*) Malloc(nlevel1*sizeof(int));
@@ -127,8 +122,8 @@ void *Replace(void *argument)
 	    {
 	      double *level1 = (double*) Malloc(nlevel1*sizeof(double));
 	      double *level2 = (double*) Malloc(nlevel2*sizeof(double));
-	      zaxisInqLevels(vlistInqVarZaxis(vlistID1, varID1), level1);
-	      zaxisInqLevels(vlistInqVarZaxis(vlistID2, varID2), level2);
+	      cdoZaxisInqLevels(vlistInqVarZaxis(vlistID1, varID1), level1);
+	      cdoZaxisInqLevels(vlistInqVarZaxis(vlistID2, varID2), level2);
 
 	      for ( levelID = 0; levelID < nlevel1; levelID++ )
 		varlevel[idx][levelID] = -1;
@@ -159,7 +154,7 @@ void *Replace(void *argument)
   vlistDefTaxis(vlistID3, taxisID3);
   streamDefVlist(streamID3, vlistID3);
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
   double *array = (double*) Malloc(gridsize*sizeof(double));
 
   int nts2 = vlistNtsteps(vlistID2);
@@ -175,15 +170,15 @@ void *Replace(void *argument)
 	  if ( nrecs2 == 0 )
 	    cdoAbort("Input streams have different number of timesteps!");
 
-	  for ( recID = 0; recID < nrecs2; recID++ )
+	  for ( int recID = 0; recID < nrecs2; recID++ )
 	    {
 	      streamInqRecord(streamID2, &varID, &levelID);
 	      
 	      for ( idx = 0; idx < nchvars; idx++ )
 		if ( varlist2[idx] == varID )
 		  {
-		    gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
-		    offset   = gridsize*levelID;
+		    int gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
+		    int offset   = gridsize*levelID;
 		    parray   = vardata2[idx]+offset;
 		    streamReadRecord(streamID2, parray, &nmiss);
 		    varnmiss2[idx][levelID] = nmiss;
@@ -194,7 +189,7 @@ void *Replace(void *argument)
 
       streamDefTimestep(streamID3, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -206,8 +201,8 @@ void *Replace(void *argument)
 		levelID2 = varlevel[idx][levelID];
 		if ( levelID2 != -1 )
 		  {
-		    gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
-		    offset   = gridsize*levelID2;
+		    int gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
+		    int offset   = gridsize*levelID2;
 		    parray   = vardata2[idx]+offset;
 		    nmiss    = varnmiss2[idx][levelID2];
 		    break;
diff --git a/src/Replacevalues.c b/src/Replacevalues.c
index 3c49c2b..35b6a92 100644
--- a/src/Replacevalues.c
+++ b/src/Replacevalues.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -27,46 +27,36 @@
 #include "cdo.h"
 #include "cdo_int.h"
 #include "pstream.h"
-#include "list.h"
+#include "listarray.h"
 
 
 void *Replacevalues(void *argument)
 {
-  int  SETVALS, SETRTOC, SETRTOC2;
-  int operatorID;
-  int streamID1, streamID2;
-  int gridsize;
-  int nrecs, recID;
-  int tsID;
+  int nrecs;
   int varID, levelID;
-  int vlistID1, vlistID2;
   int nmiss;
   int nvals = 0;
-  LIST *flist = listNew(FLT_LIST);
+  lista_t *flista = lista_new(FLT_LISTA);
   double *fltarr = NULL;
-  int i, j;
-  double missval;
   double rmin = 0, rmax = 0;
-  double *array;
-  int taxisID1, taxisID2;
   double newval = 0, newval2 = 0;
 
   cdoInitialize(argument);
 
-  SETVALS  = cdoOperatorAdd("setvals" , 0, 0, "I1,O1,...,In,On");
-  SETRTOC  = cdoOperatorAdd("setrtoc",  0, 0, "range (min, max), value");
-  SETRTOC2 = cdoOperatorAdd("setrtoc2", 0, 0, "range (min, max), value1, value2");
+  int SETVALS  = cdoOperatorAdd("setvals" , 0, 0, "I1,O1,...,In,On");
+  int SETRTOC  = cdoOperatorAdd("setrtoc",  0, 0, "range (min, max), value");
+  int SETRTOC2 = cdoOperatorAdd("setrtoc2", 0, 0, "range (min, max), value1, value2");
 
-  operatorID = cdoOperatorID();
+  int operatorID = cdoOperatorID();
 
   operatorInputArg(cdoOperatorEnter(operatorID));
 
   if ( operatorID == SETVALS )
     {
-      nvals = args2fltlist(operatorArgc(), operatorArgv(), flist);
+      nvals = args2flt_lista(operatorArgc(), operatorArgv(), flista);
       if ( nvals < 2 ) cdoAbort("Too few arguments!");
       if ( nvals % 2 != 0 )  cdoAbort("Need pairs of arguments!");
-      fltarr = (double *) listArrayPtr(flist);
+      fltarr = (double *) lista_dataptr(flista);
       nvals = nvals / 2;
     }
   else if ( operatorID == SETRTOC )
@@ -85,45 +75,44 @@ void *Replacevalues(void *argument)
       newval2 = parameter2double(operatorArgv()[3]);
     }
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
 
-  array = (double*) Malloc(gridsize*sizeof(double));
+  double *array = (double*) Malloc(gridsize*sizeof(double));
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
-
       streamDefTimestep(streamID2, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, array, &nmiss);
 
 	  gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
-	  missval = vlistInqVarMissval(vlistID1, varID);
+	  double missval = vlistInqVarMissval(vlistID1, varID);
 
 	  if ( operatorID == SETVALS )
 	    {
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( int i = 0; i < gridsize; i++ )
 		if ( !DBL_IS_EQUAL(array[i], missval) )
 		  {
 		    /* printf("\nelem %d val %f ",i,array[i]); */
-		    for (j=0; j < nvals; j++)
+		    for ( int j = 0; j < nvals; j++ )
 		      {
 			if ( DBL_IS_EQUAL(array[i], fltarr[j*2] ) )
 			  {
@@ -131,34 +120,27 @@ void *Replacevalues(void *argument)
 			    /* printf("j=%d %f %f ",j,fltarr[j*2],fltarr[j*2+1]); */
 			    break;
 			  }
-			
 		      }
 		  }
 	    }
 	  else if ( operatorID == SETRTOC )
 	    {
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( int i = 0; i < gridsize; i++ )
 		if ( !DBL_IS_EQUAL(array[i], missval) )
 		  {
 		    if ( array[i] >= rmin && array[i] <= rmax)
-		      {
-			array[i] = newval;
-		      }
+                      array[i] = newval;
 		  }
 	    }
 	  else if ( operatorID == SETRTOC2 )
 	    {
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( int i = 0; i < gridsize; i++ )
 		if ( !DBL_IS_EQUAL(array[i], missval) )
 		  {
 		    if ( array[i] >= rmin && array[i] <= rmax )
-		      {
-			array[i] = newval;
-		      }
+                      array[i] = newval;
 		    else
-		      {
-			array[i] = newval2;
-		      }
+                      array[i] = newval2;
 		  }
 	    }
 
@@ -173,7 +155,7 @@ void *Replacevalues(void *argument)
 
   if ( array ) Free(array);
 
-  listDelete(flist);
+  lista_destroy(flista);
 
   cdoFinish();
 
diff --git a/src/Rhopot.c b/src/Rhopot.c
index 5e9863a..f2c2c8d 100644
--- a/src/Rhopot.c
+++ b/src/Rhopot.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -21,7 +21,6 @@
       Rhopot      rhopot          potential density
 */
 
-#include <ctype.h>
 
 #include <cdi.h>
 #include "cdo.h"
@@ -65,14 +64,10 @@ double potrho_1(double t, double sal, double p)
          r_ak0 = 8.50935e-5, r_ak1 = -6.12293e-6, r_ak2 = 5.2787e-8,
          r_am0 = -9.9348e-7, r_am1 = 2.0816e-8, r_am2 = 9.1697e-10;
 
-  double s, s3h; 
-  double rho;
+  double s = MAX(sal, 0.0);
+  double s3h = sqrt(s*s*s);
 
-    {
-      s = MAX(sal, 0.0);
-      s3h = sqrt(s*s*s);
-
-      rho = (r_a0 + t * (r_a1 + t * (r_a2 + t * (r_a3 + t * (r_a4 + t * r_a5))))
+  double rho = (r_a0 + t * (r_a1 + t * (r_a2 + t * (r_a3 + t * (r_a4 + t * r_a5))))
             + s * (r_b0 + t * (r_b1 + t * (r_b2 + t * (r_b3 + t * r_b4))))    
             + r_d0 * s*s                 
             + s3h * (r_c0 + t * (r_c1 + r_c2 * t)))                           
@@ -85,9 +80,8 @@ double potrho_1(double t, double sal, double p)
                     + r_e0 + t * (r_e1 + t * (r_e2 + t * (r_e3 + t * r_e4)))  
                     + s * (r_f0 + t * (r_f1 + t * (r_f2 + t * r_f3)))         
                     + s3h * (r_g0 + t * (r_g1 + r_g2 * t))));
-    }
 
-  return (rho);
+  return rho;
 }
 
 /*
@@ -126,23 +120,20 @@ int main (int argc, char *argv[])
 */
 
 static
-void calc_rhopot(long gridsize, long nlevel, double *pressure, field_t to, field_t sao, field_t rho)
+void calc_rhopot(long gridsize, long nlevel, double *pressure, field_type to, field_type sao, field_type rho)
 {
   /* pressure units: hPa     */
   /* to units:       Celsius */
   /* sao units:      psu     */
 
-  long i, levelID, offset;
-  double *rhoptr, *toptr, *saoptr;
-
-  for ( levelID = 0; levelID < nlevel; ++levelID )
+  for ( long levelID = 0; levelID < nlevel; ++levelID )
     {
-      offset = gridsize*levelID;
-      toptr = to.ptr + offset;
-      saoptr = sao.ptr + offset;
-      rhoptr = rho.ptr + offset;
+      long offset = gridsize*levelID;
+      double *toptr = to.ptr + offset;
+      double *saoptr = sao.ptr + offset;
+      double *rhoptr = rho.ptr + offset;
 
-      for ( i = 0; i < gridsize; ++i )
+      for ( long i = 0; i < gridsize; ++i )
 	{
 	  if ( DBL_IS_EQUAL(toptr[i], to.missval) ||
 	       DBL_IS_EQUAL(saoptr[i], sao.missval) )
@@ -160,38 +151,30 @@ void calc_rhopot(long gridsize, long nlevel, double *pressure, field_t to, field
 
 void *Rhopot(void *argument)
 {
-  int streamID1, streamID2;
   int nrecs;
-  int tsID, recID, varID, levelID;
-  int nlevel1, nlevel2;
-  int nvars, code, zaxisID;
-  int vlistID1, vlistID2;
+  int varID, levelID;
+  int zaxisID;
   int offset;
-  int nlevel;
-  int i;
   int nmiss;
   int toID = -1, saoID = -1, thoID = -1;
   char varname[CDI_MAX_NAME], stdname[CDI_MAX_NAME];
-  int taxisID1, taxisID2;
   double pin = -1;
-  double *pressure;
   double *single;
-  field_t to, sao, rho;
+  field_type to, sao, rho;
 
   cdoInitialize(argument);
 
   if ( operatorArgc() == 1 ) pin = parameter2double(operatorArgv()[0]);
   
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
+  int vlistID1 = streamInqVlist(streamID1);
 
-  nvars = vlistNvars(vlistID1);
+  int nvars = vlistNvars(vlistID1);
 
   for ( varID = 0; varID < nvars; varID++ )
     {
-      code = vlistInqVarCode(vlistID1, varID);
-
+      int code = vlistInqVarCode(vlistID1, varID);
       if ( code <= 0 )
 	{
 	  vlistInqVarName(vlistID1, varID, varname);
@@ -227,25 +210,25 @@ void *Rhopot(void *argument)
   int gridsize = vlist_check_gridsize(vlistID1);
 
   zaxisID = vlistInqVarZaxis(vlistID1, saoID);
-  nlevel1 = zaxisInqSize(zaxisID);
+  int nlevel1 = zaxisInqSize(zaxisID);
   zaxisID = vlistInqVarZaxis(vlistID1, toID);
-  nlevel2 = zaxisInqSize(zaxisID);
+  int nlevel2 = zaxisInqSize(zaxisID);
 
   if ( nlevel1 != nlevel2 ) cdoAbort("temperature and salinity have different number of levels!");
-  nlevel = nlevel1;
+  int nlevel = nlevel1;
 
-  pressure = (double*) Malloc(nlevel*sizeof(double));
-  zaxisInqLevels(zaxisID, pressure);
+  double *pressure = (double*) Malloc(nlevel*sizeof(double));
+  cdoZaxisInqLevels(zaxisID, pressure);
 
   if ( pin >= 0 ) 
-    for ( i = 0; i < nlevel; ++i ) pressure[i] = pin;
+    for ( int i = 0; i < nlevel; ++i ) pressure[i] = pin;
   else
-    for ( i = 0; i < nlevel; ++i ) pressure[i] /= 10;
+    for ( int i = 0; i < nlevel; ++i ) pressure[i] /= 10;
 
   if ( cdoVerbose )
     {
       cdoPrint("Level Pressure");
-      for ( i = 0; i < nlevel; ++i )
+      for ( int i = 0; i < nlevel; ++i )
 	cdoPrint("%5d  %g", i+1, pressure[i]);
     }
 
@@ -264,8 +247,12 @@ void *Rhopot(void *argument)
   sao.missval = vlistInqVarMissval(vlistID1, saoID);
   rho.missval = to.missval;
 
+  int datatype = CDI_DATATYPE_FLT32;
+  if ( vlistInqVarDatatype(vlistID1, toID) == CDI_DATATYPE_FLT64 &&
+       vlistInqVarDatatype(vlistID1, saoID) == CDI_DATATYPE_FLT64 )
+    datatype = CDI_DATATYPE_FLT64;
 
-  vlistID2 = vlistCreate();
+  int vlistID2 = vlistCreate();
   varID = vlistDefVar(vlistID2, gridID, zaxisID, TSTEP_INSTANT);
   vlistDefVarParam(vlistID2, varID, cdiEncodeParam(18, 255, 255));
   vlistDefVarName(vlistID2, varID, "rhopoto");
@@ -273,24 +260,23 @@ void *Rhopot(void *argument)
   vlistDefVarStdname(vlistID2, varID, "sea_water_potential_density");
   vlistDefVarUnits(vlistID2, varID, "kg m-3");
   vlistDefVarMissval(vlistID2, varID, rho.missval);
+  vlistDefVarDatatype(vlistID2, varID, datatype);
 
-
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
-
       streamDefTimestep(streamID2, tsID);
 	       
-      for ( recID = 0; recID < nrecs; ++recID )
+      for ( int recID = 0; recID < nrecs; ++recID )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -316,7 +302,7 @@ void *Rhopot(void *argument)
 	  single = rho.ptr+offset;
 
 	  nmiss = 0;
-	  for ( i = 0; i < gridsize; ++i )
+	  for ( int i = 0; i < gridsize; ++i )
 	    if ( DBL_IS_EQUAL(single[i], rho.missval) ) nmiss++;
  
 	  streamDefRecord(streamID2, 0, levelID);
diff --git a/src/Rotuv.c b/src/Rotuv.c
index a2f7672..672b8b4 100644
--- a/src/Rotuv.c
+++ b/src/Rotuv.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -21,7 +21,6 @@
       Rotuv      rotuvb          Backward rotation
 */
 
-#include <ctype.h>
 
 #include <cdi.h>
 #include "cdo.h"
@@ -33,43 +32,35 @@
 static
 void rot_uv_back(int gridID, double *us, double *vs)
 {
-  long i, ilat, ilon, nlat, nlon;
-  double u, v;
-  double xval, yval;
   double xpole, ypole, angle;
-  double *xvals, *yvals;
-
-  nlon = gridInqXsize(gridID);
-  nlat = gridInqYsize(gridID);
-
-  xpole = gridInqXpole(gridID);
-  ypole = gridInqYpole(gridID);
-  angle = gridInqAngle(gridID);
+  if ( gridInqType(gridID) == GRID_PROJECTION && gridInqProjType(gridID) == CDI_PROJ_RLL )
+    gridInqParamRLL(gridID, &xpole, &ypole, &angle);
 
-  xvals = (double*) Malloc(nlon*sizeof(double));
-  yvals = (double*) Malloc(nlat*sizeof(double));
+  long nlon = gridInqXsize(gridID);
+  long nlat = gridInqYsize(gridID);
 
+  double *xvals = (double*) Malloc(nlon*sizeof(double));
+  double *yvals = (double*) Malloc(nlat*sizeof(double));
   gridInqXvals(gridID, xvals);
   gridInqYvals(gridID, yvals);
 
   /* Convert lat/lon units if required */
-  {
-    char units[CDI_MAX_NAME];
-    gridInqXunits(gridID, units);
-    grid_to_degree(units, 1, &xpole, "xpole");
-    grid_to_degree(units, nlon, xvals, "grid center lon");
-    gridInqYunits(gridID, units);
-    grid_to_degree(units, 1, &ypole, "ypole");
-    grid_to_degree(units, nlat, yvals, "grid center lat");
-  }
-
-  for ( ilat = 0; ilat < nlat; ilat++ )
-    for ( ilon = 0; ilon < nlon; ilon++ )
+  char units[CDI_MAX_NAME];
+  gridInqXunits(gridID, units);
+  grid_to_degree(units, 1, &xpole, "xpole");
+  grid_to_degree(units, nlon, xvals, "grid center lon");
+  gridInqYunits(gridID, units);
+  grid_to_degree(units, 1, &ypole, "ypole");
+  grid_to_degree(units, nlat, yvals, "grid center lat");
+
+  double u, v;
+  for ( long ilat = 0; ilat < nlat; ilat++ )
+    for ( long ilon = 0; ilon < nlon; ilon++ )
       {
-	i = ilat*nlon + ilon;
+	long i = ilat*nlon + ilon;
 
-        xval = lamrot_to_lam(yvals[ilat], xvals[ilon], ypole, xpole, angle);
-        yval = phirot_to_phi(yvals[ilat], xvals[ilon], ypole, angle);
+        double xval = lamrot_to_lam(yvals[ilat], xvals[ilon], ypole, xpole, angle);
+        double yval = phirot_to_phi(yvals[ilat], xvals[ilon], ypole, angle);
 
 	usvs_to_uv(us[i], vs[i], yval, xval, ypole, xpole, &u, &v);
 	/*
@@ -89,15 +80,12 @@ void rot_uv_back(int gridID, double *us, double *vs)
 
 void *Rotuv(void *argument)
 {
-  int recID, varID, levelID;
+  int varID, levelID;
   int varID1, varID2, nlevel1, nlevel2;
   int gridsize;
   int code, gridID;
   int offset;
   int nlevel;
-  int lvar = FALSE;
-  int i;
-  int lfound[MAXARG];
   int chcodes[MAXARG];
   char *chvars[MAXARG];
   char varname[CDI_MAX_NAME];
@@ -110,25 +98,26 @@ void *Rotuv(void *argument)
   int nch = operatorArgc();
   if ( nch%2 ) cdoAbort("Odd number of input arguments!");
 
-  int lcode = TRUE;
+  bool lvar = false;
+  bool lcode = true;
   int len = (int)strlen(operatorArgv()[0]);
-  for ( i = 0; i < len; ++i )
+  for ( int i = 0; i < len; ++i )
     if ( !isdigit(operatorArgv()[0][i]) )
       {
-        lcode = FALSE;
+        lcode = false;
         break;
       }
 
   if ( lcode )
     {
-      lvar = FALSE;
-      for ( i = 0; i < nch; i++ )
+      lvar = false;
+      for ( int i = 0; i < nch; i++ )
 	chcodes[i] = parameter2int(operatorArgv()[i]);
     }
   else
     {
-      lvar = TRUE;
-      for ( i = 0; i < nch; i++ )
+      lvar = true;
+      for ( int i = 0; i < nch; i++ )
 	chvars[i] = operatorArgv()[i];
     }
 
@@ -146,17 +135,18 @@ void *Rotuv(void *argument)
   int **varnmiss    = (int **) Malloc(nvars*sizeof(int *));
   double **vardata  = (double **) Malloc(nvars*sizeof(double *));
 
-  for ( i = 0; i < nch; i++ ) lfound[i] = FALSE;
+  bool lfound[MAXARG];
+  for ( int i = 0; i < nch; i++ ) lfound[i] = false;
 
   if ( lvar )
     {
       for ( varID = 0; varID < nvars; varID++ )
 	{
 	  vlistInqVarName(vlistID2, varID, varname);
-	  for ( i = 0; i < nch; i++ )
-	    if ( strcmp(varname, chvars[i]) == 0 ) lfound[i] = TRUE;
+	  for ( int i = 0; i < nch; i++ )
+	    if ( strcmp(varname, chvars[i]) == 0 ) lfound[i] = true;
 	}
-      for ( i = 0; i < nch; i++ )
+      for ( int i = 0; i < nch; i++ )
 	if ( ! lfound[i] ) cdoAbort("Variable %s not found!", chvars[i]);
     }
   else
@@ -164,18 +154,18 @@ void *Rotuv(void *argument)
       for ( varID = 0; varID < nvars; varID++ )
 	{
 	  code = vlistInqVarCode(vlistID2, varID);
-	  for ( i = 0; i < nch; i++ )
-	    if ( code == chcodes[i] ) lfound[i] = TRUE;
+	  for ( int i = 0; i < nch; i++ )
+	    if ( code == chcodes[i] ) lfound[i] = true;
 	}
-      for ( i = 0; i < nch; i++ )
+      for ( int i = 0; i < nch; i++ )
 	if ( ! lfound[i] ) cdoAbort("Code %d not found!", chcodes[i]);
     }
 
   for ( varID = 0; varID < nvars; varID++ )
     {
       gridID = vlistInqVarGrid(vlistID1, varID);
-      if ( ! (gridInqType(gridID) == GRID_LONLAT && gridIsRotated(gridID)) )
-	cdoAbort("Only rotated lon/lat grids supported");
+      if ( ! (gridInqType(gridID) == GRID_PROJECTION && gridInqProjType(gridID) == CDI_PROJ_RLL) )
+	cdoAbort("Only rotated lon/lat grids supported!");
 
       gridsize = gridInqSize(gridID);
       nlevel   = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
@@ -198,7 +188,7 @@ void *Rotuv(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -213,7 +203,7 @@ void *Rotuv(void *argument)
 	    cdoAbort("Missing values unsupported for this operator!");
 	}
 
-      for ( i = 0; i < nch; i += 2 )
+      for ( int i = 0; i < nch; i += 2 )
 	{
 	  for ( varID = 0; varID < nvars; varID++ )
 	    {
@@ -277,7 +267,7 @@ void *Rotuv(void *argument)
 	    }
 	}
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  varID    = recVarID[recID];
 	  levelID  = recLevelID[recID];
diff --git a/src/Runpctl.c b/src/Runpctl.c
index 0fae864..2ace7fb 100644
--- a/src/Runpctl.c
+++ b/src/Runpctl.c
@@ -31,19 +31,9 @@
 void *Runpctl(void *argument)
 {
   int timestat_date = TIMESTAT_MEAN;
-  int gridsize;
   int varID;
-  int recID;
-  int nrecs;
   int levelID;
-  int tsID;
-  int otsID;
-  int i, j, inp, its;
   int nmiss;
-  int nlevels;
-  double missval, val;
-  double *array;
-  field_t ***vars1 = NULL;
 
   cdoInitialize(argument);
 
@@ -78,22 +68,21 @@ void *Runpctl(void *argument)
   dtlist_set_stat(dtlist, timestat_date);
   dtlist_set_calendar(dtlist, taxisInqCalendar(taxisID1));
 
-  vars1 = (field_t ***) Malloc((ndates+1)*sizeof(field_t **));
-  array = (double*) Malloc(ndates*sizeof(double));
+  field_type ***vars1 = (field_type ***) Malloc((ndates+1)*sizeof(field_type **));
+  double *array = (double*) Malloc(ndates*sizeof(double));
   
-  for ( its = 0; its < ndates; its++ )
-    {
-      vars1[its] = field_malloc(vlistID1, FIELD_PTR);
-    }
+  for ( int its = 0; its < ndates; its++ )
+    vars1[its] = field_malloc(vlistID1, FIELD_PTR);
 
+  int tsID;
   for ( tsID = 0; tsID < ndates; tsID++ )
     {
-      nrecs = streamInqTimestep(streamID1, tsID);
+      int nrecs = streamInqTimestep(streamID1, tsID);
       if ( nrecs == 0 ) cdoAbort("File has less than %d timesteps!", ndates);
 
       dtlist_taxisInqTimestep(dtlist, taxisID1, tsID);
         
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
         {
           streamInqRecord(streamID1, &varID, &levelID);
 
@@ -108,27 +97,27 @@ void *Runpctl(void *argument)
         }
     }
 
-  otsID = 0;
+  int otsID = 0;
   while ( TRUE )
     {
       for ( varID = 0; varID < nvars; varID++ )
         {
           if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
           
-          gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
-          missval  = vlistInqVarMissval(vlistID1, varID);
-          nlevels  = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
+          int gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
+          double missval  = vlistInqVarMissval(vlistID1, varID);
+          int nlevels  = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
           
           for ( levelID = 0; levelID < nlevels; levelID++ )
             {
               nmiss = 0;  
-              for ( i = 0; i < gridsize; i++ )
+              for ( int i = 0; i < gridsize; i++ )
                 {
-                  for ( inp = 0, j = 0; inp < ndates; inp++ )
+                  int j = 0;
+                  for ( int inp = 0, j = 0; inp < ndates; inp++ )
                     {
-                      val = vars1[inp][varID][levelID].ptr[i];
-                      if ( !DBL_IS_EQUAL(val, missval) )
-                        array[j++] = val;
+                      double val = vars1[inp][varID][levelID].ptr[i];
+                      if ( !DBL_IS_EQUAL(val, missval) ) array[j++] = val;
                     }
                   
                   if ( j > 0 )
@@ -148,7 +137,7 @@ void *Runpctl(void *argument)
       dtlist_stat_taxisDefTimestep(dtlist, taxisID2, ndates);
       streamDefTimestep(streamID2, otsID);
 
-      for ( recID = 0; recID < nrecords; recID++ )
+      for ( int recID = 0; recID < nrecords; recID++ )
         {
           varID    = recVarID[recID];
           levelID  = recLevelID[recID];
@@ -164,17 +153,14 @@ void *Runpctl(void *argument)
       dtlist_shift(dtlist);
 
       vars1[ndates] = vars1[0];
-      for ( inp = 0; inp < ndates; inp++ )
-        {
-          vars1[inp] = vars1[inp+1];
-        }
+      for ( int inp = 0; inp < ndates; inp++ ) vars1[inp] = vars1[inp+1];
 
-      nrecs = streamInqTimestep(streamID1, tsID);
+      int nrecs = streamInqTimestep(streamID1, tsID);
       if ( nrecs == 0 ) break;
 
       dtlist_taxisInqTimestep(dtlist, taxisID1, ndates-1);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
         {
           streamInqRecord(streamID1, &varID, &levelID);
           
@@ -185,10 +171,8 @@ void *Runpctl(void *argument)
       tsID++;
     }
 
-  for ( its = 0; its < ndates; its++ )
-    {
-      field_free(vars1[its], vlistID1);
-    }
+  for ( int its = 0; its < ndates; its++ )
+    field_free(vars1[its], vlistID1);
 
   Free(vars1);
   Free(array);
diff --git a/src/Runstat.c b/src/Runstat.c
index 1187ffa..87222b5 100644
--- a/src/Runstat.c
+++ b/src/Runstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -38,20 +38,10 @@
 void *Runstat(void *argument)
 {
   int timestat_date = TIMESTAT_MEAN;
-  int gridsize;
-  int i;
   int varID;
-  int recID;
-  int nrecs;
   int levelID;
-  int tsID;
-  int otsID;
-  int its;
   int nmiss;
-  int nlevel;
   int runstat_nomiss = 0;
-  double missval;
-  field_t ***vars1 = NULL, ***vars2 = NULL, ***samp1 = NULL;
 
   cdoInitialize(argument);
 
@@ -92,6 +82,14 @@ void *Runstat(void *argument)
   int taxisID1 = vlistInqTaxis(vlistID1);
   int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
+  /*  Number of timestep will be reduced compared to the input
+   *  error handling in case of not enough timesteps is done per record */
+  int nsteps = vlistNtsteps(vlistID1);
+  if ( nsteps != -1 )
+    {
+      nsteps -= ndates-1;
+      if ( nsteps > 0 ) vlistDefNtsteps(vlistID2, nsteps);
+    }
 
   int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
@@ -107,13 +105,14 @@ void *Runstat(void *argument)
   dtlist_set_stat(dtlist, timestat_date);
   dtlist_set_calendar(dtlist, taxisInqCalendar(taxisID1));
 
-  vars1 = (field_t ***) Malloc((ndates+1)*sizeof(field_t **));
+  field_type ***vars1 = (field_type ***) Malloc((ndates+1)*sizeof(field_type **));
+  field_type ***vars2 = NULL, ***samp1 = NULL;
   if ( !runstat_nomiss )
-    samp1 = (field_t ***) Malloc((ndates+1)*sizeof(field_t **));
+    samp1 = (field_type ***) Malloc((ndates+1)*sizeof(field_type **));
   if ( lvarstd )
-    vars2 = (field_t ***) Malloc((ndates+1)*sizeof(field_t **));
+    vars2 = (field_type ***) Malloc((ndates+1)*sizeof(field_type **));
 
-  for ( its = 0; its < ndates; its++ )
+  for ( int its = 0; its < ndates; its++ )
     {
       vars1[its] = field_malloc(vlistID1, FIELD_PTR);
       if ( !runstat_nomiss )
@@ -123,16 +122,17 @@ void *Runstat(void *argument)
     }
 
   int gridsizemax = vlistGridsizeMax(vlistID1);
-  int *imask = (int*) Malloc(gridsizemax*sizeof(int));
+  bool *imask = (bool*) Malloc(gridsizemax*sizeof(bool));
 
+  int tsID = 0;
   for ( tsID = 0; tsID < ndates; tsID++ )
     {
-      nrecs = streamInqTimestep(streamID1, tsID);
+      int nrecs = streamInqTimestep(streamID1, tsID);
       if ( nrecs == 0 ) cdoAbort("File has less then %d timesteps!", ndates);
 
       dtlist_taxisInqTimestep(dtlist, taxisID1, tsID);
 	
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -149,16 +149,16 @@ void *Runstat(void *argument)
 
 	  if ( !runstat_nomiss )
 	    {
-	      gridsize = gridInqSize(vars1[0][varID][levelID].grid);
-	      missval  = vars1[0][varID][levelID].missval;
+	      int gridsize = gridInqSize(vars1[0][varID][levelID].grid);
+	      double missval  = vars1[0][varID][levelID].missval;
 
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( int i = 0; i < gridsize; i++ )
 		if ( DBL_IS_EQUAL(vars1[tsID][varID][levelID].ptr[i], missval) )
-		  imask[i] = 0;
+		  imask[i] = false;
 		else
-		  imask[i] = 1;
+		  imask[i] = true;
 
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( int i = 0; i < gridsize; i++ )
 		samp1[tsID][varID][levelID].ptr[i] = (double) imask[i];
 
 #if defined(_OPENMP)
@@ -168,7 +168,7 @@ void *Runstat(void *argument)
 		{
 		  double *ptr = samp1[inp][varID][levelID].ptr;
 		  for ( int i = 0; i < gridsize; i++ )
-		    if ( imask[i] > 0 ) ptr[i]++;
+		    if ( imask[i] ) ptr[i]++;
 		}
 	    }
 
@@ -197,14 +197,14 @@ void *Runstat(void *argument)
 	}
     }
 
-  otsID = 0;
+  int otsID = 0;
   while ( TRUE )
     {
       if ( lmean )
 	for ( varID = 0; varID < nvars; varID++ )
 	  {
 	    if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
-	    nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
+	    int nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
 	    for ( levelID = 0; levelID < nlevel; levelID++ )
 	      {
 		if ( runstat_nomiss )
@@ -217,7 +217,7 @@ void *Runstat(void *argument)
 	for ( varID = 0; varID < nvars; varID++ )
 	  {
 	    if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
-	    nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
+	    int nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
 	    for ( levelID = 0; levelID < nlevel; levelID++ )
 	      {
 		if ( runstat_nomiss )
@@ -240,7 +240,7 @@ void *Runstat(void *argument)
       dtlist_stat_taxisDefTimestep(dtlist, taxisID2, ndates);
       streamDefTimestep(streamID2, otsID);
 
-      for ( recID = 0; recID < nrecords; recID++ )
+      for ( int recID = 0; recID < nrecords; recID++ )
 	{
 	  varID    = recVarID[recID];
 	  levelID  = recLevelID[recID];
@@ -270,12 +270,12 @@ void *Runstat(void *argument)
 	    vars2[inp] = vars2[inp+1];
 	}
 
-      nrecs = streamInqTimestep(streamID1, tsID);
+      int nrecs = streamInqTimestep(streamID1, tsID);
       if ( nrecs == 0 ) break;
 
       dtlist_taxisInqTimestep(dtlist, taxisID1, ndates-1);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  
@@ -286,16 +286,16 @@ void *Runstat(void *argument)
 
 	  if ( !runstat_nomiss )
 	    {
-	      gridsize = gridInqSize(vars1[0][varID][levelID].grid);
-	      missval  = vars1[0][varID][levelID].missval;
+	      int gridsize = gridInqSize(vars1[0][varID][levelID].grid);
+	      double missval  = vars1[0][varID][levelID].missval;
 
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( int i = 0; i < gridsize; i++ )
 		if ( DBL_IS_EQUAL(vars1[ndates-1][varID][levelID].ptr[i], missval) )
-		  imask[i] = 0;
+		  imask[i] = false;
 		else
-		  imask[i] = 1;
+		  imask[i] = true;
 
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( int i = 0; i < gridsize; i++ )
 		samp1[ndates-1][varID][levelID].ptr[i] = (double) imask[i];
 
 #if defined(_OPENMP)
@@ -305,7 +305,7 @@ void *Runstat(void *argument)
 		{
 		  double *ptr = samp1[inp][varID][levelID].ptr;
 		  for ( int i = 0; i < gridsize; i++ )
-		    if ( imask[i] > 0 ) ptr[i]++;
+		    if ( imask[i] ) ptr[i]++;
 		}
 	    }
 
@@ -336,7 +336,7 @@ void *Runstat(void *argument)
       tsID++;
     }
 
-  for ( its = 0; its < ndates; its++ )
+  for ( int its = 0; its < ndates; its++ )
     {
       field_free(vars1[its], vlistID1);
       if ( !runstat_nomiss ) field_free(samp1[its], vlistID1);
diff --git a/src/Seascount.c b/src/Seascount.c
index c8f2ef1..67757bc 100644
--- a/src/Seascount.c
+++ b/src/Seascount.c
@@ -31,74 +31,62 @@
 
 void *Seascount(void *argument)
 {
-  int gridsize;
-  int vdate = 0, vtime = 0;
   int vdate0 = 0, vtime0 = 0;
-  int nrecs, nrecords;
-  int varID, levelID, recID;
-  int tsID;
-  int otsID;
+  int nrecs;
+  int varID, levelID;
   int nmiss;
-  long nsets;
-  int i;
-  int year, month, day, seas, seas0 = 0;
-  int streamID1, streamID2;
-  int vlistID1, vlistID2, taxisID1, taxisID2;
-  int nwpv; // number of words per value; real:1  complex:2
-  int *recVarID, *recLevelID;
-  int newseas, oldmon = 0, newmon;
-  field_t **vars1 = NULL;
-  field_t field;
-  int season_start;
+  int year, month, day, seas0 = 0;
+  int oldmon = 0;
 
   cdoInitialize(argument);
 
   cdoOperatorAdd("seascount", 0, 0, NULL);
 
-  season_start = get_season_start();
+  int season_start = get_season_start();
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  nrecords = vlistNrecs(vlistID1);
+  int nrecords = vlistNrecs(vlistID1);
 
-  recVarID   = (int*) Malloc(nrecords*sizeof(int));
-  recLevelID = (int*) Malloc(nrecords*sizeof(int));
+  int *recVarID   = (int*) Malloc(nrecords*sizeof(int));
+  int *recLevelID = (int*) Malloc(nrecords*sizeof(int));
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
   if ( vlistNumber(vlistID1) != CDI_REAL ) gridsize *= 2;
 
+  field_type field;
   field_init(&field);
   field.ptr = (double*) Malloc(gridsize*sizeof(double));
 
-  vars1 = field_malloc(vlistID1, FIELD_PTR);
+  field_type **vars1 = field_malloc(vlistID1, FIELD_PTR);
 
-  tsID    = 0;
-  otsID   = 0;
+  int tsID    = 0;
+  int otsID   = 0;
   while ( TRUE )
     {
-      nsets = 0;
-      newseas = FALSE;
+      int nsets = 0;
+      bool newseas = false;
       while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
         {
-          vdate = taxisInqVdate(taxisID1);
-          vtime = taxisInqVtime(taxisID1);
+          int vdate = taxisInqVdate(taxisID1);
+          int vtime = taxisInqVtime(taxisID1);
 	  cdiDecodeDate(vdate, &year, &month, &day);
 
-	  newmon = month;
+	  int newmon = month;
 	  if ( season_start == START_DEC && newmon == 12 ) newmon = 0;
 
-          seas = month_to_season(month);
+          int seas = month_to_season(month);
 
           if ( nsets == 0 )
             {
@@ -106,13 +94,13 @@ void *Seascount(void *argument)
               oldmon = newmon;
             }
 
-          if ( newmon < oldmon ) newseas = TRUE;
+          if ( newmon < oldmon ) newseas = true;
 
           if ( (seas != seas0) || newseas ) break;
 
           oldmon = newmon;
 
-          for ( recID = 0; recID < nrecs; recID++ )
+          for ( int recID = 0; recID < nrecs; recID++ )
             {
               streamInqRecord(streamID1, &varID, &levelID);
 
@@ -121,13 +109,13 @@ void *Seascount(void *argument)
                   recVarID[recID]   = varID;
                   recLevelID[recID] = levelID;
                 }
-
-	      nwpv     = vars1[varID][levelID].nwpv;
+              // number of words per value; real:1  complex:2
+	      int nwpv = vars1[varID][levelID].nwpv;
               gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
 
               if ( nsets == 0 )
                 {
-                  for ( i = 0; i < nwpv*gridsize; i++ )
+                  for ( int i = 0; i < nwpv*gridsize; i++ )
                     vars1[varID][levelID].ptr[i] = vars1[varID][levelID].missval;
 		  vars1[varID][levelID].nmiss = gridsize;
                 }
@@ -152,7 +140,7 @@ void *Seascount(void *argument)
       taxisDefVtime(taxisID2, vtime0);
       streamDefTimestep(streamID2, otsID);
 
-      for ( recID = 0; recID < nrecords; recID++ )
+      for ( int recID = 0; recID < nrecords; recID++ )
         {
           varID   = recVarID[recID];
           levelID = recLevelID[recID];
diff --git a/src/Seaspctl.c b/src/Seaspctl.c
index f5f85b5..a63e75e 100644
--- a/src/Seaspctl.c
+++ b/src/Seaspctl.c
@@ -33,23 +33,14 @@
 void *Seaspctl(void *argument)
 {
   int timestat_date = TIMESTAT_MEAN;
-  int vdate1 = 0;
-  int vdate2 = 0, vtime2 = 0;
-  int vdate3 = 0, vtime3 = 0;
   int nrecs;
-  int gridID, varID, levelID, recID;
-  int tsID;
-  int otsID;
-  long nsets;
-  int year, month, day, seas, seas0 = 0;
+  int gridID, varID, levelID;
+  int year, month, day, seas0 = 0;
   int nmiss;
   int nlevels;
-  int newseas, oldmon = 0, newmon;
-  double missval;
-  field_t **vars1 = NULL;
-  field_t field;
-  HISTOGRAM_SET *hset = NULL;
+  int oldmon = 0;
   int season_start;
+  double missval;
 
   cdoInitialize(argument);
 
@@ -97,10 +88,12 @@ void *Seaspctl(void *argument)
 
   int gridsize = vlistGridsizeMax(vlistID1);
 
+  field_type field;
+  field_init(&field);
   field.ptr = (double*) Malloc(gridsize*sizeof(double));
 
-  vars1 = (field_t **) Malloc(nvars * sizeof(field_t *));
-  hset = hsetCreate(nvars);
+  field_type **vars1 = (field_type **) Malloc(nvars * sizeof(field_type *));
+  HISTOGRAM_SET *hset = hsetCreate(nvars);
 
   for ( varID = 0; varID < nvars; varID++ )
     {
@@ -109,7 +102,7 @@ void *Seaspctl(void *argument)
       nlevels   = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
       missval  = vlistInqVarMissval(vlistID1, varID);
 
-      vars1[varID] = (field_t*) Malloc(nlevels * sizeof(field_t));
+      vars1[varID] = (field_type*) Malloc(nlevels * sizeof(field_type));
       hsetCreateVarLevels(hset, varID, nlevels, gridID);
 
       for ( levelID = 0; levelID < nlevels; levelID++ )
@@ -121,29 +114,29 @@ void *Seaspctl(void *argument)
 	}
     }
 
-  tsID    = 0;
-  otsID   = 0;
+  int tsID    = 0;
+  int otsID   = 0;
   while ( TRUE )
     {
       nrecs = streamInqTimestep(streamID2, otsID);
       if ( nrecs != streamInqTimestep(streamID3, otsID) )
         cdoAbort("Number of records at time step %d of %s and %s differ!", otsID+1, cdoStreamName(1)->args, cdoStreamName(2)->args);
       
-      vdate2 = taxisInqVdate(taxisID2);
-      vtime2 = taxisInqVtime(taxisID2);
-      vdate3 = taxisInqVdate(taxisID3);
-      vtime3 = taxisInqVtime(taxisID3);
+      int vdate2 = taxisInqVdate(taxisID2);
+      int vtime2 = taxisInqVtime(taxisID2);
+      int vdate3 = taxisInqVdate(taxisID3);
+      int vtime3 = taxisInqVtime(taxisID3);
       if ( vdate2 != vdate3 || vtime2 != vtime3 )
         cdoAbort("Verification dates at time step %d of %s and %s differ!", otsID+1, cdoStreamName(1)->args, cdoStreamName(2)->args);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
         {
           streamInqRecord(streamID2, &varID, &levelID);
 	  streamReadRecord(streamID2, vars1[varID][levelID].ptr, &nmiss);
           vars1[varID][levelID].nmiss = nmiss;
         }
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
         {
           streamInqRecord(streamID3, &varID, &levelID);
 	  streamReadRecord(streamID3, field.ptr, &nmiss);
@@ -154,20 +147,20 @@ void *Seaspctl(void *argument)
 	  hsetDefVarLevelBounds(hset, varID, levelID, &vars1[varID][levelID], &field);
         }
 
-      nsets   = 0;
-      newseas = FALSE;
+      int nsets   = 0;
+      bool newseas = false;
       while ( nrecs && (nrecs = streamInqTimestep(streamID1, tsID)) )
 	{
 	  dtlist_taxisInqTimestep(dtlist, taxisID1, nsets);
-	  vdate1 = dtlist_get_vdate(dtlist, nsets);
+	  int vdate1 = dtlist_get_vdate(dtlist, nsets);
 
 	  cdiDecodeDate(vdate1, &year, &month, &day);
 
-	  newmon = month;
+	  int newmon = month;
 
 	  if ( season_start == START_DEC && newmon == 12 ) newmon = 0;
 
-          seas = month_to_season(month);
+          int seas = month_to_season(month);
 
 	  if ( nsets == 0 )
 	    {
@@ -175,13 +168,13 @@ void *Seaspctl(void *argument)
 	      oldmon = newmon;
 	    }
 
-	  if ( newmon < oldmon ) newseas = TRUE;
+	  if ( newmon < oldmon ) newseas = true;
 
 	  if ( (seas != seas0) || newseas ) break;
 
 	  oldmon = newmon;
 
-	  for ( recID = 0; recID < nrecs; recID++ )
+	  for ( int recID = 0; recID < nrecs; recID++ )
 	    {
 	      streamInqRecord(streamID1, &varID, &levelID);
 	      if ( tsID == 0 )
@@ -213,7 +206,7 @@ void *Seaspctl(void *argument)
       dtlist_stat_taxisDefTimestep(dtlist, taxisID4, nsets);
       streamDefTimestep(streamID4, otsID);
 
-      for ( recID = 0; recID < nrecords; recID++ )
+      for ( int recID = 0; recID < nrecords; recID++ )
 	{
 	  varID   = recVarID[recID];
 	  levelID = recLevelID[recID];
diff --git a/src/Seasstat.c b/src/Seasstat.c
index b3e51c1..bdd13a7 100644
--- a/src/Seasstat.c
+++ b/src/Seasstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -40,18 +40,14 @@
 void *Seasstat(void *argument)
 {
   int timestat_date = TIMESTAT_MEAN;
-  int gridsize;
-  int vdate = 0, vtime = 0;
   int vdate0 = 0, vtime0 = 0;
   int vdate1 = 0, vtime1 = 0;
   int nrecs;
-  int varID, levelID, recID;
-  int nsets;
-  int i;
-  int year, month, day, seas, seas0 = 0;
+  int varID, levelID;
+  int year, month, day, seas0 = 0;
   int nmiss;
   int nlevel;
-  int newseas, oldmon = 0, newmon;
+  int oldmon = 0;
   int nseason = 0;
   const char *seas_name[4];
 
@@ -102,36 +98,36 @@ void *Seasstat(void *argument)
   dtlist_set_stat(dtlist, timestat_date);
   dtlist_set_calendar(dtlist, taxisInqCalendar(taxisID1));
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
 
-  field_t field;
+  field_type field;
   field_init(&field);
   field.ptr = (double*) Malloc(gridsize*sizeof(double));
 
-  field_t **samp1 = field_malloc(vlistID1, FIELD_NONE);
-  field_t **vars1 = field_malloc(vlistID1, FIELD_PTR);
-  field_t **vars2 = NULL;
+  field_type **samp1 = field_malloc(vlistID1, FIELD_NONE);
+  field_type **vars1 = field_malloc(vlistID1, FIELD_PTR);
+  field_type **vars2 = NULL;
   if ( lvarstd ) vars2 = field_malloc(vlistID1, FIELD_PTR);
 
   int tsID    = 0;
   int otsID   = 0;
   while ( TRUE )
     {
-      nsets = 0;
-      newseas = FALSE;
+      long nsets = 0;
+      bool newseas = false;
       while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
 	{
 	  dtlist_taxisInqTimestep(dtlist, taxisID1, nsets);
-	  vdate = dtlist_get_vdate(dtlist, nsets);
-	  vtime = dtlist_get_vtime(dtlist, nsets);
+	  int vdate = dtlist_get_vdate(dtlist, nsets);
+	  int vtime = dtlist_get_vtime(dtlist, nsets);
 
 	  cdiDecodeDate(vdate, &year, &month, &day);
 
-	  newmon = month;
+	  int newmon = month;
 
 	  if ( season_start == START_DEC && newmon == 12 ) newmon = 0;
 
-          seas = month_to_season(month);
+          int seas = month_to_season(month);
 
 	  if ( nsets == 0 )
 	    {
@@ -142,13 +138,13 @@ void *Seasstat(void *argument)
 	      oldmon = newmon;
 	    }
 
-	  if ( newmon < oldmon ) newseas = TRUE;
+	  if ( newmon < oldmon ) newseas = true;
 
 	  if ( (seas != seas0) || newseas ) break;
 
 	  oldmon = newmon;
 
-	  for ( recID = 0; recID < nrecs; recID++ )
+	  for ( int recID = 0; recID < nrecs; recID++ )
 	    {
 	      streamInqRecord(streamID1, &varID, &levelID);
 
@@ -170,7 +166,7 @@ void *Seasstat(void *argument)
 		      if ( samp1[varID][levelID].ptr == NULL )
 			samp1[varID][levelID].ptr = (double*) Malloc(gridsize*sizeof(double));
 
-		      for ( i = 0; i < gridsize; i++ )
+		      for ( int i = 0; i < gridsize; i++ )
 			if ( DBL_IS_EQUAL(vars1[varID][levelID].ptr[i],
 					  vars1[varID][levelID].missval) )
 			  samp1[varID][levelID].ptr[i] = 0;
@@ -190,11 +186,11 @@ void *Seasstat(void *argument)
 		      if ( samp1[varID][levelID].ptr == NULL )
 			{
 			  samp1[varID][levelID].ptr = (double*) Malloc(gridsize*sizeof(double));
-			  for ( i = 0; i < gridsize; i++ )
+			  for ( int i = 0; i < gridsize; i++ )
 			    samp1[varID][levelID].ptr[i] = nsets;
 			}
 
-		      for ( i = 0; i < gridsize; i++ )
+		      for ( int i = 0; i < gridsize; i++ )
 			if ( !DBL_IS_EQUAL(field.ptr[i], vars1[varID][levelID].missval) )
 			  samp1[varID][levelID].ptr[i]++;
 		    }
@@ -288,7 +284,7 @@ void *Seasstat(void *argument)
 		     otsID+1, vdatestr, nsets, nsets == 1 ? "" : "s");
 	}
 
-      for ( recID = 0; recID < nrecords; recID++ )
+      for ( int recID = 0; recID < nrecords; recID++ )
 	{
 	  varID   = recVarID[recID];
 	  levelID = recLevelID[recID];
diff --git a/src/Selbox.c b/src/Selbox.c
index 829eaf6..7d23c44 100644
--- a/src/Selbox.c
+++ b/src/Selbox.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -32,82 +32,32 @@
 static
 void correct_xvals(long nlon, long inc, double *xvals)
 {
-  long i; 
-
   if ( IS_EQUAL(xvals[0], xvals[(nlon-1)*inc]) ) xvals[(nlon-1)*inc] += 360;
 
   if ( xvals[0] > xvals[(nlon-1)*inc] )
-    for ( i = 0; i < nlon; i++ )
+    for ( int i = 0; i < nlon; i++ )
       if ( xvals[i*inc] >= 180 ) xvals[i*inc] -= 360;
 
-  for ( i = 0; i < nlon; i++ )
+  for ( int i = 0; i < nlon; i++ )
     {
       if ( xvals[i*inc] < -180 ) xvals[i*inc] += 360;
       if ( xvals[i*inc] >  360 ) xvals[i*inc] -= 360;
     }
 
   if ( xvals[0] > xvals[(nlon-1)*inc] )
-    for ( i = 1; i < nlon; i++ )
+    for ( int i = 1; i < nlon; i++ )
       if ( xvals[i*inc] < xvals[(i-1)*inc] ) xvals[i*inc] += 360;
 }
 
 static
-int gengrid(int gridID1, int lat1, int lat2, int lon11, int lon12, int lon21, int lon22)
+void gengridxyvals(int gridtype, int gridID1, int gridID2, int nlon, int nlat, int nlon2, int nlat2,
+                   int lat1, int lat2, int lon11, int lon12, int lon21, int lon22, const char *xunits)
 {
-  int i;
-  int ilat, ilon;
-  int lxvals, lyvals;
-  char xname[CDI_MAX_NAME], xlongname[CDI_MAX_NAME], xunits[CDI_MAX_NAME];
-  char yname[CDI_MAX_NAME], ylongname[CDI_MAX_NAME], yunits[CDI_MAX_NAME];
   double *xvals1 = NULL, *yvals1 = NULL;
   double *xvals2 = NULL, *yvals2 = NULL;
-  double *xbounds1 = NULL, *ybounds1 = NULL;
-  double *xbounds2 = NULL, *ybounds2 = NULL;
-  double *pxvals2 = NULL, *pyvals2 = NULL;
-  double *pxbounds2 = NULL, *pybounds2 = NULL;
-
-  int nlon = gridInqXsize(gridID1);
-  int nlat = gridInqYsize(gridID1);
-
-  int nlon21 = lon12 - lon11 + 1;
-  int nlon22 = lon22 - lon21 + 1;
-  int nlon2 = nlon21 + nlon22;
-  int nlat2 = lat2 - lat1 + 1;
-
-  int gridtype = gridInqType(gridID1);
-  int prec     = gridInqPrec(gridID1);
-
-  int gridID2 = gridCreate(gridtype, nlon2*nlat2);
-  gridDefXsize(gridID2, nlon2);
-  gridDefYsize(gridID2, nlat2);
-
-  gridDefNP(gridID2, gridInqNP(gridID1));
-
-  gridDefPrec(gridID2, prec);
-
-  gridInqXname(gridID1, xname);
-  gridInqXlongname(gridID1, xlongname);
-  gridInqXunits(gridID1, xunits);
-  gridInqYname(gridID1, yname);
-  gridInqYlongname(gridID1, ylongname);
-  gridInqYunits(gridID1, yunits);
-
-  gridDefXname(gridID2, xname);
-  gridDefXlongname(gridID2, xlongname);
-  gridDefXunits(gridID2, xunits);
-  gridDefYname(gridID2, yname);
-  gridDefYlongname(gridID2, ylongname);
-  gridDefYunits(gridID2, yunits);
-
-  if ( gridIsRotated(gridID1) )
-    {
-      gridDefXpole(gridID2, gridInqXpole(gridID1));
-      gridDefYpole(gridID2, gridInqYpole(gridID1));
-      gridDefAngle(gridID2, gridInqAngle(gridID1));
-    }
 
-  lxvals = gridInqXvals(gridID1, NULL);
-  lyvals = gridInqYvals(gridID1, NULL);
+  int lxvals = gridInqXvals(gridID1, NULL);
+  int lyvals = gridInqYvals(gridID1, NULL);
 
   if ( gridtype == GRID_CURVILINEAR )
     {
@@ -127,8 +77,8 @@ int gengrid(int gridID1, int lat1, int lat2, int lon11, int lon12, int lon21, in
       if ( lyvals ) yvals2 = (double*) Malloc(nlat2*sizeof(double));
     }
 
-  pxvals2 = xvals2;
-  pyvals2 = yvals2;
+  double *pxvals2 = xvals2;
+  double *pyvals2 = yvals2;
 
   if ( xvals1 ) gridInqXvals(gridID1, xvals1);
   if ( yvals1 ) gridInqYvals(gridID1, yvals1);
@@ -136,14 +86,14 @@ int gengrid(int gridID1, int lat1, int lat2, int lon11, int lon12, int lon21, in
   if ( gridtype == GRID_CURVILINEAR )
     {
       if ( lxvals && lyvals )
-	for ( ilat = lat1; ilat <= lat2; ilat++ )
+	for ( int ilat = lat1; ilat <= lat2; ilat++ )
 	  {
-	    for ( ilon = lon21; ilon <= lon22; ilon++ )
+	    for ( int ilon = lon21; ilon <= lon22; ilon++ )
 	      {
 		*pxvals2++ = xvals1[ilat*nlon + ilon];
 		*pyvals2++ = yvals1[ilat*nlon + ilon];
 	      }
-	    for ( ilon = lon11; ilon <= lon12; ilon++ )
+	    for ( int ilon = lon11; ilon <= lon12; ilon++ )
 	      {
 		*pxvals2++ = xvals1[ilat*nlon + ilon];
 		*pyvals2++ = yvals1[ilat*nlon + ilon];
@@ -154,16 +104,16 @@ int gengrid(int gridID1, int lat1, int lat2, int lon11, int lon12, int lon21, in
     {
       if ( lxvals )
 	{
-	  for ( i = lon21; i <= lon22; i++ ) *pxvals2++ = xvals1[i];
-	  for ( i = lon11; i <= lon12; i++ ) *pxvals2++ = xvals1[i];
-	  if ( strncmp(xunits, "degree", 6) == 0 ) correct_xvals(nlon2, 1, xvals2);
+	  for ( int i = lon21; i <= lon22; i++ ) *pxvals2++ = xvals1[i];
+	  for ( int i = lon11; i <= lon12; i++ ) *pxvals2++ = xvals1[i];
+	  if ( xunits && strncmp(xunits, "degree", 6) == 0 ) correct_xvals(nlon2, 1, xvals2);
 	}
       
-      if ( lyvals ) for ( i = lat1;  i <= lat2;  i++ ) *pyvals2++ = yvals1[i];
+      if ( lyvals ) for ( int i = lat1;  i <= lat2;  i++ ) *pyvals2++ = yvals1[i];
     }
   /*
-    for ( i = 0; i < nlat2; i++ ) printf("lat : %d %g\n", i+1, yvals2[i]);
-    for ( i = 0; i < nlon2; i++ ) printf("lon : %d %g\n", i+1, xvals2[i]);
+    for ( int i = 0; i < nlat2; i++ ) printf("lat : %d %g\n", i+1, yvals2[i]);
+    for ( int i = 0; i < nlon2; i++ ) printf("lon : %d %g\n", i+1, xvals2[i]);
   */
   if ( xvals2 ) gridDefXvals(gridID2, xvals2);
   if ( yvals2 ) gridDefYvals(gridID2, yvals2);
@@ -172,9 +122,45 @@ int gengrid(int gridID1, int lat1, int lat2, int lon11, int lon12, int lon21, in
   if ( yvals1 ) Free(yvals1);
   if ( xvals2 ) Free(xvals2);
   if ( yvals2 ) Free(yvals2);
+}
+
+static
+int gengrid(int gridID1, int lat1, int lat2, int lon11, int lon12, int lon21, int lon22)
+{
+  int nlon = gridInqXsize(gridID1);
+  int nlat = gridInqYsize(gridID1);
+
+  int nlon21 = lon12 - lon11 + 1;
+  int nlon22 = lon22 - lon21 + 1;
+  int nlon2 = nlon21 + nlon22;
+  int nlat2 = lat2 - lat1 + 1;
+
+  int gridtype = gridInqType(gridID1);
+
+  int gridID2 = gridCreate(gridtype, nlon2*nlat2);
+  gridDefXsize(gridID2, nlon2);
+  gridDefYsize(gridID2, nlat2);
+
+  gridDefNP(gridID2, gridInqNP(gridID1));
+  gridDefPrec(gridID2, gridInqPrec(gridID1));
+
+  grid_copy_attributes(gridID1, gridID2);
+
+  if ( gridtype == GRID_PROJECTION ) grid_copy_mapping(gridID1, gridID2);
+
+  char xunits[CDI_MAX_NAME]; xunits[0] = 0;
+  char yunits[CDI_MAX_NAME]; yunits[0] = 0;
+  cdiGridInqKeyStr(gridID1, CDI_KEY_XUNITS, CDI_MAX_NAME, xunits);
+  cdiGridInqKeyStr(gridID1, CDI_KEY_YUNITS, CDI_MAX_NAME, yunits);
+
+  gengridxyvals(gridtype, gridID1, gridID2, nlon, nlat, nlon2, nlat2,
+                lat1, lat2, lon11, lon12, lon21, lon22, xunits);
 
   if ( gridInqXbounds(gridID1, NULL) && gridInqYbounds(gridID1, NULL) )
     {
+      double *xbounds1 = NULL, *ybounds1 = NULL;
+      double *xbounds2 = NULL, *ybounds2 = NULL;
+
       if ( gridtype == GRID_CURVILINEAR )
 	{
 	  xbounds1 = (double*) Malloc(4*nlon*nlat*sizeof(double));
@@ -190,8 +176,8 @@ int gengrid(int gridID1, int lat1, int lat2, int lon11, int lon12, int lon21, in
 	  ybounds2 = (double*) Malloc(2*nlat2*sizeof(double));
 	}
 
-      pxbounds2 = xbounds2;
-      pybounds2 = ybounds2;
+      double *pxbounds2 = xbounds2;
+      double *pybounds2 = ybounds2;
 
       gridInqXbounds(gridID1, xbounds1);
       gridInqYbounds(gridID1, ybounds1);
@@ -199,14 +185,14 @@ int gengrid(int gridID1, int lat1, int lat2, int lon11, int lon12, int lon21, in
       if ( gridtype == GRID_CURVILINEAR )
 	{
 	  gridDefNvertex(gridID2, 4);
-	  for ( ilat = lat1; ilat <= lat2; ilat++ )
+	  for ( int ilat = lat1; ilat <= lat2; ilat++ )
 	    {
-	      for ( ilon = 4*lon21; ilon < 4*(lon22+1); ilon++ )
+	      for ( int ilon = 4*lon21; ilon < 4*(lon22+1); ilon++ )
 		{
 		  *pxbounds2++ = xbounds1[4*ilat*nlon + ilon];
 		  *pybounds2++ = ybounds1[4*ilat*nlon + ilon];
 		}
-	      for ( ilon = 4*lon11; ilon < 4*(lon12+1); ilon++ )
+	      for ( int ilon = 4*lon11; ilon < 4*(lon12+1); ilon++ )
 		{
 		  *pxbounds2++ = xbounds1[4*ilat*nlon + ilon];
 		  *pybounds2++ = ybounds1[4*ilat*nlon + ilon];
@@ -216,9 +202,9 @@ int gengrid(int gridID1, int lat1, int lat2, int lon11, int lon12, int lon21, in
       else
 	{
 	  gridDefNvertex(gridID2, 2);
-	  for ( i = 2*lon21; i < 2*(lon22+1); i++ ) *pxbounds2++ = xbounds1[i];
-	  for ( i = 2*lon11; i < 2*(lon12+1); i++ ) *pxbounds2++ = xbounds1[i];
-	  for ( i = 2*lat1;  i < 2*(lat2+1);  i++ ) *pybounds2++ = ybounds1[i];
+	  for ( int i = 2*lon21; i < 2*(lon22+1); i++ ) *pxbounds2++ = xbounds1[i];
+	  for ( int i = 2*lon11; i < 2*(lon12+1); i++ ) *pxbounds2++ = xbounds1[i];
+	  for ( int i = 2*lat1;  i < 2*(lat2+1);  i++ ) *pybounds2++ = ybounds1[i];
 
 	  if ( strncmp(xunits, "degree", 6) == 0 )
 	    {
@@ -236,64 +222,60 @@ int gengrid(int gridID1, int lat1, int lat2, int lon11, int lon12, int lon21, in
       Free(ybounds2);
     }
 
-  return (gridID2);
+  int projID1 = gridInqProj(gridID1);
+  if ( projID1 != CDI_UNDEFID && gridInqType(projID1) == GRID_PROJECTION )
+    {
+      int projID2 = gridCreate(GRID_PROJECTION, nlon2*nlat2);
+      gridDefXsize(projID2, nlon2);
+      gridDefYsize(projID2, nlat2);
+
+      grid_copy_attributes(projID1, projID2);
+      grid_copy_mapping(projID1, projID2);
+
+      gengridxyvals(GRID_PROJECTION, projID1, projID2, nlon, nlat, nlon2, nlat2,
+                    lat1, lat2, lon11, lon12, lon21, lon22, NULL);
+
+      gridDefProj(gridID2, projID2);
+    }
+
+  return gridID2;
 }
 
-static
+
 int gengridcell(int gridID1, int gridsize2, int *cellidx)
 {
-  int i, k, nv;
-  char xname[CDI_MAX_NAME], xlongname[CDI_MAX_NAME], xunits[CDI_MAX_NAME];
-  char yname[CDI_MAX_NAME], ylongname[CDI_MAX_NAME], yunits[CDI_MAX_NAME];
-  double *xvals1 = NULL, *yvals1 = NULL;
-  double *xvals2 = NULL, *yvals2 = NULL;
-  double *xbounds1 = NULL, *ybounds1 = NULL;
-  double *xbounds2 = NULL, *ybounds2 = NULL;
-
+  int gridID2 = -1;
+  int gridtype  = gridInqType(gridID1);
   int gridsize1 = gridInqSize(gridID1);
+  int prec      = gridInqPrec(gridID1);
 
-  /* printf("gridsize1 = %d, gridsize2 = %d\n", gridsize1, gridsize2); */
+  if ( gridtype == GRID_CURVILINEAR ) gridtype = GRID_UNSTRUCTURED;
 
-  int gridtype = gridInqType(gridID1);
-  int prec     = gridInqPrec(gridID1);
-
-  int gridID2 = gridCreate(gridtype, gridsize2);
+  if ( gridtype == GRID_UNSTRUCTURED )
+    gridID2 = gridCreate(gridtype, gridsize2);
+  else
+    return gridID2;
 
   gridDefPrec(gridID2, prec);
 
-  gridInqXname(gridID1, xname);
-  gridInqXlongname(gridID1, xlongname);
-  gridInqXunits(gridID1, xunits);
-  gridInqYname(gridID1, yname);
-  gridInqYlongname(gridID1, ylongname);
-  gridInqYunits(gridID1, yunits);
-
-  gridDefXname(gridID2, xname);
-  gridDefXlongname(gridID2, xlongname);
-  gridDefXunits(gridID2, xunits);
-  gridDefYname(gridID2, yname);
-  gridDefYlongname(gridID2, ylongname);
-  gridDefYunits(gridID2, yunits);
+  grid_copy_attributes(gridID1, gridID2);
 
   if ( gridInqXvals(gridID1, NULL) && gridInqYvals(gridID1, NULL) )
     {
-      xvals1 = (double*) Malloc(gridsize1*sizeof(double));
-      yvals1 = (double*) Malloc(gridsize1*sizeof(double));
-      xvals2 = (double*) Malloc(gridsize2*sizeof(double));
-      yvals2 = (double*) Malloc(gridsize2*sizeof(double));
+      double *xvals1 = (double*) Malloc(gridsize1*sizeof(double));
+      double *yvals1 = (double*) Malloc(gridsize1*sizeof(double));
+      double *xvals2 = (double*) Malloc(gridsize2*sizeof(double));
+      double *yvals2 = (double*) Malloc(gridsize2*sizeof(double));
 
       gridInqXvals(gridID1, xvals1);
       gridInqYvals(gridID1, yvals1);
 
-      for ( i = 0; i < gridsize2; ++i )
+      for ( int i = 0; i < gridsize2; ++i )
 	{
 	  xvals2[i] = xvals1[cellidx[i]];
 	  yvals2[i] = yvals1[cellidx[i]];
 	}
 
-      if ( cdoVerbose )
-	for ( i = 0; i < gridsize2; i++ ) printf("lat/lon : %d %g %g\n", i+1, yvals2[i], xvals2[i]);
-
       gridDefXvals(gridID2, xvals2);
       gridDefYvals(gridID2, yvals2);
 
@@ -305,21 +287,21 @@ int gengridcell(int gridID1, int gridsize2, int *cellidx)
 
   if ( gridInqXbounds(gridID1, NULL) && gridInqYbounds(gridID1, NULL) )
     {
-      nv = gridInqNvertex(gridID1);
+      int nv = gridInqNvertex(gridID1);
 
-      xbounds1 = (double*) Malloc(nv*gridsize1*sizeof(double));
-      ybounds1 = (double*) Malloc(nv*gridsize1*sizeof(double));
-      xbounds2 = (double*) Malloc(nv*gridsize2*sizeof(double));
-      ybounds2 = (double*) Malloc(nv*gridsize2*sizeof(double));
+      double *xbounds1 = (double*) Malloc(nv*gridsize1*sizeof(double));
+      double *ybounds1 = (double*) Malloc(nv*gridsize1*sizeof(double));
+      double *xbounds2 = (double*) Malloc(nv*gridsize2*sizeof(double));
+      double *ybounds2 = (double*) Malloc(nv*gridsize2*sizeof(double));
 
       gridInqXbounds(gridID1, xbounds1);
       gridInqYbounds(gridID1, ybounds1);
 
       gridDefNvertex(gridID2, nv);
 
-      for ( i = 0; i < gridsize2; ++i )
+      for ( int i = 0; i < gridsize2; ++i )
 	{
-	  for ( k = 0; k < nv; ++k )
+	  for ( int k = 0; k < nv; ++k )
 	    {
 	      xbounds2[i*nv+k] = xbounds1[cellidx[i]*nv+k];
 	      ybounds2[i*nv+k] = ybounds1[cellidx[i]*nv+k];
@@ -335,15 +317,13 @@ int gengridcell(int gridID1, int gridsize2, int *cellidx)
       Free(ybounds2);
     }
 
-  return (gridID2);
+  return gridID2;
 }
 
 
 void genlonlatbox_reg(int gridID, double xlon1, double xlon2, double xlat1, double xlat2,
 		      int *lat1, int *lat2, int *lon11, int *lon12, int *lon21, int *lon22)
 {
-  int ilon, ilat;
-
   int nlon = gridInqXsize(gridID);
   int nlat = gridInqYsize(gridID);
 
@@ -362,8 +342,8 @@ void genlonlatbox_reg(int gridID, double xlon1, double xlon2, double xlat1, doub
   if ( strncmp(xunits, "radian", 6) == 0 ) xfact = RAD2DEG;
   if ( strncmp(yunits, "radian", 6) == 0 ) yfact = RAD2DEG;
 
-  for ( ilat = 0; ilat < nlat; ilat++ ) yvals[ilat] *= yfact;
-  for ( ilon = 0; ilon < nlon; ilon++ ) xvals[ilon] *= xfact;
+  for ( int ilat = 0; ilat < nlat; ilat++ ) yvals[ilat] *= yfact;
+  for ( int ilon = 0; ilon < nlon; ilon++ ) xvals[ilon] *= xfact;
 
   if ( IS_NOT_EQUAL(xlon1, xlon2) )
     {
@@ -433,12 +413,10 @@ void genlonlatbox_reg(int gridID, double xlon1, double xlon2, double xlat1, doub
     cdoAbort("Latitudinal dimension is too small!");
 }
 
-
+static
 void genlonlatbox_curv(int gridID, double xlon1, double xlon2, double xlat1, double xlat2,
                        int *lat1, int *lat2, int *lon11, int *lon12, int *lon21, int *lon22)
-{
-  int ilon, ilat;
-  
+{  
   int nlon = gridInqXsize(gridID);
   int nlat = gridInqYsize(gridID);
   int gridsize = nlon*nlat;
@@ -460,9 +438,6 @@ void genlonlatbox_curv(int gridID, double xlon1, double xlon2, double xlat1, dou
   if ( strncmp(xunits, "radian", 6) == 0 ) xfact = RAD2DEG;
   if ( strncmp(yunits, "radian", 6) == 0 ) yfact = RAD2DEG;
 
-  double xval, yval, xfirst, xlast, ylast;
-  int lp2 = FALSE;
-
   if ( xlon1 > xlon2 ) 
     cdoAbort("The second longitude have to be greater than the first one!");
 
@@ -472,7 +447,14 @@ void genlonlatbox_curv(int gridID, double xlon1, double xlon2, double xlat1, dou
       xlat1 = xlat2;
       xlat2 = xtemp;
     }
-	  
+  /*
+  printf("xlon1, xlon2 %g %g\n",xlon1, xlon2);
+  double x0 = 0;
+  for ( int ilat = 0; ilat < nlat; ilat++ ) if ( xvals[ilat*nlon] < x0 ) x0 = xvals[ilat*nlon];
+  xlon2 -= 360 * floor ((xlon1 - x0) / 360);
+  xlon1 -= 360 * floor ((xlon1 - x0) / 360);
+  printf("xlon1, xlon2 %g %g\n",xlon1, xlon2);
+  */	  
   *lat1 = nlat-1;
   *lat2 = 0;
   *lon11 = 0;
@@ -480,29 +462,31 @@ void genlonlatbox_curv(int gridID, double xlon1, double xlon2, double xlat1, dou
   *lon21 = nlon-1;
   *lon22 = 0;
 
-  for ( ilat = 0; ilat < nlat; ilat++ )
+  bool lp2 = false;
+  double xfirst, xlast, ylast;
+  if ( grid_is_circular )
     {
-      xlast = xfact * xvals[ilat*nlon + nlon-1];
-      ylast = yfact * yvals[ilat*nlon + nlon-1];
-      if ( ylast >= xlat1 && ylast <= xlat2 )
-        if ( grid_is_circular && xlon1 <= xlast && xlon2 > xlast && (xlon2-xlon1) < 360 )
-          {
-            *lon11 = nlon-1;
-            *lon12 = 0;
-            lp2 = TRUE;
-          }
+      for ( int ilat = 0; ilat < nlat; ilat++ )
+        {
+          xlast = xfact * xvals[ilat*nlon + nlon-1];
+          ylast = yfact * yvals[ilat*nlon + nlon-1];
+          if ( ylast >= xlat1 && ylast <= xlat2 )
+            if ( xlon1 <= xlast && xlon2 > xlast && (xlon2-xlon1) < 360 )
+              {
+                *lon11 = nlon-1;
+                *lon12 = 0;
+                lp2 = true;
+                break;
+              }
+        }
     }
 
-  for ( ilat = 0; ilat < nlat; ilat++ )
+  for ( int ilat = 0; ilat < nlat; ilat++ )
     {
-      for ( ilon = 0; ilon < nlon; ilon++ )
+      for ( int ilon = 0; ilon < nlon; ilon++ )
         {
-          xval = xvals[ilat*nlon + ilon];
-          yval = yvals[ilat*nlon + ilon];
-
-          xval *= xfact;
-          yval *= yfact;
-
+          double xval = xfact * xvals[ilat*nlon + ilon];
+          double yval = yfact * yvals[ilat*nlon + ilon];
           if ( yval >= xlat1 && yval <= xlat2 )
             {
               if ( lp2 )
@@ -544,7 +528,6 @@ void genlonlatbox_curv(int gridID, double xlon1, double xlon2, double xlat1, dou
         }
     }
 
-  // printf("lon11, lon12, lon21, lon22, lat1, lat2 %d %d %d %d %d %d\n", *lon11, *lon12, *lon21, *lon22, *lat1, *lat2);
   if ( *lon12 == 0 && *lon11 > 0 ) *lon11 = -1;
 
   if ( *lat2 - *lat1 + 1 <= 0 )
@@ -557,9 +540,9 @@ void genlonlatbox_curv(int gridID, double xlon1, double xlon2, double xlat1, dou
 
 void getlonlatparams(int argc_offset, double *xlon1, double *xlon2, double *xlat1, double *xlat2)
 {
-  int lset = FALSE;
-  int nargc = operatorArgc() - argc_offset;
+  bool lset = false;
 
+  int nargc = operatorArgc() - argc_offset;
   if ( nargc == 1 )
     {
       const char *gridname = operatorArgv()[argc_offset+0];
@@ -569,7 +552,7 @@ void getlonlatparams(int argc_offset, double *xlon1, double *xlon2, double *xlat
           *xlon2 =  60;
           *xlat1 =  30;
           *xlat2 =  80;
-          lset = TRUE;
+          lset = true;
         }
     }
 
@@ -605,66 +588,59 @@ void genlonlatbox(int argc_offset, int gridID, int *lat1, int *lat2, int *lon11,
 static
 int genlonlatgrid(int gridID1, int *lat1, int *lat2, int *lon11, int *lon12, int *lon21, int *lon22)
 {
-  int gridID2;
-
   genlonlatbox(0, gridID1, lat1, lat2, lon11, lon12, lon21, lon22);
 
-  gridID2 = gengrid(gridID1, *lat1, *lat2, *lon11, *lon12, *lon21, *lon22);
+  int gridID2 = gengrid(gridID1, *lat1, *lat2, *lon11, *lon12, *lon21, *lon22);
 
-  return (gridID2);
+  return gridID2;
 }
 
 static
 int gencellgrid(int gridID1, int *gridsize2, int **cellidx)
 {
-  int gridtype, gridID2;
-  double *xvals, *yvals;
-  double xlon1, xlon2, xlat1, xlat2, x, xval, yval;
-  int i, gridsize1;
-  int nvals = 0;
-  int maxcell = 0;
   int cellinc = 4096;
-  char xunits[CDI_MAX_NAME];
-  char yunits[CDI_MAX_NAME];
-  double xfact = 1, yfact = 1;
+  
   int argc_offset = 0;
-
   operatorCheckArgc(argc_offset+4);
 
-  xlon1 = parameter2double(operatorArgv()[argc_offset+0]);
-  xlon2 = parameter2double(operatorArgv()[argc_offset+1]);
-  xlat1 = parameter2double(operatorArgv()[argc_offset+2]);
-  xlat2 = parameter2double(operatorArgv()[argc_offset+3]);
+  double xlon1 = parameter2double(operatorArgv()[argc_offset+0]);
+  double xlon2 = parameter2double(operatorArgv()[argc_offset+1]);
+  double xlat1 = parameter2double(operatorArgv()[argc_offset+2]);
+  double xlat2 = parameter2double(operatorArgv()[argc_offset+3]);
 
+  double x;
   if ( xlon1 >= xlon2 ) { x = xlon1; xlon1 = xlon2; xlon2 = x; }
   if ( xlat1 >= xlat2 ) { x = xlat1; xlat1 = xlat2; xlat2 = x; }
 
-  gridtype = gridInqType(gridID1);
-
-  gridsize1 = gridInqSize(gridID1);
+  int gridtype = gridInqType(gridID1);
+  int gridsize1 = gridInqSize(gridID1);
 
   if ( gridtype != GRID_UNSTRUCTURED ) cdoAbort("Internal problem, wrong grid type!");
 
-  xvals = (double*) Malloc(gridsize1*sizeof(double));
-  yvals = (double*) Malloc(gridsize1*sizeof(double));
-
+  double *xvals = (double*) Malloc(gridsize1*sizeof(double));
+  double *yvals = (double*) Malloc(gridsize1*sizeof(double));
   gridInqXvals(gridID1, xvals);
   gridInqYvals(gridID1, yvals);
 
+  char xunits[CDI_MAX_NAME];
+  char yunits[CDI_MAX_NAME];
   gridInqXunits(gridID1, xunits);
   gridInqYunits(gridID1, yunits);
 
+  double xfact = 1, yfact = 1;
   if ( strncmp(xunits, "radian", 6) == 0 ) xfact = RAD2DEG;
   if ( strncmp(yunits, "radian", 6) == 0 ) yfact = RAD2DEG;
 
   /* find gridsize2 */
   *cellidx = NULL;
-  for ( i = 0; i < gridsize1; ++i )
+  int maxcell = 0;
+  int nvals = 0;
+  for ( int i = 0; i < gridsize1; ++i )
     {
-      xval = xvals[i]*xfact;
-      yval = yvals[i]*yfact;
+      double xval = xvals[i]*xfact;
+      double yval = yvals[i]*yfact;
       if ( yval >= xlat1 && yval <= xlat2 )
-	if ( (xval >= xlon1 && xval <= xlon2) ||
+	if ( (xval     >= xlon1 && xval     <= xlon2) ||
 	     (xval+360 >= xlon1 && xval+360 <= xlon2) ||
 	     (xval-360 >= xlon1 && xval-360 <= xlon2)  )
 	  {
@@ -685,9 +661,9 @@ int gencellgrid(int gridID1, int *gridsize2, int **cellidx)
   Free(xvals);
   Free(yvals);
 
-  gridID2 = gengridcell(gridID1, *gridsize2, *cellidx);
+  int gridID2 = gengridcell(gridID1, *gridsize2, *cellidx);
 
-  return (gridID2);
+  return gridID2;
 }
 
 
@@ -775,23 +751,19 @@ void genindexbox(int argc_offset, int gridID1, int *lat1, int *lat2, int *lon11,
 static
 int genindexgrid(int gridID1, int *lat1, int *lat2, int *lon11, int *lon12, int *lon21, int *lon22)
 {
-  int gridID2;
-
   genindexbox(0, gridID1, lat1, lat2, lon11, lon12, lon21, lon22);
 
-  gridID2 = gengrid(gridID1, *lat1, *lat2, *lon11, *lon12, *lon21, *lon22);
+  int gridID2 = gengrid(gridID1, *lat1, *lat2, *lon11, *lon12, *lon21, *lon22);
 
-  return (gridID2);
+  return gridID2;
 }
 
 static
 void window(int nwpv, double *array1, int gridID1, double *array2,
 	    long lat1, long lat2, long lon11, long lon12, long lon21, long lon22)
 {
-  long nlon;
   long ilat, ilon;
-
-  nlon = gridInqXsize(gridID1);
+  long nlon = gridInqXsize(gridID1);
 
   if ( nwpv == 2 )
     {
@@ -824,11 +796,9 @@ void window(int nwpv, double *array1, int gridID1, double *array2,
 static
 void window_cell(int nwpv, double *array1, int gridID1, double *array2, long gridsize2, int *cellidx)
 {
-  long i;
-
   if ( nwpv == 2 )
     {
-      for ( i = 0; i < gridsize2; ++i )
+      for ( long i = 0; i < gridsize2; ++i )
 	{
 	  array2[i*2]   = array1[cellidx[i]*2];
 	  array2[i*2+1] = array1[cellidx[i]*2+1];
@@ -836,7 +806,7 @@ void window_cell(int nwpv, double *array1, int gridID1, double *array2, long gri
     }
   else
     {
-      for ( i = 0; i < gridsize2; ++i )
+      for ( long i = 0; i < gridsize2; ++i )
 	array2[i] = array1[cellidx[i]];
     }
 }
@@ -845,12 +815,10 @@ void window_cell(int nwpv, double *array1, int gridID1, double *array2, long gri
 void *Selbox(void *argument)
 {
   int nrecs;
-  int recID, varID, levelID;
+  int varID, levelID;
   int gridID1 = -1, gridID2;
   int index, gridtype = -1;
   int nmiss;
-  int i;
-  int nwpv; // number of words per value; real:1  complex:2
   double missval;
   typedef struct {
     int gridID1, gridID2;
@@ -877,8 +845,8 @@ void *Selbox(void *argument)
   vlistDefTaxis(vlistID2, taxisID2);
 
   int nvars = vlistNvars(vlistID1);
-  int *vars  = (int *) Malloc(nvars*sizeof(int));
-  for ( varID = 0; varID < nvars; varID++ ) vars[varID] = FALSE;
+  bool *vars  = (bool*) Malloc(nvars*sizeof(bool));
+  for ( varID = 0; varID < nvars; varID++ ) vars[varID] = false;
 
   int ngrids = vlistNgrids(vlistID1);
   sbox_t *sbox = (sbox_t *) Malloc(ngrids*sizeof(sbox_t));
@@ -889,7 +857,8 @@ void *Selbox(void *argument)
       gridtype = gridInqType(gridID1);
 
       if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN || gridtype == GRID_CURVILINEAR ||
-	   (operatorID == SELINDEXBOX && (gridtype == GRID_GENERIC || gridtype == GRID_SINUSOIDAL) && 
+           (gridtype == GRID_PROJECTION && gridInqProjType(gridID1) == CDI_PROJ_RLL) ||
+	   (operatorID == SELINDEXBOX && gridtype == GRID_GENERIC && 
 	    gridInqXsize(gridID1) > 0 && gridInqYsize(gridID1) > 0) ||
 	   (operatorID == SELLONLATBOX && gridtype == GRID_UNSTRUCTURED) )
 	{
@@ -915,7 +884,7 @@ void *Selbox(void *argument)
 
 	  for ( varID = 0; varID < nvars; varID++ )
 	    if ( gridID1 == vlistInqVarGrid(vlistID1, varID) )
-	      vars[varID] = TRUE;
+	      vars[varID] = true;
 	}
       else if ( gridtype == GRID_GENERIC && gridInqXsize(gridID1) <= 1 && gridInqYsize(gridID1) <=1 )
 	{
@@ -941,7 +910,7 @@ void *Selbox(void *argument)
     }
 
   for ( varID = 0; varID < nvars; varID++ )
-    if ( vars[varID] == TRUE ) break;
+    if ( vars[varID] ) break;
 
   if ( varID >= nvars ) cdoWarning("No variables selected!");
 
@@ -964,7 +933,7 @@ void *Selbox(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, array1, &nmiss);
@@ -973,7 +942,8 @@ void *Selbox(void *argument)
 
 	  if ( vars[varID] )
 	    {
-	      nwpv    = vlistInqNWPV(vlistID1, varID);
+              // number of words per value; real:1  complex:2
+	      int nwpv = vlistInqNWPV(vlistID1, varID);
 	      
 	      gridID1 = vlistInqVarGrid(vlistID1, varID);
 
@@ -994,7 +964,7 @@ void *Selbox(void *argument)
 		{
 		  nmiss = 0;
 		  missval = vlistInqVarMissval(vlistID2, varID);
-		  for ( i = 0; i < gridsize2; i++ )
+		  for ( int i = 0; i < gridsize2; i++ )
 		    if ( DBL_IS_EQUAL(array2[i], missval) ) nmiss++;
 		}
 
diff --git a/src/Select.c b/src/Select.c
index 90e8f1d..4d0bc65 100644
--- a/src/Select.c
+++ b/src/Select.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -28,35 +28,10 @@
 #include "error.h"
 #include "util.h"
 #include "pmlist.h"
+#include "sellist.h"
 
-double datestr_to_double(const char *datestr, int opt);
-
-int vlist_get_psvarid(int vlistID, int zaxisID)
-{
-  int psvarid = -1;
-  char name[CDI_MAX_NAME];
-  char psname[CDI_MAX_NAME];
-  psname[0] = 0;
-  zaxisInqPsName(zaxisID, psname);
-
-  if ( psname[0] )
-    {
-      int nvars = vlistNvars(vlistID);
-      for ( int varID = 0; varID < nvars; ++varID )
-        {
-          vlistInqVarName(vlistID, varID, name);
-          if ( strcmp(name, psname) == 0 )
-            {
-              psvarid = varID;
-              break;
-            }
-        }
-      if ( cdoVerbose && psvarid == -1 )
-        cdoWarning("Surface pressure variable not found - %s", psname);
-    }
 
-  return psvarid;
-}
+double datestr_to_double(const char *datestr, int opt);
 
 static
 void write_const_vars(int streamID2, int vlistID2, int nvars, double **vardata2)
@@ -123,38 +98,40 @@ void *Select(void *argument)
   int nsel = operatorArgc();
   char **argnames = operatorArgv();
 
-  if ( cdoVerbose )
-    for ( int i = 0; i < nsel; ++i )
-      cdoPrint("name %d = %s", i+1, argnames[i]);
-
-  pml_t *pml = pml_create("SELECT");
-
-  PML_ADD_INT(pml, timestep_of_year, 4096, "Timestep of year");
-  PML_ADD_INT(pml, timestep,         4096, "Timestep");
-  PML_ADD_INT(pml, year,             1024, "Year");
-  PML_ADD_INT(pml, month,              32, "Month");
-  PML_ADD_INT(pml, day,                32, "Day");
-  PML_ADD_INT(pml, hour,               24, "Hour");
-  PML_ADD_INT(pml, minute,             60, "Minute");
-  PML_ADD_INT(pml, code,             1024, "Code number");
-  PML_ADD_INT(pml, levidx,           1024, "Level index");
-  PML_ADD_INT(pml, ltype,             256, "Level type");
-  PML_ADD_INT(pml, zaxisnum,          256, "Zaxis number");
-  PML_ADD_INT(pml, gridnum,           256, "Grid number");
-  PML_ADD_FLT(pml, level,            1024, "Level");
-  PML_ADD_WORD(pml, name,            1024, "Variable name");
-  PML_ADD_WORD(pml, param,           1024, "Parameter");
-  PML_ADD_WORD(pml, zaxisname,        256, "Zaxis name");
-  PML_ADD_WORD(pml, gridname,         256, "Grid name");
-  PML_ADD_WORD(pml, steptype,          32, "Time step type");
-  PML_ADD_WORD(pml, startdate,          1, "Start date");
-  PML_ADD_WORD(pml, enddate,            1, "End date");
-  PML_ADD_WORD(pml, season,            12, "Season");
-  PML_ADD_WORD(pml, date,            1024, "Date");
-
-  int status = pml_read(pml, nsel, argnames);
-  if ( cdoVerbose ) pml_print(pml);
-  if ( status != 0 ) cdoAbort("Parameter read error!");
+  if ( nsel == 0 ) cdoAbort("Parameter missing!");
+
+  list_t *kvlist = kvlist_new("SELECT");
+  if ( kvlist_parse_cmdline(kvlist, nsel, argnames) != 0 ) cdoAbort("Parse error!");
+  if ( cdoVerbose ) kvlist_print(kvlist);
+
+  sellist_t *sellist = sellist_create(kvlist);
+
+  SELLIST_ADD_INT(timestep_of_year, "Timestep of year");
+  SELLIST_ADD_INT(timestep,         "Timestep");
+  SELLIST_ADD_INT(year,             "Year");
+  SELLIST_ADD_INT(month,            "Month");
+  SELLIST_ADD_INT(day,              "Day");
+  SELLIST_ADD_INT(hour,             "Hour");
+  SELLIST_ADD_INT(minute,           "Minute");
+  SELLIST_ADD_INT(code,             "Code number");
+  SELLIST_ADD_INT(levidx,           "Level index");
+  SELLIST_ADD_INT(ltype,            "Level type");
+  SELLIST_ADD_INT(zaxisnum,         "Zaxis number");
+  SELLIST_ADD_INT(gridnum,          "Grid number");
+  SELLIST_ADD_FLT(level,            "Level");
+  SELLIST_ADD_WORD(name,            "Variable name");
+  SELLIST_ADD_WORD(param,           "Parameter");
+  SELLIST_ADD_WORD(zaxisname,       "Zaxis name");
+  SELLIST_ADD_WORD(gridname,        "Grid name");
+  SELLIST_ADD_WORD(steptype,        "Time step type");
+  SELLIST_ADD_WORD(startdate,       "Start date");
+  SELLIST_ADD_WORD(enddate,         "End date");
+  SELLIST_ADD_WORD(season,          "Season");
+  SELLIST_ADD_WORD(date,            "Date");
+
+  if ( cdoVerbose ) sellist_print(sellist);
+
+  sellist_verify(sellist);
 
   int streamCnt = cdoStreamCnt();
   int nfiles = streamCnt - 1;
@@ -177,7 +154,7 @@ void *Select(void *argument)
 
       if ( indf == 0 )
 	{
-          bool xresult = false;
+          bool xresult = true;
 
 	  // vlistID0 = vlistDuplicate(vlistID1);
 
@@ -196,19 +173,16 @@ void *Select(void *argument)
 		    vlistDefFlag(vlistID1, varID, levID, TRUE);
 		}
 	    }
-	  else if ( operatorID == SELECT )
-	    {
-	      xresult = true;
-	    }
 
-          bool lvarsel = PML_NOCC(pml, code) || PML_NOCC(pml, ltype) || PML_NOCC(pml, zaxisnum) ||
-            PML_NOCC(pml, gridnum) || PML_NOCC(pml, name) || PML_NOCC(pml, param) ||
-            PML_NOCC(pml, zaxisname) || PML_NOCC(pml, gridname) || PML_NOCC(pml, steptype);
-          bool llevsel = PML_NOCC(pml, level) || PML_NOCC(pml, levidx);
+          bool lvarsel = SELLIST_NVAL(code) || SELLIST_NVAL(ltype) || SELLIST_NVAL(zaxisnum) ||
+            SELLIST_NVAL(gridnum) || SELLIST_NVAL(name) || SELLIST_NVAL(param) ||
+            SELLIST_NVAL(zaxisname) || SELLIST_NVAL(gridname) || SELLIST_NVAL(steptype);
 
-	  ltimsel = PML_NOCC(pml, date) || PML_NOCC(pml, startdate) || PML_NOCC(pml, enddate) || PML_NOCC(pml, season) ||
-            PML_NOCC(pml, timestep_of_year) || PML_NOCC(pml, timestep) || PML_NOCC(pml, year) || PML_NOCC(pml, month) ||
-            PML_NOCC(pml, day) || PML_NOCC(pml, hour) || PML_NOCC(pml, minute);
+          bool llevsel = SELLIST_NVAL(level) || SELLIST_NVAL(levidx);
+
+	  ltimsel = SELLIST_NVAL(date) || SELLIST_NVAL(startdate) || SELLIST_NVAL(enddate) || SELLIST_NVAL(season) ||
+            SELLIST_NVAL(timestep_of_year) || SELLIST_NVAL(timestep) || SELLIST_NVAL(year) || SELLIST_NVAL(month) ||
+            SELLIST_NVAL(day) || SELLIST_NVAL(hour) || SELLIST_NVAL(minute);
           
 	  for ( varID = 0; varID < nvars; ++varID )
 	    {
@@ -225,7 +199,7 @@ void *Select(void *argument)
 	      int gridID  = vlistInqVarGrid(vlistID1, varID);
 	      int zaxisID = vlistInqVarZaxis(vlistID1, varID);
 	      int nlevs   = zaxisInqSize(zaxisID);
-	      ltype   = zaxis2ltype(zaxisID);
+	      ltype = zaxis2ltype(zaxisID);
 
               zaxisnum = vlistZaxisIndex(vlistID1, zaxisID)+1;
               int zaxistype = zaxisInqType(zaxisID);
@@ -251,19 +225,21 @@ void *Select(void *argument)
               else                                    steptype = "unknown";
               
 	      vars[varID] = false;
-              bool found_code  = PML_NOCC(pml, code)      && PML_CHECK_INT(pml, code);
-              bool found_name  = PML_NOCC(pml, name)      && PML_CHECK_WORD(pml, name);
-              bool found_param = PML_NOCC(pml, param)     && PML_CHECK_WORD(pml, param);
-              bool found_grid  = PML_NOCC(pml, gridnum)   && PML_CHECK_INT(pml, gridnum);
-              bool found_gname = PML_NOCC(pml, gridname)  && PML_CHECK_WORD(pml, gridname);
-              bool found_stype = PML_NOCC(pml, steptype)  && PML_CHECK_WORD(pml, steptype);
-              bool found_ltype = PML_NOCC(pml, ltype)     && PML_CHECK_INT(pml, ltype);
-              bool found_zaxis = PML_NOCC(pml, zaxisnum)  && PML_CHECK_INT(pml, zaxisnum);
-              bool found_zname = PML_NOCC(pml, zaxisname) && PML_CHECK_WORD(pml, zaxisname);
+
+              bool found_code  = SELLIST_CHECK(code);
+              bool found_name  = SELLIST_CHECK(name);
+              bool found_param = SELLIST_CHECK(param);
+              bool found_grid  = SELLIST_CHECK(gridnum);
+              bool found_gname = SELLIST_CHECK(gridname);
+              bool found_stype = SELLIST_CHECK(steptype);
+              bool found_ltype = SELLIST_CHECK(ltype);
+              bool found_zaxis = SELLIST_CHECK(zaxisnum);
+              bool found_zname = SELLIST_CHECK(zaxisname);
+
               bool lvar  = found_code || found_name || found_param;
-              bool lstep = PML_NOCC(pml, steptype) ? found_stype : true;
-              bool lgrid = (PML_NOCC(pml, gridnum) || PML_NOCC(pml, gridname)) ? (found_grid || found_gname) : true;
-              bool lvert = (PML_NOCC(pml, ltype) || PML_NOCC(pml, zaxisnum) || PML_NOCC(pml, zaxisname)) ? (found_ltype || found_zaxis || found_zname) : true;
+              bool lstep = SELLIST_NVAL(steptype) ? found_stype : true;
+              bool lgrid = (SELLIST_NVAL(gridnum) || SELLIST_NVAL(gridname)) ? (found_grid || found_gname) : true;
+              bool lvert = (SELLIST_NVAL(ltype) || SELLIST_NVAL(zaxisnum) || SELLIST_NVAL(zaxisname)) ? (found_ltype || found_zaxis || found_zname) : true;
 	     
               if ( !vars[varID] && lgrid && lvar ) vars[varID] = true;
               if ( !vars[varID] && lvert && lvar ) vars[varID] = true;
@@ -274,14 +250,14 @@ void *Select(void *argument)
                   if      ( found_grid || found_gname ) vars[varID] = true;
                   else if ( found_stype ) vars[varID] = true;
                   else if ( found_ltype || found_zaxis || found_zname ) vars[varID] = true;
-                  else if ( !lvarsel && (PML_NOCC(pml, levidx) || PML_NOCC(pml, level)) )
+                  else if ( !lvarsel && (SELLIST_NVAL(levidx) || SELLIST_NVAL(level)) )
                     {
                       for ( int levID = 0; levID < nlevs; ++levID )
                         {
                           levidx = levID + 1;
-                          level = zaxisInqLevel(zaxisID, levID);
-                          if ( !vars[varID] && PML_NOCC(pml, levidx) && PML_CHECK_INT(pml, levidx) ) vars[varID] = true;
-                          if ( !vars[varID] && PML_NOCC(pml, level)  && PML_CHECK_FLT(pml, level)  ) vars[varID] = true;
+                          level = cdoZaxisInqLevel(zaxisID, levID);
+                          if ( !vars[varID] && SELLIST_CHECK(levidx) ) vars[varID] = true;
+                          if ( !vars[varID] && SELLIST_CHECK(level)  ) vars[varID] = true;
                         }
                     }
                 }
@@ -309,22 +285,23 @@ void *Select(void *argument)
 		  for ( int levID = 0; levID < nlevs; ++levID )
 		    {
 		      levidx = levID + 1;
-		      level = zaxisInqLevel(zaxisID, levID);
+                      level = cdoZaxisInqLevel(zaxisID, levID);
 		      
 		      if ( nlevs == 1 && IS_EQUAL(level, 0) )
 			{
+                          SELLIST_CHECK(level);
 			  vlistDefFlag(vlistID1, varID, levID, xresult);
 			}
 		      else
 			{
-			  if ( PML_NOCC(pml, levidx) )
+			  if ( SELLIST_NVAL(levidx) )
 			    {
-			      if ( PML_CHECK_INT(pml, levidx) )
+			      if ( SELLIST_CHECK(levidx) )
 				vlistDefFlag(vlistID1, varID, levID, xresult);
 			    }
-			  else if ( PML_NOCC(pml, level) )
+			  else if ( SELLIST_NVAL(level) )
 			    {
-			      if ( PML_CHECK_FLT(pml, level) )
+			      if ( SELLIST_CHECK(level) )
 				vlistDefFlag(vlistID1, varID, levID, xresult);
 			    }
 			  else
@@ -336,17 +313,17 @@ void *Select(void *argument)
 		}
 	    }
 
-	  PML_CHECK_INT_FLAG(pml, code);
-	  PML_CHECK_INT_FLAG(pml, levidx);
-	  PML_CHECK_INT_FLAG(pml, ltype);
-	  PML_CHECK_INT_FLAG(pml, zaxisnum);
-	  PML_CHECK_INT_FLAG(pml, gridnum);
-	  PML_CHECK_FLT_FLAG(pml, level);
-	  PML_CHECK_WORD_FLAG(pml, name);
-	  PML_CHECK_WORD_FLAG(pml, param);
-	  PML_CHECK_WORD_FLAG(pml, zaxisname);
-	  PML_CHECK_WORD_FLAG(pml, gridname);
-	  PML_CHECK_WORD_FLAG(pml, steptype);
+	  SELLIST_CHECK_FLAG(code);
+	  SELLIST_CHECK_FLAG(levidx);
+	  SELLIST_CHECK_FLAG(ltype);
+	  SELLIST_CHECK_FLAG(zaxisnum);
+	  SELLIST_CHECK_FLAG(gridnum);
+	  SELLIST_CHECK_FLAG(level);
+	  SELLIST_CHECK_FLAG(name);
+	  SELLIST_CHECK_FLAG(param);
+	  SELLIST_CHECK_FLAG(zaxisname);
+	  SELLIST_CHECK_FLAG(gridname);
+	  SELLIST_CHECK_FLAG(steptype);
 
 	  int npar = 0;
 	  for ( varID = 0; varID < nvars; ++varID )
@@ -429,8 +406,7 @@ void *Select(void *argument)
 	      if ( varID == nvars2 ) ntsteps = 0;
 	    }
 
-	  ntsteps2 = ntsteps;
-	  if ( operatorID == SELECT && PML_NOCC(pml, timestep) == 1 ) ntsteps2 = 1;
+	  ntsteps2 = (operatorID == SELECT && SELLIST_NVAL(timestep) == 1) ? 1 : ntsteps;
 	  
 	  if ( ntsteps2 == 0 && nfiles > 1 )
 	    {
@@ -440,15 +416,18 @@ void *Select(void *argument)
 	    }
 
 	  // support for negative timestep values
-	  if ( PML_NOCC(pml, timestep) > 0 && ntsteps > 0 && nfiles == 1 )
+	  if ( SELLIST_NVAL(timestep) > 0 && ntsteps > 0 && nfiles == 1 )
 	    {
-	      for ( int i = 0; i < PML_NOCC(pml, timestep); ++i )
+	      for ( int i = 0; i < SELLIST_NVAL(timestep); ++i )
 		{
-		  if ( par_timestep[i] < 0 )
+                  int ptimestep;
+                  SELLIST_GET_VAL(timestep, i, &ptimestep);
+		  if ( ptimestep < 0 )
 		    {
 		      if ( cdoVerbose )
-			cdoPrint("timestep %d changed to %d", par_timestep[i], par_timestep[i] + ntsteps + 1);
-		      par_timestep[i] += ntsteps + 1;
+			cdoPrint("timestep %d changed to %d", ptimestep, ptimestep + ntsteps + 1);
+		      ptimestep += ntsteps + 1;
+                      SELLIST_DEF_VAL(timestep, i, &ptimestep);
 		    }
 		}
 	    }
@@ -460,10 +439,10 @@ void *Select(void *argument)
 	      array = (double*) Malloc(gridsize*sizeof(double));
 	    }
 
-	  startdate = par_startdate[0];
-	  enddate   = par_enddate[0];
-	  if ( PML_NOCC(pml, startdate) ) fstartdate = datestr_to_double(startdate, 0);
-	  if ( PML_NOCC(pml, enddate)   ) fenddate   = datestr_to_double(enddate, 1);
+	  SELLIST_GET_VAL(startdate, 0, &startdate);
+	  SELLIST_GET_VAL(enddate, 0, &enddate);
+	  if ( SELLIST_NVAL(startdate) ) fstartdate = datestr_to_double(startdate, 0);
+	  if ( SELLIST_NVAL(enddate)   ) fenddate   = datestr_to_double(enddate, 1);
 	}
       else
 	{
@@ -473,7 +452,7 @@ void *Select(void *argument)
 
       if ( nvars2 == 0 )
 	{
-	  cdoWarning("No resulting variables available!");
+	  cdoWarning("No variable selected!");
 	  goto END_LABEL;
 	}
 
@@ -494,11 +473,16 @@ void *Select(void *argument)
 	    {
 	      copytimestep = false;
 
-	      if ( operatorID == SELECT && PML_NOCC(pml, timestep) > 0 && timestep > par_timestep[PML_NOCC(pml, timestep)-1] )
+	      if ( operatorID == SELECT && SELLIST_NVAL(timestep) > 0 )
 		{
-		  lstop = true;
-		  break;
-		}
+                  int ptimestep;
+                  SELLIST_GET_VAL(timestep, SELLIST_NVAL(timestep)-1, &ptimestep);
+                  if ( timestep > ptimestep )
+                    {
+                      lstop = true;
+                      break;
+                    }
+                }
 
 	      int vdate = taxisInqVdate(taxisID1);
 	      int vtime = taxisInqVtime(taxisID1);
@@ -515,63 +499,51 @@ void *Select(void *argument)
 
 	      timestep_of_year++;
 
-	      if ( PML_NOCC(pml, timestep) && PML_CHECK_INT(pml, timestep) ) copytimestep = true;
-	      if ( PML_NOCC(pml, timestep_of_year) && PML_CHECK_INT(pml, timestep_of_year) ) copytimestep = true;
+	      if ( SELLIST_CHECK(timestep) ) copytimestep = true;
+	      if ( SELLIST_CHECK(timestep_of_year) ) copytimestep = true;
 
-	      if ( !copytimestep && PML_NOCC(pml, date) == 0 && PML_NOCC(pml, timestep) == 0 && PML_NOCC(pml, timestep_of_year) == 0 )
+	      if ( !copytimestep && SELLIST_NVAL(date) == 0 && SELLIST_NVAL(timestep) == 0 && SELLIST_NVAL(timestep_of_year) == 0 )
 		{
 		  bool lseason = false, lyear = false, lmonth = false, lday = false, lhour = false, lminute = false;
 
-		  if ( PML_NOCC(pml, season) == 0 || (PML_NOCC(pml, season) && PML_CHECK_SEASON(pml, season, month)) ) lseason   = true;
-		  if ( PML_NOCC(pml, year)   == 0 || (PML_NOCC(pml, year)   && PML_CHECK_INT(pml, year))   ) lyear   = true;
-		  if ( PML_NOCC(pml, month)  == 0 || (PML_NOCC(pml, month)  && PML_CHECK_INT(pml, month))  ) lmonth  = true;
-		  if ( PML_NOCC(pml, day)    == 0 || (PML_NOCC(pml, day)    && PML_CHECK_INT(pml, day))    ) lday    = true;
-		  if ( PML_NOCC(pml, hour)   == 0 || (PML_NOCC(pml, hour)   && PML_CHECK_INT(pml, hour))   ) lhour   = true;
-		  if ( PML_NOCC(pml, minute) == 0 || (PML_NOCC(pml, minute) && PML_CHECK_INT(pml, minute)) ) lminute = true;
+		  if ( SELLIST_NVAL(season) == 0 || SELLIST_CHECK_SEASON(season, month) ) lseason   = true;
+		  if ( SELLIST_NVAL(year)   == 0 || SELLIST_CHECK(year)   ) lyear   = true;
+		  if ( SELLIST_NVAL(month)  == 0 || SELLIST_CHECK(month)  ) lmonth  = true;
+		  if ( SELLIST_NVAL(day)    == 0 || SELLIST_CHECK(day)    ) lday    = true;
+		  if ( SELLIST_NVAL(hour)   == 0 || SELLIST_CHECK(hour)   ) lhour   = true;
+		  if ( SELLIST_NVAL(minute) == 0 || SELLIST_CHECK(minute) ) lminute = true;
 
 		  if ( lseason && lyear && lmonth && lday && lhour && lminute ) copytimestep = true;
 		}
 
 	      double fdate = ((double)vdate) + ((double)vtime)/1000000.;
 
-	      if ( PML_NOCC(pml, enddate) )
+	      if ( SELLIST_NVAL(enddate) )
 		{
+                  copytimestep = (fdate <= fenddate);
 		  if ( fdate > fenddate )
 		    {
-		      flag_enddate[0] = true;
-		      copytimestep = false;
+                      SELLIST_DEF_FLAG(enddate, 0, true);
 		      if ( operatorID == SELECT )
 			{
 			  lstop = true;
 			  break;
 			}
 		    }
-		  else
-		    {
-		      copytimestep = true;
-		    }
 		}
 
-	      if ( PML_NOCC(pml, startdate) )
+	      if ( SELLIST_NVAL(startdate) )
 		{
-		  if ( fdate < fstartdate )
-		    {
-		      copytimestep = false;
-		    }
-		  else
-		    {
-		      flag_startdate[0] = true;
-		      copytimestep = true;
-		    }
+                  copytimestep = (fdate >= fstartdate);
+		  if ( fdate >= fstartdate ) SELLIST_DEF_FLAG(startdate, 0, true);
 		}
 
-              
-              if ( PML_NOCC(pml, date) )
+              if ( SELLIST_NVAL(date) )
                 {
                   char vdatetimestr[64];
                   datetime2str(vdate, vtime, vdatetimestr, sizeof(vdatetimestr));
                   date = vdatetimestr;
-                  if ( PML_CHECK_DATE(pml, date) ) copytimestep = true;
+                  if ( SELLIST_CHECK_DATE(date) ) copytimestep = true;
                 }
 
 	      if ( operatorID == DELETE ) copytimestep = !copytimestep;
@@ -664,24 +636,25 @@ void *Select(void *argument)
 
   if ( !cdoVerbose && nfiles > 1 ) progressStatus(0, 1, 1);    
 
-  PML_CHECK_INT_FLAG(pml, timestep_of_year);
-  PML_CHECK_INT_FLAG(pml, timestep);
-  PML_CHECK_INT_FLAG(pml, year);
-  PML_CHECK_INT_FLAG(pml, month);
-  PML_CHECK_INT_FLAG(pml, day);
-  PML_CHECK_INT_FLAG(pml, hour);
-  PML_CHECK_INT_FLAG(pml, minute);
-  PML_CHECK_WORD_FLAG(pml, startdate);
-  //  PML_CHECK_WORD_FLAG(pml, enddate);
-  PML_CHECK_WORD_FLAG(pml, season);
-  PML_CHECK_WORD_FLAG(pml, date);
+  SELLIST_CHECK_FLAG(timestep_of_year);
+  SELLIST_CHECK_FLAG(timestep);
+  SELLIST_CHECK_FLAG(year);
+  SELLIST_CHECK_FLAG(month);
+  SELLIST_CHECK_FLAG(day);
+  SELLIST_CHECK_FLAG(hour);
+  SELLIST_CHECK_FLAG(minute);
+  SELLIST_CHECK_FLAG(startdate);
+  //  SELLIST_CHECK_FLAG(enddate);
+  SELLIST_CHECK_FLAG(season);
+  SELLIST_CHECK_FLAG(date);
 
   if ( streamID2 != CDI_UNDEFID ) streamClose(streamID2);
 
   vlistDestroy(vlistID0);
   vlistDestroy(vlistID2);
 
-  pml_destroy(pml);
+  sellist_destroy(sellist);
+  kvlist_destroy(kvlist);
 
   if ( array ) Free(array);
   if ( vars ) Free(vars);
diff --git a/src/Selindex.c b/src/Selindex.c
new file mode 100644
index 0000000..d81404a
--- /dev/null
+++ b/src/Selindex.c
@@ -0,0 +1,229 @@
+/*
+  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.
+*/
+
+/*
+   This module contains the following operators:
+
+      Selindex     selindex    Select grid indices
+*/
+
+#include <cdi.h>
+#include "cdo.h"
+#include "cdo_int.h"
+#include "grid.h"
+#include "listarray.h"
+#include "pstream.h"
+
+
+int gengridcell(int gridID1, int gridsize2, int *cellidx);
+
+static
+int genindexgrid(int gridID1, int gridsize2, int *cellidx)
+{
+  int gridID0 = gridID1;
+  int gridtype1 = gridInqType(gridID1);
+
+  if ( gridtype1 == GRID_LONLAT || gridtype1 == GRID_GAUSSIAN || gridtype1 == GRID_PROJECTION )
+    {
+      gridID1 = gridToCurvilinear(gridID1, 0);
+      gridtype1 = GRID_CURVILINEAR;
+    }
+
+  int gridID2 = -1;
+  if ( gridtype1 == GRID_UNSTRUCTURED || gridtype1 == GRID_CURVILINEAR )
+    gridID2 = gengridcell(gridID1, gridsize2, cellidx);
+
+  if ( gridID0 != gridID1 ) gridDestroy(gridID1);
+
+  return gridID2;
+}
+
+static
+void sel_index(double *array1, double *array2, int nind, int *indarr)
+{
+  for ( int i = 0; i < nind; ++i )
+    {
+      array2[i] = array1[indarr[i]];
+    }
+}
+
+
+void *Selindex(void *argument)
+{
+  int nrecs;
+  int varID, levelID;
+  int gridID1 = -1, gridID2;
+  int index, gridtype = -1;
+  int nmiss;
+  double missval;
+  typedef struct {
+    int gridID1, gridID2;
+  } sindex_t;
+  lista_t *ilista = lista_new(INT_LISTA);
+
+  cdoInitialize(argument);
+
+  cdoOperatorAdd("selindex", 0, 0, "grid cell indices (1-N)");
+
+  operatorInputArg(cdoOperatorEnter(0));
+
+  int nind = args2int_lista(operatorArgc(), operatorArgv(), ilista);
+  int *indarr = (int*) lista_dataptr(ilista);
+
+  int indmin = indarr[0];
+  int indmax = indarr[0];
+  for ( int i = 1; i < nind; i++ )
+    {
+      if ( indmax < indarr[i] ) indmax = indarr[i];
+      if ( indmin > indarr[i] ) indmin = indarr[i];
+    }
+
+  if ( cdoVerbose )
+    for ( int i = 0; i < nind; i++ )
+      cdoPrint("int %d = %d", i+1, indarr[i]);
+
+  if ( indmin < 1 ) cdoAbort("Index < 1 not allowed!");
+
+  for ( int i = 0; i < nind; i++ ) indarr[i] -= 1;
+
+
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
+
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
+  vlistDefTaxis(vlistID2, taxisID2);
+
+  int nvars = vlistNvars(vlistID1);
+  bool *vars  = (bool*) Malloc(nvars*sizeof(bool));
+  for ( varID = 0; varID < nvars; varID++ ) vars[varID] = false;
+
+  int ngrids = vlistNgrids(vlistID1);
+  sindex_t *sindex = (sindex_t *) Malloc(ngrids*sizeof(sindex_t));
+
+  for ( index = 0; index < ngrids; index++ )
+    {
+      gridID1  = vlistGrid(vlistID1, index);
+      gridtype = gridInqType(gridID1);
+
+      int gridsize = gridInqSize(gridID1);
+      if ( gridsize == 1 ) continue;
+      if ( indmax > gridsize )
+        {
+          cdoWarning("Max grid index is greater than grid size, skipped grid %d!", index+1);
+          continue;
+        }
+
+      gridID2 = genindexgrid(gridID1, nind, indarr);
+
+      if ( gridID2 == -1 )
+        {
+          cdoWarning("Unsupported grid type >%s<, skipped grid %d!", gridNamePtr(gridtype), index+1);
+          continue;
+        }
+	  
+      sindex[index].gridID1 = gridID1;
+      sindex[index].gridID2 = gridID2;
+
+      vlistChangeGridIndex(vlistID2, index, gridID2);
+
+      for ( varID = 0; varID < nvars; varID++ )
+        if ( gridID1 == vlistInqVarGrid(vlistID1, varID) )
+          vars[varID] = true;
+    }
+
+  for ( varID = 0; varID < nvars; varID++ )
+    if ( vars[varID] ) break;
+
+  if ( varID >= nvars ) cdoAbort("No variables selected!");
+
+  
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+
+  streamDefVlist(streamID2, vlistID2);
+
+  int gridsize = vlistGridsizeMax(vlistID1);
+  if ( vlistNumber(vlistID1) != CDI_REAL ) gridsize *= 2;
+  double *array1 = (double*) Malloc(gridsize*sizeof(double));
+
+  int gridsize2 = vlistGridsizeMax(vlistID2);
+  if ( vlistNumber(vlistID2) != CDI_REAL ) gridsize2 *= 2;
+  double *array2 = (double*) Malloc(gridsize2*sizeof(double));
+
+  int tsID = 0;
+  while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
+    {
+      taxisCopyTimestep(taxisID2, taxisID1);
+
+      streamDefTimestep(streamID2, tsID);
+	       
+      for ( int recID = 0; recID < nrecs; recID++ )
+	{
+	  streamInqRecord(streamID1, &varID, &levelID);
+	  streamReadRecord(streamID1, array1, &nmiss);
+
+	  streamDefRecord(streamID2, varID, levelID);
+
+	  if ( vars[varID] )
+	    {	      
+	      gridID1 = vlistInqVarGrid(vlistID1, varID);
+
+	      for ( index = 0; index < ngrids; index++ )
+		if ( gridID1 == sindex[index].gridID1 ) break;
+
+	      if ( index == ngrids ) cdoAbort("Internal problem, grid not found!");
+
+	      gridsize2 = gridInqSize(sindex[index].gridID2);
+
+              sel_index(array1, array2, nind, indarr); 
+
+	      if ( nmiss )
+		{
+		  nmiss = 0;
+		  missval = vlistInqVarMissval(vlistID2, varID);
+		  for ( int i = 0; i < gridsize2; i++ )
+		    if ( DBL_IS_EQUAL(array2[i], missval) ) nmiss++;
+		}
+
+	      streamWriteRecord(streamID2, array2, nmiss);
+	    }
+	  else
+	    {
+	      streamWriteRecord(streamID2, array1, nmiss);
+	    }
+	}
+      tsID++;
+    }
+
+  streamClose(streamID2);
+  streamClose(streamID1);
+
+  vlistDestroy(vlistID2);
+
+  if ( vars   ) Free(vars);
+  if ( array2 ) Free(array2);
+  if ( array1 ) Free(array1);
+  if ( sindex ) Free(sindex);
+
+  lista_destroy(ilista);
+
+  cdoFinish();
+
+  return 0;
+}
diff --git a/src/Seloperator.c b/src/Seloperator.c
index 65fbfdc..5d57239 100644
--- a/src/Seloperator.c
+++ b/src/Seloperator.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -24,13 +24,13 @@
 void *Seloperator(void *argument)
 {
   int nrecs;
-  int recID, varID, levelID;
-  double slevel = 0, level;
+  int varID, levelID;
   int nlevs, code, zaxisID, selfound = FALSE;
   int levID, ltype = 0;
   int varID2, levelID2;
   int sellevel, selcode, selltype;
   int gridsize, nmiss;
+  double slevel = 0, level;
   double *array = NULL;
 
   cdoInitialize(argument);
@@ -60,7 +60,7 @@ void *Seloperator(void *argument)
 
       for ( levID = 0; levID < nlevs; levID++ )
 	{
-	  level = zaxisInqLevel(zaxisID, levID);
+	  level = cdoZaxisInqLevel(zaxisID, levID);
 
 	  if ( operatorArgc() == 3 )
 	    sellevel = IS_EQUAL(level, slevel);
@@ -112,7 +112,7 @@ void *Seloperator(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  if ( vlistInqFlag(vlistID1, varID, levelID) == TRUE )
diff --git a/src/Selrec.c b/src/Selrec.c
index 43b819c..1213e2f 100644
--- a/src/Selrec.c
+++ b/src/Selrec.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -27,21 +27,14 @@
 #include "pstream.h"
 #include "error.h"
 #include "util.h"
-#include "list.h"
+#include "listarray.h"
 
 
 void *Selrec(void *argument)
 {
-  int streamID1, streamID2;
-  int tsID, nrecs;
-  int recID, varID, levelID;
-  int *intarr, nsel = 0;
-  int vlistID1 = -1, vlistID2 = -1;
-  int i;
-  int recordID;
-  int filetype;
-  int taxisID1, taxisID2;
-  LIST *ilist = listNew(INT_LIST);
+  int nrecs;
+  int varID, levelID;
+  lista_t *ilista = lista_new(INT_LISTA);
 
   cdoInitialize(argument);
 
@@ -49,48 +42,48 @@ void *Selrec(void *argument)
 
   operatorInputArg("records");
 
-  nsel = args2intlist(operatorArgc(), operatorArgv(), ilist);
+  int nsel = args2int_lista(operatorArgc(), operatorArgv(), ilista);
 
-  intarr = (int *) listArrayPtr(ilist);
+  int *intarr = (int *) lista_dataptr(ilista);
 
   if ( cdoVerbose )
     {
-      for ( i = 0; i < nsel; i++ )
+      for ( int i = 0; i < nsel; i++ )
 	cdoPrint("intarr entry: %d %d", i, intarr[i]);
     }
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  filetype = streamInqFiletype(streamID1);
+  int filetype = streamInqFiletype(streamID1);
 
-  if ( filetype == FILETYPE_NC || filetype == FILETYPE_NC2 || filetype == FILETYPE_NC4 || filetype == FILETYPE_NC4C )
+  if ( filetype == CDI_FILETYPE_NC || filetype == CDI_FILETYPE_NC2 || filetype == CDI_FILETYPE_NC4 || filetype == CDI_FILETYPE_NC4C )
     cdoAbort("This operator does not work on NetCDF data!");
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  recordID = 0;
-  tsID = 0;
+  int recordID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
 
       streamDefTimestep(streamID2, tsID);
      
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  recordID++;
 	  streamInqRecord(streamID1, &varID, &levelID);
 
-	  for ( i = 0; i < nsel; i++ )
+	  for ( int i = 0; i < nsel; i++ )
 	    {
 	      if ( recordID == intarr[i] )
 		{
@@ -108,7 +101,7 @@ void *Selrec(void *argument)
   streamClose(streamID2);
   streamClose(streamID1);
 
-  listDelete(ilist);
+  lista_destroy(ilista);
 
   cdoFinish();
 
diff --git a/src/Seltime.c b/src/Seltime.c
index cd7516a..a4d58fa 100644
--- a/src/Seltime.c
+++ b/src/Seltime.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -29,7 +29,6 @@
       Seltime    selsmon         Select single month
 */
 
-#include <ctype.h>
 
 #include <cdi.h>
 #include "cdo.h"
@@ -37,7 +36,7 @@
 #include "pstream.h"
 #include "error.h"
 #include "util.h"
-#include "list.h"
+#include "listarray.h"
 
 
 void season_to_months(const char *season, int *imonths)
@@ -64,7 +63,7 @@ void season_to_months(const char *season, int *imonths)
 }
 
 static
-int seaslist(LIST *ilist)
+int seaslist(lista_t *ilista)
 {
   int imon[13]; /* 1-12 ! */
   for ( int i = 0; i < 13; ++i ) imon[i] = 0;
@@ -89,7 +88,7 @@ int seaslist(LIST *ilist)
     }
 
   nsel = 0;
-  for ( int i = 1; i < 13; ++i ) if ( imon[i] ) listSetInt(ilist, nsel++, i);
+  for ( int i = 1; i < 13; ++i ) if ( imon[i] ) lista_set_int(ilista, nsel++, i);
 
   return nsel;
 }
@@ -125,9 +124,9 @@ double datestr_to_double(const char *datestr, int opt)
 }
 
 static
-int datelist(LIST *flist)
+int datelist(lista_t *flista)
 {
-  int set2 = TRUE;
+  bool set2 = true;
   double fval = 0;
 
   int nsel = operatorArgc();
@@ -143,28 +142,28 @@ int datelist(LIST *flist)
 	  else
 	    fval =  99999999999.;
 
-	  listSetFlt(flist, i,  fval);
+	  lista_set_flt(flista, i,  fval);
 	}
       else
 	{
 	  fval = datestr_to_double(operatorArgv()[i], 0);
 	  if ( strchr(operatorArgv()[i], 'T') )
-	    set2 = FALSE;
+	    set2 = false;
 	  else if ( nsel > 1 && i > 0 )
 	    fval += 0.999;
 	}
 
-      listSetFlt(flist, i, fval);
+      lista_set_flt(flista, i, fval);
     }
 
-  if ( nsel == 1 && set2 == TRUE )
+  if ( nsel == 1 && set2 )
     {
       fval += 0.999;
-      listSetFlt(flist, nsel, fval);
+      lista_set_flt(flista, nsel, fval);
       nsel = 2;
     }
 
-  return (nsel);
+  return nsel;
 }
 
 
@@ -182,15 +181,15 @@ void *Seltime(void *argument)
   int its1 = 0, its2 = 0;
   double selfval = 0;
   double *array = NULL;
-  LIST *ilist = listNew(INT_LIST);
-  LIST *flist = listNew(FLT_LIST);
+  lista_t *ilista = lista_new(INT_LISTA);
+  lista_t *flista = lista_new(FLT_LISTA);
   bool copy_nts2 = false;
   bool lconstout = false;
   bool process_nts1 = false, process_nts2 = false;
   bool *selfound = NULL;
   int *vdate_list = NULL, *vtime_list = NULL;
   double *single;
-  field_t ***vars = NULL;
+  field_type ***vars = NULL;
 
   cdoInitialize(argument);
 
@@ -214,11 +213,11 @@ void *Seltime(void *argument)
 
   if ( operatorID == SELSEASON )
     {
-      nsel = seaslist(ilist);
+      nsel = seaslist(ilista);
     }
   else if ( operatorID == SELDATE )
     {
-      nsel = datelist(flist);
+      nsel = datelist(flista);
     }
   else if ( operatorID == SELTIME )
     {
@@ -229,23 +228,23 @@ void *Seltime(void *argument)
 	  if ( strchr(operatorArgv()[i], ':') )
 	    {
 	      sscanf(operatorArgv()[i], "%d:%d:%d", &hour, &minute, &second);
-	      listSetInt(ilist, i, cdiEncodeTime(hour, minute, second));
+	      lista_set_int(ilista, i, cdiEncodeTime(hour, minute, second));
 	    }
 	  else
 	    {
-	      listSetInt(ilist, i, parameter2int(operatorArgv()[i]));
+	      lista_set_int(ilista, i, parameter2int(operatorArgv()[i]));
 	    }
 	}
     }
   else
     {
-      nsel = args2intlist(operatorArgc(), operatorArgv(), ilist);
+      nsel = args2int_lista(operatorArgc(), operatorArgv(), ilista);
     }
 
   if ( nsel < 1 ) cdoAbort("No timestep selected!");
 
-  int *intarr = (int *) listArrayPtr(ilist);
-  double *fltarr = (double *) listArrayPtr(flist);
+  int *intarr = (int *) lista_dataptr(ilista);
+  double *fltarr = (double *) lista_dataptr(flista);
 
   if ( operatorID == SELSMON )
     {
@@ -330,7 +329,7 @@ void *Seltime(void *argument)
 	  nts1 = 1;
 	}
 
-      vars  = (field_t ***) Malloc(nts1*sizeof(field_t **));
+      vars  = (field_type ***) Malloc(nts1*sizeof(field_type **));
 
       for ( int tsID = 0; tsID < nts1; tsID++ )
 	{
@@ -648,7 +647,8 @@ void *Seltime(void *argument)
 
   if ( selfound ) Free(selfound);
 
-  listDelete(ilist);
+  lista_destroy(ilista);
+  lista_destroy(flista);
 
   if ( lnts1 || nconst )
     {
diff --git a/src/Selvar.c b/src/Selvar.c
index 0f35e12..87859da 100644
--- a/src/Selvar.c
+++ b/src/Selvar.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -33,7 +33,6 @@
       Selvar     selltype        Select GRIB level type 
 */
 
-#include <ctype.h>  /* isdigit */
 
 #include <cdi.h>
 #include "cdo.h"
@@ -41,7 +40,7 @@
 #include "pstream.h"
 #include "error.h"
 #include "util.h"
-#include "list.h"
+#include "listarray.h"
 
 
 void *Selvar(void *argument)
@@ -59,8 +58,8 @@ void *Selvar(void *argument)
   char **argnames = NULL;
   int nmiss;
   int gridnum = 0;
-  LIST *ilist = listNew(INT_LIST);
-  LIST *flist = listNew(FLT_LIST);
+  lista_t *ilista = lista_new(INT_LISTA);
+  lista_t *flista = lista_new(FLT_LISTA);
 
   cdoInitialize(argument);
 
@@ -105,8 +104,8 @@ void *Selvar(void *argument)
     }
   else if ( TAKES_FLOATS(operatorID) )
     {
-      nsel = args2fltlist(operatorArgc(), operatorArgv(), flist);
-      fltarr = (double *) listArrayPtr(flist);
+      nsel = args2flt_lista(operatorArgc(), operatorArgv(), flista);
+      fltarr = (double *) lista_dataptr(flista);
 
       if ( cdoVerbose )
 	for ( int i = 0; i < nsel; i++ )
@@ -114,8 +113,8 @@ void *Selvar(void *argument)
     }
   else
     {
-      nsel = args2intlist(operatorArgc(), operatorArgv(), ilist);
-      intarr = (int *) listArrayPtr(ilist);
+      nsel = args2int_lista(operatorArgc(), operatorArgv(), ilista);
+      intarr = (int *) lista_dataptr(ilista);
 
       if ( cdoVerbose )
 	for ( int i = 0; i < nsel; i++ )
@@ -164,7 +163,7 @@ void *Selvar(void *argument)
   vlistClearFlag(vlistID1);
   for ( varID = 0; varID < nvars; varID++ )
     {
-      vars[varID] = ldelete ? true : false;
+      vars[varID] = ldelete;
 
       vlistInqVarName(vlistID1, varID, varname);
       vlistInqVarStdname(vlistID1, varID, stdname);
@@ -184,77 +183,44 @@ void *Selvar(void *argument)
 
       for ( int levID = 0; levID < nlevs; levID++ )
 	{
-	  double level = zaxisInqLevel(zaxisID, levID);
+	  double level = cdoZaxisInqLevel(zaxisID, levID);
 
 	  if ( ldelete ) vlistDefFlag(vlistID1, varID, levID, TRUE);
           
 	  for ( int isel = 0; isel < nsel; isel++ )
 	    {
               bool found = false;
-	      if ( operatorID == SELCODE )
-		{
-		  found = intarr[isel] == code;
-		}
+	      if ( operatorID == SELCODE ) found = intarr[isel] == code;
 	      else if ( operatorID == SELPARAM )
-		{
-		  found = wildcardmatch(argnames[isel], paramstr) == 0;
-		}
+                found = wildcardmatch(argnames[isel], paramstr) == 0;
 	      else if ( operatorID == SELNAME )
-		{
-		  found = wildcardmatch(argnames[isel], varname) == 0;
-		}
+                found = wildcardmatch(argnames[isel], varname) == 0;
 	      else if ( operatorID == SELSTDNAME )
-		{
-		  found = wildcardmatch(argnames[isel], stdname) == 0;
-		}
+                found = wildcardmatch(argnames[isel], stdname) == 0;
 	      else if ( operatorID == SELLEVEL )
-		{
-		  found = fabs(fltarr[isel] - level) < 0.0001;
-		}
+                found = fabs(fltarr[isel] - level) < 0.0001;
 	      else if ( operatorID == SELLEVIDX )
-		{
-		  found = intarr[isel] == (levID+1);
-		}
+                found = intarr[isel] == (levID+1);
 	      else if ( operatorID == SELGRID && args_are_numeric )
-		{
-		  found = intarr[isel] == (grididx+1);
-		}
+                found = intarr[isel] == (grididx+1);
 	      else if ( operatorID == SELGRID && !args_are_numeric )
-		{
-		  found = memcmp(argnames[isel], gridname, strlen(argnames[isel])) == 0;
-		}
+                found = memcmp(argnames[isel], gridname, strlen(argnames[isel])) == 0;
 	      else if ( operatorID == SELZAXIS && args_are_numeric )
-		{
-		  found = intarr[isel] == (zaxisidx+1);
-		}
+                found = intarr[isel] == (zaxisidx+1);
 	      else if ( operatorID == SELZAXIS && !args_are_numeric )
-		{
-		  found = memcmp(argnames[isel], zaxistypename, strlen(argnames[isel])) == 0;
-		}
+                found = memcmp(argnames[isel], zaxistypename, strlen(argnames[isel])) == 0;
 	      else if ( operatorID == SELZAXISNAME )
-		{
-		  found = wildcardmatch(argnames[isel], zaxisname) == 0;
-		}
+                found = wildcardmatch(argnames[isel], zaxisname) == 0;
 	      else if ( operatorID == SELTABNUM )
-		{
-		  found = intarr[isel] == tabnum;
-		}
+                found = intarr[isel] == tabnum;
 	      else if ( operatorID == DELCODE )
-		{
-		  found = intarr[isel] == code;
-		}
+                found = intarr[isel] == code;
 	      else if ( operatorID == DELNAME )
-		{
-		  found = wildcardmatch(argnames[isel], varname) == 0;
-		}
+                found = wildcardmatch(argnames[isel], varname) == 0;
 	      else if ( operatorID == DELPARAM )
-		{
-		  found = strcmp(argnames[isel], paramstr) == 0;
-		}
+                found = strcmp(argnames[isel], paramstr) == 0;
 	      else if ( operatorID == SELLTYPE )
-		{
-		  found = intarr[isel] == zaxis2ltype(zaxisID);
-		}
+                found = intarr[isel] == zaxis2ltype(zaxisID);
 
 	      if ( found )
 	        {
@@ -291,57 +257,31 @@ void *Selvar(void *argument)
       if ( selfound[isel] == false )
 	{
 	  if ( operatorID == SELCODE || operatorID == DELCODE )
-	    {
-	      cdoWarning("Code number %d not found!", intarr[isel]);
-	    }
+            cdoWarning("Code number %d not found!", intarr[isel]);
 	  else if ( operatorID == SELPARAM || operatorID == DELPARAM )
-	    {
-	      cdoWarning("Parameter %s not found!", argnames[isel]);
-	    }
+            cdoWarning("Parameter %s not found!", argnames[isel]);
 	  else if ( operatorID == SELNAME || operatorID == DELNAME )
-	    {
-	      cdoWarning("Variable name %s not found!", argnames[isel]);
-	    }
+            cdoWarning("Variable name %s not found!", argnames[isel]);
 	  else if ( operatorID == SELSTDNAME )
-	    {
-	      cdoWarning("Variable with standard name %s not found!", argnames[isel]);
-	    }
+            cdoWarning("Variable with standard name %s not found!", argnames[isel]);
 	  else if ( operatorID == SELLEVEL )
-	    {
-	      cdoWarning("Level %g not found!", fltarr[isel]);
-	    }
+            cdoWarning("Level %g not found!", fltarr[isel]);
 	  else if ( operatorID == SELLEVIDX )
-	    {
-	      cdoWarning("Level index %d not found!", intarr[isel]);
-	    }
+            cdoWarning("Level index %d not found!", intarr[isel]);
 	  else if ( operatorID == SELGRID && args_are_numeric )
-	    {
-	      cdoWarning("Grid %d not found!", intarr[isel]);
-	    }
+            cdoWarning("Grid %d not found!", intarr[isel]);
 	  else if ( operatorID == SELGRID && !args_are_numeric )
-	    {
-	      cdoWarning("Grid name %s not found!", argnames[isel]);
-	    }
+            cdoWarning("Grid name %s not found!", argnames[isel]);
 	  else if ( operatorID == SELZAXIS && args_are_numeric )
-	    {
-	      cdoWarning("Zaxis %d not found!", intarr[isel]);
-	    }
+            cdoWarning("Zaxis %d not found!", intarr[isel]);
 	  else if ( operatorID == SELZAXIS && !args_are_numeric )
-	    {
-	      cdoWarning("Zaxis type %s not found!", argnames[isel]);
-	    }
+            cdoWarning("Zaxis type %s not found!", argnames[isel]);
 	  else if ( operatorID == SELZAXISNAME )
-	    {
-	      cdoWarning("Zaxis name %s not found!", argnames[isel]);
-	    }
+            cdoWarning("Zaxis name %s not found!", argnames[isel]);
 	  else if ( operatorID == SELTABNUM )
-	    {
-	      cdoWarning("Table number %d not found!", intarr[isel]);
-	    }
+            cdoWarning("Table number %d not found!", intarr[isel]);
 	  else if ( operatorID == SELLTYPE )
-	    {
-	      cdoWarning("GRIB level type %d not found!", intarr[isel]);
-	    }
+            cdoWarning("GRIB level type %d not found!", intarr[isel]);
 	}
     }
 
@@ -416,8 +356,8 @@ void *Selvar(void *argument)
 
   if ( selfound ) Free(selfound);
 
-  listDelete(ilist);
-  listDelete(flist);
+  lista_destroy(ilista);
+  lista_destroy(flista);
 
   cdoFinish();
 
diff --git a/src/Set.c b/src/Set.c
index dbfeca3..f0be92a 100644
--- a/src/Set.c
+++ b/src/Set.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -33,49 +33,40 @@
 
 int stringToParam(const char *paramstr)
 {
-  int param = 0;
   int pnum = -1, pcat = 255, pdis = 255;
-
   sscanf(paramstr, "%d.%d.%d", &pnum, &pcat, &pdis);
   
   if ( cdoVerbose ) cdoPrint("pnum, pcat, pdis: %d.%d.%d", pnum, pcat, pdis);
 
-  param = cdiEncodeParam(pnum, pcat, pdis);
+  int param = cdiEncodeParam(pnum, pcat, pdis);
 
-  return (param);
+  return param;
 }
 
 
 void *Set(void *argument)
 {
-  int SETCODE, SETPARAM, SETNAME, SETUNIT, SETLEVEL, SETLTYPE, SETTABNUM;
-  int operatorID;
-  int streamID1, streamID2 = CDI_UNDEFID;
   int nrecs, nvars, newval = -1, tabnum = 0;
-  int tsID1, recID, varID, levelID;
-  int vlistID1, vlistID2;
-  int taxisID1, taxisID2;
+  int varID, levelID;
   int nmiss;
-  int gridsize;
   int index, zaxisID1, zaxisID2, nzaxis, nlevs;
   int zaxistype;
   int newparam    = 0;
   char *newname   = NULL, *newunit = NULL;
   double newlevel = 0;
   double *levels  = NULL;
-  double *array   = NULL;
 
   cdoInitialize(argument);
 
-  SETCODE    = cdoOperatorAdd("setcode",    0, 0, "code number");
-  SETPARAM   = cdoOperatorAdd("setparam",   0, 0, "parameter identifier (format: code[.tabnum] or num[.cat[.dis]])");
-  SETNAME    = cdoOperatorAdd("setname",    0, 0, "variable name");
-  SETUNIT    = cdoOperatorAdd("setunit",    0, 0, "variable unit");
-  SETLEVEL   = cdoOperatorAdd("setlevel",   0, 0, "level");
-  SETLTYPE   = cdoOperatorAdd("setltype",   0, 0, "GRIB level type");
-  SETTABNUM  = cdoOperatorAdd("settabnum",  0, 0, "GRIB table number");
+  int SETCODE    = cdoOperatorAdd("setcode",    0, 0, "code number");
+  int SETPARAM   = cdoOperatorAdd("setparam",   0, 0, "parameter identifier (format: code[.tabnum] or num[.cat[.dis]])");
+  int SETNAME    = cdoOperatorAdd("setname",    0, 0, "variable name");
+  int SETUNIT    = cdoOperatorAdd("setunit",    0, 0, "variable unit");
+  int SETLEVEL   = cdoOperatorAdd("setlevel",   0, 0, "level");
+  int SETLTYPE   = cdoOperatorAdd("setltype",   0, 0, "GRIB level type");
+  int SETTABNUM  = cdoOperatorAdd("settabnum",  0, 0, "GRIB table number");
 
-  operatorID = cdoOperatorID();
+  int operatorID = cdoOperatorID();
 
   operatorInputArg(cdoOperatorEnter(operatorID));
   if ( operatorID == SETCODE || operatorID == SETLTYPE )
@@ -103,14 +94,14 @@ void *Set(void *argument)
       newlevel = parameter2double(operatorArgv()[0]);
     }
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
   /* vlistPrint(vlistID2);*/
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
   if ( operatorID == SETCODE )
@@ -148,7 +139,7 @@ void *Set(void *argument)
 	  zaxisID2 = zaxisDuplicate(zaxisID1);
 	  nlevs = zaxisInqSize(zaxisID2);
 	  levels = (double*) Malloc(nlevs*sizeof(double));
-	  zaxisInqLevels(zaxisID2, levels);
+	  cdoZaxisInqLevels(zaxisID2, levels);
 	  levels[0] = newlevel;
 	  zaxisDefLevels(zaxisID2, levels);
 	  vlistChangeZaxis(vlistID2, zaxisID1, zaxisID2);
@@ -171,22 +162,21 @@ void *Set(void *argument)
     }
 
   /* vlistPrint(vlistID2);*/
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
   if ( vlistNumber(vlistID1) != CDI_REAL ) gridsize *= 2;
-  array = (double*) Malloc(gridsize*sizeof(double));
+  double *array = (double*) Malloc(gridsize*sizeof(double));
 
-  tsID1 = 0;
+  int tsID1 = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID1)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
-
       streamDefTimestep(streamID2, tsID1);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamDefRecord(streamID2,  varID,  levelID);
diff --git a/src/Setattribute.c b/src/Setattribute.c
new file mode 100644
index 0000000..ea6ee90
--- /dev/null
+++ b/src/Setattribute.c
@@ -0,0 +1,277 @@
+/*
+  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 <cdi.h>
+#include "cdo.h"
+#include "cdo_int.h"
+#include "pstream.h"
+
+
+static
+void set_attributes(list_t *kvlist, int vlistID)
+{
+  enum {Undefined=-99};
+  const int delim = '@';
+  int nvars = vlistNvars(vlistID);
+  int ngrids = vlistNgrids(vlistID);
+  int nzaxis = vlistNzaxis(vlistID);
+  int maxvars = nvars+ngrids*2+nzaxis;
+  int *varIDs = (int*) Malloc(maxvars*sizeof(int));
+
+  int kvn = list_size(kvlist);
+  char **wname = (char**) Malloc(kvn*sizeof(char*));
+  for ( int i = 0; i < kvn; ++i ) wname[i] = NULL;
+
+  char name[CDI_MAX_NAME];
+  char buffer[CDI_MAX_NAME];
+  for ( listNode_t *kvnode = kvlist->head; kvnode; kvnode = kvnode->next )
+    {
+      char *varname = NULL, *attname = NULL;
+      keyValues_t *kv = *(keyValues_t **)kvnode->data;
+      strcpy(buffer, kv->key);
+      char *result = strrchr(buffer, delim);
+      if ( result == NULL )
+        {
+          attname = buffer;
+        }
+      else
+        {
+          attname = result+1;
+          *result = 0;
+          varname = buffer;
+        }
+
+      if ( *attname == 0 ) cdoAbort("Attribute name missing in >%s<!", kv->key);
+
+      int nv = 0;
+      int cdiID = Undefined;
+      if ( varname && *varname )
+        {
+          for ( int idx = 0; idx < nvars; idx++ )
+            {
+              vlistInqVarName(vlistID, idx, name);
+              if ( wildcardmatch(varname, name) == 0 )
+                {
+                  cdiID = vlistID;
+                  varIDs[nv++] = idx;
+                }
+            }
+
+          if ( cdiID == Undefined )
+            {
+              /*
+              for ( int idx = 0; idx < ngrids; idx++ )
+                {
+                  int gridID = vlistGrid(vlistID, idx);
+                  gridInqXname(gridID, name);
+                  if ( wildcardmatch(varname, name) == 0 )
+                    {
+                      cdiID = gridID;
+                      varIDs[nv++] = CDI_GLOBAL;
+                    }
+                  gridInqYname(gridID, name);
+                  if ( wildcardmatch(varname, name) == 0 )
+                    {
+                      cdiID = gridID;
+                      varIDs[nv++] = CDI_GLOBAL;
+                    }
+                }
+              */
+              for ( int idx = 0; idx < nzaxis; idx++ )
+                {
+                  int zaxisID = vlistZaxis(vlistID, idx);
+                  zaxisInqName(zaxisID, name);
+                  if ( wildcardmatch(varname, name) == 0 )
+                    {
+                      cdiID = zaxisID;
+                      varIDs[nv++] = CDI_GLOBAL;
+                    }
+                }
+            }
+
+          if ( cdiID == Undefined )
+            {
+              bool lwarn = true;
+              for ( int i = 0; i < kvn; ++i )
+                {
+                  if ( wname[i] == NULL )
+                    {
+                      wname[i] = strdup(varname);
+                      break;
+                    }
+                  if ( STR_IS_EQ(wname[i], varname) )
+                    {
+                      lwarn = false;
+                      break;
+                    }
+                }
+              if ( lwarn )
+                {
+                  cdoWarning("Variable >%s< not found!", varname);
+                }
+            }
+        }
+      else
+        {
+          cdiID = vlistID;
+          varIDs[nv++] = CDI_GLOBAL;
+        }
+
+      if ( cdiID != Undefined && nv > 0 )
+        {
+          const char *value = (kv->nvalues > 0) ? kv->values[0] : NULL;
+          int nvalues = kv->nvalues;
+          if ( nvalues == 1 && !*value ) nvalues = 0;
+          int dtype = literals_find_datatype(nvalues, kv->values);
+
+          for ( int idx = 0; idx < nv; ++idx )
+            {
+              int varID = varIDs[idx];
+              // if ( cdoVerbose ) printf("varID, cdiID, attname %d %d %s %d\n", varID, cdiID, attname, (int)strlen(attname));
+              if ( dtype == CDI_DATATYPE_INT8 || dtype == CDI_DATATYPE_INT16 || dtype == CDI_DATATYPE_INT32 )
+                {
+                  int *ivals = (int*) Malloc(nvalues*sizeof(int));
+                  for ( int i = 0; i < nvalues; ++i ) ivals[i] = literal_to_int(kv->values[i]);
+                  cdiDefAttInt(cdiID, varID, attname, dtype, nvalues, ivals);
+                  Free(ivals);
+                }
+              else if ( dtype == CDI_DATATYPE_FLT32 || dtype == CDI_DATATYPE_FLT64 )
+                {
+                  double *dvals = (double*) Malloc(nvalues*sizeof(double));
+                  for ( int i = 0; i < nvalues; ++i ) dvals[i] = literal_to_double(kv->values[i]);
+                  cdiDefAttFlt(cdiID, varID, attname, dtype, nvalues, dvals);
+                  Free(dvals);
+                }
+              else
+                {
+                  int len = (value && *value) ? (int) strlen(value) : 0;
+                  cdiDefAttTxt(cdiID, varID, attname, len, value);
+                }
+            }
+         }
+    }
+
+  Free(varIDs);
+  for ( int i = 0; i < kvn; ++i ) if ( wname[i] ) free(wname[i]);
+}
+
+
+void *Setattribute(void *argument)
+{
+  int nrecs;
+  int varID, levelID;
+
+  cdoInitialize(argument);
+
+  cdoOperatorAdd("setattribute", 0, 0, "attributes");
+
+  bool lcopy = UNCHANGED_RECORD;
+
+  int operatorID = cdoOperatorID();
+
+  operatorInputArg(cdoOperatorEnter(operatorID));
+
+  int natts = operatorArgc();
+  if ( natts == 0 ) cdoAbort("Parameter missing!");
+
+  list_t *pmlist = NULL;
+  list_t *kvlist = kvlist_new("SETATTRIBUTES");
+  if ( kvlist_parse_cmdline(kvlist, natts, operatorArgv()) != 0 ) cdoAbort("Parse error!");
+  if ( cdoVerbose ) kvlist_print(kvlist);
+
+  if ( natts == 1 )
+    {
+      keyValues_t *kv = *(keyValues_t **)kvlist->head->data;
+      if ( STR_IS_EQ(kv->key, "FILE") )
+        {
+          if ( cdoVerbose ) cdoPrint("Reading attributes from: %s", kv->values[0]);
+          const char *filename = parameter2word(kv->values[0]);
+          FILE *fp = fopen(filename, "r");
+          if ( fp == NULL ) cdoAbort("Open failed on: %s\n", filename);
+
+          pmlist = namelist_to_pmlist(fp, filename);
+          if ( pmlist == NULL ) cdoAbort("Parse error!");
+          list_destroy(kvlist);
+          kvlist = *(list_t **)pmlist->head->data;
+          if ( kvlist == NULL ) cdoAbort("Parse error!");;
+          fclose(fp);
+          if ( cdoVerbose ) kvlist_print(kvlist);
+        }
+    }
+
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
+
+  set_attributes(kvlist, vlistID2);
+
+  if ( pmlist ) list_destroy(pmlist);
+  else          list_destroy(kvlist);
+
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
+  vlistDefTaxis(vlistID2, taxisID2);
+
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+
+  streamDefVlist(streamID2, vlistID2);
+
+  double *array = NULL;
+  if ( ! lcopy )
+    {
+      size_t gridsize = (size_t) vlistGridsizeMax(vlistID1);
+      if ( vlistNumber(vlistID1) != CDI_REAL ) gridsize *= 2;
+      array = (double*) Malloc(gridsize*sizeof(double));
+    }
+
+  int tsID = 0;
+  while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
+    {
+      taxisCopyTimestep(taxisID2, taxisID1);
+
+      streamDefTimestep(streamID2, tsID);
+	       
+      for ( int recID = 0; recID < nrecs; recID++ )
+	{
+	  streamInqRecord(streamID1, &varID, &levelID);
+	  streamDefRecord(streamID2,  varID,  levelID);
+	  
+          if ( lcopy )
+            {
+              streamCopyRecord(streamID2, streamID1);
+            }
+          else
+            {
+              int nmiss;
+              streamReadRecord(streamID1, array, &nmiss);
+              streamWriteRecord(streamID2, array, nmiss);
+            }
+        }
+
+      tsID++;
+    }
+
+  streamClose(streamID1);
+  streamClose(streamID2);
+
+  if ( array ) Free(array);
+
+  cdoFinish();
+
+  return 0;
+}
diff --git a/src/Setbox.c b/src/Setbox.c
index bd1538f..edc9fd7 100644
--- a/src/Setbox.c
+++ b/src/Setbox.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -59,7 +59,7 @@ void *Setbox(void *argument)
   int operatorID;
   int streamID1, streamID2;
   int nrecs, nvars;
-  int tsID, recID, varID, levelID;
+  int tsID, varID, levelID;
   int gridsize;
   int vlistID1, vlistID2;
   int gridID = -1;
@@ -145,10 +145,9 @@ void *Setbox(void *argument)
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
-
       streamDefTimestep(streamID2, tsID);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
diff --git a/src/Setgatt.c b/src/Setgatt.c
index bab54ae..fc21704 100644
--- a/src/Setgatt.c
+++ b/src/Setgatt.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -22,8 +22,6 @@
       Setgatt    setgatts        Set global attributes
 */
 
-#include <ctype.h>
-
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
@@ -32,24 +30,18 @@
 
 void *Setgatt(void *argument)
 {
-  int SETGATT, SETGATTS;
-  int operatorID;
-  int streamID1, streamID2 = CDI_UNDEFID;
   int nrecs;
-  int tsID, recID, varID, levelID;
-  int vlistID1, vlistID2;
+  int varID, levelID;
   int gridsize;
   int nmiss;
   char *attname = NULL, *attstring = NULL, *attfile = NULL;
-  double *array = NULL;
-  int taxisID1, taxisID2;
 
   cdoInitialize(argument);
 
-  SETGATT  = cdoOperatorAdd("setgatt",  0, 0, "attribute name and string");
-  SETGATTS = cdoOperatorAdd("setgatts", 0, 0, NULL);
+  int SETGATT  = cdoOperatorAdd("setgatt",  0, 0, "attribute name and string");
+                 cdoOperatorAdd("setgatts", 0, 0, NULL);
 
-  operatorID = cdoOperatorID();
+  int operatorID = cdoOperatorID();
 
   if ( operatorID == SETGATT )
     {
@@ -62,28 +54,27 @@ void *Setgatt(void *argument)
       attfile   = operatorArgv()[0];
     }
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   if ( operatorID == SETGATT )
     {
-      vlistDefAttTxt(vlistID2, CDI_GLOBAL, attname, (int)strlen(attstring), attstring);
+      cdiDefAttTxt(vlistID2, CDI_GLOBAL, attname, (int)strlen(attstring), attstring);
     }
   else
     {
       char line[1024];
-      FILE *fp;
       int attlen = 0;
 
-      fp = fopen(attfile, "r");
+      FILE *fp = fopen(attfile, "r");
       if ( fp == 0 ) cdoAbort("Open failed on %s", attfile);
 
       while ( readline(fp, line, 1024) )
@@ -111,7 +102,7 @@ void *Setgatt(void *argument)
 	    }
 
 	  if ( attstring && attlen)
-	    vlistDefAttTxt(vlistID2, CDI_GLOBAL, attname, attlen, attstring);
+	    cdiDefAttTxt(vlistID2, CDI_GLOBAL, attname, attlen, attstring);
 	}
 
       fclose(fp);
@@ -121,16 +112,16 @@ void *Setgatt(void *argument)
 
   gridsize = vlistGridsizeMax(vlistID1);
   if ( vlistNumber(vlistID1) != CDI_REAL ) gridsize *= 2;
-  array = (double*) Malloc(gridsize*sizeof(double));
+  double *array = (double*) Malloc(gridsize*sizeof(double));
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
 
       streamDefTimestep(streamID2, tsID);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamDefRecord(streamID2,  varID,  levelID);
diff --git a/src/Setgrid.c b/src/Setgrid.c
index 7dccf52..47b4392 100644
--- a/src/Setgrid.c
+++ b/src/Setgrid.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -34,18 +34,16 @@
 void *Setgrid(void *argument)
 {
   int nrecs;
-  int recID, varID, levelID;
-  int gridID1, gridID2 = -1;
-  int ngrids, index;
+  int varID, levelID;
+  int gridID2 = -1;
   int gridtype = -1;
   int nmiss;
-  int found;
-  long i, gridsize;
-  long areasize = 0;
-  long masksize = 0;
-  int lregular = 0;
-  int ldereference = 0;
-  int ligme = 0;
+  int gridsize;
+  int areasize = 0;
+  int  masksize = 0;
+  bool lregular = false;
+  bool lregularnn = false;
+  bool ldereference = false;
   int number = 0, position = 0;
   int grid2_nvgp;
   int lbounds = TRUE;
@@ -86,10 +84,11 @@ void *Setgrid(void *argument)
       else if ( strcmp(gridname, "unstructured0") == 0 ) {gridtype = GRID_UNSTRUCTURED; lbounds = 0;}
       else if ( strcmp(gridname, "unstructured") == 0 )  {gridtype = GRID_UNSTRUCTURED; lbounds = 1;}
       else if ( strcmp(gridname, "generic") == 0 )        gridtype = GRID_GENERIC;
-      else if ( strcmp(gridname, "dereference") == 0 )    ldereference = 1;
+      else if ( strcmp(gridname, "dereference") == 0 )    ldereference = true;
       else if ( strcmp(gridname, "lonlat") == 0 )         gridtype = GRID_LONLAT;
       else if ( strcmp(gridname, "gaussian") == 0 )       gridtype = GRID_GAUSSIAN;
-      else if ( strcmp(gridname, "regular") == 0 )       {gridtype = GRID_GAUSSIAN; lregular = 1;}
+      else if ( strcmp(gridname, "regularnn") == 0 )     {gridtype = GRID_GAUSSIAN; lregularnn = true;}
+      else if ( strcmp(gridname, "regular") == 0 )       {gridtype = GRID_GAUSSIAN; lregular = true;}
       else cdoAbort("Unsupported grid name: %s", gridname);
     }
   else if ( operatorID == SETGRIDAREA )
@@ -111,7 +110,6 @@ void *Setgrid(void *argument)
       areaweight = (double*) Malloc(areasize*sizeof(double));
   
       streamReadRecord(streamID, areaweight, &nmiss);
-
       streamClose(streamID);
 
       if ( cdoVerbose )
@@ -119,7 +117,7 @@ void *Setgrid(void *argument)
 	  double arrmean = areaweight[0];
 	  double arrmin  = areaweight[0];
 	  double arrmax  = areaweight[0];
-	  for ( i = 1; i < areasize; i++ )
+	  for ( int i = 1; i < areasize; i++ )
 	    {
 	      if ( areaweight[i] < arrmin ) arrmin = areaweight[i];
 	      if ( areaweight[i] > arrmax ) arrmax = areaweight[i];
@@ -149,10 +147,9 @@ void *Setgrid(void *argument)
       gridmask = (double*) Malloc(masksize*sizeof(double));
   
       streamReadRecord(streamID, gridmask, &nmiss);
-
       streamClose(streamID);
 
-      for ( i = 0; i < masksize; i++ )
+      for ( int i = 0; i < masksize; i++ )
 	if ( DBL_IS_EQUAL(gridmask[i], missval) ) gridmask[i] = 0;
     }
   else if ( operatorID == SETGRIDNUMBER )
@@ -184,11 +181,11 @@ void *Setgrid(void *argument)
 
   if ( operatorID == SETGRID )
     {
-      found = 0;
-      ngrids = vlistNgrids(vlistID1);
-      for ( index = 0; index < ngrids; index++ )
+      int found = 0;
+      int ngrids = vlistNgrids(vlistID1);
+      for ( int index = 0; index < ngrids; index++ )
 	{
-	  gridID1 = vlistGrid(vlistID1, index);
+	  int gridID1 = vlistGrid(vlistID1, index);
 
 	  if ( gridInqSize(gridID1) == gridInqSize(gridID2) )
 	    {
@@ -200,7 +197,7 @@ void *Setgrid(void *argument)
     }
   else if ( operatorID == SETGRIDNUMBER || operatorID == SETGRIDURI )
     {
-      gridID1 = vlistGrid(vlistID1, 0);
+      int gridID1 = vlistGrid(vlistID1, 0);
 
       if ( operatorID == SETGRIDNUMBER )
 	{
@@ -214,9 +211,9 @@ void *Setgrid(void *argument)
 	  gridDefReference(gridID2, griduri);
 	}
 
-      found = 0;
-      ngrids = vlistNgrids(vlistID1);
-      for ( index = 0; index < ngrids; index++ )
+      int found = 0;
+      int ngrids = vlistNgrids(vlistID1);
+      for ( int index = 0; index < ngrids; index++ )
 	{
 	  gridID1 = vlistGrid(vlistID1, index);
 
@@ -230,20 +227,19 @@ void *Setgrid(void *argument)
     }
   else if ( operatorID == SETGRIDTYPE )
     {
-      ngrids = vlistNgrids(vlistID1);
-      for ( index = 0; index < ngrids; index++ )
+      bool lrgrid = false;
+      int ngrids = vlistNgrids(vlistID1);
+      for ( int index = 0; index < ngrids; index++ )
 	{
-	  gridID1 = vlistGrid(vlistID1, index);
+	  int gridID1 = vlistGrid(vlistID1, index);
 	  gridID2 = -1;
 
 	  if ( gridInqType(gridID1) == GRID_GENERIC && gridInqSize(gridID1) == 1 ) continue;
 	  
-	  if ( lregular )
+	  if ( lregular || lregularnn )
 	    {
 	      if ( gridInqType(gridID1) == GRID_GAUSSIAN_REDUCED )
-		{
-		  gridID2 = gridToRegular(gridID1);
-		}
+                gridID2 = gridToRegular(gridID1);
 	    }
 	  else if ( ldereference )
 	    {
@@ -258,7 +254,8 @@ void *Setgrid(void *argument)
 		}
 	      else if ( gridtype == GRID_UNSTRUCTURED )
 		{
-		  if ( gridInqType(gridID1) == GRID_GME ) ligme = 1;
+                  bool ligme = false;
+		  if ( gridInqType(gridID1) == GRID_GME ) ligme = true;
 		  gridID2 = gridToUnstructured(gridID1, 1);
 
 		  if ( ligme )
@@ -293,21 +290,26 @@ void *Setgrid(void *argument)
 
 	  if ( gridID2 == -1 )
             {
-              if ( lregular )
-                cdoAbort("No Gaussian reduced grid found!");
-              else
+              if ( !(lregular || lregularnn) )
                 cdoAbort("Unsupported grid type!");
             }
-          
-	  vlistChangeGridIndex(vlistID2, index, gridID2);
-	}
+
+	  if ( gridID2 != -1 )
+            {
+              if ( lregular || lregularnn ) lrgrid = true;
+              vlistChangeGridIndex(vlistID2, index, gridID2);
+            }
+        }
+
+      if ( (lregular || lregularnn) && !lrgrid )
+        cdoWarning("No reduced Gaussian grid found!");
     }
   else if ( operatorID == SETGRIDAREA )
     {
-      ngrids = vlistNgrids(vlistID1);
-      for ( index = 0; index < ngrids; index++ )
+      int ngrids = vlistNgrids(vlistID1);
+      for ( int index = 0; index < ngrids; index++ )
 	{
-	  gridID1  = vlistGrid(vlistID1, index);
+	  int gridID1  = vlistGrid(vlistID1, index);
 	  gridsize = gridInqSize(gridID1);
 	  if ( gridsize == areasize )
 	    {
@@ -319,15 +321,15 @@ void *Setgrid(void *argument)
     }
   else if ( operatorID == SETGRIDMASK )
     {
-      ngrids = vlistNgrids(vlistID1);
-      for ( index = 0; index < ngrids; index++ )
+      int ngrids = vlistNgrids(vlistID1);
+      for ( int index = 0; index < ngrids; index++ )
 	{
-	  gridID1  = vlistGrid(vlistID1, index);
+	  int gridID1  = vlistGrid(vlistID1, index);
 	  gridsize = gridInqSize(gridID1);
 	  if ( gridsize == masksize )
 	    {
 	      int *mask = (int*) Malloc(masksize*sizeof(int));
-	      for ( i = 0; i < masksize; i++ )
+	      for ( int i = 0; i < masksize; i++ )
 		{
 		  if ( gridmask[i] < 0 || gridmask[i] > 255 )
 		    mask[i] = 0;
@@ -343,10 +345,10 @@ void *Setgrid(void *argument)
     }
   else if ( operatorID == UNSETGRIDMASK )
     {
-      ngrids = vlistNgrids(vlistID1);
-      for ( index = 0; index < ngrids; index++ )
+      int ngrids = vlistNgrids(vlistID1);
+      for ( int index = 0; index < ngrids; index++ )
 	{
-	  gridID1  = vlistGrid(vlistID1, index);
+	  int gridID1  = vlistGrid(vlistID1, index);
 	  gridID2 = gridDuplicate(gridID1);
 	  gridDefMask(gridID2, NULL);
 	  vlistChangeGridIndex(vlistID2, index, gridID2);
@@ -358,7 +360,7 @@ void *Setgrid(void *argument)
   streamDefVlist(streamID2, vlistID2);
   //vlistPrint(vlistID2);
 
-  if ( lregular )
+  if ( lregular || lregularnn )
     gridsize = vlistGridsizeMax(vlistID2);
   else
     gridsize = vlistGridsizeMax(vlistID1);
@@ -373,28 +375,29 @@ void *Setgrid(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamDefRecord(streamID2,  varID,  levelID);
 	  
 	  streamReadRecord(streamID1, array, &nmiss);
 
-	  gridID1 = vlistInqVarGrid(vlistID1, varID);
-	  if ( lregular )
+	  int gridID1 = vlistInqVarGrid(vlistID1, varID);
+	  if ( lregular || lregularnn )
 	    {
 	      gridID2 = vlistInqVarGrid(vlistID2, varID);
 	      if ( gridInqType(gridID1) == GRID_GAUSSIAN_REDUCED )
 		{
 		  double missval = vlistInqVarMissval(vlistID1, varID);
-		  field2regular(gridID1, gridID2, missval, array, nmiss);
+                  int lnearst = lregularnn ? 1 : 0;
+                  field2regular(gridID1, gridID2, missval, array, nmiss, lnearst);
 		}
 	    }
 	  else if ( gridInqType(gridID1) == GRID_GME )
 	    {
-	      int j = 0;
 	      gridsize = gridInqSize(gridID1);
-	      for ( i = 0; i < gridsize; i++ )
+	      int j = 0;
+	      for ( int i = 0; i < gridsize; i++ )
 		if ( grid2_vgpm[i] ) array[j++] = array[i];
 	    }
 
diff --git a/src/Sethalo.c b/src/Sethalo.c
index 9c8c0c1..74309f7 100644
--- a/src/Sethalo.c
+++ b/src/Sethalo.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -35,8 +35,6 @@ int gentpngrid(int gridID1)
   int nlon2, nlat2;
   int prec;
   int ilat, ilon, ilonr, k, kr;
-  char xname[CDI_MAX_NAME], xlongname[CDI_MAX_NAME], xunits[CDI_MAX_NAME];
-  char yname[CDI_MAX_NAME], ylongname[CDI_MAX_NAME], yunits[CDI_MAX_NAME];
   double *xvals1 = NULL, *yvals1 = NULL;
   double *xvals2 = NULL, *yvals2 = NULL;
   double *xbounds1 = NULL, *ybounds1 = NULL;
@@ -57,19 +55,12 @@ int gentpngrid(int gridID1)
 
   gridDefPrec(gridID2, prec);
 
-  gridInqXname(gridID1, xname);
-  gridInqXlongname(gridID1, xlongname);
-  gridInqXunits(gridID1, xunits);
-  gridInqYname(gridID1, yname);
-  gridInqYlongname(gridID1, ylongname);
-  gridInqYunits(gridID1, yunits);
-
-  gridDefXname(gridID2, xname);
-  gridDefXlongname(gridID2, xlongname);
-  gridDefXunits(gridID2, xunits);
-  gridDefYname(gridID2, yname);
-  gridDefYlongname(gridID2, ylongname);
-  gridDefYunits(gridID2, yunits);
+  grid_copy_attributes(gridID1, gridID2);
+
+  char xunits[CDI_MAX_NAME]; xunits[0] = 0;
+  char yunits[CDI_MAX_NAME]; yunits[0] = 0;
+  cdiGridInqKeyStr(gridID1, CDI_KEY_XUNITS, CDI_MAX_NAME, xunits);
+  cdiGridInqKeyStr(gridID1, CDI_KEY_YUNITS, CDI_MAX_NAME, yunits);
 	
   if ( gridInqXvals(gridID1, NULL) && gridInqYvals(gridID1, NULL) )
     {
@@ -172,7 +163,7 @@ int gentpngrid(int gridID1)
 	}
     }
 
-  return (gridID2);
+  return gridID2;
 }
 
 static
@@ -185,8 +176,6 @@ int gengrid(int gridID1, int lhalo, int rhalo)
   int i;
   int prec;
   int ilat, ilon;
-  char xname[CDI_MAX_NAME], xlongname[CDI_MAX_NAME], xunits[CDI_MAX_NAME];
-  char yname[CDI_MAX_NAME], ylongname[CDI_MAX_NAME], yunits[CDI_MAX_NAME];
   double *xvals1 = NULL, *yvals1 = NULL;
   double *xvals2 = NULL, *yvals2 = NULL;
   double *xbounds1 = NULL, *ybounds1 = NULL;
@@ -218,19 +207,12 @@ int gengrid(int gridID1, int lhalo, int rhalo)
 
   gridDefPrec(gridID2, prec);
 
-  gridInqXname(gridID1, xname);
-  gridInqXlongname(gridID1, xlongname);
-  gridInqXunits(gridID1, xunits);
-  gridInqYname(gridID1, yname);
-  gridInqYlongname(gridID1, ylongname);
-  gridInqYunits(gridID1, yunits);
+  grid_copy_attributes(gridID1, gridID2);
 
-  gridDefXname(gridID2, xname);
-  gridDefXlongname(gridID2, xlongname);
-  gridDefXunits(gridID2, xunits);
-  gridDefYname(gridID2, yname);
-  gridDefYlongname(gridID2, ylongname);
-  gridDefYunits(gridID2, yunits);
+  char xunits[CDI_MAX_NAME]; xunits[0] = 0;
+  char yunits[CDI_MAX_NAME]; yunits[0] = 0;
+  cdiGridInqKeyStr(gridID1, CDI_KEY_XUNITS, CDI_MAX_NAME, xunits);
+  cdiGridInqKeyStr(gridID1, CDI_KEY_YUNITS, CDI_MAX_NAME, yunits);
 
   if ( memcmp(xunits, "degree", 6) == 0 ) cpi2 *= RAD2DEG;
 
@@ -367,22 +349,19 @@ int gengrid(int gridID1, int lhalo, int rhalo)
       Free(ybounds2);
     }
 
-  return (gridID2);
+  return gridID2;
 }
 
 
 static
 int genindexgrid(int gridID1, int *lhalo, int *rhalo)
 {
-  int gridID2;
-  int nlon1;
-
   operatorCheckArgc(2);
 
   *lhalo = parameter2int(operatorArgv()[0]);
   *rhalo = parameter2int(operatorArgv()[1]);
 
-  nlon1 = gridInqXsize(gridID1);
+  int nlon1 = gridInqXsize(gridID1);
 
   if ( *lhalo > nlon1 )
     {
@@ -408,36 +387,32 @@ int genindexgrid(int gridID1, int *lhalo, int *rhalo)
       cdoWarning("right halo out of range. Set to %d.", rhalo);
     }
 
-  gridID2 = gengrid(gridID1, *lhalo, *rhalo);
+  int gridID2 = gengrid(gridID1, *lhalo, *rhalo);
 
-  return (gridID2);
+  return gridID2;
 }
 
 
 static
 void halo(double *array1, int gridID1, double *array2, int lhalo, int rhalo)
 {
-  int nlon1, nlat;
-  int ilat, ilon;
-  int nmin, nmax;
-
-  nlon1 = gridInqXsize(gridID1);
-  nlat  = gridInqYsize(gridID1);
+  int nlon1 = gridInqXsize(gridID1);
+  int nlat  = gridInqYsize(gridID1);
 
-  nmin = 0;
-  nmax = nlon1;
+  int nmin = 0;
+  int nmax = nlon1;
   if ( lhalo < 0 ) nmin  = -lhalo;
   if ( rhalo < 0 ) nmax +=  rhalo;
 
-  for ( ilat = 0; ilat < nlat; ilat++ )
+  for ( int ilat = 0; ilat < nlat; ilat++ )
     {
-      for ( ilon = nlon1-lhalo; ilon < nlon1; ilon++ )
+      for ( int ilon = nlon1-lhalo; ilon < nlon1; ilon++ )
 	*array2++ = array1[ilat*nlon1 + ilon];
 
-      for ( ilon = nmin; ilon < nmax; ilon++ )
+      for ( int ilon = nmin; ilon < nmax; ilon++ )
 	*array2++ = array1[ilat*nlon1 + ilon];
 
-      for ( ilon = 0; ilon < rhalo; ilon++ )
+      for ( int ilon = 0; ilon < rhalo; ilon++ )
 	*array2++ = array1[ilat*nlon1 + ilon];
     }
 }
@@ -446,21 +421,16 @@ void halo(double *array1, int gridID1, double *array2, int lhalo, int rhalo)
 static
 void tpnhalo(double *array1, int gridID1, double *array2)
 {
-  int nlon, nlat;
-  int ilat, ilon, ilonr;
+  int nlon = gridInqXsize(gridID1);
+  int nlat = gridInqYsize(gridID1);
 
-  nlon = gridInqXsize(gridID1);
-  nlat = gridInqYsize(gridID1);
+  for ( int ilat = 0; ilat < nlat; ilat++ )
+    for ( int ilon = 0; ilon < nlon; ilon++ )
+      array2[(ilat+2)*nlon + ilon] = array1[ilat*nlon + ilon];
 
-  for ( ilat = 0; ilat < nlat; ilat++ )
+  for ( int ilon = 0; ilon < nlon; ilon++ )
     {
-      for ( ilon = 0; ilon < nlon; ilon++ )
-	array2[(ilat+2)*nlon + ilon] = array1[ilat*nlon + ilon];
-    }
-
-  for ( ilon = 0; ilon < nlon; ilon++ )
-    {
-      ilonr = nlon - ilon - 1;
+      int ilonr = nlon - ilon - 1;
       array2[1*nlon + ilon] = array2[2*nlon + ilonr]; /* syncronise line 2 with line 3 */
       array2[0*nlon + ilon] = array2[3*nlon + ilonr]; /* syncronise line 1 with line 4 */
     }
@@ -469,37 +439,29 @@ void tpnhalo(double *array1, int gridID1, double *array2)
 
 void *Sethalo(void *argument)
 {
-  int SETHALO, TPNHALO;
-  int operatorID;
-  int streamID1, streamID2;
-  int nrecs, nvars;
-  int tsID, recID, varID, levelID;
+  int nrecs;
+  int varID, levelID;
   int gridsize, gridsize2;
-  int vlistID1, vlistID2;
   int gridID1 = -1, gridID2;
-  int index, ngrids, gridtype;
+  int index, gridtype;
   int nmiss;
-  int *vars;
   int i;
   int lhalo = 0, rhalo = 0;
-  int ndiffgrids;
   double missval;
-  double *array1 = NULL, *array2 = NULL;
-  int taxisID1, taxisID2;
 
   cdoInitialize(argument);
 
-  SETHALO = cdoOperatorAdd("sethalo", 0, 0, NULL);
-  TPNHALO = cdoOperatorAdd("tpnhalo", 0, 0, NULL);
+  int SETHALO = cdoOperatorAdd("sethalo", 0, 0, NULL);
+                cdoOperatorAdd("tpnhalo", 0, 0, NULL);
 
-  operatorID = cdoOperatorID();
+  int operatorID = cdoOperatorID();
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
+  int vlistID1 = streamInqVlist(streamID1);
 
-  ngrids = vlistNgrids(vlistID1);
-  ndiffgrids = 0;
+  int ngrids = vlistNgrids(vlistID1);
+  int ndiffgrids = 0;
   for ( index = 1; index < ngrids; index++ )
     if ( vlistGrid(vlistID1, 0) != vlistGrid(vlistID1, index))
       ndiffgrids++;
@@ -530,10 +492,10 @@ void *Sethalo(void *argument)
       gridID2 = gentpngrid(gridID1);
     }
 
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
   ngrids = vlistNgrids(vlistID1);
@@ -546,8 +508,8 @@ void *Sethalo(void *argument)
 	}
     }
 
-  nvars = vlistNvars(vlistID1);
-  vars  = (int*) Malloc(nvars*sizeof(int));
+  int nvars = vlistNvars(vlistID1);
+  int *vars  = (int*) Malloc(nvars*sizeof(int));
   for ( varID = 0; varID < nvars; varID++ )
     {
       if ( gridID1 == vlistInqVarGrid(vlistID1, varID) )
@@ -556,24 +518,23 @@ void *Sethalo(void *argument)
 	vars[varID] = FALSE;
     }
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+ int  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
   gridsize = gridInqSize(gridID1);
-  array1 = (double*) Malloc(gridsize*sizeof(double));
+  double *array1 = (double*) Malloc(gridsize*sizeof(double));
 
   gridsize2 = gridInqSize(gridID2);
-  array2 = (double*) Malloc(gridsize2*sizeof(double));
+  double *array2 = (double*) Malloc(gridsize2*sizeof(double));
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
-
       streamDefTimestep(streamID2, tsID);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
diff --git a/src/Setmiss.c b/src/Setmiss.c
index a1f15e9..d14ac1e 100644
--- a/src/Setmiss.c
+++ b/src/Setmiss.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -42,7 +42,7 @@ int isnan(const double x);
 
 void *Setmiss(void *argument)
 {
-  int nrecs, recID;
+  int nrecs;
   int varID, levelID;
   int nmiss;
   int i;
@@ -124,7 +124,7 @@ void *Setmiss(void *argument)
 
       nvars = vlistNvars(vlistID2);
       for ( varID = 0; varID < nvars; varID++ )
-	vlistDefAttFlt(vlistID2, varID, "valid_range", DATATYPE_FLT64, 2, range);
+	cdiDefAttFlt(vlistID2, varID, "valid_range", CDI_DATATYPE_FLT64, 2, range);
     }
   */
   int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
@@ -139,10 +139,9 @@ void *Setmiss(void *argument)
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
-
       streamDefTimestep(streamID2, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, array, &nmiss);
diff --git a/src/Setpartab.c b/src/Setpartab.c
index e415090..5954728 100644
--- a/src/Setpartab.c
+++ b/src/Setpartab.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -21,157 +21,19 @@
       Setpartab  setpartab       Set parameter table
 */
 
-#if  defined(HAVE_CONFIG_H)
-#  include "config.h"
-#endif
-
-#if defined(HAVE_LIBUDUNITS2) && (defined(HAVE_UDUNITS2_H) || defined(HAVE_UDUNITS2_UDUNITS2_H))
-#define HAVE_UDUNITS2
-#endif
-
-#if defined(HAVE_UDUNITS2)
-#if defined(HAVE_UDUNITS2_UDUNITS2_H)
-#  include <udunits2/udunits2.h>
-#else
-#  include <udunits2.h>
-#endif
-#endif
-
-#include <errno.h>
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
 #include "pstream.h"
 #include "util.h"
-#include "namelist.h"
+#include "pmlist.h"
+#include "convert_units.h"
 
 int stringToParam(const char *paramstr);
+void paramToStringLong(int param, char *paramstr, int maxlen);
 
 typedef enum {CODE_NUMBER, PARAMETER_ID, VARIABLE_NAME, STANDARD_NAME} pt_mode_t;
 
-#if defined(HAVE_UDUNITS2)
-
-static void udunitsInitialize(void);
-static int udunitsInit = 0;
-
-#if defined(HAVE_LIBPTHREAD)
-#  include <pthread.h>
-
-static pthread_once_t  udunitsInitThread = PTHREAD_ONCE_INIT;
-static pthread_mutex_t udunitsMutex;
-
-#  define UDUNITS_LOCK()         pthread_mutex_lock(&udunitsMutex)
-#  define UDUNITS_UNLOCK()       pthread_mutex_unlock(&udunitsMutex)
-#  define UDUNITS_INIT()         pthread_once(&udunitsInitThread, udunitsInitialize)
-
-#else
-
-#  define UDUNITS_LOCK()
-#  define UDUNITS_UNLOCK()
-#  define UDUNITS_INIT()         if ( !udunitsInit ) udunitsInitialize();
-
-#endif
-
-
-static ut_system *ut_read = NULL;
-
-static
-void udunitsInitialize(void)
-{
-#if defined(HAVE_LIBPTHREAD)
-  /* initialize global API mutex lock */
-  pthread_mutex_init(&udunitsMutex, NULL);
-#endif
-
-  udunitsInit = 1;
-}
-
-static
-void *get_converter(char *src_unit_str, char *tgt_unit_str, int *rstatus)
-{
-  ut_unit *src_unit, *tgt_unit;
-  cv_converter *ut_units_converter = NULL;
-  int status;
-
-  *rstatus = -1;
-
-  if ( ut_read == NULL )
-    {
-      ut_set_error_message_handler(ut_ignore);
-
-      errno = 0;
-      ut_read = ut_read_xml(NULL);
-      status = ut_get_status();
-      if ( status == UT_PARSE )
-	{
-	  if ( cdoVerbose ) cdoWarning("Udunits: Couldn't parse unit database!");
-	}
-      if ( status == UT_OPEN_ENV || status == UT_OPEN_DEFAULT || status == UT_OS )
-	{
-	  if ( cdoVerbose ) cdoWarning("Udunits: %s", strerror(errno));
-	}
-      errno = 0;
-      if ( status != UT_SUCCESS )
-	{
-	  if ( cdoVerbose ) cdoWarning("Udunits: Error reading units system!");
-	  return NULL;
-	}
-    }
-
-  ut_trim(src_unit_str, UT_ASCII);
-  src_unit = ut_parse(ut_read, src_unit_str, UT_ASCII);
-  if ( ut_get_status() != UT_SUCCESS )
-    {
-      if ( cdoVerbose ) cdoWarning("Udunits: Error parsing units: [%s]", src_unit_str);
-      return NULL;
-    }
-
-  ut_trim(tgt_unit_str, UT_ASCII);
-  tgt_unit = ut_parse(ut_read, tgt_unit_str, UT_ASCII);
-  if ( ut_get_status() != UT_SUCCESS )
-    {
-      if ( cdoVerbose ) cdoWarning("Udunits: Error parsing units: [%s]", tgt_unit_str);
-      return NULL;
-    }
-
-  status = ut_compare(src_unit, tgt_unit);
-  if ( status == 0 ) *rstatus = -2;
-
-  if ( *rstatus == -1 )
-    {
-      status = ut_are_convertible(src_unit, tgt_unit);
-      if ( status == 0 ) *rstatus = -3;
-    }
-
-  if ( *rstatus == -1 )
-    {
-      ut_units_converter = ut_get_converter(src_unit, tgt_unit);
-      if ( ut_units_converter == NULL || ut_get_status() != UT_SUCCESS )
-	{
-	  if ( cdoVerbose ) cdoWarning("Udunits: Error getting converter from [%s] to [%s]", src_unit_str, tgt_unit_str);
-	}
-      else
-	*rstatus = 0;
-    }
-
-  ut_free(src_unit);
-  if ( ut_get_status() != UT_SUCCESS )
-    {
-      if ( cdoVerbose ) cdoWarning("Udunits: Error freeing units [%s]", src_unit_str);
-      return NULL;
-    }
-     
-  ut_free(tgt_unit);
-  if ( ut_get_status() != UT_SUCCESS )
-    {
-      if ( cdoVerbose ) cdoWarning("Udunits: Error freeing units [%s]", tgt_unit_str);
-      return NULL;
-    }
-
-  return ((void *) ut_units_converter);
-}
-#endif
-
 typedef struct
 {
   bool convert;
@@ -200,397 +62,222 @@ typedef struct
   char name[CDI_MAX_NAME];
   // converter
   void *ut_converter;
-} var_t;
 
+  double amean;
+  long nvals, n_lower_min, n_greater_max;
+} var_t;
 
-static
-void defineVarAttText(int vlistID2, int varID, const char *attname, const char *atttext)
-{
-  int len = strlen(atttext);
-  vlistDefAttTxt(vlistID2, varID, attname, len, atttext);
-}
-
-static
-void convertVarUnits(var_t *vars, int varID, char *name)
-{
-  if ( vars[varID].convert == false ) vars[varID].changeunits = false;
-
-  if ( vars[varID].changeunits )
-    {
-      char *units = vars[varID].units;
-      char *units_old = vars[varID].units_old;
-#if defined(HAVE_UDUNITS2)
-      int status;
-      UDUNITS_INIT();
-      UDUNITS_LOCK();
-      vars[varID].ut_converter = get_converter(units_old, units, &status);
-      UDUNITS_UNLOCK();
-      if ( vars[varID].ut_converter == NULL )
-	{
-	  if ( status == -2 )
-	    {
-	      if ( cdoVerbose )
-		cdoPrint("%s - not converted from  [%s] to [%s], units are equal!", name, units_old, units);
-	    }
-	  else if ( status == -3 )
-	    {
-	      cdoWarning("%s - converting units from [%s] to [%s] failed, not convertible!", name, units_old, units);
-	    }
-	  else
-	    cdoWarning("%s - converting units from [%s] to [%s] failed!", name, units_old, units);
-	  vars[varID].changeunits = false;
-	}
-      else
-	{
-	  // if ( cdoVerbose )
-	    {
-	      char buf[64];
-	      cv_get_expression((const cv_converter*)vars[varID].ut_converter, buf, 64, name);
-	      cdoPrint("%s - convert units from [%s] to [%s] (expression: %s).", name, units_old, units, buf);
-	    }
-	}
-#else
-      static bool lwarn_udunits = true;
-      if ( lwarn_udunits )
-	{
-	  cdoWarning("%s - converting units from [%s] to [%s] failed, UDUNITS2 support not compiled in!", name,units_old, units);
-	  vars[varID].changeunits = false;
-	  lwarn_udunits = false;
-	}
-#endif
-    }
-}
-
-static
-void defineVarUnits(var_t *vars, int vlistID2, int varID, char *units)
-{
-  char units_old[CDI_MAX_NAME];
 
-  vlistInqVarUnits(vlistID2, varID, units_old);
-  size_t len1 = strlen(units_old);
-  size_t len2 = strlen(units);
+void cdo_define_var_units(var_t *var, int vlistID2, int varID, const char *units);
 
-  if ( strcmp(units, units_old) != 0 )
-    {
-      if ( len1 > 0 && len2 > 0 )
-	{
-	  vars[varID].changeunits = true;
-	  strcpy(vars[varID].units_old, units_old);
-	  strcpy(vars[varID].units, units);
-	}
+void cmor_check_init(int nvars, var_t *vars);
+void cmor_check_eval(int vlistID, int nvars, var_t *vars);
+void cmor_check_prep(var_t *var, long gridsize, double missval, double *array);
 
-      vlistDefVarUnits(vlistID2, varID, units);
-      defineVarAttText(vlistID2, varID, "original_units", units_old);
-    }
-}
 
 static
-void read_partab(pt_mode_t ptmode, int nvars, int vlistID2, var_t *vars)
+void apply_parameterlist(pt_mode_t ptmode, list_t *pmlist, int nvars, int vlistID2, var_t *vars)
 {
-  FILE *fp = NULL;
-  namelist_t *nml;
-  int nml_code, nml_out_code, nml_table, nml_param, nml_out_param, nml_chunktype, nml_datatype, nml_type, nml_name, nml_out_name, nml_stdname;
-  int nml_longname, nml_units, nml_comment, nml_ltype, nml_delete, nml_convert, nml_missval, nml_factor;
-  int nml_cell_methods, nml_cell_measures;
-  int nml_valid_min, nml_valid_max, nml_ok_min_mean_abs, nml_ok_max_mean_abs;
-  int i;
-  int code, out_code, table, ltype, remove, convert;
-  int nml_index = 0;
-  int codenum, tabnum, levtype, param;
-  int varID, tableID;
-  int num_pt_files;
-  double missval, factor;
-  double valid_min, valid_max, ok_min_mean_abs, ok_max_mean_abs;
-  char *partab = NULL;
-  char *chunktypestr = NULL;
-  char *datatypestr = NULL;
-  char *typestr = NULL;
-  char *paramstr = NULL;
-  char *out_paramstr = NULL;
-  char *name = NULL, *out_name = NULL, *stdname = NULL, longname[CDI_MAX_NAME] = "", units[CDI_MAX_NAME] = "";
-  char cell_methods[CDI_MAX_NAME] = "", cell_measures[CDI_MAX_NAME] = "";
+  const char *hentry[] = {"Header"};
+  const char *ventry[] = {"variable_entry", "parameter"};
+  int nventry = (int) sizeof(ventry)/sizeof(ventry[0]);
+  int nhentry = (int) sizeof(hentry)/sizeof(hentry[0]);
+  char valstr[CDI_MAX_NAME];
   char varname[CDI_MAX_NAME];
-  char comment[1024] = "";
-
-  //num_pt_files = operatorArgc();
-  num_pt_files = 1;
-
-  for ( int fileID = 0; fileID < num_pt_files; ++fileID )
-    {
-      partab = operatorArgv()[fileID];
-      if ( fileExists(partab) ) fp = fopen(partab, "r");
-      if ( fp == NULL ) cdoAbort("Open failed on parameter table %d file name %s!", fileID+1, partab);
-
-      nml_index = 0;
-      nml = namelistNew("parameter");
-      nml->dis = 0;
-
-      nml_code            = namelistAdd(nml, "code",            NML_INT,  0, &code, 1);
-      nml_out_code        = namelistAdd(nml, "out_code",        NML_INT,  0, &out_code, 1);
-      nml_table           = namelistAdd(nml, "table",           NML_INT,  0, &table, 1);
-      nml_ltype           = namelistAdd(nml, "ltype",           NML_INT,  0, &ltype, 1);
-      nml_delete          = namelistAdd(nml, "delete",          NML_INT,  0, &remove, 1);
-      nml_convert         = namelistAdd(nml, "convert",         NML_INT,  0, &convert, 1);
-      nml_missval         = namelistAdd(nml, "missing_value",   NML_FLT,  0, &missval, 1);
-      nml_factor          = namelistAdd(nml, "factor",          NML_FLT,  0, &factor, 1);
-      nml_valid_min       = namelistAdd(nml, "valid_min",       NML_FLT,  0, &valid_min, 1);
-      nml_valid_max       = namelistAdd(nml, "valid_max",       NML_FLT,  0, &valid_max, 1);
-      nml_ok_min_mean_abs = namelistAdd(nml, "ok_min_mean_abs", NML_FLT,  0, &ok_min_mean_abs, 1);
-      nml_ok_max_mean_abs = namelistAdd(nml, "ok_max_mean_abs", NML_FLT,  0, &ok_max_mean_abs, 1);
-      nml_param           = namelistAdd(nml, "param",           NML_WORD, 0, &paramstr, 1);
-      nml_out_param       = namelistAdd(nml, "out_param",       NML_WORD, 0, &out_paramstr, 1);
-      nml_chunktype       = namelistAdd(nml, "chunktype",       NML_WORD, 0, &chunktypestr, 1);
-      nml_datatype        = namelistAdd(nml, "datatype",        NML_WORD, 0, &datatypestr, 1);
-      nml_type            = namelistAdd(nml, "type",            NML_WORD, 0, &typestr, 1);
-      nml_name            = namelistAdd(nml, "name",            NML_WORD, 0, &name, 1);
-      nml_out_name        = namelistAdd(nml, "out_name",        NML_WORD, 0, &out_name, 1);
-      nml_stdname         = namelistAdd(nml, "standard_name",   NML_WORD, 0, &stdname, 1);
-      nml_longname        = namelistAdd(nml, "long_name",       NML_TEXT, 0, longname, sizeof(longname));
-      nml_units           = namelistAdd(nml, "units",           NML_TEXT, 0, units, sizeof(units));
-      nml_comment         = namelistAdd(nml, "comment",         NML_TEXT, 0, comment, sizeof(comment));
-      nml_cell_methods    = namelistAdd(nml, "cell_methods",    NML_TEXT, 0, cell_methods, sizeof(cell_methods));
-      nml_cell_measures   = namelistAdd(nml, "cell_measures",   NML_TEXT, 0, cell_measures, sizeof(cell_measures));
-
-      while ( ! feof(fp) )
-	{
-	  namelistReset(nml);
-
-	  namelistRead(fp, nml);
-
-	  if ( cdoVerbose ) namelistPrint(nml);
-
-	  bool locc = false;
-	  for ( i = 0; i < nml->size; i++ )
-	    {
-	      if ( nml->entry[i]->occ ) { locc = true; break; }
-	    }
-
-	  if ( locc )
-	    {
-	      // namelistPrint(nml);
-	  
-	      nml_index++;
-
-	      if ( ptmode == CODE_NUMBER )
-		{
-		  if ( nml->entry[nml_code]->occ == 0 )
-		    {
-		      cdoPrint("Parameter entry %d (parameter table %d) skipped, code number not found!", nml_index, fileID+1);
-		      continue;
-		    }
-		}
-	      else if ( ptmode == PARAMETER_ID )
-		{
-		  if ( nml->entry[nml_param]->occ == 0 )
-		    {
-		      cdoWarning("Parameter entry %d (parameter table %d) skipped, parameter ID not found!", nml_index, fileID+1);
-		      continue;
-		    }
-		}
-	      else if ( ptmode == VARIABLE_NAME )
-		{
-		  if ( nml->entry[nml_name]->occ == 0 )
-		    {
-		      cdoWarning("Parameter entry %d (parameter table %d) skipped, variable name not found!", nml_index, fileID+1);
-		      continue;
-		    }
-		}
-
-	      for ( varID = 0; varID < nvars; varID++ )
-		{
-		  if ( ptmode == CODE_NUMBER )
-		    {
-		      codenum = vlistInqVarCode(vlistID2, varID);
-		      tableID = vlistInqVarTable(vlistID2, varID);
-		      tabnum  = tableInqNum(tableID);
-		      levtype = zaxisInqLtype(vlistInqVarZaxis(vlistID2, varID));
-		      
-		      // printf("code = %d  tabnum = %d  ltype = %d\n", codenum, tabnum, levtype);
-		      
-		      if ( nml->entry[nml_table]->occ == 0 ) table = tabnum;
-		      if ( nml->entry[nml_ltype]->occ == 0 ) ltype = levtype;
-		  
-		      if ( codenum == code && tabnum == table && levtype == ltype ) break;
-		    }
-		  else if ( ptmode == PARAMETER_ID )
-		    {
-		      int paramid = stringToParam(paramstr);
-
-		      param   = vlistInqVarParam(vlistID2, varID);
-		      levtype = zaxisInqLtype(vlistInqVarZaxis(vlistID2, varID));
-
-		      if ( nml->entry[nml_ltype]->occ == 0 ) ltype = levtype;
-		  
-		      if ( param == paramid && levtype == ltype ) break;
-		    }
-		  else if ( ptmode == VARIABLE_NAME )
-		    {
-		      vlistInqVarName(vlistID2, varID, varname);
-		      if ( strcmp(varname, name) == 0 ) break;
-		    }
-		}
+  char paramstr[32];
+  int codenum;
 
-	      if ( varID < nvars )
-		{
-                  int pnum, ptab, pdum;
-                  cdiDecodeParam(vlistInqVarParam(vlistID2, varID), &pnum, &ptab, &pdum);
-		  if ( nml->entry[nml_code]->occ     )  vlistDefVarParam(vlistID2, varID, cdiEncodeParam(code, ptab, 255));
-		  if ( nml->entry[nml_out_code]->occ )  vlistDefVarParam(vlistID2, varID, cdiEncodeParam(out_code, ptab, 255));
-		  if ( nml->entry[nml_name]->occ     )  strcpy(vars[varID].name, name);
-		  if ( nml->entry[nml_name]->occ     )  vlistDefVarName(vlistID2, varID, name);
-		  if ( nml->entry[nml_out_name]->occ )  vlistDefVarName(vlistID2, varID, out_name);
-		  if ( nml->entry[nml_out_name]->occ )  defineVarAttText(vlistID2, varID, "original_name", vars[varID].name);
-		  if ( nml->entry[nml_stdname]->occ  )  vlistDefVarStdname(vlistID2, varID, stdname);
-		  if ( nml->entry[nml_longname]->occ )  vlistDefVarLongname(vlistID2, varID, longname);
-		  if ( nml->entry[nml_units]->occ    )  defineVarUnits(vars, vlistID2, varID, units);
-		  if ( nml->entry[nml_comment]->occ  )  defineVarAttText(vlistID2, varID, "comment", comment);
-		  if ( nml->entry[nml_cell_methods]->occ  ) defineVarAttText(vlistID2, varID, "cell_methods", cell_methods);
-		  if ( nml->entry[nml_cell_measures]->occ ) defineVarAttText(vlistID2, varID, "cell_measures", cell_measures);
-		  if ( nml->entry[nml_delete]->occ && remove == 1 ) vars[varID].remove = true;
-		  if ( nml->entry[nml_convert]->occ )   vars[varID].convert = convert==0 ? false : true;
-		  if ( nml->entry[nml_param]->occ )     vlistDefVarParam(vlistID2, varID, stringToParam(paramstr));
-		  if ( nml->entry[nml_out_param]->occ ) vlistDefVarParam(vlistID2, varID, stringToParam(out_paramstr));
-		  if ( nml->entry[nml_datatype]->occ )
-		    {
-		      int datatype = str2datatype(datatypestr);
-		      if ( datatype != -1 ) vlistDefVarDatatype(vlistID2, varID, datatype);
-		    }
-		  if ( nml->entry[nml_type]->occ )
-		    {
-		      int datatype = str2datatype(typestr);
-		      if ( datatype != -1 ) vlistDefVarDatatype(vlistID2, varID, datatype);
-		    }
-		  if ( nml->entry[nml_missval]->occ )
-		    {
-		      double missval_old;
-		      missval_old = vlistInqVarMissval(vlistID2, varID);
-		      if ( ! DBL_IS_EQUAL(missval, missval_old) )
-			{
-			  if ( cdoVerbose ) 
-			    cdoPrint("%s - change missval from %g to %g", name, missval_old, missval);
-			  vars[varID].changemissval = true;
-			  vars[varID].missval_old = missval_old;
-			  vlistDefVarMissval(vlistID2, varID, missval);
-			}
-		    }
-		  if ( nml->entry[nml_factor]->occ )
-		    {
-		      vars[varID].lfactor = true;
-		      vars[varID].factor = factor;
-		      if ( cdoVerbose ) 
-			cdoPrint("%s - scale factor %g", name, factor);
-		    }
-		  if ( nml->entry[nml_valid_min]->occ && nml->entry[nml_valid_max]->occ )
-		    {
-		      vars[varID].checkvalid = true;
-		      vars[varID].valid_min = valid_min;
-		      vars[varID].valid_max = valid_max;
-		    }
-		  if ( nml->entry[nml_ok_min_mean_abs]->occ )
-		    {
-		      vars[varID].check_min_mean_abs = true;
-		      vars[varID].ok_min_mean_abs = ok_min_mean_abs;
-		    }
-		  if ( nml->entry[nml_ok_max_mean_abs]->occ )
-		    {
-		      vars[varID].check_max_mean_abs = true;
-		      vars[varID].ok_max_mean_abs = ok_max_mean_abs;
-		    }
-		}
-	      /*
-	      else
-		{
-		  if ( cdoVerbose )
-		    {
-		      if ( ptmode == CODE_NUMBER )
-			{
-			  if ( nml->entry[nml_table]->occ == 0 )
-			    cdoPrint("Code %d not found!", code);
-			  else
-			    cdoPrint("Code %d and table %d not found!", code, table);
-			}
-		      else
-			cdoPrint("%s - not found!", name);
-		    }
-		}
-	      */
-	    }
-	  else
-	    break;
-	}
-  
-      namelistDelete(nml);
-
-      fclose(fp);
-    }
-}
-
-static
-void check_data(int vlistID2, int varID2, int varID, var_t *vars, long gridsize, double missval, double *array)
-{
-  char varname[CDI_MAX_NAME];
-  int nvals = 0;
-  double amean = 0, aval;
-  double amin  =  1.e300;
-  double amax  = -1.e300;
-  
-  for ( long i = 0; i < gridsize; ++i )
+  // search for global missing value
+  bool lmissval = false;
+  double missval;
+  list_t *kvlist = pmlist_get_kvlist_ventry(pmlist, nhentry, hentry);
+  if ( kvlist )
     {
-      aval = array[i];
-      if ( !DBL_IS_EQUAL(aval, missval) )
-	{
-	  if ( aval < amin ) amin = aval;
-	  if ( aval > amax ) amax = aval;
-	  amean += aval;
-	  nvals++;
-	}
+      keyValues_t *kv = kvlist_search(kvlist, "missing_value");
+      if ( kv && kv->nvalues > 0 )
+        {
+          lmissval = true;
+          missval = parameter2double(kv->values[0]);
+        }
     }
 
-  if ( nvals > 0 ) amean /= nvals;
-
-  int n_lower_min = 0;
-  int n_greater_max = 0;
-  for ( long i = 0; i < gridsize; ++i )
+  for ( int varID = 0; varID < nvars; varID++ )
     {
-      aval = array[i];
-      if ( !DBL_IS_EQUAL(aval, missval) )
-	{
-	  if ( aval < vars[varID].valid_min ) n_lower_min++;
-	  if ( aval > vars[varID].valid_max ) n_greater_max++;
-	}
-    }
+      var_t *var = &vars[varID];
+      vlistInqVarName(vlistID2, varID, varname);
 
-  vlistInqVarName(vlistID2, varID2, varname);
-
-  if ( n_lower_min > 0 )
-    cdoWarning("Invalid value(s) detected for variable '%s': %i values were lower than minimum valid value (%.4g).",
-	       varname, n_lower_min, vars[varID].valid_min);
-  if ( n_greater_max > 0 )
-    cdoWarning("Invalid value(s) detected for variable '%s': %i values were greater than maximum valid value (%.4g).",
-	       varname, n_greater_max, vars[varID].valid_max);
+      strcpy(var->name, varname);
+      if ( lmissval )
+        {
+          double missval_old = vlistInqVarMissval(vlistID2, varID);
+          if ( ! DBL_IS_EQUAL(missval, missval_old) )
+            {
+              var->changemissval = true;
+              var->missval_old = missval_old;
+              vlistDefVarMissval(vlistID2, varID, missval);
+            }
+        }
 
-  amean = fabs(amean);
+      list_t *kvlist = NULL;
+      if ( ptmode == CODE_NUMBER )
+        {
+          codenum = vlistInqVarCode(vlistID2, varID);          
+          snprintf(valstr, sizeof(valstr), "%d", codenum);
+          kvlist = pmlist_search_kvlist_ventry(pmlist, "code", valstr, nventry, ventry);
+          if ( kvlist )
+            {
+              int tableID = vlistInqVarTable(vlistID2, varID);
+              int tabnum  = tableInqNum(tableID);
+              int levtype = zaxisInqLtype(vlistInqVarZaxis(vlistID2, varID));
+              int table = tabnum;
+              int ltype = levtype;
+              keyValues_t *kv = kvlist_search(kvlist, "table");
+              if ( kv && kv->nvalues == 1 ) table = parameter2int(kv->values[0]);
+              kv = kvlist_search(kvlist, "ltype");
+              if ( kv && kv->nvalues == 1 ) ltype = parameter2int(kv->values[0]);
+              if ( !(tabnum == table && levtype == ltype) ) kvlist = NULL;
+            }
+        }
+      else if ( ptmode == PARAMETER_ID )
+        {
+          int param = vlistInqVarParam(vlistID2, varID);
+          paramToStringLong(param, paramstr, sizeof(paramstr));
+          snprintf(valstr, sizeof(valstr), "%s", paramstr);
+          kvlist = pmlist_search_kvlist_ventry(pmlist, "param", valstr, nventry, ventry);
+          if ( kvlist )
+            {
+              int levtype = zaxisInqLtype(vlistInqVarZaxis(vlistID2, varID));
+              int ltype = levtype;
+              keyValues_t *kv = kvlist_search(kvlist, "ltype");
+              if ( kv && kv->nvalues == 1 ) ltype = parameter2int(kv->values[0]);
+              if ( !(levtype == ltype) ) kvlist = NULL;
+            }  
+        }
+      else if ( ptmode == VARIABLE_NAME )
+        {
+          kvlist = pmlist_search_kvlist_ventry(pmlist, "name", varname, nventry, ventry);
+        }
 
-  if ( vars[varID].check_min_mean_abs )
-    {
-      if ( amean < .1*vars[varID].ok_min_mean_abs )
-	cdoWarning("Invalid Absolute Mean for variable '%s' (%.5g) is lower by more than an order of magnitude than minimum allowed: %.4g",
-		 varname, amean, vars[varID].ok_min_mean_abs);
+      if ( kvlist )
+        {
+          int pnum, ptab, pdum;
+          cdiDecodeParam(vlistInqVarParam(vlistID2, varID), &pnum, &ptab, &pdum);
+          bool lvalid_min = false, lvalid_max = false;
 
-      if ( amean < vars[varID].ok_min_mean_abs)
-	cdoWarning("Invalid Absolute Mean for variable '%s' (%.5g) is lower than minimum allowed: %.4g",
-		   varname, amean, vars[varID].ok_min_mean_abs);
-    }
+          for ( listNode_t *kvnode = kvlist->head; kvnode; kvnode = kvnode->next )
+            {
+              keyValues_t *kv = *(keyValues_t **)kvnode->data;
+              const char *key = kv->key;
+              const char *value = (kv->nvalues > 0) ? kv->values[0] : NULL;
+              bool lv1 = (kv->nvalues == 1);
+              
+              // printf("key=%s  value=%s\n", key, value ? value : "");
+
+              if      ( lv1 && STR_IS_EQ(key, "standard_name") ) vlistDefVarStdname(vlistID2, varID, value);
+              else if ( lv1 && STR_IS_EQ(key, "long_name")     ) vlistDefVarLongname(vlistID2, varID, value);
+              else if ( lv1 && STR_IS_EQ(key, "units")         ) cdo_define_var_units(var, vlistID2, varID, value);
+              else if ( lv1 && STR_IS_EQ(key, "name")          ) /*vlistDefVarName(vlistID2, varID, parameter2word(value))*/;
+              else if ( lv1 && STR_IS_EQ(key, "out_name")      )
+                {
+                  const char *outname = parameter2word(value);
+                  if ( !STR_IS_EQ(var->name, outname) )
+                    {
+                      vlistDefVarName(vlistID2, varID, outname);
+                      cdiDefAttTxt(vlistID2, varID, "original_name", (int)strlen(var->name), var->name);
+                    }
+                }
+              else if ( lv1 && STR_IS_EQ(key, "param")         ) vlistDefVarParam(vlistID2, varID, stringToParam(parameter2word(value)));
+              else if ( lv1 && STR_IS_EQ(key, "out_param")     ) vlistDefVarParam(vlistID2, varID, stringToParam(parameter2word(value)));
+              else if ( lv1 && STR_IS_EQ(key, "code")          ) vlistDefVarParam(vlistID2, varID, cdiEncodeParam(parameter2int(value), ptab, 255));
+              else if ( lv1 && STR_IS_EQ(key, "out_code")      ) vlistDefVarParam(vlistID2, varID, cdiEncodeParam(parameter2int(value), ptab, 255));
+              else if ( lv1 && STR_IS_EQ(key, "comment")       ) cdiDefAttTxt(vlistID2, varID, key, (int)strlen(value), value);
+              else if ( lv1 && STR_IS_EQ(key, "chunktype")     ) ;
+              else if ( lv1 && STR_IS_EQ(key, "cell_methods")  ) cdiDefAttTxt(vlistID2, varID, key, (int)strlen(value), value);
+              else if ( lv1 && STR_IS_EQ(key, "cell_measures") ) cdiDefAttTxt(vlistID2, varID, key, (int)strlen(value), value);
+              else if ( lv1 && STR_IS_EQ(key, "delete")        ) var->remove = parameter2bool(value);
+              else if ( lv1 && STR_IS_EQ(key, "convert")       ) var->convert = parameter2bool(value);
+              else if ( lv1 && STR_IS_EQ(key, "factor")        )
+                {
+                  var->lfactor = true;
+                  var->factor = parameter2double(value);
+                  if ( cdoVerbose ) cdoPrint("%s - scale factor %g", varname, var->factor);
+                }
+              else if ( lv1 && (STR_IS_EQ(key, "missval") || STR_IS_EQ(key, "missing_value")) )
+                {
+                  double missval = parameter2double(value);
+                  double missval_old = vlistInqVarMissval(vlistID2, varID);
+                  if ( ! DBL_IS_EQUAL(missval, missval_old) )
+                    {
+                      if ( cdoVerbose ) cdoPrint("%s - change missval from %g to %g", varname, missval_old, missval);
+                      var->changemissval = true;
+                      var->missval_old = missval_old;
+                      vlistDefVarMissval(vlistID2, varID, missval);
+                    }
+                }
+              else if ( lv1 && STR_IS_EQ(key, "valid_min") )
+                {
+                  lvalid_min = true;
+                  var->valid_min = parameter2double(value);
+                }
+              else if ( lv1 && STR_IS_EQ(key, "valid_max") )
+                {
+                  lvalid_max = true;
+                  var->valid_max = parameter2double(value);
+                }
+              else if ( lv1 && STR_IS_EQ(key, "ok_min_mean_abs") )
+                {
+                  var->check_min_mean_abs = true;
+                  var->ok_min_mean_abs = parameter2double(value);
+                }
+              else if ( lv1 && STR_IS_EQ(key, "ok_max_mean_abs") )
+                {
+                  var->check_max_mean_abs = true;
+                  var->ok_max_mean_abs = parameter2double(value);
+                }
+              else if ( lv1 && (STR_IS_EQ(key, "datatype") || STR_IS_EQ(key, "type")) )
+                {
+                  int datatype = str2datatype(parameter2word(value));
+                  if ( datatype != -1 ) vlistDefVarDatatype(vlistID2, varID, datatype);
+                }
+              else if ( lv1 && STR_IS_EQ(key, "dimensions") )
+                {
+                }
+              else
+                {
+                  int nvalues = kv->nvalues;
+                  if ( nvalues == 1 && !*value ) nvalues = 0;
+                  int dtype = literals_find_datatype(nvalues, kv->values);
+                  
+                  if ( dtype == CDI_DATATYPE_INT8 || dtype == CDI_DATATYPE_INT16 || dtype == CDI_DATATYPE_INT32 )
+                    {
+                      int *ivals = (int*) Malloc(nvalues*sizeof(int));
+                      for ( int i = 0; i < nvalues; ++i ) ivals[i] = literal_to_int(kv->values[i]);
+                      cdiDefAttInt(vlistID2, varID, key, dtype, nvalues, ivals);
+                      Free(ivals);
+                    }
+                  else if ( dtype == CDI_DATATYPE_FLT32 || dtype == CDI_DATATYPE_FLT64 )
+                    {
+                      double *dvals = (double*) Malloc(nvalues*sizeof(double));
+                      for ( int i = 0; i < nvalues; ++i ) dvals[i] = literal_to_double(kv->values[i]);
+                      cdiDefAttFlt(vlistID2, varID, key, dtype, nvalues, dvals);
+                      Free(dvals);
+                    }
+                  else
+                    {
+                      int len = (value && *value) ? (int) strlen(value) : 0;
+                      cdiDefAttTxt(vlistID2, varID, key, len, value);
+                    }
+                }
+            }
 
-  if ( vars[varID].check_max_mean_abs )
-    {
-      if ( amean > 10.*vars[varID].ok_max_mean_abs )
-	cdoWarning("Invalid Absolute Mean for variable '%s' (%.5g) is greater by more than an order of magnitude than maximum allowed: %.4g",
-		 varname, amean, vars[varID].ok_max_mean_abs);
-      
-      if ( amean > vars[varID].ok_max_mean_abs )
-	cdoWarning("Invalid Absolute Mean for variable '%s' (%.5g) is greater than maximum allowed: %.4g",
-		   varname, amean, vars[varID].ok_max_mean_abs);
+          if ( lvalid_min && lvalid_max ) var->checkvalid = true;
+        }
+      else
+        {
+          if      ( ptmode == CODE_NUMBER )   cdoPrint("Code number %d not found in parameter table!", codenum);
+          else if ( ptmode == PARAMETER_ID )  cdoPrint("Parameter ID %s not found in parameter table!", paramstr);
+          else if ( ptmode == VARIABLE_NAME ) cdoPrint("Variable %s not found in parameter table!", varname);
+        }
     }
 }
 
@@ -600,9 +287,9 @@ void *Setpartab(void *argument)
   int nrecs;
   int varID, levelID;
   int nmiss;
-  bool delvars = false;
   int tableID = -1;
   int tableformat = 0;
+  bool delvars = false;
   double missval;
 
   cdoInitialize(argument);
@@ -709,7 +396,15 @@ void *Setpartab(void *argument)
     }
   else
     {
-      read_partab(ptmode, nvars, vlistID2, vars);
+      const char *filename = operatorArgv()[0];
+      FILE *fp = fopen(filename, "r");
+      if ( fp == NULL ) cdoAbort("Open failed on: %s\n", filename);
+      
+      list_t *pmlist = namelist_to_pmlist(fp, filename);
+      fclose(fp);
+
+      apply_parameterlist(ptmode, pmlist, nvars, vlistID2, vars);
+      list_destroy(pmlist);
 
       for ( int varID = 0; varID < nvars; ++varID )
 	if ( vars[varID].remove )
@@ -745,10 +440,16 @@ void *Setpartab(void *argument)
 	  vlistDestroy(vlistID2);
 
 	  vlistID2 = vlistIDx;
+          if ( vlistNvars(vlistID2) == 0 ) cdoAbort("No variable selected!");
 	}
 
       for ( int varID = 0; varID < nvars; ++varID )
-	convertVarUnits(vars, varID, vars[varID].name);
+        {
+          var_t *var = &vars[varID];
+          if ( var->convert == false ) var->changeunits = false;
+          if ( var->changeunits )
+            cdoConvertUnits(&var->ut_converter, &var->changeunits, (char*)&var->units, (char*)&var->units_old, var->name);
+        }
     }
 
   int taxisID1 = vlistInqTaxis(vlistID1);
@@ -771,16 +472,19 @@ void *Setpartab(void *argument)
 
       streamDefTimestep(streamID2, tsID1);
 	       
+      cmor_check_init(nvars, vars);
+
       for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
+          var_t *var = &vars[varID];
 	  int varID2 = varID;
 	  int levelID2 = levelID;
 
 	  if ( delvars )
 	    {
-	      if ( vars[varID].remove ) continue;
+	      if ( var->remove ) continue;
 
 	      if ( vlistInqFlag(vlistID1, varID, levelID) == TRUE )
 		{
@@ -797,48 +501,50 @@ void *Setpartab(void *argument)
 	  gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID2));
 	  if ( vlistInqVarNumber(vlistID2, varID2) != CDI_REAL ) gridsize *= 2;
 
-	  if ( nmiss > 0 && vars[varID].changemissval )
+	  if ( nmiss > 0 && var->changemissval )
 	    {
 	      for ( long i = 0; i < gridsize; ++i )
 		{
-		  if ( DBL_IS_EQUAL(array[i], vars[varID].missval_old) ) array[i] = missval;
+		  if ( DBL_IS_EQUAL(array[i], var->missval_old) ) array[i] = missval;
 		}
 	    }
 
-	  if ( vars[varID].lfactor )
+	  if ( var->lfactor )
 	    {
 	      for ( long i = 0; i < gridsize; ++i )
 		{
-		  if ( !DBL_IS_EQUAL(array[i], missval) ) array[i] *= vars[varID].factor;
+		  if ( !DBL_IS_EQUAL(array[i], missval) ) array[i] *= var->factor;
 		}
 	    }
 
 #if defined(HAVE_UDUNITS2)
-	  if ( vars[varID].changeunits )
+	  if ( var->changeunits )
 	    {
 	      int nerr = 0;
 	      for ( long i = 0; i < gridsize; ++i )
 		{
 		  if ( !DBL_IS_EQUAL(array[i], missval) )
 		    {
-		      array[i] = cv_convert_double((const cv_converter*)vars[varID].ut_converter, array[i]);
+		      array[i] = cv_convert_double((const cv_converter*)var->ut_converter, array[i]);
 		      if ( ut_get_status() != UT_SUCCESS ) nerr++;
 		    }
 		}
 	      if ( nerr )
 		{
 		  cdoWarning("Udunits: Error converting units from [%s] to [%s], parameter: %s",
-			     vars[varID].units_old, vars[varID].units, vars[varID].name);
-		  vars[varID].changeunits = false;
+			     var->units_old, var->units, var->name);
+		  var->changeunits = false;
 		}
 	    }
 #endif
 	  
 	  streamWriteRecord(streamID2, array, nmiss);
 
-	  if ( vars[varID].checkvalid || vars[varID].check_min_mean_abs || vars[varID].check_max_mean_abs )
-	    check_data(vlistID2, varID2, varID, vars, gridsize, missval, array);
+          cmor_check_prep(var, gridsize, missval, array);
 	}
+
+      cmor_check_eval(vlistID2, nvars, vars);
+
       tsID1++;
     }
 
@@ -846,18 +552,10 @@ void *Setpartab(void *argument)
   streamClose(streamID1);
 
 #if defined(HAVE_UDUNITS2)
-  UDUNITS_LOCK();
-
   for ( int varID = 0; varID < nvars; varID++ )
-    if ( vars[varID].ut_converter ) cv_free((cv_converter*)vars[varID].ut_converter);
-
-  if ( ut_read )
-    { 
-      ut_free_system(ut_read);
-      ut_read = NULL;
-    }
+    if ( vars[varID].ut_converter ) cdoConvertFree(vars[varID].ut_converter);
 
-  UDUNITS_UNLOCK();
+  cdoConvertDestroy();
 #endif
 
   if ( array ) Free(array);
diff --git a/src/Setrcaname.c b/src/Setrcaname.c
index c90b5e9..c81a7ac 100644
--- a/src/Setrcaname.c
+++ b/src/Setrcaname.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -25,7 +25,7 @@
 void *Setrcaname(void *argument)
 {
   int nrecs;
-  int recID, varID, levelID;
+  int varID, levelID;
   char **rcsnames;
   char line[MAX_LINE_LEN];
   char sname[CDI_MAX_NAME], sdescription[CDI_MAX_NAME], sunits[CDI_MAX_NAME];
@@ -77,7 +77,7 @@ void *Setrcaname(void *argument)
 			  cdoWarning("Maybe environment variable SPLIT_LTYPE_105 is not set.");
 			  continue;
 			}
-		      level = (int) zaxisInqLevel(zaxisID, 0);
+		      level = (int) cdoZaxisInqLevel(zaxisID, 0);
 		      if ( sltype == 105 && slevel == level )
 			{
 			  vlistDefVarName(vlistID2, varID, sname);
@@ -125,7 +125,7 @@ void *Setrcaname(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamDefRecord(streamID2,  varID,  levelID);
diff --git a/src/Settime.c b/src/Settime.c
index 5ee5cb5..c2bcf0b 100644
--- a/src/Settime.c
+++ b/src/Settime.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -30,7 +30,6 @@
       Settime    shifttime       Shift timesteps
 */
 
-#include <ctype.h>  /* isdigit */
 
 #include <cdi.h>
 #include "cdo.h"
@@ -41,9 +40,7 @@
 
 int get_tunits(const char *unit, int *incperiod, int *incunit, int *tunit)
 {
-  size_t len;
-	
-  len = strlen(unit);
+  size_t len = strlen(unit);
   
   if      ( memcmp(unit, "seconds", len) == 0 ) { *incunit =     1; *tunit = TUNIT_SECOND;  }
   else if ( memcmp(unit, "minutes", len) == 0 ) { *incunit =    60; *tunit = TUNIT_MINUTE;  }
@@ -141,8 +138,7 @@ void gen_bounds(int calendar, int tunit, int vdate, int vtime, int *vdateb, int
 void *Settime(void *argument)
 {
   int nrecs, newval = 0;
-  int tsID1, recID, varID, levelID;
-  int vdate, vtime;
+  int varID, levelID;
   int vdateb[2], vtimeb[2];
   int sdate = 0, stime = 0;
   int taxisID2 = CDI_UNDEFID;
@@ -152,12 +148,10 @@ void *Settime(void *argument)
   int ijulinc = 0, incperiod = 1, incunit = 86400;
   int year = 1, month = 1, day = 1, hour = 0, minute = 0, second = 0;
   int day0;
-  int copy_timestep = FALSE;
+  bool copy_timestep = false;
   int newcalendar = CALENDAR_STANDARD;
   // int nargs;
-  const char *datestr, *timestr;
   juldate_t juldate;
-  double *array = NULL;
 
   cdoInitialize(argument);
 
@@ -185,8 +179,8 @@ void *Settime(void *argument)
       if ( operatorArgc() < 2 ) cdoAbort("Too few arguments!");
       if ( operatorArgc() > 3 ) cdoAbort("Too many arguments!");
 
-      datestr = operatorArgv()[0];
-      timestr = operatorArgv()[1];
+      const char *datestr = operatorArgv()[0];
+      const char *timestr = operatorArgv()[1];
 
       if ( strchr(datestr+1, '-') )
 	{
@@ -226,7 +220,7 @@ void *Settime(void *argument)
   else if ( operatorID == SETDATE )
     {
       operatorCheckArgc(1);
-      datestr = operatorArgv()[0];
+      const char *datestr = operatorArgv()[0];
       if ( strchr(datestr, '-') )
 	{
 	  sscanf(datestr, "%d-%d-%d", &year, &month, &day);
@@ -240,7 +234,7 @@ void *Settime(void *argument)
   else if ( operatorID == SETTIME )
     {
       operatorCheckArgc(1);
-      timestr = operatorArgv()[0];
+      const char *timestr = operatorArgv()[0];
 
       if ( strchr(timestr, ':') )
 	{
@@ -332,7 +326,7 @@ void *Settime(void *argument)
 
   if ( operatorID == SETREFTIME )
     {
-      copy_timestep = TRUE;
+      copy_timestep = true;
 
       if ( taxisInqType(taxisID1) == TAXIS_ABSOLUTE )
 	{
@@ -348,7 +342,7 @@ void *Settime(void *argument)
     }
   else if ( operatorID == SETTUNITS )
     {
-      copy_timestep = TRUE;
+      copy_timestep = true;
 
       if ( taxisInqType(taxisID1) == TAXIS_ABSOLUTE )
 	{
@@ -362,14 +356,14 @@ void *Settime(void *argument)
     }
   else if ( operatorID == SETCALENDAR )
     {
-      copy_timestep = TRUE;
+      copy_timestep = true;
       /*
       if ( ((char *)argument)[0] == '-' )
 	cdoAbort("This operator does not work with pipes!");
       */
       if ( taxisInqType(taxisID1) == TAXIS_ABSOLUTE )
 	{/*
-	  if ( cdoFiletype() != FILETYPE_NC )
+	  if ( cdoFiletype() != CDI_FILETYPE_NC )
 	    cdoAbort("This operator does not work on an absolute time axis!");
 	 */
 	  cdoPrint("Changing absolute to relative time axis!");
@@ -398,7 +392,7 @@ void *Settime(void *argument)
     }
 
   if ( operatorID != SHIFTTIME )
-    if ( taxis_has_bounds && copy_timestep == FALSE )
+    if ( taxis_has_bounds && !copy_timestep )
       {
 	cdoWarning("Time bounds unsupported by this operator, removed!");
 	taxisDeleteBounds(taxisID2);
@@ -413,13 +407,13 @@ void *Settime(void *argument)
 
   gridsize = vlistGridsizeMax(vlistID1);
   if ( vlistNumber(vlistID1) != CDI_REAL ) gridsize *= 2;
-  array = (double*) Malloc(gridsize*sizeof(double));
+  double *array = (double*) Malloc(gridsize*sizeof(double));
 
-  tsID1 = 0;
+  int tsID1 = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID1)) )
     {
-      vdate = taxisInqVdate(taxisID1);
-      vtime = taxisInqVtime(taxisID1);
+      int vdate = taxisInqVdate(taxisID1);
+      int vtime = taxisInqVtime(taxisID1);
 
       if ( operatorID == SETTAXIS )
 	{
@@ -521,7 +515,7 @@ void *Settime(void *argument)
 
       streamDefTimestep(streamID2, tsID1);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamDefRecord(streamID2,  varID,  levelID);
diff --git a/src/Setzaxis.c b/src/Setzaxis.c
index 0adcc29..08c1fa5 100644
--- a/src/Setzaxis.c
+++ b/src/Setzaxis.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -54,12 +54,12 @@ int getkeyval_dp(const char *keyval, const char *key, double *val)
 void *Setzaxis(void *argument)
 {
   int nrecs;
-  int recID, varID, levelID;
+  int varID, levelID;
   int zaxisID1, zaxisID2 = -1;
   int nzaxis, index;
   int nmiss;
   int found;
-  int lztop = FALSE, lzbot = FALSE;
+  bool lztop = false, lzbot = false;
   double ztop = 0, zbot = 0;
 
   cdoInitialize(argument);
@@ -84,8 +84,8 @@ void *Setzaxis(void *argument)
         {
           if ( cdoVerbose ) cdoPrint("keyval[%d]: %s", i+1, parnames[i]);
           
-          if      ( !lzbot && getkeyval_dp(parnames[i], "zbot", &zbot) ) lzbot = TRUE;
-          else if ( !lztop && getkeyval_dp(parnames[i], "ztop", &ztop) ) lztop = TRUE;
+          if      ( !lzbot && getkeyval_dp(parnames[i], "zbot", &zbot) ) lzbot = true;
+          else if ( !lztop && getkeyval_dp(parnames[i], "ztop", &ztop) ) lztop = true;
           else cdoAbort("Parameter >%s< unsupported! Supported parameter are: zbot, ztop", parnames[i]);
         }
     }
@@ -130,8 +130,9 @@ void *Setzaxis(void *argument)
 
           if ( nlev > 1 )
             {
-              zaxisInqLevels(zaxisID1, levels);
+              cdoZaxisInqLevels(zaxisID1, levels);
               zaxisID2 = zaxisDuplicate(zaxisID1);
+              if ( !zaxisInqLevels(zaxisID1, NULL) ) zaxisDefLevels(zaxisID2, levels);
 
               genLayerBounds(nlev, levels, lbounds, ubounds);
 
@@ -161,7 +162,7 @@ void *Setzaxis(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamDefRecord(streamID2,  varID,  levelID);
diff --git a/src/Shiftxy.c b/src/Shiftxy.c
new file mode 100644
index 0000000..21f54d2
--- /dev/null
+++ b/src/Shiftxy.c
@@ -0,0 +1,298 @@
+/*
+  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.
+*/
+
+/*
+   This module contains the following operators:
+
+      Selbox     sellonlatbox    Select lon/lat box
+      Selbox     selindexbox     Select index box
+*/
+
+#include <cdi.h>
+#include "cdo.h"
+#include "cdo_int.h"
+#include "grid.h"
+#include "pstream.h"
+
+
+static
+void shiftx(bool lcyclic, int nshift, int nx, int ny, const double *array1, double *array2, double missval)
+{
+  for ( int i = 0; i < nx; i++ )
+    {
+      bool is_cyclic = false;
+      int ins = i + nshift%nx;
+      while ( ins >= nx ) { ins -= nx; is_cyclic = true; }
+      while ( ins <   0 ) { ins += nx; is_cyclic = true; }
+        
+      if ( !lcyclic && is_cyclic )
+        {
+          for ( int j = 0; j < ny; j++ )
+            array2[IX2D(j,ins,nx)] = missval;
+        }
+      else
+        {
+          for ( int j = 0; j < ny; j++ )
+            array2[IX2D(j,ins,nx)] = array1[IX2D(j,i,nx)];
+        }
+    }
+}
+
+static
+void shifty(bool lcyclic, int nshift, int nx, int ny, const double *array1, double *array2, double missval)
+{
+  for ( int j = 0; j < ny; j++ )
+    {
+      bool is_cyclic = false;
+      int jns = j + nshift%ny;
+
+      while ( jns >= ny ) { jns -= ny; is_cyclic = true; }
+      while ( jns <   0 ) { jns += ny; is_cyclic = true; }
+
+      if ( !lcyclic && is_cyclic )
+        {
+          for ( int i = 0; i < nx; i++ )
+            array2[IX2D(jns,i,nx)] = missval;
+        }
+      else
+        {
+          for ( int i = 0; i < nx; i++ )
+            array2[IX2D(jns,i,nx)] = array1[IX2D(j,i,nx)];
+        }
+    }
+}
+
+static
+int shiftx_coord(bool lcyclic, int nshift, int gridID1)
+{
+  int gridID2 = gridDuplicate(gridID1);
+
+  int nx = gridInqXsize(gridID1);
+  int ny = gridInqYsize(gridID1);
+  if ( gridInqType(gridID1) != GRID_CURVILINEAR ) ny = 1;
+
+  double *array1 = (double*) Malloc(nx*ny*sizeof(double));
+  double *array2 = (double*) Malloc(nx*ny*sizeof(double));
+
+  gridInqXvals(gridID1, array1);
+  shiftx(lcyclic, nshift, nx, ny, array1, array2, 0);
+  gridDefXvals(gridID2, array2);
+
+  if ( gridInqXbounds(gridID1, NULL) )
+    {
+      int nv = 4;
+      if ( gridInqType(gridID1) != GRID_CURVILINEAR ) nv = 2;
+      
+      double *bounds = (double*) Malloc(nx*ny*nv*sizeof(double));
+      gridInqXbounds(gridID1, bounds);
+      for ( int k = 0; k < nv; ++k )
+        {
+          for ( int i = 0; i < nx*ny; ++i ) array1[i] = bounds[i*nv+k];
+          shiftx(lcyclic, nshift, nx, ny, array1, array2, 0);
+          for ( int i = 0; i < nx*ny; ++i ) bounds[i*nv+k] = array2[i];
+        }
+      gridDefXbounds(gridID2, bounds);
+      Free(bounds);
+    }
+
+  Free(array2);
+  Free(array1);
+
+  return gridID2;
+}
+
+static
+int shifty_coord(bool lcyclic, int nshift, int gridID1)
+{
+  int gridID2 = gridDuplicate(gridID1);
+
+  int nx = gridInqXsize(gridID1);
+  int ny = gridInqYsize(gridID1);
+  if ( gridInqType(gridID1) != GRID_CURVILINEAR ) nx = 1;
+
+  double *array1 = (double*) Malloc(nx*ny*sizeof(double));
+  double *array2 = (double*) Malloc(nx*ny*sizeof(double));
+
+  gridInqYvals(gridID1, array1);
+  shifty(lcyclic, nshift, nx, ny, array1, array2, 0);
+  gridDefYvals(gridID2, array2);
+
+  if ( gridInqYbounds(gridID1, NULL) )
+    {
+      int nv = 4;
+      if ( gridInqType(gridID1) != GRID_CURVILINEAR ) nv = 2;
+      
+      double *bounds = (double*) Malloc(nx*ny*nv*sizeof(double));
+      gridInqYbounds(gridID1, bounds);
+      for ( int k = 0; k < nv; ++k )
+        {
+          for ( int i = 0; i < nx*ny; ++i ) array1[i] = bounds[i*nv+k];
+          shifty(lcyclic, nshift, nx, ny, array1, array2, 0);
+          for ( int i = 0; i < nx*ny; ++i ) bounds[i*nv+k] = array2[i];
+        }
+      gridDefYbounds(gridID2, bounds);
+      Free(bounds);
+    }
+
+  Free(array2);
+  Free(array1);
+
+  return gridID2;
+}
+
+
+void *Shiftxy(void *argument)
+{
+  bool lcyclic = false;
+  bool lcoord = false;
+  int nrecs;
+  int varID, levelID;
+  int nmiss;
+
+  cdoInitialize(argument);
+
+  int SHIFTX = cdoOperatorAdd("shiftx", 0, 0, NULL);
+  int SHIFTY = cdoOperatorAdd("shifty", 0, 0, NULL);
+
+  int operatorID = cdoOperatorID();
+
+  int nshift = 1;
+  if ( operatorArgc() > 0 )
+    {
+      nshift = parameter2int(operatorArgv()[0]);
+      int pargc = operatorArgc();
+      char **pargv = operatorArgv();
+      for ( int ic = 1; ic < pargc; ++ic )
+        {
+          if      ( strcmp(pargv[ic], "cyclic") == 0 ) lcyclic = true;
+          else if ( strcmp(pargv[ic], "coord") == 0 ) lcoord = true;
+        }
+    }
+
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
+
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
+  vlistDefTaxis(vlistID2, taxisID2);
+
+  int nvars = vlistNvars(vlistID1);
+  bool *vars = (bool*) Malloc(nvars*sizeof(bool));
+  for ( varID = 0; varID < nvars; varID++ ) vars[varID] = false;
+
+  int ngrids = vlistNgrids(vlistID1);
+  for ( int index = 0; index < ngrids; index++ )
+    {
+      int gridID1  = vlistGrid(vlistID1, index);
+      int gridtype = gridInqType(gridID1);
+
+      if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN || gridtype == GRID_CURVILINEAR ||
+           (gridtype == GRID_PROJECTION && gridInqProjType(gridID1) == CDI_PROJ_RLL) ||
+	   (gridtype == GRID_GENERIC && gridInqXsize(gridID1) > 0 && gridInqYsize(gridID1) > 0) )
+	{
+          if ( lcoord )
+            {
+              int gridID2 = -1;
+              if      ( operatorID == SHIFTX ) gridID2 = shiftx_coord(lcyclic, nshift, gridID1);
+              else if ( operatorID == SHIFTY ) gridID2 = shifty_coord(lcyclic, nshift, gridID1);
+
+              vlistChangeGridIndex(vlistID2, index, gridID2);
+            }
+
+	  for ( varID = 0; varID < nvars; varID++ )
+	    if ( gridID1 == vlistInqVarGrid(vlistID1, varID) )
+	      vars[varID] = true;
+	}
+      else if ( gridtype == GRID_GENERIC && gridInqXsize(gridID1) <= 1 && gridInqYsize(gridID1) <=1 )
+	{
+	}
+      else
+	{
+	  cdoPrint("Unsupported grid type: %s", gridNamePtr(gridtype));
+	  if ( gridtype == GRID_GAUSSIAN_REDUCED )
+	    cdoPrint("Use option -R to convert Gaussian reduced grid to a regular grid!");
+	  cdoAbort("Unsupported grid type!");
+	}
+    }
+
+  for ( varID = 0; varID < nvars; varID++ )
+    if ( vars[varID] ) break;
+
+  if ( varID >= nvars ) cdoWarning("No variables selected!");
+
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+
+  streamDefVlist(streamID2, vlistID2);
+
+  int gridsize = vlistGridsizeMax(vlistID1);
+  double *array1 = (double*) Malloc(gridsize*sizeof(double));
+  double *array2 = (double*) Malloc(gridsize*sizeof(double));
+
+  int tsID = 0;
+  while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
+    {
+      taxisCopyTimestep(taxisID2, taxisID1);
+      streamDefTimestep(streamID2, tsID);
+	       
+      for ( int recID = 0; recID < nrecs; recID++ )
+	{
+	  streamInqRecord(streamID1, &varID, &levelID);
+	  streamReadRecord(streamID1, array1, &nmiss);
+
+	  streamDefRecord(streamID2, varID, levelID);
+
+	  if ( vars[varID] )
+	    {	      
+	      int gridID1 = vlistInqVarGrid(vlistID1, varID);
+	      int gridsize = gridInqSize(gridID1);
+              double missval = vlistInqVarMissval(vlistID2, varID);
+                  
+              int nx = gridInqXsize(gridID1);
+              int ny = gridInqYsize(gridID1);
+
+              if      ( operatorID == SHIFTX ) shiftx(lcyclic, nshift, nx, ny, array1, array2, missval);
+              else if ( operatorID == SHIFTY ) shifty(lcyclic, nshift, nx, ny, array1, array2, missval);
+
+              nmiss = 0;
+              for ( int i = 0; i < gridsize; i++ )
+                if ( DBL_IS_EQUAL(array2[i], missval) ) nmiss++;
+
+	      streamWriteRecord(streamID2, array2, nmiss);
+	    }
+	  else
+	    {
+	      streamWriteRecord(streamID2, array1, nmiss);
+	    }
+	}
+      tsID++;
+    }
+
+  streamClose(streamID2);
+  streamClose(streamID1);
+
+  vlistDestroy(vlistID2);
+
+  if ( vars   ) Free(vars);
+  if ( array2 ) Free(array2);
+  if ( array1 ) Free(array1);
+
+  cdoFinish();
+
+  return 0;
+}
diff --git a/src/Showinfo.c b/src/Showinfo.c
index b62d2c9..f0f6a5c 100644
--- a/src/Showinfo.c
+++ b/src/Showinfo.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -254,7 +254,7 @@ void *Showinfo(void *argument)
 	  zaxisID = vlistInqVarZaxis(vlistID, varID);
 	  nlevs = zaxisInqSize(zaxisID);
 	  for ( levelID = 0; levelID < nlevs; levelID++ )
-	    fprintf(stdout, " %.9g", zaxisInqLevel(zaxisID, levelID));
+	    fprintf(stdout, " %.9g", cdoZaxisInqLevel(zaxisID, levelID));
 	  fprintf(stdout, "\n");
 	}
     }
diff --git a/src/Sinfo.c b/src/Sinfo.c
index e75b9d8..48f4d38 100644
--- a/src/Sinfo.c
+++ b/src/Sinfo.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -89,9 +89,6 @@ void *Sinfo(void *argument)
   char varname[CDI_MAX_NAME];
   char paramstr[32];
   char vdatestr[32], vtimestr[32];
-  const char *modelptr, *instptr;
-  int streamID = 0;
-  int vlistID;
   int datatype;
   char pstr[4];
 
@@ -113,9 +110,9 @@ void *Sinfo(void *argument)
 
   for ( int indf = 0; indf < cdoStreamCnt(); indf++ )
     {
-      streamID = streamOpenRead(cdoStreamName(indf));
+      int streamID = streamOpenRead(cdoStreamName(indf));
 
-      vlistID = streamInqVlist(streamID);
+      int vlistID = streamInqVlist(streamID);
 
       set_text_color(stdout, BRIGHT, BLACK);
       fprintf(stdout, "   File format");
@@ -159,14 +156,14 @@ void *Sinfo(void *argument)
 	      
 	  set_text_color(stdout, RESET, BLUE);
 	  /* institute info */
-	  instptr = institutInqNamePtr(vlistInqVarInstitut(vlistID, varID));
+	  const char *instptr = institutInqNamePtr(vlistInqVarInstitut(vlistID, varID));
 	  strcpy(tmpname, "unknown");
 	  if ( instptr ) strncpy(tmpname, instptr, CDI_MAX_NAME);
 	  limit_string_length(tmpname, CDI_MAX_NAME);
 	  fprintf(stdout, "%-8s ", tmpname);
 
 	  /* source info */
-	  modelptr = modelInqNamePtr(vlistInqVarModel(vlistID, varID));
+	  const char *modelptr = modelInqNamePtr(vlistInqVarModel(vlistID, varID));
 	  strcpy(tmpname, "unknown");
 	  if ( modelptr ) strncpy(tmpname, modelptr, CDI_MAX_NAME);
 	  limit_string_length(tmpname, CDI_MAX_NAME);
@@ -203,24 +200,30 @@ void *Sinfo(void *argument)
               fprintf(stdout, " %6d  ", subtypesize);
               fprintf(stdout, "%3d ", vlistSubtypeIndex(vlistID, subtypeID) + 1);
             }
+	  reset_text_color(stdout);
 
 	  /* layer info */
 	  levelsize = zaxisInqSize(zaxisID);
+	  set_text_color(stdout, RESET, GREEN);
 	  fprintf(stdout, "%6d ", levelsize);
+	  reset_text_color(stdout);
 	  fprintf(stdout, "%3d ", vlistZaxisIndex(vlistID, zaxisID) + 1);
 
 	  /* grid info */
 	  gridsize = gridInqSize(gridID);
+	  set_text_color(stdout, RESET, GREEN);
 	  fprintf(stdout, "%9d ", gridsize);
+	  reset_text_color(stdout);
 	  fprintf(stdout, "%3d ", vlistGridIndex(vlistID, gridID) + 1);
 
 	  /* datatype */
 	  datatype = vlistInqVarDatatype(vlistID, varID);
 	  datatype2str(datatype, pstr);
 
+	  set_text_color(stdout, RESET, BLUE);
 	  fprintf(stdout, " %-3s", pstr);
 
-	  if ( vlistInqVarCompType(vlistID, varID) == COMPRESS_NONE )
+	  if ( vlistInqVarCompType(vlistID, varID) == CDI_COMPRESS_NONE )
 	    fprintf(stdout, "  ");
 	  else
 	    fprintf(stdout, "z ");
diff --git a/src/Smooth.c b/src/Smooth.c
index 36e1170..fdc7c25 100644
--- a/src/Smooth.c
+++ b/src/Smooth.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -46,9 +46,9 @@ typedef struct {
 
 double intlin(double x, double y1, double x1, double y2, double x2);
 
-double smooth_knn_compute_weights(unsigned num_neighbors, const int *restrict src_grid_mask, struct gsknn *knn, double search_radius, double weight0, double weightR)
+double smooth_knn_compute_weights(unsigned num_neighbors, const bool *restrict src_grid_mask, struct gsknn *knn, double search_radius, double weight0, double weightR)
 {
-  int *restrict nbr_mask = knn->mask;
+  bool *restrict nbr_mask = knn->mask;
   const int *restrict nbr_add = knn->add;
   double *restrict nbr_dist = knn->dist;
 
@@ -57,12 +57,12 @@ double smooth_knn_compute_weights(unsigned num_neighbors, const int *restrict sr
 
   for ( unsigned n = 0; n < num_neighbors; ++n )
     {
-      nbr_mask[n] = FALSE;
+      nbr_mask[n] = false;
       if ( nbr_add[n] >= 0 && src_grid_mask[nbr_add[n]] )
         {
           nbr_dist[n] = intlin(nbr_dist[n], weight0, 0, weightR, search_radius);
           dist_tot += nbr_dist[n];
-          nbr_mask[n] = TRUE;
+          nbr_mask[n] = true;
         }
     }
 
@@ -72,7 +72,7 @@ double smooth_knn_compute_weights(unsigned num_neighbors, const int *restrict sr
 
 unsigned smooth_knn_normalize_weights(unsigned num_neighbors, double dist_tot, struct gsknn *knn)
 {
-  const int *restrict nbr_mask = knn->mask;
+  const bool *restrict nbr_mask = knn->mask;
   int *restrict nbr_add = knn->add;
   double *restrict nbr_dist = knn->dist;
 
@@ -101,9 +101,9 @@ void smooth(int gridID, double missval, const double *restrict array1, double *r
   unsigned num_neighbors = spoint.maxpoints;
   if ( num_neighbors > gridsize ) num_neighbors = gridsize;
 
-  int *mask = (int*) Malloc(gridsize*sizeof(int));
+  bool *mask = (bool*) Malloc(gridsize*sizeof(bool));
   for ( unsigned i = 0; i < gridsize; ++i )
-    mask[i] = DBL_IS_EQUAL(array1[i], missval) ? 0 : 1;
+    mask[i] = !DBL_IS_EQUAL(array1[i], missval);
   
   double *xvals = (double*) Malloc(gridsize*sizeof(double));
   double *yvals = (double*) Malloc(gridsize*sizeof(double));
@@ -210,7 +210,7 @@ void smooth(int gridID, double missval, const double *restrict array1, double *r
 }
 
 static inline
-void smooth9_sum(size_t ij, short *mask, double sfac, const double *restrict array, double *avg, double *divavg)
+void smooth9_sum(size_t ij, bool *mask, double sfac, const double *restrict array, double *avg, double *divavg)
 {
   if ( mask[ij] ) { *avg += sfac*array[ij]; *divavg += sfac; }
 }
@@ -223,13 +223,10 @@ void smooth9(int gridID, double missval, const double *restrict array1, double *
   size_t nlat = gridInqYsize(gridID);
   int grid_is_cyclic = gridIsCircular(gridID);
 
-  short *mask = (short*) Malloc(gridsize*sizeof(short));
+  bool *mask = (bool*) Malloc(gridsize*sizeof(bool));
 
   for ( size_t i = 0; i < gridsize; ++i ) 
-    {		
-      if ( DBL_IS_EQUAL(missval, array1[i]) ) mask[i] = 0;
-      else mask[i] = 1;
-    }
+    mask[i] = !DBL_IS_EQUAL(missval, array1[i]);
  
   *nmiss = 0;
   for ( size_t i = 0; i < nlat; i++ )
@@ -292,7 +289,7 @@ void smooth9(int gridID, double missval, const double *restrict array1, double *
             }
           else if ( mask[j+nlon*i] )
             {			 
-              avg += array1[j+nlon*i]; divavg+= 1;
+              avg += array1[j+nlon*i]; divavg += 1;
 			    
               smooth9_sum(((i-1)*nlon)+j-1, mask, 0.3, array1, &avg, &divavg);
               smooth9_sum(((i-1)*nlon)+j,   mask, 0.5, array1, &avg, &divavg);
@@ -319,22 +316,18 @@ void smooth9(int gridID, double missval, const double *restrict array1, double *
   Free(mask);
 }
 
-static
-double convert_radius(const char *string)
+
+double radius_str_to_deg(const char *string)
 {
   char *endptr = NULL;
   double radius = strtod(string, &endptr);
 
   if ( *endptr != 0 )
     {
-      if ( strcmp(endptr, "km") == 0 )
-        radius = 360*((radius*1000)/(2*PlanetRadius*M_PI));
-      else if ( strncmp(endptr, "m", 1) == 0 )
-        radius = 360*((radius)/(2*PlanetRadius*M_PI));
-      else if ( strncmp(endptr, "deg", 3) == 0 )
-        ;
-      else if ( strncmp(endptr, "rad", 3) == 0 )
-        radius *= RAD2DEG;
+      if      ( strcmp(endptr, "km") == 0 )      radius = 360*((radius*1000)/(2*PlanetRadius*M_PI));
+      else if ( strncmp(endptr, "m", 1) == 0 )   radius = 360*((radius)/(2*PlanetRadius*M_PI));
+      else if ( strncmp(endptr, "deg", 3) == 0 ) ;
+      else if ( strncmp(endptr, "rad", 3) == 0 ) radius *= RAD2DEG;
       else
         cdoAbort("Float parameter >%s< contains invalid character at position %d!",
                  string, (int)(endptr-string+1));
@@ -356,6 +349,44 @@ int convert_form(const char *formstr)
   return form;
 }
 
+static
+void smooth_set_parameter(int *xnsmooth, smoothpoint_t *spoint)
+{
+  int pargc = operatorArgc();
+
+  if ( pargc )
+    { 
+      char **pargv = operatorArgv();
+
+      list_t *kvlist = list_new(sizeof(keyValues_t *), free_keyval, "SMOOTH");
+      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, "nsmooth")   ) *xnsmooth = parameter2int(value);
+          else if ( STR_IS_EQ(key, "maxpoints") ) spoint->maxpoints = parameter2int(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);
+          else if ( STR_IS_EQ(key, "form")      ) spoint->form = convert_form(value);
+          else cdoAbort("Invalid parameter key >%s<!", key);
+        }          
+          
+      list_destroy(kvlist);
+    }
+      
+  if ( cdoVerbose )
+    cdoPrint("nsmooth = %d, maxpoints = %d, radius = %gdeg, form = %s, weight0 = %g, weightR = %g",
+             *xnsmooth, spoint->maxpoints, spoint->radius, Form[spoint->form], spoint->weight0, spoint->weightR);
+}
+
 
 void *Smooth(void *argument)
 {
@@ -377,47 +408,9 @@ void *Smooth(void *argument)
  
   int operatorID = cdoOperatorID();
 
-  if ( operatorID == SMOOTH )
-    {
-      int pargc = operatorArgc();
+  if ( operatorID == SMOOTH ) smooth_set_parameter(&xnsmooth, &spoint);
 
-      if ( pargc )
-        {
-          char **pargv = operatorArgv();
-          pml_t *pml = pml_create("SMOOTH");
-
-          PML_ADD_INT(pml, nsmooth,   1, "Number of times to smooth");
-          PML_ADD_INT(pml, maxpoints, 1, "Maximum number of points");
-          PML_ADD_FLT(pml, weight0,   1, "Weight at distance 0");
-          PML_ADD_FLT(pml, weightR,   1, "Weight at the search radius");
-          PML_ADD_WORD(pml, radius,   1, "Search radius");
-          PML_ADD_WORD(pml, form,     1, "Form of the curve (linear, exponential, gauss)");
-      
-          int status = pml_read(pml, pargc, pargv);
-          if ( cdoVerbose ) pml_print(pml);
-          if ( status != 0 ) cdoAbort("Parameter read error!");
-          
-          if ( PML_NOCC(pml, nsmooth) )   xnsmooth         = par_nsmooth[0];
-          if ( PML_NOCC(pml, maxpoints) ) spoint.maxpoints = par_maxpoints[0];
-          if ( PML_NOCC(pml, weight0) )   spoint.weight0   = par_weight0[0];
-          if ( PML_NOCC(pml, weightR) )   spoint.weightR   = par_weightR[0];
-          if ( PML_NOCC(pml, radius) )    spoint.radius    = convert_radius(par_radius[0]);
-          if ( PML_NOCC(pml, form) )      spoint.form      = convert_form(par_form[0]);
-
-          UNUSED(nsmooth);
-          UNUSED(maxpoints);
-          UNUSED(radius);
-          UNUSED(form);
-          UNUSED(weight0);
-          UNUSED(weightR);
-
-          pml_destroy(pml);
-        }
-      
-      if ( cdoVerbose )
-        cdoPrint("nsmooth = %d, maxpoints = %d, radius = %gdegree, form = %s, weight0 = %g, weightR = %g",
-                 xnsmooth, spoint.maxpoints, spoint.radius, Form[spoint.form], spoint.weight0, spoint.weightR);
-    }
+  if ( spoint.radius < 0 || spoint.radius > 180 ) cdoAbort("%s=%g out of bounds (0-180 deg)!", "radius", spoint.radius);
 
   spoint.radius *= DEG2RAD;
 
diff --git a/src/Sort.c b/src/Sort.c
index bebe4ac..ff83ee3 100644
--- a/src/Sort.c
+++ b/src/Sort.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -147,7 +147,7 @@ void paramToStringLong(int param, char *paramstr, int maxlen)
 
 void *Sort(void *argument)
 {
-  int recID, varID, levelID, zaxisID;
+  int varID, levelID, zaxisID;
   int vindex, lindex;
   int nrecs, nlevs, offset;
   int gridsize;
@@ -219,7 +219,7 @@ void *Sort(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -232,7 +232,7 @@ void *Sort(void *argument)
 	      vlistInqVarName(vlistID1, varID, varInfo[varID].name);
 	      zaxisID = vlistInqVarZaxis(vlistID1, varID);
 	      varInfo[varID].levInfo[levelID].levelID = levelID;
-	      varInfo[varID].levInfo[levelID].level   = zaxisInqLevel(zaxisID, levelID);
+	      varInfo[varID].levInfo[levelID].level   = cdoZaxisInqLevel(zaxisID, levelID);
 	    }
 
 	  gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
diff --git a/src/Sorttimestamp.c b/src/Sorttimestamp.c
index fe7fc79..b18fb8e 100644
--- a/src/Sorttimestamp.c
+++ b/src/Sorttimestamp.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -49,7 +49,7 @@ int cmpdatetime(const void *s1, const void *s2)
   if      ( x->datetime < y->datetime ) cmp = -1;
   else if ( x->datetime > y->datetime ) cmp =  1;
 
-  return (cmp);
+  return cmp;
 }
 
 
@@ -57,30 +57,26 @@ void *Sorttimestamp(void *argument)
 {
   int gridsize;
   int nrecs;
-  int gridID, varID, levelID, recID;
-  int tsID, tsID2, xtsID, lasttsID = -1;
-  int nfiles, fileID;
-  int nts;
+  int gridID, varID, levelID;
+  int tsID, lasttsID = -1;
   int nalloc = 0;
-  int streamID1, streamID2;
-  int vlistID1 = -1, vlistID2 = -1, taxisID1, taxisID2 = -1;
+  int vlistID2 = -1, taxisID2 = -1;
   int nmiss;
   int nvars = 0, nlevel;
   int *vdate = NULL, *vtime = NULL;
-  field_t ***vars = NULL;
-  timeinfo_t *timeinfo;
+  field_type ***vars = NULL;
 
   cdoInitialize(argument);
 
-  nfiles = cdoStreamCnt() - 1;
+  int nfiles = cdoStreamCnt() - 1;
 
-  xtsID = 0;
-  for ( fileID = 0; fileID < nfiles; fileID++ )
+  int xtsID = 0;
+  for ( int fileID = 0; fileID < nfiles; fileID++ )
     {
-      streamID1 = streamOpenRead(cdoStreamName(fileID));
+      int streamID1 = streamOpenRead(cdoStreamName(fileID));
 
-      vlistID1 = streamInqVlist(streamID1);
-      taxisID1 = vlistInqTaxis(vlistID1);
+      int vlistID1 = streamInqVlist(streamID1);
+      int taxisID1 = vlistInqTaxis(vlistID1);
 
       if ( fileID == 0 )
 	{
@@ -99,7 +95,7 @@ void *Sorttimestamp(void *argument)
 
       nvars = vlistNvars(vlistID1);
 
-      tsID = 0;
+      int tsID = 0;
       while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
 	{
 	  if ( xtsID >= nalloc )
@@ -107,7 +103,7 @@ void *Sorttimestamp(void *argument)
 	      nalloc += NALLOC_INC;
 	      vdate = (int*) Realloc(vdate, nalloc*sizeof(int));
 	      vtime = (int*) Realloc(vtime, nalloc*sizeof(int));
-	      vars  = (field_t ***) Realloc(vars, nalloc*sizeof(field_t **));
+	      vars  = (field_type ***) Realloc(vars, nalloc*sizeof(field_type **));
 	    }
 
 	  vdate[xtsID] = taxisInqVdate(taxisID1);
@@ -115,7 +111,7 @@ void *Sorttimestamp(void *argument)
 
 	  vars[xtsID] = field_malloc(vlistID1, FIELD_NONE);
 
-	  for ( recID = 0; recID < nrecs; recID++ )
+	  for ( int recID = 0; recID < nrecs; recID++ )
 	    {
 	      streamInqRecord(streamID1, &varID, &levelID);
 	      gridID   = vlistInqVarGrid(vlistID1, varID);
@@ -132,19 +128,16 @@ void *Sorttimestamp(void *argument)
       streamClose(streamID1);
     }
 
-  nts = xtsID;
+  int nts = xtsID;
 
-  timeinfo= (timeinfo_t*) Malloc(nts*sizeof(timeinfo_t));
+  timeinfo_t *timeinfo= (timeinfo_t*) Malloc(nts*sizeof(timeinfo_t));
 
   for ( tsID = 0; tsID < nts; tsID++ )
     {
-      int calendar, julday, secofday;
-      double vdatetime;
-
-      calendar = taxisInqCalendar(taxisID2);
-      julday = date_to_julday(calendar, vdate[tsID]);
-      secofday = time_to_sec(vtime[tsID]);
-      vdatetime = julday + secofday / 86400.;
+      int calendar = taxisInqCalendar(taxisID2);
+      int julday = date_to_julday(calendar, vdate[tsID]);
+      int secofday = time_to_sec(vtime[tsID]);
+      double vdatetime = julday + secofday / 86400.;
       timeinfo[tsID].index    = tsID;
       timeinfo[tsID].datetime = vdatetime;
     }
@@ -155,11 +148,11 @@ void *Sorttimestamp(void *argument)
 
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(nfiles), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(nfiles), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  tsID2 = 0;
+  int tsID2 = 0;
   for ( tsID = 0; tsID < nts; tsID++ )
     {
       xtsID = timeinfo[tsID].index;
diff --git a/src/Specinfo.c b/src/Specinfo.c
index 406d964..e697191 100644
--- a/src/Specinfo.c
+++ b/src/Specinfo.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -21,11 +21,11 @@
       Specinfo specinfo  Spectral information
 */
 
-#include <ctype.h>
 
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
+#include "grid.h"
 #include "pstream.h"
 
 
@@ -38,16 +38,14 @@
 #define NGP2NI(ngp)           ((int) sqrt((double)ngp/10.) - 1)
 
 
-static void fac(int nlonin, int *nlonout, int *ierr)
-{
-  int n2, n3, n5;
-  int m;
-  
-  n2 = 0;
-  n3 = 0;
-  n5 = 0;
+static
+void fac(int nlonin, int *nlonout, int *ierr)
+{  
+  int n2 = 0;
+  int n3 = 0;
+  int n5 = 0;
 
-  m = nlonin;
+  int m = nlonin;
 
   while (m%2 == 0)
     {
@@ -76,49 +74,14 @@ static void fac(int nlonin, int *nlonout, int *ierr)
   return;
 }
 
-
-static int compnlon(int nlat)
-{
-  int nlon, n;
-
-  nlon = 2 * nlat;
-
-  /* check that FFT works with nlon */
-  while ( 1 )
-    {
-      n = nlon;
-      if    ( n % 8 == 0 )  { n /= 8; }
-      while ( n % 6 == 0 )  { n /= 6; }
-      while ( n % 5 == 0 )  { n /= 5; }
-      while ( n % 4 == 0 )  { n /= 4; }
-      while ( n % 3 == 0 )  { n /= 3; }
-      if    ( n % 2 == 0 )  { n /= 2; }
-
-      if ( n <= 8 ) break;
-
-      nlon = nlon + 4;
-
-      if ( nlon > 9999 )
-	{
-	  nlon = 2 * nlat;
-	  fprintf(stderr, "FFT does not work with len %d!\n", nlon);
-	  break;
-	}
-    }
-
-  return (nlon);
-}
-
-
-static int nlat2nlon(int nlat)
+static
+int nlat2nlon(int nlat)
 {
-  int nlon, m, ierr;
+  if ( nlat == 0 ) cdoAbort("nlat = 0!");
 
-  if ( nlat == 0 )
-    cdoAbort("nlat = 0!");
-
-  nlon = 2*nlat;
+  int nlon = 2*nlat;
 
+  int m, ierr;
   fac(nlon, &m, &ierr);
   /* adjust till fft is possible */
   while (ierr != 0) 
@@ -129,30 +92,29 @@ static int nlat2nlon(int nlat)
       fac(nlon, &m, &ierr);
     }
 
-  return (nlon);
+  return nlon;
 }
 
 
 int ngp2ntr(int ngp)
 {
   int ntr   = (int)lround(sqrt(0.25+ngp)-1.5);
-  int nlonl = compnlon(ntr2nlat_linear(ntr));
+  int nlonl = nlat_to_nlon(ntr_to_nlat_linear(ntr));
   int nlatl = nlonl/2;
 
   ntr = (2*nlatl-1)/2;
 
-  return (ntr);
+  return ntr;
 }
 
 
 int ipow(int i1, int i2)
 {
-  int i;
   int i3 = 1;
 
-  for ( i = 0; i < i2; ++i ) i3 *= i1;
+  for ( int i = 0; i < i2; ++i ) i3 *= i1;
 
-  return (i3);
+  return i3;
 }
 
 
@@ -251,7 +213,8 @@ void lookup_rl(int nsp, int *nroot, int *nlevel)
 void *Specinfo(void *argument)
 {
   char arg[128], *parg;
-  int len, i, nout1 = 0, nout2 = 0;
+  bool nout1 = false, nout2 = false;
+  int i;
   int ntr1 = 0, nsp1 = 0, nlat1 = 0, nlon1 = 0, ngp1 = 0, ni1 = 0, ngp_gme1 = 0;
   int ntr2 = 0, nsp2 = 0, nlat2 = 0, nlon2 = 0, ngp2 = 0, ni2 = 0, ngp_gme2 = 0;
   int nlevel1 = 0, nlevel2 = 0, ngp_icon1 = 0, ngp_icon2 = 0;
@@ -261,7 +224,7 @@ void *Specinfo(void *argument)
 
   operatorInputArg("Txx, TLxx, NLON=xx, NLAT=xx, NIxx or ICONRyyLxx");
 
-  len = strlen(operatorArgv()[0]);
+  int len = strlen(operatorArgv()[0]);
 
   if ( (len+1) >= 128 ) cdoAbort("Parameter string too large!");
 
@@ -275,15 +238,15 @@ void *Specinfo(void *argument)
       if ( ! isdigit((int) *parg) ) cdoAbort("Wrong parameter: %s", arg);
       ntr2   = atoi(parg);
       nsp2   = NTR2NSP(ntr2);
-      nlat2  = ntr2nlat_linear(ntr2);
-      nlon2  = compnlon(nlat2);
+      nlat2  = ntr_to_nlat_linear(ntr2);
+      nlon2  = nlat_to_nlon(nlat2);
       ngp2   = nlon2*nlat2;
 
       lookup_ni(nsp2, &nrootg2, &ni2);
       lookup_rl(nsp2, &nrooti2, &nlevel2);
 
-      nout1  = FALSE;
-      nout2  = TRUE;
+      nout1  = false;
+      nout2  = true;
     }
   else if ( arg[0] == 'T' )
     {
@@ -292,15 +255,15 @@ void *Specinfo(void *argument)
       if ( ! isdigit((int) *parg) ) cdoAbort("Wrong parameter: %s", arg);
       ntr1   = atoi(parg);
       nsp1   = NTR2NSP(ntr1);
-      nlat1  = ntr2nlat(ntr1);
-      nlon1  = compnlon(nlat1);
+      nlat1  = ntr_to_nlat(ntr1);
+      nlon1  = nlat_to_nlon(nlat1);
       ngp1   = nlon1*nlat1;
 
       lookup_ni(nsp1, &nrootg1, &ni1);
       lookup_rl(nsp1, &nrooti1, &nlevel1);
 
-      nout1  = TRUE;
-      nout2  = FALSE;
+      nout1  = true;
+      nout2  = false;
     }
   else if ( arg[0] == 'N' && arg[1] == 'I' )
     {
@@ -318,12 +281,12 @@ void *Specinfo(void *argument)
       ntr1 = NSP2NTR(nsp1);
       ntr2 = ntr1;
 
-      nlat1 = ntr2nlat(ntr1);
-      nlon1 = compnlon(nlat1);
+      nlat1 = ntr_to_nlat(ntr1);
+      nlon1 = nlat_to_nlon(nlat1);
       nlat1 = nlon1/2;
 
-      nlat2 = ntr2nlat_linear(ntr2);
-      nlon2 = compnlon(nlat2);
+      nlat2 = ntr_to_nlat_linear(ntr2);
+      nlon2 = nlat_to_nlon(nlat2);
       nlat2 = nlon2/2;
 
       /* lookup_ni(nsp1, &nrootg1, &ni1); */
@@ -334,8 +297,8 @@ void *Specinfo(void *argument)
       nrooti2 = nrooti1;
       nlevel2 = nlevel1;
 
-      nout1  = TRUE;
-      nout2  = TRUE;
+      nout1  = true;
+      nout2  = true;
     }
   else if ( arg[0] == 'N' && arg[1] == 'L' && arg[2] == 'O' && arg[3] == 'N' )
     {
@@ -364,8 +327,8 @@ void *Specinfo(void *argument)
       lookup_ni(nsp2, &nrootg2, &ni2);
       lookup_rl(nsp2, &nrooti2, &nlevel2);
 
-      nout1  = TRUE;
-      nout2  = TRUE;
+      nout1  = true;
+      nout2  = true;
     }
   else if ( arg[0] == 'N' && arg[1] == 'L' && arg[2] == 'A' && arg[3] == 'T' )
     {
@@ -392,8 +355,8 @@ void *Specinfo(void *argument)
       lookup_ni(nsp2, &nrootg2, &ni2);
       lookup_rl(nsp2, &nrooti2, &nlevel2);
 
-      nout1  = TRUE;
-      nout2  = TRUE;
+      nout1  = true;
+      nout2  = true;
     }
   else if ( arg[0] == 'N' )
     {
@@ -420,8 +383,8 @@ void *Specinfo(void *argument)
       lookup_ni(nsp2, &nrootg2, &ni2);
       lookup_rl(nsp2, &nrooti2, &nlevel2);
 
-      nout1  = TRUE;
-      nout2  = TRUE;
+      nout1  = true;
+      nout2  = true;
     }
   else if ( arg[0] == 'I' && arg[1] == 'C' && arg[2] == 'O' && arg[3] == 'N' )
     {
@@ -445,12 +408,12 @@ void *Specinfo(void *argument)
       ntr1 = NSP2NTR(nsp1);
       ntr2 = ntr1;
 
-      nlat1 = ntr2nlat(ntr1);
-      nlon1 = compnlon(nlat1);
+      nlat1 = ntr_to_nlat(ntr1);
+      nlon1 = nlat_to_nlon(nlat1);
       nlat1 = nlon1/2;
 
-      nlat2 = ntr2nlat_linear(ntr2);
-      nlon2 = compnlon(nlat2);
+      nlat2 = ntr_to_nlat_linear(ntr2);
+      nlon2 = nlat_to_nlon(nlat2);
       nlat2 = nlon2/2;
 
       lookup_ni(nsp1, &nrootg1, &ni1);
@@ -461,8 +424,8 @@ void *Specinfo(void *argument)
       nrooti2 = nrooti1;
       nlevel2 = nlevel1;
 
-      nout1  = TRUE;
-      nout2  = TRUE;
+      nout1  = true;
+      nout2  = true;
     }
   else
     cdoAbort("Unsupported parameter: %s", arg);
diff --git a/src/Spectral.c b/src/Spectral.c
index 11b00c2..e31ee2e 100644
--- a/src/Spectral.c
+++ b/src/Spectral.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -26,14 +26,14 @@
       Spectral   spcut           Cut spectral wave number
 */
 
-#include <ctype.h>
 
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
+#include "grid.h"
 #include "pstream.h"
 #include "specspace.h"
-#include "list.h"
+#include "listarray.h"
 
 
 void *Spectral(void *argument)
@@ -51,7 +51,7 @@ void *Spectral(void *argument)
   double *array2 = NULL;
   int nlon, nlat, ntr;
   SPTRANS *sptrans = NULL;
-  LIST *ilist = listNew(INT_LIST);
+  lista_t *ilista = lista_new(INT_LISTA);
 
   cdoInitialize(argument);
 
@@ -107,9 +107,9 @@ void *Spectral(void *argument)
       if ( gridID1 != -1 )
 	{
 	  if ( operatorID == GP2SP )
-	    ntr = nlat2ntr(gridInqYsize(gridID1));
+	    ntr = nlat_to_ntr(gridInqYsize(gridID1));
 	  else
-	    ntr = nlat2ntr_linear(gridInqYsize(gridID1));
+	    ntr = nlat_to_ntr_linear(gridInqYsize(gridID1));
 
 	  if ( gridIDsp != -1 )
 	    if ( ntr != gridInqTrunc(gridIDsp) ) gridIDsp = -1;
@@ -146,9 +146,9 @@ void *Spectral(void *argument)
 	  if ( gridIDgp != -1 )
 	    {
 	      if ( operatorID == SP2GP )
-		ntr = nlat2ntr(gridInqYsize(gridIDgp));
+		ntr = nlat_to_ntr(gridInqYsize(gridIDgp));
 	      else
-		ntr = nlat2ntr_linear(gridInqYsize(gridIDgp));
+		ntr = nlat_to_ntr_linear(gridInqYsize(gridIDgp));
 
 	      if ( gridInqTrunc(gridIDsp) != ntr ) gridIDgp = -1;
 	    }
@@ -157,11 +157,11 @@ void *Spectral(void *argument)
 	    {
 	      char gridname[20];
 	      if ( operatorID == SP2GP )
-		sprintf(gridname, "t%dgrid", gridInqTrunc(gridIDsp));
+		snprintf(gridname, sizeof(gridname), "t%dgrid", gridInqTrunc(gridIDsp));
 	      else
-		sprintf(gridname, "tl%dgrid", gridInqTrunc(gridIDsp));
+		snprintf(gridname, sizeof(gridname), "tl%dgrid", gridInqTrunc(gridIDsp));
 
-	      gridIDgp = gridFromName(gridname);
+	      gridIDgp = grid_from_name(gridname);
 	    }
 
 	  gridID2 = gridIDgp;
@@ -201,8 +201,8 @@ void *Spectral(void *argument)
       if ( gridID1 != -1 )
 	{
 	  maxntr = 1+gridInqTrunc(gridID1);
-	  ncut = args2intlist(operatorArgc(), operatorArgv(), ilist);
-	  wnums = (int *) listArrayPtr(ilist);
+	  ncut = args2int_lista(operatorArgc(), operatorArgv(), ilista);
+	  wnums = (int *) lista_dataptr(ilista);
 	  waves = (int*) Malloc(maxntr*sizeof(int));
 	  for ( i = 0; i < maxntr; i++ ) waves[i] = 1;
 	  for ( i = 0; i < ncut; i++ )
@@ -299,7 +299,7 @@ void *Spectral(void *argument)
   if ( vars )   Free(vars);
   if ( waves )  Free(waves);
 
-  listDelete(ilist);
+  lista_destroy(ilista);
 
   sptrans_delete(sptrans);
 
diff --git a/src/Spectrum.c b/src/Spectrum.c
index 3da32a5..c5a44f2 100644
--- a/src/Spectrum.c
+++ b/src/Spectrum.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -166,42 +166,33 @@ void *Spectrum(void *argument)
 {
   int gridsize;
   int nrecs;
-  int gridID, varID, levelID, recID;
-  int tsID;
+  int gridID, varID, levelID;
   int i, k;
-  int nts;
   int nalloc = 0;
-  int streamID1, streamID2;
-  int vlistID1, vlistID2, taxisID1, taxisID2;
   int nmiss;
-  int nvars, nlevel;
+  int nlevel;
   int *vdate = NULL, *vtime = NULL;
-  int freq, nfreq;
-  int seg_l, seg_n, detrend, which_window;
-  double wssum;
-  double *array1, *array2;
-  double *real, *imag, *window;
-  field_t ***vars = NULL;
-  field_t ***vars2 = NULL;
+  int freq;
+  field_type ***vars = NULL;
 
   cdoInitialize(argument);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisCreate(TAXIS_ABSOLUTE);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisCreate(TAXIS_ABSOLUTE);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  nvars = vlistNvars(vlistID1);
+  int nvars = vlistNvars(vlistID1);
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       if ( tsID >= nalloc )
@@ -209,7 +200,7 @@ void *Spectrum(void *argument)
 	  nalloc += NALLOC_INC;
 	  vdate = (int*) Realloc(vdate, nalloc*sizeof(int));
 	  vtime = (int*) Realloc(vtime, nalloc*sizeof(int));
-	  vars  = (field_t ***) Realloc(vars, nalloc*sizeof(field_t **));
+	  vars  = (field_type ***) Realloc(vars, nalloc*sizeof(field_type **));
 	}
 
       vdate[tsID] = taxisInqVdate(taxisID1);
@@ -217,7 +208,7 @@ void *Spectrum(void *argument)
 
       vars[tsID] = field_malloc(vlistID1, FIELD_NONE);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  gridID   = vlistInqVarGrid(vlistID1, varID);
@@ -232,7 +223,7 @@ void *Spectrum(void *argument)
       tsID++;
     }
 
-  nts = tsID;
+  int nts = tsID;
 
 
   operatorInputArg("detrend type, length of segments, number of segments, window type\n\n"
@@ -247,10 +238,10 @@ void *Spectrum(void *argument)
 
   operatorCheckArgc(4);
 
-  detrend = parameter2int(operatorArgv()[0]);
-  seg_l = parameter2int(operatorArgv()[1]);
-  seg_n = parameter2int(operatorArgv()[2]);
-  which_window = parameter2int(operatorArgv()[3]);
+  int detrend = parameter2int(operatorArgv()[0]);
+  int seg_l = parameter2int(operatorArgv()[1]);
+  int seg_n = parameter2int(operatorArgv()[2]);
+  int which_window = parameter2int(operatorArgv()[3]);
 
   if ( detrend < 0 || detrend > 3 )
     cdoAbort("Illegal value for detrend (=%d)!",detrend);
@@ -262,17 +253,17 @@ void *Spectrum(void *argument)
     cdoAbort("Number of segments must be positiv and not greater than %d!", nts - seg_l + 1);
 
 
-  nfreq = seg_l/2 + 1;
+  int nfreq = seg_l/2 + 1;
 
-  vars2 = (field_t ***) Malloc(nfreq*sizeof(field_t **));
+  field_type ***vars2 = (field_type ***) Malloc(nfreq*sizeof(field_type **));
   for ( freq = 0; freq < nfreq; freq++ )
     vars2[freq] = field_malloc(vlistID1, FIELD_PTR);
 
-  array1  = (double*) Malloc(nts   * sizeof(double));
-  array2  = (double*) Malloc(nfreq * sizeof(double));
-  real    = (double*) Malloc(seg_l * sizeof(double));
-  imag    = (double*) Malloc(seg_l * sizeof(double));
-  window  = (double*) Malloc(seg_l * sizeof(double));
+  double *array1  = (double*) Malloc(nts   * sizeof(double));
+  double *array2  = (double*) Malloc(nfreq * sizeof(double));
+  double *real    = (double*) Malloc(seg_l * sizeof(double));
+  double *imag    = (double*) Malloc(seg_l * sizeof(double));
+  double *window  = (double*) Malloc(seg_l * sizeof(double));
   	   
   switch (which_window)
     {
@@ -301,7 +292,7 @@ void *Spectrum(void *argument)
       break;
     }
   
-  wssum = 0;
+  double wssum = 0;
   for ( k = 0; k < seg_l; k++ )
     wssum += window[k] * window[k];
 
diff --git a/src/Split.c b/src/Split.c
index b807e6d..74e3f8a 100644
--- a/src/Split.c
+++ b/src/Split.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -35,7 +35,7 @@
 
 
 static
-void gen_filename(char *filename, int swap_obase, const char *obase, const char *suffix)
+void gen_filename(char *filename, bool swap_obase, const char *obase, const char *suffix)
 {
   if ( swap_obase ) strcat(filename, obase);
   if ( suffix[0] ) strcat(filename, suffix);
@@ -46,9 +46,7 @@ void *Split(void *argument)
 {
   int nchars = 0;
   int varID;
-  int code, tabnum, param;
-  int nlevs;
-  int recID, levelID, zaxisID, levID;
+  int levelID, levID;
   int varID2, levelID2;
   int vlistID2;
   int *vlistIDs = NULL, *streamIDs = NULL;
@@ -56,13 +54,10 @@ void *Split(void *argument)
   double ftmp[999];
   char filesuffix[32];
   char filename[8192];
-  const char *refname;
   int nsplit = 0;
-  int index;
-  int i;
   int gridsize;
   int nmiss;
-  int swap_obase = FALSE;
+  bool swap_obase = false;
   const char *uuid_attribute = NULL;
 
   cdoInitialize(argument);
@@ -81,10 +76,10 @@ void *Split(void *argument)
 
   int operatorID = cdoOperatorID();
 
-  for( i = 0; i < operatorArgc(); ++i )
+  for( int i = 0; i < operatorArgc(); ++i )
     {
       if ( strcmp("swap", operatorArgv()[i]) == 0 )
-          swap_obase = TRUE;
+          swap_obase = true;
       else if ( strncmp("uuid=", operatorArgv()[i], 5 ) == 0 )
           uuid_attribute = operatorArgv()[i] + 5;
       else cdoAbort("Unknown parameter: >%s<", operatorArgv()[0]); 
@@ -96,13 +91,13 @@ void *Split(void *argument)
 
   int nvars  = vlistNvars(vlistID1);
 
-  if ( swap_obase == 0 )
+  if ( !swap_obase )
     {
       strcpy(filename, cdoStreamName(1)->args);
       nchars = strlen(filename);
     }
 
-  refname = cdoStreamName(0)->argv[cdoStreamName(0)->argc-1];
+  const char *refname = cdoStreamName(0)->argv[cdoStreamName(0)->argc-1];
   filesuffix[0] = 0;
   cdoGenFileSuffix(filesuffix, sizeof(filesuffix), streamInqFiletype(streamID1), vlistID1, refname);
   
@@ -111,7 +106,8 @@ void *Split(void *argument)
       nsplit = 0;
       for ( varID = 0; varID < nvars; varID++ )
 	{
-	  code = vlistInqVarCode(vlistID1, varID);
+	  int code = vlistInqVarCode(vlistID1, varID);
+          int index;
 	  for ( index = 0; index < varID; index++ )
 	    if ( code == vlistInqVarCode(vlistID1, index) ) break;
 
@@ -127,16 +123,15 @@ void *Split(void *argument)
       int codes[nsplit];
       memcpy(codes, itmp, nsplit*sizeof(int));
 
-      for ( index = 0; index < nsplit; index++ )
+      for ( int index = 0; index < nsplit; index++ )
 	{
 	  vlistClearFlag(vlistID1);
 	  for ( varID = 0; varID < nvars; varID++ )
 	    {
-	      code    = vlistInqVarCode(vlistID1, varID);
-	      zaxisID = vlistInqVarZaxis(vlistID1, varID);
-	      nlevs   = zaxisInqSize(zaxisID);
+	      int code    = vlistInqVarCode(vlistID1, varID);
 	      if ( codes[index] == code )
 		{
+                  int nlevs = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
 		  for ( levID = 0; levID < nlevs; levID++ )
 		    {
 		      vlistDefIndex(vlistID1, varID, levID, index);
@@ -176,7 +171,8 @@ void *Split(void *argument)
       nsplit = 0;
       for ( varID = 0; varID < nvars; varID++ )
 	{
-	  param = vlistInqVarParam(vlistID1, varID);
+	  int param = vlistInqVarParam(vlistID1, varID);
+          int index;
 	  for ( index = 0; index < varID; index++ )
 	    if ( param == vlistInqVarParam(vlistID1, index) ) break;
 
@@ -192,16 +188,15 @@ void *Split(void *argument)
       int params[nsplit];
       memcpy(params, itmp, nsplit*sizeof(int));
 
-      for ( index = 0; index < nsplit; index++ )
+      for ( int index = 0; index < nsplit; index++ )
 	{
 	  vlistClearFlag(vlistID1);
 	  for ( varID = 0; varID < nvars; varID++ )
 	    {
-	      param   = vlistInqVarParam(vlistID1, varID);
-	      zaxisID = vlistInqVarZaxis(vlistID1, varID);
-	      nlevs   = zaxisInqSize(zaxisID);
+	      int param   = vlistInqVarParam(vlistID1, varID);
 	      if ( params[index] == param )
 		{
+                  int nlevs   = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
 		  for ( levID = 0; levID < nlevs; levID++ )
 		    {
 		      vlistDefIndex(vlistID1, varID, levID, index);
@@ -230,7 +225,8 @@ void *Split(void *argument)
       nsplit = 0;
       for ( varID = 0; varID < nvars; varID++ )
 	{
-	  tabnum  = tableInqNum(vlistInqVarTable(vlistID1, varID));
+          int tabnum  = tableInqNum(vlistInqVarTable(vlistID1, varID));
+          int index;
 	  for ( index = 0; index < varID; index++ )
 	    if ( tabnum == tableInqNum(vlistInqVarTable(vlistID1, index)) ) break;
 
@@ -246,16 +242,15 @@ void *Split(void *argument)
       int tabnums[nsplit];
       memcpy(tabnums, itmp, nsplit*sizeof(int));
 
-      for ( index = 0; index < nsplit; index++ )
+      for ( int index = 0; index < nsplit; index++ )
 	{
 	  vlistClearFlag(vlistID1);
 	  for ( varID = 0; varID < nvars; varID++ )
 	    {
-	      tabnum  = tableInqNum(vlistInqVarTable(vlistID1, varID));
-	      zaxisID = vlistInqVarZaxis(vlistID1, varID);
-	      nlevs   = zaxisInqSize(zaxisID);
+	      int tabnum  = tableInqNum(vlistInqVarTable(vlistID1, varID));
 	      if ( tabnums[index] == tabnum )
 		{
+                  int nlevs = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
 		  for ( levID = 0; levID < nlevs; levID++ )
 		    {
 		      vlistDefIndex(vlistID1, varID, levID, index);
@@ -283,12 +278,11 @@ void *Split(void *argument)
       vlistIDs  = (int*) Malloc(nsplit*sizeof(int));
       streamIDs = (int*) Malloc(nsplit*sizeof(int));
 
-      for ( index = 0; index < nsplit; index++ )
+      for ( int index = 0; index < nsplit; index++ )
 	{
 	  vlistClearFlag(vlistID1);
 	  varID = index;
-	  zaxisID = vlistInqVarZaxis(vlistID1, varID);
-	  nlevs   = zaxisInqSize(zaxisID);
+	  int nlevs = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
 	  for ( levID = 0; levID < nlevs; levID++ )
 	    {
 	      vlistDefIndex(vlistID1, varID, levID, index);
@@ -314,13 +308,14 @@ void *Split(void *argument)
       double level;
       int nzaxis = vlistNzaxis(vlistID1);
       nsplit = 0;
-      for ( index = 0; index < nzaxis; index++ )
+      for ( int index = 0; index < nzaxis; index++ )
 	{
-	  zaxisID = vlistZaxis(vlistID1, index);
-	  nlevs   = zaxisInqSize(zaxisID);
+          int zaxisID = vlistZaxis(vlistID1, index);
+	  int nlevs = zaxisInqSize(zaxisID);
 	  for ( levID = 0; levID < nlevs; levID++ )
 	    {
-	      level = zaxisInqLevel(zaxisID, levID);
+	      level = cdoZaxisInqLevel(zaxisID, levID);
+              int i;
 	      for ( i = 0; i < nsplit; i++ )
 		if ( IS_EQUAL(level, ftmp[i]) ) break;
 	      if ( i == nsplit )
@@ -333,16 +328,16 @@ void *Split(void *argument)
       double levels[nsplit];
       memcpy(levels, ftmp, nsplit*sizeof(double));
 
-      for ( index = 0; index < nsplit; index++ )
+      for ( int index = 0; index < nsplit; index++ )
 	{
 	  vlistClearFlag(vlistID1);
 	  for ( varID = 0; varID < nvars; varID++ )
 	    {
-	      zaxisID = vlistInqVarZaxis(vlistID1, varID);
-	      nlevs   = zaxisInqSize(zaxisID);
+              int zaxisID = vlistInqVarZaxis(vlistID1, varID);
+	      int nlevs = zaxisInqSize(zaxisID);
 	      for ( levID = 0; levID < nlevs; levID++ )
 		{
-		  level = zaxisInqLevel(zaxisID, levID);
+                  level = cdoZaxisInqLevel(zaxisID, levID);
 		  if ( IS_EQUAL(levels[index], level) )
 		    {
 		      vlistDefIndex(vlistID1, varID, levID, index);
@@ -371,19 +366,18 @@ void *Split(void *argument)
       vlistIDs  = (int*) Malloc(nsplit*sizeof(int));
       streamIDs = (int*) Malloc(nsplit*sizeof(int));
       int gridIDs[nsplit];
-      for ( index = 0; index < nsplit; index++ )
+      for ( int index = 0; index < nsplit; index++ )
 	gridIDs[index] = vlistGrid(vlistID1, index);
 
-      for ( index = 0; index < nsplit; index++ )
+      for ( int index = 0; index < nsplit; index++ )
 	{
 	  vlistClearFlag(vlistID1);
 	  for ( varID = 0; varID < nvars; varID++ )
 	    {
 	      gridID  = vlistInqVarGrid(vlistID1, varID);
-	      zaxisID = vlistInqVarZaxis(vlistID1, varID);
-	      nlevs   = zaxisInqSize(zaxisID);
 	      if ( gridIDs[index] == gridID )
 		{
+                  int nlevs = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
 		  for ( levID = 0; levID < nlevs; levID++ )
 		    {
 		      vlistDefIndex(vlistID1, varID, levID, index);
@@ -405,26 +399,24 @@ void *Split(void *argument)
     }
   else if ( operatorID == SPLITZAXIS )
     {
-      int zaxisID;
-
       nsplit = vlistNzaxis(vlistID1);
 
       vlistIDs  = (int*) Malloc(nsplit*sizeof(int));
       streamIDs = (int*) Malloc(nsplit*sizeof(int));
       int zaxisIDs[nsplit];
-      for ( index = 0; index < nsplit; index++ )
+      for ( int index = 0; index < nsplit; index++ )
 	zaxisIDs[index] = vlistZaxis(vlistID1, index);
 
-      for ( index = 0; index < nsplit; index++ )
+      for ( int index = 0; index < nsplit; index++ )
 	{
 	  vlistClearFlag(vlistID1);
 	  for ( varID = 0; varID < nvars; varID++ )
 	    {
-	      zaxisID = vlistInqVarZaxis(vlistID1, varID);
-	      nlevs   = zaxisInqSize(zaxisID);
+	      int zaxisID = vlistInqVarZaxis(vlistID1, varID);
 	      if ( zaxisIDs[index] == zaxisID )
 		{
-		  for ( levID = 0; levID < nlevs; levID++ )
+                  int nlevs = zaxisInqSize(zaxisID);
+                  for ( levID = 0; levID < nlevs; levID++ )
 		    {
 		      vlistDefIndex(vlistID1, varID, levID, index);
 		      vlistDefFlag(vlistID1, varID, levID, TRUE);
@@ -448,7 +440,7 @@ void *Split(void *argument)
       cdoAbort("not implemented!");
     }
 
-  for ( index = 0; index < nsplit; index++ )
+  for ( int  index = 0; index < nsplit; index++ )
     {
       if ( uuid_attribute ) cdo_def_tracking_id(vlistIDs[index], uuid_attribute);
 
@@ -467,14 +459,14 @@ void *Split(void *argument)
   int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
-      for ( index = 0; index < nsplit; index++ )
+      for ( int index = 0; index < nsplit; index++ )
 	streamDefTimestep(streamIDs[index], tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
-	  index    = vlistInqIndex(vlistID1, varID, levelID);
+	  int index    = vlistInqIndex(vlistID1, varID, levelID);
 	  vlistID2 = vlistIDs[index];
 	  varID2   = vlistFindVar(vlistID2, varID);
 	  levelID2 = vlistFindLevel(vlistID2, varID, levelID);
@@ -498,7 +490,7 @@ void *Split(void *argument)
 
   streamClose(streamID1);
 
-  for ( index = 0; index < nsplit; index++ )
+  for ( int index = 0; index < nsplit; index++ )
     {
       streamClose(streamIDs[index]);
       vlistDestroy(vlistIDs[index]);
diff --git a/src/Splitrec.c b/src/Splitrec.c
index d5755a2..afafa70 100644
--- a/src/Splitrec.c
+++ b/src/Splitrec.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -30,8 +30,7 @@
 void *Splitrec(void *argument)
 {
   int varID;
-  int recID, levelID;
-  int varID2, levelID2;
+  int levelID;
   char filesuffix[32];
   char filename[8192];
   const char *refname;
@@ -69,7 +68,7 @@ void *Splitrec(void *argument)
   int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -92,8 +91,8 @@ void *Splitrec(void *argument)
 
 	  streamDefVlist(streamID2, vlistID2);
 
-	  varID2   = vlistFindVar(vlistID2, varID);
-	  levelID2 = vlistFindLevel(vlistID2, varID, levelID);
+	  int varID2   = vlistFindVar(vlistID2, varID);
+	  int levelID2 = vlistFindLevel(vlistID2, varID, levelID);
 
 	  streamDefTimestep(streamID2, 0);
 	  streamDefRecord(streamID2, varID2, levelID2);
diff --git a/src/Splitsel.c b/src/Splitsel.c
index 9c772c3..1426037 100644
--- a/src/Splitsel.c
+++ b/src/Splitsel.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -30,27 +30,21 @@
 void *Splitsel(void *argument)
 {
   int gridsize;
-  //int vdate = 0, vtime = 0;
   int nrecs = 0;
-  int varID, levelID, recID;
-  int tsID, tsID2;
-  int nsets;
+  int varID, levelID;
+  int tsID;
   int nmiss;
   int gridID;
   int nlevel;
-/*   int ndates = 0, noffset = 0, nskip = 0, nargc; */
-  double ndates, noffset, nskip;
   int i2 = 0;
-  int nargc;
-
   /* from Splittime.c */
   int nchars;
   char filesuffix[32];
   char filename[8192];
   const char *refname;
-  int index = 0;
+  double ndates, noffset, nskip;
   double *array = NULL;
-  field_t **vars = NULL;
+  field_type **vars = NULL;
 
   cdoInitialize(argument);
 
@@ -62,8 +56,7 @@ void *Splitsel(void *argument)
 
   /*  operatorInputArg("nsets <noffset <nskip>>"); */
 
-  nargc = operatorArgc();
-
+  int nargc = operatorArgc();
   if ( nargc < 1 )
     cdoAbort("Too few arguments! Need %d found %d.", 1, nargc);
 
@@ -71,7 +64,7 @@ void *Splitsel(void *argument)
 /*   if ( nargc > 1 ) noffset = parameter2int(operatorArgv()[1]); */
 /*   if ( nargc > 2 ) nskip   = parameter2int(operatorArgv()[2]); */
 /*   printf("%s %s %s\n", operatorArgv()[0],operatorArgv()[1],operatorArgv()[2]); */
-  ndates = noffset = nskip = 0.0;
+  noffset = nskip = 0.0;
   ndates = parameter2double(operatorArgv()[0]);
   if ( nargc > 1 ) noffset = parameter2double(operatorArgv()[1]);
   if ( nargc > 2 ) nskip   = parameter2double(operatorArgv()[2]);
@@ -109,7 +102,7 @@ void *Splitsel(void *argument)
 
   if ( nconst )
     {
-      vars = (field_t **) Malloc(nvars*sizeof(field_t *));
+      vars = (field_type **) Malloc(nvars*sizeof(field_type *));
 
       for ( varID = 0; varID < nvars; varID++ )
 	{
@@ -119,7 +112,7 @@ void *Splitsel(void *argument)
 	      nlevel  = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
 	      gridsize = gridInqSize(gridID);
 		  
-	      vars[varID] = (field_t*) Malloc(nlevel*sizeof(field_t));
+	      vars[varID] = (field_type*) Malloc(nlevel*sizeof(field_type));
 
 	      for ( levelID = 0; levelID < nlevel; levelID++ )
 		{
@@ -131,6 +124,8 @@ void *Splitsel(void *argument)
 	}
     }
 
+  int index = 0;
+  int nsets = 0;
 
   /* offset */
   for ( tsID = 0; tsID < noffset; tsID++ )
@@ -143,7 +138,7 @@ void *Splitsel(void *argument)
 	}
 
       if ( tsID == 0 && nconst )
-	for ( recID = 0; recID < nrecs; recID++ )
+	for ( int recID = 0; recID < nrecs; recID++ )
 	  {
 	    streamInqRecord(streamID1, &varID, &levelID);
 	    if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT )
@@ -154,8 +149,6 @@ void *Splitsel(void *argument)
           }
     }
 
-  index = 0;
-  nsets = 0;
   while ( TRUE )
     {
       sprintf(filename+nchars, "%06d", index);
@@ -168,19 +161,13 @@ void *Splitsel(void *argument)
 
       streamDefVlist(streamID2, vlistID2);
 
-      tsID2 = 0;
+      int tsID2 = 0;
 
       for ( ; nsets < (int)(ndates*(index+1)); nsets++ ) 
 	{
 	  nrecs = streamInqTimestep(streamID1, tsID);
 	  if ( nrecs == 0 ) break;
 
-	  /*
-	  vdate = taxisInqVdate(taxisID1);
-	  vtime = taxisInqVtime(taxisID1);
-	  printf("vdate: %d vtime: %d\n", vdate, vtime);
-	   */
-
 	  taxisCopyTimestep(taxisID2, taxisID1);
 	  streamDefTimestep(streamID2, tsID2);
 
@@ -201,7 +188,7 @@ void *Splitsel(void *argument)
 		}
 	    }
 
-	  for ( recID = 0; recID < nrecs; recID++ )
+	  for ( int recID = 0; recID < nrecs; recID++ )
 	    {
 	      
 	      streamInqRecord(streamID1, &varID, &levelID);
diff --git a/src/Splittime.c b/src/Splittime.c
index 5d7cb7b..39a5eb6 100644
--- a/src/Splittime.c
+++ b/src/Splittime.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -58,19 +58,17 @@ void *Splittime(void *argument)
   int streamID2;
   int varID;
   int nrecs;
-  int tsID, recID, levelID;
+  int levelID;
   int  streamIDs[MAX_STREAMS], tsIDs[MAX_STREAMS];
-  char filesuffix[32];
-  char filename[8192];
   int index = 0;
-  int i;
-  int vdate, vtime;
   int gridsize;
   int nmiss;
   int gridID;
   int nlevel;
+  char filesuffix[32];
+  char filename[8192];
   double *array = NULL;
-  field_t **vars = NULL;
+  field_type **vars = NULL;
   const char *format = NULL;
 
   cdoInitialize(argument);
@@ -99,8 +97,8 @@ void *Splittime(void *argument)
   const char *seas_name[4];
   get_season_name(seas_name);
 
-  for ( i = 0; i < MAX_STREAMS; i++ ) streamIDs[i] = -1;
-  for ( i = 0; i < MAX_STREAMS; i++ ) tsIDs[i] = 0;
+  for ( int i = 0; i < MAX_STREAMS; i++ ) streamIDs[i] = -1;
+  for ( int i = 0; i < MAX_STREAMS; i++ ) tsIDs[i] = 0;
 
   int streamID1 = streamOpenRead(cdoStreamName(0));
 
@@ -132,7 +130,7 @@ void *Splittime(void *argument)
 
   if ( nconst )
     {
-      vars = (field_t **) Malloc(nvars*sizeof(field_t *));
+      vars = (field_type **) Malloc(nvars*sizeof(field_type *));
 
       for ( varID = 0; varID < nvars; varID++ )
 	{
@@ -142,7 +140,7 @@ void *Splittime(void *argument)
 	      nlevel  = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
 	      gridsize = gridInqSize(gridID);
 		  
-	      vars[varID] = (field_t*) Malloc(nlevel*sizeof(field_t));
+	      vars[varID] = (field_type*) Malloc(nlevel*sizeof(field_type));
 
 	      for ( levelID = 0; levelID < nlevel; levelID++ )
 		{
@@ -154,11 +152,11 @@ void *Splittime(void *argument)
 	}
     }
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
-      vdate = taxisInqVdate(taxisID1);
-      vtime = taxisInqVtime(taxisID1);
+      int vdate = taxisInqVdate(taxisID1);
+      int vtime = taxisInqVtime(taxisID1);
 
       if ( operfunc == func_date )
 	{
@@ -235,7 +233,7 @@ void *Splittime(void *argument)
 	    }
 	}
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamDefRecord(streamID2,  varID,  levelID);
diff --git a/src/Splityear.c b/src/Splityear.c
index 5810466..73ca61c 100644
--- a/src/Splityear.c
+++ b/src/Splityear.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -37,10 +37,7 @@ void *Splityear(void *argument)
   int streamID2 = -1;
   int varID;
   int nrecs;
-  int tsID, tsID2, recID, levelID;
-  char filesuffix[32];
-  char filename[8192];
-  int vdate;
+  int levelID;
   int day;
   int year1, year2;
   int mon1, mon2;
@@ -50,8 +47,10 @@ void *Splityear(void *argument)
   int nmiss;
   int gridID;
   int nlevel;
+  char filesuffix[32];
+  char filename[8192];
   double *array = NULL;
-  field_t **vars = NULL;
+  field_type **vars = NULL;
 
   cdoInitialize(argument);
 
@@ -97,7 +96,7 @@ void *Splityear(void *argument)
 
   if ( nconst )
     {
-      vars = (field_t **) Malloc(nvars*sizeof(field_t *));
+      vars = (field_type **) Malloc(nvars*sizeof(field_type *));
 
       for ( varID = 0; varID < nvars; varID++ )
 	{
@@ -107,7 +106,7 @@ void *Splityear(void *argument)
 	      nlevel  = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
 	      gridsize = gridInqSize(gridID);
 		  
-	      vars[varID] = (field_t*) Malloc(nlevel*sizeof(field_t));
+	      vars[varID] = (field_type*) Malloc(nlevel*sizeof(field_type));
 
 	      for ( levelID = 0; levelID < nlevel; levelID++ )
 		{
@@ -123,11 +122,11 @@ void *Splityear(void *argument)
   int index2;
   year1 = -1;
   mon1  = -1;
-  tsID  = 0;
-  tsID2 = 0;
+  int tsID  = 0;
+  int tsID2 = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
-      vdate = taxisInqVdate(taxisID1);
+      int vdate = taxisInqVdate(taxisID1);
       cdiDecodeDate(vdate, &year2, &mon2, &day);
 
       if ( operatorID == SPLITYEAR )
@@ -211,7 +210,7 @@ void *Splityear(void *argument)
 	    }
 	}
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamDefRecord(streamID2,  varID,  levelID);
diff --git a/src/Subtrend.c b/src/Subtrend.c
index 6ac1205..448f937 100644
--- a/src/Subtrend.c
+++ b/src/Subtrend.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -30,55 +30,47 @@
 
 void *Subtrend(void *argument)
 {
-  int gridsize;
-  int nrecs;
-  int gridID, varID, levelID, recID;
-  int tsID;
-  int i;
-  int streamID1, streamID2, streamID3, streamID4;
-  int vlistID1, vlistID2, vlistID3, vlistID4, taxisID1, taxisID4;
+  int gridID, varID, levelID;
   int nmiss;
-  double missval, missval1, missval2;
-  field_t **vars2, **vars3;
-  field_t field1, field4;
 
   cdoInitialize(argument);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
-  streamID2 = streamOpenRead(cdoStreamName(1));
-  streamID3 = streamOpenRead(cdoStreamName(2));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID2 = streamOpenRead(cdoStreamName(1));
+  int streamID3 = streamOpenRead(cdoStreamName(2));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = streamInqVlist(streamID2);
-  vlistID3 = streamInqVlist(streamID3);
-  vlistID4 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = streamInqVlist(streamID2);
+  int vlistID3 = streamInqVlist(streamID3);
+  int vlistID4 = vlistDuplicate(vlistID1);
 
   vlistCompare(vlistID1, vlistID2, CMP_DIM);
   vlistCompare(vlistID1, vlistID3, CMP_DIM);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID4 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID4 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID4, taxisID4);
 
-  streamID4 = streamOpenWrite(cdoStreamName(3), cdoFiletype());
+  int streamID4 = streamOpenWrite(cdoStreamName(3), cdoFiletype());
 
   streamDefVlist(streamID4, vlistID4);
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
 
+  field_type field1, field4;
   field_init(&field1);
   field_init(&field4);
   field1.ptr = (double*) Malloc(gridsize*sizeof(double));
   field4.ptr = (double*) Malloc(gridsize*sizeof(double));
 
-  vars2 = field_malloc(vlistID1, FIELD_PTR);
-  vars3 = field_malloc(vlistID1, FIELD_PTR);
+  field_type **vars2 = field_malloc(vlistID1, FIELD_PTR);
+  field_type **vars3 = field_malloc(vlistID1, FIELD_PTR);
 
 
-  tsID = 0;
-  nrecs = streamInqTimestep(streamID2, tsID);
+  int tsID = 0;
+  int nrecs = streamInqTimestep(streamID2, tsID);
 
-  for ( recID = 0; recID < nrecs; recID++ )
+  for ( int recID = 0; recID < nrecs; recID++ )
     {
       streamInqRecord(streamID2, &varID, &levelID);
       streamReadRecord(streamID2, vars2[varID][levelID].ptr, &nmiss);
@@ -87,7 +79,7 @@ void *Subtrend(void *argument)
   tsID = 0;
   nrecs = streamInqTimestep(streamID3, tsID);
 
-  for ( recID = 0; recID < nrecs; recID++ )
+  for ( int recID = 0; recID < nrecs; recID++ )
     {
       streamInqRecord(streamID3, &varID, &levelID);
       streamReadRecord(streamID3, vars3[varID][levelID].ptr, &nmiss);
@@ -101,22 +93,22 @@ void *Subtrend(void *argument)
 
       streamDefTimestep(streamID4, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, field1.ptr, &nmiss);
 
-	  missval  = vlistInqVarMissval(vlistID1, varID);
 	  gridID   = vlistInqVarGrid(vlistID1, varID);
 	  gridsize = gridInqSize(gridID);
 
-	  missval1 = missval;
-	  missval2 = missval;
-	  for ( i = 0; i < gridsize; i++ )
+	  double missval = vlistInqVarMissval(vlistID1, varID);
+	  double missval1 = missval;
+	  double missval2 = missval;
+	  for ( int i = 0; i < gridsize; i++ )
 	    field4.ptr[i] = SUBMN(field1.ptr[i], ADDMN(vars2[varID][levelID].ptr[i], MULMN(vars3[varID][levelID].ptr[i], tsID)));
     
 	  nmiss = 0;
-	  for ( i = 0; i < gridsize; i++ )
+	  for ( int i = 0; i < gridsize; i++ )
 	    if ( DBL_IS_EQUAL(field4.ptr[i], missval) ) nmiss++;
 
 	  streamDefRecord(streamID4, varID, levelID);
diff --git a/src/Tee.c b/src/Tee.c
index 9543175..6fcdf2a 100644
--- a/src/Tee.c
+++ b/src/Tee.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
diff --git a/src/Templates.c b/src/Templates.c
index f67f32c..a9db63c 100644
--- a/src/Templates.c
+++ b/src/Templates.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -55,7 +55,6 @@ void *Template1(void *argument)
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
-
       streamDefTimestep(streamID2, tsID);
 	       
       for ( int recID = 0; recID < nrecs; recID++ )
@@ -118,7 +117,6 @@ void *Template2(void *argument)
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
-
       streamDefTimestep(streamID2, tsID);
 	       
       for ( int recID = 0; recID < nrecs; recID++ )
diff --git a/src/Test.c b/src/Test.c
index e0c24bc..bd3dddd 100644
--- a/src/Test.c
+++ b/src/Test.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -67,54 +67,44 @@ void *Test2(void *argument)
 
 void *Testdata(void *argument)
 {
-  int streamID1, streamID2 = CDI_UNDEFID;
   int nrecs;
-  int tsID1, tsID2, recID, varID, levelID;
-  int gridsize, i;
-  int vlistID1, vlistID2 = -1;
+  int varID, levelID;
   int nmiss;
-  int taxisID1, taxisID2 = CDI_UNDEFID;
-  double *array = NULL;
-  float *fval;
-  int *ival;
-  unsigned char *cval;
-  unsigned char *cval2;
-  FILE *fp;
 
   cdoInitialize(argument);
 
-  tsID2 = 0;
+  int tsID2 = 0;
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  taxisID1 = vlistInqTaxis(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
-  vlistID2 = vlistDuplicate(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
   streamDefVlist(streamID2, vlistID2);
 
-  gridsize = vlistGridsizeMax(vlistID1);
-  array = (double*) Malloc(gridsize*sizeof(double));
-  fval = (float*) Malloc(gridsize*sizeof(float));
-  ival = (int*) Malloc(gridsize*sizeof(int));
-  cval = (unsigned char*) Malloc(gridsize*sizeof(unsigned char)*4);
-  cval2 = (unsigned char*) Malloc(gridsize*sizeof(unsigned char)*4);
+  int gridsize = vlistGridsizeMax(vlistID1);
+  double *array = (double*) Malloc(gridsize*sizeof(double));
+  float *fval = (float*) Malloc(gridsize*sizeof(float));
+  int *ival = (int*) Malloc(gridsize*sizeof(int));
+  unsigned char *cval = (unsigned char*) Malloc(gridsize*sizeof(unsigned char)*4);
+  unsigned char *cval2 = (unsigned char*) Malloc(gridsize*sizeof(unsigned char)*4);
 
-  fp = fopen("testdata", "w");
+  FILE *fp = fopen("testdata", "w");
 
-  tsID1 = 0;
+  int tsID1 = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID1)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
 
       streamDefTimestep(streamID2, tsID2);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamDefRecord(streamID2,  varID,  levelID);
@@ -122,7 +112,7 @@ void *Testdata(void *argument)
 	  streamReadRecord(streamID1, array, &nmiss);
 
 	  gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
-	  for ( i = 0; i < gridsize; ++i )
+	  for ( int i = 0; i < gridsize; ++i )
 	    {
 	      fval[i] = (float) array[i];
 
diff --git a/src/Tests.c b/src/Tests.c
index 9a87bc9..74ad842 100644
--- a/src/Tests.c
+++ b/src/Tests.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -24,29 +24,21 @@
 
 void *Tests(void *argument)
 {
-  int NORMAL, STUDENTT, CHISQUARE, BETA, FISHER;
-  int operatorID;
-  int streamID1, streamID2 = CDI_UNDEFID;
   int nrecs;
-  int i;
-  int tsID, recID, varID, levelID;
-  int vlistID1, vlistID2;
-  int gridsize;
+  int varID, levelID;
   int nmiss;
-  int taxisID1, taxisID2;
   double degree_of_freedom = 0, p = 0, q = 0, n = 0, d = 0;
   double missval;
-  double *array1 = NULL, *array2 = NULL;
 
   cdoInitialize(argument);
 
-  NORMAL    = cdoOperatorAdd("normal",    0, 0, NULL);
-  STUDENTT  = cdoOperatorAdd("studentt",  0, 0, "degree of freedom");
-  CHISQUARE = cdoOperatorAdd("chisquare", 0, 0, "degree of freedom");
-  BETA      = cdoOperatorAdd("beta",      0, 0, "p and q");
-  FISHER    = cdoOperatorAdd("fisher",    0, 0, "degree of freedom of nominator and of denominator");
+  int NORMAL    = cdoOperatorAdd("normal",    0, 0, NULL);
+  int STUDENTT  = cdoOperatorAdd("studentt",  0, 0, "degree of freedom");
+  int CHISQUARE = cdoOperatorAdd("chisquare", 0, 0, "degree of freedom");
+  int BETA      = cdoOperatorAdd("beta",      0, 0, "p and q");
+  int FISHER    = cdoOperatorAdd("fisher",    0, 0, "degree of freedom of nominator and of denominator");
 
-  operatorID = cdoOperatorID();
+  int operatorID = cdoOperatorID();
 
   if ( operatorID == STUDENTT || operatorID == CHISQUARE )
     {
@@ -84,31 +76,31 @@ void *Tests(void *argument)
 	cdoAbort("both degrees must be positive!");
     }
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  gridsize = vlistGridsizeMax(vlistID1);
-  array1 = (double*) Malloc(gridsize*sizeof(double));
-  array2 = (double*) Malloc(gridsize*sizeof(double));
+  int gridsize = vlistGridsizeMax(vlistID1);
+  double *array1 = (double*) Malloc(gridsize*sizeof(double));
+  double *array2 = (double*) Malloc(gridsize*sizeof(double));
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
 
       streamDefTimestep(streamID2, tsID);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);	  
 	  streamReadRecord(streamID1, array1, &nmiss);
@@ -118,25 +110,25 @@ void *Tests(void *argument)
 
 	  if ( operatorID == NORMAL )
 	    {
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( int i = 0; i < gridsize; i++ )
 		array2[i] = DBL_IS_EQUAL(array1[i], missval) ? missval :
 		  normal(array1[i], processInqPrompt());
 	    }
 	  else if ( operatorID == STUDENTT )
 	    {
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( int i = 0; i < gridsize; i++ )
 		array2[i] = DBL_IS_EQUAL(array1[i], missval) ? missval :
 		  student_t(degree_of_freedom, array1[i], processInqPrompt());
 	    }
 	  else if ( operatorID == CHISQUARE )
 	    {
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( int i = 0; i < gridsize; i++ )
 		array2[i] = DBL_IS_EQUAL(array1[i], missval) ? missval :
 		  chi_square(degree_of_freedom, array1[i], processInqPrompt());
 	    }
 	  else if ( operatorID == BETA )
 	    {
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( int i = 0; i < gridsize; i++ )
 		{
 		  if ( array1[i] < 0 || array1[i] > 1 )
 		    cdoAbort("Value out of range (0-1)!");
@@ -147,7 +139,7 @@ void *Tests(void *argument)
 	    }
 	  else if ( operatorID == FISHER )
 	    {
-	      for ( i = 0; i < gridsize; i++ )
+	      for ( int i = 0; i < gridsize; i++ )
 		array2[i] = DBL_IS_EQUAL(array1[i], missval) ? missval :
 		  fisher(n, d, array1[i], processInqPrompt());
 	    }
diff --git a/src/Timcount.c b/src/Timcount.c
index 14ac303..e7396f4 100644
--- a/src/Timcount.c
+++ b/src/Timcount.c
@@ -34,26 +34,12 @@
 
 void *Timcount(void *argument)
 {
-  int operatorID;
-  int cmplen;
   char indate1[DATE_LEN+1], indate2[DATE_LEN+1];
-  int gridsize;
-  int vdate = 0, vtime = 0;
   int vdate0 = 0, vtime0 = 0;
-  int nrecs, nrecords;
-  int varID, levelID, recID;
-  int tsID;
-  int otsID;
-  long nsets;
-  int i;
-  int streamID1, streamID2;
-  int vlistID1, vlistID2, taxisID1, taxisID2;
-  int nvars;
+  int nrecs;
+  int varID, levelID;
   int nmiss;
   int nwpv; // number of words per value; real:1  complex:2
-  int *recVarID, *recLevelID;
-  field_t **vars1 = NULL;
-  field_t field;
 
   cdoInitialize(argument);
 
@@ -63,57 +49,58 @@ void *Timcount(void *argument)
   cdoOperatorAdd("daycount",  0,  6, NULL);
   cdoOperatorAdd("hourcount", 0,  4, NULL);
 
-  operatorID = cdoOperatorID();
+  int operatorID = cdoOperatorID();
 
-  cmplen = DATE_LEN - cdoOperatorF2(operatorID);
+  int cmplen = DATE_LEN - cdoOperatorF2(operatorID);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  nvars    = vlistNvars(vlistID1);
+  int nvars = vlistNvars(vlistID1);
   for ( varID = 0; varID < nvars; varID++ )
       vlistDefVarUnits(vlistID2, varID, "No.");
 
   if ( cdoOperatorF2(operatorID) == 16 ) vlistDefNtsteps(vlistID2, 1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  nrecords = vlistNrecs(vlistID1);
-  recVarID   = (int*) Malloc(nrecords*sizeof(int));
-  recLevelID = (int*) Malloc(nrecords*sizeof(int));
+  int nrecords = vlistNrecs(vlistID1);
+  int *recVarID   = (int*) Malloc(nrecords*sizeof(int));
+  int *recLevelID = (int*) Malloc(nrecords*sizeof(int));
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
   if ( vlistNumber(vlistID1) != CDI_REAL ) gridsize *= 2;
 
+  field_type field;
   field_init(&field);
   field.ptr = (double*) Malloc(gridsize*sizeof(double));
 
-  vars1 = field_malloc(vlistID1, FIELD_PTR);
+  field_type **vars1 = field_malloc(vlistID1, FIELD_PTR);
 
-  tsID    = 0;
-  otsID   = 0;
+  int tsID    = 0;
+  int otsID   = 0;
   while ( TRUE )
     {
-      nsets = 0;
+      int nsets = 0;
       while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
 	{
-	  vdate = taxisInqVdate(taxisID1);
-	  vtime = taxisInqVtime(taxisID1);
+	  int vdate = taxisInqVdate(taxisID1);
+	  int vtime = taxisInqVtime(taxisID1);
 
 	  if ( nsets == 0 ) SET_DATE(indate2, vdate, vtime);
 	  SET_DATE(indate1, vdate, vtime);
 
 	  if ( DATE_IS_NEQ(indate1, indate2, cmplen) ) break;
 
-	  for ( recID = 0; recID < nrecs; recID++ )
+	  for ( int recID = 0; recID < nrecs; recID++ )
 	    {
 	      streamInqRecord(streamID1, &varID, &levelID);
 
@@ -128,7 +115,7 @@ void *Timcount(void *argument)
 
 	      if ( nsets == 0 )
 		{
-		  for ( i = 0; i < nwpv*gridsize; i++ )
+		  for ( int i = 0; i < nwpv*gridsize; i++ )
 		    vars1[varID][levelID].ptr[i] = vars1[varID][levelID].missval;
 		  vars1[varID][levelID].nmiss = gridsize;
 		}
@@ -153,7 +140,7 @@ void *Timcount(void *argument)
       taxisDefVtime(taxisID2, vtime0);
       streamDefTimestep(streamID2, otsID);
 
-      for ( recID = 0; recID < nrecords; recID++ )
+      for ( int recID = 0; recID < nrecords; recID++ )
 	{
 	  varID   = recVarID[recID];
 	  levelID = recLevelID[recID];
diff --git a/src/Timcumsum.c b/src/Timcumsum.c
new file mode 100644
index 0000000..d2d8ac9
--- /dev/null
+++ b/src/Timcumsum.c
@@ -0,0 +1,116 @@
+/*
+  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.
+*/
+
+/*
+   This module contains the following operators:
+
+      Timcumsum    timcumsum         Cumulative sum over time
+*/
+
+
+#include <cdi.h>
+#include "cdo.h"
+#include "cdo_int.h"
+#include "pstream.h"
+
+
+void *Timcumsum(void *argument)
+{
+  int nrecs;
+  int varID, levelID;
+  int nmiss;
+
+  cdoInitialize(argument);
+
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
+
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
+  vlistDefTaxis(vlistID2, taxisID2);
+
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+
+  streamDefVlist(streamID2, vlistID2);
+
+  int gridsize = vlistGridsizeMax(vlistID1);
+  if ( vlistNumber(vlistID1) != CDI_REAL ) gridsize *= 2;
+
+  field_type field;
+  field_init(&field);
+  field.ptr = (double*) Malloc(gridsize*sizeof(double));
+
+  field_type **vars1 = field_malloc(vlistID1, FIELD_PTR);
+
+  int tsID  = 0;
+  while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
+    {
+      taxisCopyTimestep(taxisID2, taxisID1);
+
+      streamDefTimestep(streamID2, tsID);
+    
+      for ( int recID = 0; recID < nrecs; recID++ )
+        {
+          streamInqRecord(streamID1, &varID, &levelID);
+
+          field_type *pvar1 = &vars1[varID][levelID];
+              
+          gridsize = gridInqSize(pvar1->grid);
+
+          if ( tsID == 0 )
+            {
+              streamReadRecord(streamID1, pvar1->ptr, &nmiss);
+              // pvar1->nmiss = (size_t)nmiss;
+              if ( nmiss )
+                for ( int i = 0; i < gridsize; ++i )
+                  if ( DBL_IS_EQUAL(pvar1->ptr[i], pvar1->missval) ) pvar1->ptr[i] = 0;
+            }
+          else
+            {
+              streamReadRecord(streamID1, field.ptr, &nmiss);
+              // field.nmiss   = (size_t)nmiss;
+              field.size    = gridsize;
+              field.grid    = pvar1->grid;
+              field.missval = pvar1->missval;
+
+              if ( nmiss )
+                for ( int i = 0; i < gridsize; ++i )
+                  if ( DBL_IS_EQUAL(field.ptr[i], pvar1->missval) ) field.ptr[i] = 0;
+
+              farfun(pvar1, field, func_sum);
+            }
+          
+	  streamDefRecord(streamID2, varID, levelID);
+	  streamWriteRecord(streamID2, pvar1->ptr, (int)pvar1->nmiss);
+        }
+
+      tsID++;
+    }
+
+  field_free(vars1, vlistID1);
+
+  streamClose(streamID2);
+  streamClose(streamID1);
+
+  if ( field.ptr ) Free(field.ptr);
+
+  cdoFinish();
+
+  return 0;
+}
diff --git a/src/Timpctl.c b/src/Timpctl.c
index fdfb0df..d5b5339 100644
--- a/src/Timpctl.c
+++ b/src/Timpctl.c
@@ -38,19 +38,10 @@ void timpctl(int operatorID)
 {
   int timestat_date = TIMESTAT_MEAN;
   char indate1[DATE_LEN+1], indate2[DATE_LEN+1];
-  int vdate1 = 0, vtime1 = 0;
-  int vdate2 = 0, vtime2 = 0;
-  int vdate3 = 0, vtime3 = 0;
   int nrecs;
-  int gridID, varID, levelID, recID;
-  int tsID;
-  int otsID;
-  long nsets;
+  int gridID, varID, levelID;
   int nmiss;
   int nlevels;
-  field_t **vars1 = NULL;
-  field_t field;
-  HISTOGRAM_SET *hset = NULL;
   
   operatorInputArg("percentile number");
   double pn = parameter2double(operatorArgv()[0]);
@@ -96,11 +87,12 @@ void timpctl(int operatorID)
 
   int gridsize = vlistGridsizeMax(vlistID1);
 
+  field_type field;
   field_init(&field);
   field.ptr = (double*) Malloc(gridsize * sizeof(double));
 
-  vars1 = field_malloc(vlistID1, FIELD_PTR);
-  hset = hsetCreate(nvars);
+  field_type **vars1 = field_malloc(vlistID1, FIELD_PTR);
+  HISTOGRAM_SET *hset = hsetCreate(nvars);
   
   for ( varID = 0; varID < nvars; varID++ )
     {
@@ -110,29 +102,29 @@ void timpctl(int operatorID)
       hsetCreateVarLevels(hset, varID, nlevels, gridID);
     }
 
-  tsID    = 0;
-  otsID   = 0;
+  int tsID    = 0;
+  int otsID   = 0;
   while ( TRUE )
     {      
       nrecs = streamInqTimestep(streamID2, otsID);
       if ( nrecs != streamInqTimestep(streamID3, otsID) )
         cdoAbort("Number of records at time step %d of %s and %s differ!", otsID+1, cdoStreamName(1)->args, cdoStreamName(2)->args);
 
-      vdate2 = taxisInqVdate(taxisID2);
-      vtime2 = taxisInqVtime(taxisID2);
-      vdate3 = taxisInqVdate(taxisID3);
-      vtime3 = taxisInqVtime(taxisID3);
+      int vdate2 = taxisInqVdate(taxisID2);
+      int vtime2 = taxisInqVtime(taxisID2);
+      int vdate3 = taxisInqVdate(taxisID3);
+      int vtime3 = taxisInqVtime(taxisID3);
       if ( vdate2 != vdate3 || vtime2 != vtime3 )
         cdoAbort("Verification dates at time step %d of %s and %s differ!", otsID+1, cdoStreamName(1)->args, cdoStreamName(2)->args);
       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
         {
           streamInqRecord(streamID2, &varID, &levelID);
 	  streamReadRecord(streamID2, vars1[varID][levelID].ptr, &nmiss);
           vars1[varID][levelID].nmiss = nmiss;
         }
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
         {
           streamInqRecord(streamID3, &varID, &levelID);
 	  streamReadRecord(streamID3, field.ptr, &nmiss);
@@ -143,19 +135,19 @@ void timpctl(int operatorID)
 	  hsetDefVarLevelBounds(hset, varID, levelID, &vars1[varID][levelID], &field);
         }
           
-      nsets = 0;
+      int nsets = 0;
       while ( nrecs && (nrecs = streamInqTimestep(streamID1, tsID)) )
 	{
 	  dtlist_taxisInqTimestep(dtlist, taxisID1, nsets);
-	  vdate1 = dtlist_get_vdate(dtlist, nsets);
-	  vtime1 = dtlist_get_vtime(dtlist, nsets);
+	  int vdate1 = dtlist_get_vdate(dtlist, nsets);
+	  int vtime1 = dtlist_get_vtime(dtlist, nsets);
 
 	  if ( nsets == 0 ) SET_DATE(indate2, vdate1, vtime1);
 	  SET_DATE(indate1, vdate1, vtime1);
 
 	  if ( DATE_IS_NEQ(indate1, indate2, cmplen) ) break;
 
-	  for ( recID = 0; recID < nrecs; recID++ )
+	  for ( int recID = 0; recID < nrecs; recID++ )
 	    {
 	      streamInqRecord(streamID1, &varID, &levelID);
 	      if ( tsID == 0 )
@@ -187,7 +179,7 @@ void timpctl(int operatorID)
       dtlist_stat_taxisDefTimestep(dtlist, taxisID4, nsets);
       streamDefTimestep(streamID4, otsID);
 
-      for ( recID = 0; recID < nrecords; recID++ )
+      for ( int recID = 0; recID < nrecords; recID++ )
 	{
 	  varID   = recVarID[recID];
 	  levelID = recLevelID[recID];
diff --git a/src/Timselpctl.c b/src/Timselpctl.c
index 2ad4de3..7c8499e 100644
--- a/src/Timselpctl.c
+++ b/src/Timselpctl.c
@@ -32,18 +32,11 @@
 void *Timselpctl(void *argument)
 {
   int timestat_date = TIMESTAT_MEAN;
-  int vdate2 = 0, vtime2 = 0;
-  int vdate3 = 0, vtime3 = 0;
   int nrecs = 0;
-  int gridID, varID, levelID, recID;
+  int gridID, varID, levelID;
   int tsID;
-  int nsets = 0;
-  int i;
   int nmiss;
   int nlevels;
-  field_t **vars1 = NULL;
-  field_t field;
-  HISTOGRAM_SET *hset = NULL;
 
   cdoInitialize(argument);
 
@@ -99,11 +92,12 @@ void *Timselpctl(void *argument)
 
   int gridsize = vlistGridsizeMax(vlistID1);
 
+  field_type field;
   field_init(&field);
   field.ptr = (double*) Malloc(gridsize * sizeof(double));
 
-  vars1 = field_malloc(vlistID1, FIELD_PTR);
-  hset = hsetCreate(nvars);
+  field_type **vars1 = field_malloc(vlistID1, FIELD_PTR);
+  HISTOGRAM_SET *hset = hsetCreate(nvars);
 
   for ( varID = 0; varID < nvars; varID++ )
     {
@@ -118,7 +112,7 @@ void *Timselpctl(void *argument)
       nrecs = streamInqTimestep(streamID1, tsID);
       if ( nrecs == 0 ) break;
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -143,21 +137,21 @@ void *Timselpctl(void *argument)
       if ( nrecs != streamInqTimestep(streamID3, otsID) )
         cdoAbort("Number of records at time step %d of %s and %s differ!", otsID+1, cdoStreamName(1)->args, cdoStreamName(2)->args);
 
-      vdate2 = taxisInqVdate(taxisID2);
-      vtime2 = taxisInqVtime(taxisID2);
-      vdate3 = taxisInqVdate(taxisID3);
-      vtime3 = taxisInqVtime(taxisID3);
+      int vdate2 = taxisInqVdate(taxisID2);
+      int vtime2 = taxisInqVtime(taxisID2);
+      int vdate3 = taxisInqVdate(taxisID3);
+      int vtime3 = taxisInqVtime(taxisID3);
       if ( vdate2 != vdate3 || vtime2 != vtime3 )
         cdoAbort("Verification dates at time step %d of %s and %s differ!", otsID+1, cdoStreamName(1)->args, cdoStreamName(2)->args);
       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
         {
           streamInqRecord(streamID2, &varID, &levelID);
           streamReadRecord(streamID2, vars1[varID][levelID].ptr, &nmiss);
           vars1[varID][levelID].nmiss = nmiss;
         }
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
         {
           streamInqRecord(streamID3, &varID, &levelID);
           streamReadRecord(streamID3, field.ptr, &nmiss);
@@ -168,7 +162,7 @@ void *Timselpctl(void *argument)
           hsetDefVarLevelBounds(hset, varID, levelID, &vars1[varID][levelID], &field);
         }
 
-      nsets = 0;
+      int nsets = 0;
       if ( nrecs )
 	for ( nsets = 0; nsets < ndates; nsets++ )
 	  {
@@ -177,7 +171,7 @@ void *Timselpctl(void *argument)
 
 	    dtlist_taxisInqTimestep(dtlist, taxisID1, nsets);
 
-	    for ( recID = 0; recID < nrecs; recID++ )
+	    for ( int recID = 0; recID < nrecs; recID++ )
 	      {
 		streamInqRecord(streamID1, &varID, &levelID);
 
@@ -210,7 +204,7 @@ void *Timselpctl(void *argument)
       dtlist_stat_taxisDefTimestep(dtlist, taxisID4, nsets);
       streamDefTimestep(streamID4, otsID);
 
-      for ( recID = 0; recID < nrecords; recID++ )
+      for ( int recID = 0; recID < nrecords; recID++ )
 	{
 	  varID   = recVarID[recID];
 	  levelID = recLevelID[recID];
@@ -224,7 +218,7 @@ void *Timselpctl(void *argument)
       if ( nrecs == 0 ) break;
       otsID++;
 
-      for ( i = 0; i < nskip; i++ )
+      for ( int i = 0; i < nskip; i++ )
 	{
 	  nrecs = streamInqTimestep(streamID1, tsID);
 	  if ( nrecs == 0 ) break;
diff --git a/src/Timselstat.c b/src/Timselstat.c
index a003dc2..7e7b967 100644
--- a/src/Timselstat.c
+++ b/src/Timselstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -40,10 +40,9 @@ void *Timselstat(void *argument)
 {
   int timestat_date = TIMESTAT_MEAN;
   int nrecs = 0;
-  int varID, levelID, recID;
+  int varID, levelID;
   int tsID;
   int nsets;
-  int i;
   int nmiss;
   int nlevel;
 
@@ -102,13 +101,13 @@ void *Timselstat(void *argument)
 
   int gridsize = vlistGridsizeMax(vlistID1);
 
-  field_t field;
+  field_type field;
   field_init(&field);
   field.ptr = (double*) Malloc(gridsize*sizeof(double));
 
-  field_t **samp1 = field_malloc(vlistID1, FIELD_NONE);
-  field_t **vars1 = field_malloc(vlistID1, FIELD_PTR);
-  field_t **vars2 = NULL;
+  field_type **samp1 = field_malloc(vlistID1, FIELD_NONE);
+  field_type **vars1 = field_malloc(vlistID1, FIELD_PTR);
+  field_type **vars2 = NULL;
   if ( lvarstd ) vars2 = field_malloc(vlistID1, FIELD_PTR);
 
   for ( tsID = 0; tsID < noffset; tsID++ )
@@ -116,7 +115,7 @@ void *Timselstat(void *argument)
       nrecs = streamInqTimestep(streamID1, tsID);
       if ( nrecs == 0 ) break;
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -144,7 +143,7 @@ void *Timselstat(void *argument)
 
 	  dtlist_taxisInqTimestep(dtlist, taxisID1, nsets);
 
-	  for ( recID = 0; recID < nrecs; recID++ )
+	  for ( int recID = 0; recID < nrecs; recID++ )
 	    {
 	      streamInqRecord(streamID1, &varID, &levelID);
 
@@ -166,7 +165,7 @@ void *Timselstat(void *argument)
 		      if ( samp1[varID][levelID].ptr == NULL )
 			samp1[varID][levelID].ptr = (double*) Malloc(gridsize*sizeof(double));
 
-		      for ( i = 0; i < gridsize; i++ )
+		      for ( int i = 0; i < gridsize; i++ )
 			if ( DBL_IS_EQUAL(vars1[varID][levelID].ptr[i],
 					  vars1[varID][levelID].missval) )
 			  samp1[varID][levelID].ptr[i] = 0;
@@ -186,11 +185,11 @@ void *Timselstat(void *argument)
 		      if ( samp1[varID][levelID].ptr == NULL )
 			{
 			  samp1[varID][levelID].ptr = (double*) Malloc(gridsize*sizeof(double));
-			  for ( i = 0; i < gridsize; i++ )
+			  for ( int i = 0; i < gridsize; i++ )
 			    samp1[varID][levelID].ptr[i] = nsets;
 			}
 
-		      for ( i = 0; i < gridsize; i++ )
+		      for ( int i = 0; i < gridsize; i++ )
 			if ( !DBL_IS_EQUAL(field.ptr[i], vars1[varID][levelID].missval) )
 			  samp1[varID][levelID].ptr[i]++;
 		    }
@@ -261,7 +260,7 @@ void *Timselstat(void *argument)
       dtlist_stat_taxisDefTimestep(dtlist, taxisID2, nsets);
       streamDefTimestep(streamID2, otsID);
 
-      for ( recID = 0; recID < nrecords; recID++ )
+      for ( int recID = 0; recID < nrecords; recID++ )
 	{
 	  varID   = recVarID[recID];
 	  levelID = recLevelID[recID];
@@ -275,7 +274,7 @@ void *Timselstat(void *argument)
       if ( nrecs == 0 ) break;
       otsID++;
 
-      for ( i = 0; i < nskip; i++ )
+      for ( int i = 0; i < nskip; i++ )
 	{
 	  nrecs = streamInqTimestep(streamID1, tsID);
 	  if ( nrecs == 0 ) break;
diff --git a/src/Timsort.c b/src/Timsort.c
index 56fa368..17fcba6 100644
--- a/src/Timsort.c
+++ b/src/Timsort.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -40,7 +40,7 @@ int cmpdarray(const void *s1, const void *s2)
   if      ( *x < *y ) cmp = -1;
   else if ( *x > *y ) cmp =  1;
 
-  return (cmp);
+  return cmp;
 }
 
 
@@ -48,37 +48,31 @@ void *Timsort(void *argument)
 {
   int gridsize;
   int nrecs;
-  int gridID, varID, levelID, recID;
-  int tsID;
-  int i;
-  int nts;
+  int gridID, varID, levelID;
   int nalloc = 0;
-  int streamID1, streamID2;
-  int vlistID1, vlistID2, taxisID1, taxisID2;
   int nmiss;
-  int nvars, nlevel;
+  int nlevel;
   int *vdate = NULL, *vtime = NULL;
-  double **sarray = NULL;
-  field_t ***vars = NULL;
+  field_type ***vars = NULL;
 
   cdoInitialize(argument);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisCreate(TAXIS_ABSOLUTE);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisCreate(TAXIS_ABSOLUTE);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  nvars = vlistNvars(vlistID1);
+  int nvars = vlistNvars(vlistID1);
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       if ( tsID >= nalloc )
@@ -86,7 +80,7 @@ void *Timsort(void *argument)
 	  nalloc += NALLOC_INC;
 	  vdate = (int*) Realloc(vdate, nalloc*sizeof(int));
 	  vtime = (int*) Realloc(vtime, nalloc*sizeof(int));
-	  vars  = (field_t ***) Realloc(vars, nalloc*sizeof(field_t **));
+	  vars  = (field_type ***) Realloc(vars, nalloc*sizeof(field_type **));
 	}
 
       vdate[tsID] = taxisInqVdate(taxisID1);
@@ -94,7 +88,7 @@ void *Timsort(void *argument)
 
       vars[tsID] = field_malloc(vlistID1, FIELD_NONE);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  gridID   = vlistInqVarGrid(vlistID1, varID);
@@ -107,10 +101,10 @@ void *Timsort(void *argument)
       tsID++;
     }
 
-  nts = tsID;
+  int nts = tsID;
 
-  sarray = (double **) Malloc(ompNumThreads*sizeof(double *));
-  for ( i = 0; i < ompNumThreads; i++ )
+  double **sarray = (double **) Malloc(ompNumThreads*sizeof(double *));
+  for ( int i = 0; i < ompNumThreads; i++ )
     sarray[i] = (double*) Malloc(nts*sizeof(double));
 
   for ( varID = 0; varID < nvars; varID++ )
@@ -140,7 +134,7 @@ void *Timsort(void *argument)
 	}
     }
 
-  for ( i = 0; i < ompNumThreads; i++ )
+  for ( int i = 0; i < ompNumThreads; i++ )
     if ( sarray[i] ) Free(sarray[i]);
 
   if ( sarray ) Free(sarray);
diff --git a/src/Timstat.c b/src/Timstat.c
index 4da05e5..2fada79 100644
--- a/src/Timstat.c
+++ b/src/Timstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -18,6 +18,7 @@
 /*
    This module contains the following operators:
 
+      Timstat    timrange        Time range
       Timstat    timmin          Time minimum
       Timstat    timmax          Time maximum
       Timstat    timsum          Time sum
@@ -27,6 +28,7 @@
       Timstat    timvar1         Time variance [Normalize by (n-1)]
       Timstat    timstd          Time standard deviation
       Timstat    timstd1         Time standard deviation [Normalize by (n-1)]
+      Hourstat   hourrange       Hourly range
       Hourstat   hourmin         Hourly minimum
       Hourstat   hourmax         Hourly maximum
       Hourstat   hoursum         Hourly sum
@@ -36,6 +38,7 @@
       Hourstat   hourvar1        Hourly variance [Normalize by (n-1)]
       Hourstat   hourstd         Hourly standard deviation
       Hourstat   hourstd1        Hourly standard deviation [Normalize by (n-1)]
+      Daystat    dayrange        Daily range
       Daystat    daymin          Daily minimum
       Daystat    daymax          Daily maximum
       Daystat    daysum          Daily sum
@@ -45,6 +48,7 @@
       Daystat    dayvar1         Daily variance [Normalize by (n-1)]
       Daystat    daystd          Daily standard deviation
       Daystat    daystd1         Daily standard deviation [Normalize by (n-1)]
+      Monstat    monrange        Monthly range
       Monstat    monmin          Monthly minimum
       Monstat    monmax          Monthly maximum
       Monstat    monsum          Monthly sum
@@ -54,6 +58,7 @@
       Monstat    monvar1         Monthly variance [Normalize by (n-1)]
       Monstat    monstd          Monthly standard deviation
       Monstat    monstd1         Monthly standard deviation [Normalize by (n-1)]
+      Yearstat   yearrange       Yearly range
       Yearstat   yearmin         Yearly minimum
       Yearstat   yearmax         Yearly maximum
       Yearstat   yearsum         Yearly sum
@@ -88,7 +93,7 @@ void *Timstat(void *argument)
   int streamID3 = -1;
   int vlistID3, taxisID3 = -1;
   int nmiss;
-  int lvfrac = FALSE;
+  bool lvfrac = false;
   int nwpv; // number of words per value; real:1  complex:2
   char indate1[DATE_LEN+1], indate2[DATE_LEN+1];
   double vfrac = 1;
@@ -96,6 +101,7 @@ void *Timstat(void *argument)
 
   cdoInitialize(argument);
 
+  cdoOperatorAdd("timrange",  func_range, DATE_LEN, NULL);
   cdoOperatorAdd("timmin",    func_min,   DATE_LEN, NULL);
   cdoOperatorAdd("timmax",    func_max,   DATE_LEN, NULL);
   cdoOperatorAdd("timsum",    func_sum,   DATE_LEN, NULL);
@@ -105,6 +111,7 @@ void *Timstat(void *argument)
   cdoOperatorAdd("timvar1",   func_var1,  DATE_LEN, NULL);
   cdoOperatorAdd("timstd",    func_std,   DATE_LEN, NULL);
   cdoOperatorAdd("timstd1",   func_std1,  DATE_LEN, NULL);
+  cdoOperatorAdd("yearrange", func_range, YEAR_LEN, NULL);
   cdoOperatorAdd("yearmin",   func_min,   YEAR_LEN, NULL);
   cdoOperatorAdd("yearmax",   func_max,   YEAR_LEN, NULL);
   cdoOperatorAdd("yearsum",   func_sum,   YEAR_LEN, NULL);
@@ -114,6 +121,7 @@ void *Timstat(void *argument)
   cdoOperatorAdd("yearvar1",  func_var1,  YEAR_LEN, NULL);
   cdoOperatorAdd("yearstd",   func_std,   YEAR_LEN, NULL);
   cdoOperatorAdd("yearstd1",  func_std1,  YEAR_LEN, NULL);
+  cdoOperatorAdd("monrange",  func_range, MON_LEN, NULL);
   cdoOperatorAdd("monmin",    func_min,   MON_LEN, NULL);
   cdoOperatorAdd("monmax",    func_max,   MON_LEN, NULL);
   cdoOperatorAdd("monsum",    func_sum,   MON_LEN, NULL);
@@ -123,6 +131,7 @@ void *Timstat(void *argument)
   cdoOperatorAdd("monvar1",   func_var1,  MON_LEN, NULL);
   cdoOperatorAdd("monstd",    func_std,   MON_LEN, NULL);
   cdoOperatorAdd("monstd1",   func_std1,  MON_LEN, NULL);
+  cdoOperatorAdd("dayrange",  func_range, DAY_LEN, NULL);
   cdoOperatorAdd("daymin",    func_min,   DAY_LEN, NULL);
   cdoOperatorAdd("daymax",    func_max,   DAY_LEN, NULL);
   cdoOperatorAdd("daysum",    func_sum,   DAY_LEN, NULL);
@@ -132,6 +141,7 @@ void *Timstat(void *argument)
   cdoOperatorAdd("dayvar1",   func_var1,  DAY_LEN, NULL);
   cdoOperatorAdd("daystd",    func_std,   DAY_LEN, NULL);
   cdoOperatorAdd("daystd1",   func_std1,  DAY_LEN, NULL);
+  cdoOperatorAdd("hourrange", func_range, HOUR_LEN, NULL);
   cdoOperatorAdd("hourmin",   func_min,   HOUR_LEN, NULL);
   cdoOperatorAdd("hourmax",   func_max,   HOUR_LEN, NULL);
   cdoOperatorAdd("hoursum",   func_sum,   HOUR_LEN, NULL);
@@ -146,10 +156,11 @@ void *Timstat(void *argument)
   int operfunc   = cdoOperatorF1(operatorID);
   int comparelen = cdoOperatorF2(operatorID);
 
-  int lmean   = operfunc == func_mean || operfunc == func_avg;
-  int lstd    = operfunc == func_std || operfunc == func_std1;
-  int lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
-  int divisor = operfunc == func_std1 || operfunc == func_var1;
+  bool lrange  = operfunc == func_range;
+  bool lmean   = operfunc == func_mean || operfunc == func_avg;
+  bool lstd    = operfunc == func_std || operfunc == func_std1;
+  bool lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
+  int divisor  = operfunc == func_std1 || operfunc == func_var1;
 
   if ( operfunc == func_mean )
     {
@@ -158,7 +169,7 @@ void *Timstat(void *argument)
 
       if ( oargc == 1 )
 	{
-	  lvfrac = TRUE;
+	  lvfrac = true;
 	  vfrac = atof(oargv[0]);
 	  if ( cdoVerbose ) cdoPrint("Set vfrac to %g", vfrac);
 	  if ( vfrac < 0 || vfrac > 1 ) cdoAbort("vfrac out of range!");
@@ -192,7 +203,7 @@ void *Timstat(void *argument)
   if      ( comparelen == DAY_LEN )  freq = "day";
   else if ( comparelen == MON_LEN )  freq = "mon";
   else if ( comparelen == YEAR_LEN ) freq = "year";
-  if ( freq ) vlistDefAttTxt(vlistID2, CDI_GLOBAL, "frequency", (int)strlen(freq), freq);
+  if ( freq ) cdiDefAttTxt(vlistID2, CDI_GLOBAL, "frequency", (int)strlen(freq), freq);
 
   int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
@@ -213,7 +224,7 @@ void *Timstat(void *argument)
 
       for ( varID = 0; varID < nvars; ++varID )
 	{
-	  vlistDefVarDatatype(vlistID3, varID, DATATYPE_INT32);
+	  vlistDefVarDatatype(vlistID3, varID, CDI_DATATYPE_INT32);
 	  vlistDefVarMissval(vlistID3, varID, -1);
 	  vlistDefVarUnits(vlistID3, varID, "");
 	  vlistDefVarAddoffset(vlistID3, varID, 0);
@@ -238,7 +249,7 @@ void *Timstat(void *argument)
   int FIELD_MEMTYPE = 0;
   if ( CDO_Memtype == MEMTYPE_FLOAT ) FIELD_MEMTYPE = MEMTYPE_FLOAT;
 
-  field_t field;
+  field_type field;
   field_init(&field);
   field.memtype = FIELD_MEMTYPE;
   if ( FIELD_MEMTYPE == MEMTYPE_FLOAT )
@@ -246,10 +257,10 @@ void *Timstat(void *argument)
   else
     field.ptr = (double*) Malloc(gridsize*sizeof(double));
 
-  field_t **vars1 = field_malloc(vlistID1, FIELD_PTR);
-  field_t **samp1 = field_malloc(vlistID1, FIELD_NONE);
-  field_t **vars2 = NULL;
-  if ( lvarstd ) vars2 = field_malloc(vlistID1, FIELD_PTR);
+  field_type **vars1 = field_malloc(vlistID1, FIELD_PTR);
+  field_type **samp1 = field_malloc(vlistID1, FIELD_NONE);
+  field_type **vars2 = NULL;
+  if ( lvarstd || lrange ) vars2 = field_malloc(vlistID1, FIELD_PTR);
 
   int tsID  = 0;
   int otsID = 0;
@@ -277,7 +288,7 @@ void *Timstat(void *argument)
                   recinfo[recID].levelID = levelID;
 		}
 
-              field_t *pvar1 = &vars1[varID][levelID];
+              field_type *pvar1 = &vars1[varID][levelID];
               
 	      nwpv     = pvar1->nwpv;
 	      gridsize = gridInqSize(pvar1->grid);
@@ -286,6 +297,14 @@ void *Timstat(void *argument)
 		{
 		  streamReadRecord(streamID1, pvar1->ptr, &nmiss);
 		  pvar1->nmiss = (size_t)nmiss;
+                  if ( lrange )
+                    {
+                      field_type *pvar2 = &vars2[varID][levelID];
+		      for ( int i = 0; i < nwpv*gridsize; i++ )
+                        pvar2->ptr[i] = pvar1->ptr[i];
+                      pvar2->nmiss = (size_t)nmiss;
+                    }
+
 		  if ( nmiss > 0 || samp1[varID][levelID].ptr )
 		    {
 		      if ( samp1[varID][levelID].ptr == NULL )
@@ -324,10 +343,16 @@ void *Timstat(void *argument)
 
 		  if ( lvarstd )
 		    {
-                      field_t *pvar2 = &vars2[varID][levelID];
+                      field_type *pvar2 = &vars2[varID][levelID];
 		      farsumq(pvar2, field);
 		      farsum(pvar1, field);
 		    }
+                  else if ( lrange )
+                    {
+                      field_type *pvar2 = &vars2[varID][levelID];
+                      farmin(pvar2, field);
+                      farmax(pvar1, field);
+                    }
 		  else
 		    {
 		      farfun(pvar1, field, operfunc);
@@ -340,8 +365,8 @@ void *Timstat(void *argument)
               {
                 int varID   = recinfo[recID].varID;
                 int levelID = recinfo[recID].levelID;
-                field_t *pvar1 = &vars1[varID][levelID];
-                field_t *pvar2 = &vars2[varID][levelID];
+                field_type *pvar1 = &vars1[varID][levelID];
+                field_type *pvar2 = &vars2[varID][levelID];
 
 		if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
 
@@ -361,7 +386,7 @@ void *Timstat(void *argument)
           {
             int varID   = recinfo[recID].varID;
             int levelID = recinfo[recID].levelID;
-            field_t *pvar1 = &vars1[varID][levelID];
+            field_type *pvar1 = &vars1[varID][levelID];
 
 	    if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
 
@@ -375,8 +400,8 @@ void *Timstat(void *argument)
           {
             int varID   = recinfo[recID].varID;
             int levelID = recinfo[recID].levelID;
-            field_t *pvar1 = &vars1[varID][levelID];
-            field_t *pvar2 = &vars2[varID][levelID];
+            field_type *pvar1 = &vars1[varID][levelID];
+            field_type *pvar2 = &vars2[varID][levelID];
 
             if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
 
@@ -391,6 +416,18 @@ void *Timstat(void *argument)
                 else        farvar(pvar1, *pvar2, samp1[varID][levelID], divisor);
 	      }
 	  }
+      else if ( lrange )
+        for ( int recID = 0; recID < maxrecs; recID++ )
+          {
+            int varID   = recinfo[recID].varID;
+            int levelID = recinfo[recID].levelID;
+            field_type *pvar1 = &vars1[varID][levelID];
+            field_type *pvar2 = &vars2[varID][levelID];
+
+            if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
+
+            farsub(pvar1, *pvar2);
+	  }
 
       if ( cdoVerbose )
 	{
@@ -405,7 +442,7 @@ void *Timstat(void *argument)
           {
             int varID   = recinfo[recID].varID;
             int levelID = recinfo[recID].levelID;
-            field_t *pvar1 = &vars1[varID][levelID];
+            field_type *pvar1 = &vars1[varID][levelID];
 
 	    if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
 
@@ -447,7 +484,7 @@ void *Timstat(void *argument)
 	{
           int varID   = recinfo[recID].varID;
           int levelID = recinfo[recID].levelID;
-          field_t *pvar1 = &vars1[varID][levelID];
+          field_type *pvar1 = &vars1[varID][levelID];
 
 	  if ( otsID && vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
 
@@ -456,11 +493,16 @@ void *Timstat(void *argument)
           
 	  if ( cdoDiag )
 	    {
-	      if ( samp1[varID][levelID].ptr )
-		{
-		  streamDefRecord(streamID3, varID, levelID);
-		  streamWriteRecord(streamID3, samp1[varID][levelID].ptr, 0);
-		}
+              double *sampptr = field.ptr;
+	      if ( samp1[varID][levelID].ptr ) sampptr = samp1[varID][levelID].ptr;
+              else
+                {
+                  gridsize = gridInqSize(pvar1->grid);
+                  for ( int i = 0; i < gridsize; ++i ) sampptr[i] = nsets;
+                }
+
+              streamDefRecord(streamID3, varID, levelID);
+              streamWriteRecord(streamID3, sampptr, 0);
 	    }
 	}
 
@@ -471,7 +513,7 @@ void *Timstat(void *argument)
 
   field_free(vars1, vlistID1);
   field_free(samp1, vlistID1);
-  if ( lvarstd ) field_free(vars2, vlistID1);
+  if ( lvarstd || lrange ) field_free(vars2, vlistID1);
 
   dtlist_delete(dtlist);
 
diff --git a/src/Timstat2.c b/src/Timstat2.c
index 9b73a70..3524b59 100644
--- a/src/Timstat2.c
+++ b/src/Timstat2.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -31,12 +31,11 @@ static
 int correlation_t(long gridsize, double missval1, double missval2, int *nofvals, 
 		  double *work0, double *work1, double *work2, double *work3, double *work4)
 {
-  long i;
   int nvals, nmiss = 0;
   double temp0, temp1, temp2, temp3, temp4, temp5, temp6;
   double cor;
 
-  for ( i = 0; i < gridsize; i++ )
+  for ( long i = 0; i < gridsize; i++ )
     {	  
       nvals = nofvals[i];
 
@@ -74,13 +73,12 @@ static
 int covariance_t(long gridsize, double missval1, double missval2, int *nofvals, 
 		 double *work0, double *work1, double *work2)
 {
-  long i;
   int nvals, nmiss = 0;
   double temp;
   double dnvals;
   double covar;
 
-  for ( i = 0; i < gridsize; i++ )
+  for ( long i = 0; i < gridsize; i++ )
     {	  
       nvals = nofvals[i];
       dnvals = nvals;
@@ -111,7 +109,7 @@ void *Timstat2(void *argument)
   int vdate = 0, vtime = 0;
   int nrecs2, nlevs;
   long i, gridsize;
-  int varID, recID, levelID, gridID;
+  int varID, levelID, gridID;
   int nmiss;
   double missval1, missval2;
 
@@ -191,7 +189,7 @@ void *Timstat2(void *argument)
       if ( nrecs != nrecs2 )
         cdoWarning("Input streams have different number of records!");
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamInqRecord(streamID2, &varID, &levelID);
@@ -250,7 +248,7 @@ void *Timstat2(void *argument)
   taxisDefVtime(taxisID3, vtime);
   streamDefTimestep(streamID3, tsID);
 
-  for ( recID = 0; recID < nrecs3; recID++ )
+  for ( int recID = 0; recID < nrecs3; recID++ )
     {
       varID    = recVarID[recID];
       levelID  = recLevelID[recID];
diff --git a/src/Timstat3.c b/src/Timstat3.c
index 84f6a00..0ae65cc 100644
--- a/src/Timstat3.c
+++ b/src/Timstat3.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -36,38 +36,33 @@
 
 void *Timstat3(void *argument)
 {
-  int VARQUOT2TEST, MEANDIFF2TEST;
   int streamID[NIN];
   int vlistID[NIN], vlistID2 = -1;
-  int gridsize;
   int vdate = 0, vtime = 0;
   int nlevs;
-  int i, iw, is;
-  int varID, recID, levelID, gridID;
+  int is;
+  int varID, levelID, gridID;
   int nmiss;
-  double rconst, risk;
-  double fnvals0, fnvals1;
   double missval, missval1, missval2;
   double fractil_1, fractil_2, statistic;
-  double temp0, temp1, temp2, temp3;
   int ***iwork[NIWORK];
-  field_t **fwork[NFWORK];
-  field_t in[NIN], out[NOUT];
+  field_type **fwork[NFWORK];
+  field_type in[NIN], out[NOUT];
   int reached_eof[NIN];
   int n_in = NIN;
 
 
   cdoInitialize(argument);
 
-  VARQUOT2TEST  = cdoOperatorAdd("varquot2test",  0, 0, NULL);
-  MEANDIFF2TEST = cdoOperatorAdd("meandiff2test", 0, 0, NULL);
+  int VARQUOT2TEST  = cdoOperatorAdd("varquot2test",  0, 0, NULL);
+  int MEANDIFF2TEST = cdoOperatorAdd("meandiff2test", 0, 0, NULL);
 
   int operatorID = cdoOperatorID();
 
   operatorInputArg("constant and risk (e.g. 0.05)");
   operatorCheckArgc(2);
-  rconst = parameter2double(operatorArgv()[0]);
-  risk   = parameter2double(operatorArgv()[1]);
+  double rconst = parameter2double(operatorArgv()[0]);
+  double risk   = parameter2double(operatorArgv()[1]);
 
   if ( operatorID == VARQUOT2TEST )
     {
@@ -92,7 +87,7 @@ void *Timstat3(void *argument)
 
   int vlistID3 = vlistDuplicate(vlistID[0]);
 
-  gridsize = vlistGridsizeMax(vlistID[0]);
+  int gridsize = vlistGridsizeMax(vlistID[0]);
   int nvars = vlistNvars(vlistID[0]);
   int nrecs = vlistNrecs(vlistID[0]);
   int nrecs3 = nrecs;
@@ -107,23 +102,23 @@ void *Timstat3(void *argument)
 
   streamDefVlist(streamID3, vlistID3);
 
-  for ( i = 0; i < NIN; ++i ) reached_eof[i] = 0;
+  for ( int i = 0; i < NIN; ++i ) reached_eof[i] = 0;
 
-  for ( i = 0; i < NIN; ++i )
+  for ( int i = 0; i < NIN; ++i )
     {
       field_init(&in[i]);
       in[i].ptr = (double*) Malloc(gridsize*sizeof(double));
     }
 				 
-  for ( i = 0; i < NOUT; ++i )
+  for ( int i = 0; i < NOUT; ++i )
     {
       field_init(&out[i]);
       out[i].ptr = (double*) Malloc(gridsize*sizeof(double));
     }
 				 
-  for ( iw = 0; iw < NFWORK; ++iw )
-    fwork[iw] = (field_t **) Malloc(nvars*sizeof(field_t *));
-  for ( iw = 0; iw < NIWORK; ++iw )
+  for ( int iw = 0; iw < NFWORK; ++iw )
+    fwork[iw] = (field_type **) Malloc(nvars*sizeof(field_type *));
+  for ( int iw = 0; iw < NIWORK; ++iw )
     iwork[iw] = (int ***) Malloc(nvars*sizeof(int **));
 
   for ( varID = 0; varID < nvars; ++varID )
@@ -134,14 +129,14 @@ void *Timstat3(void *argument)
       missval  = missval1 = vlistInqVarMissval(vlistID[0], varID);
       // missval2 = vlistInqVarMissval(vlistID[1], varID); 
 
-      for ( iw = 0; iw < NFWORK; ++iw )
-	fwork[iw][varID] = (field_t*) Malloc(nlevs*sizeof(field_t));
-      for ( iw = 0; iw < NIWORK; ++iw )
+      for ( int iw = 0; iw < NFWORK; ++iw )
+	fwork[iw][varID] = (field_type*) Malloc(nlevs*sizeof(field_type));
+      for ( int iw = 0; iw < NIWORK; ++iw )
 	iwork[iw][varID] = (int **) Malloc(nlevs*sizeof(int *));  
 
       for ( levelID = 0; levelID < nlevs; ++levelID )
 	{
-	  for ( iw = 0; iw < NFWORK; ++iw )
+	  for ( int iw = 0; iw < NFWORK; ++iw )
 	    {
 	      field_init(&fwork[iw][varID][levelID]);
 	      fwork[iw][varID][levelID].grid    = gridID;
@@ -151,7 +146,7 @@ void *Timstat3(void *argument)
 	      memset(fwork[iw][varID][levelID].ptr, 0, gridsize*sizeof(double));
 	    }
 
-	  for ( iw = 0; iw < NIWORK; ++iw )
+	  for ( int iw = 0; iw < NIWORK; ++iw )
 	    {
 	      iwork[iw][varID][levelID] = (int*) Malloc(gridsize*sizeof(int));
 	      memset(iwork[iw][varID][levelID], 0, gridsize*sizeof(int));
@@ -176,7 +171,7 @@ void *Timstat3(void *argument)
 	  vdate = taxisInqVdate(taxisID1);
 	  vtime = taxisInqVtime(taxisID1);
 
-	  for ( recID = 0; recID < nrecs; recID++ )
+	  for ( int recID = 0; recID < nrecs; recID++ )
 	    {
 	      streamInqRecord(streamID[is], &varID, &levelID);
 
@@ -193,7 +188,7 @@ void *Timstat3(void *argument)
 	      streamReadRecord(streamID[is], in[is].ptr, &nmiss);
 	      in[is].nmiss = (size_t) nmiss;
               
-	      for ( i = 0; i < gridsize; ++i )
+	      for ( int i = 0; i < gridsize; ++i )
 		{
 		  /*
 		  if ( ( ! DBL_IS_EQUAL(array1[i], missval1) ) && 
@@ -221,7 +216,7 @@ void *Timstat3(void *argument)
   taxisDefVtime(taxisID3, vtime);
   streamDefTimestep(streamID3, 0);
 
-  for ( recID = 0; recID < nrecs3; recID++ )
+  for ( int recID = 0; recID < nrecs3; recID++ )
     {
       varID    = recVarID[recID];
       levelID  = recLevelID[recID];
@@ -231,15 +226,15 @@ void *Timstat3(void *argument)
 
       if ( operatorID == VARQUOT2TEST )
 	{
-	  for ( i = 0; i < gridsize; ++i )
+	  for ( int i = 0; i < gridsize; ++i )
 	    {
-	      fnvals0 = iwork[0][varID][levelID][i];
-	      fnvals1 = iwork[1][varID][levelID][i];
+	      double fnvals0 = iwork[0][varID][levelID][i];
+	      double fnvals1 = iwork[1][varID][levelID][i];
 
-	      temp0 = DIVMN( MULMN(fwork[0][varID][levelID].ptr[i], fwork[0][varID][levelID].ptr[i]), fnvals0);
-	      temp1 = DIVMN( MULMN(fwork[2][varID][levelID].ptr[i], fwork[2][varID][levelID].ptr[i]), fnvals1);
-	      temp2 = SUBMN(fwork[1][varID][levelID].ptr[i], temp0);
-	      temp3 = SUBMN(fwork[3][varID][levelID].ptr[i], temp1);
+	      double temp0 = DIVMN( MULMN(fwork[0][varID][levelID].ptr[i], fwork[0][varID][levelID].ptr[i]), fnvals0);
+	      double temp1 = DIVMN( MULMN(fwork[2][varID][levelID].ptr[i], fwork[2][varID][levelID].ptr[i]), fnvals1);
+	      double temp2 = SUBMN(fwork[1][varID][levelID].ptr[i], temp0);
+	      double temp3 = SUBMN(fwork[3][varID][levelID].ptr[i], temp1);
 	      statistic = DIVMN(temp2, ADDMN(temp2, MULMN(rconst, temp3)));
 	      
 	      if ( fnvals0 <= 1 || fnvals1 <= 1 )
@@ -254,25 +249,21 @@ void *Timstat3(void *argument)
 	}									       
       else if ( operatorID == MEANDIFF2TEST )
 	{
-	  int j;
-	  double fnvals;
 	  double fractil;
 	  double mean_factor[NIN], var_factor[NIN];
-	  double stddev_estimator, mean_estimator, norm, deg_of_freedom;
-	  double tmp;
 	  
 	  mean_factor[0] = 1;
 	  mean_factor[1] = -1;
 	  var_factor[0] = var_factor[1] = 1;
 
-	  for ( i = 0; i < gridsize; ++i )
+	  for ( int i = 0; i < gridsize; ++i )
 	    {
-	      temp0 = 0;
-	      deg_of_freedom = -n_in;
-	      for ( j = 0; j < n_in; j++ )
+	      double temp0 = 0;
+	      double deg_of_freedom = -n_in;
+	      for ( int j = 0; j < n_in; j++ )
 		{
-		  fnvals = iwork[j][varID][levelID][i];
-		  tmp   = DIVMN( MULMN(fwork[2*j][varID][levelID].ptr[i], fwork[2*j][varID][levelID].ptr[i]), fnvals);
+		  double fnvals = iwork[j][varID][levelID][i];
+		  double tmp   = DIVMN( MULMN(fwork[2*j][varID][levelID].ptr[i], fwork[2*j][varID][levelID].ptr[i]), fnvals);
 		  temp0 = ADDMN(temp0, DIVMN( SUBMN(fwork[2*j+1][varID][levelID].ptr[i], tmp), var_factor[j]));
 		  deg_of_freedom = ADDMN(deg_of_freedom, fnvals);
 		}
@@ -280,27 +271,27 @@ void *Timstat3(void *argument)
 	      if ( !DBL_IS_EQUAL(temp0, missval1) && temp0 < 0 ) /* This is possible because */
 		temp0 = 0;	                                 /* of rounding errors       */
 
-	      stddev_estimator = SQRTMN( DIVMN(temp0, deg_of_freedom));
-	      mean_estimator = -rconst;
-	      for ( j = 0; j < n_in; j++ )
+	      double stddev_estimator = SQRTMN( DIVMN(temp0, deg_of_freedom));
+	      double mean_estimator = -rconst;
+	      for ( int j = 0; j < n_in; j++ )
 		{
-		  fnvals = iwork[j][varID][levelID][i];
+		  double fnvals = iwork[j][varID][levelID][i];
 		  mean_estimator = ADDMN(mean_estimator,
 				       MULMN(mean_factor[j],
 					   DIVMN(fwork[2*j][varID][levelID].ptr[i], fnvals)));
 		}
 
-	      temp1 = 0;
-	      for ( j = 0; j < n_in; j++ )
+	      double temp1 = 0;
+	      for ( int j = 0; j < n_in; j++ )
 		{
-		  fnvals = iwork[j][varID][levelID][i];
+		  double fnvals = iwork[j][varID][levelID][i];
 		  temp1 = ADDMN(temp1, DIVMN( MULMN( MULMN(mean_factor[j], mean_factor[j]),
 					     var_factor[j]), fnvals));
 		}
 
-	      norm = SQRTMN(temp1);
+	      double norm = SQRTMN(temp1);
 	      
-	      temp2 = DIVMN( DIVMN(mean_estimator, norm), stddev_estimator);
+	      double temp2 = DIVMN( DIVMN(mean_estimator, norm), stddev_estimator);
 	      fractil = deg_of_freedom < 1 ? missval1 :
 		student_t_inv (deg_of_freedom, 1 - risk/2, __func__);
 
@@ -310,7 +301,7 @@ void *Timstat3(void *argument)
 	}
 
       nmiss = 0;
-      for ( i = 0; i < gridsize; i++ )
+      for ( int i = 0; i < gridsize; i++ )
 	if ( DBL_IS_EQUAL(out[0].ptr[i], missval1) ) nmiss++;
 
       streamDefRecord(streamID3, varID, levelID);
@@ -322,26 +313,26 @@ void *Timstat3(void *argument)
       nlevs = zaxisInqSize(vlistInqVarZaxis(vlistID[0], varID));
       for ( levelID = 0; levelID < nlevs; levelID++ )
 	{
-	  for ( iw = 0; iw < NFWORK; ++iw )
+	  for ( int iw = 0; iw < NFWORK; ++iw )
 	    Free(fwork[iw][varID][levelID].ptr);
-	  for ( iw = 0; iw < NIWORK; ++iw )
+	  for ( int iw = 0; iw < NIWORK; ++iw )
 	    Free(iwork[iw][varID][levelID]);
 	}
     
-      for ( iw = 0; iw < NFWORK; ++iw ) Free(fwork[iw][varID]);
-      for ( iw = 0; iw < NIWORK; ++iw ) Free(iwork[iw][varID]);
+      for ( int iw = 0; iw < NFWORK; ++iw ) Free(fwork[iw][varID]);
+      for ( int iw = 0; iw < NIWORK; ++iw ) Free(iwork[iw][varID]);
     }
 
-  for ( iw = 0; iw < NFWORK; iw++ ) Free(fwork[iw]);
-  for ( iw = 0; iw < NIWORK; iw++ ) Free(iwork[iw]);
+  for ( int iw = 0; iw < NFWORK; iw++ ) Free(fwork[iw]);
+  for ( int iw = 0; iw < NIWORK; iw++ ) Free(iwork[iw]);
 
 
   streamClose(streamID3);
   for ( is = 0; is < NIN; ++is )
     streamClose(streamID[is]);
 
-  for ( i = 0; i < NIN; ++i ) Free(in[i].ptr);
-  for ( i = 0; i < NOUT; ++i ) Free(out[i].ptr);
+  for ( int i = 0; i < NIN; ++i ) Free(in[i].ptr);
+  for ( int i = 0; i < NOUT; ++i ) Free(out[i].ptr);
 
   Free(recVarID);
   Free(recLevelID);
diff --git a/src/Tinfo.c b/src/Tinfo.c
index a4d21a1..0a9a31f 100644
--- a/src/Tinfo.c
+++ b/src/Tinfo.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -52,8 +52,7 @@ void getTimeInc(double jdelta, int vdate0, int vdate1, int *incperiod, int *incu
 
   if ( lperiod < 0 )
     {
-      int tmp;
-      tmp = vdate1;
+      int tmp = vdate1;
       vdate1 = vdate0;
       vdate0 = tmp;
       lperiod = -lperiod;
@@ -210,7 +209,7 @@ int fill_gap(int ngaps, int ntsm[MAX_NTSM], int rangetsm[MAX_GAPS][2],
       ntsm[ngaps] = its;
     }
 
-  return (its);
+  return its;
 }
 
 
@@ -219,14 +218,13 @@ void *Tinfo(void *argument)
   int vdate_first = 0, vtime_first = 0;
   int vdate0 = 0, vtime0 = 0;
   int vdate = 0, vtime = 0;
-  int fdate = 0, ftime = 0;
   int nrecs;
   int tsID = 0, ntimeout;
   int calendar;
   int year0, month0, day0;
   int year, month, day;
   int unit;
-  int lforecast = FALSE;
+  bool lforecast = false;
   int incperiod0 = 0, incunit0 = 0;
   int incperiod = 0, incunit = 0;
   int its = 0, igap;
@@ -284,8 +282,8 @@ void *Tinfo(void *argument)
 
 	      if ( taxisInqType(taxisID) == TAXIS_FORECAST )
 		{
-		  fdate = taxisInqFdate(taxisID);
-		  ftime = taxisInqFtime(taxisID);
+		  int fdate = taxisInqFdate(taxisID);
+		  int ftime = taxisInqFtime(taxisID);
 	      
 		  date2str(fdate, vdatestr, sizeof(vdatestr));
 		  time2str(ftime, vtimestr, sizeof(vtimestr));
@@ -297,12 +295,12 @@ void *Tinfo(void *argument)
 
 		  fprintf(stdout, "\n");
 
-		  lforecast = TRUE;
+		  lforecast = true;
 		}
 	    }
 	}
 
-      calendar = taxisInqCalendar(taxisID);
+      int calendar = taxisInqCalendar(taxisID);
 
       fprintf(stdout, "\n");
       fprintf(stdout, "         Verification Time              ");
@@ -353,8 +351,8 @@ void *Tinfo(void *argument)
 
 	  if ( lforecast )
 	    {
-	      fdate = taxisInqFdate(taxisID);
-	      ftime = taxisInqFtime(taxisID);
+	      int fdate = taxisInqFdate(taxisID);
+	      int ftime = taxisInqFtime(taxisID);
 	      
 	      date2str(fdate, vdatestr, sizeof(vdatestr));
 	      time2str(ftime, vtimestr, sizeof(vtimestr));
diff --git a/src/Tocomplex.c b/src/Tocomplex.c
index 2e6630b..217a0e8 100644
--- a/src/Tocomplex.c
+++ b/src/Tocomplex.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -24,64 +24,55 @@
 
 void *Tocomplex(void *argument)
 {
-  int RETOCOMPLEX, IMTOCOMPLEX;
-  int operatorID;
-  int streamID1, streamID2;
-  int tsID, tsID2, nrecs;
-  int recID, varID, levelID;
-  int vlistID1, vlistID2;
-  int taxisID1, taxisID2;
-  int i, gridsize;
-  int datatype;
-  int nmiss, nvars;
-  double *array1 = NULL, *array2 = NULL;
+  int nrecs;
+  int varID, levelID;
+  int nmiss;
 
   cdoInitialize(argument);
 
-  RETOCOMPLEX = cdoOperatorAdd("retocomplex", 0, 0, NULL);
-  IMTOCOMPLEX = cdoOperatorAdd("imtocomplex", 0, 0, NULL);
+  int RETOCOMPLEX = cdoOperatorAdd("retocomplex", 0, 0, NULL);
+  int IMTOCOMPLEX = cdoOperatorAdd("imtocomplex", 0, 0, NULL);
 
-  operatorID = cdoOperatorID();
+  int operatorID = cdoOperatorID();
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  nvars = vlistNvars(vlistID2);
+  int nvars = vlistNvars(vlistID2);
   for ( varID = 0; varID < nvars; ++varID )
     {
-      datatype = vlistInqVarDatatype(vlistID2, varID);
-      if ( datatype == DATATYPE_FLT64 )
-	datatype = DATATYPE_CPX64;
+      int datatype = vlistInqVarDatatype(vlistID2, varID);
+      if ( datatype == CDI_DATATYPE_FLT64 )
+	datatype = CDI_DATATYPE_CPX64;
       else
-	datatype = DATATYPE_CPX32;
+	datatype = CDI_DATATYPE_CPX32;
 
       vlistDefVarDatatype(vlistID2, varID, datatype);
     }
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  if ( cdoFiletype() != FILETYPE_EXT ) cdoAbort("Complex numbers need EXTRA format; used CDO option -f ext!");
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  if ( cdoFiletype() != CDI_FILETYPE_EXT ) cdoAbort("Complex numbers need EXTRA format; used CDO option -f ext!");
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  gridsize = vlistGridsizeMax(vlistID1);
-  array1 = (double*) Malloc(gridsize*sizeof(double));
-  array2 = (double*) Malloc(2*gridsize*sizeof(double));
+  int gridsize = vlistGridsizeMax(vlistID1);
+  double *array1 = (double*) Malloc(gridsize*sizeof(double));
+  double *array2 = (double*) Malloc(2*gridsize*sizeof(double));
       
-  tsID  = 0;
-  tsID2 = 0;
+  int tsID  = 0;
+  int tsID2 = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
-
       streamDefTimestep(streamID2, tsID2++);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamDefRecord(streamID2, varID, levelID);
@@ -92,7 +83,7 @@ void *Tocomplex(void *argument)
 
 	  if ( operatorID == RETOCOMPLEX )
 	    {
-	      for ( i = 0; i < gridsize; ++i )
+	      for ( int i = 0; i < gridsize; ++i )
 		{
 		  array2[2*i]   = array1[i];
 		  array2[2*i+1] = 0;
@@ -100,7 +91,7 @@ void *Tocomplex(void *argument)
 	    }
 	  else if ( operatorID == IMTOCOMPLEX )
 	    {
-	      for ( i = 0; i < gridsize; ++i )
+	      for ( int i = 0; i < gridsize; ++i )
 		{
 		  array2[2*i]   = 0;
 		  array2[2*i+1] = array1[i];
diff --git a/src/Transpose.c b/src/Transpose.c
index 27c64e4..2fff013 100644
--- a/src/Transpose.c
+++ b/src/Transpose.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -30,92 +30,89 @@
 
 void transxy(int gridID, double *array1, double *array2)
 {
-  int i, j;
-  int nx, ny;
-  double **a2D1, **a2D2;
+  int nx = gridInqXsize(gridID);
+  int ny = gridInqYsize(gridID);
+  int gridsize = nx*ny;
 
-  nx = gridInqXsize(gridID);
-  ny = gridInqYsize(gridID);
-
-  a2D1 = (double **) Malloc(ny*sizeof(double *));
-  a2D2 = (double **) Malloc(nx*sizeof(double *));
+  if ( gridsize > 0 )
+    {
+      double **a2D1 = (double **) Malloc(ny*sizeof(double *));
+      double **a2D2 = (double **) Malloc(nx*sizeof(double *));
 
-  for ( j = 0; j < ny; ++j ) a2D1[j] = array1+j*nx;
-  for ( i = 0; i < nx; ++i ) a2D2[i] = array2+i*ny;
+      for ( int j = 0; j < ny; ++j ) a2D1[j] = array1+j*nx;
+      for ( int i = 0; i < nx; ++i ) a2D2[i] = array2+i*ny;
 
-  for ( j = 0; j < ny; ++j )
-    for ( i = 0; i < nx; ++i )
-      a2D2[i][j] = a2D1[j][i];
+      for ( int j = 0; j < ny; ++j )
+        for ( int i = 0; i < nx; ++i )
+          a2D2[i][j] = a2D1[j][i];
 
-  Free(a2D1);
-  Free(a2D2);
+      Free(a2D1);
+      Free(a2D2);
+    }
+  else
+    {
+      gridsize = gridInqSize(gridID);
+      for ( int i = 0; i < gridsize; ++i )
+        array2[i] = array1[i];
+    }
 }
 
 
 void *Transpose(void *argument)
 {
-  int streamID1, streamID2;
-  int gridsize;
-  int ngrids, index;
-  int gridID1, gridID2;
-  int nx, ny;
-  int nrecs, recID;
-  int gridID, tsID;
+  int nrecs;
   int varID, levelID;
-  int vlistID1, vlistID2;
   int nmiss;
-  int taxisID1, taxisID2;
-  double *array1, *array2;
 
   cdoInitialize(argument);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  ngrids = vlistNgrids(vlistID1);
-  for ( index = 0; index < ngrids; index++ )
+  int ngrids = vlistNgrids(vlistID1);
+  for ( int index = 0; index < ngrids; index++ )
     {
-      gridID1 = vlistGrid(vlistID1, index);
-      nx = gridInqXsize(gridID1);
-      ny = gridInqYsize(gridID1);
-
-      gridID2 = gridCreate(GRID_GENERIC, nx*ny);
-      gridDefXsize(gridID2, ny);
-      gridDefYsize(gridID2, nx);
-
-      vlistChangeGridIndex(vlistID2, index, gridID2);
+      int gridID1 = vlistGrid(vlistID1, index);
+      int nx = gridInqXsize(gridID1);
+      int ny = gridInqYsize(gridID1);
+      int gridsize = nx*ny;
+      if ( gridsize > 0 )
+        {
+          int gridID2 = gridCreate(GRID_GENERIC, gridsize);
+          gridDefXsize(gridID2, ny);
+          gridDefYsize(gridID2, nx);
+          vlistChangeGridIndex(vlistID2, index, gridID2);
+        }
     }
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
 
-  array1 = (double*) Malloc(gridsize*sizeof(double));
-  array2 = (double*) Malloc(gridsize*sizeof(double));
+  double *array1 = (double*) Malloc(gridsize*sizeof(double));
+  double *array2 = (double*) Malloc(gridsize*sizeof(double));
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
-
       streamDefTimestep(streamID2, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, array1, &nmiss);
 
-	  gridID = vlistInqVarGrid(vlistID1, varID);
-
-	  transxy(gridID, array1, array2);
+	  int gridID = vlistInqVarGrid(vlistID1, varID);
+          transxy(gridID, array1, array2);
 
 	  streamDefRecord(streamID2, varID, levelID);
 	  streamWriteRecord(streamID2, array2, nmiss);
diff --git a/src/Trend.c b/src/Trend.c
index b143ef3..98be674 100644
--- a/src/Trend.c
+++ b/src/Trend.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -30,72 +30,62 @@
 
 void *Trend(void *argument)
 {
-  int gridsize;
   int vdate = 0, vtime = 0;
-  int nrecs, nrecords;
-  int gridID, varID, levelID, recID;
-  int tsID;
-  int i, w;
-  int streamID1, streamID2, streamID3;
-  int vlistID1, vlistID2, taxisID1, taxisID2;
+  int varID, levelID;
   int nmiss;
-  int nvars;
-  int *recVarID, *recLevelID;
-  int nwork = 5;
-  double zj;
+  int nrecs;
   double temp1, temp2;
-  double missval, missval1, missval2;
-  field_t **work[5];
-  field_t field1, field2;
+  enum {nwork = 5};
+  field_type **work[5];
 
   cdoInitialize(argument);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
   vlistDefNtsteps(vlistID2, 1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  nvars    = vlistNvars(vlistID1);
-  nrecords = vlistNrecs(vlistID1);
+  int nvars    = vlistNvars(vlistID1);
+  int nrecords = vlistNrecs(vlistID1);
 
   for ( varID = 0; varID < nvars; varID++ )
-    vlistDefVarDatatype(vlistID2, varID, DATATYPE_FLT64);
+    vlistDefVarDatatype(vlistID2, varID, CDI_DATATYPE_FLT64);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
-  streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
   streamDefVlist(streamID3, vlistID2);
 
-  recVarID   = (int*) Malloc(nrecords*sizeof(int));
-  recLevelID = (int*) Malloc(nrecords*sizeof(int));
+  int *recVarID   = (int*) Malloc(nrecords*sizeof(int));
+  int *recLevelID = (int*) Malloc(nrecords*sizeof(int));
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
 
+  field_type field1, field2;
   field_init(&field1);
   field_init(&field2);
-
   field1.ptr = (double*) Malloc(gridsize*sizeof(double));
   field2.ptr = (double*) Malloc(gridsize*sizeof(double));
 
-  for ( w = 0; w < nwork; w++ )
+  for ( int w = 0; w < nwork; w++ )
     work[w] = field_calloc(vlistID1, FIELD_PTR);
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       vdate = taxisInqVdate(taxisID1);
       vtime = taxisInqVtime(taxisID1);
 
-      zj = tsID;
+      double zj = (double)tsID;
       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -107,11 +97,11 @@ void *Trend(void *argument)
 
 	  streamReadRecord(streamID1, field1.ptr, &nmiss);
 
-	  missval  = vlistInqVarMissval(vlistID1, varID);
-	  gridID   = vlistInqVarGrid(vlistID1, varID);
-	  gridsize = gridInqSize(gridID);
+	  double missval  = vlistInqVarMissval(vlistID1, varID);
+	  int gridID   = vlistInqVarGrid(vlistID1, varID);
+	  int gridsize = gridInqSize(gridID);
 
-	  for ( i = 0; i < gridsize; i++ )
+	  for ( int i = 0; i < gridsize; i++ )
 	    if ( !DBL_IS_EQUAL(field1.ptr[i], missval) )
 	      {
 		work[0][varID][levelID].ptr[i] += zj;
@@ -131,19 +121,19 @@ void *Trend(void *argument)
   streamDefTimestep(streamID2, 0);
   streamDefTimestep(streamID3, 0);
 
-  for ( recID = 0; recID < nrecords; recID++ )
+  for ( int recID = 0; recID < nrecords; recID++ )
     {
       varID   = recVarID[recID];
       levelID = recLevelID[recID];
 
-      missval  = vlistInqVarMissval(vlistID1, varID);
-      gridID   = vlistInqVarGrid(vlistID1, varID);
-      gridsize = gridInqSize(gridID);
+      double missval  = vlistInqVarMissval(vlistID1, varID);
+      int gridID   = vlistInqVarGrid(vlistID1, varID);
+      int gridsize = gridInqSize(gridID);
 
-      missval1  = missval;
-      missval2  = missval;
+      double missval1  = missval;
+      double missval2  = missval;
 
-      for ( i = 0; i < gridsize; i++ )
+      for ( int i = 0; i < gridsize; i++ )
 	{
 	  temp1 = SUBMN(work[2][varID][levelID].ptr[i],
 		      DIVMN( MULMN(work[0][varID][levelID].ptr[i], work[3][varID][levelID].ptr[i]), work[4][varID][levelID].ptr[i]));
@@ -156,14 +146,14 @@ void *Trend(void *argument)
 	}
 
       nmiss = 0;
-      for ( i = 0; i < gridsize; i++ )
+      for ( int i = 0; i < gridsize; i++ )
 	if ( DBL_IS_EQUAL(field1.ptr[i], missval) ) nmiss++;
 
       streamDefRecord(streamID2, varID, levelID);
       streamWriteRecord(streamID2, field1.ptr, nmiss);
 
       nmiss = 0;
-      for ( i = 0; i < gridsize; i++ )
+      for ( int i = 0; i < gridsize; i++ )
 	if ( DBL_IS_EQUAL(field2.ptr[i], missval) ) nmiss++;
 
       streamDefRecord(streamID3, varID, levelID);
@@ -171,7 +161,7 @@ void *Trend(void *argument)
     }
 
 
-  for ( w = 0; w < nwork; w++ ) field_free(work[w], vlistID1);
+  for ( int w = 0; w < nwork; w++ ) field_free(work[w], vlistID1);
 
   if ( field1.ptr ) Free(field1.ptr);
   if ( field2.ptr ) Free(field2.ptr);
diff --git a/src/Trms.c b/src/Trms.c
index 8c25e67..2784429 100644
--- a/src/Trms.c
+++ b/src/Trms.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -28,7 +28,7 @@
 #include "grid.h"
 
 
-void trms(field_t field1, field_t field2, double *dp, field_t *field3)
+void trms(field_type field1, field_type field2, double *dp, field_type *field3)
 {
   int i, k, nlev, len, rnmiss = 0;
   int    zaxis    = field1.zaxis;
@@ -65,46 +65,31 @@ void trms(field_t field1, field_t field2, double *dp, field_t *field3)
 
 void *Trms(void *argument)
 {
-  int streamID1, streamID2, streamID3;
-  int vlistID1, vlistID2, vlistID3;
   int gridID1, gridID3, lastgrid = -1;
-  int wstatus = FALSE;
   int code = 0, oldcode = 0;
   int zaxisID;
-  int index, ngrids, nzaxis;
-  int recID, nrecs;
-  int nvars, nlevel;
-  int gridsize;
-  int i, k;
+  int nrecs;
   int nmiss;
-  int tsID, varID, levelID;
-  int lim;
+  int varID, levelID;
   int pcode = 152, pvarID = -1;
-  int needWeights = FALSE;
   long offset;
   size_t vctsize = 0;
-  const double *vct, *va = NULL, *vb = NULL;
-  double dp1, dp2;
-  double *dp;
+  const double *va = NULL, *vb = NULL;
   double *single;
-  double **vardata1 = NULL, **vardata2 = NULL;
-  double slon, slat;
   double sglval;
-  field_t field1, field2, field3;
-  int taxisID1, taxisID3;
 
   cdoInitialize(argument);
 
-  needWeights = TRUE;
+  bool needWeights = true;
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
-  streamID2 = streamOpenRead(cdoStreamName(1));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID2 = streamOpenRead(cdoStreamName(1));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = streamInqVlist(streamID2);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = streamInqVlist(streamID2);
 
-  slon = 0;
-  slat = 0;
+  double slon = 0;
+  double slat = 0;
   gridID3 = gridCreate(GRID_LONLAT, 1);
   gridDefXsize(gridID3, 1);
   gridDefYsize(gridID3, 1);
@@ -112,7 +97,7 @@ void *Trms(void *argument)
   gridDefYvals(gridID3, &slat);
 
   vlistClearFlag(vlistID1);
-  nvars    = vlistNvars(vlistID1);
+  int nvars = vlistNvars(vlistID1);
   for ( varID = 0; varID < nvars; varID++ )
     {
       if ( vlistInqVarCode(vlistID1, varID) == pcode )
@@ -123,15 +108,15 @@ void *Trms(void *argument)
 
   if ( pvarID == -1 ) cdoAbort("pressure variable missing!");
 
-  vlistID3 = vlistCreate();
+  int vlistID3 = vlistCreate();
   vlistCopyFlag(vlistID3, vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID3 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID3 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID3, taxisID3);
 
-  ngrids = vlistNgrids(vlistID1);
-  index = 0;
+  int ngrids = vlistNgrids(vlistID1);
+  int index = 0;
   gridID1 = vlistGrid(vlistID1, index);
   
   if ( needWeights &&
@@ -142,14 +127,14 @@ void *Trms(void *argument)
   vlistChangeGridIndex(vlistID3, index, gridID3);
   if ( ngrids > 1 ) cdoAbort("Too many different grids!");
 
-  nzaxis = vlistNzaxis(vlistID1);
+  int nzaxis = vlistNzaxis(vlistID1);
   for ( index = 0; index < nzaxis; index++ )
     {
       zaxisID = vlistZaxis(vlistID1, index);
       if ( zaxisInqType(zaxisID) == ZAXIS_HYBRID )
 	{
 	  vctsize = zaxisInqVctSize(zaxisID);
-	  vct     = zaxisInqVctPtr(zaxisID);
+	  const double *vct = zaxisInqVctPtr(zaxisID);
 	  va = vct;
 	  vb = vct + vctsize/2;
 	  /*
@@ -166,16 +151,16 @@ void *Trms(void *argument)
 
   if ( vctsize == 0 ) cdoAbort("VCT missing!");
 
-  streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
+  int streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
 
   streamDefVlist(streamID3, vlistID3);
 
-  vardata1 = (double**) Malloc(nvars*sizeof(double*));
-  vardata2 = (double**) Malloc(nvars*sizeof(double*));
+  double **vardata1 = (double**) Malloc(nvars*sizeof(double*));
+  double **vardata2 = (double**) Malloc(nvars*sizeof(double*));
 
-  gridsize = gridInqSize(vlistInqVarGrid(vlistID1, pvarID));
-  nlevel   = vctsize/2 - 1;
-  dp = (double*) Malloc(gridsize*nlevel*sizeof(double));
+  int gridsize = gridInqSize(vlistInqVarGrid(vlistID1, pvarID));
+  int nlevel   = vctsize/2 - 1;
+  double *dp = (double*) Malloc(gridsize*nlevel*sizeof(double));
 
   for ( varID = 0; varID < nvars; varID++ )
     {
@@ -185,11 +170,12 @@ void *Trms(void *argument)
       vardata2[varID] = (double*) Malloc(gridsize*nlevel*sizeof(double));
     }
 
+  field_type field1, field2, field3;
   field_init(&field1);
   field_init(&field2);
   field_init(&field3);
 
-  lim = vlistGridsizeMax(vlistID1);
+  int lim = vlistGridsizeMax(vlistID1);
   field1.weight = NULL;
   if ( needWeights )
     field1.weight = (double*) Malloc(lim*sizeof(double));
@@ -199,7 +185,7 @@ void *Trms(void *argument)
   field3.ptr  = &sglval;
   field3.grid = gridID3;
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       nrecs = streamInqTimestep(streamID2, tsID);
@@ -208,7 +194,7 @@ void *Trms(void *argument)
 
       streamDefTimestep(streamID3, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -228,20 +214,20 @@ void *Trms(void *argument)
 	}
 
       gridsize = gridInqSize(vlistInqVarGrid(vlistID1, pvarID));
-      for ( i = 0; i < gridsize; i++ )
+      for ( int i = 0; i < gridsize; i++ )
 	{
 	  vardata1[pvarID][i] = exp(vardata1[pvarID][i]);
 	  vardata2[pvarID][i] = exp(vardata2[pvarID][i]);
 	}
 
       nlevel = vctsize/2 - 1;
-      for ( k = 0; k < nlevel; k++ )
+      for ( int k = 0; k < nlevel; k++ )
 	{
 	  offset = gridsize*k;
-	  for ( i = 0; i < gridsize; i++ )
+	  for ( int i = 0; i < gridsize; i++ )
 	    {
-	      dp1 = (va[k+1] + vb[k+1]*vardata1[pvarID][i]) - (va[k] + vb[k]*vardata1[pvarID][i]);
-	      dp2 = (va[k+1] + vb[k+1]*vardata2[pvarID][i]) - (va[k] + vb[k]*vardata2[pvarID][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]);
 
 	      dp[offset+i] = 0.5 * (dp1 + dp2);
 	    }
@@ -255,6 +241,7 @@ void *Trms(void *argument)
 	  field1.zaxis   = vlistInqVarZaxis(vlistID1, varID);
 	  field1.grid    = vlistInqVarGrid(vlistID1, varID);
 	  field2.grid    = vlistInqVarGrid(vlistID2, varID);
+          bool wstatus = false;
 	  if ( needWeights && field1.grid != lastgrid )
 	    {
 	      lastgrid = field1.grid;
diff --git a/src/Tstepcount.c b/src/Tstepcount.c
index 89acbae..0391c74 100644
--- a/src/Tstepcount.c
+++ b/src/Tstepcount.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -36,7 +36,7 @@ double tstepcount(long nts, double missval1, double *array1, double refval)
   long j;
   long n = 0;
 
-  if ( DBL_IS_EQUAL(refval, missval1) ) return (missval1);
+  if ( DBL_IS_EQUAL(refval, missval1) ) return missval1;
 
   for ( j = 0; j < nts; j++ )
     {
@@ -45,9 +45,9 @@ double tstepcount(long nts, double missval1, double *array1, double refval)
     }
 
   if ( j == nts )
-    return (missval1);
+    return missval1;
   else
-    return ((double) n);
+    return (double) n;
 }
 
 
@@ -55,57 +55,51 @@ void *Tstepcount(void *argument)
 {
   int gridsize;
   int nrecs;
-  int gridID, varID, levelID, recID;
-  int tsID;
-  int i;
-  int nts;
+  int gridID, varID, levelID;
   int nalloc = 0;
-  int streamID1, streamID2;
-  int vlistID1, vlistID2, taxisID1, taxisID2;
   int nmiss;
-  int nvars, nlevel;
+  int nlevel;
   int vdate = 0, vtime = 0;
   double missval;
   double refval = 0;
-  field_t ***vars = NULL;
+  field_type ***vars = NULL;
   typedef struct
   {
     double *array1;
   } memory_t;
-  memory_t *mem = NULL;
 
   cdoInitialize(argument);
 
   if ( operatorArgc() == 1 ) refval = parameter2double(operatorArgv()[0]);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
   vlistDefNtsteps(vlistID2, 1);
 
-  nvars = vlistNvars(vlistID1);
+  int nvars = vlistNvars(vlistID1);
   for ( varID = 0; varID < nvars; varID++ )
     {
       vlistDefVarUnits(vlistID2, varID, "steps");
     }
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       if ( tsID >= nalloc )
 	{
 	  nalloc += NALLOC_INC;
-	  vars  = (field_t ***) Realloc(vars, nalloc*sizeof(field_t **));
+	  vars  = (field_type ***) Realloc(vars, nalloc*sizeof(field_type **));
 	}
 
       vdate = taxisInqVdate(taxisID1);
@@ -113,7 +107,7 @@ void *Tstepcount(void *argument)
 
       vars[tsID] = field_malloc(vlistID1, FIELD_NONE);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  gridID   = vlistInqVarGrid(vlistID1, varID);
@@ -126,10 +120,10 @@ void *Tstepcount(void *argument)
       tsID++;
     }
 
-  nts = tsID;
+  int nts = tsID;
 
-  mem = (memory_t*) Malloc(ompNumThreads*sizeof(memory_t));
-  for ( i = 0; i < ompNumThreads; i++ )
+  memory_t *mem = (memory_t*) Malloc(ompNumThreads*sizeof(memory_t));
+  for ( int i = 0; i < ompNumThreads; i++ )
     {
       mem[i].array1 = (double*) Malloc(nts*sizeof(double));
     }
@@ -158,10 +152,8 @@ void *Tstepcount(void *argument)
 	}
     }
 
-  for ( i = 0; i < ompNumThreads; i++ )
-    {
-      Free(mem[i].array1);
-    }
+  for ( int i = 0; i < ompNumThreads; i++ )
+    Free(mem[i].array1);
   Free(mem);
 
   taxisDefVdate(taxisID2, vdate);
@@ -180,7 +172,7 @@ void *Tstepcount(void *argument)
 	  streamDefRecord(streamID2, varID, levelID);
 
 	  nmiss = 0;
-	  for ( i = 0; i < gridsize; i++ )
+	  for ( int i = 0; i < gridsize; i++ )
 	    if ( DBL_IS_EQUAL(vars[0][varID][levelID].ptr[i], missval) ) nmiss++;
 
 	  streamWriteRecord(streamID2, vars[0][varID][levelID].ptr, nmiss);
@@ -189,7 +181,7 @@ void *Tstepcount(void *argument)
 
   for ( tsID = 0; tsID < nts; tsID++ ) field_free(vars[tsID], vlistID1);
 
-  if ( vars  ) Free(vars);
+  if ( vars ) Free(vars);
 
   streamClose(streamID2);
   streamClose(streamID1);
diff --git a/src/Vargen.c b/src/Vargen.c
index 998f04c..3e4fa29 100644
--- a/src/Vargen.c
+++ b/src/Vargen.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -33,7 +33,7 @@
 #include "cdo.h"
 #include "cdo_int.h"
 #include "pstream.h"
-#include "list.h"
+#include "listarray.h"
 #include "grid.h"
 #include "constants.h"
 #include "stdnametable.h"
@@ -134,7 +134,7 @@ 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)
 {
-  if ( !(gridInqType(gridID) == GRID_LONLAT && !gridIsRotated(gridID)) )
+  if ( gridInqType(gridID) != GRID_LONLAT )
     cdoAbort("Internal error, wrong grid type!");
 
   int nxvals = gridInqXsize(gridID);
@@ -221,7 +221,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)
 {
-  if ( gridInqType(gridID) == GRID_LONLAT && !gridIsRotated(gridID) )
+  if ( gridInqType(gridID) == GRID_LONLAT )
     remap_nn_reg2d_reg2d(nx, ny, data, gridID, array);
   else
     remap_nn_reg2d_nonreg2d(nx, ny, data, gridID, array);
@@ -234,10 +234,8 @@ void *Vargen(void *argument)
 {
   int ntimesteps, nlevels = 1;
   int varID, varID2 = -1, levelID;
-  int i;
   int gridID = -1, gridIDdata = -1, zaxisID;
-  int vdate, vtime;
-  double rval, rstart = 0, rstop = 0, rinc = 0;
+  double rstart = 0, rstop = 0, rinc = 0;
   double rconst = 0;
   double *levels = NULL;
   double lon[NLON], lat[NLAT];
@@ -326,14 +324,14 @@ void *Vargen(void *argument)
   else if ( operatorID == STDATM )
     {
       double lon = 0, lat = 0;
-      LIST *flist = listNew(FLT_LIST);
+      lista_t *flista = lista_new(FLT_LISTA);
 
       operatorInputArg(cdoOperatorEnter(operatorID));
-      nlevels = args2fltlist(operatorArgc(), operatorArgv(), flist);
-      levels  = (double *) listArrayPtr(flist);
-      //listDelete(flist);
+      nlevels = args2flt_lista(operatorArgc(), operatorArgv(), flista);
+      levels  = (double *) lista_dataptr(flista);
+      //lista_destroy(flista);
 
-      if ( cdoVerbose ) for ( i = 0; i < nlevels; ++i ) printf("levels %d: %g\n", i, levels[i]);
+      if ( cdoVerbose ) for ( int i = 0; i < nlevels; ++i ) printf("levels %d: %g\n", i, levels[i]);
 
       gridID = gridCreate(GRID_LONLAT, 1);
       gridDefXsize(gridID, 1);
@@ -371,7 +369,7 @@ void *Vargen(void *argument)
     varID2 = vlistDefVar(vlistID, gridID, zaxisID, TSTEP_CONSTANT);
 
   if ( operatorID == MASK )
-    vlistDefVarDatatype(vlistID, varID, DATATYPE_INT8);
+    vlistDefVarDatatype(vlistID, varID, CDI_DATATYPE_INT8);
 
   if ( operatorID == STDATM )
     {
@@ -429,9 +427,9 @@ void *Vargen(void *argument)
 
   for ( int tsID = 0; tsID < ntimesteps; tsID++ )
     {
-      rval  = rstart + rinc*tsID;
-      vdate = julday_to_date(CALENDAR_PROLEPTIC, julday + tsID);
-      vtime = 0;
+      double rval  = rstart + rinc*tsID;
+      int vdate = julday_to_date(CALENDAR_PROLEPTIC, julday + tsID);
+      int vtime = 0;
       taxisDefVdate(taxisID, vdate);
       taxisDefVtime(taxisID, vtime);
       streamDefTimestep(streamID, tsID);
@@ -445,7 +443,7 @@ void *Vargen(void *argument)
 
               if ( operatorID == RANDOM )
                 {
-                  for ( i = 0; i < gridsize; i++ )
+                  for ( int i = 0; i < gridsize; i++ )
                     array[i] = ((double)rand())/((double)RAND_MAX);
                 }
               else if ( operatorID == SINCOS || operatorID == COSHILL )
@@ -477,12 +475,12 @@ void *Vargen(void *argument)
                   
 		  if ( operatorID == SINCOS )
 		    {
-		      for ( i = 0; i < gridsize; i++ )
+		      for ( int i = 0; i < gridsize; i++ )
 			array[i] = cos(1.0 * xvals[i]) * sin(2.0 * yvals[i]);
 		    }
 		  else if ( operatorID == COSHILL )
 		    {		     
-		      for ( i = 0; i < gridsize; i++ )
+		      for ( int i = 0; i < gridsize; i++ )
 			array[i] = 2 - cos(acos(cos(xvals[i]) * cos(yvals[i]))/1.2);
 		    }
 
@@ -491,13 +489,13 @@ void *Vargen(void *argument)
 		}
               else if ( operatorID == CONST )
                 {
-                  for ( i = 0; i < gridsize; i++ )
+                  for ( int i = 0; i < gridsize; i++ )
                     array[i] = rconst;
                 }
               else if ( operatorID == TOPO )
                 {
 #if defined(ENABLE_DATA)
-                  for ( i = 0; i < datasize; i++ )
+                  for ( int i = 0; i < datasize; i++ )
                     data[i] = etopo[i]/etopo_scale - etopo_offset;
 #else
                   cdoAbort("Operator support disabled!");
@@ -506,7 +504,7 @@ void *Vargen(void *argument)
               else if ( operatorID == TEMP )
                 {
 #if defined(ENABLE_DATA)
-                  for ( i = 0; i < datasize; i++ )
+                  for ( int i = 0; i < datasize; i++ )
                     data[i] = temp[i]/temp_scale - temp_offset;
 #else
                   cdoAbort("Operator support disabled!");
@@ -515,7 +513,7 @@ void *Vargen(void *argument)
               else if ( operatorID == MASK )
                 {
 #if defined(ENABLE_DATA)
-                  for ( i = 0; i < datasize; i++ )
+                  for ( int i = 0; i < datasize; i++ )
                     data[i] = mask[i]/mask_scale - mask_offset;
 #else
                   cdoAbort("Operator support disabled!");
diff --git a/src/Varrms.c b/src/Varrms.c
index c36b6fc..22986d5 100644
--- a/src/Varrms.c
+++ b/src/Varrms.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -30,60 +30,50 @@
 
 void *Varrms(void *argument)
 {
-  int streamID1, streamID2, streamID3;
-  int vlistID1, vlistID2, vlistID3;
-  int gridID1, gridID3, lastgrid = -1;
+  int lastgrid = -1;
   int wstatus = FALSE;
-  int code = 0, oldcode = 0;
-  int index, ngrids;
-  int recID, nrecs;
-  int nvars, nlevel;
+  int oldcode = 0;
+  int nrecs;
   int gridsize;
   int nmiss;
-  int tsID, varID, levelID;
-  int lim;
-  int needWeights = FALSE;
+  int varID, levelID;
   long offset;
   double *single;
-  double **vardata1 = NULL, **vardata2 = NULL;
-  double slon, slat;
   double sglval;
-  field_t field1, field2, field3;
-  int taxisID1, taxisID3;
 
   cdoInitialize(argument);
 
-  needWeights = TRUE;
+  bool needWeights = true;
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
-  streamID2 = streamOpenRead(cdoStreamName(1));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID2 = streamOpenRead(cdoStreamName(1));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = streamInqVlist(streamID2);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = streamInqVlist(streamID2);
 
-  slon = 0;
-  slat = 0;
-  gridID3 = gridCreate(GRID_LONLAT, 1);
+  double slon = 0;
+  double slat = 0;
+  int gridID3 = gridCreate(GRID_LONLAT, 1);
   gridDefXsize(gridID3, 1);
   gridDefYsize(gridID3, 1);
   gridDefXvals(gridID3, &slon);
   gridDefYvals(gridID3, &slat);
 
   vlistClearFlag(vlistID1);
-  nvars    = vlistNvars(vlistID1);
+  int nvars    = vlistNvars(vlistID1);
   for ( varID = 0; varID < nvars; varID++ )
     vlistDefFlag(vlistID1, varID, 0, TRUE);
 
-  vlistID3 = vlistCreate();
+  int vlistID3 = vlistCreate();
   vlistCopyFlag(vlistID3, vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID3 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID3 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID3, taxisID3);
 
-  ngrids = vlistNgrids(vlistID1);
-  index = 0;
-  gridID1 = vlistGrid(vlistID1, index);
+  int ngrids = vlistNgrids(vlistID1);
+  int index = 0;
+  int gridID1 = vlistGrid(vlistID1, index);
   
   if ( needWeights &&
        gridInqType(gridID1) != GRID_LONLAT &&
@@ -93,26 +83,27 @@ void *Varrms(void *argument)
   vlistChangeGridIndex(vlistID3, index, gridID3);
   if ( ngrids > 1 ) cdoAbort("Too many different grids!");
 
-  streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
+  int streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
 
   streamDefVlist(streamID3, vlistID3);
 
-  vardata1 = (double**) Malloc(nvars*sizeof(double*));
-  vardata2 = (double**) Malloc(nvars*sizeof(double*));
+  double **vardata1 = (double**) Malloc(nvars*sizeof(double*));
+  double **vardata2 = (double**) Malloc(nvars*sizeof(double*));
 
   for ( varID = 0; varID < nvars; varID++ )
     {
-      gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
-      nlevel   = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
+      int gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
+      int nlevel   = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
       vardata1[varID] = (double*) Malloc(gridsize*nlevel*sizeof(double));
       vardata2[varID] = (double*) Malloc(gridsize*nlevel*sizeof(double));
     }
 
+  field_type field1, field2, field3;
   field_init(&field1);
   field_init(&field2);
   field_init(&field2);
 
-  lim = vlistGridsizeMax(vlistID1);
+  int lim = vlistGridsizeMax(vlistID1);
   field1.weight = NULL;
   if ( needWeights )
     field1.weight = (double*) Malloc(lim*sizeof(double));
@@ -122,7 +113,7 @@ void *Varrms(void *argument)
   field3.ptr  = &sglval;
   field3.grid = gridID3;
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       nrecs = streamInqTimestep(streamID2, tsID);
@@ -131,7 +122,7 @@ void *Varrms(void *argument)
 
       streamDefTimestep(streamID3, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -163,7 +154,7 @@ void *Varrms(void *argument)
 	      lastgrid = field1.grid;
 	      wstatus = gridWeights(field1.grid, field1.weight);
 	    }
-	  code = vlistInqVarCode(vlistID1, varID);
+	  int code = vlistInqVarCode(vlistID1, varID);
 	  if ( wstatus != 0 && tsID == 0 && code != oldcode )
 	    cdoWarning("Using constant area weights for code %d!", oldcode=code);
 
diff --git a/src/Verifygrid.c b/src/Verifygrid.c
index e85be53..77b9ace 100644
--- a/src/Verifygrid.c
+++ b/src/Verifygrid.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -28,8 +28,9 @@
 #include "time.h"
 
 /* Quicksort is called with a pointer to the array to be sorted and an integer indicating its length. */
-
-void quick_sort(double * array, int array_length) {
+static
+void quick_sort(double * array, int array_length)
+{
   int i, j;
   double p, temp;
   
@@ -52,8 +53,9 @@ void quick_sort(double * array, int array_length) {
 }
 
 /* Quicksort is called with a pointer to the array of center points to be sorted and an integer indicating its length. It sorts the array by its longitude coordinates */
-
-void quick_sort_by_lon(double * array, int array_length) {
+static
+void quick_sort_by_lon(double * array, int array_length)
+{
   int i, j;
   double p, temp_lon, temp_lat;
   
@@ -89,9 +91,9 @@ void quick_sort_by_lon(double * array, int array_length) {
 }
 
 /* This uses quicksort to sort the latitude coordinates in a subarray of all coordinates. */
-
-void quick_sort_of_subarray_by_lat(double * array, int subarray_start, int subarray_end){
-
+static
+void quick_sort_of_subarray_by_lat(double * array, int subarray_start, int subarray_end)
+{
   int subarray_length = (subarray_end - subarray_start) / 2 + 1;     
   double subarray[subarray_length];
   int subarray_index = 0;
@@ -112,11 +114,9 @@ void quick_sort_of_subarray_by_lat(double * array, int subarray_start, int subar
 }
 
 
-
-
 static
-double determinant(double matrix[3][3]){
-  
+double determinant(double matrix[3][3])
+{  
   /* Calculates the determinant for a 3 x 3 matrix. */
   
   return matrix[0][0] * matrix[1][1] * matrix[2][2] 
@@ -128,28 +128,25 @@ double determinant(double matrix[3][3]){
 }
 
 static
-void find_unit_normal(double a[3], double b[3], double c[3], double * unit_normal){
-  
+void find_unit_normal(double a[3], double b[3], double c[3], double * unit_normal)
+{  
   /* Calculates the unit normal for a plane defined on three points a, b, c in Euclidean space. */
 
   double matrix_for_x[3][3] = {{1, a[1], a[2]},
 			       {1, b[1], b[2]},
-			       {1, c[1], c[2]}			 
-  };
+			       {1, c[1], c[2]}};
 
   double x = determinant(matrix_for_x);
 
   double matrix_for_y[3][3] = {{a[0], 1, a[2]},
 			       {b[0], 1, b[2]},
-			       {c[0], 1, c[2]}
-  };
+			       {c[0], 1, c[2]}};
   
   double y = determinant(matrix_for_y);
   
   double matrix_for_z[3][3] = {{a[0], a[1], 1},
 			       {b[0], b[1], 1},
-			       {c[0], c[1], 1}
-  };
+			       {c[0], c[1], 1}};
 
   double z = determinant(matrix_for_z);
 
@@ -158,7 +155,6 @@ void find_unit_normal(double a[3], double b[3], double c[3], double * unit_norma
   unit_normal[0] = x / magnitude;
   unit_normal[1] = y / magnitude;
   unit_normal[2] = z / magnitude;
-
 }
 
 static
@@ -168,9 +164,7 @@ int no_of_duplicates_in_this_list_of_vertices(double cell_corners[], int array_l
   
   /* Ensure that the lenght of the array is a multiple of 3. */
 
-  if ((array_length % 3) != 0){
-    return -1;
-  }
+  if ( (array_length % 3) != 0 ) return -1;
 
   /* A brute force search for duplicate Cartesian coordinates. */
 
@@ -204,8 +198,8 @@ double is_point_left_of_edge(double point_on_line_1[2], double point_on_line_2[2
 }
 
 static
-int winding_numbers_algorithm(double cell_corners[], int number_corners, double point[]){
-  
+int winding_numbers_algorithm(double cell_corners[], int number_corners, double point[])
+{  
   /* 
      Computes whether a point is inside the bounds of a cell. This is the solution to the point in polygon problem.
      Returns 0 if the point is outside, returns 1 if the point is inside the cell.
@@ -221,9 +215,7 @@ int winding_numbers_algorithm(double cell_corners[], int number_corners, double
 	double point_on_edge_1[2] = {cell_corners[i * 2 + 0], cell_corners[i * 2 + 1]};
 	double point_on_edge_2[2] = {cell_corners[(i + 1) * 2 + 0], cell_corners[(i + 1) * 2 + 1]};
 
-	if (is_point_left_of_edge(point_on_edge_1, point_on_edge_2, point) > 0){
-	  winding_number++;
-	}
+	if ( is_point_left_of_edge(point_on_edge_1, point_on_edge_2, point) > 0) winding_number++;
       }       
     }
     else { 
@@ -232,9 +224,7 @@ int winding_numbers_algorithm(double cell_corners[], int number_corners, double
 	double point_on_edge_1[2] = {cell_corners[i * 2 + 0], cell_corners[i * 2 + 1]};
 	double point_on_edge_2[2] = {cell_corners[(i + 1) * 2 + 0], cell_corners[(i + 1) * 2 + 1]};
 
-	if (is_point_left_of_edge(point_on_edge_1, point_on_edge_2, point) < 0){
-	  winding_number--;
-	}
+	if ( is_point_left_of_edge(point_on_edge_1, point_on_edge_2, point) < 0 ) winding_number--;
       }
     }
   }
@@ -250,33 +240,31 @@ double sign(double x)
 }
 
 static
-bool is_simple_polygon_convex(double cell_corners[], int number_corners){
-
+bool is_simple_polygon_convex(double cell_corners[], int number_corners)
+{
    /* Tests in which direction the polygon winds when walking along its edges. Does so for all edges of the polygon. */
 
   double direction = 0;
   
-  for ( int i = 0; i < number_corners - 2; i++ ){
-    
-    double turns_to = (cell_corners[i * 2 + 0] - cell_corners[(i + 1) * 2 + 0]) 
-      * (cell_corners[(i + 1) * 2 + 1] - cell_corners[(i + 2) * 2 + 1]) - (cell_corners[i * 2 + 1] - cell_corners[(i + 1) * 2 + 1]) 
-      * (cell_corners[(i + 1) * 2 + 0] - cell_corners[(i + 2) * 2 + 0]); 
+  for ( int i = 0; i < number_corners - 2; i++ )
+    {
+      double turns_to = (cell_corners[i * 2 + 0] - cell_corners[(i + 1) * 2 + 0]) 
+        * (cell_corners[(i + 1) * 2 + 1] - cell_corners[(i + 2) * 2 + 1]) - (cell_corners[i * 2 + 1] - cell_corners[(i + 1) * 2 + 1]) 
+        * (cell_corners[(i + 1) * 2 + 0] - cell_corners[(i + 2) * 2 + 0]); 
 
-    /* In the first iteration the direction of winding of the entire polygon is set. Better not be 0.*/
+      /* In the first iteration the direction of winding of the entire polygon is set. Better not be 0.*/
 
-    if (i == 1){
-      direction = turns_to;
-    }
+      if ( i == 1 ) direction = turns_to;
 
-    if ( IS_NOT_EQUAL(sign(direction), sign(turns_to)) ){
-      if ( IS_NOT_EQUAL(direction, 0) ){
-	return false;
-      }
+      if ( IS_NOT_EQUAL(sign(direction), sign(turns_to)) )
+        {
+          if ( IS_NOT_EQUAL(direction, 0) ) return false;
+        }
+      else
+        {
+          direction = turns_to;
+        }      
     }
-    else{
-      direction = turns_to;
-    }      
-  }
 
   return true;
 }
@@ -289,10 +277,8 @@ double calculate_the_polygon_area(double cell_corners[], int number_corners)
   
   double twice_the_polygon_area = 0;
 
-  for (int i = 0; i < number_corners - 1; i++)
-    {
-      twice_the_polygon_area += (cell_corners[i * 2 + 0] * cell_corners[(i + 1) * 2 + 1]) - (cell_corners[(i + 1) * 2 + 0] * cell_corners[i * 2 + 1]); 
-    }
+  for ( int i = 0; i < number_corners - 1; i++ )
+    twice_the_polygon_area += (cell_corners[i * 2 + 0] * cell_corners[(i + 1) * 2 + 1]) - (cell_corners[(i + 1) * 2 + 0] * cell_corners[i * 2 + 1]); 
   
   return twice_the_polygon_area / 2;
 }
@@ -309,8 +295,8 @@ bool are_polygon_vertices_arranged_in_clockwise_order(double cell_area)
 }
 
 static
-void verify_grid(int gridtype, int gridsize, int gridno, int ngrids, int ncorner, double *grid_center_lon, double *grid_center_lat, double *grid_corner_lon, double *grid_corner_lat){
-
+void verify_grid(int gridtype, int gridsize, int gridno, int ngrids, int ncorner, double *grid_center_lon, double *grid_center_lat, double *grid_corner_lon, double *grid_corner_lat)
+{
   /* 
      First, this function performs the following test:
 
@@ -324,8 +310,8 @@ void verify_grid(int gridtype, int gridsize, int gridno, int ngrids, int ncorner
      The results of the tests are printed on stdout.
   */
   
-  double center_point_in_Euclidean_space[3];
-  double cell_corners_in_Euclidean_space_open_cell[ncorner * 3];
+  double center_point_xyz[3];
+  double cell_corners_xyz_open_cell[ncorner * 3];
   
   double corner_coordinates[3];
   double second_corner_coordinates[3];
@@ -333,27 +319,15 @@ void verify_grid(int gridtype, int gridsize, int gridno, int ngrids, int ncorner
   double surface_normal_of_the_cell[3];
   double center_point_plane_projection[2];
 
-  int cell_no = 0;
-  int corner_no = 0;
-  int actual_number_of_corners = 0;
   int no_of_cells_with_duplicates = 0;
   int no_convex_cells = 0;
   int no_clockwise_cells = 0;
   int no_counterclockwise_cells = 0;
-  int winding_number = 0;
   int no_of_cells_with_center_points_out_of_bounds = 0;
   int coordinate_to_ignore = 0;
-  int subarray_start = 0;
-  int subarray_end = 0;
   int no_unique_center_points = 1;
-
-  double abs_x = 0; 
-  double abs_y = 0; 
-  double abs_z = 0;
-  double polygon_area = 0;
   
-  double * p_surface_normal_of_the_cell;
-  p_surface_normal_of_the_cell = &surface_normal_of_the_cell[0];
+  double *p_surface_normal_of_the_cell = &surface_normal_of_the_cell[0];
 
   int no_cells_with_a_specific_no_of_corners[ncorner];
 
@@ -368,14 +342,13 @@ void verify_grid(int gridtype, int gridsize, int gridno, int ngrids, int ncorner
 
   /* For performing the first test, an array of all center point coordinates is built. */
 
-  double * center_point_array = (double *)Malloc(gridsize * 2 * sizeof(double));
-  
-  for(cell_no = 0; cell_no < gridsize; cell_no++){
-    center_point_array[cell_no * 2 + 0] = grid_center_lon[cell_no];
-    center_point_array[cell_no * 2 + 1] = grid_center_lat[cell_no];
-  }
-
+  double *center_point_array = (double *)Malloc(gridsize * 2 * sizeof(double));
   
+  for ( int cell_no = 0; cell_no < gridsize; cell_no++ )
+    {
+      center_point_array[cell_no * 2 + 0] = grid_center_lon[cell_no];
+      center_point_array[cell_no * 2 + 1] = grid_center_lat[cell_no];
+    }
 
   /* The cell center points are sorted by their first coordinate (lon) with quicksort. */
 
@@ -383,35 +356,43 @@ void verify_grid(int gridtype, int gridsize, int gridno, int ngrids, int ncorner
   
   /* Now the lat coordinates in subarrays that reflect equal lon coordinates are sorted with quicksort. */
 
-  for(cell_no = 0; cell_no < gridsize - 1; cell_no++){
+  int subarray_start = 0;
+  int subarray_end = 0;
 
-    if(cell_no == gridsize - 2){    
-      subarray_end = gridsize * 2 - 2;      
-      quick_sort_of_subarray_by_lat(center_point_array, subarray_start, subarray_end);
-    }
+  for ( int cell_no = 0; cell_no < gridsize - 1; cell_no++ )
+    {
+      if ( cell_no == gridsize - 2 )
+        {    
+          subarray_end = gridsize * 2 - 2;      
+          quick_sort_of_subarray_by_lat(center_point_array, subarray_start, subarray_end);
+        }
             
-    if(fabs(center_point_array[cell_no * 2 + 0] - center_point_array[(cell_no + 1)  * 2  + 0]) > 0.0001){     
-      subarray_end = cell_no * 2;    
-      if((subarray_end - subarray_start) > 1){	
-	quick_sort_of_subarray_by_lat(center_point_array, subarray_start, subarray_end);
-      }     
-      subarray_start = subarray_end + 2;  
-    }        
-  }
+      if ( fabs(center_point_array[cell_no * 2 + 0] - center_point_array[(cell_no + 1)  * 2  + 0]) > 0.0001 )
+        {     
+          subarray_end = cell_no * 2;    
+          if ( (subarray_end - subarray_start) > 1 )	
+            quick_sort_of_subarray_by_lat(center_point_array, subarray_start, subarray_end);
+
+          subarray_start = subarray_end + 2;  
+        }
+    }
 
   /* Now checking for the number of unique center point coordinates. */
 
-  for(cell_no = 0; cell_no < gridsize - 1; cell_no++){
-    if(fabs(center_point_array[cell_no * 2 + 0] - center_point_array[(cell_no + 1) * 2 + 0]) < 0.0001){
-      if(fabs(center_point_array[cell_no * 2 + 1] - center_point_array[(cell_no + 1) * 2 + 1]) < 0.0001){
-	continue;
-      } else {
-	no_unique_center_points += 1;
-      }
-    } else {
-      	no_unique_center_points += 1;
+  for ( int cell_no = 0; cell_no < gridsize - 1; cell_no++ )
+    {
+      if ( fabs(center_point_array[cell_no * 2 + 0] - center_point_array[(cell_no + 1) * 2 + 0]) < 0.0001 )
+        {
+          if ( fabs(center_point_array[cell_no * 2 + 1] - center_point_array[(cell_no + 1) * 2 + 1]) < 0.0001 )
+            continue;
+          else
+            no_unique_center_points += 1;
+        }
+      else
+        {
+          no_unique_center_points += 1;
+        }
     }
-  }
   
   Free(center_point_array);
 
@@ -419,159 +400,157 @@ void verify_grid(int gridtype, int gridsize, int gridno, int ngrids, int ncorner
      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 
   */
-  
 
-  for ( cell_no = 0; cell_no < gridsize; cell_no++ )
+  for ( int cell_no = 0; cell_no < gridsize; cell_no++ )
     {    
       /* Conversion of center point spherical coordinates to Cartesian coordinates. */
 
-      LLtoXYZ_deg(grid_center_lon[cell_no], grid_center_lat[cell_no], center_point_in_Euclidean_space);
+      LLtoXYZ_deg(grid_center_lon[cell_no], grid_center_lat[cell_no], center_point_xyz);
       
-      for (corner_no = 0; corner_no < ncorner; corner_no++)
+      for ( int corner_no = 0; corner_no < ncorner; corner_no++ )
 	{	  
 	  /* Conversion of corner spherical coordinates to Cartesian coordinates. */
 
 	  LLtoXYZ_deg(grid_corner_lon[cell_no * ncorner + corner_no], grid_corner_lat[cell_no * ncorner + corner_no], corner_coordinates);
 	  
 	  /* The components of the result vector are appended to the list of cell corner coordinates. */
-	  
-	  cell_corners_in_Euclidean_space_open_cell[corner_no * 3 + 0] = corner_coordinates[0];	  
-	  cell_corners_in_Euclidean_space_open_cell[corner_no * 3 + 1] = corner_coordinates[1];	  
-	  cell_corners_in_Euclidean_space_open_cell[corner_no * 3 + 2] = corner_coordinates[2];	  
+
+          int off = corner_no * 3;
+	  cell_corners_xyz_open_cell[off + 0] = corner_coordinates[0];	  
+	  cell_corners_xyz_open_cell[off + 1] = corner_coordinates[1];	  
+	  cell_corners_xyz_open_cell[off + 2] = corner_coordinates[2];	  
 	}
       
       /* 
-	 Not all cells have the same number of corners. The array, however, has ncorner * 3  values for each cell, where ncorner is the maximum number of corners. Unused values have been filled with the values of the final cell.
+	 Not all cells have the same number of corners. The array, however, has ncorner * 3  values for each cell, where ncorner is the maximum number of corners.
+         Unused values have been filled with the values of the final cell.
 	 The following identifies the surplus corners and gives the correct length of the cell.
       */
       
-      actual_number_of_corners = ncorner;
-
-      double *cell_corners = cell_corners_in_Euclidean_space_open_cell;
-      for (corner_no = ncorner - 1; corner_no > 0; corner_no--){
-	if ( IS_EQUAL(cell_corners[corner_no * 3 + 0], cell_corners[(corner_no - 1) * 3 + 0]) &&
-             IS_EQUAL(cell_corners[corner_no * 3 + 1], cell_corners[(corner_no - 1) * 3 + 1]) &&
-             IS_EQUAL(cell_corners[corner_no * 3 + 2], cell_corners[(corner_no - 1) * 3 + 2]) ){
-          actual_number_of_corners = actual_number_of_corners - 1;
-        } else {
-	  break;
-	}	
-      }                  
+      int actual_number_of_corners = ncorner;
+
+      for ( int corner_no = ncorner - 1; corner_no > 0; corner_no-- )
+        {
+          int off = corner_no * 3;
+          int off2 = (corner_no - 1) * 3;
+          if ( IS_EQUAL(cell_corners_xyz_open_cell[off + 0], cell_corners_xyz_open_cell[off2 + 0]) &&
+               IS_EQUAL(cell_corners_xyz_open_cell[off + 1], cell_corners_xyz_open_cell[off2 + 1]) &&
+               IS_EQUAL(cell_corners_xyz_open_cell[off + 2], cell_corners_xyz_open_cell[off2 + 2]) )
+            actual_number_of_corners = actual_number_of_corners - 1;
+          else
+            break;
+        }                  
 
       no_cells_with_a_specific_no_of_corners[actual_number_of_corners - 1] += 1;
       
       /* If there are less than three corners in the cell, it is unusable and considered degenerate. No area can be computed. */
       
-      if (actual_number_of_corners < 3){
-	if (cdoVerbose){
-	  fprintf(stdout,"Less than three vertices found in cell no %u. This cell is considered degenerate and will be omitted from further computation!\n", cell_no + 1);
-	}
-	continue;
-      }
+      if ( actual_number_of_corners < 3 )
+        {
+          if ( cdoVerbose )
+            fprintf(stdout,"Less than three vertices found in cell no %u. This cell is considered degenerate and will be omitted from further computation!\n", cell_no + 1);
+          
+          continue;
+        }
       
       /* 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[actual_number_of_corners];
-
-      for(int i = 0; i < actual_number_of_corners; i++){
-	marked_duplicate_indices[i] = 0;
-      }
+      for ( int i = 0; i < actual_number_of_corners; i++ ) marked_duplicate_indices[i] = 0;
 
       int no_duplicates = 0;
       
-      for (int i = 0; i < actual_number_of_corners * 3; i = i + 3){
-	for (int j = i + 3; j < actual_number_of_corners * 3; j = j + 3 ){
-	  if (fabs(cell_corners_in_Euclidean_space_open_cell[i + 0] - cell_corners_in_Euclidean_space_open_cell[j]) < 0.000001){
-	    if (fabs(cell_corners_in_Euclidean_space_open_cell[i + 1] - cell_corners_in_Euclidean_space_open_cell[j + 1]) < 0.000001){
-	      if (fabs(cell_corners_in_Euclidean_space_open_cell[i + 2] - cell_corners_in_Euclidean_space_open_cell[j + 2]) < 0.000001){
-		if (cdoVerbose){
-		  fprintf(stdout,"The duplicate vertex %f, %f, %f was found in cell no %u.\n", cell_corners_in_Euclidean_space_open_cell[j],  cell_corners_in_Euclidean_space_open_cell[j + 1],  cell_corners_in_Euclidean_space_open_cell[j + 2], cell_no + 1);
-		}
-		no_duplicates += 1;
-		marked_duplicate_indices[j / 3] = 1;
-	      }
-	    }
-	  }
-	}
-      }
+      for ( int i = 0; i < actual_number_of_corners * 3; i = i + 3 )
+	for ( int j = i + 3; j < actual_number_of_corners * 3; j = j + 3 )
+	  if ( fabs(cell_corners_xyz_open_cell[i + 0] - cell_corners_xyz_open_cell[j + 0]) < 0.000001 &&
+               fabs(cell_corners_xyz_open_cell[i + 1] - cell_corners_xyz_open_cell[j + 1]) < 0.000001 &&
+               fabs(cell_corners_xyz_open_cell[i + 2] - cell_corners_xyz_open_cell[j + 2]) < 0.000001 )
+            {
+              if ( cdoVerbose )
+                fprintf(stdout,"The duplicate vertex %f, %f, %f was found in cell no %u.\n",
+                        cell_corners_xyz_open_cell[j],  cell_corners_xyz_open_cell[j + 1],  cell_corners_xyz_open_cell[j + 2], cell_no + 1);
 
+              no_duplicates += 1;
+              marked_duplicate_indices[j / 3] = 1;
+            }
 
       /* Writes the unique corner vertices in a new array. */
 
-      double cell_corners_in_Euclidean_space_without_duplicates[(actual_number_of_corners - no_duplicates) * 3];
+      double cell_corners_xyz_without_duplicates[(actual_number_of_corners - no_duplicates) * 3];
       
       int unique_corner_number = 0;
       
-      for(int corner_number = 0; corner_number < actual_number_of_corners; corner_number++){
-	if(marked_duplicate_indices[corner_number] == 0){
-	  cell_corners_in_Euclidean_space_without_duplicates[unique_corner_number * 3 + 0] = cell_corners_in_Euclidean_space_open_cell[corner_number * 3 + 0];
-	  cell_corners_in_Euclidean_space_without_duplicates[unique_corner_number * 3 + 1] = cell_corners_in_Euclidean_space_open_cell[corner_number * 3 + 1];
-	  cell_corners_in_Euclidean_space_without_duplicates[unique_corner_number * 3 + 2] = cell_corners_in_Euclidean_space_open_cell[corner_number * 3 + 2];
-	  unique_corner_number += 1;
-	}
-      }
+      for ( int corner_no = 0; corner_no < actual_number_of_corners; corner_no++ )
+        {
+          if ( marked_duplicate_indices[corner_no] == 0 )
+            {
+              int off = corner_no * 3;
+              int off2 = unique_corner_number * 3;
+              cell_corners_xyz_without_duplicates[off2 + 0] = cell_corners_xyz_open_cell[off + 0];
+              cell_corners_xyz_without_duplicates[off2 + 1] = cell_corners_xyz_open_cell[off + 1];
+              cell_corners_xyz_without_duplicates[off2 + 2] = cell_corners_xyz_open_cell[off + 2];
+              unique_corner_number += 1;
+            }
+        }
       
       actual_number_of_corners = actual_number_of_corners - no_duplicates;
 
       /* If there are less than three corners in the cell left after removing duplicates, it is unusable and considered degenerate. No area can be computed. */
       
-      if (actual_number_of_corners < 3){
-	if (cdoVerbose){
-	  fprintf(stdout,"Less than three vertices found in cell no %u. This cell is considered degenerate and will be omitted from further computation!\n", cell_no + 1);
-	}
-	continue;
-      }
+      if ( actual_number_of_corners < 3 )
+        {
+          if ( cdoVerbose )
+            fprintf(stdout,"Less than three vertices found in cell no %u. This cell is considered degenerate and will be omitted from further computation!\n", cell_no + 1);
+
+          continue;
+        }
       
-      if (no_duplicates != 0){
-	no_of_cells_with_duplicates += 1;
-      }
+      if ( no_duplicates != 0 ) no_of_cells_with_duplicates += 1;
 
       /* We are creating a closed polygon/cell by setting the additional last corner to be the same as the first one. */
 
-      double cell_corners_in_Euclidean_space[(actual_number_of_corners + 1) * 3];
+      double cell_corners_xyz[(actual_number_of_corners + 1) * 3];
 
-      for (corner_no = 0; corner_no < actual_number_of_corners; corner_no++){
-	cell_corners_in_Euclidean_space[corner_no * 3 + 0] = cell_corners_in_Euclidean_space_without_duplicates[corner_no * 3 + 0];
-	cell_corners_in_Euclidean_space[corner_no * 3 + 1] = cell_corners_in_Euclidean_space_without_duplicates[corner_no * 3 + 1];
-	cell_corners_in_Euclidean_space[corner_no * 3 + 2] = cell_corners_in_Euclidean_space_without_duplicates[corner_no * 3 + 2];
-      }
+      for ( int corner_no = 0; corner_no < actual_number_of_corners; corner_no++ )
+        {
+          int off = corner_no * 3;
+          cell_corners_xyz[off + 0] = cell_corners_xyz_without_duplicates[off + 0];
+          cell_corners_xyz[off + 1] = cell_corners_xyz_without_duplicates[off + 1];
+          cell_corners_xyz[off + 2] = cell_corners_xyz_without_duplicates[off + 2];
+        }
 
-      cell_corners_in_Euclidean_space[actual_number_of_corners * 3 + 0] = cell_corners_in_Euclidean_space[0];
-      cell_corners_in_Euclidean_space[actual_number_of_corners * 3 + 1] = cell_corners_in_Euclidean_space[1];
-      cell_corners_in_Euclidean_space[actual_number_of_corners * 3 + 2] = cell_corners_in_Euclidean_space[2];
+      cell_corners_xyz[actual_number_of_corners * 3 + 0] = cell_corners_xyz[0];
+      cell_corners_xyz[actual_number_of_corners * 3 + 1] = cell_corners_xyz[1];
+      cell_corners_xyz[actual_number_of_corners * 3 + 2] = cell_corners_xyz[2];
 
       /* Takes the first three corners/vertices of the cell and calculates the unit normal via determinants. */
       
-      corner_coordinates[0] = cell_corners_in_Euclidean_space[0];
-      corner_coordinates[1] = cell_corners_in_Euclidean_space[1];
-      corner_coordinates[2] = cell_corners_in_Euclidean_space[2];
+      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_in_Euclidean_space[3 + 0];
-      second_corner_coordinates[1] = cell_corners_in_Euclidean_space[3 + 1];
-      second_corner_coordinates[2] = cell_corners_in_Euclidean_space[3 + 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];
 
-      third_corner_coordinates[0] = cell_corners_in_Euclidean_space[6 + 0];
-      third_corner_coordinates[1] = cell_corners_in_Euclidean_space[6 + 1];
-      third_corner_coordinates[2] = cell_corners_in_Euclidean_space[6 + 2];
+      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];
       
       find_unit_normal(corner_coordinates, second_corner_coordinates, third_corner_coordinates, p_surface_normal_of_the_cell);
 
       /* The surface normal is used to choose the coordinate to ignore. */
 
-      abs_x = fabs(surface_normal_of_the_cell[0]);
-      abs_y = fabs(surface_normal_of_the_cell[1]);
-      abs_z = fabs(surface_normal_of_the_cell[2]);
+      double abs_x = fabs(surface_normal_of_the_cell[0]);
+      double abs_y = fabs(surface_normal_of_the_cell[1]);
+      double abs_z = fabs(surface_normal_of_the_cell[2]);
 
       coordinate_to_ignore = 3;
 
       if (abs_x > abs_y){
-	if (abs_x > abs_z){
-	  coordinate_to_ignore = 1;
-	}
+	if (abs_x > abs_z) coordinate_to_ignore = 1;
       } else {
-	if (abs_y > abs_z){
-	  coordinate_to_ignore = 2;
-	}
+	if (abs_y > abs_z) coordinate_to_ignore = 2;
       }
      
       /* The remaining two-dimensional coordinates are extracted into one array for all the cell's corners and into one array for the center point. */
@@ -582,33 +561,35 @@ void verify_grid(int gridtype, int gridsize, int gridno, int ngrids, int ncorner
 	 In this case, the result of the computation of the orientation of vertices needs to be inverted. Clockwise becomes counterclockwise and vice versa. */
 
       bool invert_result = false;
-      if ( cell_corners_in_Euclidean_space[coordinate_to_ignore - 1] < 0 )
-	invert_result = true;
+      if ( cell_corners_xyz[coordinate_to_ignore - 1] < 0 ) invert_result = true;
       
       switch(coordinate_to_ignore){
       case 1:
-	for(corner_no = 0; corner_no <= actual_number_of_corners; corner_no++){
-	  cell_corners_plane_projection[corner_no * 2 + 0] = cell_corners_in_Euclidean_space[corner_no * 3 + 1];
-	  cell_corners_plane_projection[corner_no * 2 + 1] = cell_corners_in_Euclidean_space[corner_no * 3 + 2];
-	}
-	center_point_plane_projection[0] = center_point_in_Euclidean_space[1];
-	center_point_plane_projection[1] = center_point_in_Euclidean_space[2];		
+	for ( int corner_no = 0; corner_no <= actual_number_of_corners; corner_no++ )
+          {
+            cell_corners_plane_projection[corner_no * 2 + 0] = cell_corners_xyz[corner_no * 3 + 1];
+            cell_corners_plane_projection[corner_no * 2 + 1] = cell_corners_xyz[corner_no * 3 + 2];
+          }
+	center_point_plane_projection[0] = center_point_xyz[1];
+	center_point_plane_projection[1] = center_point_xyz[2];		
 	break;
       case 2:
-	for(int corner_no = 0; corner_no <= actual_number_of_corners; corner_no++){
-	  cell_corners_plane_projection[corner_no * 2 + 0] = cell_corners_in_Euclidean_space[corner_no * 3 + 2];
-	  cell_corners_plane_projection[corner_no * 2 + 1] = cell_corners_in_Euclidean_space[corner_no * 3 + 0];
-	}
-	center_point_plane_projection[0] = center_point_in_Euclidean_space[2];
-	center_point_plane_projection[1] = center_point_in_Euclidean_space[0];	
+	for ( int corner_no = 0; corner_no <= actual_number_of_corners; corner_no++ )
+          {
+            cell_corners_plane_projection[corner_no * 2 + 0] = cell_corners_xyz[corner_no * 3 + 2];
+            cell_corners_plane_projection[corner_no * 2 + 1] = cell_corners_xyz[corner_no * 3 + 0];
+          }
+	center_point_plane_projection[0] = center_point_xyz[2];
+	center_point_plane_projection[1] = center_point_xyz[0];	
 	break;
       case 3:
-	for(int corner_no = 0; corner_no <= actual_number_of_corners; corner_no++){
-	  cell_corners_plane_projection[corner_no * 2 + 0] = cell_corners_in_Euclidean_space[corner_no * 3 + 0];
-	  cell_corners_plane_projection[corner_no * 2 + 1] = cell_corners_in_Euclidean_space[corner_no * 3 + 1];
-	}
-	center_point_plane_projection[0] = center_point_in_Euclidean_space[0];
-	center_point_plane_projection[1] = center_point_in_Euclidean_space[1];	
+	for ( int corner_no = 0; corner_no <= actual_number_of_corners; corner_no++ )
+          {
+            cell_corners_plane_projection[corner_no * 2 + 0] = cell_corners_xyz[corner_no * 3 + 0];
+            cell_corners_plane_projection[corner_no * 2 + 1] = cell_corners_xyz[corner_no * 3 + 1];
+          }
+	center_point_plane_projection[0] = center_point_xyz[0];
+	center_point_plane_projection[1] = center_point_xyz[1];	
 	break;
       }
 
@@ -619,18 +600,12 @@ void verify_grid(int gridtype, int gridsize, int gridno, int ngrids, int ncorner
      
       /* Checking the arrangement or direction of cell vertices. */
 
-      polygon_area = calculate_the_polygon_area(cell_corners_plane_projection, actual_number_of_corners + 1);
+      double polygon_area = calculate_the_polygon_area(cell_corners_plane_projection, actual_number_of_corners + 1);
       bool is_clockwise = are_polygon_vertices_arranged_in_clockwise_order(polygon_area);
             
       /* If the direction of the vertices was flipped during the projection onto the two-dimensional plane, the previous result needs to be inverted now. */
 
-      if ( invert_result )
-        {
-          if ( is_clockwise )
-            is_clockwise = false;
-          else
-            is_clockwise = true;
-        }
+      if ( invert_result ) is_clockwise = !is_clockwise;
 
       /* The overall counter of (counter)clockwise cells is increased by one. */
 
@@ -641,8 +616,7 @@ void verify_grid(int gridtype, int gridsize, int gridno, int ngrids, int ncorner
       
       /* The winding numbers algorithm is used to test whether the presumed center point is within the bounds of the cell. */
         
-      winding_number = winding_numbers_algorithm(cell_corners_plane_projection, actual_number_of_corners + 1, center_point_plane_projection);
-
+      int winding_number = winding_numbers_algorithm(cell_corners_plane_projection, actual_number_of_corners + 1, center_point_plane_projection);
 
       if ( winding_number == 0 )
 	no_of_cells_with_center_points_out_of_bounds += 1;
diff --git a/src/Vertcum.c b/src/Vertcum.c
index 5b1ba4b..090c3e0 100644
--- a/src/Vertcum.c
+++ b/src/Vertcum.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -57,12 +57,10 @@ void add_vars_mv(int gridsize, double missval, const double *restrict var1, cons
 
 void *Vertcum(void *argument)
 {
-  int recID, nrecs;
-  int i, gridsize, nlevs = 0, nlevs2 = 0, nlevshl = 0;
-  int varID, levelID, zaxisID;
+  int nrecs;
+  int i, nlevshl = 0;
+  int varID, levelID;
   int nmiss;
-  double *single;
-  double missval;
 
   cdoInitialize(argument);
 
@@ -88,10 +86,10 @@ void *Vertcum(void *argument)
       double *vct = NULL;
       int lhybrid = FALSE;
       int nzaxis  = vlistNzaxis(vlistID1);
-      for ( i = 0; i < nzaxis; ++i )
+      for ( int i = 0; i < nzaxis; ++i )
         {
-          zaxisID = vlistZaxis(vlistID1, i);
-          nlevs   = zaxisInqSize(zaxisID);
+          int zaxisID = vlistZaxis(vlistID1, i);
+          int nlevs   = zaxisInqSize(zaxisID);
 
           if ( zaxisInqType(zaxisID) == ZAXIS_HYBRID && nlevs > 1 )
             {
@@ -126,9 +124,9 @@ void *Vertcum(void *argument)
 
   for ( varID = 0; varID < nvars; varID++ )
     {
-      gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
-      nlevs    = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
-      nlevs2   = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
+      int gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
+      int nlevs    = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
+      int nlevs2   = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
 
       varnmiss[varID] = (int*) Malloc(nlevs*sizeof(int));
       vardata1[varID] = (double**) Malloc(nlevs*sizeof(double*));
@@ -154,7 +152,7 @@ void *Vertcum(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
           streamReadRecord(streamID1, vardata1[varID][levelID], &varnmiss[varID][levelID]);
@@ -162,9 +160,9 @@ void *Vertcum(void *argument)
 
       for ( varID = 0; varID < nvars; ++varID )
 	{
-          missval  = vlistInqVarMissval(vlistID2, varID);
-          gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
-          nlevs2   = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
+          double missval  = vlistInqVarMissval(vlistID2, varID);
+          int gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
+          int nlevs2   = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
 
           if ( operatorID == VERTCUMHL && nlevs2 == nlevshl )
             {
@@ -178,13 +176,9 @@ void *Vertcum(void *argument)
           for ( levelID = 1; levelID < nlevs2; ++levelID )
             {
               if ( operatorID == VERTCUMHL && nlevs2 == nlevshl )
-                {
-                  add_vars_mv(gridsize, missval, vardata1[varID][levelID-1], vardata2[varID][levelID-1], vardata2[varID][levelID]);
-                }
+                add_vars_mv(gridsize, missval, vardata1[varID][levelID-1], vardata2[varID][levelID-1], vardata2[varID][levelID]);
               else
-                {
-                  add_vars_mv(gridsize, missval, vardata1[varID][levelID], vardata2[varID][levelID-1], vardata2[varID][levelID]);
-                }
+                add_vars_mv(gridsize, missval, vardata1[varID][levelID], vardata2[varID][levelID-1], vardata2[varID][levelID]);
             }
 
           if ( operatorID == VERTCUMHL && nlevs2 == nlevshl )
@@ -206,15 +200,15 @@ void *Vertcum(void *argument)
 
       for ( varID = 0; varID < nvars; ++varID )
 	{
-          missval  = vlistInqVarMissval(vlistID2, varID);
-          gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
-          nlevs2   = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
+          double missval  = vlistInqVarMissval(vlistID2, varID);
+          int gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
+          int nlevs2   = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
           for ( levelID = 0; levelID < nlevs2; ++levelID )
 	    {
-              single = vardata2[varID][levelID];
+              double *single = vardata2[varID][levelID];
 
               nmiss = 0;
-              for ( i = 0; i < gridsize; ++i )
+              for ( int i = 0; i < gridsize; ++i )
                 if ( DBL_IS_EQUAL(single[i], missval) ) nmiss++;
 
               streamDefRecord(streamID2, varID, levelID);
@@ -227,8 +221,8 @@ void *Vertcum(void *argument)
 
   for ( varID = 0; varID < nvars; ++varID )
     {
-      nlevs  = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
-      nlevs2 = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
+      int nlevs  = zaxisInqSize(vlistInqVarZaxis(vlistID1, varID));
+      int nlevs2 = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
       for ( levelID = 0; levelID < nlevs; ++levelID ) Free(vardata1[varID][levelID]);
       for ( levelID = 0; levelID < nlevs2; ++levelID ) Free(vardata2[varID][levelID]);
       Free(vardata1[varID]);
diff --git a/src/Vertintap.c b/src/Vertintap.c
index 656dbbc..460663c 100644
--- a/src/Vertintap.c
+++ b/src/Vertintap.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -22,14 +22,12 @@
 */
 
 
-#include <ctype.h>
-
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
 #include "pstream.h"
 #include "after_vertint.h"
-#include "list.h"
+#include "listarray.h"
 #include "stdnametable.h"
 
 static
@@ -69,25 +67,21 @@ void *Vertintap(void *argument)
   int i, k, offset;
   int varID, levelID;
   int zaxisIDp, zaxisIDh = -1;
-  int gridID, zaxisID;
   int nhlev = 0, nhlevf = 0, nhlevh = 0, nlevel;
   int *vert_index = NULL;
   int apressID = -1, dpressID = -1;
   int psID = -1, tempID = -1;
-  int param;
   //int sortlevels = TRUE;
   int *pnmiss = NULL;
   char paramstr[32];
   char stdname[CDI_MAX_NAME];
   char varname[CDI_MAX_NAME];
-  double minval, maxval;
-  double missval;
   double *vct = NULL;
   double *single1, *single2;
   double *ps_prog = NULL, *full_press = NULL, *dpress = NULL;
   double *hyb_press = NULL;
   int Extrapolate = 0;
-  LIST *flist = listNew(FLT_LIST);
+  lista_t *flista = lista_new(FLT_LISTA);
 
   cdoInitialize(argument);
 
@@ -146,8 +140,8 @@ void *Vertintap(void *argument)
     }
   else
     {
-      nplev = args2fltlist(operatorArgc(), operatorArgv(), flist);
-      plev  = (double *) listArrayPtr(flist);
+      nplev = args2flt_lista(operatorArgc(), operatorArgv(), flista);
+      plev  = (double *) lista_dataptr(flista);
     }
 
   int streamID1 = streamOpenRead(cdoStreamName(0));
@@ -193,9 +187,9 @@ void *Vertintap(void *argument)
   if ( apressID == -1 ) cdoAbort("%s not found!", var_stdname(air_pressure));
 
   int nzaxis = vlistNzaxis(vlistID1);
-  for ( i = 0; i < nzaxis; i++ )
+  for ( int i = 0; i < nzaxis; i++ )
     {
-      zaxisID = vlistZaxis(vlistID1, i);
+      int zaxisID = vlistZaxis(vlistID1, i);
       if ( zaxisID == vlistInqVarZaxis(vlistID1, apressID) )
         {
           bool mono_level = true;
@@ -204,7 +198,7 @@ void *Vertintap(void *argument)
           if ( is_height_axis(zaxisID, nlevel) )
             {
               double *level = (double *) Malloc(nlevel*sizeof(double));
-              zaxisInqLevels(zaxisID, level);
+              cdoZaxisInqLevels(zaxisID, level);
               int l;
               for ( l = 0; l < nlevel; l++ )
                 {
@@ -272,7 +266,7 @@ void *Vertintap(void *argument)
       height2pressure(phlev, plev, nplev);
 
       if ( cdoVerbose )
-	for ( i = 0; i < nplev; ++i )
+	for ( int i = 0; i < nplev; ++i )
 	  cdoPrint("level = %d   height = %g   pressure = %g", i+1, plev[i], phlev[i]);
 
       memcpy(plev, phlev, nplev*sizeof(double));
@@ -283,9 +277,9 @@ void *Vertintap(void *argument)
 
   for ( varID = 0; varID < nvars; varID++ )
     {
-      gridID   = vlistInqVarGrid(vlistID1, varID);
-      zaxisID  = vlistInqVarZaxis(vlistID1, varID);
-      nlevel   = zaxisInqSize(zaxisID);
+      int gridID   = vlistInqVarGrid(vlistID1, varID);
+      int zaxisID  = vlistInqVarZaxis(vlistID1, varID);
+      int nlevel   = zaxisInqSize(zaxisID);
 
       if ( gridInqType(gridID) == GRID_SPECTRAL )
 	cdoAbort("Spectral data unsupported!");
@@ -338,7 +332,6 @@ void *Vertintap(void *argument)
 	}
 
       taxisCopyTimestep(taxisID2, taxisID1);
-
       streamDefTimestep(streamID2, tsID);
 
       for ( int recID = 0; recID < nrecs; recID++ )
@@ -385,6 +378,7 @@ void *Vertintap(void *argument)
 	    }
 
 	  /* check range of ps_prog */
+          double minval, maxval;
 	  minmaxval(gridsize, ps_prog, NULL, &minval, &maxval);
 	  if ( minval < MIN_PS || maxval > MAX_PS )
 	    cdoWarning("Surface pressure out of range (min=%g max=%g)!", minval, maxval);
@@ -410,9 +404,9 @@ void *Vertintap(void *argument)
 	{
 	  if ( vars[varID] )
 	    {
-	      zaxisID  = vlistInqVarZaxis(vlistID1, varID);
-	      missval  = vlistInqVarMissval(vlistID1, varID);
-	      nlevel   = zaxisInqSize(zaxisID);
+	      int zaxisID  = vlistInqVarZaxis(vlistID1, varID);
+	      int nlevel   = zaxisInqSize(zaxisID);
+	      double missval  = vlistInqVarMissval(vlistID1, varID);
 	      if ( varinterp[varID] )
 		{
 		  if ( nlevel == nhlevf )
@@ -421,7 +415,7 @@ void *Vertintap(void *argument)
 		    }
 		  else
 		    {
-		      param = vlistInqVarParam(vlistID1, varID);
+		      int param = vlistInqVarParam(vlistID1, varID);
 		      cdiParamToString(param, paramstr, sizeof(paramstr));
 		      cdoAbort("Number of generalized height level differ from full/half level (param=%s)!", paramstr);
 		    }
@@ -445,7 +439,7 @@ void *Vertintap(void *argument)
 	{
 	  if ( vars[varID] )
 	    {
-	      nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
+	      int nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
 	      for ( levelID = 0; levelID < nlevel; levelID++ )
 		{
 		  offset   = gridsize*levelID;
@@ -476,7 +470,7 @@ void *Vertintap(void *argument)
   if ( dpress     ) Free(dpress);
   if ( vct        ) Free(vct);
 
-  listDelete(flist);
+  lista_destroy(flista);
 
   cdoFinish();
 
diff --git a/src/Vertintml.c b/src/Vertintml.c
index c873d64..66e68e6 100644
--- a/src/Vertintml.c
+++ b/src/Vertintml.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -23,50 +23,60 @@
 */
 
 
-#include <ctype.h>
-
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
 #include "pstream.h"
 #include "after_vertint.h"
-#include "list.h"
+#include "listarray.h"
 #include "stdnametable.h"
 #include "constants.h"
 
 
+static
+bool zaxis_is_hybrid(int zaxistype)
+{
+  return (zaxistype == ZAXIS_HYBRID || zaxistype == ZAXIS_HYBRID_HALF);
+}
+
+static
+void change_hybrid_zaxis(int vlistID1, int vlistID2, int nvct, double *vct, int zaxisID2)
+{
+  int nzaxis = vlistNzaxis(vlistID1);
+  for ( int iz = 0; iz < nzaxis; ++iz )
+    {
+      int zaxisID = vlistZaxis(vlistID1, iz);
+      int nlevel  = zaxisInqSize(zaxisID);
+      int zaxistype = zaxisInqType(zaxisID);
+
+      if ( zaxis_is_hybrid(zaxistype) && nlevel > 1 )
+	{
+	  int nvct2 = zaxisInqVctSize(zaxisID);
+          if ( nvct2 == nvct && memcmp(vct, zaxisInqVctPtr(zaxisID), nvct*sizeof(double)) == 0 )
+            vlistChangeZaxisIndex(vlistID2, iz, zaxisID2);
+	}
+    }
+}
+
+
 void *Vertintml(void *argument)
 {
   int mode;
   enum {ECHAM_MODE, WMO_MODE};
   enum {func_pl, func_hl};
   enum {type_lin, type_log};
-  int recID, nrecs;
-  int i, k, offset;
+  int nrecs;
   int varID, levelID;
-  int zaxisIDp, zaxisIDh = -1;
-  int gridID, zaxisID;
-  int nhlev = 0, nhlevf = 0, nhlevh = 0, nlevel;
-  int *vert_index = NULL;
-  int nvct = 0;
-  int sgeopot_needed = FALSE;
-  int sgeopotID = -1, geopotID = -1, tempID = -1, psID = -1, lnpsID = -1, presID = -1, gheightID = -1;
-  int code, param;
-  int pnum, pcat, pdis;
-  //int sortlevels = TRUE;
-  int *pnmiss = NULL;
+  bool sgeopot_needed = false;
+  bool extrapolate = false;
+  int sgeopotID = -1, geopotID = -1, tempID = -1, psID = -1, lnpsID = -1, gheightID = -1;
+  // bool sortlevels = true;
   char paramstr[32];
   char varname[CDI_MAX_NAME], stdname[CDI_MAX_NAME];
   double minval, maxval;
-  double missval;
-  double *rvct = NULL; /* reduced VCT for LM */
-  double *single1, *single2;
-  double *sgeopot = NULL, *ps_prog = NULL, *full_press = NULL, *half_press = NULL;
-  int Extrapolate = 0;
-  int instNum, tableNum;
-  int useTable;
+  double *sgeopot = NULL;
   gribcode_t gribcodes = {0};
-  LIST *flist = listNew(FLT_LIST);
+  lista_t *flista = lista_new(FLT_LISTA);
 
   cdoInitialize(argument);
 
@@ -86,17 +96,16 @@ void *Vertintml(void *argument)
   if ( operatorID == ML2PL || operatorID == ML2HL || operatorID == ML2PL_LP || operatorID == ML2HL_LP )
     {
       char *envstr = getenv("EXTRAPOLATE");
-
       if ( envstr && isdigit((int) envstr[0]) )
 	{
-          Extrapolate = atoi(envstr);
-          if ( Extrapolate == 1 )
+          if ( atoi(envstr) == 1 ) extrapolate = true;
+          if ( extrapolate )
             cdoPrint("Extrapolation of missing values enabled!");
 	}
     }
   else if ( operatorID == ML2PLX || operatorID == ML2HLX || operatorID == ML2PLX_LP || operatorID == ML2HLX_LP )
     {
-      Extrapolate = 1;
+      extrapolate = true;
     }
 
   operatorInputArg(cdoOperatorEnter(operatorID));
@@ -110,7 +119,7 @@ void *Vertintml(void *argument)
           double stdlev[] = { 10, 50, 100, 500, 1000, 5000, 10000, 15000, 20000, 25000, 30000 };
           nplev = sizeof(stdlev)/sizeof(*stdlev);
           plev  = (double *) Malloc(nplev*sizeof(double));
-          for ( i = 0; i < nplev; ++i ) plev[i] = stdlev[i];
+          for ( int i = 0; i < nplev; ++i ) plev[i] = stdlev[i];
         }
       else
         {
@@ -122,13 +131,13 @@ void *Vertintml(void *argument)
                              10000,  7000,  5000,  3000,  2000, 1000 };
           nplev = sizeof(stdlev)/sizeof(*stdlev);
           plev  = (double *) Malloc(nplev*sizeof(double));
-          for ( i = 0; i < nplev; ++i ) plev[i] = stdlev[i];
+          for ( int i = 0; i < nplev; ++i ) plev[i] = stdlev[i];
         }
     }
   else
     {
-      nplev = args2fltlist(operatorArgc(), operatorArgv(), flist);
-      plev  = (double *) listArrayPtr(flist);
+      nplev = args2flt_lista(operatorArgc(), operatorArgv(), flista);
+      plev  = (double *) lista_dataptr(flista);
     }
   
   int streamID1 = streamOpenRead(cdoStreamName(0));
@@ -142,16 +151,15 @@ void *Vertintml(void *argument)
 
   int gridsize = vlist_check_gridsize(vlistID1);
 
-  if ( operfunc == func_hl )
-    zaxisIDp = zaxisCreate(ZAXIS_HEIGHT, nplev);
-  else
-    zaxisIDp = zaxisCreate(ZAXIS_PRESSURE, nplev);
-
+  int zaxisIDp = (operfunc == func_hl) ? zaxisCreate(ZAXIS_HEIGHT, nplev) : zaxisCreate(ZAXIS_PRESSURE, nplev);
   zaxisDefLevels(zaxisIDp, plev);
 
+  int nvct = 0;
+  int zaxisIDh = -1;
+  int nhlev = 0, nhlevf = 0, nhlevh = 0;
   double *vct = vlist_read_vct(vlistID1, &zaxisIDh, &nvct, &nhlev, &nhlevf, &nhlevh);
 
-  vlist_change_hybrid_zaxis(vlistID1, vlistID2, zaxisIDh, zaxisIDp);
+  change_hybrid_zaxis(vlistID1, vlistID2, nvct, vct, zaxisIDp);
 
   int psvarID = -1;
   bool linvertvct = false;
@@ -159,9 +167,9 @@ void *Vertintml(void *argument)
     {
       psvarID = vlist_get_psvarid(vlistID1, zaxisIDh);
 
+      int i;
       for ( i = nvct/2+1; i < nvct; i++ )
         if ( vct[i] > vct[i-1] ) break;
-
       if ( i == nvct ) linvertvct = true;
     }
 
@@ -171,7 +179,7 @@ void *Vertintml(void *argument)
     {
       double vctbuf[nvct];
       memcpy(vctbuf, vct, nvct*sizeof(double));
-      for ( i = 0; i < nvct/2; i++ )
+      for ( int i = 0; i < nvct/2; i++ )
         {
           vct[nvct/2-1-i] = vctbuf[i];
           vct[nvct-1-i] = vctbuf[i+nvct/2];
@@ -180,16 +188,15 @@ void *Vertintml(void *argument)
 
   int nvars = vlistNvars(vlistID1);
 
-  int vars[nvars];
+  bool vars[nvars];
+  bool varinterp[nvars];
+  int *varnmiss[nvars];
   double *vardata1[nvars];
   double *vardata2[nvars];
-  int *varnmiss[nvars];
-  int varinterp[nvars];
 
-  int maxlev   = nhlevh > nplev ? nhlevh : nplev;
+  int maxlev = nhlevh > nplev ? nhlevh : nplev;
 
-  if ( Extrapolate == 0 )
-    pnmiss = (int*) Malloc(nplev*sizeof(int));
+  int *pnmiss = extrapolate ? NULL : (int*) Malloc(nplev*sizeof(int));
 
   // check levels
   if ( zaxisIDh != -1 )
@@ -197,18 +204,20 @@ void *Vertintml(void *argument)
       int nlev = zaxisInqSize(zaxisIDh);
       if ( nlev != nhlev ) cdoAbort("Internal error, wrong number of hybrid level!");
       double levels[nlev];
-      zaxisInqLevels(zaxisIDh, levels);
+      cdoZaxisInqLevels(zaxisIDh, levels);
 
       for ( int ilev = 0; ilev < nlev; ++ilev )
 	{
 	  if ( (ilev+1) != (int)levels[ilev] )
 	    {
-	      //sortlevels = FALSE;
+	      //sortlevels = false;
 	      break;
 	    }
 	}
     }
 
+  int *vert_index = NULL;
+  double *ps_prog = NULL, *full_press = NULL, *half_press = NULL;
   if ( zaxisIDh != -1 && gridsize > 0 )
     {
       vert_index = (int*) Malloc(gridsize*nplev*sizeof(int));
@@ -225,22 +234,22 @@ void *Vertintml(void *argument)
       height2pressure(phlev, plev, nplev);
 
       if ( cdoVerbose )
-	for ( i = 0; i < nplev; ++i )
+	for ( int i = 0; i < nplev; ++i )
 	  cdoPrint("level = %d   height = %g   pressure = %g", i+1, plev[i], phlev[i]);
 
       memcpy(plev, phlev, nplev*sizeof(double));
     }
 
   if ( opertype == type_log )
-    for ( k = 0; k < nplev; k++ ) plev[k] = log(plev[k]);
+    for ( int k = 0; k < nplev; k++ ) plev[k] = log(plev[k]);
 
-  useTable = FALSE;
+  bool useTable = false;
   for ( varID = 0; varID < nvars; varID++ )
     {
-      tableNum = tableInqNum(vlistInqVarTable(vlistID1, varID));
+      int tableNum = tableInqNum(vlistInqVarTable(vlistID1, varID));
       if ( tableNum > 0 && tableNum != 255 )
 	{
-	  useTable = TRUE;
+	  useTable = true;
 	  break;
 	}
     }
@@ -249,17 +258,19 @@ void *Vertintml(void *argument)
 
   for ( varID = 0; varID < nvars; varID++ )
     {
-      gridID   = vlistInqVarGrid(vlistID1, varID);
-      zaxisID  = vlistInqVarZaxis(vlistID1, varID);
+      int gridID   = vlistInqVarGrid(vlistID1, varID);
+      int zaxisID  = vlistInqVarZaxis(vlistID1, varID);
+      int zaxistype = zaxisInqType(zaxisID);
       // gridsize = gridInqSize(gridID);
-      nlevel   = zaxisInqSize(zaxisID);
-      instNum  = institutInqCenter(vlistInqVarInstitut(vlistID1, varID));
-      tableNum = tableInqNum(vlistInqVarTable(vlistID1, varID));
-
-      code     = vlistInqVarCode(vlistID1, varID);
-      param    = vlistInqVarParam(vlistID1, varID);
+      int nlevel   = zaxisInqSize(zaxisID);
+      int instNum  = institutInqCenter(vlistInqVarInstitut(vlistID1, varID));
+      int tableNum = tableInqNum(vlistInqVarTable(vlistID1, varID));
 
+      int code     = vlistInqVarCode(vlistID1, varID);
+      
+      int param = vlistInqVarParam(vlistID1, varID);
       cdiParamToString(param, paramstr, sizeof(paramstr));
+      int pnum, pcat, pdis;
       cdiDecodeParam(param, &pnum, &pcat, &pdis);
       if ( pdis >= 0 && pdis < 255 ) code = -1;
 
@@ -326,7 +337,7 @@ void *Vertintml(void *argument)
 	  else if ( code == gribcodes.ps      && nlevel == 1      ) psID      = varID;
 	}
 
-      if ( gridInqType(gridID) == GRID_SPECTRAL && zaxisInqType(zaxisID) == ZAXIS_HYBRID )
+      if ( gridInqType(gridID) == GRID_SPECTRAL && zaxis_is_hybrid(zaxistype) )
 	cdoAbort("Spectral data on model level unsupported!");
 
       if ( gridInqType(gridID) == GRID_SPECTRAL )
@@ -337,21 +348,21 @@ void *Vertintml(void *argument)
       else
 	vardata1[varID] = (double*) Malloc(gridsize*nlevel*sizeof(double));
 
-      /* if ( zaxisInqType(zaxisID) == ZAXIS_HYBRID && zaxisIDh != -1 && nlevel == nhlev ) */
+      /* if ( zaxis_is_hybrid(zaxistype) && zaxisIDh != -1 && nlevel == nhlev ) */
       if ( zaxisID == zaxisIDh ||
-	   (zaxisInqType(zaxisID) == ZAXIS_HYBRID && zaxisIDh != -1 && (nlevel == nhlevh || nlevel == nhlevf)) )
+	   (zaxis_is_hybrid(zaxistype) && zaxisIDh != -1 && (nlevel == nhlevh || nlevel == nhlevf)) )
 	{
-	  varinterp[varID] = TRUE;
+	  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));
 	}
       else
 	{
-	  if ( zaxisInqType(zaxisID) == ZAXIS_HYBRID && zaxisIDh != -1 && nlevel > 1 )
+	  if ( zaxis_is_hybrid(zaxistype) && zaxisIDh != -1 && nlevel > 1 )
 	    cdoWarning("Parameter %d has wrong number of levels, skipped! (param=%s nlevel=%d)",
 		       varID+1, paramstr, nlevel);
-	  varinterp[varID] = FALSE;
+	  varinterp[varID] = false;
 	  vardata2[varID]  = vardata1[varID];
 	  varnmiss[varID]  = (int*) Malloc(nlevel*sizeof(int));
 	}
@@ -368,18 +379,20 @@ void *Vertintml(void *argument)
       if ( gheightID != -1 ) cdoPrint("  %s", var_stdname(geopotential_height));
     }
 
-  if ( tempID != -1 || gheightID != -1 ) sgeopot_needed = TRUE;
+  if ( tempID != -1 || gheightID != -1 ) sgeopot_needed = true;
 
   if ( zaxisIDh != -1 && sgeopot_needed )
     {
       sgeopot = (double*) Malloc(gridsize*sizeof(double));
       if ( sgeopotID == -1 )
 	{
-	  if ( geopotID == -1 )
-	    cdoWarning("%s not found - set to zero!", var_stdname(surface_geopotential));
-	  else
-	    cdoPrint("%s not found - using bottom layer of %s!", var_stdname(surface_geopotential), var_stdname(geopotential));
-
+          if ( extrapolate )
+            {
+              if ( geopotID == -1 )
+                cdoWarning("%s not found - set to zero!", var_stdname(surface_geopotential));
+              else
+                cdoPrint("%s not found - using bottom layer of %s!", var_stdname(surface_geopotential), var_stdname(geopotential));
+            }
 	  memset(sgeopot, 0, gridsize*sizeof(double));
 	}
     }
@@ -387,7 +400,7 @@ void *Vertintml(void *argument)
   if ( zaxisIDh != -1 && gheightID != -1 && tempID == -1 )
     cdoAbort("Temperature not found, needed for vertical interpolation of geopotheight!");
 
-  presID = lnpsID;
+  int presID = lnpsID;
   if ( psvarID != -1 ) presID = psvarID;
 
   if ( zaxisIDh != -1 && presID == -1 )
@@ -411,7 +424,7 @@ void *Vertintml(void *argument)
   if ( zaxisIDh != -1 )
     {
       double suma = 0, sumb = 0;
-      for ( i = 0; i < nhlevh; i++ )
+      for ( int i = 0; i < nhlevh; i++ )
         {
           suma += vct[i];
           sumb += vct[i+nhlevh];
@@ -426,18 +439,17 @@ void *Vertintml(void *argument)
   int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
-      for ( varID = 0; varID < nvars; ++varID ) vars[varID] = FALSE;
+      for ( varID = 0; varID < nvars; ++varID ) vars[varID] = false;
 
       taxisCopyTimestep(taxisID2, taxisID1);
-
       streamDefTimestep(streamID2, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  //gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
-	  zaxisID  = vlistInqVarZaxis(vlistID1, varID);
-	  nlevel   = zaxisInqSize(zaxisID);
+	  int zaxisID  = vlistInqVarZaxis(vlistID1, varID);
+	  int nlevel   = zaxisInqSize(zaxisID);
 	  /*
 	  if ( sortlevels && zaxisIDh != -1 && zaxisID == zaxisIDh && nlevel == nhlev )
 	    {
@@ -448,11 +460,11 @@ void *Vertintml(void *argument)
           if ( linvertvct && zaxisIDh != -1 && zaxisID == zaxisIDh )
             levelID = nlevel-1-levelID;
 
-	  offset   = gridsize*levelID;
-	  single1  = vardata1[varID] + offset;
+	  size_t offset  = gridsize*levelID;
+	  double *single = vardata1[varID] + offset;
 
-	  streamReadRecord(streamID1, single1, &varnmiss[varID][levelID]);
-	  vars[varID] = TRUE;
+	  streamReadRecord(streamID1, single, &varnmiss[varID][levelID]);
+	  vars[varID] = true;
 	}
 
       if ( zaxisIDh != -1 )
@@ -465,7 +477,7 @@ void *Vertintml(void *argument)
 		memcpy(sgeopot, vardata1[geopotID]+gridsize*(nhlevf-1), gridsize*sizeof(double));
 
 	      /* check range of surface geopot */
-	      if ( sgeopotID != -1 || geopotID != -1 )
+	      if ( extrapolate && (sgeopotID != -1 || geopotID != -1) )
 		{
 		  minmaxval(gridsize, sgeopot, NULL, &minval, &maxval);
 		  if ( minval < MIN_FIS || maxval > MAX_FIS )
@@ -476,7 +488,7 @@ void *Vertintml(void *argument)
 	    }
 
 	  if ( presID == lnpsID )
-	    for ( i = 0; i < gridsize; i++ ) ps_prog[i] = exp(vardata1[lnpsID][i]);
+	    for ( int i = 0; i < gridsize; i++ ) ps_prog[i] = exp(vardata1[lnpsID][i]);
 	  else if ( presID != -1 )
 	    memcpy(ps_prog, vardata1[presID], gridsize*sizeof(double));
 
@@ -490,32 +502,29 @@ void *Vertintml(void *argument)
 
 	  if ( opertype == type_log )
 	    {
-	      for ( i = 0; i < gridsize; i++ ) ps_prog[i] = log(ps_prog[i]);
+	      for ( int i = 0; i < gridsize; i++ ) ps_prog[i] = log(ps_prog[i]);
 
-	      for ( k = 0; k < nhlevh; k++ )
-		for ( i = 0; i < gridsize; i++ )
+	      for ( int k = 0; k < nhlevh; k++ )
+		for ( int i = 0; i < gridsize; i++ )
 		  half_press[k*gridsize+i] = log(half_press[k*gridsize+i]);
 
-	      for ( k = 0; k < nhlevf; k++ )
-		for ( i = 0; i < gridsize; i++ )
+	      for ( int k = 0; k < nhlevf; k++ )
+		for ( int i = 0; i < gridsize; i++ )
 		  full_press[k*gridsize+i] = log(full_press[k*gridsize+i]);
 	    }
 
 	  genind(vert_index, plev, full_press, gridsize, nplev, nhlevf);
 
-	  if ( Extrapolate == 0 )
-	    genindmiss(vert_index, plev, gridsize, nplev, ps_prog, pnmiss);
+	  if ( !extrapolate ) genindmiss(vert_index, plev, gridsize, nplev, ps_prog, pnmiss);
 	}
 
       for ( varID = 0; varID < nvars; varID++ )
 	{
 	  if ( vars[varID] )
 	    {
-	      gridID   = vlistInqVarGrid(vlistID1, varID);
-	      zaxisID  = vlistInqVarZaxis(vlistID1, varID);
-	      missval  = vlistInqVarMissval(vlistID1, varID);
-	      //gridsize = gridInqSize(gridID);
-	      nlevel   = zaxisInqSize(zaxisID);
+	      int zaxisID  = vlistInqVarZaxis(vlistID1, varID);
+	      int nlevel   = zaxisInqSize(zaxisID);
+	      double missval = vlistInqVarMissval(vlistID1, varID);
 	      if ( varinterp[varID] )
 		{
 		  /*
@@ -524,11 +533,11 @@ void *Vertintml(void *argument)
 		      int i, k;
 		      double *vl1, *vl2;
 
-		      for ( k = 1; k < nlevel; k++ )
+		      for ( int k = 1; k < nlevel; k++ )
 			{
 			  vl1  = vardata1[varID] + gridsize*(k-1);
 			  vl2  = vardata1[varID] + gridsize*(k);
-			  for ( i = 0; i < gridsize; i++ )
+			  for ( int i = 0; i < gridsize; i++ )
 			    vl1[i] = 0.5*(vl1[i] + vl2[i]);
 			}
 		      
@@ -536,17 +545,11 @@ void *Vertintml(void *argument)
 		    }
 		  */
                   double *hyb_press = NULL;
-		  if ( nlevel == nhlevh )
-		    {
-		      hyb_press = half_press;
-		    }
-		  else if ( nlevel == nhlevf )
-		    {
-		      hyb_press = full_press;
-		    }
+		  if      ( nlevel == nhlevh ) hyb_press = half_press;
+		  else if ( nlevel == nhlevf ) hyb_press = full_press;
 		  else
 		    {
-		      param = vlistInqVarParam(vlistID1, varID);
+		      int param = vlistInqVarParam(vlistID1, varID);
 		      cdiParamToString(param, paramstr, sizeof(paramstr));
 		      cdoAbort("Number of hybrid level differ from full/half level (param=%s)!", paramstr);
 		    }
@@ -562,7 +565,7 @@ void *Vertintml(void *argument)
 		      if ( nlevel == nhlevh )
 			cdoAbort("Temperature on half level unsupported!");
 
-		      if ( opertype == type_log && Extrapolate )
+		      if ( opertype == type_log && extrapolate )
 			cdoAbort("Log. extrapolation of temperature unsupported!");
 
 		      interp_T(sgeopot, vardata1[varID], vardata2[varID],
@@ -571,7 +574,7 @@ void *Vertintml(void *argument)
 		    }
 		  else if ( varID == gheightID )
 		    {
-		      for ( i = 0; i < gridsize; ++i )
+		      for ( int i = 0; i < gridsize; ++i )
 			vardata1[varID][gridsize*nlevel+i] = sgeopot[i]/PlanetGrav;
 
 		      interp_Z(sgeopot, vardata1[varID], vardata2[varID],
@@ -584,8 +587,7 @@ void *Vertintml(void *argument)
 			       vert_index, plev, nplev, gridsize, nlevel, missval);
 		    }
 		  
-		  if ( Extrapolate == 0 )
-		    memcpy(varnmiss[varID], pnmiss, nplev*sizeof(int));
+		  if ( !extrapolate ) memcpy(varnmiss[varID], pnmiss, nplev*sizeof(int));
 		}
 	    }
 	}
@@ -594,14 +596,14 @@ void *Vertintml(void *argument)
 	{
 	  if ( vars[varID] )
 	    {
-	      nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
+	      int nlevel = zaxisInqSize(vlistInqVarZaxis(vlistID2, varID));
 	      for ( levelID = 0; levelID < nlevel; levelID++ )
 		{
 		  //gridsize = gridInqSize(vlistInqVarGrid(vlistID2, varID));
-		  offset   = gridsize*levelID;
-		  single2  = vardata2[varID] + offset;
+		  size_t offset  = gridsize*levelID;
+		  double *single = vardata2[varID] + offset;
 		  streamDefRecord(streamID2, varID, levelID);
-		  streamWriteRecord(streamID2, single2, varnmiss[varID][levelID]);
+		  streamWriteRecord(streamID2, single, varnmiss[varID][levelID]);
 		}
 	    }
 	}
@@ -620,16 +622,14 @@ void *Vertintml(void *argument)
     }
 
   if ( pnmiss     ) Free(pnmiss);
-
   if ( sgeopot    ) Free(sgeopot);
   if ( ps_prog    ) Free(ps_prog);
   if ( vert_index ) Free(vert_index);
   if ( full_press ) Free(full_press);
   if ( half_press ) Free(half_press);
   if ( vct        ) Free(vct);
-  if ( rvct       ) Free(rvct);
 
-  listDelete(flist);
+  lista_destroy(flista);
 
   cdoFinish();
 
diff --git a/src/Vertstat.c b/src/Vertstat.c
index fd75f68..185e884 100644
--- a/src/Vertstat.c
+++ b/src/Vertstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -43,12 +43,11 @@
 int getSurfaceID(int vlistID)
 {
   int surfID = -1;
-  int zaxisID;
   int nzaxis = vlistNzaxis(vlistID);
 
   for ( int index = 0; index < nzaxis; ++index )
     {
-      zaxisID = vlistZaxis(vlistID, index);
+      int zaxisID = vlistZaxis(vlistID, index);
       if ( IS_SURFACE_LEVEL(zaxisID) )
 	{
 	  surfID = vlistZaxis(vlistID, index);
@@ -64,12 +63,11 @@ int getSurfaceID(int vlistID)
 static
 void setSurfaceID(int vlistID, int surfID)
 {
-  int zaxisID;
   int nzaxis = vlistNzaxis(vlistID);
 
   for ( int index = 0; index < nzaxis; ++index )
     {
-      zaxisID = vlistZaxis(vlistID, index);
+      int zaxisID = vlistZaxis(vlistID, index);
       if ( zaxisID != surfID || !IS_SURFACE_LEVEL(zaxisID) )
 	vlistChangeZaxisIndex(vlistID, index, surfID);
     }
@@ -97,7 +95,7 @@ void genLayerBounds(int nlev, double *levels, double *lbounds, double *ubounds)
 }
 
 
-int getLayerThickness(int genbounds, int index, int zaxisID, int nlev, double *thickness, double *weights)
+int getLayerThickness(bool genbounds, int index, int zaxisID, int nlev, double *thickness, double *weights)
 {
   int status = 0;
   int i;
@@ -105,7 +103,7 @@ int getLayerThickness(int genbounds, int index, int zaxisID, int nlev, double *t
   double *lbounds = (double *) Malloc(nlev*sizeof(double));
   double *ubounds = (double *) Malloc(nlev*sizeof(double));
 
-  zaxisInqLevels(zaxisID, levels);
+  cdoZaxisInqLevels(zaxisID, levels);
   if ( genbounds )
     {
       status = 2;
@@ -156,12 +154,10 @@ int getLayerThickness(int genbounds, int index, int zaxisID, int nlev, double *t
 
 void *Vertstat(void *argument)
 {
-  int recID, nrecs;
+  int nrecs;
   int gridID;
-  int i;
   int varID, levelID;
   int nmiss;
-  double missval;
   typedef struct {
     int zaxisID;
     int status;
@@ -184,14 +180,14 @@ void *Vertstat(void *argument)
                  cdoOperatorAdd("vertstd",  func_std,  1, NULL);
                  cdoOperatorAdd("vertstd1", func_std1, 1, NULL);
 
-  int operatorID  = cdoOperatorID();
-  int operfunc    = cdoOperatorF1(operatorID);
-  int needWeights = cdoOperatorF2(operatorID);
+  int operatorID   = cdoOperatorID();
+  int operfunc     = cdoOperatorF1(operatorID);
+  bool needWeights = cdoOperatorF2(operatorID);
 
-  int lmean   = operfunc == func_mean || operfunc == func_avg;
-  int lstd    = operfunc == func_std || operfunc == func_std1;
-  int lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
-  int divisor = operfunc == func_std1 || operfunc == func_var1;
+  bool lmean   = operfunc == func_mean || operfunc == func_avg;
+  bool lstd    = operfunc == func_std || operfunc == func_std1;
+  bool lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
+  int divisor  = operfunc == func_std1 || operfunc == func_var1;
 
   //int applyWeights = lmean;
 
@@ -219,7 +215,7 @@ void *Vertstat(void *argument)
   vert_t vert[nzaxis];
   if ( needWeights )
     {
-      int genbounds = FALSE;
+      bool genbounds = false;
       unsigned npar = operatorArgc();
       if ( npar > 0 )
 	{
@@ -229,7 +225,7 @@ void *Vertstat(void *argument)
 	    for ( unsigned i = 0; i < npar; i++ )
 	      cdoPrint("key %d = %s", i+1, parnames[i]);
 
-	  if ( strcmp(parnames[0], "genbounds") == 0 ) genbounds = TRUE;
+	  if ( strcmp(parnames[0], "genbounds") == 0 ) genbounds = true;
 	  else cdoAbort("Parameter >%s< unsupported! Supported parameter are: genbounds", parnames[0]);
 	}
       
@@ -256,22 +252,22 @@ void *Vertstat(void *argument)
 
   int gridsize = vlistGridsizeMax(vlistID1);
 
-  field_t field;
+  field_type field;
   field_init(&field);
   field.ptr = (double*) Malloc(gridsize*sizeof(double));
 
-  field_t *vars1 = (field_t*) Malloc(nvars*sizeof(field_t));
-  field_t *samp1 = (field_t*) Malloc(nvars*sizeof(field_t));
-  field_t *vars2 = NULL;
+  field_type *vars1 = (field_type*) Malloc(nvars*sizeof(field_type));
+  field_type *samp1 = (field_type*) Malloc(nvars*sizeof(field_type));
+  field_type *vars2 = NULL;
   if ( lvarstd )
-    vars2 = (field_t*) Malloc(nvars*sizeof(field_t));
+    vars2 = (field_type*) Malloc(nvars*sizeof(field_type));
 
   for ( varID = 0; varID < nvars; varID++ )
     {
       gridID   = vlistInqVarGrid(vlistID1, varID);
       gridsize = gridInqSize(gridID);
       zaxisID  = vlistInqVarZaxis(vlistID1, varID);
-      missval  = vlistInqVarMissval(vlistID1, varID);
+      double missval = vlistInqVarMissval(vlistID1, varID);
 
       field_init(&vars1[varID]);
       field_init(&samp1[varID]);
@@ -299,10 +295,9 @@ void *Vertstat(void *argument)
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
-
       streamDefTimestep(streamID2, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -360,7 +355,7 @@ void *Vertstat(void *argument)
 		  if ( samp1[varID].ptr == NULL )
 		    samp1[varID].ptr = (double *) Malloc(gridsize*sizeof(double));
 
-		  for ( i = 0; i < gridsize; i++ )
+		  for ( int i = 0; i < gridsize; i++ )
 		    if ( DBL_IS_EQUAL(vars1[varID].ptr[i], vars1[varID].missval) )
 		      samp1[varID].ptr[i] = 0.;
 		    else
@@ -382,11 +377,11 @@ void *Vertstat(void *argument)
 		  if ( samp1[varID].ptr == NULL )
 		    {
 		      samp1[varID].ptr = (double*) Malloc(gridsize*sizeof(double));
-		      for ( i = 0; i < gridsize; i++ )
+		      for ( int i = 0; i < gridsize; i++ )
 			samp1[varID].ptr[i] = vars1[varID].nsamp;
 		    }
 
-		  for ( i = 0; i < gridsize; i++ )
+		  for ( int i = 0; i < gridsize; i++ )
 		    if ( !DBL_IS_EQUAL(field.ptr[i], vars1[varID].missval) )
 		      samp1[varID].ptr[i] += layer_weight;
 		}
diff --git a/src/Vertwind.c b/src/Vertwind.c
index 1345415..b5049d5 100644
--- a/src/Vertwind.c
+++ b/src/Vertwind.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -21,7 +21,6 @@
       Vertwind    vertwind      Convert the vertical velocity to [m/s]
 */
 
-#include <ctype.h>
 
 #include <cdi.h>
 #include "cdo.h"
@@ -35,25 +34,14 @@
 
 void *Vertwind(void *argument)
 {
-  int streamID2;
-  int vlistID2;
-  int taxisID1, taxisID2;
-  int gridID, zaxisID, tsID;
-  int nlevel, nrecs, recID, code;
+  int nrecs;
   int varID, levelID;
-  int nvars, nvct = 0;
-  int gridsize, i;
-  int offset;
-  int nmiss, nmiss_out;
-  int temp_code, sq_code, ps_code, omega_code;
+  int nvct = 0;
+  int nmiss;
   int tempID = -1, sqID = -1, psID = -1, omegaID = -1;
   char varname[CDI_MAX_NAME];
   double *vct = NULL;
-  double tv, rho;
-  double *level = NULL;
-  double *temp = NULL, *sq = NULL, *omega = NULL, *wms = NULL;
-  double *fpress = NULL, *hpress = NULL, *ps_prog = NULL;
-  double missval_t, missval_sq, missval_wap, missval_out;
+  double *hpress = NULL, *ps_prog = NULL;
 
   cdoInitialize(argument);
 
@@ -63,31 +51,25 @@ void *Vertwind(void *argument)
 
   vlist_check_gridsize(vlistID1);
 
-  temp_code  = 130;
-  sq_code    = 133;
-  ps_code    = 134;
-  omega_code = 135;
+  int temp_code  = 130;
+  int sq_code    = 133;
+  int ps_code    = 134;
+  int omega_code = 135;
 
-  nvars = vlistNvars(vlistID1);
+  int nvars = vlistNvars(vlistID1);
   for ( varID = 0; varID < nvars; ++varID )
     {
-      gridID   = vlistInqVarGrid(vlistID1, varID);
-      zaxisID  = vlistInqVarZaxis(vlistID1, varID);
-      gridsize = gridInqSize(gridID);
-      nlevel   = zaxisInqSize(zaxisID);
-
-      code = vlistInqVarCode(vlistID1, varID);
+      int code = vlistInqVarCode(vlistID1, varID);
 
       if ( code <= 0 )
 	{
 	  vlistInqVarName(vlistID1, varID, varname);
-
 	  strtolower(varname);
 
-	  if      ( strcmp(varname, "st")    == 0 ) code = 130;
-	  else if ( strcmp(varname, "sq")    == 0 ) code = 133;
-	  else if ( strcmp(varname, "aps")   == 0 ) code = 134;
-	  else if ( strcmp(varname, "omega") == 0 ) code = 135;
+	  if      ( strcmp(varname, "st")    == 0 ) code = temp_code;
+	  else if ( strcmp(varname, "sq")    == 0 ) code = sq_code;
+	  else if ( strcmp(varname, "aps")   == 0 ) code = ps_code;
+	  else if ( strcmp(varname, "omega") == 0 ) code = omega_code;
 	}
 
       if      ( code == temp_code  ) tempID  = varID;
@@ -105,35 +87,35 @@ void *Vertwind(void *argument)
     }
 
   /* Get missing values */
-  missval_t   = vlistInqVarMissval(vlistID1, tempID);
-  missval_sq  = vlistInqVarMissval(vlistID1, sqID);
-  missval_wap = vlistInqVarMissval(vlistID1, omegaID);
-  missval_out = missval_wap;
+  double missval_t   = vlistInqVarMissval(vlistID1, tempID);
+  double missval_sq  = vlistInqVarMissval(vlistID1, sqID);
+  double missval_wap = vlistInqVarMissval(vlistID1, omegaID);
+  double missval_out = missval_wap;
 
-  gridID  = vlistInqVarGrid(vlistID1, omegaID);
-  zaxisID = vlistInqVarZaxis(vlistID1, omegaID);
+  int gridID  = vlistInqVarGrid(vlistID1, omegaID);
+  int zaxisID = vlistInqVarZaxis(vlistID1, omegaID);
 
   if ( psID == -1 && zaxisInqType(zaxisID) == ZAXIS_HYBRID )
     cdoAbort("Surface pressure (code 134) not found!");
 
-  gridsize = gridInqSize(gridID);
-  nlevel = zaxisInqSize(zaxisID);
-  level  = (double*) Malloc(nlevel*sizeof(double));
-  zaxisInqLevels(zaxisID, level);
+  int gridsize = gridInqSize(gridID);
+  int nlevel = zaxisInqSize(zaxisID);
+  double *level = (double*) Malloc(nlevel*sizeof(double));
+  cdoZaxisInqLevels(zaxisID, level);
 
-  temp    = (double*) Malloc(gridsize*nlevel*sizeof(double));
-  sq      = (double*) Malloc(gridsize*nlevel*sizeof(double));
-  omega   = (double*) Malloc(gridsize*nlevel*sizeof(double));
-  wms     = (double*) Malloc(gridsize*nlevel*sizeof(double));
-  fpress  = (double*) Malloc(gridsize*nlevel*sizeof(double));
+  double *temp    = (double*) Malloc(gridsize*nlevel*sizeof(double));
+  double *sq      = (double*) Malloc(gridsize*nlevel*sizeof(double));
+  double *omega   = (double*) Malloc(gridsize*nlevel*sizeof(double));
+  double *wms     = (double*) Malloc(gridsize*nlevel*sizeof(double));
+  double *fpress  = (double*) Malloc(gridsize*nlevel*sizeof(double));
 
 
   if ( zaxisInqType(zaxisID) == ZAXIS_PRESSURE )
     {
       for ( levelID = 0; levelID < nlevel; ++levelID )
 	{
-	  offset = levelID*gridsize;
-	  for ( i = 0; i < gridsize; ++i )
+	  size_t offset = (size_t)levelID*gridsize;
+	  for ( int i = 0; i < gridsize; ++i )
 	    fpress[offset+i] = level[levelID];
 	}
     }
@@ -159,7 +141,7 @@ void *Vertwind(void *argument)
   for ( levelID = 0; levelID < nlevel; ++levelID )
     vlistDefFlag(vlistID1, omegaID, levelID, TRUE);
 
-  vlistID2 = vlistCreate();
+  int vlistID2 = vlistCreate();
   vlistCopyFlag(vlistID2, vlistID1);
   vlistDefVarCode(vlistID2, 0, 40);
   vlistDefVarName(vlistID2, 0, "W");
@@ -167,26 +149,25 @@ void *Vertwind(void *argument)
   vlistDefVarUnits(vlistID2, 0, "m/s");
   vlistDefVarMissval(vlistID2, 0, missval_out);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
-
       streamDefTimestep(streamID2, tsID);
      
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
-	  offset = levelID*gridsize;
+	  size_t offset = (size_t)levelID*gridsize;
 
 	  if      ( varID == tempID )
 	    streamReadRecord(streamID1, temp+offset, &nmiss);
@@ -203,9 +184,9 @@ void *Vertwind(void *argument)
 
       for ( levelID = 0; levelID < nlevel; ++levelID )
 	{
-	  offset = levelID*gridsize;
+	  size_t offset = (size_t)levelID*gridsize;
 
-	  for ( i = 0; i < gridsize; ++i )
+	  for ( int i = 0; i < gridsize; ++i )
 	    {
 	      if ( DBL_IS_EQUAL(temp[offset+i],missval_t)    || 
 		   DBL_IS_EQUAL(omega[offset+i],missval_wap) ||
@@ -215,19 +196,14 @@ void *Vertwind(void *argument)
 		}
 	      else
 		{
-	          /* Virtuelle Temperatur bringt die Feuchteabhaengigkeit hinein */
-	          tv = temp[offset+i] * (1. + 0.608*sq[offset+i]);
-
-	          /*
-		    Die Dichte erhaelt man nun mit der Gasgleichung rho=p/(R*tv)
-		    Level in Pa!
-	          */
-	          rho = fpress[offset+i] / (R*tv);
+	          // Virtuelle Temperatur bringt die Feuchteabhaengigkeit hinein
+	          double tv = temp[offset+i] * (1. + 0.608*sq[offset+i]);
 
+	          // Die Dichte erhaelt man nun mit der Gasgleichung rho=p/(R*tv) Level in Pa!
+	          double rho = fpress[offset+i] / (R*tv);
 	          /*
-		    Nun daraus die Vertikalgeschwindigkeit im m/s, indem man die
-		    Vertikalgeschwindigkeit in Pa/s durch die Erdbeschleunigung
-		    und die Dichte teilt
+		    Nun daraus die Vertikalgeschwindigkeit im m/s, indem man die Vertikalgeschwindigkeit
+                    in Pa/s durch die Erdbeschleunigung und die Dichte teilt
 	          */
 	          wms[offset+i] = omega[offset+i]/(G*rho);
 	        }
@@ -236,13 +212,13 @@ void *Vertwind(void *argument)
 
       for ( levelID = 0; levelID < nlevel; ++levelID )
 	{
-	  nmiss_out = 0;
-	  for ( i = 0; i < gridsize; i++ )
+	  size_t offset = (size_t)levelID*gridsize;
+
+	  int nmiss_out = 0;
+	  for ( int i = 0; i < gridsize; i++ )
             if ( DBL_IS_EQUAL(wms[offset+i],missval_out) )
 	      nmiss_out++;
 
-	  offset = levelID*gridsize;
-
 	  streamDefRecord(streamID2, 0, levelID);
 	  streamWriteRecord(streamID2, wms+offset, nmiss_out);
 	}
diff --git a/src/Wct.c b/src/Wct.c
old mode 100755
new mode 100644
index 2f13f1f..8446ee5
--- a/src/Wct.c
+++ b/src/Wct.c
@@ -43,7 +43,7 @@ static double windchillTemperature(double t, double ff, double missval)
 }
 
 
-static void farexpr(field_t *field1, field_t field2, double (*expression)(double, double, double))
+static void farexpr(field_type *field1, field_type field2, double (*expression)(double, double, double))
 {
   int   i, len;
   const int     grid1    = field1->grid;
@@ -82,49 +82,41 @@ static void farexpr(field_t *field1, field_t field2, double (*expression)(double
    
 void *Wct(void *argument)
 {
-  int streamID1, streamID2, streamID3;
-  int gridsize;
-  int nrecs, nrecs2, recID;
-  int tsID;
+  int nrecs, nrecs2;
   int nmiss;
-  int gridID, zaxisID;
-  int varID1, varID2, varID3;
+  int varID1, varID2;
   int levelID1, levelID2;
-  int vlistID1, vlistID2, vlistID3;
-  int taxisID1, taxisID2, taxisID3;
-  field_t field1, field2;
 
   cdoInitialize(argument);
   cdoOperatorAdd("wct", 0, 0, NULL);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
-  streamID2 = streamOpenRead(cdoStreamName(1));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID2 = streamOpenRead(cdoStreamName(1));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = streamInqVlist(streamID2);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = streamInqVlist(streamID2);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = vlistInqTaxis(vlistID2);
+  int taxisID1 = vlistInqTaxis(vlistID1);
 
   vlistCompare(vlistID1, vlistID2, CMP_DIM);
   
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
   
+  field_type field1, field2;
   field_init(&field1);
   field_init(&field2);
-
   field1.ptr = (double*) Malloc(gridsize*sizeof(double));
   field2.ptr = (double*) Malloc(gridsize*sizeof(double));
 
   if ( cdoVerbose )
     cdoPrint("Number of timesteps: file1 %d, file2 %d", vlistNtsteps(vlistID1), vlistNtsteps(vlistID2));
 
-  vlistID3 = vlistCreate();
-  gridID   = vlistInqVarGrid(vlistID1, FIRST_VAR);
-  zaxisID  = vlistInqVarZaxis(vlistID1, FIRST_VAR);
-  varID3   = vlistDefVar(vlistID3, gridID, zaxisID, TSTEP_INSTANT);
+  int vlistID3 = vlistCreate();
+  int gridID   = vlistInqVarGrid(vlistID1, FIRST_VAR);
+  int zaxisID  = vlistInqVarZaxis(vlistID1, FIRST_VAR);
+  int varID3   = vlistDefVar(vlistID3, gridID, zaxisID, TSTEP_INSTANT);
 
-  taxisID3 = taxisCreate(TAXIS_RELATIVE);
+  int taxisID3 = taxisCreate(TAXIS_RELATIVE);
   taxisDefTunit(taxisID3, TUNIT_MINUTE);
   taxisDefCalendar(taxisID3, CALENDAR_STANDARD);
   taxisDefRdate(taxisID3, 19550101);
@@ -135,11 +127,11 @@ void *Wct(void *argument)
   vlistDefVarLongname(vlistID3, varID3, WCT_LONGNAME);
   vlistDefVarUnits(vlistID3, varID3, WCT_UNITS);
 
-  streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
+  int streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
 
   streamDefVlist(streamID3, vlistID3);
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       nrecs2 = streamInqTimestep(streamID2, tsID);
@@ -149,7 +141,7 @@ void *Wct(void *argument)
       taxisCopyTimestep(taxisID3, taxisID1);
       streamDefTimestep(streamID3, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID1, &levelID1);
 	  streamReadRecord(streamID1, field1.ptr, &nmiss);
diff --git a/src/Wind.c b/src/Wind.c
index af2f00e..7aff47c 100644
--- a/src/Wind.c
+++ b/src/Wind.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -27,15 +27,16 @@
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
+#include "grid.h"
 #include "pstream.h"
 #include "specspace.h"
-#include "list.h"
+#include "listarray.h"
 
 
 void *Wind(void *argument)
 {
   int nrecs;
-  int recID, varID, levelID;
+  int varID, levelID;
   int nlev = 0;
   int index, ngrids;
   int gridIDsp = -1, gridIDgp = -1;
@@ -165,9 +166,9 @@ void *Wind(void *argument)
 	  if ( gridID1 != -1 )
 	    {
 	      if ( operatorID == UV2DV )
-		ntr = nlat2ntr(gridInqYsize(gridID1));
+		ntr = nlat_to_ntr(gridInqYsize(gridID1));
 	      else
-		ntr = nlat2ntr_linear(gridInqYsize(gridID1));
+		ntr = nlat_to_ntr_linear(gridInqYsize(gridID1));
 
 	      if ( gridIDsp != -1 )
 		if ( ntr != gridInqTrunc(gridIDsp) ) gridIDsp = -1;
@@ -223,9 +224,9 @@ void *Wind(void *argument)
 	  if ( gridIDgp != -1 )
 	    {
 	      if ( operatorID == DV2UV )
-		ntr = nlat2ntr(gridInqYsize(gridIDgp));
+		ntr = nlat_to_ntr(gridInqYsize(gridIDgp));
 	      else
-		ntr = nlat2ntr_linear(gridInqYsize(gridIDgp));
+		ntr = nlat_to_ntr_linear(gridInqYsize(gridIDgp));
 	      
 	      if ( gridInqTrunc(gridIDsp) != ntr ) gridIDgp = -1;
 	    }
@@ -235,11 +236,11 @@ void *Wind(void *argument)
 	      char gridname[20];
 
 	      if ( operatorID == DV2UV )
-		sprintf(gridname, "t%dgrid", gridInqTrunc(gridIDsp));
+		snprintf(gridname, sizeof(gridname), "t%dgrid", gridInqTrunc(gridIDsp));
 	      else
-		sprintf(gridname, "tl%dgrid", gridInqTrunc(gridIDsp));
+		snprintf(gridname, sizeof(gridname), "tl%dgrid", gridInqTrunc(gridIDsp));
 	  
-	      gridIDgp = gridFromName(gridname);
+	      gridIDgp = grid_from_name(gridname);
 	    }
 
 	  gridID2 = gridIDgp;
@@ -319,7 +320,7 @@ void *Wind(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
diff --git a/src/Writegrid.c b/src/Writegrid.c
index 9196236..086a327 100644
--- a/src/Writegrid.c
+++ b/src/Writegrid.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -30,22 +30,15 @@
 
 void *Writegrid(void *argument)
 {
-  int streamID;
-  int vlistID;
-  int gridID;
-  long gridsize, i;
-  int gridtype;
-  int *mask = NULL;
-
   cdoInitialize(argument);
 
-  streamID = streamOpenRead(cdoStreamName(0));
+  int streamID = streamOpenRead(cdoStreamName(0));
 
-  vlistID = streamInqVlist(streamID);
-  gridID  = vlistGrid(vlistID, 0);
+  int vlistID = streamInqVlist(streamID);
+  int gridID  = vlistGrid(vlistID, 0);
 
-  gridtype = gridInqType(gridID);
-  gridsize = gridInqSize(gridID);
+  int gridtype = gridInqType(gridID);
+  int gridsize = gridInqSize(gridID);
 
   if ( gridtype == GRID_GME ) gridID = gridToUnstructured(gridID, 1);
 
@@ -55,7 +48,7 @@ void *Writegrid(void *argument)
   if ( gridInqXbounds(gridID, NULL) == 0 || gridInqYbounds(gridID, NULL) == 0 )
     cdoAbort("Grid corner missing!");
 
-  mask = (int*) Malloc(gridsize*sizeof(int));
+  int *mask = (int*) Malloc(gridsize*sizeof(int));
 
   if ( gridInqMask(gridID, NULL) )
     {
@@ -63,7 +56,7 @@ void *Writegrid(void *argument)
     }
   else
     {
-      for ( i = 0; i < gridsize; i++ ) mask[i] = 1;
+      for ( int i = 0; i < gridsize; i++ ) mask[i] = 1;
     }
       
   writeNCgrid(cdoStreamName(1)->args, gridID, mask);
diff --git a/src/Writerandom.c b/src/Writerandom.c
index b1b18a9..5e8f9fa 100644
--- a/src/Writerandom.c
+++ b/src/Writerandom.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -29,46 +29,40 @@
 
 void *Writerandom(void *argument)
 {
-  int streamID1, streamID2;
-  int vlistID1, vlistID2;
   int gridsize;
-  int recID, nrecs;
-  int tsID, varID, levelID;
-  int index, rindex, ipos;
-  double **recdata = NULL;
-  int *recvarID, *reclevelID, *recnmiss, *recindex;
-  int taxisID1, taxisID2;
-
+  int nrecs;
+  int varID, levelID;
+  int rindex;
 
   cdoInitialize(argument);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
 
       streamDefTimestep(streamID2, tsID);
 
-      recdata    = (double**) Malloc(nrecs*sizeof(double*));
-      recvarID   = (int*) Malloc(nrecs*sizeof(int));
-      reclevelID = (int*) Malloc(nrecs*sizeof(int));
-      recnmiss   = (int*) Malloc(nrecs*sizeof(int));
-      recindex   = (int*) Malloc(nrecs*sizeof(int));
+      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));
+      int *recindex   = (int*) Malloc(nrecs*sizeof(int));
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  gridsize = gridInqSize(vlistInqVarGrid(vlistID1, varID));
@@ -78,14 +72,14 @@ void *Writerandom(void *argument)
 	  streamReadRecord(streamID1, recdata[recID], &recnmiss[recID]);
 	}
 
-      for ( recID = 0; recID < nrecs; recID++ ) recindex[recID] = -1;
+      for ( int recID = 0; recID < nrecs; recID++ ) recindex[recID] = -1;
 
       for ( rindex = nrecs-1; rindex >= 0; rindex-- )
 	{
-	  index = (int) (rindex*((double)rand())/((double)RAND_MAX));
+	  int index = (int) (rindex*((double)rand())/((double)RAND_MAX));
 	  /*	printf("rindex %d %d\n", rindex, index); */
-	  ipos = -1;
-	  for ( recID = 0; recID < nrecs; recID++ )
+	  int ipos = -1;
+	  for ( int recID = 0; recID < nrecs; recID++ )
 	    {
 	      if ( recindex[recID] == -1 ) ipos++;
 	      if ( recindex[recID] == -1 && ipos == index )
@@ -97,14 +91,14 @@ void *Writerandom(void *argument)
 	}
 
       /*
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	printf("recID %d %d\n", recID, recindex[recID]);
       */
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	if ( recindex[recID] == -1 )
 	  cdoAbort("Internal problem! Random initialize.");
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  rindex   = recindex[recID];
 	  varID    = recvarID[rindex];
@@ -114,7 +108,7 @@ void *Writerandom(void *argument)
 	  streamWriteRecord(streamID2, recdata[rindex], recnmiss[rindex]);
 	}
 
-      for ( recID = 0; recID < nrecs; recID++ ) Free(recdata[recID]);
+      for ( int recID = 0; recID < nrecs; recID++ ) Free(recdata[recID]);
 
       Free(recdata);
       Free(recvarID);
diff --git a/src/XTimstat.c b/src/XTimstat.c
index b9856bd..3d1eca8 100644
--- a/src/XTimstat.c
+++ b/src/XTimstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -83,7 +83,7 @@ typedef struct {
   int tsIDnext;
   int streamID, nrecs;
   recinfo_t *recinfo;
-  field_t **vars;
+  field_type **vars;
 }
 readarg_t;
 
@@ -94,7 +94,7 @@ void *cdoReadTimestep(void *rarg)
 {
   int varID, levelID, nmiss;
   readarg_t *readarg = (readarg_t *) rarg;
-  field_t **input_vars = readarg->vars;
+  field_type **input_vars = readarg->vars;
   recinfo_t *recinfo = readarg->recinfo;
   int streamID = readarg->streamID;
   int tsIDnext = readarg->tsIDnext;
@@ -128,7 +128,7 @@ void *cdoReadTimestep(void *rarg)
 }
 
 static
-void cdoUpdateVars(int nvars, int vlistID, field_t **vars)
+void cdoUpdateVars(int nvars, int vlistID, field_type **vars)
 {
   void *tmp = NULL;
 
@@ -162,11 +162,10 @@ void *XTimstat(void *argument)
   int vdate = 0, vtime = 0;
   int vdate0 = 0, vtime0 = 0;
   int varID;
-  int nsets;
   int streamID3 = -1;
   int vlistID3, taxisID3 = -1;
   int nmiss;
-  int lvfrac = FALSE;
+  bool lvfrac = false;
   int nwpv; // number of words per value; real:1  complex:2
   char indate1[DATE_LEN+1], indate2[DATE_LEN+1];
   double vfrac = 1;
@@ -206,10 +205,10 @@ void *XTimstat(void *argument)
   int operfunc   = cdoOperatorF1(operatorID);
   int comparelen = cdoOperatorF2(operatorID);
 
-  int lmean   = operfunc == func_mean || operfunc == func_avg;
-  int lstd    = operfunc == func_std || operfunc == func_std1;
-  int lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
-  int divisor = operfunc == func_std1 || operfunc == func_var1;
+  bool lmean   = operfunc == func_mean || operfunc == func_avg;
+  bool lstd    = operfunc == func_std || operfunc == func_std1;
+  bool lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
+  int divisor  = operfunc == func_std1 || operfunc == func_var1;
 
   if ( operfunc == func_mean )
     {
@@ -218,7 +217,7 @@ void *XTimstat(void *argument)
 
       if ( oargc == 1 )
 	{
-	  lvfrac = TRUE;
+	  lvfrac = true;
 	  vfrac = atof(oargv[0]);
 	  if ( cdoVerbose ) cdoPrint("Set vfrac to %g", vfrac);
 	  if ( vfrac < 0 || vfrac > 1 ) cdoAbort("vfrac out of range!");
@@ -252,7 +251,7 @@ void *XTimstat(void *argument)
   if      ( comparelen == DAY_LEN )  freq = "day";
   else if ( comparelen == MON_LEN )  freq = "mon";
   else if ( comparelen == YEAR_LEN ) freq = "year";
-  if ( freq ) vlistDefAttTxt(vlistID2, CDI_GLOBAL, "frequency", (int)strlen(freq), freq);
+  if ( freq ) cdiDefAttTxt(vlistID2, CDI_GLOBAL, "frequency", (int)strlen(freq), freq);
 
   int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
@@ -272,7 +271,7 @@ void *XTimstat(void *argument)
 
       for ( varID = 0; varID < nvars; ++varID )
 	{
-	  vlistDefVarDatatype(vlistID3, varID, DATATYPE_INT32);
+	  vlistDefVarDatatype(vlistID3, varID, CDI_DATATYPE_INT32);
 	  vlistDefVarMissval(vlistID3, varID, -1);
 	  vlistDefVarUnits(vlistID3, varID, "");
 	  vlistDefVarAddoffset(vlistID3, varID, 0);
@@ -294,10 +293,10 @@ void *XTimstat(void *argument)
 
   int FIELD_MEMTYPE = 0;
   if ( CDO_Memtype == MEMTYPE_FLOAT ) FIELD_MEMTYPE = FIELD_FLT;
-  field_t **input_vars = field_malloc(vlistID1, FIELD_PTR | FIELD_PTR2 | FIELD_MEMTYPE);
-  field_t **vars1 = field_malloc(vlistID1, FIELD_PTR);
-  field_t **samp1 = field_malloc(vlistID1, FIELD_NONE);
-  field_t **vars2 = NULL;
+  field_type **input_vars = field_malloc(vlistID1, FIELD_PTR | FIELD_PTR2 | FIELD_MEMTYPE);
+  field_type **vars1 = field_malloc(vlistID1, FIELD_PTR);
+  field_type **samp1 = field_malloc(vlistID1, FIELD_NONE);
+  field_type **vars2 = NULL;
   if ( lvarstd ) vars2 = field_malloc(vlistID1, FIELD_PTR);
 
   readarg_t readarg;
@@ -305,7 +304,7 @@ void *XTimstat(void *argument)
   readarg.vars = input_vars;
 
   int lparallelread = CDO_Parallel_Read;
-  int ltsfirst = TRUE;
+  bool ltsfirst = true;
   void *read_task = NULL;
   void *readresult = NULL;
 
@@ -328,7 +327,7 @@ void *XTimstat(void *argument)
   tsID++;
   while ( TRUE )
     {
-      nsets = 0;
+      int nsets = 0;
       while ( nrecs > 0 )
 	{
 	  dtlist_taxisInqTimestep(dtlist, taxisID1, nsets);
@@ -346,7 +345,7 @@ void *XTimstat(void *argument)
 
           if ( ltsfirst || lparallelread == FALSE )
             {
-              ltsfirst = FALSE;
+              ltsfirst = false;
               readresult = cdoReadTimestep(&readarg);
             }
           else
@@ -374,8 +373,8 @@ void *XTimstat(void *argument)
                   int varID    = recinfo[recID].varID;
                   int levelID  = recinfo[recID].levelID;
 
-                  field_t *pvar1 = &vars1[varID][levelID];
-                  field_t *pinput_var = &input_vars[varID][levelID];
+                  field_type *pvar1 = &vars1[varID][levelID];
+                  field_type *pinput_var = &input_vars[varID][levelID];
 
                   int nwpv     = pvar1->nwpv;
                   int gridsize = pvar1->size;
@@ -406,8 +405,8 @@ void *XTimstat(void *argument)
                   int varID    = recinfo[recID].varID;
                   int levelID  = recinfo[recID].levelID;
                   
-                  field_t *pvar1 = &vars1[varID][levelID];
-                  field_t *pinput_var = &input_vars[varID][levelID];
+                  field_type *pvar1 = &vars1[varID][levelID];
+                  field_type *pinput_var = &input_vars[varID][levelID];
 
                   int nwpv     = pvar1->nwpv;
                   int gridsize = pvar1->size;
@@ -429,7 +428,7 @@ void *XTimstat(void *argument)
                   
 		  if ( lvarstd )
 		    {
-                      field_t *pvar2 = &vars2[varID][levelID];
+                      field_type *pvar2 = &vars2[varID][levelID];
 		      farsumq(pvar2, *pinput_var);
 		      farsum(pvar1, *pinput_var);
 		    }
@@ -445,8 +444,8 @@ void *XTimstat(void *argument)
               {
                 int varID   = recinfo[recID].varID;
                 int levelID = recinfo[recID].levelID;
-                field_t *pvar1 = &vars1[varID][levelID];
-                field_t *pvar2 = &vars2[varID][levelID];
+                field_type *pvar1 = &vars1[varID][levelID];
+                field_type *pvar2 = &vars2[varID][levelID];
 
 		if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
 
@@ -462,43 +461,47 @@ void *XTimstat(void *argument)
       if ( nrecs == 0 && nsets == 0 ) break;
 
       if ( lmean )
+        {
 #if defined(_OPENMP)
 #pragma omp parallel for default(none) shared(vlistID1, nsets, maxrecs, recinfo, vars1, samp1) if(maxrecs>1)
 #endif
-        for ( int recID = 0; recID < maxrecs; recID++ )
-          {
-            int varID   = recinfo[recID].varID;
-            int levelID = recinfo[recID].levelID;
-            field_t *pvar1 = &vars1[varID][levelID];
+          for ( int recID = 0; recID < maxrecs; recID++ )
+            {
+              int varID   = recinfo[recID].varID;
+              int levelID = recinfo[recID].levelID;
+              field_type *pvar1 = &vars1[varID][levelID];
 
-	    if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
+              if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
 
-            if ( samp1[varID][levelID].ptr == NULL )
-              farcdiv(pvar1, (double)nsets);
-            else
-              fardiv(pvar1, samp1[varID][levelID]);
-	  }
+              if ( samp1[varID][levelID].ptr == NULL )
+                farcdiv(pvar1, (double)nsets);
+              else
+                fardiv(pvar1, samp1[varID][levelID]);
+            }
+        }
       else if ( lvarstd )
-        for ( int recID = 0; recID < maxrecs; recID++ )
-          {
-            int varID   = recinfo[recID].varID;
-            int levelID = recinfo[recID].levelID;
-            field_t *pvar1 = &vars1[varID][levelID];
-            field_t *pvar2 = &vars2[varID][levelID];
+        {
+          for ( int recID = 0; recID < maxrecs; recID++ )
+            {
+              int varID   = recinfo[recID].varID;
+              int levelID = recinfo[recID].levelID;
+              field_type *pvar1 = &vars1[varID][levelID];
+              field_type *pvar2 = &vars2[varID][levelID];
 
-            if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
+              if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
 
-            if ( samp1[varID][levelID].ptr == NULL )
-              {
-                if ( lstd ) farcstd(pvar1, *pvar2, nsets, divisor);
-                else        farcvar(pvar1, *pvar2, nsets, divisor);
-              }
-            else
-              {
-                if ( lstd ) farstd(pvar1, *pvar2, samp1[varID][levelID], divisor);
-                else        farvar(pvar1, *pvar2, samp1[varID][levelID], divisor);
-	      }
-	  }
+              if ( samp1[varID][levelID].ptr == NULL )
+                {
+                  if ( lstd ) farcstd(pvar1, *pvar2, nsets, divisor);
+                  else        farcvar(pvar1, *pvar2, nsets, divisor);
+                }
+              else
+                {
+                  if ( lstd ) farstd(pvar1, *pvar2, samp1[varID][levelID], divisor);
+                  else        farvar(pvar1, *pvar2, samp1[varID][levelID], divisor);
+                }
+            }
+        }
 
       if ( cdoVerbose )
 	{
@@ -513,7 +516,7 @@ void *XTimstat(void *argument)
           {
             int varID   = recinfo[recID].varID;
             int levelID = recinfo[recID].levelID;
-            field_t *pvar1 = &vars1[varID][levelID];
+            field_type *pvar1 = &vars1[varID][levelID];
 
 	    if ( vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
 
@@ -555,7 +558,7 @@ void *XTimstat(void *argument)
 	{
           int varID   = recinfo[recID].varID;
           int levelID = recinfo[recID].levelID;
-          field_t *pvar1 = &vars1[varID][levelID];
+          field_type *pvar1 = &vars1[varID][levelID];
 
 	  if ( otsID && vlistInqVarTsteptype(vlistID1, varID) == TSTEP_CONSTANT ) continue;
 
diff --git a/src/YAR.c b/src/YAR.c
index 6f6c221..496a30a 100644
--- a/src/YAR.c
+++ b/src/YAR.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -172,7 +172,7 @@ void store_link_bilin(remapvars_t *rv, int dst_add, int src_add[4], double weigh
 
 } /* store_link_bilin */
 
-void yar_remap_bil(field_t *field1, field_t *field2)
+void yar_remap_bil(field_type *field1, field_type *field2)
 {
   int nlonIn, nlatIn;
   int nlonOut, nlatOut;
@@ -205,7 +205,7 @@ void yar_remap_bil(field_t *field1, field_t *field2)
 
   remap.src_grid.num_srch_bins = 0;
   remap.tgt_grid.num_srch_bins = 0;
-  remap.vars.pinit = FALSE;
+  remap.vars.pinit = false;
 
   if ( cdoTimer ) timer_start(timer_yar_remap_init);
   remap_grids_init(MAP_TYPE_BILINEAR, 0, gridIDin, &remap.src_grid, gridIDout, &remap.tgt_grid);
@@ -423,7 +423,7 @@ void yar_remap_bil(field_t *field1, field_t *field2)
 }
 
 
-void yar_remap_con(field_t *field1, field_t *field2)
+void yar_remap_con(field_type *field1, field_type *field2)
 {
   int nlonIn, nlatIn;
   int nlonOut, nlatOut;
@@ -454,7 +454,7 @@ void yar_remap_con(field_t *field1, field_t *field2)
 
   remap.src_grid.num_srch_bins = 0;
   remap.tgt_grid.num_srch_bins = 0;
-  remap.vars.pinit = FALSE;
+  remap.vars.pinit = false;
 
   if ( cdoTimer ) timer_start(timer_yar_remap_init);
   remap_grids_init(MAP_TYPE_CONSERV, 0, gridIDin, &remap.src_grid, gridIDout, &remap.tgt_grid);
@@ -741,7 +741,7 @@ void *YAR(void *argument)
 {
   int nrecs;
   int index;
-  int recID, varID, levelID;
+  int varID, levelID;
   int gridID1 = -1;
   int nmiss;
   int xinc = 0, yinc = 0;
@@ -766,7 +766,7 @@ void *YAR(void *argument)
 
   operatorInputArg("grid description file or name");
 
-  field_t field1, field2;
+  field_type field1, field2;
   field_init(&field1);
   field_init(&field2);
 
@@ -789,9 +789,6 @@ void *YAR(void *argument)
       if ( gridInqType(gridID1) != GRID_LONLAT && gridInqType(gridID1) != GRID_GAUSSIAN )
 	cdoAbort("Interpolation of %s data unsupported!", gridNamePtr(gridInqType(gridID1)) );
 
-      if ( gridIsRotated(gridID1) )
-	cdoAbort("Rotated grids not supported!");
-
       vlistChangeGridIndex(vlistID2, index, gridID2);
     }
 
@@ -800,19 +797,18 @@ void *YAR(void *argument)
   streamDefVlist(streamID2, vlistID2);
 
   int gridsize = vlistGridsizeMax(vlistID1);
-  double *array1   = (double*) Malloc(gridsize*sizeof(double));
+  double *array1 = (double*) Malloc(gridsize*sizeof(double));
 
   gridsize = gridInqSize(gridID2);
-  double *array2   = (double*) Malloc(gridsize*sizeof(double));
+  double *array2 = (double*) Malloc(gridsize*sizeof(double));
 
   int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       taxisCopyTimestep(taxisID2, taxisID1);
-
       streamDefTimestep(streamID2, tsID);
 	       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, array1, &nmiss);
diff --git a/src/Ydayarith.c b/src/Ydayarith.c
index 50568a4..f10961e 100644
--- a/src/Ydayarith.c
+++ b/src/Ydayarith.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -62,7 +62,7 @@ void *Ydayarith(void *argument)
 
   int gridsize = vlistGridsizeMax(vlistID1);
 
-  field_t field1, field2;
+  field_type field1, field2;
   field_init(&field1);
   field_init(&field2);
   field1.ptr = (double*) Malloc(gridsize*sizeof(double));
diff --git a/src/Ydaypctl.c b/src/Ydaypctl.c
index b6239b1..dd9719c 100644
--- a/src/Ydaypctl.c
+++ b/src/Ydaypctl.c
@@ -35,7 +35,6 @@ int getmonthday(int date);
 void *Ydaypctl(void *argument)
 {
   int varID;
-  int recID;
   int gridID;
   int vdate, vtime;
   int year, month, day, dayoy;
@@ -46,7 +45,7 @@ void *Ydaypctl(void *argument)
   int vdates1[NDAY], vtimes1[NDAY];
   int vdates2[NDAY];
   long nsets[NDAY];
-  field_t **vars1[NDAY];
+  field_type **vars1[NDAY];
   HISTOGRAM_SET *hsets[NDAY];
 
   cdoInitialize(argument);
@@ -96,7 +95,7 @@ void *Ydaypctl(void *argument)
 
   int gridsize = vlistGridsizeMax(vlistID1);
 
-  field_t field;
+  field_type field;
   field_init(&field);
   field.ptr = (double*) Malloc(gridsize*sizeof(double));
 
@@ -140,13 +139,13 @@ void *Ydaypctl(void *argument)
 	    }
 	}
       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
         {
           streamInqRecord(streamID2, &varID, &levelID);
 	  streamReadRecord(streamID2, vars1[dayoy][varID][levelID].ptr, &nmiss);
           vars1[dayoy][varID][levelID].nmiss = nmiss;
         }
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
         {
           streamInqRecord(streamID3, &varID, &levelID);
 	  streamReadRecord(streamID3, field.ptr, &nmiss);
@@ -184,7 +183,7 @@ void *Ydaypctl(void *argument)
       if ( vars1[dayoy] == NULL )
         cdoAbort("No data for day %d in %s and %s", dayoy, cdoStreamName(1)->args, cdoStreamName(2)->args);
         
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -225,7 +224,7 @@ void *Ydaypctl(void *argument)
 	taxisDefVtime(taxisID4, vtimes1[dayoy]);
 	streamDefTimestep(streamID4, otsID);
 
-	for ( recID = 0; recID < nrecords; recID++ )
+	for ( int recID = 0; recID < nrecords; recID++ )
 	  {
 	    varID    = recVarID[recID];
 	    levelID  = recLevelID[recID];
diff --git a/src/Ydaystat.c b/src/Ydaystat.c
index 51dfb5f..672f735 100644
--- a/src/Ydaystat.c
+++ b/src/Ydaystat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -47,7 +47,7 @@ void *Ydaystat(void *argument)
   int nmiss;
   int nlevel;
   int vdates[MAX_DOY], vtimes[MAX_DOY];
-  field_t **vars1[MAX_DOY], **vars2[MAX_DOY], **samp1[MAX_DOY];
+  field_type **vars1[MAX_DOY], **vars2[MAX_DOY], **samp1[MAX_DOY];
 
   cdoInitialize(argument);
 
@@ -64,10 +64,10 @@ void *Ydaystat(void *argument)
   int operatorID = cdoOperatorID();
   int operfunc = cdoOperatorF1(operatorID);
 
-  int lmean   = operfunc == func_mean || operfunc == func_avg;
-  int lstd    = operfunc == func_std || operfunc == func_std1;
-  int lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
-  int divisor = operfunc == func_std1 || operfunc == func_var1;
+  bool lmean   = operfunc == func_mean || operfunc == func_avg;
+  bool lstd    = operfunc == func_std || operfunc == func_std1;
+  bool lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
+  int divisor  = operfunc == func_std1 || operfunc == func_var1;
 
   for ( int dayoy = 0; dayoy < MAX_DOY; dayoy++ )
     {
@@ -99,7 +99,7 @@ void *Ydaystat(void *argument)
 
   int gridsize = vlistGridsizeMax(vlistID1);
 
-  field_t field;
+  field_type field;
   field_init(&field);
   field.ptr = (double*) Malloc(gridsize*sizeof(double));
 
diff --git a/src/Ydrunpctl.c b/src/Ydrunpctl.c
index 7244644..b355476 100644
--- a/src/Ydrunpctl.c
+++ b/src/Ydrunpctl.c
@@ -42,20 +42,18 @@ int getmonthday(int date)
 void *Ydrunpctl(void *argument)
 {
   int varID;
-  int recID;
   int gridID;
   int nrecs;
   int levelID;
   int inp, its;
   int nmiss;
   int nlevels;
-  field_t ***vars1 = NULL, **vars2[NDAY];
-  cdo_datetime_t *datetime;
+  int year, month, day, dayoy;
   int vdate, vtime;
   int vdates1[NDAY], vtimes1[NDAY];
   int vdates2[NDAY] /*, vtimes2[NDAY]*/;
   int nsets[NDAY];
-  int year, month, day, dayoy;
+  field_type **vars2[NDAY];
   HISTOGRAM_SET *hsets[NDAY];
     
   cdoInitialize(argument);
@@ -110,13 +108,13 @@ void *Ydrunpctl(void *argument)
 
   int gridsize = vlistGridsizeMax(vlistID1);
 
-  field_t field;
+  field_type field;
   field_init(&field);
   field.ptr = (double*) Malloc(gridsize*sizeof(double));
 
-  datetime = (cdo_datetime_t*) Malloc((ndates+1)*sizeof(cdo_datetime_t));
+  cdo_datetime_t *datetime = (cdo_datetime_t*) Malloc((ndates+1)*sizeof(cdo_datetime_t));
   
-  vars1 = (field_t ***) Malloc((ndates+1)*sizeof(field_t **));
+  field_type ***vars1 = (field_type ***) Malloc((ndates+1)*sizeof(field_type **));
   
   for ( its = 0; its < ndates; its++ )
     {
@@ -164,13 +162,13 @@ void *Ydrunpctl(void *argument)
 	    }
 	}
       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
         {
           streamInqRecord(streamID2, &varID, &levelID);
 	  streamReadRecord(streamID2, vars2[dayoy][varID][levelID].ptr, &nmiss);
           vars2[dayoy][varID][levelID].nmiss = nmiss;
         }
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
         {
           streamInqRecord(streamID3, &varID, &levelID);
 	  streamReadRecord(streamID3, field.ptr, &nmiss);
@@ -193,7 +191,7 @@ void *Ydrunpctl(void *argument)
       datetime[tsID].date = taxisInqVdate(taxisID1);
       datetime[tsID].time = taxisInqVtime(taxisID1);
 	
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -256,7 +254,7 @@ void *Ydrunpctl(void *argument)
       datetime[ndates-1].date = taxisInqVdate(taxisID1);
       datetime[ndates-1].time = taxisInqVtime(taxisID1);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  
@@ -306,7 +304,7 @@ void *Ydrunpctl(void *argument)
 	taxisDefVtime(taxisID4, vtimes1[dayoy]);
 	streamDefTimestep(streamID4, otsID);
 
-	for ( recID = 0; recID < nrecords; recID++ )
+	for ( int recID = 0; recID < nrecords; recID++ )
 	  {
 	    varID    = recVarID[recID];
 	    levelID  = recLevelID[recID];
diff --git a/src/Ydrunstat.c b/src/Ydrunstat.c
index f7bd640..9e88fbc 100644
--- a/src/Ydrunstat.c
+++ b/src/Ydrunstat.c
@@ -42,8 +42,8 @@
 typedef struct {
   int       vdate[NDAY];
   int       vtime[NDAY];  
-  field_t **vars1[NDAY]; 
-  field_t **vars2[NDAY];
+  field_type **vars1[NDAY]; 
+  field_type **vars2[NDAY];
   int       nsets[NDAY];
   int       vlist;
 }
@@ -53,18 +53,16 @@ YDAY_STATS;
 static YDAY_STATS *ydstatCreate(int vlistID);
 static void ydstatDestroy(YDAY_STATS *stats);
 static void ydstatUpdate(YDAY_STATS *stats, int vdate, int vtime, 
-  field_t **vars1, field_t **vars2, int nsets, int operfunc);
+  field_type **vars1, field_type **vars2, int nsets, int operfunc);
 static void ydstatFinalize(YDAY_STATS *stats, int operfunc);
 
 
 void *Ydrunstat(void *argument)
 {
   int varID;
-  int recID;
   int nrecs;
   int levelID;
   int tsID;
-  int otsID;
   int inp, its;
   int nmiss;
   int vdate, vtime;
@@ -88,7 +86,7 @@ void *Ydrunstat(void *argument)
   operatorInputArg("number of timesteps");
   int ndates = parameter2int(operatorArgv()[0]);
 
-  int lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
+  bool lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
   
   int streamID1 = streamOpenRead(cdoStreamName(0));
 
@@ -115,10 +113,10 @@ void *Ydrunstat(void *argument)
   cdo_datetime_t *datetime = (cdo_datetime_t*) Malloc((ndates+1)*sizeof(cdo_datetime_t));
   
   YDAY_STATS *stats = ydstatCreate(vlistID1);
-  field_t ***vars1 = (field_t ***) Malloc((ndates+1)*sizeof(field_t **));
-  field_t ***vars2 = NULL;
+  field_type ***vars1 = (field_type ***) Malloc((ndates+1)*sizeof(field_type **));
+  field_type ***vars2 = NULL;
   if ( lvarstd )
-    vars2 = (field_t ***) Malloc((ndates+1)*sizeof(field_t **));
+    vars2 = (field_type ***) Malloc((ndates+1)*sizeof(field_type **));
   
   for ( its = 0; its < ndates; its++ )
     {
@@ -136,7 +134,7 @@ void *Ydrunstat(void *argument)
       datetime[tsID].date = taxisInqVdate(taxisID1);
       datetime[tsID].time = taxisInqVtime(taxisID1);
 	
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -199,7 +197,7 @@ void *Ydrunstat(void *argument)
       datetime[ndates-1].date = taxisInqVdate(taxisID1);
       datetime[ndates-1].time = taxisInqVtime(taxisID1);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  
@@ -247,7 +245,7 @@ void *Ydrunstat(void *argument)
   */
   ydstatFinalize(stats, operfunc);
 
-  otsID = 0;
+  int otsID = 0;
 
   for ( dayoy = 0; dayoy < NDAY; dayoy++ )
     if ( stats->nsets[dayoy] )
@@ -256,7 +254,7 @@ void *Ydrunstat(void *argument)
 	taxisDefVtime(taxisID2, stats->vtime[dayoy]);
 	streamDefTimestep(streamID2, otsID);
 
-	for ( recID = 0; recID < nrecords; recID++ )
+	for ( int recID = 0; recID < nrecords; recID++ )
 	  {
 	    varID   = recVarID[recID];
 	    levelID = recLevelID[recID];
@@ -354,7 +352,7 @@ void ydstatDestroy(YDAY_STATS *stats)
 
 static
 void ydstatUpdate(YDAY_STATS *stats, int vdate, int vtime, 
-		  field_t **vars1, field_t **vars2, int nsets, int operfunc)
+		  field_type **vars1, field_type **vars2, int nsets, int operfunc)
 {
   int varID, levelID, nvars, nlevels;
   int gridsize;
diff --git a/src/Yearmonstat.c b/src/Yearmonstat.c
index f341dbe..fcbb29b 100644
--- a/src/Yearmonstat.c
+++ b/src/Yearmonstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -33,13 +33,10 @@
 void *Yearmonstat(void *argument)
 {
   int timestat_date = TIMESTAT_MEAN;
-  int gridsize;
   int vdate = 0, vtime = 0;
   int vdate0 = 0, vtime0 = 0;
   int nrecs;
-  int varID, levelID, recID;
-  int tsID;
-  int otsID;
+  int varID, levelID;
   int i;
   int dpm;
   int year0 = 0, month0 = 0;
@@ -49,8 +46,6 @@ void *Yearmonstat(void *argument)
   long nsets;
   double dsets;
   char vdatestr[32], vtimestr[32];
-  field_t **vars1 = NULL, **samp1 = NULL;
-  field_t field;
 
   cdoInitialize(argument);
 
@@ -84,16 +79,17 @@ void *Yearmonstat(void *argument)
   dtlist_set_stat(dtlist, timestat_date);
   dtlist_set_calendar(dtlist, calendar);
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
 
+  field_type field;
   field_init(&field);
   field.ptr = (double*) Malloc(gridsize*sizeof(double));
 
-  vars1 = field_malloc(vlistID1, FIELD_PTR);
-  samp1 = field_malloc(vlistID1, FIELD_NONE);
+  field_type **vars1 = field_malloc(vlistID1, FIELD_PTR);
+  field_type **samp1 = field_malloc(vlistID1, FIELD_NONE);
 
-  tsID    = 0;
-  otsID   = 0;
+  int tsID    = 0;
+  int otsID   = 0;
   while ( TRUE )
     {
       nsets = 0;
@@ -122,7 +118,7 @@ void *Yearmonstat(void *argument)
 
 	  dpm = days_per_month(calendar, year, month);
 
-	  for ( recID = 0; recID < nrecs; recID++ )
+	  for ( int recID = 0; recID < nrecs; recID++ )
 	    {
 	      streamInqRecord(streamID1, &varID, &levelID);
 
@@ -213,7 +209,7 @@ void *Yearmonstat(void *argument)
       dtlist_stat_taxisDefTimestep(dtlist, taxisID2, nsets);
       streamDefTimestep(streamID2, otsID);
 
-      for ( recID = 0; recID < nrecords; recID++ )
+      for ( int recID = 0; recID < nrecords; recID++ )
 	{
 	  varID   = recVarID[recID];
 	  levelID = recLevelID[recID];
diff --git a/src/Yhourarith.c b/src/Yhourarith.c
index 2e3f16a..2c99b2a 100644
--- a/src/Yhourarith.c
+++ b/src/Yhourarith.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -54,26 +54,18 @@ int hour_of_year(int vdate, int vtime)
       cdoAbort("Hour of year %d out of range (%s %s)!", houroy, vdatestr, vtimestr);
     }
 
-  return (houroy);
+  return houroy;
 }
 
 
 void *Yhourarith(void *argument)
 {
-  int operatorID;
-  int operfunc;
-  int streamID1, streamID2, streamID3;
-  int gridsize;
-  int nrecs, nvars, nlev, recID;
-  int tsID;
+  int nrecs, nlev;
   int varID, levelID;
   int offset;
-  int vlistID1, vlistID2, vlistID3;
-  int taxisID1, taxisID2, taxisID3;
   int vdate, vtime;
   int nmiss;
   int houroy;
-  field_t field1, field2;
   int **varnmiss2[MAX_HOUR];
   double **vardata2[MAX_HOUR];
 
@@ -84,39 +76,40 @@ void *Yhourarith(void *argument)
   cdoOperatorAdd("yhourmul", func_mul, 0, NULL);
   cdoOperatorAdd("yhourdiv", func_div, 0, NULL);
 
-  operatorID = cdoOperatorID();
-  operfunc = cdoOperatorF1(operatorID);
+  int operatorID = cdoOperatorID();
+  int operfunc = cdoOperatorF1(operatorID);
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
-  streamID2 = streamOpenRead(cdoStreamName(1));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID2 = streamOpenRead(cdoStreamName(1));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = streamInqVlist(streamID2);
-  vlistID3 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = streamInqVlist(streamID2);
+  int vlistID3 = vlistDuplicate(vlistID1);
 
   vlistCompare(vlistID1, vlistID2, CMP_ALL);
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
 
+  field_type field1, field2;
   field_init(&field1);
   field_init(&field2);
   field1.ptr = (double*) Malloc(gridsize*sizeof(double));
   field2.ptr = (double*) Malloc(gridsize*sizeof(double));
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = vlistInqTaxis(vlistID2);
-  taxisID3 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = vlistInqTaxis(vlistID2);
+  int taxisID3 = taxisDuplicate(taxisID1);
   vlistDefTaxis(vlistID3, taxisID3);
 
-  streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
+  int streamID3 = streamOpenWrite(cdoStreamName(2), cdoFiletype());
 
   streamDefVlist(streamID3, vlistID3);
 
-  nvars  = vlistNvars(vlistID2);
+  int nvars  = vlistNvars(vlistID2);
 
   for ( houroy = 0; houroy < MAX_HOUR ; ++houroy ) vardata2[houroy] = NULL;
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID2, tsID)) )
     {
       vdate = taxisInqVdate(taxisID2);
@@ -136,7 +129,7 @@ void *Yhourarith(void *argument)
 	  varnmiss2[houroy][varID] = (int*) Malloc(nlev*sizeof(int));
 	}
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID2, &varID, &levelID);
 
@@ -164,7 +157,7 @@ void *Yhourarith(void *argument)
 
       streamDefTimestep(streamID3, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, field1.ptr, &nmiss);
diff --git a/src/Yhourstat.c b/src/Yhourstat.c
index 6b6c939..8879795 100644
--- a/src/Yhourstat.c
+++ b/src/Yhourstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -59,34 +59,23 @@ int hour_of_year(int vdate, int vtime)
       cdoAbort("Hour of year %d out of range (%s %s)!", houroy, vdatestr, vtimestr);
     }
 
-  return (houroy);
+  return houroy;
 }
 
 
 void *Yhourstat(void *argument)
 {
-  int operatorID;
-  int operfunc;
-  int gridsize;
   int i;
   int varID;
-  int recID;
   int vdate, vtime;
   int houroy;
-  int nrecs, nrecords;
+  int nrecs;
   int levelID;
-  int tsID;
-  int otsID;
   int nsets[MAX_HOUR];
-  int streamID1, streamID2;
-  int vlistID1, vlistID2, taxisID1, taxisID2;
   int nmiss;
-  int nvars, nlevel;
-  int *recVarID, *recLevelID;
+  int nlevel;
   int vdates[MAX_HOUR], vtimes[MAX_HOUR];
-  int lmean = FALSE, lvarstd = FALSE, lstd = FALSE;
-  field_t **vars1[MAX_HOUR], **vars2[MAX_HOUR], **samp1[MAX_HOUR];
-  field_t field;
+  field_type **vars1[MAX_HOUR], **vars2[MAX_HOUR], **samp1[MAX_HOUR];
 
   cdoInitialize(argument);
 
@@ -100,12 +89,12 @@ void *Yhourstat(void *argument)
   cdoOperatorAdd("yhourstd",  func_std,  0, NULL);
   cdoOperatorAdd("yhourstd1", func_std1, 0, NULL);
 
-  operatorID = cdoOperatorID();
-  operfunc = cdoOperatorF1(operatorID);
+  int operatorID = cdoOperatorID();
+  int operfunc = cdoOperatorF1(operatorID);
 
-  lmean   = operfunc == func_mean || operfunc == func_avg;
-  lstd    = operfunc == func_std || operfunc == func_std1;
-  lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
+  bool lmean   = operfunc == func_mean || operfunc == func_avg;
+  bool lstd    = operfunc == func_std || operfunc == func_std1;
+  bool lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
   int divisor = operfunc == func_std1 || operfunc == func_var1;
 
   for ( houroy = 0; houroy < MAX_HOUR; ++houroy )
@@ -116,32 +105,34 @@ void *Yhourstat(void *argument)
       nsets[houroy] = 0;
     }
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   if ( taxisHasBounds(taxisID2) ) taxisDeleteBounds(taxisID2);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  nvars    = vlistNvars(vlistID1);
-  nrecords = vlistNrecs(vlistID1);
+  int nvars    = vlistNvars(vlistID1);
+  int nrecords = vlistNrecs(vlistID1);
 
-  recVarID   = (int*) Malloc(nrecords*sizeof(int));
-  recLevelID = (int*) Malloc(nrecords*sizeof(int));
+  int *recVarID   = (int*) Malloc(nrecords*sizeof(int));
+  int *recLevelID = (int*) Malloc(nrecords*sizeof(int));
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
+
+  field_type field;
   field_init(&field);
   field.ptr = (double*) Malloc(gridsize*sizeof(double));
 
-  tsID = 0;
-  otsID = 0;
+  int tsID = 0;
+  int otsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       vdate = taxisInqVdate(taxisID1);
@@ -162,7 +153,7 @@ void *Yhourstat(void *argument)
 	    vars2[houroy] = field_malloc(vlistID1, FIELD_PTR);
 	}
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -282,7 +273,7 @@ void *Yhourstat(void *argument)
 	taxisDefVtime(taxisID2, vtimes[houroy]);
 	streamDefTimestep(streamID2, otsID);
 
-	for ( recID = 0; recID < nrecords; recID++ )
+	for ( int recID = 0; recID < nrecords; recID++ )
 	  {
 	    varID    = recVarID[recID];
 	    levelID  = recLevelID[recID];
diff --git a/src/Ymonarith.c b/src/Ymonarith.c
index 073456a..c708841 100644
--- a/src/Ymonarith.c
+++ b/src/Ymonarith.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -40,13 +40,11 @@
 void *Ymonarith(void *argument)
 {
   enum {MONTHLY, SEASONAL};
-  int nrecs, nvars, nlev, recID;
-  int tsID;
+  int nrecs, nlev;
   int varID, levelID;
   int offset;
   int nmiss;
   int vdate, year, mon, day;
-  field_t field1, field2;
   int **varnmiss2[MAX_MON];
   double **vardata2[MAX_MON];
   const char *seas_name[4];
@@ -77,6 +75,7 @@ void *Ymonarith(void *argument)
 
   int gridsize = vlistGridsizeMax(vlistID1);
 
+  field_type field1, field2;
   field_init(&field1);
   field_init(&field2);
   field1.ptr = (double*) Malloc(gridsize*sizeof(double));
@@ -91,13 +90,13 @@ void *Ymonarith(void *argument)
 
   streamDefVlist(streamID3, vlistID3);
 
-  nvars  = vlistNvars(vlistID2);
+  int nvars  = vlistNvars(vlistID2);
 
   if ( opertype == SEASONAL ) get_season_name(seas_name);
 
   for ( mon = 0; mon < MAX_MON ; mon++ ) vardata2[mon] = NULL;
 
-  tsID = 0;
+  int tsID = 0;
   while ( (nrecs = streamInqTimestep(streamID2, tsID)) )
     {
       vdate = taxisInqVdate(taxisID2);
@@ -127,7 +126,7 @@ void *Ymonarith(void *argument)
 	  varnmiss2[mon][varID] = (int*) Malloc(nlev*sizeof(int));
 	}
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID2, &varID, &levelID);
 
@@ -162,10 +161,9 @@ void *Ymonarith(void *argument)
 	}
 
       taxisCopyTimestep(taxisID3, taxisID1);
-
       streamDefTimestep(streamID3, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, field1.ptr, &nmiss);
diff --git a/src/Ymonpctl.c b/src/Ymonpctl.c
index 3ec0c8e..c561c94 100644
--- a/src/Ymonpctl.c
+++ b/src/Ymonpctl.c
@@ -41,7 +41,6 @@ int getmonth(int date)
 void *Ymonpctl(void *argument)
 {
   int varID;
-  int recID;
   int gridID;
   int vdate, vtime;
   int year, month, day;
@@ -51,7 +50,7 @@ void *Ymonpctl(void *argument)
   int vdates1[NMONTH], vtimes1[NMONTH];
   int vdates2[NMONTH];
   long nsets[NMONTH];
-  field_t **vars1[NMONTH];
+  field_type **vars1[NMONTH];
   HISTOGRAM_SET *hsets[NMONTH];
 
   cdoInitialize(argument);
@@ -101,7 +100,7 @@ void *Ymonpctl(void *argument)
 
   int gridsize = vlistGridsizeMax(vlistID1);
 
-  field_t field;
+  field_type field;
   field_init(&field);
   field.ptr = (double*) Malloc(gridsize*sizeof(double));
 
@@ -139,13 +138,13 @@ void *Ymonpctl(void *argument)
 	    }
 	}
       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
         {
           streamInqRecord(streamID2, &varID, &levelID);
 	  streamReadRecord(streamID2, vars1[month][varID][levelID].ptr, &nmiss);
           vars1[month][varID][levelID].nmiss = nmiss;
         }
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
         {
           streamInqRecord(streamID3, &varID, &levelID);
 	  streamReadRecord(streamID3, field.ptr, &nmiss);
@@ -177,7 +176,7 @@ void *Ymonpctl(void *argument)
       if ( vars1[month] == NULL )
         cdoAbort("No data for month %d in %s and %s", month, cdoStreamName(1)->args, cdoStreamName(2)->args);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -218,7 +217,7 @@ void *Ymonpctl(void *argument)
 	taxisDefVtime(taxisID4, vtimes1[month]);
 	streamDefTimestep(streamID4, otsID);
 
-	for ( recID = 0; recID < nrecords; recID++ )
+	for ( int recID = 0; recID < nrecords; recID++ )
 	  {
 	    varID    = recVarID[recID];
 	    levelID  = recLevelID[recID];
diff --git a/src/Ymonstat.c b/src/Ymonstat.c
index 0dd2db4..1ae7634 100644
--- a/src/Ymonstat.c
+++ b/src/Ymonstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -49,36 +49,26 @@ int cmpint(const void *s1, const void *s2)
   if      ( *x < *y ) cmp = -1;
   else if ( *x > *y ) cmp =  1;
 
-  return (cmp);
+  return cmp;
 }
 */
 
 void *Ymonstat(void *argument)
 {
-  int operatorID;
-  int operfunc;
-  int gridsize;
   int i;
   int varID;
-  int recID;
   int vdate, vtime;
   int year, month, day;
-  int nrecs, nrecords;
+  int nrecs;
   int levelID;
-  int tsID;
-  int otsID;
   int nsets[NMONTH];
-  int streamID1, streamID2;
-  int vlistID1, vlistID2, taxisID1, taxisID2;
   int nmiss;
-  int nvars, nlevel;
-  int *recVarID, *recLevelID;
+  int nlevel;
   int vdates[NMONTH], vtimes[NMONTH];
   int mon[NMONTH];
   int nmon = 0;
-  int lmean = FALSE, lvarstd = FALSE, lstd = FALSE;
-  field_t **vars1[NMONTH], **vars2[NMONTH], **samp1[NMONTH];
-  field_t field;
+  field_type **vars1[NMONTH], **vars2[NMONTH], **samp1[NMONTH];
+  field_type field;
 
   cdoInitialize(argument);
 
@@ -92,13 +82,13 @@ void *Ymonstat(void *argument)
   cdoOperatorAdd("ymonstd",  func_std,  0, NULL);
   cdoOperatorAdd("ymonstd1", func_std1, 0, NULL);
 
-  operatorID = cdoOperatorID();
-  operfunc = cdoOperatorF1(operatorID);
+  int operatorID = cdoOperatorID();
+  int operfunc = cdoOperatorF1(operatorID);
 
-  lmean   = operfunc == func_mean || operfunc == func_avg;
-  lstd    = operfunc == func_std || operfunc == func_std1;
-  lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
-  int divisor = operfunc == func_std1 || operfunc == func_var1;
+  bool lmean   = operfunc == func_mean || operfunc == func_avg;
+  bool lstd    = operfunc == func_std || operfunc == func_std1;
+  bool lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
+  int divisor  = operfunc == func_std1 || operfunc == func_var1;
 
   for ( month = 0; month < NMONTH; month++ )
     {
@@ -108,32 +98,32 @@ void *Ymonstat(void *argument)
       nsets[month] = 0;
     }
 
-  streamID1 = streamOpenRead(cdoStreamName(0));
+  int streamID1 = streamOpenRead(cdoStreamName(0));
 
-  vlistID1 = streamInqVlist(streamID1);
-  vlistID2 = vlistDuplicate(vlistID1);
+  int vlistID1 = streamInqVlist(streamID1);
+  int vlistID2 = vlistDuplicate(vlistID1);
 
-  taxisID1 = vlistInqTaxis(vlistID1);
-  taxisID2 = taxisDuplicate(taxisID1);
+  int taxisID1 = vlistInqTaxis(vlistID1);
+  int taxisID2 = taxisDuplicate(taxisID1);
   if ( taxisHasBounds(taxisID2) ) taxisDeleteBounds(taxisID2);
   vlistDefTaxis(vlistID2, taxisID2);
 
-  streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
+  int streamID2 = streamOpenWrite(cdoStreamName(1), cdoFiletype());
 
   streamDefVlist(streamID2, vlistID2);
 
-  nvars    = vlistNvars(vlistID1);
-  nrecords = vlistNrecs(vlistID1);
+  int nvars    = vlistNvars(vlistID1);
+  int nrecords = vlistNrecs(vlistID1);
 
-  recVarID   = (int*) Malloc(nrecords*sizeof(int));
-  recLevelID = (int*) Malloc(nrecords*sizeof(int));
+  int *recVarID   = (int*) Malloc(nrecords*sizeof(int));
+  int *recLevelID = (int*) Malloc(nrecords*sizeof(int));
 
-  gridsize = vlistGridsizeMax(vlistID1);
+  int gridsize = vlistGridsizeMax(vlistID1);
   field_init(&field);
   field.ptr = (double*) Malloc(gridsize*sizeof(double));
 
-  tsID = 0;
-  otsID = 0;
+  int tsID = 0;
+  int otsID = 0;
   while ( (nrecs = streamInqTimestep(streamID1, tsID)) )
     {
       vdate = taxisInqVdate(taxisID1);
@@ -158,7 +148,7 @@ void *Ymonstat(void *argument)
 	    vars2[month] = field_malloc(vlistID1, FIELD_PTR);
 	}
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -306,7 +296,7 @@ void *Ymonstat(void *argument)
       taxisDefVtime(taxisID2, vtimes[month]);
       streamDefTimestep(streamID2, otsID);
 
-      for ( recID = 0; recID < nrecords; recID++ )
+      for ( int recID = 0; recID < nrecords; recID++ )
 	{
 	  varID    = recVarID[recID];
 	  levelID  = recLevelID[recID];
diff --git a/src/Yseaspctl.c b/src/Yseaspctl.c
index 014c697..cdfd255 100644
--- a/src/Yseaspctl.c
+++ b/src/Yseaspctl.c
@@ -44,7 +44,6 @@ int getmonthday(int date);
 void *Yseaspctl(void *argument)
 {
   int varID;
-  int recID;
   int gridID;
   int vdate, vtime;
   int year, month, day, seas;
@@ -54,7 +53,7 @@ void *Yseaspctl(void *argument)
   int nlevels;
   long nsets[NSEAS];
   date_time_t datetime1[NSEAS], datetime2[NSEAS];
-  field_t **vars1[NSEAS];
+  field_type **vars1[NSEAS];
   HISTOGRAM_SET *hsets[NSEAS];
 
   cdoInitialize(argument);
@@ -108,7 +107,7 @@ void *Yseaspctl(void *argument)
 
   int gridsize = vlistGridsizeMax(vlistID1);
 
-  field_t field;
+  field_type field;
   field_init(&field);
   field.ptr = (double*) Malloc(gridsize*sizeof(double));
 
@@ -146,13 +145,13 @@ void *Yseaspctl(void *argument)
 	    }
 	}
       
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
         {
           streamInqRecord(streamID2, &varID, &levelID);
 	  streamReadRecord(streamID2, vars1[seas][varID][levelID].ptr, &nmiss);
           vars1[seas][varID][levelID].nmiss = nmiss;
         }
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
         {
           streamInqRecord(streamID3, &varID, &levelID);
 	  streamReadRecord(streamID3, field.ptr, &nmiss);
@@ -188,7 +187,7 @@ void *Yseaspctl(void *argument)
       if ( vars1[seas] == NULL )
         cdoAbort("No data for season %d in %s and %s", seas, cdoStreamName(1)->args, cdoStreamName(2)->args);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -229,7 +228,7 @@ void *Yseaspctl(void *argument)
 	taxisDefVtime(taxisID4, datetime1[seas].vtime);
 	streamDefTimestep(streamID4, otsID);
 
-	for ( recID = 0; recID < nrecords; recID++ )
+	for ( int recID = 0; recID < nrecords; recID++ )
 	  {
 	    varID    = recVarID[recID];
 	    levelID  = recLevelID[recID];
diff --git a/src/Yseasstat.c b/src/Yseasstat.c
index e8795e9..09c247d 100644
--- a/src/Yseasstat.c
+++ b/src/Yseasstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -47,7 +47,6 @@ date_time_t;
 void set_date(int vdate_new, int vtime_new, date_time_t *datetime)
 {
   int year, month, day;
-
   cdiDecodeDate(vdate_new, &year, &month, &day);
   if ( month == 12 ) vdate_new = cdiEncodeDate(year-1, month, day);
 
@@ -63,7 +62,6 @@ void *Yseasstat(void *argument)
 {
   int i;
   int varID;
-  int recID;
   int vdate, vtime;
   int year, month, day, seas;
   int nrecs;
@@ -72,7 +70,7 @@ void *Yseasstat(void *argument)
   int nmiss;
   int nlevel;
   date_time_t datetime[NSEAS];
-  field_t **vars1[NSEAS], **vars2[NSEAS], **samp1[NSEAS];
+  field_type **vars1[NSEAS], **vars2[NSEAS], **samp1[NSEAS];
 
   cdoInitialize(argument);
 
@@ -99,10 +97,10 @@ void *Yseasstat(void *argument)
       datetime[seas].vtime = 0;
     }
 
-  int lmean   = operfunc == func_mean || operfunc == func_avg;
-  int lstd    = operfunc == func_std || operfunc == func_std1;
-  int lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
-  int divisor = operfunc == func_std1 || operfunc == func_var1;
+  bool lmean   = operfunc == func_mean || operfunc == func_avg;
+  bool lstd    = operfunc == func_std || operfunc == func_std1;
+  bool lvarstd = operfunc == func_std || operfunc == func_var || operfunc == func_std1 || operfunc == func_var1;
+  int divisor  = operfunc == func_std1 || operfunc == func_var1;
 
   int streamID1 = streamOpenRead(cdoStreamName(0));
 
@@ -126,7 +124,7 @@ void *Yseasstat(void *argument)
 
   int gridsize = vlistGridsizeMax(vlistID1);
 
-  field_t field;
+  field_type field;
   field_init(&field);
   field.ptr = (double*) Malloc(gridsize*sizeof(double));
 
@@ -150,7 +148,7 @@ void *Yseasstat(void *argument)
 	    vars2[seas] = field_malloc(vlistID1, FIELD_PTR);
 	}
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 
@@ -270,7 +268,7 @@ void *Yseasstat(void *argument)
 	taxisDefVtime(taxisID2, datetime[seas].vtime);
 	streamDefTimestep(streamID2, otsID);
 
-	for ( recID = 0; recID < nrecords; recID++ )
+	for ( int recID = 0; recID < nrecords; recID++ )
 	  {
 	    varID    = recVarID[recID];
 	    levelID  = recLevelID[recID];
diff --git a/src/Zonstat.c b/src/Zonstat.c
index cda3eed..0664a6d 100644
--- a/src/Zonstat.c
+++ b/src/Zonstat.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.1
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -45,7 +45,7 @@ void *Zonstat(void *argument)
   int zongridID = -1;
   int index;
   int nmiss;
-  int recID, nrecs;
+  int nrecs;
   int varID, levelID;
 
   cdoInitialize(argument);
@@ -137,7 +137,7 @@ void *Zonstat(void *argument)
 
   int lim = vlistGridsizeMax(vlistID1);
 
-  field_t field1, field2;
+  field_type field1, field2;
   field_init(&field2);
   field_init(&field2);
   field1.ptr  = (double*) Malloc(lim*sizeof(double));
@@ -151,7 +151,7 @@ void *Zonstat(void *argument)
 
       streamDefTimestep(streamID2, tsID);
 
-      for ( recID = 0; recID < nrecs; recID++ )
+      for ( int recID = 0; recID < nrecs; recID++ )
 	{
 	  streamInqRecord(streamID1, &varID, &levelID);
 	  streamReadRecord(streamID1, field1.ptr, &nmiss);
diff --git a/src/after_fctrans.c b/src/after_fctrans.c
index 6b84069..3541002 100644
--- a/src/after_fctrans.c
+++ b/src/after_fctrans.c
@@ -40,7 +40,7 @@
 
 long get_nfft(void)
 {
-  return ((long) NFFT);
+  return (long) NFFT;
 }
 
 
diff --git a/src/after_namelist.c b/src/after_namelist.c
index 817eaf6..d37e4a9 100644
--- a/src/after_namelist.c
+++ b/src/after_namelist.c
@@ -8,12 +8,10 @@
 static
 char *amatch(char *msr, const char *sub)
 {
-  int i,nm,ns;
+  int nm = strlen(msr);
+  int ns = strlen(sub);
 
-  nm = strlen(msr);
-  ns = strlen(sub);
-
-  for (i = 0; i < nm-ns; i++)
+  for ( int i = 0; i < nm-ns; i++ )
     if (strncmp (msr+i,sub,ns) == 0) return (msr+i+ns);
 
   return NULL;
@@ -22,28 +20,26 @@ char *amatch(char *msr, const char *sub)
 
 int scan_par_obsolate(char *namelist, const char *name, int def)
 {
-  char *cp;
   int value;
 
-  cp = amatch(namelist, name);
+  char *cp = amatch(namelist, name);
 
   if ( cp == NULL ) value = def;
-  else              value = atoi (cp);
+  else              value = atoi(cp);
   /*
   fprintf(stdout, " %16.16s = %6d ", name, value);
   if ( value == def ) fprintf(stdout, " (default)\n");
   else                fprintf(stdout, "          \n");
   */
-  return (value);
+  return value;
 }
 
 
 int scan_par(int verbose, char *namelist, const char *name, int def)
 {
-  char *cp;
   int value;
 
-  cp = amatch(namelist, name);
+  char *cp = amatch(namelist, name);
 
   if ( cp == NULL ) value = def;
   else              value = atoi (cp);
@@ -55,17 +51,16 @@ int scan_par(int verbose, char *namelist, const char *name, int def)
       else                fprintf(stdout, "          \n");
     }
   
-  return (value);
+  return value;
 }
 
 
 int scan_time(int verbose, char *namelist, int *hours, int max_hours)
 {
-  char *cp, *icp;
-  int time;
+  char *icp;
   int nrqh = 0;
 
-  cp = amatch (namelist, "timesel");
+  char *cp = amatch (namelist, "timesel");
   if ( cp == NULL )
     {
       hours[nrqh++] = -1;
@@ -73,7 +68,7 @@ int scan_time(int verbose, char *namelist, int *hours, int max_hours)
       return (nrqh);
     }
 
-  time = (int) strtol (cp, &icp, 10);
+  int time = (int) strtol (cp, &icp, 10);
 
   while ((char *)icp != (char *)cp && nrqh < max_hours)
     {
@@ -89,19 +84,19 @@ int scan_time(int verbose, char *namelist, int *hours, int max_hours)
       fprintf(stdout, "\n");
     }
   
-  return (nrqh);
+  return nrqh;
 }
 
 
 void scan_code(char *namelist, struct Variable *vars, int maxCodes, int *numCodes)
 {
-  char *cp, *icp;
-  int code, ncodes = 0;
+  char *icp;
+  int ncodes = 0;
 
-  cp = amatch(namelist, "code");
+  char *cp = amatch(namelist, "code");
   if ( cp != NULL )
     {
-      code = (int) strtol(cp,&icp,10);
+      int code = (int) strtol(cp,&icp,10);
       while ( code > 0 && code < maxCodes )
 	{
 	  ncodes++;
@@ -117,11 +112,11 @@ void scan_code(char *namelist, struct Variable *vars, int maxCodes, int *numCode
 
 void scan_darray(char *namelist, const char *name, double *values, int maxValues, int *numValues)
 {
-  char *cp,*icp;
+  char *icp;
   double val;
   int nval = 0;
 
-  cp = amatch(namelist, name);
+  char *cp = amatch(namelist, name);
 
   if ( cp != NULL )
     {
diff --git a/src/afterburnerlib.c b/src/afterburnerlib.c
index 172dca5..0a6f964 100644
--- a/src/afterburnerlib.c
+++ b/src/afterburnerlib.c
@@ -34,7 +34,7 @@ char *FieldName(int code, const char *text)
 {
   static char name[256];
 
-  sprintf(name, "[%3d].%s", code, text);
+  snprintf(name, sizeof(name), "[%3d].%s", code, text);
 
   return name;
 }
diff --git a/src/array.c b/src/array.c
new file mode 100644
index 0000000..b280ad3
--- /dev/null
+++ b/src/array.c
@@ -0,0 +1,81 @@
+#include <stdio.h>
+#include <float.h>
+#include <fenv.h>
+
+#include "compare.h"
+
+//#pragma STDC FENV_ACCESS ON
+
+const char *fpe_errstr(int fpeRaised)
+{
+  const char *errstr = NULL;
+
+  if      ( fpeRaised & FE_DIVBYZERO ) errstr = "division by zero";
+  else if ( fpeRaised & FE_INEXACT   ) errstr = "inexact result";
+  else if ( fpeRaised & FE_INVALID   ) errstr = "invalid result";
+  else if ( fpeRaised & FE_OVERFLOW  ) errstr = "overflow";
+  else if ( fpeRaised & FE_UNDERFLOW ) errstr = "underflow";
+
+  return errstr;
+}
+
+
+int array_minmaxmean_val(size_t len, const double *array, double *rmin, double *rmax, double *rmean)
+{
+  int excepts = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+  feclearexcept(FE_ALL_EXCEPT);
+
+  double min =  DBL_MAX;
+  double max = -DBL_MAX;
+  double mean = 0;
+
+  // #pragma omp parallel for default(none) shared(min, max, array, gridsize) reduction(+:mean)
+  // #pragma omp simd reduction(+:mean) reduction(min:min) reduction(max:max) aligned(array:16)
+  for ( size_t i = 0; i < len; ++i )
+    {
+      if ( array[i] < min ) min = array[i];
+      if ( array[i] > max ) max = array[i];
+      mean += array[i];
+    }
+
+  if ( len ) mean /= (double)len;
+    
+  if ( rmin ) *rmin = min;
+  if ( rmax ) *rmax = max;
+  if ( rmean ) *rmean = mean;
+
+  return fetestexcept(excepts);
+}
+
+
+int array_mean_val_weighted(size_t len, const double *restrict array, const double *restrict w, double missval, double *rmean)
+{
+  int excepts = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+  feclearexcept(FE_ALL_EXCEPT);
+
+  double rsum = 0, rsumw = 0;
+
+  for ( size_t i = 0; i < len; i++ ) 
+    {
+      rsum  += w[i] * array[i];
+      rsumw += w[i];
+    }
+
+  *rmean = DBL_IS_EQUAL(rsumw, 0.) ? missval : rsum/rsumw;
+
+  return fetestexcept(excepts);
+}
+
+
+int array_add_array(size_t len, double *restrict array1, const double *restrict array2)
+{
+  int excepts = FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
+  feclearexcept(FE_ALL_EXCEPT);
+
+  //#if defined(_OPENMP)
+  //#pragma omp parallel for default(none) shared(array1,array2)
+  //#endif
+  for ( size_t i = 0; i < len; i++ ) array1[i] += array2[i];
+
+  return fetestexcept(excepts);
+}
diff --git a/src/array.h b/src/array.h
new file mode 100644
index 0000000..b3a092e
--- /dev/null
+++ b/src/array.h
@@ -0,0 +1,13 @@
+#ifndef _ARRAY_H
+#define _ARRAY_H
+
+const char *fpe_errstr(int fpeRaised);
+
+int array_minmaxmean_val(size_t len, const double *array, double *rmin, double *rmax, double *rmean);
+
+int array_mean_val_weighted(size_t len, const double *restrict array, const double *restrict w, double missval, double *rmean);
+
+int array_add_array(size_t len, double *restrict array1, const double *restrict array2);
+
+#endif // _ARRAY_H
+
diff --git a/src/cdo.c b/src/cdo.c
index 6fc669c..d1f67f8 100644
--- a/src/cdo.c
+++ b/src/cdo.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -29,7 +29,6 @@
 
 #include <signal.h>
 #include <fenv.h>
-#include <ctype.h>
 /*#include <malloc.h>*/ /* mallopt and malloc_stats */
 #include <sys/stat.h>
 #if defined(HAVE_GETRLIMIT)
@@ -58,7 +57,6 @@
 #endif
 
 #include "modules.h"
-#include "util.h"
 #include "error.h"
 
 #if defined(_OPENMP)
@@ -158,10 +156,29 @@ void cdo_sig_handler(int signo)
 }
 
 static
+void cdo_set_digits(const char *optarg)
+{
+  char *ptr1 = 0;
+  if ( optarg != 0 && (int) strlen(optarg) > 0 && optarg[0] != ',' )
+    CDO_flt_digits = (int)strtol(optarg, &ptr1, 10);
+
+  if ( CDO_flt_digits < 1 || CDO_flt_digits > 20 )
+    cdoAbort("Unreasonable value for float significant digits: %d", CDO_flt_digits);
+
+  if ( ptr1 && *ptr1 == ',' )
+    {
+      char *ptr2 = 0;
+      CDO_dbl_digits = (int)strtol(ptr1+1, &ptr2, 10);
+      if  ( ptr2 == ptr1+1 || CDO_dbl_digits < 1 || CDO_dbl_digits > 20 )
+        cdoAbort("Unreasonable value for double significant digits: %d", CDO_dbl_digits);
+    }
+}
+
+static
 void cdo_version(void)
 {
-  const int   filetypes[] = {FILETYPE_SRV, FILETYPE_EXT, FILETYPE_IEG, FILETYPE_GRB, FILETYPE_GRB2, FILETYPE_NC, FILETYPE_NC2, FILETYPE_NC4, FILETYPE_NC4C};
-  const char* typenames[] = {        "srv",        "ext",        "ieg",        "grb",        "grb2",        "nc",        "nc2",        "nc4",        "nc4c"};
+  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};
+  const char* typenames[] = {        "srv",        "ext",        "ieg",       "grb1",        "grb2",       "nc1",        "nc2",        "nc4",        "nc4c"};
 
   fprintf(stderr, "%s\n", CDO_Version);
 #if defined(USER_NAME) && defined(HOST_NAME) && defined(SYSTEM_TYPE)
@@ -201,17 +218,14 @@ void cdo_usage(void)
   set_text_color(stderr, RESET, BLUE);
   fprintf(stderr, "    -a             Generate an absolute time axis\n");
   fprintf(stderr, "    -b <nbits>     Set the number of bits for the output precision\n");
-  fprintf(stderr, "                   (I8/I16/I32/F32/F64 for nc/nc2/nc4/nc4c; F32/F64 for grb2/srv/ext/ieg; P1 - P24 for grb/grb2)\n");
+  fprintf(stderr, "                   (I8/I16/I32/F32/F64 for nc1/nc2/nc4/nc4c; F32/F64 for grb2/srv/ext/ieg; P1 - P24 for grb1/grb2)\n");
   fprintf(stderr, "                   Add L or B to set the byteorder to Little or Big endian\n");
-  if ( ITSME )
-    {
-      fprintf(stderr, "    --enableexcept <except>\n");
-      fprintf(stderr, "                   Set individual floating-point traps (DIVBYZERO, INEXACT, INVALID, OVERFLOW, UNDERFLOW, ALL_EXCEPT)\n");
-    }
   fprintf(stderr, "    --cmor         CMOR conform NetCDF output\n");
   fprintf(stderr, "    -C, --color    Colorized output messages\n");
+  fprintf(stderr, "    --enableexcept <except>\n");
+  fprintf(stderr, "                   Set individual floating-point traps (DIVBYZERO, INEXACT, INVALID, OVERFLOW, UNDERFLOW, ALL_EXCEPT)\n");
   fprintf(stderr, "    -f, --format <format>\n");
-  fprintf(stderr, "                   Format of the output file. (grb/grb2/nc/nc2/nc4/nc4c/srv/ext/ieg)\n");
+  fprintf(stderr, "                   Format of the output file. (grb1/grb2/nc1/nc2/nc4/nc4c/srv/ext/ieg)\n");
   fprintf(stderr, "    -g <grid>      Set default grid name or file. Available grids: \n");
   fprintf(stderr, "                   n<N>, t<RES>, tl<RES>, global_<DXY>, r<NX>x<NY>, g<NX>x<NY>, gme<NI>, lon=<LON>/lat=<LAT>\n");
   fprintf(stderr, "    -h, --help     Help information for the operators\n");
@@ -239,6 +253,8 @@ void cdo_usage(void)
 #endif
   fprintf(stderr, "    --percentile <method>\n");
   fprintf(stderr, "                   Percentile method: nrank, nist, numpy, numpy_lower, numpy_higher, numpy_nearest\n");
+  fprintf(stderr, "    --precision <float_digits[,double_digits]>\n");
+  fprintf(stderr, "                   Precision to use in displaying floating-point data (default: 7,15)\n");
   fprintf(stderr, "    --reduce_dim   Reduce NetCDF dimensions (module: TIMSTAT, FLDSTAT)\n");
   fprintf(stderr, "    -R, --regular  Convert GRIB1 data from reduced to regular grid (cgribex only)\n");
   fprintf(stderr, "    -r             Generate a relative time axis\n");
@@ -273,7 +289,7 @@ void cdo_usage(void)
   */
 
   fprintf(stderr, "\n");
-  fprintf(stderr, "  CDO version %s, Copyright (C) 2003-2016 Uwe Schulzweida\n", VERSION);
+  fprintf(stderr, "  CDO version %s, Copyright (C) 2003-2017 Uwe Schulzweida\n", VERSION);
   //  fprintf(stderr, "  Available from <http://mpimet.mpg.de/cdo>\n");
   fprintf(stderr, "  This is free software and comes with ABSOLUTELY NO WARRANTY\n");
   fprintf(stderr, "  Report bugs to <http://mpimet.mpg.de/cdo>\n");
@@ -298,13 +314,10 @@ void cdoPrintHelp(const char *phelp[]/*, char *xoperator*/)
     fprintf(stderr, "No help available for this operator!\n");
   else
     {
-      int lprint;
+      bool lprint;
       while ( *phelp )
         {
-          lprint = TRUE;
-          if ( *phelp[0] == '\0' )
-            if ( *(phelp+1) )
-              if ( *(phelp+1)[0] == ' ' ) lprint = FALSE;
+          lprint = !(*phelp[0] == '\0' && *(phelp+1) && *(phelp+1)[0] == ' ');
           
           if ( lprint )
             {
@@ -375,54 +388,34 @@ void setDefaultDataType(const char *datatypestr)
   enum {D_UINT, D_INT, D_FLT, D_CPX};
   int dtype = -1;
 
-  if      ( *datatypestr == 'i' || *datatypestr == 'I' )
-    {
-      dtype = D_INT;
-      datatypestr++;
-    }
-  else if ( *datatypestr == 'u' || *datatypestr == 'U' )
-    {
-      dtype = D_UINT;
-      datatypestr++;
-    }
-  else if ( *datatypestr == 'f' || *datatypestr == 'F' )
-    {
-      dtype = D_FLT;
-      datatypestr++;
-    }
-  else if ( *datatypestr == 'c' || *datatypestr == 'C' )
-    {
-      dtype = D_CPX;
-      datatypestr++;
-    }
-  else if ( *datatypestr == 'p' || *datatypestr == 'P' )
-    {
-      datatypestr++;
-    }
+  int datatype = tolower(*datatypestr);
+  if      ( datatype == 'i' ) { dtype = D_INT;  datatypestr++; }
+  else if ( datatype == 'u' ) { dtype = D_UINT; datatypestr++; }
+  else if ( datatype == 'f' ) { dtype = D_FLT;  datatypestr++; }
+  else if ( datatype == 'c' ) { dtype = D_CPX;  datatypestr++; }
+  else if ( datatype == 'p' ) { datatypestr++; }
 
   if ( isdigit((int) *datatypestr) )
     {
       nbits = atoi(datatypestr);
-      if ( nbits < 10 )
-        datatypestr += 1;
-      else
-        datatypestr += 2;
+      datatypestr += 1;
+      if ( nbits >= 10 ) datatypestr += 1;
 
       if ( dtype == -1 )
         {
           if      ( nbits > 0 && nbits < 32 ) cdoDefaultDataType = nbits;
           else if ( nbits == 32 )
             {
-              if ( cdoDefaultFileType == FILETYPE_GRB )
-                cdoDefaultDataType = DATATYPE_PACK32;
+              if ( cdoDefaultFileType == CDI_FILETYPE_GRB )
+                cdoDefaultDataType = CDI_DATATYPE_PACK32;
               else
-                cdoDefaultDataType = DATATYPE_FLT32;
+                cdoDefaultDataType = CDI_DATATYPE_FLT32;
             }
-          else if ( nbits == 64 ) cdoDefaultDataType = DATATYPE_FLT64;
+          else if ( nbits == 64 ) cdoDefaultDataType = CDI_DATATYPE_FLT64;
           else
             {
               fprintf(stderr, "Unsupported number of bits %d!\n", nbits);
-              fprintf(stderr, "Use I8/I16/I32/F32/F64 for nc/nc2/nc4/nc4c; F32/F64 for grb2/srv/ext/ieg; P1 - P24 for grb/grb2.\n");
+              fprintf(stderr, "Use I8/I16/I32/F32/F64 for nc1/nc2/nc4/nc4c; F32/F64 for grb2/srv/ext/ieg; P1 - P24 for grb1/grb2.\n");
               exit(EXIT_FAILURE);
             }
         }
@@ -430,9 +423,9 @@ void setDefaultDataType(const char *datatypestr)
         {
           if ( dtype == D_INT )
             {
-              if      ( nbits ==  8 ) cdoDefaultDataType = DATATYPE_INT8;
-              else if ( nbits == 16 ) cdoDefaultDataType = DATATYPE_INT16;
-              else if ( nbits == 32 ) cdoDefaultDataType = DATATYPE_INT32;
+              if      ( nbits ==  8 ) cdoDefaultDataType = CDI_DATATYPE_INT8;
+              else if ( nbits == 16 ) cdoDefaultDataType = CDI_DATATYPE_INT16;
+              else if ( nbits == 32 ) cdoDefaultDataType = CDI_DATATYPE_INT32;
               else
                 {
                   fprintf(stderr, "Unsupported number of bits = %d for datatype INT!\n", nbits);
@@ -441,9 +434,9 @@ void setDefaultDataType(const char *datatypestr)
             }
           else if ( dtype == D_UINT )
             {
-              if      ( nbits ==  8 ) cdoDefaultDataType = DATATYPE_UINT8;
-              else if ( nbits == 16 ) cdoDefaultDataType = DATATYPE_UINT16;
-              else if ( nbits == 32 ) cdoDefaultDataType = DATATYPE_UINT32;
+              if      ( nbits ==  8 ) cdoDefaultDataType = CDI_DATATYPE_UINT8;
+              else if ( nbits == 16 ) cdoDefaultDataType = CDI_DATATYPE_UINT16;
+              else if ( nbits == 32 ) cdoDefaultDataType = CDI_DATATYPE_UINT32;
               else
                 {
                   fprintf(stderr, "Unsupported number of bits = %d for datatype UINT!\n", nbits);
@@ -452,8 +445,8 @@ void setDefaultDataType(const char *datatypestr)
             }
           else if ( dtype == D_FLT )
             {
-              if      ( nbits == 32 ) cdoDefaultDataType = DATATYPE_FLT32;
-              else if ( nbits == 64 ) cdoDefaultDataType = DATATYPE_FLT64;
+              if      ( nbits == 32 ) cdoDefaultDataType = CDI_DATATYPE_FLT32;
+              else if ( nbits == 64 ) cdoDefaultDataType = CDI_DATATYPE_FLT64;
               else
                 {
                   fprintf(stderr, "Unsupported number of bits = %d for datatype FLT!\n", nbits);
@@ -462,8 +455,8 @@ void setDefaultDataType(const char *datatypestr)
             }
           else if ( dtype == D_CPX )
             {
-              if      ( nbits == 32 ) cdoDefaultDataType = DATATYPE_CPX32;
-              else if ( nbits == 64 ) cdoDefaultDataType = DATATYPE_CPX64;
+              if      ( nbits == 32 ) cdoDefaultDataType = CDI_DATATYPE_CPX32;
+              else if ( nbits == 64 ) cdoDefaultDataType = CDI_DATATYPE_CPX64;
               else
                 {
                   fprintf(stderr, "Unsupported number of bits = %d for datatype CPX!\n", nbits);
@@ -504,15 +497,15 @@ void setDefaultDataTypeByte(char *datatypestr)
       datatype = atoi(datatypestr);
       datatypestr++;
 
-      if      ( datatype == 1 ) cdoDefaultDataType = DATATYPE_PACK8;
-      else if ( datatype == 2 ) cdoDefaultDataType = DATATYPE_PACK16;
-      else if ( datatype == 3 ) cdoDefaultDataType = DATATYPE_PACK24;
-      else if ( datatype == 4 ) cdoDefaultDataType = DATATYPE_FLT32;
-      else if ( datatype == 8 ) cdoDefaultDataType = DATATYPE_FLT64;
+      if      ( datatype == 1 ) cdoDefaultDataType = CDI_DATATYPE_PACK8;
+      else if ( datatype == 2 ) cdoDefaultDataType = CDI_DATATYPE_PACK16;
+      else if ( datatype == 3 ) cdoDefaultDataType = CDI_DATATYPE_PACK24;
+      else if ( datatype == 4 ) cdoDefaultDataType = CDI_DATATYPE_FLT32;
+      else if ( datatype == 8 ) cdoDefaultDataType = CDI_DATATYPE_FLT64;
       else
         {
           fprintf(stderr, "Unsupported datatype %d!\n", datatype);
-          fprintf(stderr, "Use 4/8 for filetype nc/srv/ext/ieg and 1/2/3 for grb/grb2.\n");
+          fprintf(stderr, "Use 4/8 for filetype nc/srv/ext/ieg and 1/2/3 for grb1/grb2.\n");
           exit(EXIT_FAILURE);
         }
     }
@@ -545,22 +538,23 @@ void setDefaultFileType(const char *filetypestr, int labort)
       const char *ftstr = filetypestr;
       size_t len;
 
-      if      ( cmpstrlen(filetypestr, "grb2", len)  == 0 ) { ftstr += len; cdoDefaultFileType = FILETYPE_GRB2;}
-      else if ( cmpstrlen(filetypestr, "grb1", len)  == 0 ) { ftstr += len; cdoDefaultFileType = FILETYPE_GRB; }
-      else if ( cmpstrlen(filetypestr, "grb",  len)  == 0 ) { ftstr += len; cdoDefaultFileType = FILETYPE_GRB; }
-      else if ( cmpstrlen(filetypestr, "nc2",  len)  == 0 ) { ftstr += len; cdoDefaultFileType = FILETYPE_NC2; }
-      else if ( cmpstrlen(filetypestr, "nc4c", len)  == 0 ) { ftstr += len; cdoDefaultFileType = FILETYPE_NC4C;}
-      else if ( cmpstrlen(filetypestr, "nc4",  len)  == 0 ) { ftstr += len; cdoDefaultFileType = FILETYPE_NC4; }
-      else if ( cmpstrlen(filetypestr, "nc",   len)  == 0 ) { ftstr += len; cdoDefaultFileType = FILETYPE_NC;  }
-      else if ( cmpstrlen(filetypestr, "srv",  len)  == 0 ) { ftstr += len; cdoDefaultFileType = FILETYPE_SRV; }
-      else if ( cmpstrlen(filetypestr, "ext",  len)  == 0 ) { ftstr += len; cdoDefaultFileType = FILETYPE_EXT; }
-      else if ( cmpstrlen(filetypestr, "ieg",  len)  == 0 ) { ftstr += len; cdoDefaultFileType = FILETYPE_IEG; }
+      if      ( cmpstrlen(filetypestr, "grb2", len)  == 0 ) { ftstr += len; cdoDefaultFileType = CDI_FILETYPE_GRB2;}
+      else if ( cmpstrlen(filetypestr, "grb1", len)  == 0 ) { ftstr += len; cdoDefaultFileType = CDI_FILETYPE_GRB; }
+      else if ( cmpstrlen(filetypestr, "grb",  len)  == 0 ) { ftstr += len; cdoDefaultFileType = CDI_FILETYPE_GRB; }
+      else if ( cmpstrlen(filetypestr, "nc2",  len)  == 0 ) { ftstr += len; cdoDefaultFileType = CDI_FILETYPE_NC2; }
+      else if ( cmpstrlen(filetypestr, "nc4c", len)  == 0 ) { ftstr += len; cdoDefaultFileType = CDI_FILETYPE_NC4C;}
+      else if ( cmpstrlen(filetypestr, "nc4",  len)  == 0 ) { ftstr += len; cdoDefaultFileType = CDI_FILETYPE_NC4; }
+      else if ( cmpstrlen(filetypestr, "nc1",  len)  == 0 ) { ftstr += len; cdoDefaultFileType = CDI_FILETYPE_NC;  }
+      else if ( cmpstrlen(filetypestr, "nc",   len)  == 0 ) { ftstr += len; cdoDefaultFileType = CDI_FILETYPE_NC2; }
+      else if ( cmpstrlen(filetypestr, "srv",  len)  == 0 ) { ftstr += len; cdoDefaultFileType = CDI_FILETYPE_SRV; }
+      else if ( cmpstrlen(filetypestr, "ext",  len)  == 0 ) { ftstr += len; cdoDefaultFileType = CDI_FILETYPE_EXT; }
+      else if ( cmpstrlen(filetypestr, "ieg",  len)  == 0 ) { ftstr += len; cdoDefaultFileType = CDI_FILETYPE_IEG; }
       else
         {
           if ( labort )
             {
               fprintf(stderr, "Unsupported filetype %s!\n", filetypestr);
-              fprintf(stderr, "Available filetypes: grb/grb2/nc/nc2/nc4/nc4c/srv/ext/ieg\n");
+              fprintf(stderr, "Available filetypes: grb1/grb2/nc1/nc2/nc4/nc4c/srv/ext/ieg\n");
               exit(EXIT_FAILURE);
             }
           else
@@ -581,8 +575,8 @@ void setDefaultFileType(const char *filetypestr, int labort)
             {
               fprintf(stderr, "Unexpected character >%c< in file type >%s<!\n", *ftstr, filetypestr);
               fprintf(stderr, "Use format[_nbits] with:\n");
-              fprintf(stderr, "    format = grb, grb2, nc, nc2, nc4, nc4c, srv, ext or ieg\n");
-              fprintf(stderr, "    nbits  = 32/64 for grb2/nc/nc2/nc4/nc4c/srv/ext/ieg; 1 - 24 for grb/grb2\n");
+              fprintf(stderr, "    format = grb1, grb2, nc1, nc2, nc4, nc4c, srv, ext or ieg\n");
+              fprintf(stderr, "    nbits  = 32/64 for grb2/nc1/nc2/nc4/nc4c/srv/ext/ieg; 1 - 24 for grb1/grb2\n");
               exit(EXIT_FAILURE);
             }
         }
@@ -630,22 +624,22 @@ void defineCompress(const char *arg)
 
   if      ( strncmp(arg, "szip", len) == 0 )
     {
-      cdoCompType  = COMPRESS_SZIP;
+      cdoCompType  = CDI_COMPRESS_SZIP;
       cdoCompLevel = 0;
     }
   else if ( strncmp(arg, "jpeg", len) == 0 )
     {
-      cdoCompType = COMPRESS_JPEG;
+      cdoCompType = CDI_COMPRESS_JPEG;
       cdoCompLevel = 0;
     }
   else if ( strncmp(arg, "gzip", len) == 0 )
     {
-      cdoCompType  = COMPRESS_GZIP;
+      cdoCompType  = CDI_COMPRESS_GZIP;
       cdoCompLevel = 6;
     }
   else if ( strncmp(arg, "zip", 3) == 0 )
     {
-      cdoCompType  = COMPRESS_ZIP;
+      cdoCompType  = CDI_COMPRESS_ZIP;
       if ( len == 5 && arg[3] == '_' && isdigit(arg[4]) )
         cdoCompLevel = atoi(&arg[4]);
       else
@@ -661,9 +655,9 @@ void defineCompress(const char *arg)
 static
 void defineChunktype(const char *arg)
 {
-  if      ( strcmp("auto",  arg)   == 0 ) cdoChunkType = CHUNK_AUTO;
-  else if ( strcmp("grid",  arg)   == 0 ) cdoChunkType = CHUNK_GRID;
-  else if ( strcmp("lines", arg)   == 0 ) cdoChunkType = CHUNK_LINES;
+  if      ( strcmp("auto",  arg)   == 0 ) cdoChunkType = CDI_CHUNK_AUTO;
+  else if ( strcmp("grid",  arg)   == 0 ) cdoChunkType = CDI_CHUNK_GRID;
+  else if ( strcmp("lines", arg)   == 0 ) cdoChunkType = CDI_CHUNK_LINES;
   else
     {
       fprintf(stderr, "Chunk type '%s' unsupported!\n", arg);
@@ -1072,13 +1066,19 @@ int parse_options_long(int argc, char *argv[])
   int lgridsearchnn;
   int lgridsearchradius;
   int lremap_genweights;
+  int lprecision;
   int lpercentile;
+  int lprintoperatorsno = 0;
   int lprintoperators = 0;
   int lenableexcept;
   int ltimestat_date;
+  int ltimestat_bounds;
+  int lsortname;
+  int lsortparam;
 
   struct cdo_option opt_long[] =
     {
+      { "precision",         required_argument,        &lprecision,   1  },
       { "percentile",        required_argument,        &lpercentile,  1  },
       { "netcdf_hdr_pad",    required_argument,    &lnetcdf_hdr_pad,  1  },
       { "header_pad",        required_argument,    &lnetcdf_hdr_pad,  1  },
@@ -1089,10 +1089,12 @@ int parse_options_long(int argc, char *argv[])
       { "remap_genweights",  required_argument,  &lremap_genweights,  1  },
       { "enableexcept",      required_argument,      &lenableexcept,  1  },
       { "timestat_date",     required_argument,     &ltimestat_date,  1  },
+      { "timestat_bounds",         no_argument,   &ltimestat_bounds,  1  },
       { "cmor",                    no_argument,      &CDO_CMOR_Mode,  1  },
       { "reduce_dim",              no_argument,     &CDO_Reduce_Dim,  1  },
       { "float",                   no_argument,        &CDO_Memtype,  MEMTYPE_FLOAT  },
       { "rusage",                  no_argument,         &CDO_Rusage,  1  },
+      { "operators_no_output",     no_argument,  &lprintoperatorsno,  1  },
       { "operators",               no_argument,    &lprintoperators,  1  },
       { "no_warnings",             no_argument,           &_Verbose,  0  },
       { "color",                   no_argument,                NULL, 'C' },
@@ -1103,6 +1105,8 @@ int parse_options_long(int argc, char *argv[])
       { "regular",                 no_argument,                NULL, 'R' },
       { "silent",                  no_argument,                NULL, 's' },
       { "sort",                    no_argument,                NULL, 'Q' },
+      { "sortname",                no_argument,          &lsortname,  1  },
+      { "sortparam",               no_argument,         &lsortparam,  1  },
       { "table",             required_argument,                NULL, 't' },
       { "verbose",                 no_argument,                NULL, 'v' },
       { "version",                 no_argument,                NULL, 'V' },
@@ -1113,6 +1117,7 @@ int parse_options_long(int argc, char *argv[])
 
   while ( 1 )
     {
+      lprecision = 0;
       lpercentile = 0;
       lnetcdf_hdr_pad = 0;
       luse_fftw = 0;
@@ -1121,6 +1126,9 @@ int parse_options_long(int argc, char *argv[])
       lremap_genweights = 0;
       lenableexcept = 0;
       ltimestat_date = 0;
+      ltimestat_bounds = 0;
+      lsortname = 0;
+      lsortparam = 0;
 
       c = cdo_getopt_long(argc, argv, "f:b:e:P:g:i:k:l:m:n:t:D:z:aBCcdhLMOpQRrsSTuVvWXZ", opt_long, NULL);
       if ( c == -1 ) break;
@@ -1143,6 +1151,10 @@ int parse_options_long(int argc, char *argv[])
               int netcdf_hdr_pad = str_to_int(CDO_optarg);
               if ( netcdf_hdr_pad >= 0 ) CDO_netcdf_hdr_pad = netcdf_hdr_pad;
             }
+          else if ( lprecision )
+            {
+              cdo_set_digits(CDO_optarg);
+            }
           else if ( lpercentile )
             {
               percentile_set_method(CDO_optarg);
@@ -1171,6 +1183,11 @@ int parse_options_long(int argc, char *argv[])
               extern int CDO_Timestat_Date;
               CDO_Timestat_Date = timestatdate;
             }
+          else if ( ltimestat_bounds )
+            {
+              extern bool CDO_Timestat_Bounds;
+              CDO_Timestat_Bounds = true;
+            }
           else if ( luse_fftw )
             {
               int intarg = parameter2int(CDO_optarg);
@@ -1185,11 +1202,9 @@ int parse_options_long(int argc, char *argv[])
           else if ( lgridsearchradius )
             {
               extern double gridsearch_radius;
-              double fval = atof(CDO_optarg);
-              if ( fval < 0 || fval > 180 )
-                cdoAbort("gridsearchradius=%g out of bounds (0-180)", fval);
-              else
-                gridsearch_radius = fval;
+              double fval = radius_str_to_deg(CDO_optarg);
+              if ( fval < 0 || fval > 180 ) cdoAbort("%s=%g out of bounds (0-180 deg)!", "gridsearchradius", fval);
+              gridsearch_radius = fval;
             }
           else if ( lremap_genweights )
             {
@@ -1198,6 +1213,14 @@ int parse_options_long(int argc, char *argv[])
                 cdoAbort("Unsupported value for option --remap_genweights=%d [range: 0-1]", intarg);
               remap_genweights = intarg;
             }
+          else if ( lsortname )
+            {
+              cdiDefGlobal("SORTNAME", TRUE);
+            }
+          else if ( lsortparam )
+            {
+              cdiDefGlobal("SORTPARAM", TRUE);
+            }
           break;
         case 'a':
           cdoDefaultTimeType = TAXIS_ABSOLUTE;
@@ -1242,7 +1265,7 @@ int parse_options_long(int argc, char *argv[])
           setDefaultFileType(CDO_optarg, 1);
           break;
         case 'g':
-          defineGrid(CDO_optarg);
+          cdo_set_grids(CDO_optarg);
           break;
         case 'h':        
           Help = 1;
@@ -1312,6 +1335,7 @@ int parse_options_long(int argc, char *argv[])
           break;
         case 'v':
           cdoVerbose = TRUE;
+          _Verbose = 1;
           break;
         case 'W': /* Warning messages */
           _Verbose = 1;
@@ -1328,15 +1352,16 @@ int parse_options_long(int argc, char *argv[])
         }
     }
 
-  if ( lprintoperators )
+  if ( lprintoperators || lprintoperatorsno )
     {
       set_text_color(stderr, RESET, GREEN);
-      operatorPrintList();
+      bool print_no_output = lprintoperatorsno > 0;
+      operatorPrintList(print_no_output);
       //operatorPrintAll();
       reset_text_color(stderr);
       return 1;
     }
-  
+ 
   return 0;
 }
 
@@ -1371,7 +1396,6 @@ int main(int argc, char *argv[])
   int lstop = FALSE;
   int noff = 0;
   int status = 0;
-  char *operatorName = NULL;
   char *operatorArg = NULL;
   argument_t *argument = NULL;
 
@@ -1486,7 +1510,7 @@ int main(int argc, char *argv[])
 
   if ( cdoDefaultTableID != CDI_UNDEFID ) cdiDefTableID(cdoDefaultTableID);
 
-  operatorName = getOperatorName(operatorArg);
+  const char *operatorName = getOperatorName(operatorArg);
 
   if ( Help )
     {
diff --git a/src/cdo.h b/src/cdo.h
index bb6f03c..4938b75 100644
--- a/src/cdo.h
+++ b/src/cdo.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
diff --git a/src/cdo_getopt.c b/src/cdo_getopt.c
index 35df1da..2f95dba 100644
--- a/src/cdo_getopt.c
+++ b/src/cdo_getopt.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
diff --git a/src/cdo_getopt.h b/src/cdo_getopt.h
index 0575bd4..00cde16 100644
--- a/src/cdo_getopt.h
+++ b/src/cdo_getopt.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
diff --git a/src/cdo_history.c b/src/cdo_history.c
index 6eac85f..1a0e8db 100644
--- a/src/cdo_history.c
+++ b/src/cdo_history.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -122,7 +122,7 @@ void cdoDefHistory(int fileID, char *histstring)
 void cdo_def_creation_date(int vlistID)
 {
   if ( strlen(datetimestr) == 0 ) init_strtime();
-  vlistDefAttTxt(vlistID, CDI_GLOBAL, "creation_date", (int)strlen(datetimestr)+1, datetimestr);
+  cdiDefAttTxt(vlistID, CDI_GLOBAL, "creation_date", (int)strlen(datetimestr), datetimestr);
 }
 
 
@@ -141,5 +141,5 @@ void cdo_def_tracking_id(int vlistID, const char *uuid_attribute)
 {
   char uuidstr[UUIDSTR_SIZE];
   get_uuid(uuidstr);
-  vlistDefAttTxt(vlistID, CDI_GLOBAL, uuid_attribute, UUIDSTR_SIZE, uuidstr);
+  cdiDefAttTxt(vlistID, CDI_GLOBAL, uuid_attribute, UUIDSTR_SIZE, uuidstr);
 }
diff --git a/src/cdo_int.h b/src/cdo_int.h
index 0eb1cbd..d5716b1 100644
--- a/src/cdo_int.h
+++ b/src/cdo_int.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -32,7 +32,10 @@
 #include <ctype.h>
 #include <stdarg.h>
 
+#include "pmlist.h"
+#include "listbuf.h"
 #include "compare.h"
+#include "array.h"
 #include "timebase.h"
 #include "field.h"
 #include "functs.h"
@@ -118,15 +121,8 @@ int     readline(FILE *fp, char *line, int len);
 
 int zaxis2ltype(int zaxisID);
 
+double radius_str_to_deg(const char *string);
 
-int nfc2nlat(int nfc, int ntr);
-int nlat2ntr(int nlat);
-int nlat2ntr_linear(int nlat);
-int ntr2nlat(int ntr);
-int ntr2nlat_linear(int ntr);
-int compNlon(int nlat);
-
-void param2str(int param, char *paramstr, int maxlen);
 void datetime2str(int date, int time, char *datetimestr, int maxlen);
 void date2str(int date, char *datestr, int maxlen);
 void time2str(int time, char *timestr, int maxlen);
@@ -134,7 +130,7 @@ void time2str(int time, char *timestr, int maxlen);
 const char * tunit2str(int tunits);
 const char * calendar2str(int calendar);
 
-void    defineGrid(const char *gridarg);
+void    cdo_set_grids(const char *gridarg);
 void    defineInstitution(const char *instarg);
 int     defineTable(const char *tablearg);
 
@@ -157,12 +153,29 @@ off_t fileSize(const char *restrict filename);
 
 char *expand_filename(const char *string);
 
+const char *parameter2word(const char *string);
 double parameter2double(const char *string);
+bool   parameter2bool(const char *string);
 int    parameter2int(const char *string);
 int    parameter2intlist(const char *string);
 
 int referenceToGrid(int gridID1);
 
+void cdo_read_field(const char *name, char *pline, int size, double *field, int *lineno, FILE *fp, const char *dname);
+
+double cdoZaxisInqLevel(int zaxisID, int levelID);
+int cdoZaxisInqLevels(int zaxisID, double *levels);
+
+list_t *namelistbuf_to_pmlist(listbuf_t *listbuf);
+list_t *namelist_to_pmlist(FILE *fp, const char *name);
+list_t *cmortable_to_pmlist(FILE *fp, const char *name);
+
+int literals_find_datatype(int n, char **literals);
+int literal_get_datatype(const char *literal);
+int literal_to_int(const char *literal);
+double literal_to_double(const char *literal);
+
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -177,6 +190,10 @@ void gaussaw(double *restrict pa, double *restrict pw, size_t nlat);
 int qu2reg3_double(double *pfield, int *kpoint, int klat, int klon,
 		   double msval, int *kret, int omisng, int operio, int oveggy);
 
+void cdoCompareGrids(int gridID1, int gridID2);
+void vlistCompare(int vlistID1, int vlistID2, int flag);
+int  vlistCompareX(int vlistID1, int vlistID2, int flag);
+
 #if defined (__cplusplus)
 }
 #endif
diff --git a/src/cdo_pthread.c b/src/cdo_pthread.c
index 44622cc..c5755f0 100644
--- a/src/cdo_pthread.c
+++ b/src/cdo_pthread.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
diff --git a/src/cdo_vlist.c b/src/cdo_vlist.c
index 471c72c..4c95b77 100644
--- a/src/cdo_vlist.c
+++ b/src/cdo_vlist.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -22,6 +22,36 @@
 #include "error.h"
 
 
+double cdoZaxisInqLevel(int zaxisID, int levelID)
+{
+  int zaxistype  = zaxisInqType(zaxisID);
+  double level = zaxisInqLevels(zaxisID, NULL) ? zaxisInqLevel(zaxisID, levelID) :
+                 (zaxistype == ZAXIS_SURFACE) ? 0 : levelID+1;
+  return level;
+}
+
+
+int cdoZaxisInqLevels(int zaxisID, double *levels)
+{
+  int size = zaxisInqLevels(zaxisID, NULL);
+
+  if ( levels )
+    {
+      if ( size )
+        zaxisInqLevels(zaxisID, levels);
+      else
+        {
+          size = zaxisInqSize(zaxisID);
+          if ( size == 1 && zaxisInqType(zaxisID) == ZAXIS_SURFACE )
+            levels[0] = 0;
+          else
+            for ( int i = 0; i < size; ++i ) levels[i] = i+1;
+        }
+    }
+
+  return size;
+}
+
 static
 void compare_lat_reg2d(int ysize, int gridID1, int gridID2)
 {
@@ -82,8 +112,8 @@ void compare_lon_reg2d(int xsize, int gridID1, int gridID2)
 static
 void compare_grid_unstructured(int gridID1, int gridID2)
 {
-  if ( gridInqXvals(gridID1, NULL) == gridInqXvals(gridID2, NULL) &&
-       gridInqYvals(gridID1, NULL) == gridInqYvals(gridID2, NULL) )
+  if ( gridInqXvals(gridID1, NULL) && gridInqXvals(gridID1, NULL) == gridInqXvals(gridID2, NULL) &&
+       gridInqYvals(gridID1, NULL) && gridInqYvals(gridID1, NULL) == gridInqYvals(gridID2, NULL) )
     {
       int gridsize = gridInqSize(gridID1);
       
@@ -113,8 +143,8 @@ void compare_grid_unstructured(int gridID1, int gridID2)
     }
 }
 
-static
-void compareGrids(int gridID1, int gridID2)
+
+void cdoCompareGrids(int gridID1, int gridID2)
 {
   /* compare grids of first variable */
 
@@ -160,15 +190,15 @@ int cmpnames(const void *s1, const void *s2)
 void vlistCompare(int vlistID1, int vlistID2, int flag)
 {
   int varID;
-  int lchecknames = FALSE;
+  bool lchecknames = false;
+
+  int nvars = vlistNvars(vlistID1);
 
-  if ( vlistNvars(vlistID1) != vlistNvars(vlistID2) )
+  if ( nvars != vlistNvars(vlistID2) )
     cdoAbort("Input streams have different number of variables per timestep!");
 
   if ( vlistNrecs(vlistID1) != vlistNrecs(vlistID2) )
-    cdoAbort("Input streams have different number of records per timestep!");
-
-  int nvars = vlistNvars(vlistID1);
+    cdoAbort("Input streams have different number of %s per timestep!", nvars==1 ? "layers" : "records");
 
   for ( varID = 0; varID < nvars; varID++ )
     {
@@ -183,8 +213,8 @@ void vlistCompare(int vlistID1, int vlistID2, int flag)
 	      strtolower(name2);
 	      if ( strcmp(name1, name2) != 0 )
 		{
-		  cdoWarning("Input streams have different parameters!");
-		  lchecknames = TRUE;
+		  cdoWarning("Input streams have different parameter names!");
+		  lchecknames = true;
 		  flag -= CMP_NAME;
 		  //    break;
 		}
@@ -211,24 +241,25 @@ void vlistCompare(int vlistID1, int vlistID2, int flag)
 
               double *lev1 = (double*) Malloc(nlev1*sizeof(double));
               double *lev2 = (double*) Malloc(nlev1*sizeof(double));
-              zaxisInqLevels(zaxisID1, lev1);
-              zaxisInqLevels(zaxisID2, lev2);
-              
-              int ldiffer = FALSE;
+              cdoZaxisInqLevels(zaxisID1, lev1);
+              cdoZaxisInqLevels(zaxisID2, lev2);
+
+              bool ldiffer = false;
               for ( int i = 0; i < nlev1; ++i )
                 if ( IS_NOT_EQUAL(lev1[i], lev2[i]) )
-                  { ldiffer = TRUE; break; }
+                  { ldiffer = true; break; }
               if ( ldiffer )
                 {
-                  ldiffer = FALSE;
+                  ldiffer = false;
                   for ( int i = 0; i < nlev1; ++i )
                     if ( IS_NOT_EQUAL(lev1[i], lev2[nlev1-1-i]) )
-                      { ldiffer = TRUE; break; }
+                      { ldiffer = true; break; }
 
                   if ( ldiffer )
                     cdoWarning("Input parameters have different levels!");
                   else
                     cdoWarning("Z-axis orientation differ!");
+                  break;
                 }
               
               Free(lev1);
@@ -239,12 +270,9 @@ void vlistCompare(int vlistID1, int vlistID2, int flag)
 
   if ( flag & CMP_GRID )
     {
-      int gridID1, gridID2;
-
-      gridID1 = vlistInqVarGrid(vlistID1, 0);
-      gridID2 = vlistInqVarGrid(vlistID2, 0);
-
-      compareGrids(gridID1, gridID2);
+      int gridID1 = vlistInqVarGrid(vlistID1, 0);
+      int gridID2 = vlistInqVarGrid(vlistID2, 0);
+      cdoCompareGrids(gridID1, gridID2);
     }
 
   if ( lchecknames )
@@ -256,12 +284,13 @@ void vlistCompare(int vlistID1, int vlistID2, int flag)
 	vlistInqVarName(vlistID2, varID, names2[varID]);
 
       qsort(names1[0], nvars, CDI_MAX_NAME, cmpnames);
+      qsort(names2[0], nvars, CDI_MAX_NAME, cmpnames);
 
       for ( varID = 0; varID < nvars; varID++ )
 	if ( strcmp(names1[varID], names2[varID]) != 0 ) break;
 
       if ( varID == nvars )
-	cdoPrint("Use the CDO option -Q to sort the parameter names, if you have NetCDF input files!");
+	cdoPrint("Use CDO option --sortname to sort the parameter by name (NetCDF only)!");
     }
 }
 
@@ -294,12 +323,9 @@ int vlistCompareX(int vlistID1, int vlistID2, int flag)
 
   if ( flag & CMP_GRID )
     {
-      int gridID1, gridID2;
-
-      gridID1 = vlistInqVarGrid(vlistID1, 0);
-      gridID2 = vlistInqVarGrid(vlistID2, 0);
-
-      compareGrids(gridID1, gridID2);
+      int gridID1 = vlistInqVarGrid(vlistID1, 0);
+      int gridID2 = vlistInqVarGrid(vlistID2, 0);
+      cdoCompareGrids(gridID1, gridID2);
     }
 
   return nlevels2;
@@ -314,7 +340,7 @@ int vlistIsSzipped(int vlistID)
   for ( int varID = 0; varID < nvars; varID++ )
     {						
       int comptype = vlistInqVarCompType(vlistID, varID);
-      if ( comptype == COMPRESS_SZIP )
+      if ( comptype == CDI_COMPRESS_SZIP )
 	{
 	  lszip = TRUE;
 	  break;
@@ -329,8 +355,8 @@ int vlistInqNWPV(int vlistID, int varID)
 {
   int nwpv; // number of words per value; real:1  complex:2
 
-  if ( vlistInqVarDatatype(vlistID, varID) == DATATYPE_CPX32 || 
-       vlistInqVarDatatype(vlistID, varID) == DATATYPE_CPX64 )
+  if ( vlistInqVarDatatype(vlistID, varID) == CDI_DATATYPE_CPX32 || 
+       vlistInqVarDatatype(vlistID, varID) == CDI_DATATYPE_CPX64 )
     nwpv = 2;
   else
     nwpv = 1;
@@ -341,7 +367,7 @@ int vlistInqNWPV(int vlistID, int varID)
 
 int vlist_check_gridsize(int vlistID)
 {
-  int lerror = FALSE;
+  bool lerror = false;
   int ngrids = vlistNgrids(vlistID);
   int gridID = vlistGrid(vlistID, 0);
   int ngp    = gridInqSize(gridID);
@@ -352,7 +378,7 @@ int vlist_check_gridsize(int vlistID)
       gridID = vlistGrid(vlistID, index);
       if ( ngp != gridInqSize(gridID) )
 	{
-	  lerror = TRUE;
+	  lerror = true;
 	  break;
 	}
     }
@@ -375,26 +401,26 @@ int vlist_check_gridsize(int vlistID)
 
 double *vlist_read_vct(int vlistID, int *rzaxisIDh, int *rnvct, int *rnhlev, int *rnhlevf, int *rnhlevh)
 {
+  double *vct = NULL;
   int zaxisIDh = -1;
   int nhlev = 0, nhlevf = 0, nhlevh = 0;
   int nvct = 0;
-  double *vct = NULL;
   
   bool lhavevct = false;
   int nzaxis = vlistNzaxis(vlistID);
-  for ( int i = 0; i < nzaxis; ++i )
+  for ( int iz = 0; iz < nzaxis; ++iz )
     {
       // bool mono_level = false;
       bool mono_level = true;
-      int zaxisID = vlistZaxis(vlistID, i);
+      int zaxisID = vlistZaxis(vlistID, iz);
       int nlevel  = zaxisInqSize(zaxisID);
+      int zaxistype = zaxisInqType(zaxisID);
 
-      if ( (zaxisInqType(zaxisID) == ZAXIS_HYBRID || zaxisInqType(zaxisID) == ZAXIS_HYBRID_HALF) &&
-	   nlevel > 1 )
+      if ( (zaxistype == ZAXIS_HYBRID || zaxistype == ZAXIS_HYBRID_HALF) && nlevel > 1 && !mono_level )
 	{
 	  int l;
 	  double *level = (double*) Malloc(nlevel*sizeof(double));
-	  zaxisInqLevels(zaxisID, level);
+	  cdoZaxisInqLevels(zaxisID, level);
 	  for ( l = 0; l < nlevel; l++ )
 	    {
 	      if ( (l+1) != (int) (level[l]+0.5) ) break;
@@ -403,8 +429,7 @@ double *vlist_read_vct(int vlistID, int *rzaxisIDh, int *rnvct, int *rnhlev, int
 	  Free(level);
 	}
 
-      if ( (zaxisInqType(zaxisID) == ZAXIS_HYBRID || zaxisInqType(zaxisID) == ZAXIS_HYBRID_HALF) &&
-	   nlevel > 1 && mono_level )
+      if ( (zaxistype == ZAXIS_HYBRID || zaxistype == ZAXIS_HYBRID_HALF) && nlevel > 1 && mono_level )
 	{
 	  nvct = zaxisInqVctSize(zaxisID);
 	  if ( nlevel == (nvct/2 - 1) )
@@ -458,7 +483,7 @@ double *vlist_read_vct(int vlistID, int *rzaxisIDh, int *rnvct, int *rnhlev, int
 
 		      /* calculate VCT for LM */
 
-		      for ( i = 0; i < vctsize/2; i++ )
+		      for ( int i = 0; i < vctsize/2; i++ )
 			{
 			  if ( rvct[voff+i] >= rvct[voff] && rvct[voff+i] <= rvct[3] )
 			    {
@@ -474,7 +499,7 @@ double *vlist_read_vct(int vlistID, int *rzaxisIDh, int *rnvct, int *rnhlev, int
 		      
 		      if ( cdoVerbose )
 			{
-			  for ( i = 0; i < vctsize/2; i++ )
+			  for ( int i = 0; i < vctsize/2; i++ )
 			    fprintf(stdout, "%5d %25.17f %25.17f\n", i, vct[i], vct[vctsize/2+i]);
 			}
 		    }
@@ -499,7 +524,7 @@ void vlist_change_hybrid_zaxis(int vlistID1, int vlistID2, int zaxisID1, int zax
   int nvct0 = 0;
   double *vct = NULL;
 
-  int nzaxis  = vlistNzaxis(vlistID1);
+  int nzaxis = vlistNzaxis(vlistID1);
   for ( int i = 0; i < nzaxis; ++i )
     {
       int zaxisID = vlistZaxis(vlistID1, i);
@@ -526,3 +551,30 @@ void vlist_change_hybrid_zaxis(int vlistID1, int vlistID2, int zaxisID1, int zax
 
   if ( vct ) Free(vct);
 }
+
+
+int vlist_get_psvarid(int vlistID, int zaxisID)
+{
+  int psvarid = -1;
+  char name[CDI_MAX_NAME];
+  char psname[CDI_MAX_NAME]; psname[0] = 0;
+  cdiZaxisInqKeyStr(zaxisID, CDI_KEY_PSNAME, CDI_MAX_NAME, psname);
+
+  if ( psname[0] )
+    {
+      int nvars = vlistNvars(vlistID);
+      for ( int varID = 0; varID < nvars; ++varID )
+        {
+          vlistInqVarName(vlistID, varID, name);
+          if ( strcmp(name, psname) == 0 )
+            {
+              psvarid = varID;
+              break;
+            }
+        }
+      if ( cdoVerbose && psvarid == -1 )
+        cdoWarning("Surface pressure variable not found - %s", psname);
+    }
+
+  return psvarid;
+}
diff --git a/src/cdotest.c b/src/cdotest.c
old mode 100755
new mode 100644
index 0b0bf69..686a766
--- a/src/cdotest.c
+++ b/src/cdotest.c
@@ -110,13 +110,13 @@ void writeNcFile(const char path[], const double array[], int length)
   
   varID = vlistDefVar(vlistID, gridID, zaxisID, TSTEP_INSTANT);
   vlistDefVarName(vlistID, varID, "test_values");
-  vlistDefVarDatatype(vlistID, varID, DATATYPE_FLT64);
+  vlistDefVarDatatype(vlistID, varID, CDI_DATATYPE_FLT64);
   vlistDefVarMissval(vlistID, varID, MISSVAL);
   
   taxisID = taxisCreate(TAXIS_ABSOLUTE);
   vlistDefTaxis(vlistID, taxisID);
   
-  streamID = streamOpenWrite(path, FILETYPE_NC);
+  streamID = streamOpenWrite(path, CDI_FILETYPE_NC);
   if ( streamID < 0 ) 
     {
       fprintf(stderr, "%s\n", cdiStringError(streamID));
diff --git a/src/cmortable_parser.c b/src/cmortable_parser.c
new file mode 100644
index 0000000..6174c47
--- /dev/null
+++ b/src/cmortable_parser.c
@@ -0,0 +1,321 @@
+#include <errno.h>
+#include "cdo_int.h"
+#include "pmlist.h"
+#include "json/jsmn.h"
+
+
+static
+char *readLineFromBuffer(char *buffer, size_t *buffersize, char *line, size_t len)
+{
+  int ichar;
+  size_t ipos = 0;
+
+  while ( *buffersize )
+    {
+      ichar = *buffer;
+      (*buffersize)--;
+      buffer++;
+      if ( ichar == '\r' )
+        {
+          if ( *buffersize )
+            {
+              ichar = *buffer;
+              if ( ichar == '\n' )
+                {
+                  (*buffersize)--;
+                  buffer++;
+                }
+            }
+          break;
+        }
+      if ( ichar == '\n' ) break;
+      line[ipos++] = ichar;
+      if ( ipos >= len )
+        {
+          fprintf(stderr, "readLineFromBuffer: end of line not found (maxlen = %ld)!\n", len);
+          break;
+        }
+    }
+
+  line[ipos] = 0;
+
+  if ( *buffersize == 0 && ipos == 0 ) buffer = NULL;
+
+  return buffer;
+}
+
+static
+char *skipSeparator(char *pline)
+{
+  while ( isspace((int) *pline) ) pline++;
+  if ( *pline == '=' || *pline == ':' ) pline++;
+  while ( isspace((int) *pline) ) pline++;
+
+  return pline;
+}
+
+static
+char *getElementName(char *pline, char *name)
+{
+  while ( isspace((int) *pline) ) pline++;
+  size_t len = strlen(pline);
+  size_t pos = 0;
+  while ( pos < len && !isspace((int) *(pline+pos)) && *(pline+pos) != '=' && *(pline+pos) != ':' ) pos++;
+
+  strncpy(name, pline, pos);
+  name[pos] = 0;
+
+  pline += pos;
+  return pline;
+}
+
+static
+char *getElementValue(char *pline)
+{
+  while ( isspace((int) *pline) ) pline++;
+  size_t len = strlen(pline);
+  if ( *pline != '"' && *pline != '\'' )
+    for ( size_t i = 1; i < len; ++i )
+      if ( pline[i] == '!' ) { pline[i] = 0; len = i; break; }
+  while ( isspace((int) *(pline+len-1)) && len ) { *(pline+len-1) = 0; len--; }
+
+  return pline;
+}
+
+
+void cmortablebuf_to_pmlist(list_t *pmlist, size_t buffersize, char *buffer)
+{
+  char line[4096];
+  char name[256];
+  char *pline;
+  const char *listentry[] = {"axis_entry", "variable_entry"};
+  int nentry = sizeof(listentry)/sizeof(listentry[0]);
+  int linenumber = 0;
+  list_t *kvlist = NULL;
+
+  while ( (buffer = readLineFromBuffer(buffer, &buffersize, line, sizeof(line))) )
+    {
+      linenumber++;
+      pline = line;
+      while ( isspace((int) *pline) ) pline++;
+      if ( *pline == '#' || *pline == '!' || *pline == '\0' ) continue;
+      //  len = (int) strlen(pline);
+
+      int ientry = -1;
+      for ( ientry = 0; ientry < nentry; ++ientry )
+        if ( strncmp(pline, listentry[ientry], strlen(listentry[ientry])) == 0 ) break;
+      
+      if ( ientry < nentry )
+	{
+	  pline += strlen(listentry[ientry]);
+
+          kvlist = kvlist_new(listentry[ientry]);
+          list_append(pmlist, &kvlist);
+
+	  pline = skipSeparator(pline);
+	  pline = getElementValue(pline);
+
+	  if ( *pline ) kvlist_append(kvlist, "name", (const char **)&pline, 1);
+	}
+      else
+	{
+	  pline = getElementName(pline, name);
+	  pline = skipSeparator(pline);
+	  pline = getElementValue(pline);
+
+	  if ( kvlist == NULL )
+            {
+              kvlist = kvlist_new("Header");
+              list_append(pmlist, &kvlist);
+            }
+
+	  if ( *pline ) kvlist_append(kvlist, name, (const char **)&pline, 1);
+	}
+    }
+}
+
+// not used
+int dump_json(const char *js, jsmntok_t *t, size_t count, int level)
+{
+  int i, j, k;
+  if (count == 0)  return 0;
+
+  if (t->type == JSMN_PRIMITIVE)
+    {
+      printf("%.*s", t->end - t->start, js+t->start);
+      return 1;
+    }
+  else if (t->type == JSMN_STRING)
+    {
+      printf("'%.*s'", t->end - t->start, js+t->start);
+      return 1;
+    }
+  else if (t->type == JSMN_OBJECT)
+    {
+      printf("\n");
+      //  printf("Object: size %d\n", t->size);
+      printf("Object: size %d count %d level %d\n", t->size, (int)count, level);
+      j = 0;
+      for (i = 0; i < t->size; i++)
+        {
+          for (k = 0; k < level; k++) printf("  ");
+          j += dump_json(js, t+1+j, count-j, level+1);
+          printf(": ");
+          j += dump_json(js, t+1+j, count-j, level+1);
+          printf("\n");
+        }
+      return j+1;
+    }
+  else if (t->type == JSMN_ARRAY)
+    {
+      j = 0;
+      printf("\n");
+      for (i = 0; i < t->size; i++)
+        {
+          for (k = 0; k < level-1; k++) printf("  ");
+          printf("   - ");
+          j += dump_json(js, t+1+j, count-j, level+1);
+          printf("\n");
+        }
+      return j+1;
+    }
+  return 0;
+}
+
+static
+void kvlist_append_json(list_t *kvlist, const char *key, const char *js, jsmntok_t *t, int nvalues)
+{
+  keyValues_t *keyval = (keyValues_t *) malloc(sizeof(keyValues_t));
+  keyval->key = strdup(key);
+  keyval->nvalues = nvalues;
+  keyval->values = (char **) malloc(nvalues*sizeof(char*));
+  for ( int i = 0; i < nvalues; ++i )
+    {
+      size_t len = t[i].end - t[i].start;
+      char *value = (char*) malloc((len+1)*sizeof(char));
+      snprintf(value, len+1, "%.*s", (int)len, js+t[i].start);
+      value[len] = 0;
+      // printf("set %s: '%s'\n", key, value);
+      keyval->values[i] = value;
+    }
+  list_append(kvlist, &keyval);
+}
+
+static
+int json_to_pmlist(list_t *pmlist, const char *js, jsmntok_t *t, int count)
+{
+  bool debug = false;
+  char name[4096];
+  int i = 0;
+  int nobj = t[0].size;
+  if ( t[0].type == JSMN_OBJECT )
+    while ( nobj-- )
+      {
+        ++i;
+        int pmlname = i;
+        if ( debug ) printf("  object: %.*s\n", t[i].end - t[i].start, js+t[i].start);
+        ++i;
+        if ( t[i].type == JSMN_OBJECT )
+          {
+            int ic = 0;
+          NEXT:
+            snprintf(name, sizeof(name), "%.*s", t[pmlname].end - t[pmlname].start, js+t[pmlname].start);
+            name[sizeof(name)-1] = 0;
+            // printf("new object: %s\n", name);
+            list_t *kvlist = kvlist_new(name);
+            list_append(pmlist, &kvlist);
+                
+            if ( t[i+2].type == JSMN_OBJECT )
+              {
+                if ( ic == 0 ) ic = t[i].size;
+                else           ic--;
+                
+                ++i;
+                kvlist_append_json(kvlist, "name", js, &t[i], 1);
+                if ( debug ) printf("    name: '%.*s'\n", t[i].end - t[i].start, js+t[i].start);
+                ++i;
+              }
+            int n = t[i].size;
+            while ( n-- )
+              {
+                ++i;
+                snprintf(name, sizeof(name), "%.*s", t[i].end - t[i].start, js+t[i].start);
+                name[sizeof(name)-1] = 0;
+                if ( debug ) printf("    %.*s:", t[i].end - t[i].start, js+t[i].start);
+                ++i;
+                if ( t[i].type == JSMN_ARRAY )
+                  {
+                    int nae = t[i].size;
+                    kvlist_append_json(kvlist, name, js, &t[i+1], nae);
+                    while ( nae-- )
+                      {
+                        ++i;
+                        if ( debug ) printf(" '%.*s'", t[i].end - t[i].start, js+t[i].start);
+                      }
+                  }
+                else
+                  {
+                    kvlist_append_json(kvlist, name, js, &t[i], 1);
+                    if ( debug ) printf(" '%.*s'", t[i].end - t[i].start, js+t[i].start);
+                  }
+                if ( debug ) printf("\n");
+              }
+            if ( ic > 1 ) goto NEXT;
+          }
+      }
+
+  if ( debug ) printf("Processed %d of %d tokens!\n", i, count-1);
+
+  return 0;
+}
+
+
+void cmortablebuf_to_pmlist_json(list_t *pmlist, size_t buffersize, char *buffer, const char *filename)
+{
+  /* Prepare parser */
+  jsmn_parser *p = jsmn_new();
+
+  int status = jsmn_parse(p, buffer, buffersize);
+  if ( status != 0 )
+    {
+      switch (status)
+        {
+        case JSMN_ERROR_INVAL: fprintf(stderr, "JSON error: Invalid character in %s (line=%d character='%c')!\n", filename, p->lineno, buffer[p->pos]); break;
+        case JSMN_ERROR_PART:  fprintf(stderr, "JSON error: End of string not found in %s (line=%d)!\n", filename, p->lineno); break;
+        default:               fprintf(stderr, "JSON error in %s (line=%d)\n", filename, p->lineno); break;
+        }
+    }
+
+  json_to_pmlist(pmlist, buffer, p->tokens, (int)p->toknext);
+  jsmn_destroy(p);
+}
+
+
+list_t *cmortable_to_pmlist(FILE *fp, const char *name)
+{
+  listbuf_t *listbuf = listbuf_new();
+  if ( listbuf_read(listbuf, fp, name) ) cdoAbort("Read error on CMOR table %s!", name);
+  
+  list_t *pmlist = NULL;
+
+  if ( listbuf->buffer[0] == '{' )
+    {
+      pmlist = list_new(sizeof(list_t *), free_kvlist, name);
+      cmortablebuf_to_pmlist_json(pmlist, listbuf->size, listbuf->buffer, name);
+    }
+  else if ( strncmp(listbuf->buffer, "table_id:", 9) == 0 )
+    {
+      pmlist = list_new(sizeof(list_t *), free_kvlist, name);
+      cmortablebuf_to_pmlist(pmlist, listbuf->size, listbuf->buffer);
+    }
+  else if ( listbuf->buffer[0] == '&' || listbuf->buffer[0] == '#' )
+    {
+      pmlist = namelistbuf_to_pmlist(listbuf);
+    }
+  else
+    cdoAbort("Invalid CMOR table (file: %s)!", name);
+
+  listbuf_destroy(listbuf);
+
+  return pmlist;
+}
diff --git a/src/commandline.c b/src/commandline.c
index 49d8bce..31f2acc 100644
--- a/src/commandline.c
+++ b/src/commandline.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
diff --git a/src/compare.h b/src/compare.h
index 6aeb13a..76f9340 100644
--- a/src/compare.h
+++ b/src/compare.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -50,4 +50,6 @@
 #  define IS_EQUAL(x,y)     (!IS_NOT_EQUAL(x,y))
 #endif
 
+#define STR_IS_EQ(x,y) ((*x)==(*y) && strcmp(x,y) == 0)
+
 #endif  /* _COMPARE_H */
diff --git a/src/convert_units.c b/src/convert_units.c
new file mode 100644
index 0000000..dff4031
--- /dev/null
+++ b/src/convert_units.c
@@ -0,0 +1,190 @@
+#include <errno.h>
+#include "convert_units.h"
+
+#if defined(HAVE_UDUNITS2)
+
+static void udunitsInitialize(void);
+static int udunitsInit = 0;
+
+#if defined(HAVE_LIBPTHREAD)
+#  include <pthread.h>
+
+static pthread_once_t  udunitsInitThread = PTHREAD_ONCE_INIT;
+static pthread_mutex_t udunitsMutex;
+
+#  define UDUNITS_LOCK()         pthread_mutex_lock(&udunitsMutex)
+#  define UDUNITS_UNLOCK()       pthread_mutex_unlock(&udunitsMutex)
+#  define UDUNITS_INIT()         pthread_once(&udunitsInitThread, udunitsInitialize)
+
+#else
+
+#  define UDUNITS_LOCK()
+#  define UDUNITS_UNLOCK()
+#  define UDUNITS_INIT()         if ( !udunitsInit ) udunitsInitialize();
+
+#endif
+
+static ut_system *ut_read = NULL;
+
+static
+void udunitsInitialize(void)
+{
+#if defined(HAVE_LIBPTHREAD)
+  /* initialize global API mutex lock */
+  pthread_mutex_init(&udunitsMutex, NULL);
+#endif
+
+  udunitsInit = 1;
+}
+
+static
+void *get_converter(char *src_unit_str, char *tgt_unit_str, int *rstatus)
+{
+  ut_unit *src_unit, *tgt_unit;
+  cv_converter *ut_units_converter = NULL;
+  int status;
+
+  *rstatus = -1;
+
+  if ( ut_read == NULL )
+    {
+      ut_set_error_message_handler(ut_ignore);
+
+      errno = 0;
+      ut_read = ut_read_xml(NULL);
+      status = ut_get_status();
+      if ( status == UT_PARSE )
+	{
+	  if ( cdoVerbose ) cdoWarning("Udunits: Couldn't parse unit database!");
+	}
+      if ( status == UT_OPEN_ENV || status == UT_OPEN_DEFAULT || status == UT_OS )
+	{
+	  if ( cdoVerbose ) cdoWarning("Udunits: %s", strerror(errno));
+	}
+      errno = 0;
+      if ( status != UT_SUCCESS )
+	{
+	  if ( cdoVerbose ) cdoWarning("Udunits: Error reading units system!");
+	  return NULL;
+	}
+    }
+
+  ut_trim(src_unit_str, UT_ASCII);
+  src_unit = ut_parse(ut_read, src_unit_str, UT_ASCII);
+  if ( ut_get_status() != UT_SUCCESS )
+    {
+      if ( cdoVerbose ) cdoWarning("Udunits: Error parsing units: [%s]", src_unit_str);
+      return NULL;
+    }
+
+  ut_trim(tgt_unit_str, UT_ASCII);
+  tgt_unit = ut_parse(ut_read, tgt_unit_str, UT_ASCII);
+  if ( ut_get_status() != UT_SUCCESS )
+    {
+      if ( cdoVerbose ) cdoWarning("Udunits: Error parsing units: [%s]", tgt_unit_str);
+      return NULL;
+    }
+
+  status = ut_compare(src_unit, tgt_unit);
+  if ( status == 0 ) *rstatus = -2;
+
+  if ( *rstatus == -1 )
+    {
+      status = ut_are_convertible(src_unit, tgt_unit);
+      if ( status == 0 ) *rstatus = -3;
+    }
+
+  if ( *rstatus == -1 )
+    {
+      ut_units_converter = ut_get_converter(src_unit, tgt_unit);
+      if ( ut_units_converter == NULL || ut_get_status() != UT_SUCCESS )
+	{
+	  if ( cdoVerbose ) cdoWarning("Udunits: Error getting converter from [%s] to [%s]", src_unit_str, tgt_unit_str);
+	}
+      else
+	*rstatus = 0;
+    }
+
+  ut_free(src_unit);
+  if ( ut_get_status() != UT_SUCCESS )
+    {
+      if ( cdoVerbose ) cdoWarning("Udunits: Error freeing units [%s]", src_unit_str);
+      return NULL;
+    }
+     
+  ut_free(tgt_unit);
+  if ( ut_get_status() != UT_SUCCESS )
+    {
+      if ( cdoVerbose ) cdoWarning("Udunits: Error freeing units [%s]", tgt_unit_str);
+      return NULL;
+    }
+
+  return (void *) ut_units_converter;
+}
+
+
+void cdoConvertFree(void *ut_converter)
+{
+  UDUNITS_LOCK();
+  cv_free((cv_converter*)ut_converter);
+  UDUNITS_UNLOCK();
+}
+
+
+void cdoConvertDestroy()
+{
+  UDUNITS_LOCK();
+  if ( ut_read )
+    { 
+      ut_free_system(ut_read);
+      ut_read = NULL;
+    }
+  UDUNITS_UNLOCK();
+}
+#endif
+
+void cdoConvertUnits(void **ut_converter, bool *changeunits, char *units, char *units_old, const char *name)
+{
+  if ( *changeunits )
+    {
+#if defined(HAVE_UDUNITS2)
+      int status;
+      UDUNITS_INIT();
+      UDUNITS_LOCK();
+      *ut_converter = get_converter(units_old, units, &status);
+      UDUNITS_UNLOCK();
+      if ( *ut_converter == NULL )
+	{
+	  if ( status == -2 )
+	    {
+	      if ( cdoVerbose )
+		cdoPrint("%s - not converted from  [%s] to [%s], units are equal!", name, units_old, units);
+	    }
+	  else if ( status == -3 )
+	    {
+	      cdoWarning("%s - converting units from [%s] to [%s] failed, not convertible!", name, units_old, units);
+	    }
+	  else
+	    cdoWarning("%s - converting units from [%s] to [%s] failed!", name, units_old, units);
+	  *changeunits = false;
+	}
+      else
+	{
+	  // if ( cdoVerbose )
+	    {
+	      char buf[64];
+	      cv_get_expression((const cv_converter*)*ut_converter, buf, sizeof(buf), name);
+	      cdoPrint("%s - convert units from [%s] to [%s] (expression: %s).", name, units_old, units, buf);
+	    }
+	}
+#else
+      static bool lwarn_udunits = true;
+      if ( lwarn_udunits )
+	{
+	  cdoWarning("%s - converting units from [%s] to [%s] failed, UDUNITS2 support not compiled in!", name, units_old, units);
+	  *changeunits = false;
+	  lwarn_udunits = false;
+	}
+#endif
+    }
+}
diff --git a/src/convert_units.h b/src/convert_units.h
new file mode 100644
index 0000000..3ea15d1
--- /dev/null
+++ b/src/convert_units.h
@@ -0,0 +1,27 @@
+#ifndef __CONVERT_UNITS_H_
+#define __CONVERT_UNITS_H_
+
+#if  defined(HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#if defined(HAVE_LIBUDUNITS2) && (defined(HAVE_UDUNITS2_H) || defined(HAVE_UDUNITS2_UDUNITS2_H))
+#define HAVE_UDUNITS2
+#endif
+
+#if defined(HAVE_UDUNITS2)
+#if defined(HAVE_UDUNITS2_UDUNITS2_H)
+#  include <udunits2/udunits2.h>
+#else
+#  include <udunits2.h>
+#endif
+
+void cdoConvertFree(void *ut_converter);
+void cdoConvertDestroy();
+#endif
+
+#include "cdo_int.h"
+
+void cdoConvertUnits(void **ut_converter, bool *changeunits, char *units, char *units_old, const char *name);
+
+#endif // __CONVERT_UNITS_H_
diff --git a/src/datetime.c b/src/datetime.c
index ff689bc..bd1131a 100644
--- a/src/datetime.c
+++ b/src/datetime.c
@@ -2,7 +2,8 @@
 #include "cdo_int.h"
 #include "datetime.h"
 
-int CDO_Timestat_Date = -1;
+int  CDO_Timestat_Date = -1;
+bool CDO_Timestat_Bounds = false ;
 
 static
 void get_timestat_date(int *tstat_date)
@@ -105,7 +106,8 @@ void dtlist_taxisInqTimestep(dtlist_type *dtlist, int taxisID, int tsID)
       taxisInqVdateBounds(taxisID, &(dtlist->dtinfo[tsID].b[0].date), &(dtlist->dtinfo[tsID].b[1].date));
       taxisInqVtimeBounds(taxisID, &(dtlist->dtinfo[tsID].b[0].time), &(dtlist->dtinfo[tsID].b[1].time));
 
-      if ( dtlist->dtinfo[tsID].v.date == dtlist->dtinfo[tsID].b[1].date &&
+      if ( CDO_Timestat_Bounds &&
+           dtlist->dtinfo[tsID].v.date == dtlist->dtinfo[tsID].b[1].date &&
            dtlist->dtinfo[tsID].v.time == dtlist->dtinfo[tsID].b[1].time )
         {
           int calendar = dtlist->calendar;
diff --git a/src/ecacore.c b/src/ecacore.c
old mode 100755
new mode 100644
index 5a43380..139da3e
--- a/src/ecacore.c
+++ b/src/ecacore.c
@@ -43,7 +43,7 @@ void eca1(const ECA_REQUEST_1 *request)
   int ivdate = 0, ivtime = 0;
   int ovdate = 0, ovtime = 0;
   int nrecs, nrecords;
-  int gridID, zaxisID, varID, levelID, recID;
+  int gridID, zaxisID, varID, levelID;
   int itsID;
   int otsID;
   long nsets;
@@ -53,8 +53,8 @@ void eca1(const ECA_REQUEST_1 *request)
   int nlevels;
   int *recVarID, *recLevelID;
   double missval;
-  field_t *var12 = NULL, *samp1 = NULL, *samp2 = NULL, *var13 = NULL, *var21 = NULL, *var23 = NULL, *var;
-  field_t field1, field2;
+  field_type *var12 = NULL, *samp1 = NULL, *samp2 = NULL, *var13 = NULL, *var21 = NULL, *var23 = NULL, *var;
+  field_type field1, field2;
   
   cmplen = DATE_LEN - cdoOperatorF2(operatorID);
 
@@ -124,16 +124,16 @@ void eca1(const ECA_REQUEST_1 *request)
 
   nlevels = zaxisInqSize(zaxisID);
 
-  var12 = (field_t*) Malloc(nlevels*sizeof(field_t));
-  samp1 = (field_t*) Malloc(nlevels*sizeof(field_t));
-  samp2 = (field_t*) Malloc(nlevels*sizeof(field_t));
+  var12 = (field_type*) Malloc(nlevels*sizeof(field_type));
+  samp1 = (field_type*) Malloc(nlevels*sizeof(field_type));
+  samp2 = (field_type*) Malloc(nlevels*sizeof(field_type));
   if ( IS_SET(request->var1.f3) ) 
-    var13 = (field_t*) Malloc(nlevels*sizeof(field_t));
+    var13 = (field_type*) Malloc(nlevels*sizeof(field_type));
     
   if ( IS_SET(request->var2.h2) ) 
-    var21 = (field_t*) Malloc(nlevels*sizeof(field_t));
+    var21 = (field_type*) Malloc(nlevels*sizeof(field_type));
   if ( IS_SET(request->var2.h3) ) 
-    var23 = (field_t*) Malloc(nlevels*sizeof(field_t));
+    var23 = (field_type*) Malloc(nlevels*sizeof(field_type));
       
   for ( levelID = 0; levelID < nlevels; levelID++ )
     {
@@ -196,7 +196,7 @@ void eca1(const ECA_REQUEST_1 *request)
 
 	  if ( DATE_IS_NEQ(indate1, indate2, cmplen) ) break;
 
-          for ( recID = 0; recID < nrecs; recID++ )
+          for ( int recID = 0; recID < nrecs; recID++ )
             {
               streamInqRecord(istreamID, &varID, &levelID);
 
@@ -411,7 +411,7 @@ void eca2(const ECA_REQUEST_2 *request)
   int ivdate = 0, ivtime = 0;
   int ovdate = 0, ovtime = 0;
   int nrecs, nrecords;
-  int gridID, zaxisID, varID, levelID, recID;
+  int gridID, zaxisID, varID, levelID;
   int itsID;
   int otsID;
   long nsets;
@@ -421,8 +421,8 @@ void eca2(const ECA_REQUEST_2 *request)
   int nlevels;
   int *recVarID, *recLevelID;
   double missval1, missval2;
-  field_t *var14 = NULL, *samp1 = NULL, *samp2 = NULL, *samp3 = NULL, *total = NULL, *var15 = NULL, *var22 = NULL, *var;
-  field_t field1, field2;
+  field_type *var14 = NULL, *samp1 = NULL, *samp2 = NULL, *samp3 = NULL, *total = NULL, *var15 = NULL, *var22 = NULL, *var;
+  field_type field1, field2;
   
   cmplen = DATE_LEN - cdoOperatorF2(operatorID);
 
@@ -493,17 +493,17 @@ void eca2(const ECA_REQUEST_2 *request)
 
   nlevels = zaxisInqSize(zaxisID);
   
-  var14 = (field_t*) Malloc(nlevels*sizeof(field_t));
-  samp1 = (field_t*) Malloc(nlevels*sizeof(field_t));
-  samp2 = (field_t*) Malloc(nlevels*sizeof(field_t));
-  samp3 = (field_t*) Malloc(nlevels*sizeof(field_t));
+  var14 = (field_type*) Malloc(nlevels*sizeof(field_type));
+  samp1 = (field_type*) Malloc(nlevels*sizeof(field_type));
+  samp2 = (field_type*) Malloc(nlevels*sizeof(field_type));
+  samp3 = (field_type*) Malloc(nlevels*sizeof(field_type));
   
   if ( request->var1.epilog == PERCENT_OF_TOTAL_AMOUNT )
-    total = (field_t*) Malloc(nlevels*sizeof(field_t));
+    total = (field_type*) Malloc(nlevels*sizeof(field_type));
   if ( IS_SET(request->var1.f5) )
-    var15 = (field_t*) Malloc(nlevels*sizeof(field_t));
+    var15 = (field_type*) Malloc(nlevels*sizeof(field_type));
   if ( IS_SET(request->var2.h2) )
-    var22 = (field_t*) Malloc(nlevels*sizeof(field_t));
+    var22 = (field_type*) Malloc(nlevels*sizeof(field_type));
       
   for ( levelID = 0; levelID < nlevels; levelID++ )
     {
@@ -575,7 +575,7 @@ void eca2(const ECA_REQUEST_2 *request)
 
 	  if ( DATE_IS_NEQ(indate1, indate2, cmplen) ) break;
 
-          for ( recID = 0; recID < nrecs; recID++ )
+          for ( int recID = 0; recID < nrecs; recID++ )
             {
               streamInqRecord(istreamID1, &varID, &levelID);
               streamInqRecord(istreamID2, &varID, &levelID);
@@ -802,7 +802,7 @@ void eca3(const ECA_REQUEST_3 *request)
   int ivdate2 = 0, ivtime2 = 0;
   int ovdate = 0, ovtime = 0;
   int nrecs, nrecords;
-  int gridID, zaxisID, varID, levelID, recID;
+  int gridID, zaxisID, varID, levelID;
   int itsID;
   int otsID;
   long nsets;
@@ -812,8 +812,8 @@ void eca3(const ECA_REQUEST_3 *request)
   int nlevels;
   int *recVarID, *recLevelID;
   double missval;
-  field_t *var1 = NULL, *var2 = NULL;
-  field_t field1, field2;
+  field_type *var1 = NULL, *var2 = NULL;
+  field_type field1, field2;
   
   cmplen = DATE_LEN - cdoOperatorF2(operatorID);
 
@@ -870,8 +870,8 @@ void eca3(const ECA_REQUEST_3 *request)
 
   nlevels = zaxisInqSize(zaxisID);
 
-  var1 = (field_t*) Malloc(nlevels*sizeof(field_t));
-  var2 = (field_t*) Malloc(nlevels*sizeof(field_t));
+  var1 = (field_type*) Malloc(nlevels*sizeof(field_type));
+  var2 = (field_type*) Malloc(nlevels*sizeof(field_type));
         
   for ( levelID = 0; levelID < nlevels; levelID++ )
     {
@@ -913,7 +913,7 @@ void eca3(const ECA_REQUEST_3 *request)
 
 	  if ( DATE_IS_NEQ(indate1, indate2, cmplen) ) break;
 
-          for ( recID = 0; recID < nrecs; recID++ )
+          for ( int recID = 0; recID < nrecs; recID++ )
             {
               streamInqRecord(istreamID1, &varID, &levelID);
               streamInqRecord(istreamID2, &varID, &levelID);
@@ -1011,7 +1011,7 @@ void eca4(const ECA_REQUEST_4 *request)
   int ovdate = 0, ovtime = 0;
   int month, yearcnt = 0;
   int nrecs, nrecords;
-  int gridID, zaxisID, varID, ovarID1, ovarID2, levelID, recID;
+  int gridID, zaxisID, varID, ovarID1, ovarID2, levelID;
   int itsID;
   int otsID;
   long nsets;
@@ -1021,10 +1021,10 @@ void eca4(const ECA_REQUEST_4 *request)
   int nlevels;
   int *recVarID, *recLevelID;
   double missval;
-  field_t *startCount          , *endCount;
-  field_t *startDateWithHist[2], *endDateWithHist[2];
-  field_t *gslDuration, *gslFirstDay;
-  field_t fieldGt, fieldLt, mask;
+  field_type *startCount          , *endCount;
+  field_type *startDateWithHist[2], *endDateWithHist[2];
+  field_type *gslDuration, *gslFirstDay;
+  field_type fieldGt, fieldLt, mask;
   int resetAtJan = FALSE, resetAtJul = FALSE;
   int isFirstYear = TRUE;
 
@@ -1110,18 +1110,18 @@ void eca4(const ECA_REQUEST_4 *request)
 
   nlevels     = zaxisInqSize(zaxisID);
 
-  startCount  = (field_t*) Malloc(nlevels*sizeof(field_t));
-  endCount    = (field_t*) Malloc(nlevels*sizeof(field_t));
-  gslDuration = (field_t*) Malloc(nlevels*sizeof(field_t));
-  gslFirstDay = (field_t*) Malloc(nlevels*sizeof(field_t));
+  startCount  = (field_type*) Malloc(nlevels*sizeof(field_type));
+  endCount    = (field_type*) Malloc(nlevels*sizeof(field_type));
+  gslDuration = (field_type*) Malloc(nlevels*sizeof(field_type));
+  gslFirstDay = (field_type*) Malloc(nlevels*sizeof(field_type));
 
   /* because of the different definitions for northern and southern hemisphere,
    * the values of the last year have to be present
    * THE LAST YEAR HAS THE INDEX 1 */
   for ( int h = 0; h < 2; h++ )
   {
-    startDateWithHist[h] = (field_t*) Malloc(nlevels*sizeof(field_t));
-    endDateWithHist[h]   = (field_t*) Malloc(nlevels*sizeof(field_t));
+    startDateWithHist[h] = (field_type*) Malloc(nlevels*sizeof(field_type));
+    endDateWithHist[h]   = (field_type*) Malloc(nlevels*sizeof(field_type));
   }
 
   for ( levelID = 0; levelID < nlevels; levelID++ )
@@ -1209,7 +1209,7 @@ void eca4(const ECA_REQUEST_4 *request)
             break;
           }
 
-          for ( recID = 0; recID < nrecs; recID++ )
+          for ( int recID = 0; recID < nrecs; recID++ )
             {
               streamInqRecord(istreamID1, &varID, &levelID);
 
diff --git a/src/ecacore.h b/src/ecacore.h
old mode 100755
new mode 100644
index a4bf32f..a13ffc7
--- a/src/ecacore.h
+++ b/src/ecacore.h
@@ -27,9 +27,9 @@ typedef enum {
 }
 ECA_EPILOG;
 
-typedef void (*ECA_FUNC_1)(field_t *, double);
-typedef void (*ECA_FUNC_2)(field_t *, field_t);
-typedef void (*ECA_FUNC_3)(field_t *, field_t, double);
+typedef void (*ECA_FUNC_1)(field_type *, double);
+typedef void (*ECA_FUNC_2)(field_type *, field_type);
+typedef void (*ECA_FUNC_3)(field_type *, field_type, double);
 
 /**
  * Structure describing a processing request of the form
diff --git a/src/ecautil.c b/src/ecautil.c
old mode 100755
new mode 100644
index ae2511d..c6e04dd
--- a/src/ecautil.c
+++ b/src/ecautil.c
@@ -145,7 +145,7 @@ unsigned long day_of_year(int date)
  * @param mode   the counting mode, must be an exact mathematical
  *               integer
  */  
-static void count(field_t *field1, const field_t *field2, double mode)
+static void count(field_type *field1, const field_type *field2, double mode)
 {
   int   i, len;
   const int     grid1    = field1->grid;
@@ -229,7 +229,7 @@ static void count(field_t *field1, const field_t *field2, double mode)
  * @param field2  the reference field
  * @param compare the comparator
  */  
-static void selcomp(field_t *field1, const field_t *field2, int (*compare)(double, double))
+static void selcomp(field_type *field1, const field_type *field2, int (*compare)(double, double))
 {
   int   i, len;
   const int     grid1    = field1->grid;
@@ -280,7 +280,7 @@ static void selcomp(field_t *field1, const field_t *field2, int (*compare)(doubl
  * @param c       the refence value
  * @param compare the comparator
  */  
-static void selcompc(field_t *field, double c, int (*compare)(double, double))
+static void selcompc(field_type *field, double c, int (*compare)(double, double))
 {
   int   i, len;
   const int     grid    = field->grid;
@@ -350,25 +350,25 @@ static int ne(double a, double b)
 }
 
 
-void farnum(field_t *field1, field_t field2)
+void farnum(field_type *field1, field_type field2)
 {
   count(field1, &field2, 0.0);
 }
 
 
-void farnum2(field_t *field1, field_t field2)
+void farnum2(field_type *field1, field_type field2)
 {
   count(field1, &field2, 1.0);
 }
 
 
-void farnum3(field_t *field1, field_t field2, double n)
+void farnum3(field_type *field1, field_type field2, double n)
 {
   count(field1, &field2, n);
 }
 
 
-void farsel(field_t *field1, field_t field2)
+void farsel(field_type *field1, field_type field2)
 {
   int   i, len;
   const int     grid1    = field1->grid;
@@ -402,78 +402,78 @@ void farsel(field_t *field1, field_t field2)
 }
 
 
-void farselle(field_t *field1, field_t field2)
+void farselle(field_type *field1, field_type field2)
 {
   selcomp(field1, &field2, le);
 }
 
 
-void farsellt(field_t *field1, field_t field2)
+void farsellt(field_type *field1, field_type field2)
 {
   selcomp(field1, &field2, lt);
 }
 
 
-void farselge(field_t *field1, field_t field2)
+void farselge(field_type *field1, field_type field2)
 {
   selcomp(field1, &field2, ge);
 }
 
 
-void farselgt(field_t *field1, field_t field2)
+void farselgt(field_type *field1, field_type field2)
 {
   selcomp(field1, &field2, gt);
 }
 
 
-void farseleq(field_t *field1, field_t field2)
+void farseleq(field_type *field1, field_type field2)
 {
   selcomp(field1, &field2, eq);
 }
 
 
-void farselne(field_t *field1, field_t field2)
+void farselne(field_type *field1, field_type field2)
 {
   selcomp(field1, &field2, ne);
 }
 
 
-void farsellec(field_t *field, double c)
+void farsellec(field_type *field, double c)
 {
   selcompc(field, c, le);
 }
 
 
-void farselltc(field_t *field, double c)
+void farselltc(field_type *field, double c)
 {
   selcompc(field, c, lt);
 }
 
 
-void farselgec(field_t *field, double c)
+void farselgec(field_type *field, double c)
 {
   selcompc(field, c, ge);
 }
 
 
-void farseleqc(field_t *field, double c)
+void farseleqc(field_type *field, double c)
 {
   selcompc(field, c, eq);
 }
 
 
-void farselnec(field_t *field, double c)
+void farselnec(field_type *field, double c)
 {
   selcompc(field, c, ne);
 }
 
 
-void farselgtc(field_t *field, double c)
+void farselgtc(field_type *field, double c)
 {
   selcompc(field, c, gt);
 }
 
-void updateHist(field_t *field[2], int nlevels, int gridsize, double *yvals, int onlyNorth)
+void updateHist(field_type *field[2], int nlevels, int gridsize, double *yvals, int onlyNorth)
 {
   int levelID,i;
 
@@ -489,7 +489,7 @@ void updateHist(field_t *field[2], int nlevels, int gridsize, double *yvals, int
 }
 
 void adjustEndDate(int nlevels, int gridsize, double *yvals, double missval, int ovdate,
-                field_t *startDateWithHist[2], field_t *endDateWithHist[2])
+                field_type *startDateWithHist[2], field_type *endDateWithHist[2])
 {
   int levelID, i, ovdateSouth;
 
@@ -526,8 +526,8 @@ void adjustEndDate(int nlevels, int gridsize, double *yvals, double missval, int
 }
 
 void computeGsl(int nlevels, int gridsize, double *yvals, double missval,
-                field_t *startDateWithHist[2], field_t *endDateWithHist[2],
-                field_t *gslDuration, field_t *gslFirstDay,
+                field_type *startDateWithHist[2], field_type *endDateWithHist[2],
+                field_type *gslDuration, field_type *gslFirstDay,
                 int useCurrentYear)
 {
   int levelID, i;
@@ -609,21 +609,22 @@ void computeGsl(int nlevels, int gridsize, double *yvals, double missval,
 void writeGslStream(int ostreamID, int otaxisID, int otsID,
                     int ovarID1, int ovarID2, int ivlistID1,
                     int first_var_id,
-                    field_t *gslDuration, field_t *gslFirstDay,
+                    field_type *gslDuration, field_type *gslFirstDay,
                     int vdate, int vtime, int nlevels)
 {
-  int levelID;
+  (void)ivlistID1;
+  (void)first_var_id;
 
   taxisDefVdate(otaxisID, vdate);
   taxisDefVtime(otaxisID, vtime);
   streamDefTimestep(ostreamID, otsID);
 
-  for ( levelID = 0; levelID < nlevels; levelID++ )
+  for ( int levelID = 0; levelID < nlevels; levelID++ )
     {
       streamDefRecord(ostreamID, ovarID1, levelID);
       streamWriteRecord(ostreamID, gslDuration[levelID].ptr, gslDuration[levelID].nmiss);
     }
-  for ( levelID = 0; levelID < nlevels; levelID++ )
+  for ( int levelID = 0; levelID < nlevels; levelID++ )
     {
       streamDefRecord(  ostreamID, ovarID2, levelID);
       streamWriteRecord(ostreamID, gslFirstDay[levelID].ptr, gslFirstDay[levelID].nmiss);
diff --git a/src/ecautil.h b/src/ecautil.h
old mode 100755
new mode 100644
index 7f17dc7..7d4314b
--- a/src/ecautil.h
+++ b/src/ecautil.h
@@ -42,7 +42,7 @@ unsigned long day_of_year(int date);
  * @param field1 the 1st input field, also holds the result
  * @param field2 the 2nd input field  
  */  
-void farnum(field_t *field1, field_t field2);
+void farnum(field_type *field1, field_type field2);
 
 /**
  * Counts the number of consecutive nonmissing values in a field.
@@ -58,7 +58,7 @@ void farnum(field_t *field1, field_t field2);
  * @param field1 the 1st input field, also holds the result
  * @param field2 the 2nd input field  
  */  
-void farnum2(field_t *field1, field_t field2);
+void farnum2(field_type *field1, field_type field2);
 
 /**
  * Counts the number of values in series of at least n consecutive
@@ -76,7 +76,7 @@ void farnum2(field_t *field1, field_t field2);
  * @param n      the number of consecutive values, must be an exact
  *               mathematical integer
  */  
-void farnum3(field_t *field1, field_t field2, double n);
+void farnum3(field_type *field1, field_type field2, double n);
 
 /**
  * Selects field elements according to a given mask. The result of
@@ -91,7 +91,7 @@ void farnum3(field_t *field1, field_t field2, double n);
  * @param field1  the input field, also holds the result
  * @param field2  the mask
  */  
-void farsel(field_t *field1, field_t field2);
+void farsel(field_type *field1, field_type field2);
 
 /**
  * Selects all field elements that are less than or equal to the
@@ -107,7 +107,7 @@ void farsel(field_t *field1, field_t field2);
  * @param field1 the input field, also holds the result
  * @param field2 the reference field
  */  
-void farselle(field_t *field1, field_t field2);
+void farselle(field_type *field1, field_type field2);
 
 /**
  * Selects all field elements that are less than the
@@ -123,7 +123,7 @@ void farselle(field_t *field1, field_t field2);
  * @param field1 the input field, also holds the result
  * @param field2 the reference field
  */  
-void farsellt(field_t *field1, field_t field2);
+void farsellt(field_type *field1, field_type field2);
 
 /**
  * Selects all field elements that are greater than or equal to
@@ -139,7 +139,7 @@ void farsellt(field_t *field1, field_t field2);
  * @param field1 the input field, also holds the result
  * @param field2 the reference field
  */  
-void farselge(field_t *field1, field_t field2);
+void farselge(field_type *field1, field_type field2);
 
 /**
  * Selects all field elements that are greater than the
@@ -155,7 +155,7 @@ void farselge(field_t *field1, field_t field2);
  * @param field1 the input field, also holds the result
  * @param field2 the reference field
  */  
-void farselgt(field_t *field1, field_t field2);
+void farselgt(field_type *field1, field_type field2);
 
 /**
  * Selects all field elements that are equal to the
@@ -171,7 +171,7 @@ void farselgt(field_t *field1, field_t field2);
  * @param field1 the input field, also holds the result
  * @param field2 the reference field
  */  
-void farseleq(field_t *field1, field_t field2);
+void farseleq(field_type *field1, field_type field2);
 
 /**
  * Selects all field elements that are not equal to the
@@ -187,7 +187,7 @@ void farseleq(field_t *field1, field_t field2);
  * @param field1 the input field, also holds the result
  * @param field2 the reference field
  */  
-void farselne(field_t *field1, field_t field2);
+void farselne(field_type *field1, field_type field2);
 
 /**
  * Selects all field elements that are less than or equal to a
@@ -203,7 +203,7 @@ void farselne(field_t *field1, field_t field2);
  * @param field the input field, also holds the result
  * @param c     the reference value
  */  
-void farsellec(field_t *field, double c);
+void farsellec(field_type *field, double c);
 
 /**
  * Selects all field elements that are less a
@@ -219,7 +219,7 @@ void farsellec(field_t *field, double c);
  * @param field the input field, also holds the result
  * @param c     the reference value
  */  
-void farselltc(field_t *field, double c);
+void farselltc(field_type *field, double c);
 
 /**
  * Selects all field elements that are greater than or equal to a
@@ -235,7 +235,7 @@ void farselltc(field_t *field, double c);
  * @param field the input field, also holds the result
  * @param c     the reference value
  */  
-void farselgec(field_t *field, double c);
+void farselgec(field_type *field, double c);
 
 /**
  * Selects all field elements that are greater than a
@@ -251,7 +251,7 @@ void farselgec(field_t *field, double c);
  * @param field the input field, also holds the result
  * @param c     the reference value
  */  
-void farselgtc(field_t *field, double c);
+void farselgtc(field_type *field, double c);
 
 /**
  * Selects all field elements that are equal to a
@@ -267,7 +267,7 @@ void farselgtc(field_t *field, double c);
  * @param field the input field, also holds the result
  * @param c     the reference value
  */  
-void farseleqc(field_t *field, double c);
+void farseleqc(field_type *field, double c);
 
 /**
  * Selects all field elements that are not equal to a
@@ -283,7 +283,7 @@ void farseleqc(field_t *field, double c);
  * @param field the input field, also holds the result
  * @param c     the reference value
  */  
-void farselnec(field_t *field, double c);
+void farselnec(field_type *field, double c);
 
 /**
  * reset the fields real values to the missval for all levels
@@ -295,7 +295,7 @@ void farselnec(field_t *field, double c);
  * @param yvals     list of latitudes
  * @param onlyNorth boolean for processing only the norther hemisphere
  */
-void updateHist(field_t *field[2], int nlevels, int gridsize, double *yvals, int onlyNorth);
+void updateHist(field_type *field[2], int nlevels, int gridsize, double *yvals, int onlyNorth);
 
 /*
  * Compute the Gsl and its starting day
@@ -306,20 +306,20 @@ void updateHist(field_t *field[2], int nlevels, int gridsize, double *yvals, int
  * @param int ysize = number of gridpoints in lat-direction
  * @param double missval
  * @param int ovdate = the last year, which has been fully processed
- * @param field_t *startDate
- * @param field_t *endDate
- * @param field_t *startDateWithHist[2]
- * @param field_t *endDateWithHist[2]
- * @param field_t *gslDuration
- * @param field_t *gslFirstDay
+ * @param field_type *startDate
+ * @param field_type *endDate
+ * @param field_type *startDateWithHist[2]
+ * @param field_type *endDateWithHist[2]
+ * @param field_type *gslDuration
+ * @param field_type *gslFirstDay
  * @param int useCurrentYear = if TRUE, only measurements of the current year
  *                             (index 0) are used for computation, i.e. that
  *                             gsl can only be computed for the northern
  *                             hemisphere (see definition of GSL: EcaGsl()
  */
 void computeGsl(int nlevels, int gridsize, double *yvals, double missval, 
-                field_t *startDateWithHist[2], field_t *endDateWithHist[2],
-                field_t *gslDuration, field_t *gslFirstDay,
+                field_type *startDateWithHist[2], field_type *endDateWithHist[2],
+                field_type *gslDuration, field_type *gslFirstDay,
                 int useCurrentYear);
 
 /*
@@ -329,13 +329,13 @@ void computeGsl(int nlevels, int gridsize, double *yvals, double missval,
  * for southern hemisphere
  */
 void adjustEndDate(int nlevels, int gridsize, double *yvals, double missval, int ovdate,
-                   field_t *startDateWithHist[2], field_t *endDateWithHist[2]);
+                   field_type *startDateWithHist[2], field_type *endDateWithHist[2]);
 /*
  * Write GSL related fields to an output stream
  */
 void writeGslStream(int ostreamID, int otaxisID, int otsID, 
                     int ovarID1, int ovarID2, int ivlistID1,
                     int first_var_id,
-                    field_t *gslDuration, field_t *gslFirstDay,
+                    field_type *gslDuration, field_type *gslFirstDay,
                     int vdate, int vtime,  int nlevels);
 #endif /*ECAUTIL_H_*/
diff --git a/src/exception.c b/src/exception.c
index e92b79e..70c71a5 100644
--- a/src/exception.c
+++ b/src/exception.c
@@ -32,23 +32,23 @@ void cdiOpenError(int cdiErrno, const char *fmt, const char *path)
 
       switch (filetype)
 	{
-	case FILETYPE_GRB:
+	case CDI_FILETYPE_GRB:
           break;
-	case FILETYPE_GRB2:
-          fprintf(stderr, "To create a CDO application with GRIB2 support use: ./configure --with-netcdf=<GRIB_API root directory> ...\n");
+	case CDI_FILETYPE_GRB2:
+          fprintf(stderr, "To create a CDO application with GRIB2 support use: ./configure --with-grib_api=<GRIB_API root directory> ...\n");
           break;
-	case FILETYPE_SRV:
+	case CDI_FILETYPE_SRV:
           break;
-	case FILETYPE_EXT:
+	case CDI_FILETYPE_EXT:
           break;
-	case FILETYPE_IEG:
+	case CDI_FILETYPE_IEG:
           break;
-	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:
           {
-            const char *ncv = (filetype == FILETYPE_NC4 || filetype == FILETYPE_NC4C) ? "4" : ((filetype == FILETYPE_NC2) ? "2" : "");
+            const char *ncv = (filetype == CDI_FILETYPE_NC4 || filetype == CDI_FILETYPE_NC4C) ? "4" : ((filetype == CDI_FILETYPE_NC2) ? "2" : "");
 #if defined HAVE_LIBNETCDF
             fprintf(stderr, "CDO was build with a NetCDF version which doesn't support NetCDF%s data!\n", ncv);
 #else
diff --git a/src/expr.c b/src/expr.c
index bf056a0..c0675f2 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -39,15 +39,15 @@ int surfaceID = -1;
 
 enum {FT_STD, FT_CONST, FT_FLD, FT_VERT, FT_COORD, FT_1C};
 
-#define    COMPLT(x,y)  ((x) < (y) ? 1 : 0)
-#define    COMPGT(x,y)  ((x) > (y) ? 1 : 0)
-#define    COMPLE(x,y)  ((x) <= (y) ? 1 : 0)
-#define    COMPGE(x,y)  ((x) >= (y) ? 1 : 0)
-#define    COMPNE(x,y)  (IS_NOT_EQUAL(x,y) ? 1 : 0)
-#define    COMPEQ(x,y)  (IS_EQUAL(x,y) ? 1 : 0)
-#define   COMPLEG(x,y)  ((x) < (y) ? -1 : ((x) > (y) ? 1 : 0))
-#define   COMPAND(x,y)  (IS_NOT_EQUAL(x,0) && IS_NOT_EQUAL(y,0) ? 1 : 0)
-#define    COMPOR(x,y)  (IS_NOT_EQUAL(x,0) || IS_NOT_EQUAL(y,0) ? 1 : 0)
+#define    COMPLT(x,y)  ((x) < (y))
+#define    COMPGT(x,y)  ((x) > (y))
+#define    COMPLE(x,y)  ((x) <= (y))
+#define    COMPGE(x,y)  ((x) >= (y))
+#define    COMPNE(x,y)  IS_NOT_EQUAL(x,y)
+#define    COMPEQ(x,y)  IS_EQUAL(x,y)
+#define   COMPLEG(x,y)  ((x) < (y) ? -1. : ((x) > (y)))
+#define   COMPAND(x,y)  (IS_NOT_EQUAL(x,0) && IS_NOT_EQUAL(y,0))
+#define    COMPOR(x,y)  (IS_NOT_EQUAL(x,0) || IS_NOT_EQUAL(y,0))
 #define  MVCOMPLT(x,y)  (DBL_IS_EQUAL((x),missval1) ? missval1 : COMPLT(x,y))
 #define  MVCOMPGT(x,y)  (DBL_IS_EQUAL((x),missval1) ? missval1 : COMPGT(x,y))
 #define  MVCOMPLE(x,y)  (DBL_IS_EQUAL((x),missval1) ? missval1 : COMPLE(x,y))
@@ -701,8 +701,8 @@ nodeType *expr(int init, int oper, nodeType *p1, nodeType *p2)
         case '*':  coper = "*"; break;
         case '/':  coper = "/"; break;
         case '^':  coper = "^"; break;
-        case LT:   coper = ">"; break;
-        case GT:   coper = "<"; break;
+        case LT:   coper = "<"; break;
+        case GT:   coper = ">"; break;
         case LE:   coper = "<="; break;
         case GE:   coper = ">="; break;
         case NE:   coper = "!="; break;
@@ -837,7 +837,7 @@ nodeType *ex_fun_var(int init, int funcID, nodeType *p1)
         }
       else if ( functype == FT_FLD )
         {
-          field_t field;
+          field_type field;
           double *weights = NULL;
           //if ( funcflag == 1 ) weights = fld_weights(p1->param.gridID, ngp);
           if ( funcflag == 1 )
@@ -846,7 +846,7 @@ nodeType *ex_fun_var(int init, int funcID, nodeType *p1)
               assert(weights!=NULL);
             }
           
-          double (*exprfunc)(field_t) = (double (*)(field_t)) fun_sym_tbl[funcID].func;
+          double (*exprfunc)(field_type) = (double (*)(field_type)) fun_sym_tbl[funcID].func;
           for ( size_t k = 0; k < nlev; k++ )
             {
               fld_field_init(&field, nmiss, missval, ngp, p1data+k*ngp, weights);
@@ -856,11 +856,11 @@ nodeType *ex_fun_var(int init, int funcID, nodeType *p1)
         }
       else if ( functype == FT_VERT )
         {
-          field_t field;
+          field_type field;
           double *weights = NULL;
           if ( funcflag == 1 ) weights = vert_weights(p1->param.zaxisID, nlev);
           double *array = (double*) Malloc(nlev*sizeof(double));
-          double (*exprfunc)(field_t) = (double (*)(field_t)) fun_sym_tbl[funcID].func;
+          double (*exprfunc)(field_type) = (double (*)(field_type)) fun_sym_tbl[funcID].func;
           for ( size_t i = 0; i < ngp; i++ )
             {
               for ( size_t k = 0; k < nlev; k++ ) array[k] = p1data[k*ngp+i];
@@ -955,7 +955,7 @@ nodeType *fun1c(int init, int funcID, nodeType *p1, double value, parse_param_t
       parse_arg->coords[coordID].needed = true;
 
       data = (double*) Malloc(nlev*sizeof(double));
-      zaxisInqLevels(zaxisID, data);
+      cdoZaxisInqLevels(zaxisID, data);
     }
   else
     {
@@ -1076,12 +1076,12 @@ nodeType *ex_uminus_var(int init, nodeType *p1)
 
       if ( nmiss > 0 )
         {
-          for ( size_t i = 0; i < ngp*nlev; i++ )
+          for ( size_t i = 0; i < ngp*nlev; ++i )
             pdata[i] = DBL_IS_EQUAL(p1data[i], missval) ? missval : -(p1data[i]);
         }
       else
         {
-          for ( size_t i = 0; i < ngp*nlev; i++ )
+          for ( size_t i = 0; i < ngp*nlev; ++i )
             pdata[i] = -(p1data[i]);
         }
 
@@ -1136,13 +1136,13 @@ nodeType *ex_ifelse(int init, nodeType *p1, nodeType *p2, nodeType *p3)
     {
       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);
       if ( p2->type == typeCon )
-        printf("%g : ", p2->u.con.value);
+        fprintf(stderr, "%g : ", p2->u.con.value);
       else
-        printf("%s[L%lu][N%lu] : ", p2->u.var.nm, p2->param.nlev, p2->param.ngp);
+        fprintf(stderr, "%s[L%lu][N%lu] : ", p2->u.var.nm, p2->param.nlev, p2->param.ngp);
       if ( p3->type == typeCon )
-        printf("%g\n", p3->u.con.value);
+        fprintf(stderr, "%g\n", p3->u.con.value);
       else
-        printf("%s[L%lu][N%lu]\n", p3->u.var.nm, p3->param.nlev, p3->param.ngp);
+        fprintf(stderr, "%s[L%lu][N%lu]\n", p3->u.var.nm, p3->param.nlev, p3->param.ngp);
     }
 
   size_t nmiss1 = p1->param.nmiss;
@@ -1230,17 +1230,10 @@ nodeType *ex_ifelse(int init, nodeType *p1, nodeType *p2, nodeType *p3)
 
       for ( size_t k = 0; k < nlev; ++k )
         {
-          size_t loff1, loff2, loff3;
-          size_t loff = k*ngp;
-
-          if ( nlev1 == 1 ) loff1 = 0;
-          else              loff1 = k*ngp;
-
-          if ( nlev2 == 1 ) loff2 = 0;
-          else              loff2 = k*ngp;
-
-          if ( nlev3 == 1 ) loff3 = 0;
-          else              loff3 = k*ngp;
+          size_t loff  = k*ngp;
+          size_t loff1 = (nlev1 == 1) ? 0 : loff;
+          size_t loff2 = (nlev2 == 1) ? 0 : loff;
+          size_t loff3 = (nlev3 == 1) ? 0 : loff;
 
           const double *restrict idat1 = pdata1+loff1;
           const double *restrict idat2 = pdata2+loff2;
diff --git a/src/expr.h b/src/expr.h
index f8a013f..df84380 100644
--- a/src/expr.h
+++ b/src/expr.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
diff --git a/src/expr_fun.c b/src/expr_fun.c
index ab478e4..32923c2 100644
--- a/src/expr_fun.c
+++ b/src/expr_fun.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -19,7 +19,7 @@
 #include "grid.h"
 
 
-void fld_field_init(field_t *field, size_t nmiss, double missval, size_t ngp, double *array, double *w)
+void fld_field_init(field_type *field, size_t nmiss, double missval, size_t ngp, double *array, double *w)
 {
   field_init(field);
 
@@ -51,7 +51,7 @@ double *fld_weights(int gridID, size_t ngp)
 }
 
 
-int getLayerThickness(int genbounds, int index, int zaxisID, int nlev, double *thickness, double *weights);
+int getLayerThickness(bool genbounds, int index, int zaxisID, int nlev, double *thickness, double *weights);
 
 double *vert_weights(int zaxisID, size_t nlev)
 {
diff --git a/src/expr_fun.h b/src/expr_fun.h
index 4f48d54..8490fce 100644
--- a/src/expr_fun.h
+++ b/src/expr_fun.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -18,7 +18,7 @@
 #ifndef _EXPR_FUN_H
 #define _EXPR_FUN_H
 
-void fld_field_init(field_t *field, size_t nmiss, double missval, size_t ngp, double *array, double *w);
+void fld_field_init(field_type *field, size_t nmiss, double missval, size_t ngp, double *array, double *w);
 double *fld_weights(int gridID, size_t ngp);
 double *vert_weights(int zaxisID, size_t nlev);
 
diff --git a/src/features.c b/src/features.c
index a57b899..ecddc48 100644
--- a/src/features.c
+++ b/src/features.c
@@ -76,9 +76,6 @@ void printFeatures(void)
   fprintf(stderr, " Z");
 #endif
   */
-#if defined(HAVE_LIBJASPER)
-  fprintf(stderr, " JASPER");
-#endif
 #if defined(HAVE_LIBUDUNITS2)
   fprintf(stderr, " UDUNITS2");
 #endif
diff --git a/src/field.c b/src/field.c
index 74eaa3f..36b2fcb 100644
--- a/src/field.c
+++ b/src/field.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -23,25 +23,26 @@
 
 double crps_det_integrate(double *a, const double d, const size_t n);
 
-double fldfun(field_t field, int function)
+double fldfun(field_type field, int function)
 {
   double rval = 0;
 
   switch (function)
     {
-    case func_min:    rval = fldmin(field);  break;
-    case func_max:    rval = fldmax(field);  break;
-    case func_sum:    rval = fldsum(field);  break;
-    case func_mean:   rval = fldmean(field); break;
-    case func_avg:    rval = fldavg(field);  break;
-    case func_std:    rval = fldstd(field);  break;
-    case func_std1:   rval = fldstd1(field); break;
-    case func_var:    rval = fldvar(field);  break;
-    case func_var1:   rval = fldvar1(field); break;
-    case func_crps:   rval = fldcrps(field); break;
-    case func_brs:    rval = fldbrs(field);  break;
-    case func_rank:   rval = fldrank(field); break;
-    case func_roc:    rval = fldroc(field);  break;
+    case func_range:  rval = fldrange(field);  break;
+    case func_min:    rval = fldmin(field);    break;
+    case func_max:    rval = fldmax(field);    break;
+    case func_sum:    rval = fldsum(field);    break;
+    case func_mean:   rval = fldmean(field);   break;
+    case func_avg:    rval = fldavg(field);    break;
+    case func_std:    rval = fldstd(field);    break;
+    case func_std1:   rval = fldstd1(field);   break;
+    case func_var:    rval = fldvar(field);    break;
+    case func_var1:   rval = fldvar1(field);   break;
+    case func_crps:   rval = fldcrps(field);   break;
+    case func_brs:    rval = fldbrs(field);    break;
+    case func_rank:   rval = fldrank(field);   break;
+    case func_roc:    rval = fldroc(field);    break;
     default: cdoAbort("%s: function %d not implemented!", __func__, function);
     }
   
@@ -49,7 +50,7 @@ double fldfun(field_t field, int function)
 }
 
 
-double fldrank(field_t field) 
+double fldrank(field_type field) 
 {
   double res = 0;
   // Using first value as reference (observation)
@@ -77,12 +78,12 @@ double fldrank(field_t field)
 }
 
 
-double fldroc(field_t field) 
+double fldroc(field_type field) 
 {
   return field.missval;
 }
 
-double fldcrps(field_t field)
+double fldcrps(field_type field)
 {
   const size_t len     = field.size;
   const int    nmiss   = field.nmiss;
@@ -103,7 +104,7 @@ double fldcrps(field_t field)
 }
 
 
-double fldbrs(field_t field) 
+double fldbrs(field_type field) 
 {
   const int     nmiss   = field.nmiss;
   const size_t    len   = field.size;
@@ -136,7 +137,48 @@ double fldbrs(field_t field)
 }
 
 
-double fldmin(field_t field)
+double fldrange(field_type field)
+{
+  const int nmiss      = field.nmiss > 0;
+  const size_t len     = field.size;
+  const double missval = field.missval;
+  const double *restrict array = field.ptr;
+  double rmin =  DBL_MAX;
+  double rmax = -DBL_MAX;
+  double range = 0;
+
+  assert(array!=NULL);
+
+  if ( nmiss )
+    {
+      for ( size_t i = 0; i < len; i++ ) 
+	if ( !DBL_IS_EQUAL(array[i], missval) )
+          {
+            if ( array[i] < rmin ) rmin = array[i];
+            if ( array[i] > rmax ) rmax = array[i];
+          }
+
+      if ( IS_EQUAL(rmin,  DBL_MAX) && IS_EQUAL(rmax, -DBL_MAX) )
+        range = missval;
+      else
+        range = rmax-rmin;
+    }
+  else
+    {
+      //#pragma simd reduction(min:rmin) 
+      for ( size_t i = 0; i < len; i++ )
+        {
+          if ( array[i] < rmin ) rmin = array[i];
+          if ( array[i] > rmax ) rmax = array[i];
+        }
+      range = rmax-rmin;
+    }
+
+  return range;
+}
+
+
+double fldmin(field_type field)
 {
   const int nmiss      = field.nmiss > 0;
   const size_t len     = field.size;
@@ -152,21 +194,20 @@ double fldmin(field_t field)
 	if ( !DBL_IS_EQUAL(array[i], missval) )
 	  if ( array[i] < rmin ) rmin = array[i];
 
-      if ( IS_EQUAL(rmin, DBL_MAX) )
-	rmin = missval;
+      if ( IS_EQUAL(rmin, DBL_MAX) ) rmin = missval;
     }
   else
     {
       //#pragma simd reduction(min:rmin) 
       for ( size_t i = 0; i < len; i++ ) 
-	if ( array[i] < rmin )  rmin = array[i];
+	if ( array[i] < rmin ) rmin = array[i];
     }
 
   return rmin;
 }
 
 
-double fldmax(field_t field)
+double fldmax(field_type field)
 {
   const int nmiss      = field.nmiss > 0;
   const size_t len     = field.size;
@@ -182,20 +223,19 @@ double fldmax(field_t field)
         if ( !DBL_IS_EQUAL(array[i], missval) )
           if ( array[i] > rmax ) rmax = array[i];
       
-      if ( IS_EQUAL(rmax, -DBL_MAX) )
-        rmax = missval;
+      if ( IS_EQUAL(rmax, -DBL_MAX) ) rmax = missval;
     }
   else
     {
       for ( size_t i = 0; i < len; i++ ) 
-        if ( array[i] > rmax )  rmax = array[i];
+        if ( array[i] > rmax ) rmax = array[i];
     }
 
   return rmax;
 }
 
 
-double fldsum(field_t field)
+double fldsum(field_type field)
 {
   const int nmiss      = field.nmiss > 0;
   const size_t len     = field.size;
@@ -228,7 +268,7 @@ double fldsum(field_t field)
 }
 
 
-double fldmean(field_t field)
+double fldmean(field_type field)
 {
   const int nmiss       = field.nmiss > 0;
   const size_t len      = field.size;
@@ -237,6 +277,7 @@ double fldmean(field_t field)
   const double *restrict array = field.ptr;
   const double *restrict w     = field.weight;
   double rsum = 0, rsumw = 0;
+  double ravg = 0;
 
   assert(array!=NULL);
   assert(w!=NULL);
@@ -249,23 +290,18 @@ double fldmean(field_t field)
 	    rsum  += w[i] * array[i];
 	    rsumw += w[i];
 	  }
+      ravg = DIVMN(rsum, rsumw);
     }
   else
     {
-      for ( size_t i = 0; i < len; i++ ) 
-	{
-	  rsum  += w[i] * array[i];
-	  rsumw += w[i];
-	}
+      int fpeRaised = array_mean_val_weighted(len, array, w, missval1, &ravg);
     }
 
-  double ravg = DIVMN(rsum, rsumw);
-
   return ravg;
 }
 
 
-double fldavg(field_t field)
+double fldavg(field_type field)
 {
   const int nmiss       = field.nmiss > 0;
   const size_t len      = field.size;
@@ -340,7 +376,7 @@ void prevarsum(const double *restrict array, const double *restrict w, size_t le
 }
 
 
-double fldvar(field_t field)
+double fldvar(field_type field)
 {
   const int    nmiss   = field.nmiss > 0;
   const size_t len     = field.size;
@@ -357,7 +393,7 @@ double fldvar(field_t field)
 }
 
 
-double fldvar1(field_t field)
+double fldvar1(field_type field)
 {
   const int    nmiss   = field.nmiss > 0;
   const size_t len     = field.size;
@@ -390,19 +426,19 @@ double var_to_std(double rvar, double missval)
   return rstd;
 }
 
-double fldstd(field_t field)
+double fldstd(field_type field)
 {
   return var_to_std(fldvar(field), field.missval);
 }
 
 
-double fldstd1(field_t field)
+double fldstd1(field_type field)
 {
   return var_to_std(fldvar1(field), field.missval);
 }
 
 
-void fldrms(field_t field, field_t field2, field_t *field3)
+void fldrms(field_type field, field_type field2, field_type *field3)
 {
   size_t   i;
   size_t len;
@@ -454,7 +490,7 @@ void fldrms(field_t field, field_t field2, field_t *field3)
 }
 
 
-void varrms(field_t field, field_t field2, field_t *field3)
+void varrms(field_type field, field_type field2, field_type *field3)
 {
   size_t   i, k, nlev, len;
   int    rnmiss = 0;
@@ -508,7 +544,7 @@ void varrms(field_t field, field_t field2, field_t *field3)
 }
 
 /* RQ */
-double fldpctl(field_t field, const double pn)
+double fldpctl(field_type field, const double pn)
 {
   const size_t len     = field.size;
   const int    nmiss   = field.nmiss;
@@ -541,9 +577,9 @@ double fldpctl(field_t field, const double pn)
 }
 /* QR */
 
-/*  field_t UTILITIES */
+/*  field_type UTILITIES */
 /*  update the number non missing values */
-void fldunm(field_t *field)
+void fldunm(field_type *field)
 {
   size_t i;
 
@@ -553,10 +589,10 @@ void fldunm(field_t *field)
 }
 
 /*  check for non missval values */
-int fldhvs(field_t *fieldPtr, const size_t nlevels)
+int fldhvs(field_type *fieldPtr, const size_t nlevels)
 {
   size_t level;
-  field_t field;
+  field_type field;
 
   for ( level = 0; level < nlevels; level++)
     {
diff --git a/src/field.h b/src/field.h
index ec30bbb..12ac54b 100644
--- a/src/field.h
+++ b/src/field.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -79,6 +79,7 @@ static inline
 double FSQRTMN(double x, double missval1) { return MSQRTMN(x);}
 
 typedef struct {
+  int      fpeRaised;
   int      nwpv; // number of words per value; real:1  complex:2
   int      memtype;
   int      grid;
@@ -93,109 +94,110 @@ typedef struct {
   float   *ptrf;
   void    *ptr2;
 }
-field_t;
+field_type;
 
 
 /* fieldmem.c */
 
-void      field_init(field_t *field);
-field_t **field_malloc(const int vlistID, const int ptype);
-field_t **field_calloc(const int vlistID, const int ptype);
-void      field_free(field_t **field, const int vlistID);
+void      field_init(field_type *field);
+field_type **field_malloc(const int vlistID, const int ptype);
+field_type **field_calloc(const int vlistID, const int ptype);
+void      field_free(field_type **field, const int vlistID);
 
 /* field.c */
 
-double fldfun(field_t field, int function);
-double fldmin(field_t field);
-double fldmax(field_t field);
-double fldsum(field_t field);
-double fldavg(field_t field);
-double fldmean(field_t field);
-double fldstd(field_t field);
-double fldstd1(field_t field);
-double fldvar(field_t field);
-double fldvar1(field_t field);
-double fldpctl(field_t field, const double pn);
-void   fldunm(field_t *field);
-int    fldhvs(field_t *field, const size_t nlevels);
+double fldfun(field_type field, int function);
+double fldrange(field_type field);
+double fldmin(field_type field);
+double fldmax(field_type field);
+double fldsum(field_type field);
+double fldavg(field_type field);
+double fldmean(field_type field);
+double fldstd(field_type field);
+double fldstd1(field_type field);
+double fldvar(field_type field);
+double fldvar1(field_type field);
+double fldpctl(field_type field, const double pn);
+void   fldunm(field_type *field);
+int    fldhvs(field_type *field, const size_t nlevels);
 
 /* ENS VALIDATION */
-double fldcrps(field_t field);
-double fldbrs(field_t field);
-double fldrank(field_t field);
-double fldroc(field_t field);
+double fldcrps(field_type field);
+double fldbrs(field_type field);
+double fldrank(field_type field);
+double fldroc(field_type field);
 
 /* fieldzon.c */
 
-void zonfun(field_t field1, field_t *field2, const int function);
-void zonmin(field_t field1, field_t *field2);
-void zonmax(field_t field1, field_t *field2);
-void zonrange(field_t field1, field_t *field2);
-void zonsum(field_t field1, field_t *field2);
-void zonavg(field_t field1, field_t *field2);
-void zonmean(field_t field1, field_t *field2);
-void zonstd(field_t field1, field_t *field2);
-void zonstd1(field_t field1, field_t *field2);
-void zonvar(field_t field1, field_t *field2);
-void zonvar1(field_t field1, field_t *field2);
-void zonpctl(field_t field1, field_t *field2, const int k);
+void zonfun(field_type field1, field_type *field2, const int function);
+void zonmin(field_type field1, field_type *field2);
+void zonmax(field_type field1, field_type *field2);
+void zonrange(field_type field1, field_type *field2);
+void zonsum(field_type field1, field_type *field2);
+void zonavg(field_type field1, field_type *field2);
+void zonmean(field_type field1, field_type *field2);
+void zonstd(field_type field1, field_type *field2);
+void zonstd1(field_type field1, field_type *field2);
+void zonvar(field_type field1, field_type *field2);
+void zonvar1(field_type field1, field_type *field2);
+void zonpctl(field_type field1, field_type *field2, const int k);
 
 /* fieldmer.c */
 
-void merfun(field_t field1, field_t *field2, const int function);
-void mermin(field_t field1, field_t *field2);
-void mermax(field_t field1, field_t *field2);
-void mersum(field_t field1, field_t *field2);
-void meravg(field_t field1, field_t *field2);
-void mermean(field_t field1, field_t *field2);
-void merstd(field_t field1, field_t *field2);
-void merstd1(field_t field1, field_t *field2);
-void mervar(field_t field1, field_t *field2);
-void mervar1(field_t field1, field_t *field2);
-void merpctl(field_t field1, field_t *field2, const int k);
+void merfun(field_type field1, field_type *field2, const int function);
+void mermin(field_type field1, field_type *field2);
+void mermax(field_type field1, field_type *field2);
+void mersum(field_type field1, field_type *field2);
+void meravg(field_type field1, field_type *field2);
+void mermean(field_type field1, field_type *field2);
+void merstd(field_type field1, field_type *field2);
+void merstd1(field_type field1, field_type *field2);
+void mervar(field_type field1, field_type *field2);
+void mervar1(field_type field1, field_type *field2);
+void merpctl(field_type field1, field_type *field2, const int k);
 
-void fldrms(field_t field1, field_t field2, field_t *field3);
+void fldrms(field_type field1, field_type field2, field_type *field3);
 
-void varrms(field_t field1, field_t field2, field_t *field3);
+void varrms(field_type field1, field_type field2, field_type *field3);
 
 /* fieldc.c */
 
-void farcfun(field_t *field, const double rconst, const int function);
+void farcfun(field_type *field, const double rconst, const int function);
 
-void farcmul(field_t *field, const double rconst);
-void farcdiv(field_t *field, const double rconst);
-void farcadd(field_t *field, const double rconst);
-void farcsub(field_t *field, const double rconst);
+void farcmul(field_type *field, const double rconst);
+void farcdiv(field_type *field, const double rconst);
+void farcadd(field_type *field, const double rconst);
+void farcsub(field_type *field, const double rconst);
 
-void farmod(field_t *field, const double divisor);
+void farmod(field_type *field, const double divisor);
 
-void farinv(field_t *field);
-void farround(field_t *field);
+void farinv(field_type *field);
+void farround(field_type *field);
 
 /* field2.c */
 
-void farfun(field_t *field1, field_t field2, int function);
-
-void farcpy(field_t *field1, field_t field2);
-void faradd(field_t *field1, field_t field2);
-void farsum(field_t *field1, field_t field2);
-void farsumw(field_t *field1, field_t field2, double w);
-void farsumq(field_t *field1, field_t field2);
-void farsumqw(field_t *field1, field_t field2, double w);
-void farsumtr(field_t *field1, field_t field2, const double refval);
-void farsub(field_t *field1, field_t field2);
-void farmul(field_t *field1, field_t field2);
-void fardiv(field_t *field1, field_t field2);
-void farmin(field_t *field1, field_t field2);
-void farmax(field_t *field1, field_t field2);
-void farvar(field_t *field1, field_t field2, field_t field3, int divisor);
-void farstd(field_t *field1, field_t field2, field_t field3, int divisor);
-void farcvar(field_t *field1, field_t field2, int nsets, int divisor);
-void farcstd(field_t *field1, field_t field2, int nsets, int divisor);
-void farmoq(field_t *field1, field_t field2);
-void farmoqw(field_t *field1, field_t field2, double w);
-void faratan2(field_t *field1, field_t field2);
-
-void farcount(field_t *field1, field_t field2);
+void farfun(field_type *field1, field_type field2, int function);
+
+void farcpy(field_type *field1, field_type field2);
+void faradd(field_type *field1, field_type field2);
+void farsum(field_type *field1, field_type field2);
+void farsumw(field_type *field1, field_type field2, double w);
+void farsumq(field_type *field1, field_type field2);
+void farsumqw(field_type *field1, field_type field2, double w);
+void farsumtr(field_type *field1, field_type field2, const double refval);
+void farsub(field_type *field1, field_type field2);
+void farmul(field_type *field1, field_type field2);
+void fardiv(field_type *field1, field_type field2);
+void farmin(field_type *field1, field_type field2);
+void farmax(field_type *field1, field_type field2);
+void farvar(field_type *field1, field_type field2, field_type field3, int divisor);
+void farstd(field_type *field1, field_type field2, field_type field3, int divisor);
+void farcvar(field_type *field1, field_type field2, int nsets, int divisor);
+void farcstd(field_type *field1, field_type field2, int nsets, int divisor);
+void farmoq(field_type *field1, field_type field2);
+void farmoqw(field_type *field1, field_type field2, double w);
+void faratan2(field_type *field1, field_type field2);
+
+void farcount(field_type *field1, field_type field2);
 
 #endif  /* _FIELD_H */
diff --git a/src/field2.c b/src/field2.c
index 30a2458..9845ea6 100644
--- a/src/field2.c
+++ b/src/field2.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -20,7 +20,7 @@
 #include "cdo_int.h"
 
 
-void farfun(field_t *field1, field_t field2, int function)
+void farfun(field_type *field1, field_type field2, int function)
 {
   switch (function)
     {
@@ -66,15 +66,11 @@ int farsetnmiss(int len, double *restrict array, double missval)
 }
 
 
-void farcpy(field_t *field1, field_t field2)
+void farcpy(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;
-  double missval1 = field1->missval;
-  double missval2 = field2.missval;
   double *restrict array1 = field1->ptr;
   const double *restrict array2 = field2.ptr;
   const float *restrict array2f = field2.ptrf;
@@ -96,7 +92,7 @@ void farcpy(field_t *field1, field_t field2)
 }
 
 
-void faradd(field_t *field1, field_t field2)
+void faradd(field_type *field1, field_type field2)
 {
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
@@ -105,8 +101,8 @@ void faradd(field_t *field1, field_t field2)
   int nmiss2 = field2.nmiss;
   double missval1 = field1->missval;
   double missval2 = field2.missval;
-  double *restrict array1  = field1->ptr;
-  const double *restrict array2  = field2.ptr;
+  double *restrict array1 = field1->ptr;
+  const double *restrict array2 = field2.ptr;
   const float *restrict array2f = field2.ptrf;
 
   if ( nwpv != 2 ) nwpv = 1;
@@ -133,16 +129,13 @@ void faradd(field_t *field1, field_t field2)
         }
       else
         {
-          //#if defined(_OPENMP)
-          //#pragma omp parallel for default(none) shared(a,b)
-          //#endif
-          for ( int i = 0; i < len; i++ ) array1[i] += array2[i];
+          int fpeRaised = array_add_array(len, array1, array2);
         }
     }
 }
 
 
-void farsum(field_t *field1, field_t field2)
+void farsum(field_type *field1, field_type field2)
 {
   int nwpv = field1->nwpv;
   int gridsize1 = field1->size;
@@ -188,13 +181,13 @@ void farsum(field_t *field1, field_t field2)
         }
       else
         {
-          for ( int i = 0; i < len; i++ ) array1[i] += array2[i];
+          array_add_array(len, array1, array2);
         }
     }
 }
 
 
-void farsumw(field_t *field1, field_t field2, double w)
+void farsumw(field_type *field1, field_type field2, double w)
 {
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
@@ -245,7 +238,7 @@ void farsumw(field_t *field1, field_t field2, double w)
  * values do not change anything (they do not start a non-period by setting
  * occurrence to zero).
  */
-void farsumtr(field_t *occur, field_t field, const double refval)
+void farsumtr(field_type *occur, field_type field, const double refval)
 {
   double omissval = occur->missval;
   double fmissval = field.missval;
@@ -291,7 +284,7 @@ void farsumtr(field_t *occur, field_t field, const double refval)
 }
 
 
-void farsumq(field_t *field1, field_t field2)
+void farsumq(field_type *field1, field_type field2)
 {
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
@@ -340,7 +333,7 @@ void farsumq(field_t *field1, field_t field2)
 }
 
 
-void farsumqw(field_t *field1, field_t field2, double w)
+void farsumqw(field_type *field1, field_type field2, double w)
 {
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
@@ -382,7 +375,7 @@ void farsumqw(field_t *field1, field_t field2, double w)
 }
 
 
-void farsub(field_t *field1, field_t field2)
+void farsub(field_type *field1, field_type field2)
 {
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
@@ -418,7 +411,7 @@ void farsub(field_t *field1, field_t field2)
 }
 
 
-void farmul(field_t *field1, field_t field2)
+void farmul(field_type *field1, field_type field2)
 {
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
@@ -454,7 +447,7 @@ void farmul(field_t *field1, field_t field2)
 }
 
 
-void fardiv(field_t *field1, field_t field2)
+void fardiv(field_type *field1, field_type field2)
 {
   int nwpv  = field1->nwpv;
   int grid1 = field1->grid;
@@ -480,7 +473,7 @@ void fardiv(field_t *field1, field_t field2)
 }
 
 
-void faratan2(field_t *field1, field_t field2)
+void faratan2(field_type *field1, field_type field2)
 {
   int nwpv  = field1->nwpv;
   int grid1 = field1->grid;
@@ -506,7 +499,7 @@ void faratan2(field_t *field1, field_t field2)
 }
 
 
-void farmin(field_t *field1, field_t field2)
+void farmin(field_type *field1, field_type field2)
 {
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
@@ -546,7 +539,7 @@ void farmin(field_t *field1, field_t field2)
 }
 
 
-void farmax(field_t *field1, field_t field2)
+void farmax(field_type *field1, field_type field2)
 {
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
@@ -586,7 +579,7 @@ void farmax(field_t *field1, field_t field2)
 }
 
 
-void farvar(field_t *field1, field_t field2, field_t field3, int divisor)
+void farvar(field_type *field1, field_type field2, field_type field3, int divisor)
 {
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
@@ -630,7 +623,7 @@ void farvar(field_t *field1, field_t field2, field_t field3, int divisor)
 }
 
 
-void farstd(field_t *field1, field_t field2, field_t field3, int divisor)
+void farstd(field_type *field1, field_type field2, field_type field3, int divisor)
 {
   int nwpv  = field1->nwpv;
   int grid1 = field1->grid;
@@ -662,7 +655,7 @@ void farstd(field_t *field1, field_t field2, field_t field3, int divisor)
 }
 
 
-void farcvar(field_t *field1, field_t field2, int nsets, int divisor)
+void farcvar(field_type *field1, field_type field2, int nsets, int divisor)
 {
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
@@ -710,7 +703,7 @@ void farcvar(field_t *field1, field_t field2, int nsets, int divisor)
 }
 
 
-void farcstd(field_t *field1, field_t field2, int nsets, int divisor)
+void farcstd(field_type *field1, field_type field2, int nsets, int divisor)
 {
   int nwpv  = field1->nwpv;
   int grid1 = field1->grid;
@@ -742,7 +735,7 @@ void farcstd(field_t *field1, field_t field2, int nsets, int divisor)
 }
 
 
-void farmoq(field_t *field1, field_t field2)
+void farmoq(field_type *field1, field_type field2)
 {
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
@@ -780,7 +773,7 @@ void farmoq(field_t *field1, field_t field2)
 }
 
 
-void farmoqw(field_t *field1, field_t field2, double w)
+void farmoqw(field_type *field1, field_type field2, double w)
 {
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
@@ -830,7 +823,7 @@ void farmoqw(field_t *field1, field_t field2, double w)
  * @param field1 the 1st input field, also holds the result
  * @param field2 the 2nd input field
  */  
-void farcount(field_t *field1, field_t field2)
+void farcount(field_type *field1, field_type field2)
 {
   int nwpv   = field1->nwpv;
   int grid1  = field1->grid;
diff --git a/src/fieldc.c b/src/fieldc.c
index 6156bc0..ecb1f9e 100644
--- a/src/fieldc.c
+++ b/src/fieldc.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -20,7 +20,7 @@
 #include <cdi.h>
 
 
-void farcfun(field_t *field, double rconst, int function)
+void farcfun(field_type *field, double rconst, int function)
 {
   if      ( function == func_add ) farcadd(field, rconst);
   else if ( function == func_sub ) farcsub(field, rconst);
@@ -30,7 +30,7 @@ void farcfun(field_t *field, double rconst, int function)
   else    cdoAbort("%s: function %d not implemented!", __func__, function);
 }
 
-void farcmul(field_t *field, double rconst)
+void farcmul(field_type *field, double rconst)
 {
   int i, len;
   int    nwpv     = field->nwpv;
@@ -62,7 +62,7 @@ void farcmul(field_t *field, double rconst)
 }
 
 
-void farcdiv(field_t *field, double rconst)
+void farcdiv(field_type *field, double rconst)
 {
   int i, len;
   int    grid     = field->grid;
@@ -88,7 +88,7 @@ void farcdiv(field_t *field, double rconst)
 }
 
 
-void farcadd(field_t *field, double rconst)
+void farcadd(field_type *field, double rconst)
 {
   int i, len;
   int    grid     = field->grid;
@@ -112,13 +112,13 @@ void farcadd(field_t *field, double rconst)
 }
 
 
-void farcsub(field_t *field, double rconst)
+void farcsub(field_type *field, double rconst)
 {
   farcadd(field, -rconst);
 }
 
 
-void farinv(field_t *field)
+void farinv(field_type *field)
 {
   int i, len;
   int    grid     = field->grid;
@@ -137,11 +137,10 @@ void farinv(field_t *field)
 }
 
 
-void farround(field_t *field)
+void farround(field_type *field)
 {
   int    grid     = field->grid;
   double missval1 = field->missval;
-  double missval2 = field->missval;
   double *array   = field->ptr;
 
   int len = gridInqSize(grid);
@@ -155,7 +154,7 @@ void farround(field_t *field)
 }
 
 
-void farmod(field_t *field, double divisor)
+void farmod(field_type *field, double divisor)
 {
   int i, len;
   int    grid     = field->grid;
diff --git a/src/fieldmem.c b/src/fieldmem.c
index 7b65956..0f14b70 100644
--- a/src/fieldmem.c
+++ b/src/fieldmem.c
@@ -9,17 +9,17 @@
 #include "util.h"
 
 
-void field_init(field_t *field)
+void field_init(field_type *field)
 {
-  memset(field, 0, sizeof(field_t));
+  memset(field, 0, sizeof(field_type));
 }
 
 
-field_t **field_allocate(int vlistID, int ptype, int init)
+field_type **field_allocate(int vlistID, int ptype, int init)
 {
   int nvars = vlistNvars(vlistID);
 
-  field_t **field = (field_t **) Malloc(nvars*sizeof(field_t *));
+  field_type **field = (field_type **) Malloc(nvars*sizeof(field_type *));
 
   for ( int varID = 0; varID < nvars; ++varID )
     {
@@ -30,7 +30,7 @@ field_t **field_allocate(int vlistID, int ptype, int init)
       int nlevel   = zaxisInqSize(zaxisID);
       double missval  = vlistInqVarMissval(vlistID, varID);
 
-      field[varID] = (field_t*) Malloc(nlevel*sizeof(field_t));
+      field[varID] = (field_type*) Malloc(nlevel*sizeof(field_type));
 
       for ( int levelID = 0; levelID < nlevel; ++levelID )
 	{
@@ -88,19 +88,19 @@ field_t **field_allocate(int vlistID, int ptype, int init)
 }
 
 
-field_t **field_malloc(int vlistID, int ptype)
+field_type **field_malloc(int vlistID, int ptype)
 {
   return field_allocate(vlistID, ptype, 0);
 }
 
 
-field_t **field_calloc(int vlistID, int ptype)
+field_type **field_calloc(int vlistID, int ptype)
 {
   return field_allocate(vlistID, ptype, 1);
 }
 
 
-void field_free(field_t **field, int vlistID)
+void field_free(field_type **field, int vlistID)
 {
   int nvars = vlistNvars(vlistID);
   for ( int varID = 0; varID < nvars; ++varID )
diff --git a/src/fieldmer.c b/src/fieldmer.c
index eb36d56..b7e0826 100644
--- a/src/fieldmer.c
+++ b/src/fieldmer.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -21,7 +21,7 @@
 #include "percentiles.h"
 
 
-void merfun(field_t field1, field_t *field2, int function)
+void merfun(field_type field1, field_type *field2, int function)
 {
   if      ( function == func_min )  mermin(field1, field2);
   else if ( function == func_max )  mermax(field1, field2);  
@@ -36,7 +36,7 @@ void merfun(field_t field1, field_t *field2, int function)
 }
 
 
-void mermin(field_t field1, field_t *field2)
+void mermin(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
   int    rnmiss = 0;
@@ -78,7 +78,7 @@ void mermin(field_t field1, field_t *field2)
 }
 
 
-void mermax(field_t field1, field_t *field2)
+void mermax(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
   int    rnmiss = 0;
@@ -120,7 +120,7 @@ void mermax(field_t field1, field_t *field2)
 }
 
 
-void mersum(field_t field1, field_t *field2)
+void mersum(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
   long   nvals   = 0;
@@ -167,7 +167,7 @@ void mersum(field_t field1, field_t *field2)
 }
 
 
-void mermean(field_t field1, field_t *field2)
+void mermean(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
   int    rnmiss = 0;
@@ -216,7 +216,7 @@ void mermean(field_t field1, field_t *field2)
 }
 
 
-void meravg(field_t field1, field_t *field2)
+void meravg(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
   int    rnmiss = 0;
@@ -297,7 +297,7 @@ void prevarsum_mer(const double *restrict array, const double *restrict w, int n
 }
 
 
-void mervar(field_t field1, field_t *field2)
+void mervar(field_type field1, field_type *field2)
 {
   int    rnmiss = 0;
   int    grid    = field1.grid;
@@ -327,7 +327,7 @@ void mervar(field_t field1, field_t *field2)
 }
 
 
-void mervar1(field_t field1, field_t *field2)
+void mervar1(field_type field1, field_type *field2)
 {
   int    rnmiss = 0;
   int    grid    = field1.grid;
@@ -357,7 +357,7 @@ void mervar1(field_t field1, field_t *field2)
 }
 
 
-void merstd(field_t field1, field_t *field2)
+void merstd(field_type field1, field_type *field2)
 {
   int    rnmiss = 0;
   int    grid    = field1.grid;
@@ -381,7 +381,7 @@ void merstd(field_t field1, field_t *field2)
 }
 
 
-void merstd1(field_t field1, field_t *field2)
+void merstd1(field_type field1, field_type *field2)
 {
   int    rnmiss = 0;
   int    grid    = field1.grid;
@@ -405,7 +405,7 @@ void merstd1(field_t field1, field_t *field2)
 }
 
 /* RQ */
-void merpctl(field_t field1, field_t *field2, int p)
+void merpctl(field_type field1, field_type *field2, int p)
 {
   long   i, j, l;
   int    rnmiss = 0;
diff --git a/src/fieldzon.c b/src/fieldzon.c
index 1c7415e..92ff44c 100644
--- a/src/fieldzon.c
+++ b/src/fieldzon.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -21,7 +21,7 @@
 #include "percentiles.h"
 
 
-void zonfun(field_t field1, field_t *field2, int function)
+void zonfun(field_type field1, field_type *field2, int function)
 {
   if      ( function == func_min   )  zonmin(field1, field2);
   else if ( function == func_max   )  zonmax(field1, field2);  
@@ -37,7 +37,7 @@ void zonfun(field_t field1, field_t *field2, int function)
 }
 
 
-void zonmin(field_t field1, field_t *field2)
+void zonmin(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
   int    rnmiss = 0;
@@ -79,7 +79,7 @@ void zonmin(field_t field1, field_t *field2)
 }
 
 
-void zonmax(field_t field1, field_t *field2)
+void zonmax(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
   int    rnmiss = 0;
@@ -121,7 +121,7 @@ void zonmax(field_t field1, field_t *field2)
 }
 
 
-void zonrange(field_t field1, field_t *field2)
+void zonrange(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
   int    rnmiss = 0;
@@ -179,7 +179,7 @@ void zonrange(field_t field1, field_t *field2)
 }
 
 
-void zonsum(field_t field1, field_t *field2)
+void zonsum(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
   long   nvals   = 0;
@@ -226,7 +226,7 @@ void zonsum(field_t field1, field_t *field2)
 }
 
 
-void zonmean(field_t field1, field_t *field2)
+void zonmean(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
   int    rnmiss = 0;
@@ -273,7 +273,7 @@ void zonmean(field_t field1, field_t *field2)
 }
 
 
-void zonavg(field_t field1, field_t *field2)
+void zonavg(field_type field1, field_type *field2)
 {
   long   i, j, nx, ny;
   int    rnmiss = 0;
@@ -353,7 +353,7 @@ void prevarsum_zon(const double *restrict array, int nx, int nmiss,  double miss
 }
 
 
-void zonvar(field_t field1, field_t *field2)
+void zonvar(field_type field1, field_type *field2)
 {
   int    rnmiss = 0;
   int    grid     = field1.grid;
@@ -382,7 +382,7 @@ void zonvar(field_t field1, field_t *field2)
 }
 
 
-void zonvar1(field_t field1, field_t *field2)
+void zonvar1(field_type field1, field_type *field2)
 {
   int    rnmiss = 0;
   int    grid     = field1.grid;
@@ -411,7 +411,7 @@ void zonvar1(field_t field1, field_t *field2)
 }
 
 
-void zonstd(field_t field1, field_t *field2)
+void zonstd(field_type field1, field_type *field2)
 {
   int    rnmiss = 0;
   int    grid    = field1.grid;
@@ -435,7 +435,7 @@ void zonstd(field_t field1, field_t *field2)
 }
 
 
-void zonstd1(field_t field1, field_t *field2)
+void zonstd1(field_type field1, field_type *field2)
 {
   int    rnmiss = 0;
   int    grid    = field1.grid;
@@ -459,7 +459,7 @@ void zonstd1(field_t field1, field_t *field2)
 }
 
 /* RQ */
-void zonpctl(field_t field1, field_t *field2, int p)
+void zonpctl(field_type field1, field_type *field2, int p)
 {
   long   i, j, l;
   int    rnmiss = 0;
diff --git a/src/functs.h b/src/functs.h
index 444d123..96efb6c 100644
--- a/src/functs.h
+++ b/src/functs.h
@@ -57,7 +57,4 @@ enum cmp_flag {
   CMP_ALL      = CMP_NAME | CMP_GRIDSIZE | CMP_NLEVEL | CMP_GRID
 };
 
-void    vlistCompare(int vlistID1, int vlistID2, int flag);
-int     vlistCompareX(int vlistID1, int vlistID2, int flag);
-
 #endif  /* _FUNCTS_H */
diff --git a/src/grid.c b/src/grid.c
index e8ab4cb..04a803f 100644
--- a/src/grid.c
+++ b/src/grid.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -15,18 +15,18 @@
 */
 
 #if defined(HAVE_CONFIG_H)
-#  include "config.h"
+#include "config.h"
 #endif
 
 #if defined(_OPENMP)
-#  include <omp.h>
+#include <omp.h>
 #endif
 
 #include <stdio.h>
 #include <stdarg.h> /* va_list */
 
 #if defined(HAVE_LIBPROJ)
-#  include "proj_api.h"
+#include "proj_api.h"
 #endif
 
 #include <cdi.h>
@@ -36,6 +36,96 @@
 #include "grid.h"
 
 
+int nfc_to_nlat(int nfc, int ntr)
+{
+  int nlat = nfc / (ntr+1);
+  nlat /= 2;
+
+  return nlat;
+}
+
+
+int nlat_to_ntr(int nlat)
+{
+  int ntr = (nlat*2 - 1) / 3;
+
+  return ntr;
+}
+
+
+int nlat_to_ntr_linear(int nlat)
+{
+  int ntr = (nlat*2 - 1) / 2;
+
+  return ntr;
+}
+
+
+int ntr_to_nlat(int ntr)
+{
+  int nlat = (int)lround((ntr*3.+1.)/2.);
+  if ( (nlat % 2) > 0 )
+    {
+      nlat  = nlat + 1;
+      /*
+      int nlat2 = (int)lround(((ntr+1)*3.+1.)/2.);
+      if ( nlat == nlat2 )
+	Error("Computation of latitudes failed for truncation %d", ntr);
+      */
+    }
+
+  return nlat;
+}
+
+
+int ntr_to_nlat_linear(int ntr)
+{
+  int nlat = (int)lround((ntr*2.+1.)/2.);
+  if ( (nlat % 2) > 0 )
+    {
+      nlat  = nlat + 1;
+      /*
+      int nlat2 = (int)lround(((ntr+1)*2.+1.)/2.);
+      if ( nlat == nlat2 )
+	Error("Computation of latitudes failed for truncation %d", ntr);
+      */
+    }
+
+  return nlat;
+}
+
+
+int nlat_to_nlon(int nlat)
+{
+  int nlon = 2 * nlat;
+
+  /* check that FFT works with nlon */
+  while ( 1 )
+    {
+      int n = nlon;
+      if    ( n % 8 == 0 )  { n /= 8; }
+      while ( n % 6 == 0 )  { n /= 6; }
+      while ( n % 5 == 0 )  { n /= 5; }
+      while ( n % 4 == 0 )  { n /= 4; }
+      while ( n % 3 == 0 )  { n /= 3; }
+      if    ( n % 2 == 0 )  { n /= 2; }
+
+      if ( n <= 8 ) break;
+
+      nlon = nlon + 2;
+
+      if ( nlon > 9999 )
+	{
+	  nlon = 2 * nlat;
+	  fprintf(stderr, "FFT does not work with len %d!\n", nlon);
+	  break;
+	}
+    }
+
+  return nlon;
+}
+
+
 static
 void scale_vec(double scalefactor, long nvals, double *restrict values)
 {
@@ -49,6 +139,42 @@ void scale_vec(double scalefactor, long nvals, double *restrict values)
 }
 
 
+void grid_copy_attributes(int gridID1, int gridID2)
+{
+  char string[CDI_MAX_NAME];
+  string[0] = 0;   cdiGridInqKeyStr(gridID1, CDI_KEY_XDIMNAME, CDI_MAX_NAME, string);
+  if ( string[0] ) cdiGridDefKeyStr(gridID2, CDI_KEY_XDIMNAME, strlen(string)+1, string);
+  string[0] = 0;   cdiGridInqKeyStr(gridID1, CDI_KEY_YDIMNAME, CDI_MAX_NAME, string);
+  if ( string[0] ) cdiGridDefKeyStr(gridID2, CDI_KEY_YDIMNAME, strlen(string)+1, string);
+  string[0] = 0;   cdiGridInqKeyStr(gridID1, CDI_KEY_VDIMNAME, CDI_MAX_NAME, string);
+  if ( string[0] ) cdiGridDefKeyStr(gridID2, CDI_KEY_VDIMNAME, strlen(string)+1, string);
+  string[0] = 0;   cdiGridInqKeyStr(gridID1, CDI_KEY_XNAME, CDI_MAX_NAME, string);
+  if ( string[0] ) cdiGridDefKeyStr(gridID2, CDI_KEY_XNAME, strlen(string)+1, string);
+  string[0] = 0;   cdiGridInqKeyStr(gridID1, CDI_KEY_YNAME, CDI_MAX_NAME, string);
+  if ( string[0] ) cdiGridDefKeyStr(gridID2, CDI_KEY_YNAME, strlen(string)+1, string);
+  string[0] = 0;   cdiGridInqKeyStr(gridID1, CDI_KEY_XLONGNAME, CDI_MAX_NAME, string);
+  if ( string[0] ) cdiGridDefKeyStr(gridID2, CDI_KEY_XLONGNAME, strlen(string)+1, string);
+  string[0] = 0;   cdiGridInqKeyStr(gridID1, CDI_KEY_YLONGNAME, CDI_MAX_NAME, string);
+  if ( string[0] ) cdiGridDefKeyStr(gridID2, CDI_KEY_YLONGNAME, strlen(string)+1, string);
+  string[0] = 0;   cdiGridInqKeyStr(gridID1, CDI_KEY_XUNITS, CDI_MAX_NAME, string);
+  if ( string[0] ) cdiGridDefKeyStr(gridID2, CDI_KEY_XUNITS, strlen(string)+1, string);
+  string[0] = 0;   cdiGridInqKeyStr(gridID1, CDI_KEY_YUNITS, CDI_MAX_NAME, string);
+  if ( string[0] ) cdiGridDefKeyStr(gridID2, CDI_KEY_YUNITS, strlen(string)+1, string);
+}
+
+
+void grid_copy_mapping(int gridID1, int gridID2)
+{
+  char string[CDI_MAX_NAME];
+  string[0] = 0;   cdiGridInqKeyStr(gridID1, CDI_KEY_MAPPING, CDI_MAX_NAME, string);
+  if ( string[0] ) cdiGridDefKeyStr(gridID2, CDI_KEY_MAPPING, strlen(string)+1, string);
+  string[0] = 0;   cdiGridInqKeyStr(gridID1, CDI_KEY_MAPNAME, CDI_MAX_NAME, string);
+  if ( string[0] ) cdiGridDefKeyStr(gridID2, CDI_KEY_MAPNAME, strlen(string)+1, string);
+
+  cdiCopyAtts(gridID1, CDI_GLOBAL, gridID2, CDI_GLOBAL);
+}
+
+
 void grid_to_radian(const char *units, long nvals, double *restrict values, const char *description)
 {
   if ( cmpstr(units, "degree") == 0 )
@@ -85,14 +211,9 @@ void grid_to_degree(const char *units, long nvals, double *restrict values, cons
 
 int gridToZonal(int gridID1)
 {
-  int gridID2;
-  int gridtype, gridsize;
-  double  xval = 0;
-  double *yvals;
-
-  gridtype = gridInqType(gridID1);
-  gridsize = gridInqYsize(gridID1);
-  gridID2  = gridCreate(gridtype, gridsize);
+  int gridtype = gridInqType(gridID1);
+  int gridsize = gridInqYsize(gridID1);
+  int gridID2  = gridCreate(gridtype, gridsize);
 	  
   if ( gridtype == GRID_LONLAT   ||
        gridtype == GRID_GAUSSIAN ||
@@ -101,15 +222,14 @@ int gridToZonal(int gridID1)
       gridDefXsize(gridID2, 1);
       gridDefYsize(gridID2, gridsize);
 
+      double xval = 0;
       gridDefXvals(gridID2, &xval);
 
       if ( gridInqYvals(gridID1, NULL) )
 	{
-	  yvals = (double*) Malloc(gridsize*sizeof(double));
-
+	  double *yvals = (double*) Malloc(gridsize*sizeof(double));
 	  gridInqYvals(gridID1, yvals);
 	  gridDefYvals(gridID2, yvals);
-
 	  Free(yvals);
 	}
     }
@@ -124,14 +244,9 @@ int gridToZonal(int gridID1)
 
 int gridToMeridional(int gridID1)
 {
-  int gridID2;
-  int gridtype, gridsize;
-  double *xvals;
-  double  yval = 0;
-
-  gridtype = gridInqType(gridID1);
-  gridsize = gridInqXsize(gridID1);
-  gridID2  = gridCreate(gridtype, gridsize);
+  int gridtype = gridInqType(gridID1);
+  int gridsize = gridInqXsize(gridID1);
+  int gridID2  = gridCreate(gridtype, gridsize);
 	  
   if ( gridtype == GRID_LONLAT   ||
        gridtype == GRID_GAUSSIAN ||
@@ -142,14 +257,13 @@ int gridToMeridional(int gridID1)
 
       if ( gridInqXvals(gridID1, NULL) )
 	{
-	  xvals = (double*) Malloc(gridsize*sizeof(double));
-
+	  double *xvals = (double*) Malloc(gridsize*sizeof(double));
 	  gridInqXvals(gridID1, xvals);
 	  gridDefXvals(gridID2, xvals);
-
 	  Free(xvals);
 	}
 
+      double yval = 0;
       gridDefYvals(gridID2, &yval);
     }
   else
@@ -163,8 +277,6 @@ int gridToMeridional(int gridID1)
 
 void grid_gen_corners(int n, const double* restrict vals, double* restrict corners)
 {
-  int i;
-
   if ( n == 1 )
     {
       corners[0] = vals[0];
@@ -172,7 +284,7 @@ void grid_gen_corners(int n, const double* restrict vals, double* restrict corne
     }
   else
     {
-      for ( i = 0; i < n-1; ++i )
+      for ( int i = 0; i < n-1; ++i )
 	corners[i+1] = 0.5*(vals[i] + vals[i+1]);
 
       corners[0] = 2*vals[0] - corners[1];
@@ -212,21 +324,20 @@ void grid_check_lat_borders(int n, double *ybounds)
 void grid_cell_center_to_bounds_X2D(const char* xunitstr, long xsize, long ysize, const double* restrict grid_center_lon, 
 				    double* restrict grid_corner_lon, double dlon)
 {
-  long i, j, index;
-  double minlon, maxlon;
+  (void)xunitstr;
 
   if ( ! (dlon > 0) ) dlon = 360./xsize;
   /*
   if ( xsize == 1 || (grid_center_lon[xsize-1]-grid_center_lon[0]+dlon) < 359 )
     cdoAbort("Cannot calculate Xbounds for %d vals with dlon = %g", xsize, dlon);
   */
-  for ( i = 0; i < xsize; ++i )
+  for ( int i = 0; i < xsize; ++i )
     {
-      minlon = grid_center_lon[i] - 0.5*dlon;
-      maxlon = grid_center_lon[i] + 0.5*dlon;
-      for ( j = 0; j < ysize; ++j )
+      double minlon = grid_center_lon[i] - 0.5*dlon;
+      double maxlon = grid_center_lon[i] + 0.5*dlon;
+      for ( int j = 0; j < ysize; ++j )
 	{
-	  index = (j<<2)*xsize + (i<<2);
+	  int index = (j<<2)*xsize + (i<<2);
 	  grid_corner_lon[index  ] = minlon;
 	  grid_corner_lon[index+1] = maxlon;
 	  grid_corner_lon[index+2] = maxlon;
@@ -238,10 +349,8 @@ void grid_cell_center_to_bounds_X2D(const char* xunitstr, long xsize, long ysize
 static
 double genYmin(double y1, double y2)
 {
-  double ymin, dy;
-
-  dy = y2 - y1;
-  ymin = y1 - dy/2;
+  double dy = y2 - y1;
+  double ymin = y1 - dy/2;
 
   if ( y1 < -85 && ymin < -87.5 ) ymin = -90;
 
@@ -254,10 +363,8 @@ double genYmin(double y1, double y2)
 static
 double genYmax(double y1, double y2)
 {
-  double ymax, dy;
-
-  dy = y1 - y2;
-  ymax = y1 + dy/2;
+  double dy = y1 - y2;
+  double ymax = y1 + dy/2;
 
   if ( y1 > 85 && ymax > 87.5 ) ymax = 90;
 
@@ -273,16 +380,16 @@ double genYmax(double y1, double y2)
 
 void grid_cell_center_to_bounds_Y2D(const char* yunitstr, long xsize, long ysize, const double* restrict grid_center_lat, double* restrict grid_corner_lat)
 {
-  long i, j, index;
+  (void)yunitstr;
+
   double minlat, maxlat;
-  double firstlat, lastlat;
 
-  firstlat = grid_center_lat[0];
-  lastlat  = grid_center_lat[xsize*ysize-1];
+  double firstlat = grid_center_lat[0];
+  double lastlat  = grid_center_lat[xsize*ysize-1];
 
   // if ( ysize == 1 ) cdoAbort("Cannot calculate Ybounds for 1 value!");
 
-  for ( j = 0; j < ysize; ++j )
+  for ( int j = 0; j < ysize; ++j )
     {
       if ( ysize == 1 )
 	{
@@ -291,7 +398,7 @@ void grid_cell_center_to_bounds_Y2D(const char* yunitstr, long xsize, long ysize
 	}
       else
 	{
-	  index = j*xsize;
+	  int index = j*xsize;
 	  if ( firstlat > lastlat )
 	    {
 	      if ( j == 0 )
@@ -318,9 +425,9 @@ void grid_cell_center_to_bounds_Y2D(const char* yunitstr, long xsize, long ysize
 	    }
 	}
 
-      for ( i = 0; i < xsize; ++i )
+      for ( int i = 0; i < xsize; ++i )
 	{
-	  index = (j<<2)*xsize + (i<<2);
+	  int index = (j<<2)*xsize + (i<<2);
 	  grid_corner_lat[index  ] = minlat;
 	  grid_corner_lat[index+1] = minlat;
 	  grid_corner_lat[index+2] = maxlat;
@@ -329,20 +436,14 @@ void grid_cell_center_to_bounds_Y2D(const char* yunitstr, long xsize, long ysize
     }
 }
 
-
-void gridGenRotBounds(int gridID, int nx, int ny,
+static
+void gridGenRotBounds(double xpole, double ypole, double angle, int nx, int ny,
 		      double *xbounds, double *ybounds, double *xbounds2D, double *ybounds2D)
 {
-  long i, j, index;
   double minlon, maxlon;
   double minlat, maxlat;
-  double xpole, ypole, angle;
-
-  xpole = gridInqXpole(gridID);
-  ypole = gridInqYpole(gridID);
-  angle = gridInqAngle(gridID);
 
-  for ( j = 0; j < ny; j++ )
+  for ( int j = 0; j < ny; j++ )
     {
       if ( ybounds[0] > ybounds[1] )
 	{
@@ -355,12 +456,12 @@ void gridGenRotBounds(int gridID, int nx, int ny,
 	  minlat = ybounds[2*j];
 	}
 
-      for ( i = 0; i < nx; i++ )
+      for ( int i = 0; i < nx; i++ )
 	{
 	  minlon = xbounds[2*i];
 	  maxlon = xbounds[2*i+1];
 
-	  index = j*4*nx + 4*i;
+	  int index = j*4*nx + 4*i;
 	  xbounds2D[index+0] = lamrot_to_lam(minlat, minlon, ypole, xpole, angle);
 	  xbounds2D[index+1] = lamrot_to_lam(minlat, maxlon, ypole, xpole, angle);
 	  xbounds2D[index+2] = lamrot_to_lam(maxlat, maxlon, ypole, xpole, angle);
@@ -377,22 +478,17 @@ void gridGenRotBounds(int gridID, int nx, int ny,
 
 void grid_gen_xbounds2D(int nx, int ny, const double *restrict xbounds, double *restrict xbounds2D)
 {
-  int index;
-  double minlon, maxlon;
-
 #if defined(_OPENMP)
-#pragma omp parallel for default(none)        \
-                          shared(nx, ny, xbounds, xbounds2D) \
-                         private(minlon, maxlon, index)
+#pragma omp parallel for default(none) shared(nx, ny, xbounds, xbounds2D)
 #endif
   for ( int i = 0; i < nx; ++i )
     {
-      minlon = xbounds[2*i  ];
-      maxlon = xbounds[2*i+1];
+      double minlon = xbounds[2*i  ];
+      double maxlon = xbounds[2*i+1];
 
       for ( int j = 0; j < ny; ++j )
 	{
-	  index = j*4*nx + 4*i;
+	  int index = j*4*nx + 4*i;
 	  xbounds2D[index  ] = minlon;
 	  xbounds2D[index+1] = maxlon;
 	  xbounds2D[index+2] = maxlon;
@@ -404,16 +500,12 @@ void grid_gen_xbounds2D(int nx, int ny, const double *restrict xbounds, double *
 
 void grid_gen_ybounds2D(int nx, int ny, const double *restrict ybounds, double *restrict ybounds2D)
 {
-  int index;
-  double minlat, maxlat;
-
 #if defined(_OPENMP)
-#pragma omp parallel for default(none)        \
-                          shared(nx, ny, ybounds, ybounds2D) \
-                         private(minlat, maxlat, index)
+#pragma omp parallel for default(none) shared(nx, ny, ybounds, ybounds2D)
 #endif
   for ( int j = 0; j < ny; ++j )
     {
+      double minlat, maxlat;
       if ( ybounds[0] > ybounds[1] )
 	{
 	  maxlat = ybounds[2*j  ];
@@ -427,7 +519,7 @@ void grid_gen_ybounds2D(int nx, int ny, const double *restrict ybounds, double *
 
       for ( int i = 0; i < nx; ++i )
 	{
-	  index = j*4*nx + 4*i;
+	  int index = j*4*nx + 4*i;
 	  ybounds2D[index  ] = minlat;
 	  ybounds2D[index+1] = minlat;
 	  ybounds2D[index+2] = maxlat;
@@ -441,17 +533,15 @@ char *gen_param(const char *fmt, ...)
 {
   va_list args;
   char str[256];
-  char *rstr;
-  int len;
 
   va_start(args, fmt);
 
-  len = vsprintf(str, fmt, args);
+  int len = vsprintf(str, fmt, args);
 
   va_end(args);
 
   len++;
-  rstr = (char*) Malloc(len*sizeof(char));
+  char *rstr = (char*) Malloc(len*sizeof(char));
   memcpy(rstr, str, len*sizeof(char));
 
   return rstr;
@@ -461,13 +551,10 @@ static
 void lcc_to_geo(int gridID, int gridsize, double *xvals, double *yvals)
 {
   double originLon, originLat, lonParY, lat1, lat2, xincm, yincm;
-  double zlat, zlon;
-  double xi, xj;
   int projflag, scanflag;
-  long i;
   proj_info_t proj;
 
-  gridInqLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm, &projflag, &scanflag);
+  gridInqParamLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm, &projflag, &scanflag);
   /*
     while ( originLon < 0 ) originLon += 360;
     while ( lonParY   < 0 ) lonParY   += 360;
@@ -482,10 +569,11 @@ void lcc_to_geo(int gridID, int gridsize, double *xvals, double *yvals)
   */
   map_set(PROJ_LC, originLat, originLon, xincm, lonParY, lat1, lat2, &proj);
 
-  for ( i = 0; i < gridsize; i++ )
+  double zlat, zlon;
+  for ( int i = 0; i < gridsize; i++ )
     {
-      xi = xvals[i];
-      xj = yvals[i];
+      double xi = xvals[i];
+      double xj = yvals[i];
       // status = W3FB12(xi, xj, originLat, originLon, xincm, lonParY, lat1, &zlat, &zlon);
       ijll_lc(xi, xj, proj, &zlat, &zlon);
       xvals[i] = zlon;
@@ -494,30 +582,28 @@ void lcc_to_geo(int gridID, int gridsize, double *xvals, double *yvals)
 }
 
 static
-void sinusoidal_to_geo(int gridsize, double *xvals, double *yvals)
+void sinu_to_geo(int gridsize, double *xvals, double *yvals)
 {
 #if defined(HAVE_LIBPROJ)
   char *params[20];
   projUV data, res;
-  long i;
 
   int nbpar = 0;
   params[nbpar++] = gen_param("proj=sinu");
   params[nbpar++] = gen_param("ellps=WGS84");
 
   if ( cdoVerbose )
-    for ( i = 0; i < nbpar; ++i )
-      cdoPrint("Proj.param[%ld] = %s", i+1, params[i]);
+    for ( int i = 0; i < nbpar; ++i )
+      cdoPrint("Proj.param[%d] = %s", i+1, params[i]);
 
   projPJ proj = pj_init(nbpar, params);
-  if ( !proj )
-    cdoAbort("proj error: %s", pj_strerrno(pj_errno));
+  if ( !proj ) cdoAbort("proj error: %s", pj_strerrno(pj_errno));
 
-  for ( i = 0; i < nbpar; ++i ) Free(params[i]);
+  for ( int i = 0; i < nbpar; ++i ) Free(params[i]);
 
   /* proj->over = 1; */		/* allow longitude > 180 */
 
-  for ( i = 0; i < gridsize; i++ )
+  for ( int i = 0; i < gridsize; i++ )
     {
       data.u = xvals[i];
       data.v = yvals[i];
@@ -534,36 +620,151 @@ void sinusoidal_to_geo(int gridsize, double *xvals, double *yvals)
 #endif
 }
 
+
+void grid_def_param_sinu(int gridID)
+{
+  const char *projection = "sinusoidal";
+  cdiGridDefKeyStr(gridID, CDI_KEY_MAPNAME, (int)strlen(projection)+1, projection);
+  const char *mapvarname = "Sinusoidal";
+  cdiGridDefKeyStr(gridID, CDI_KEY_MAPPING, (int)strlen(mapvarname)+1, mapvarname);
+
+  cdiDefAttTxt(gridID, CDI_GLOBAL, "grid_mapping_name", (int)strlen(projection), projection);
+}
+
+
+void grid_def_param_laea(int gridID, double a, double lon_0, double lat_0)
+{
+  const char *projection = "lambert_azimuthal_equal_area";
+  cdiGridDefKeyStr(gridID, CDI_KEY_MAPNAME, (int)strlen(projection)+1, projection);
+  const char *mapvarname = "Lambert_AEA";
+  cdiGridDefKeyStr(gridID, CDI_KEY_MAPPING, (int)strlen(mapvarname)+1, mapvarname);
+
+  cdiDefAttTxt(gridID, CDI_GLOBAL, "grid_mapping_name", (int)strlen(projection), projection);
+  
+  cdiDefAttFlt(gridID, CDI_GLOBAL, "earth_radius", CDI_DATATYPE_FLT64, 1, &a);
+  cdiDefAttFlt(gridID, CDI_GLOBAL, "longitude_of_projection_origin", CDI_DATATYPE_FLT64, 1, &lon_0);
+  cdiDefAttFlt(gridID, CDI_GLOBAL, "latitude_of_projection_origin", CDI_DATATYPE_FLT64, 1, &lat_0);
+}
+
+static
+void grid_inq_param_laea(int gridID, double *a, double *lon_0, double *lat_0, double *x_0, double *y_0)
+{
+  *a = 0; *lon_0 = 0; *lat_0 = 0, *x_0 = 0, *y_0 = 0;
+
+  int gridtype = gridInqType(gridID);
+  if ( gridtype == GRID_PROJECTION )
+    {
+      const char *projection = "lambert_azimuthal_equal_area";
+      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;
+
+              if ( atttype == CDI_DATATYPE_FLT32 || atttype == CDI_DATATYPE_FLT64 )
+                {
+                  double attflt;
+                  cdiInqAttFlt(gridID, CDI_GLOBAL, attname, attlen, &attflt);
+                  if      ( strcmp(attname, "earth_radius") == 0 )                    *a     = attflt;
+                  else if ( strcmp(attname, "longitude_of_projection_origin") == 0 )  *lon_0 = attflt;
+                  else if ( strcmp(attname, "latitude_of_projection_origin") == 0 )   *lat_0 = attflt;
+                  else if ( strcmp(attname, "false_easting")  == 0 )  *x_0 = attflt;
+                  else if ( strcmp(attname, "false_northing") == 0 )  *y_0 = attflt;
+                }
+            }
+        }
+      else
+        Warning("%s mapping parameter missing!", projection);
+    }
+}
+
+static
+void grid_inq_param_lcc(int gridID, double *a, double *lon_0, double *lat_0, double *lat_1, double *lat_2, double *x_0, double *y_0)
+{
+  *a = 0; *lon_0 = 0; *lat_0 = 0; *lat_1 = 0, *lat_2 = 0, *x_0 = 0, *y_0 = 0;
+
+  int gridtype = gridInqType(gridID);
+  if ( gridtype == GRID_PROJECTION )
+    {
+      const char *projection = "lambert_conformal_conic";
+      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 > 2 ) continue;
+
+              if ( atttype == CDI_DATATYPE_FLT32 || atttype == CDI_DATATYPE_FLT64 )
+                {
+                  double attflt[2];
+                  cdiInqAttFlt(gridID, CDI_GLOBAL, attname, attlen, attflt);
+                  if      ( strcmp(attname, "earth_radius") == 0 )                   *a     = 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, "standard_parallel") == 0 )
+                    {
+                      *lat_1 = attflt[0];
+                      if ( attlen == 2 ) *lat_2 = attflt[1];
+                    }
+                }
+            }
+        }
+      else
+        Warning("%s mapping parameter missing!", projection);
+    }
+}
+
 static
 void laea_to_geo(int gridID, int gridsize, double *xvals, double *yvals)
 {
 #if defined(HAVE_LIBPROJ)
   char *params[20];
   projUV data, res;
-  double a, lon_0, lat_0;
-  long i;
-
-  gridInqLaea(gridID, &a , &lon_0, &lat_0);
+  
+  double a, lon_0, lat_0, x_0, y_0;
+  grid_inq_param_laea(gridID, &a, &lon_0, &lat_0, &x_0, &y_0);
 
   int nbpar = 0;
   params[nbpar++] = gen_param("proj=laea");
   if ( a > 0 ) params[nbpar++] = gen_param("a=%g", a);
   params[nbpar++] = gen_param("lon_0=%g", lon_0);
   params[nbpar++] = gen_param("lat_0=%g", lat_0);
+  if ( IS_NOT_EQUAL(x_0,0) ) params[nbpar++] = gen_param("x_0=%g", x_0);
+  if ( IS_NOT_EQUAL(y_0,0) ) params[nbpar++] = gen_param("y_0=%g", y_0);
 
   if ( cdoVerbose )
-    for ( i = 0; i < nbpar; ++i )
+    for ( int i = 0; i < nbpar; ++i )
       cdoPrint("Proj.param[%d] = %s", i+1, params[i]);
 
   projPJ proj = pj_init(nbpar, &params[0]);
-  if ( !proj )
-    cdoAbort("proj error: %s", pj_strerrno(pj_errno));
+  if ( !proj ) cdoAbort("proj error: %s", pj_strerrno(pj_errno));
 
-  for ( i = 0; i < nbpar; ++i ) Free(params[i]);
+  for ( int i = 0; i < nbpar; ++i ) Free(params[i]);
 
   /* proj->over = 1; */		/* allow longitude > 180 */
 
-  for ( i = 0; i < gridsize; i++ )
+  for ( int i = 0; i < gridsize; i++ )
     {
       data.u = xvals[i];
       data.v = yvals[i];
@@ -586,10 +787,9 @@ void lcc2_to_geo(int gridID, int gridsize, double *xvals, double *yvals)
 #if defined(HAVE_LIBPROJ)
   char *params[20];
   projUV data, res;
-  double a, lon_0, lat_0, lat_1, lat_2;
-  long i;
 
-  gridInqLcc2(gridID, &a , &lon_0, &lat_0, &lat_1, &lat_2);
+  double a, lon_0, lat_0, lat_1, lat_2, x_0, y_0;
+  grid_inq_param_lcc(gridID, &a, &lon_0, &lat_0, &lat_1, &lat_2, &x_0, &y_0);
 
   int nbpar = 0;
   params[nbpar++] = gen_param("proj=lcc");
@@ -598,26 +798,76 @@ void lcc2_to_geo(int gridID, int gridsize, double *xvals, double *yvals)
   params[nbpar++] = gen_param("lat_0=%g", lat_0);
   params[nbpar++] = gen_param("lat_1=%g", lat_1);
   params[nbpar++] = gen_param("lat_2=%g", lat_2);
+  if ( IS_NOT_EQUAL(x_0,0) ) params[nbpar++] = gen_param("x_0=%g", x_0);
+  if ( IS_NOT_EQUAL(y_0,0) ) params[nbpar++] = gen_param("y_0=%g", y_0);
 
   if ( cdoVerbose )
-    for ( i = 0; i < nbpar; ++i )
+    for ( int i = 0; i < nbpar; ++i )
       cdoPrint("Proj.param[%d] = %s", i+1, params[i]);
   
   projPJ proj = pj_init(nbpar, &params[0]);
-  if ( !proj )
-    cdoAbort("proj error: %s", pj_strerrno(pj_errno));
+  if ( !proj ) cdoAbort("proj error: %s", pj_strerrno(pj_errno));
 
-  for ( i = 0; i < nbpar; ++i ) Free(params[i]);
+  for ( int i = 0; i < nbpar; ++i ) Free(params[i]);
 
   /* proj->over = 1; */		/* allow longitude > 180 */
   
-  for ( i = 0; i < gridsize; i++ )
+  for ( int i = 0; i < gridsize; i++ )
+    {
+      data.u = xvals[i];
+      data.v = yvals[i];
+      res = pj_inv(data, proj);
+      xvals[i] = res.u*RAD2DEG;
+      yvals[i] = res.v*RAD2DEG;
+    }
+
+  pj_free(proj);
+#else
+  cdoAbort("proj4 support not compiled in!");
+#endif
+}
+
+static
+void proj_to_geo(char *proj4param, int gridsize, double *xvals, double *yvals)
+{
+#if defined(HAVE_LIBPROJ)
+  char *params[99];
+  projUV data, res;
+
+  int nbpar;
+  for ( nbpar = 0; nbpar < 99; ++nbpar )
+    {
+      while ( *proj4param == ' ' || *proj4param == '+' ) proj4param++;
+      if ( *proj4param == 0 ) break;
+      char *cstart = proj4param;
+      while ( *proj4param != ' ' && *proj4param != 0 ) proj4param++;
+      char *cend = proj4param;
+      size_t len = cend - cstart;
+      if ( len <= 0 ) break;
+      bool lend = *cend == 0;
+      if ( !lend ) *cend = 0;
+      params[nbpar] = strdup(cstart);
+      if ( !lend ) *cend = ' ';
+    }
+
+  if ( cdoVerbose )
+    for ( int i = 0; i < nbpar; ++i )
+      cdoPrint("Proj.param[%d] = %s", i+1, params[i]);
+
+  projPJ proj = pj_init(nbpar, &params[0]);
+  if ( !proj ) cdoAbort("proj error: %s", pj_strerrno(pj_errno));
+
+  for ( int i = 0; i < nbpar; ++i ) Free(params[i]);
+
+  for ( int i = 0; i < gridsize; i++ )
     {
       data.u = xvals[i];
       data.v = yvals[i];
       res = pj_inv(data, proj);
       xvals[i] = res.u*RAD2DEG;
       yvals[i] = res.v*RAD2DEG;
+      if ( xvals[i] < -9000. || xvals[i] > 9000. ) xvals[i] = -9999.;
+      if ( yvals[i] < -9000. || yvals[i] > 9000. ) yvals[i] = -9999.;
     }
 
   pj_free(proj);
@@ -637,18 +887,17 @@ void lcc2_to_geo(int gridID, int gridsize, double *xvals, double *yvals)
 static
 void grib_get_reduced_row(long pl,double lon_first,double lon_last,long* npoints,long* ilon_first, long* ilon_last )
 {
-  double range=0,dlon_first=0,dlon_last=0;
-  long irange;
+  double dlon_first=0, dlon_last=0;
 
-  range=lon_last-lon_first;
-  if (range<0) {range+=360;lon_first-=360;}
+  double range = lon_last-lon_first;
+  if ( range < 0 ) {range+=360;lon_first-=360;}
 
   /* computing integer number of points and coordinates without using floating point resolution*/
   *npoints=(range*pl)/360.0+1;
   *ilon_first=(lon_first*pl)/360.0;
   *ilon_last=(lon_last*pl)/360.0;
 
-  irange=*ilon_last-*ilon_first+1;
+  long irange=*ilon_last-*ilon_first+1;
 
   if (irange != *npoints) {
     if (irange > *npoints) {
@@ -694,7 +943,6 @@ static
 int qu2reg_subarea(int gridsize, int np, double xfirst, double xlast, 
 		   double *array, int *rowlon, int ny, double missval, int *iret, int lmiss, int lperio, int lveggy)
 {
-  int nx = 0;
   /* sub area (longitudes) */
   long ilon_firstx;
   long ilon_first, ilon_last;
@@ -704,20 +952,18 @@ int qu2reg_subarea(int gridsize, int np, double xfirst, double xlast,
   int np4 = np*4;
   int size = 0;
   int wlen;
-  double *work, **pwork;
   int ii;
-  double *parray;
 
   if ( np <= 0 ) cdoAbort("Number of values between pole and equator missing!");
 
   grib_get_reduced_row(np4, xfirst, xlast, &row_count, &ilon_firstx, &ilon_last);
-  nx = row_count;
+  int nx = row_count;
   // printf("nx %d  %ld %ld lon1 %g lon2 %g\n", nx, ilon_firstx, ilon_last, (ilon_firstx*360.)/np4, (ilon_last*360.)/np4);
 
   for ( j = 0; j < ny; ++j ) nwork += rowlon[j];
 
-  pwork = (double **) Malloc(ny*sizeof(double *));
-  work  = (double*) Malloc(ny*np4*sizeof(double));
+  double **pwork = (double **) Malloc(ny*sizeof(double *));
+  double *work = (double*) Malloc(ny*np4*sizeof(double));
   wlen = 0;
   pwork[0] = work;
   for ( j = 1; j < ny; ++j )
@@ -733,7 +979,7 @@ int qu2reg_subarea(int gridsize, int np, double xfirst, double xlast,
       for ( i = 0; i < rlon; ++i ) pwork[j][i] = missval;
     } 
 
-  parray = array;
+  double *parray = array;
   for ( j = 0; j < ny; ++j )
     {
       rlon = rowlon[j];
@@ -783,44 +1029,35 @@ int qu2reg_subarea(int gridsize, int np, double xfirst, double xlast,
 }
 
 
-void field2regular(int gridID1, int gridID2, double missval, double *array, int nmiss)
+void field2regular(int gridID1, int gridID2, double missval, double *array, int nmiss, int lnearest)
 {
-  int nx = 0, ny, np;
-  int gridtype;
-  int lmiss, lperio, lveggy;
-  int iret;
-  int *rowlon;
-  double xfirstandlast[2];
-  double xfirst, xlast;
-
-  gridtype = gridInqType(gridID1);
-
+  int gridtype = gridInqType(gridID1);
   if ( gridtype != GRID_GAUSSIAN_REDUCED ) Error("Not a reduced Gaussian grid!");
 
-  lmiss = nmiss > 0;
-  lperio = 1;
-  lveggy = 0;
+  int lmiss = nmiss > 0;
+  int lperio = 1;
 
-  ny = gridInqYsize(gridID1);
-  np = gridInqNP(gridID1);
+  int ny = gridInqYsize(gridID1);
+  int np = gridInqNP(gridID1);
 
-  rowlon = (int*) Malloc(ny*sizeof(int));
+  int *rowlon = (int*) Malloc(ny*sizeof(int));
   gridInqRowlon(gridID1, rowlon);
 
-  xfirstandlast[0] = 0.;
-  xfirstandlast[1] = 0.;
+  double xfirstandlast[2] = {0, 0};
   gridInqXvals(gridID1, xfirstandlast);
-  xfirst = xfirstandlast[0];
-  xlast  = xfirstandlast[1];
+  double xfirst = xfirstandlast[0];
+  double xlast  = xfirstandlast[1];
 
+  int iret;
+  int 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, lveggy);
+      nx = qu2reg_subarea(gridInqSize(gridID1), np, xfirst, xlast, array, rowlon, ny, missval, &iret, lmiss, lperio, lnearest);
     }
   else
     {
       nx = 2*ny;
-      (void) qu2reg3_double(array, rowlon, ny, nx, missval, &iret, lmiss, lperio, lveggy);
+      (void) qu2reg3_double(array, rowlon, ny, nx, missval, &iret, lmiss, lperio, lnearest);
     }
 
   if ( gridInqSize(gridID2) != nx*ny ) Error("Gridsize differ!");
@@ -831,29 +1068,22 @@ void field2regular(int gridID1, int gridID2, double missval, double *array, int
 
 int gridToRegular(int gridID1)
 {
-  int gridID2;
-  int gridtype, gridsize;
-  int nx = 0, ny, np;
-  long i;
-  double *xvals = NULL, *yvals = NULL;
-  double xfirstandlast[2];
-  double xfirst, xlast;
-
-  gridtype = gridInqType(gridID1);
+  int nx = 0;
+  double *xvals = NULL;
 
+  int gridtype = gridInqType(gridID1);
   if ( gridtype != GRID_GAUSSIAN_REDUCED ) Error("Not a reduced Gaussian grid!");
 
-  ny = gridInqYsize(gridID1);
-  np = gridInqNP(gridID1);
+  int ny = gridInqYsize(gridID1);
+  int np = gridInqNP(gridID1);
 
-  yvals = (double*) Malloc(ny*sizeof(double));
+  double *yvals = (double*) Malloc(ny*sizeof(double));
   gridInqYvals(gridID1, yvals);
 
-  xfirstandlast[0] = 0.;
-  xfirstandlast[1] = 0.;
+  double xfirstandlast[2] = {0, 0};
   gridInqXvals(gridID1, xfirstandlast);
-  xfirst = xfirstandlast[0];
-  xlast  = xfirstandlast[1];
+  double xfirst = xfirstandlast[0];
+  double xlast  = xfirstandlast[1];
 
   if ( fabs(xfirst) > 0 || (np > 0 && fabs(xlast - (360.0-90.0/np)) > 90.0/np) )
     {
@@ -869,7 +1099,7 @@ int gridToRegular(int gridID1)
 
       nx = row_count;
       xvals = (double*) Malloc(nx*sizeof(double));
-      for ( i = 0; i < nx; ++i )
+      for ( int i = 0; i < nx; ++i )
 	{
 	  xvals[i] = ((ilon_first+i)*360.)/np4;
 	  if ( xfirst > xlast ) xvals[i] -= 360.;
@@ -881,12 +1111,11 @@ int gridToRegular(int gridID1)
     {
       nx = 2*ny;
       xvals = (double*) Malloc(nx*sizeof(double));
-      for ( i = 0; i < nx; ++i ) xvals[i] = i * 360./nx;
+      for ( int i = 0; i < nx; ++i ) xvals[i] = i * 360./nx;
     }
 
-  gridsize = nx*ny;
-
-  gridID2  = gridCreate(GRID_GAUSSIAN, gridsize);
+  int gridsize = nx*ny;
+  int gridID2  = gridCreate(GRID_GAUSSIAN, gridsize);
 	  
   gridDefXsize(gridID2, nx);
   gridDefYsize(gridID2, ny);
@@ -914,16 +1143,15 @@ void gridCopyMask(int gridID1, int gridID2, long gridsize)
 }
 
 static
-int check_range(long n, double *vals, double valid_min, double valid_max)
+bool check_range(long n, double *vals, double valid_min, double valid_max)
 {
-  int status = 0;
-  long i;
+  bool status = false;
 
-  for ( i = 0; i < n; ++i )
+  for ( long i = 0; i < n; ++i )
     {
       if ( vals[i] < valid_min || vals[i] > valid_max )
 	{
-	  status = 1;
+	  status = true;
 	  break;
 	}
     }
@@ -932,49 +1160,116 @@ int check_range(long n, double *vals, double valid_min, double valid_max)
 }
 
 
+char *grid_get_proj4param(int gridID)
+{
+  char *proj4param = NULL;
+
+  int gridtype = gridInqType(gridID);
+  if ( gridtype == GRID_PROJECTION )
+    {
+      int atttype, attlen, atttxtlen = 0;
+      char *atttxt = NULL;
+      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 ( atttype == CDI_DATATYPE_TXT )
+            {
+              if ( attlen > atttxtlen )
+                {
+                  atttxt = (char*) Realloc(atttxt, (attlen+1));
+                  atttxtlen = attlen;
+                }
+              cdiInqAttTxt(gridID, CDI_GLOBAL, attname, attlen, atttxt);
+              atttxt[attlen] = 0;
+              if ( strcmp(attname, "proj4_params") == 0 )
+                {
+                  proj4param = atttxt;
+                  break;
+                }
+            }
+        }
+      if ( proj4param == NULL && atttxt ) Free(atttxt);
+    }
+
+  return proj4param;
+}
+
+
 int gridToCurvilinear(int gridID1, int lbounds)
 {
-  long index;
+  int index;
   int gridtype = gridInqType(gridID1);
-  size_t gridsize = (size_t) gridInqSize(gridID1);
-  int gridID2  = gridCreate(GRID_CURVILINEAR, (int) gridsize);
-  gridDefPrec(gridID2, DATATYPE_FLT32);
-	  
+
+  int nx = gridInqXsize(gridID1);
+  int ny = gridInqYsize(gridID1);
+
+  bool lxyvals = gridInqXvals(gridID1, NULL) && gridInqYvals(gridID1, NULL);
+  if ( !lxyvals ) cdoAbort("Grid coordinates missing!");
+
+  int gridsize = gridInqSize(gridID1);
+  int gridID2 = gridCreate(GRID_CURVILINEAR, gridsize);
+  gridDefPrec(gridID2, CDI_DATATYPE_FLT32);
+
+  char *proj4param = NULL;
+  bool lproj4     = false;
+  bool lproj_rll  = false;
+  bool lproj_laea = false;
+  bool lproj_lcc  = false;
+  bool lproj_sinu = false;
+  if ( gridtype == GRID_PROJECTION && gridsize == nx*ny )
+    {
+      proj4param = grid_get_proj4param(gridID1);
+      if ( proj4param )
+        {
+          lproj4 = true;
+          gridtype = GRID_LONLAT;
+        }
+      else
+        {
+          int projtype = gridInqProjType(gridID1);
+          if      ( projtype == CDI_PROJ_RLL  ) lproj_rll  = true;
+          else if ( projtype == CDI_PROJ_LAEA ) lproj_laea = true;
+          else if ( projtype == CDI_PROJ_LCC  ) lproj_lcc  = true;
+          else if ( projtype == CDI_PROJ_SINU ) lproj_sinu = true;
+
+          if ( lproj_rll || lproj_laea || lproj_lcc || lproj_sinu ) gridtype = GRID_LONLAT;
+        }
+    }
+
   switch (gridtype)
     {
     case GRID_LONLAT:
     case GRID_GAUSSIAN:
     case GRID_LCC:
-    case GRID_LCC2:
-    case GRID_LAEA:
-    case GRID_SINUSOIDAL:
       {
+        double xpole = 0, ypole = 0, angle = 0;
 	double xscale = 1, yscale = 1;
 	double *xvals = NULL, *yvals = NULL;
 	double *xbounds = NULL, *ybounds = NULL;
 	char xunits[CDI_MAX_NAME], yunits[CDI_MAX_NAME];
 
-	int nx = gridInqXsize(gridID1);
-	int ny = gridInqYsize(gridID1);
-
 	gridInqXunits(gridID1, xunits);
 	gridInqYunits(gridID1, yunits);
 
-	if ( gridtype == GRID_LAEA )
+	if ( lproj_laea || lproj_lcc || lproj_sinu )
 	  {
-	    bool lvalid_xunits = false;
-	    bool lvalid_yunits = false;
 	    int len;
 	    len = (int) strlen(xunits);
-	    if ( len == 1 && memcmp(xunits, "m",  1) == 0 ) lvalid_xunits = true;
-	    if ( len == 2 && memcmp(xunits, "km", 2) == 0 ) lvalid_xunits = true;
+            bool lvalid_xunits = (len == 1 && memcmp(xunits, "m",  1) == 0) ||
+                                 (len == 2 && memcmp(xunits, "km", 2) == 0);
 	    len = (int) strlen(yunits);
-	    if ( len == 1 && memcmp(yunits, "m",  1) == 0 ) lvalid_yunits = true;
-	    if ( len == 2 && memcmp(yunits, "km", 2) == 0 ) lvalid_yunits = true;
+            bool lvalid_yunits = (len == 1 && memcmp(yunits, "m",  1) == 0) ||
+                                 (len == 2 && memcmp(yunits, "km", 2) == 0);
 
-	    if ( lvalid_xunits == false )
+	    if ( !lvalid_xunits )
 	      cdoWarning("Possibly wrong result! Invalid x-coordinate units: \"%s\" (expected \"m\" or \"km\")", xunits);
-	    if ( lvalid_yunits == false )
+	    if ( !lvalid_yunits )
 	      cdoWarning("Possibly wrong result! Invalid y-coordinate units: \"%s\" (expected \"m\" or \"km\")", yunits);
 	  }
 
@@ -987,7 +1282,7 @@ int gridToCurvilinear(int gridID1, int lbounds)
 	double *xvals2D = (double*) Malloc(gridsize*sizeof(double));
 	double *yvals2D = (double*) Malloc(gridsize*sizeof(double));
 
-	if ( gridtype == GRID_LCC )
+        if ( gridtype == GRID_LCC )
 	  {
 	    for ( int j = 0; j < ny; j++ )
 	      for ( int i = 0; i < nx; i++ )
@@ -1000,10 +1295,6 @@ int gridToCurvilinear(int gridID1, int lbounds)
 	  }
 	else
 	  {
-            /*
-	    if ( ! (gridInqXvals(gridID1, NULL) && gridInqYvals(gridID1, NULL)) )
-	      Error("Grid has no coordinates");
-            */
             if ( nx == 0 ) nx = 1;
             if ( ny == 0 ) ny = 1;
 
@@ -1020,12 +1311,11 @@ int gridToCurvilinear(int gridID1, int lbounds)
             else
               for ( int i = 0; i < ny; ++i ) yvals[i] = 0;
             
-	    if ( gridIsRotated(gridID1) )
-	      {		
-		double xpole = gridInqXpole(gridID1);
-		double ypole = gridInqYpole(gridID1);
-		double angle = gridInqAngle(gridID1);
-		
+	    if ( lproj_rll )
+	      {
+                gridInqParamRLL(gridID1, &xpole, &ypole, &angle);
+                gridDefProj(gridID2, gridID1);
+
 		for ( int j = 0; j < ny; j++ )
 		  for ( int i = 0; i < nx; i++ )
 		    {
@@ -1042,19 +1332,10 @@ int gridToCurvilinear(int gridID1, int lbounds)
 		      yvals2D[j*nx+i] = yscale*yvals[j];
 		    }
 
-		if ( gridtype == GRID_SINUSOIDAL )
-		  {
-		    sinusoidal_to_geo(gridsize, xvals2D, yvals2D);
-		    /* correct_sinxvals(nx, ny, xvals2D); */
-		  }
-		else if ( gridtype == GRID_LAEA )
-		  {
-		    laea_to_geo(gridID1, gridsize, xvals2D, yvals2D);
-		  }
-		else if ( gridtype == GRID_LCC2 )
-		  {
-		    lcc2_to_geo(gridID1, gridsize, xvals2D, yvals2D);
-		  }
+		if      ( lproj_sinu ) sinu_to_geo(gridsize, xvals2D, yvals2D);
+		else if ( lproj_laea ) laea_to_geo(gridID1, gridsize, xvals2D, yvals2D);
+		else if ( lproj_lcc  ) lcc2_to_geo(gridID1, gridsize, xvals2D, yvals2D);
+		else if ( lproj4     ) proj_to_geo(proj4param, gridsize, xvals2D, yvals2D);
 	      }
 	  }
 
@@ -1132,9 +1413,7 @@ int gridToCurvilinear(int gridID1, int lbounds)
 	    else if ( ny > 1 )
 	      {
 		ybounds = (double*) Malloc(2*ny*sizeof(double));
-		if ( gridtype == GRID_SINUSOIDAL || 
-		     gridtype == GRID_LAEA       || 
-		     gridtype == GRID_LCC2 )
+		if ( lproj_sinu || lproj_laea || lproj_lcc || lproj4 )
 		  grid_gen_bounds(ny, yvals, ybounds);
 		else
 		  {
@@ -1148,15 +1427,13 @@ int gridToCurvilinear(int gridID1, int lbounds)
 		double *xbounds2D = (double*) Malloc(4*gridsize*sizeof(double));
 		double *ybounds2D = (double*) Malloc(4*gridsize*sizeof(double));
 
-		if ( gridIsRotated(gridID1) )
+		if ( lproj_rll )
 		  {
-		    gridGenRotBounds(gridID1, nx, ny, xbounds, ybounds, xbounds2D, ybounds2D);
+		    gridGenRotBounds(xpole, ypole, angle, nx, ny, xbounds, ybounds, xbounds2D, ybounds2D);
 		  }
 		else
 		  {
-		    if ( gridtype == GRID_SINUSOIDAL ||
-			 gridtype == GRID_LAEA       || 
-			 gridtype == GRID_LCC2 )
+		    if ( lproj_sinu || lproj_laea || lproj_lcc || lproj4 )
 		      {
 			for ( int j = 0; j < ny; j++ )
 			  for ( int i = 0; i < nx; i++ )
@@ -1176,24 +1453,10 @@ int gridToCurvilinear(int gridID1, int lbounds)
 			      ybounds2D[index+3] = yscale*ybounds[2*j];
 			    }
 			
-			if ( gridtype == GRID_SINUSOIDAL )
-			  {
-			    sinusoidal_to_geo(4*gridsize, xbounds2D, ybounds2D);
-			    /*
-			    xvals2D = (double*) Malloc(gridsize*sizeof(double));
-			    for ( j = 0; j < 4; ++j )
-			      {
-				for ( i = 0; i < gridsize; ++i ) xvals2D[i] = xbounds2D[i*4+j];
-				correct_sinxvals(nx, ny, xvals2D);
-				for ( i = 0; i < gridsize; ++i ) xbounds2D[i*4+j] = xvals2D[i];
-			      }
-			    Free(xvals2D);
-			    */
-			  }
-			else if ( gridtype == GRID_LAEA )
-			  laea_to_geo(gridID1, 4*gridsize, xbounds2D, ybounds2D);
-			else if ( gridtype == GRID_LCC2 )
-			  lcc2_to_geo(gridID1, 4*gridsize, xbounds2D, ybounds2D);
+			if      ( lproj_sinu ) sinu_to_geo(4*gridsize, xbounds2D, ybounds2D);
+			else if ( lproj_laea ) laea_to_geo(gridID1, 4*gridsize, xbounds2D, ybounds2D);
+			else if ( lproj_lcc  ) lcc2_to_geo(gridID1, 4*gridsize, xbounds2D, ybounds2D);
+                        else if ( lproj4     ) proj_to_geo(proj4param, 4*gridsize, xbounds2D, ybounds2D);
 		      }
 		    else
 		      {
@@ -1223,52 +1486,35 @@ int gridToCurvilinear(int gridID1, int lbounds)
       }
     default:
       {
-	Error("Grid type >%s< unsupported!", gridNamePtr(gridtype));
+	cdoAbort("Grid type >%s< unsupported!", gridNamePtr(gridtype));
 	break;
       }
     }
 
+  if ( proj4param ) Free(proj4param);
+
   return gridID2;
 }
 
 
 int gridToUnstructuredSelecton(int gridID1, int selectionSize, int *selectionIndexList, int nocoords, int nobounds)
 {
-
   /* transform input grid into a unstructured Version if necessary {{{ */
   int unstructuredGridID;
   if (GRID_UNSTRUCTURED == gridInqType(gridID1))
-  {
     unstructuredGridID = gridID1;
-  }
   else
-  {
     unstructuredGridID = gridToUnstructured(gridID1,!nobounds);
-  }
+
   int unstructuredGridSize = gridInqSize(unstructuredGridID);
 
   int unstructuredSelectionGridID = gridCreate(GRID_UNSTRUCTURED,selectionSize);
 
-  if ( nocoords ) return (unstructuredSelectionGridID);
+  if ( nocoords ) return unstructuredSelectionGridID;
   /* }}} */
 
   /* copy meta data of coordinates {{{*/
-  char xname[CDI_MAX_NAME], xlongname[CDI_MAX_NAME], xunits[CDI_MAX_NAME];
-  char yname[CDI_MAX_NAME], ylongname[CDI_MAX_NAME], yunits[CDI_MAX_NAME];
-
-  gridInqXname(unstructuredGridID, xname);
-  gridInqXlongname(unstructuredGridID, xlongname);
-  gridInqXunits(unstructuredGridID, xunits);
-  gridInqYname(unstructuredGridID, yname);
-  gridInqYlongname(unstructuredGridID, ylongname);
-  gridInqYunits(unstructuredGridID, yunits);
-
-  gridDefXname(unstructuredSelectionGridID, xname);
-  gridDefXlongname(unstructuredSelectionGridID, xlongname);
-  gridDefXunits(unstructuredSelectionGridID, xunits);
-  gridDefYname(unstructuredSelectionGridID, yname);
-  gridDefYlongname(unstructuredSelectionGridID, ylongname);
-  gridDefYunits(unstructuredSelectionGridID, yunits);
+  grid_copy_attributes(unstructuredGridID, unstructuredSelectionGridID);
   /* }}} */
 
   /* TODO: select bounds */
@@ -1332,21 +1578,30 @@ int gridToUnstructuredSelecton(int gridID1, int selectionSize, int *selectionInd
   Free(xvals);
   Free(yvals);
 
-  return (unstructuredSelectionGridID);
+  return unstructuredSelectionGridID;
 }
 
+
 int gridToUnstructured(int gridID1, int lbounds)
 {
   int gridtype = gridInqType(gridID1);
   int gridsize = gridInqSize(gridID1);
   int gridID2  = gridCreate(GRID_UNSTRUCTURED, gridsize);
-  gridDefPrec(gridID2, DATATYPE_FLT32);
+  gridDefPrec(gridID2, CDI_DATATYPE_FLT32);
 	  
+  bool lproj_rll = false;
+  if ( gridtype == GRID_PROJECTION && gridInqProjType(gridID1) == CDI_PROJ_RLL )
+    {
+      gridtype = GRID_LONLAT;
+      lproj_rll = true;
+    }
+
   switch (gridtype)
     {
     case GRID_LONLAT:
     case GRID_GAUSSIAN:
       {
+        double xpole = 0, ypole = 0, angle = 0;
 	gridDefXname(gridID2, "lon");
 	gridDefYname(gridID2, "lat");
 	gridDefXlongname(gridID2, "longitude");
@@ -1371,11 +1626,9 @@ int gridToUnstructured(int gridID1, int lbounds)
 	gridInqXvals(gridID1, xvals);
 	gridInqYvals(gridID1, yvals);
 
-	if ( gridIsRotated(gridID1) )
+	if ( lproj_rll )
 	  {	    
-	    double xpole = gridInqXpole(gridID1);
-	    double ypole = gridInqYpole(gridID1);
-	    double angle = gridInqAngle(gridID1);
+            gridInqParamRLL(gridID1, &xpole, &ypole, &angle);
 		
 	    for ( int j = 0; j < ny; j++ )
 	      for ( int i = 0; i < nx; i++ )
@@ -1432,9 +1685,9 @@ int gridToUnstructured(int gridID1, int lbounds)
 		double *xbounds2D = (double*) Malloc(4*gridsize*sizeof(double));
 		double *ybounds2D = (double*) Malloc(4*gridsize*sizeof(double));
 
-		if ( gridIsRotated(gridID1) )
+		if ( lproj_rll )
 		  {
-		    gridGenRotBounds(gridID1, nx, ny, xbounds, ybounds, xbounds2D, ybounds2D);
+		    gridGenRotBounds(xpole, ypole, angle, nx, ny, xbounds, ybounds, xbounds2D, ybounds2D);
 		  }
 		else
 		  {
@@ -1473,10 +1726,8 @@ int gridToUnstructured(int gridID1, int lbounds)
 	int nv = 6;
 	double *xbounds = NULL, *ybounds = NULL;
 
-	int nd  = gridInqGMEnd(gridID1);
-	int ni  = gridInqGMEni(gridID1);
-	int ni2 = gridInqGMEni2(gridID1);
-	int ni3 = gridInqGMEni3(gridID1);
+        int nd, ni, ni2, ni3;
+        gridInqParamGME(gridID1, &nd, &ni, &ni2, &ni3);
 
 	int *imask = (int*) Malloc(gridsize*sizeof(int));
 	double *xvals = (double*) Malloc(gridsize*sizeof(double));
@@ -1546,35 +1797,30 @@ int gridToUnstructured(int gridID1, int lbounds)
 int gridCurvilinearToRegular(int gridID1)
 {
   int gridID2 = -1;
-  int gridtype, gridsize;
-  long i, j;
-  int nx, ny;
-  int lx = TRUE, ly = TRUE;
-  double *xvals = NULL, *yvals = NULL;
-  double *xvals2D = NULL, *yvals2D = NULL;
+  bool lx = true, ly = true;
 	
-  gridtype = gridInqType(gridID1);
-  gridsize = gridInqSize(gridID1);
+  int gridtype = gridInqType(gridID1);
+  int gridsize = gridInqSize(gridID1);
 
   if ( gridtype != GRID_CURVILINEAR ) return gridID2;
 
-  nx = gridInqXsize(gridID1);
-  ny = gridInqYsize(gridID1);
+  int nx = gridInqXsize(gridID1);
+  int ny = gridInqYsize(gridID1);
 	
-  xvals2D = (double*) Malloc(gridsize*sizeof(double));
-  yvals2D = (double*) Malloc(gridsize*sizeof(double));
+  double *xvals2D = (double*) Malloc(gridsize*sizeof(double));
+  double *yvals2D = (double*) Malloc(gridsize*sizeof(double));
 
   gridInqXvals(gridID1, xvals2D);
   gridInqYvals(gridID1, yvals2D);
 
-  xvals = (double*) Malloc(nx*sizeof(double));
-  yvals = (double*) Malloc(ny*sizeof(double));
+  double *xvals = (double*) Malloc(nx*sizeof(double));
+  double *yvals = (double*) Malloc(ny*sizeof(double));
 
-  for ( i = 0; i < nx; i++ ) xvals[i] = xvals2D[i];
-  for ( j = 0; j < ny; j++ ) yvals[j] = yvals2D[j*nx];
+  for ( int i = 0; i < nx; i++ ) xvals[i] = xvals2D[i];
+  for ( int j = 0; j < ny; j++ ) yvals[j] = yvals2D[j*nx];
 
-  for ( j = 1; j < ny; j++ )
-    for ( i = 0; i < nx; i++ )
+  for ( int j = 1; j < ny; j++ )
+    for ( int i = 0; i < nx; i++ )
       {
 	if ( fabs(xvals[i] - xvals2D[j*nx+i]) > 1.e-6 )
 	  {
@@ -1584,8 +1830,8 @@ int gridCurvilinearToRegular(int gridID1)
 	  }
       }
 	
-  for ( i = 1; i < nx; i++ )
-    for ( j = 0; j < ny; j++ )
+  for ( int i = 1; i < nx; i++ )
+    for ( int j = 0; j < ny; j++ )
       {
 	if ( fabs(yvals[j] - yvals2D[j*nx+i]) > 1.e-6 )
 	  {
@@ -1599,17 +1845,17 @@ int gridCurvilinearToRegular(int gridID1)
   Free(yvals2D);
 
   if ( lx && ly )
-    {
-      char xunits[CDI_MAX_NAME], yunits[CDI_MAX_NAME];
-      
+    {      
       gridID2  = gridCreate(GRID_LONLAT, gridsize);
       gridDefXsize(gridID2, nx);
       gridDefYsize(gridID2, ny);
       
-      //  gridDefPrec(gridID2, DATATYPE_FLT32);
+      //  gridDefPrec(gridID2, CDI_DATATYPE_FLT32);
 
-      gridInqXunits(gridID1, xunits);
-      gridInqYunits(gridID1, yunits);
+      char xunits[CDI_MAX_NAME]; xunits[0] = 0;
+      char yunits[CDI_MAX_NAME]; yunits[0] = 0;
+      cdiGridInqKeyStr(gridID1, CDI_KEY_XUNITS, CDI_MAX_NAME, xunits);
+      cdiGridInqKeyStr(gridID1, CDI_KEY_YUNITS, CDI_MAX_NAME, yunits);
 
       grid_to_degree(xunits, nx, xvals, "grid1 center lon");
       grid_to_degree(yunits, ny, yvals, "grid1 center lat");
@@ -1627,13 +1873,11 @@ int gridCurvilinearToRegular(int gridID1)
 
 int gridGenWeights(int gridID, double *grid_area, double *grid_wgts)
 {
-  int i, nvals, gridsize, gridtype;
   int status = 0;
   int *grid_mask = NULL;
-  double total_area;
 
-  gridtype = gridInqType(gridID);
-  gridsize = gridInqSize(gridID);
+  int gridtype = gridInqType(gridID);
+  int gridsize = gridInqSize(gridID);
   
   if ( gridtype == GRID_GME )
     {
@@ -1642,9 +1886,9 @@ int gridGenWeights(int gridID, double *grid_area, double *grid_wgts)
       gridInqMaskGME(gridID, grid_mask);
     }
 
-  total_area = 0;
-  nvals = 0;
-  for ( i = 0; i < gridsize; i++ )
+  double total_area = 0;
+  int nvals = 0;
+  for ( int i = 0; i < gridsize; i++ )
     {
       if ( grid_mask )
 	if ( grid_mask[i] == 0 ) continue;
@@ -1652,9 +1896,9 @@ int gridGenWeights(int gridID, double *grid_area, double *grid_wgts)
       nvals++;
     }
 
-  if ( cdoVerbose ) cdoPrint("Total area = %g steradians", total_area);
+  if ( cdoVerbose ) cdoPrint("Total area = %g", total_area);
 
-  for ( i = 0; i < gridsize; i++ )
+  for ( int i = 0; i < gridsize; i++ )
     {
       if ( grid_mask )
 	if ( grid_mask[i] == 0 )
@@ -1675,10 +1919,8 @@ int gridGenWeights(int gridID, double *grid_area, double *grid_wgts)
 int gridWeightsOld(int gridID, double *weights)
 {
   int status = FALSE;
-  long i, j;
-  int len;
 
-  len = gridInqSize(gridID);
+  int len = gridInqSize(gridID);
 
   if ( gridHasArea(gridID) )
     {
@@ -1687,20 +1929,13 @@ int gridWeightsOld(int gridID, double *weights)
   else
     {
       int gridtype = gridInqType(gridID);
-
       if ( gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN )
 	{
-	  int     nlat, nlon;
-	  int     datapoint;
-	  double *lats = NULL, *lons = NULL;
-	  double sumw;
-	  double phi1, phi2, theta1, theta2, sindphi;
+	  int nlon = gridInqXsize(gridID);
+	  int nlat = gridInqYsize(gridID);
 
-	  nlon = gridInqXsize(gridID);
-	  nlat = gridInqYsize(gridID);
-
-	  lons = 1 + (double *) Malloc((nlon+2)*sizeof(double));
-	  lats = 1 + (double *) Malloc((nlat+2)*sizeof(double));
+	  double *lons = 1 + (double *) Malloc((nlon+2)*sizeof(double));
+	  double *lats = 1 + (double *) Malloc((nlat+2)*sizeof(double));
 
 	  gridInqXvals(gridID, lons);
 	  gridInqYvals(gridID, lats);
@@ -1714,25 +1949,25 @@ int gridWeightsOld(int gridID, double *weights)
 	  /*  Calculate weights.  */
 	  /*  phi 1 and 2 and theta 1 and 2 represent respectively the boundary */
 	  /*  latitudes and longitudes of a particular grid square.             */
-	  datapoint = 0;
-	  sumw = 0;
-	  for ( j = 0; j < nlat; j++ )
+	  int datapoint = 0;
+	  double sumw = 0;
+	  for ( int j = 0; j < nlat; j++ )
 	    {
-	      phi1 = (lats[j-1]+lats[j])/2*DEG2RAD;
-	      phi2 = (lats[j+1]+lats[j])/2*DEG2RAD;
+	      double phi1 = (lats[j-1]+lats[j])/2*DEG2RAD;
+	      double phi2 = (lats[j+1]+lats[j])/2*DEG2RAD;
 	      if ( phi1 < (-1*M_PI/2) ) phi1 = -1*M_PI/2;
 	      if ( phi1 > (   M_PI/2) ) phi1 =    M_PI/2;
 	      if ( phi2 > (   M_PI/2) ) phi2 =    M_PI/2;
 	      if ( phi2 < (-1*M_PI/2) ) phi2 = -1*M_PI/2;
-	      sindphi = sin(phi2)-sin(phi1);
-	      for( i = 0; i < nlon; i++ )
+	      double sindphi = sin(phi2)-sin(phi1);
+	      for ( int i = 0; i < nlon; i++ )
 		{
 		  if ( lons[i] >= lons[0]+360 || fabs(lats[j]) > 90 )
 		    weights[datapoint] = 0;
 		  else
 		    {
-		      theta1 = (lons[i-1]+lons[i])/2*DEG2RAD;
-		      theta2 = (lons[i+1]+lons[i])/2*DEG2RAD;
+		      double theta1 = (lons[i-1]+lons[i])/2*DEG2RAD;
+		      double theta2 = (lons[i+1]+lons[i])/2*DEG2RAD;
 		      weights[datapoint] = fabs((theta2-theta1)*sindphi);
 		      sumw += weights[datapoint];
 		    }
@@ -1742,7 +1977,7 @@ int gridWeightsOld(int gridID, double *weights)
 
 	  /* Normalise weights.  */
 	  if( IS_NOT_EQUAL(sumw, 0) )
-	    for( i = 0; i < datapoint; i++ ) weights[i] /= sumw;
+	    for( int i = 0; i < datapoint; i++ ) weights[i] /= sumw;
 
 	  if ( lons-1 ) Free(lons-1);
 	  if ( lats-1 ) Free(lats-1);
@@ -1751,7 +1986,7 @@ int gridWeightsOld(int gridID, double *weights)
 	{
 	  status = TRUE;
 
-	  for ( i = 0; i < len; i++ ) weights[i] = 1./len;
+	  for ( int i = 0; i < len; i++ ) weights[i] = 1./len;
 	}
     }
 
@@ -1761,16 +1996,14 @@ int gridWeightsOld(int gridID, double *weights)
 
 int gridWeights(int gridID, double *grid_wgts)
 {
-  int i, gridsize, gridtype;
-  int a_status, w_status;
-  double *grid_area;
+  int w_status = 1;
+  int a_status = 0;
 
-  gridtype = gridInqType(gridID);
-  gridsize = gridInqSize(gridID);
+  int gridsize = gridInqSize(gridID);
+  int gridtype = gridInqType(gridID);
+  int projtype = (gridtype == GRID_PROJECTION) ? gridInqProjType(gridID) : -1; 
   
-  grid_area = (double*) Malloc(gridsize*sizeof(double));
-
-  a_status = 0;
+  double *grid_area = (double*) Malloc(gridsize*sizeof(double));
 
   if ( gridHasArea(gridID) )
     {
@@ -1782,9 +2015,10 @@ int gridWeights(int gridID, double *grid_wgts)
       if ( gridtype == GRID_LONLAT      ||
 	   gridtype == GRID_GAUSSIAN    ||
 	   gridtype == GRID_LCC         ||
-	   gridtype == GRID_LCC2        ||
-	   gridtype == GRID_LAEA        ||
-	   gridtype == GRID_SINUSOIDAL  ||
+	   projtype == CDI_PROJ_RLL     ||
+	   projtype == CDI_PROJ_LAEA    ||
+	   projtype == CDI_PROJ_LCC     ||
+	   projtype == CDI_PROJ_SINU    ||
 	   gridtype == GRID_GME         ||
 	   gridtype == GRID_CURVILINEAR ||
 	   gridtype == GRID_UNSTRUCTURED )
@@ -1803,10 +2037,7 @@ int gridWeights(int gridID, double *grid_wgts)
     }
   else
     {
-      for ( i = 0; i < gridsize; ++i )
-	grid_wgts[i] = 1./gridsize;
-
-      w_status = 1;
+      for ( int 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 09d9323..11d5988 100644
--- a/src/grid.h
+++ b/src/grid.h
@@ -22,6 +22,19 @@
 #endif
 
 
+int nfc_to_nlat(int nfc, int ntr);
+int nlat_to_ntr(int nlat);
+int nlat_to_ntr_linear(int nlat);
+int ntr_to_nlat(int ntr);
+int ntr_to_nlat_linear(int ntr);
+int nlat_to_nlon(int nlat);
+
+void grid_copy_attributes(int gridID1, int gridID2);
+void grid_copy_mapping(int gridID1, int gridID2);
+
+void grid_def_param_laea(int gridID, double a, double lon0, double lat0);
+void grid_def_param_sinu(int gridID);
+
 bool grid_is_distance_generic(int gridID);
 
 void grid_to_radian(const char *units, long nvals, double *restrict values, const char *description);
@@ -50,7 +63,7 @@ int gridToUnstructuredSelecton(int gridID1, int selectionSize, int *selectionInd
 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);
+void field2regular(int gridID1, int gridID2, double missval, double *array, int nmiss, int lnearest);
 
 /* GME grid */
 struct cart {
diff --git a/src/grid_area.c b/src/grid_area.c
index fdd3622..9594b13 100644
--- a/src/grid_area.c
+++ b/src/grid_area.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -59,6 +59,7 @@ double yac_huiliers_area(int num_corners, double *cell_corner_lon, double *cell_
   return area;
 }
 */
+
 static
 void cross_product(const double *restrict a, const double *restrict b, double *restrict c)
 {
@@ -67,31 +68,33 @@ void cross_product(const double *restrict a, const double *restrict b, double *r
   c[2] = a[0]*b[1] - a[1]*b[0];
 }
 
+/*
 static
 double scalar_product(const double *restrict a, const double *restrict b)
 {
   return (a[0]*b[0] + a[1]*b[1] + a[2]*b[2]);
 }
+*/
 
 static
 double norm(const double *restrict a)
 {
   return (a[0]*a[0] + a[1]*a[1] + a[2]*a[2]);
 }
-
+/*
 static
 double mod_cell_area(int num_corners, double *cell_corner_lon, double *cell_corner_lat)
 {
   if ( num_corners < 3 ) return 0;
 
-  /* generalised version based on the ICON code, mo_base_geometry.f90
-     provided by Luis Kornblueh, MPI-M. */
+  // generalised version based on the ICON code, mo_base_geometry.f90
+  // provided by Luis Kornblueh, MPI-M.
 
   int M = num_corners; // number of vertices
   int m; // loop index over number of vertices M
   int i; // loop index over the three dimensions
 
-  double area;
+  double area = 0.0;
   double s[M];
   double ca[M];
   double a[M];
@@ -99,27 +102,22 @@ double mod_cell_area(int num_corners, double *cell_corner_lon, double *cell_corn
   double p[M][3];
   double u[M][3];
 
-  /* Convert into cartesian coordinates */
-
+  // Convert into cartesian coordinates
   for ( m = 0; m < M; m++ )
     lonlat_to_xyz(cell_corner_lon[m], cell_corner_lat[m], p[m]);
 
-  /* First, compute cross products Uij = Vi x Vj. */
-
+  // First, compute cross products Uij = Vi x Vj.
   for ( m = 0; m < M; m++ )
     cross_product(p[m], p[(m+1)%M], u[m]);
 
-  /*  Normalize Uij to unit vectors. */
-
-  area = 0.0;
-
+  //  Normalize Uij to unit vectors.
   for ( m = 0; m < M; m++ )
     {
       s[m] = norm(u[m]);
       area += s[m];
     }
 
-  /* Test for a degenerated cells associated with collinear vertices. */
+  // Test for a degenerated cells associated with collinear vertices.
 
   if ( fabs(area) > 0.0 )
     {
@@ -130,19 +128,18 @@ double mod_cell_area(int num_corners, double *cell_corner_lon, double *cell_corn
 	for ( i = 0; i < 3; i++ )
 	  u[m][i] = u[m][i]/s[m];
 
-      /*  Compute interior angles Ai as the dihedral angles between planes
-	  by using the definition of the scalar product
-
-	            ab = |a| |b| cos (phi)
-
-	  As a and b are already normalised this reduces to
-
-                    ab = cos (phi)
+      //  Compute interior angles Ai as the dihedral angles between planes
+      //  by using the definition of the scalar product
+      //
+      //	    ab = |a| |b| cos (phi)
+      //
+      //  As a and b are already normalised this reduces to
+      //
+      //            ab = cos (phi)
 
-          There is no explanation so far for the - in the loop below.
-	  But otherwise we don't get the correct results for triangles
-	  and cells. Must have something to do with the theorem.
-      */
+      //  There is no explanation so far for the - in the loop below.
+      //  But otherwise we don't get the correct results for triangles
+      //  and cells. Must have something to do with the theorem.
 
       for ( m = 0; m < M; m++ )
 	{
@@ -152,22 +149,19 @@ double mod_cell_area(int num_corners, double *cell_corner_lon, double *cell_corn
 	  a[m] = acos(ca[m]);
 	}
 
-      /*  Compute areas = a1 + a2 + a3 - (M-2) * pi.
-
-	  here for a unit sphere: */
-
+      //  Compute areas = a1 + a2 + a3 - (M-2) * pi. here for a unit sphere:
       area = - (double) (M-2) * M_PI;
 
       for ( m = 0; m < M; m++ )
 	area += a[m];
 
-      //   area *= EarthRadius * EarthRadius;
-
+      // area *= EarthRadius * EarthRadius;
       if ( area < 0.0 ) area = 0.0;
     }
 
   return area;
 }
+*/
 
 /** area of a spherical triangle based on L'Huilier's Theorem
   *
@@ -286,19 +280,21 @@ double mod_huiliers_area2(int num_corners, double *cell_corner_lon, double *cell
 int gridGenArea(int gridID, double* area)
 {
   int status = 0;
-  int lgrid_gen_bounds = FALSE;
-  int lgriddestroy = FALSE;
+  bool lgrid_gen_bounds = false;
+  bool lgriddestroy = false;
   long nv;
 
   long gridsize = gridInqSize(gridID);
   int gridtype = gridInqType(gridID);
+  int projtype = (gridtype == GRID_PROJECTION) ? gridInqProjType(gridID) : -1; 
 
   if ( gridtype != GRID_LONLAT      &&
        gridtype != GRID_GAUSSIAN    &&
        gridtype != GRID_LCC         &&
-       gridtype != GRID_LCC2        &&
-       gridtype != GRID_LAEA        &&
-       gridtype != GRID_SINUSOIDAL  &&
+       projtype != CDI_PROJ_RLL     &&
+       projtype != CDI_PROJ_LAEA    &&
+       projtype != CDI_PROJ_SINU    &&
+       projtype != CDI_PROJ_LCC     &&
        gridtype != GRID_GME         &&
        gridtype != GRID_CURVILINEAR &&
        gridtype != GRID_UNSTRUCTURED )
@@ -310,7 +306,7 @@ int gridGenArea(int gridID, double* area)
     {
       if ( gridtype == GRID_GME )
 	{
-	  lgriddestroy = TRUE;
+	  lgriddestroy = true;
 	  gridID = gridToUnstructured(gridID, 1);
           /*
 	  grid_mask = (int*) Malloc(gridsize*sizeof(int));
@@ -320,9 +316,9 @@ int gridGenArea(int gridID, double* area)
 	}
       else
 	{
-	  lgriddestroy = TRUE;
+	  lgriddestroy = true;
 	  gridID = gridToCurvilinear(gridID, 1);
-	  lgrid_gen_bounds = TRUE;
+	  lgrid_gen_bounds = true;
 	}
     }
 
@@ -332,7 +328,7 @@ int gridGenArea(int gridID, double* area)
 	{
 	  if ( gridInqNumber(gridID) > 0 )
 	    {
-	      lgriddestroy = TRUE;
+	      lgriddestroy = true;
 	      gridID = referenceToGrid(gridID);
 	      if ( gridID == -1 ) return 1;
 	    }
diff --git a/src/grid_from_name.c b/src/grid_from_name.c
new file mode 100644
index 0000000..2b94d14
--- /dev/null
+++ b/src/grid_from_name.c
@@ -0,0 +1,400 @@
+/*
+  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 <cdi.h>
+#include "cdo_int.h"
+#include "grid.h"
+#include "griddes.h"
+
+
+static
+void gen_grid_lonlat(griddes_t *grid, const char *pline, double inc, double lon1, double lon2, double lat1, double lat2)
+{
+  int gridtype = GRID_LONLAT;
+  bool lbounds = true;
+
+  if ( *pline != 0 && (*pline == '+' || *pline == '-') && (isdigit((int) *(pline+1)) || ispunct((int) *(pline+1))) )
+    {
+      char *endptr = (char *) pline;
+      double off = strtod(pline, &endptr);
+      pline = endptr;
+      
+      lon1 -= off;
+      lon2 += off;
+      lat1 -= off;
+      lat2 += off;
+      if ( lat1 < -90 ) lat1 = -90;
+      if ( lat2 >  90 ) lat2 =  90;
+    }
+
+  if ( *pline != 0 )
+    {
+      if ( *pline == '_' ) pline++;
+      else return;
+
+      if ( *pline == 0 ) return;
+
+      if ( ! isdigit((int) *pline) && !ispunct((int) *pline) ) return;
+
+      char *endptr = (char *) pline;
+      inc = strtod(pline, &endptr);
+      if ( *endptr != 0 )
+        {
+          pline = endptr;
+          if ( *pline == '_' ) pline++;
+          else return;
+          
+          if ( *pline == 0 ) return;
+          if ( *pline == 'c' )
+            {
+              gridtype = GRID_CURVILINEAR;
+              pline++;
+              if ( *pline == '0' )
+                {
+                  lbounds = false;
+                  pline++;
+                }
+            }
+          else if ( *pline == 'u' )
+            {
+              gridtype = GRID_UNSTRUCTURED;
+              pline++;
+              if ( *pline == '0' )
+                {
+                  lbounds = false;
+                  pline++;
+                }
+            }
+          if ( *pline != 0 ) return;          
+        }
+
+      if ( inc < 1e-9 ) inc = 1;
+    }
+
+  grid->type = gridtype;
+
+  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);
+
+  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;
+
+  if ( gridtype == GRID_LONLAT )
+    {
+      grid->xsize = nlon;
+      grid->ysize = nlat;
+      grid->xvals = xvals;
+      grid->yvals = yvals;
+      xvals = NULL;
+      yvals = NULL;
+    }
+  else
+    {
+      double 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++ )
+          {
+            xvals2D[j*nlon+i] = xvals[i];
+            yvals2D[j*nlon+i] = yvals[j];
+          }
+
+      if ( gridtype == GRID_CURVILINEAR )
+        {
+          grid->xsize = nlon;
+          grid->ysize = nlat;
+        }
+      else
+        {
+          grid->xsize = gridsize;
+          grid->ysize = gridsize;
+          if ( lbounds ) grid->nvertex = 4;
+        }
+      
+      grid->xvals = xvals2D;
+      grid->yvals = yvals2D;
+      
+      if ( lbounds && nlon > 1 && nlat > 1 )
+        {
+          double *xbounds = (double*) Malloc(2*nlon*sizeof(double));
+          grid_gen_bounds(nlon, xvals, xbounds);
+          
+          double *ybounds = (double*) Malloc(2*nlat*sizeof(double));
+          grid_gen_bounds(nlat, yvals, ybounds);
+          grid_check_lat_borders(2*nlat, ybounds);
+
+          double *xbounds2D = (double*) Malloc(4*gridsize*sizeof(double));
+          double *ybounds2D = (double*) Malloc(4*gridsize*sizeof(double));
+
+          grid_gen_xbounds2D(nlon, nlat, xbounds, xbounds2D);
+          grid_gen_ybounds2D(nlon, nlat, ybounds, ybounds2D);
+
+          Free(xbounds);
+          Free(ybounds);
+          grid->xbounds = xbounds2D;
+          grid->ybounds = ybounds2D;
+        }
+   }
+
+  if ( xvals ) Free(xvals);
+  if ( yvals ) Free(yvals);
+}
+
+
+int grid_from_name(const char *gridnameptr)
+{
+  const char *pline;
+  int gridID = CDI_UNDEFID;
+  griddes_t grid;
+  size_t len;
+  char *endptr;
+
+  char *gridname = strdup(gridnameptr);
+  strtolower(gridname);
+
+  gridInit(&grid);
+
+  if ( gridname[0] == 't' && gridname[1] == 'l' ) /* tl<RES>grid or tl<RES>spec */
+    {
+      pline = &gridname[2];
+      if ( isdigit((int) *pline) )
+	{
+	  grid.ntr = atoi(pline);
+	  while ( isdigit((int) *pline) ) pline++;
+	  if      ( cmpstrlen(pline, "grid", len) == 0 ) grid.type = GRID_GAUSSIAN;
+	  else if ( cmpstrlen(pline, "zon",  len) == 0 ) grid.type = GRID_GAUSSIAN;
+	  else if ( cmpstrlen(pline, "spec", len) == 0 ) grid.type = GRID_SPECTRAL;
+	  else if ( cmpstrlen(pline, "",     len) == 0 ) grid.type = GRID_SPECTRAL;
+      
+	  if ( pline[len] != 0 ) return gridID;
+
+	  if ( grid.type == GRID_GAUSSIAN )
+	    {
+	      grid.ysize = ntr_to_nlat_linear(grid.ntr);
+	      grid.np    = grid.ysize/2;
+	      if ( cmpstrlen(pline, "zon",  len) == 0 )
+		grid.xsize = 1;
+	      else
+		grid.xsize = nlat_to_nlon(grid.ysize);
+
+	      grid.def_xfirst = true;
+	      grid.def_yfirst = true;	      
+	    }
+	}
+    }
+  else if ( gridname[0] == 't' ) /* t<RES>grid or t<RES>spec */
+    {
+      pline = &gridname[1];
+      if ( isdigit((int) *pline) )
+	{
+	  grid.ntr = atoi(pline);
+	  while ( isdigit((int) *pline) ) pline++;
+	  if      ( cmpstrlen(pline, "grid", len) == 0 ) grid.type = GRID_GAUSSIAN;
+	  else if ( cmpstrlen(pline, "zon",  len) == 0 ) grid.type = GRID_GAUSSIAN;
+	  else if ( cmpstrlen(pline, "spec", len) == 0 ) grid.type = GRID_SPECTRAL;
+	  else if ( cmpstrlen(pline, "",     len) == 0 ) grid.type = GRID_SPECTRAL;
+     
+	  if ( pline[len] != 0 ) return gridID;
+
+	  if ( grid.type == GRID_GAUSSIAN )
+	    {
+	      grid.ysize = ntr_to_nlat(grid.ntr);
+	      grid.np    = grid.ysize/2;
+	      if ( cmpstrlen(pline, "zon",  len) == 0 )
+		grid.xsize = 1;
+	      else
+		grid.xsize = nlat_to_nlon(grid.ysize);
+
+	      grid.def_xfirst = true;
+	      grid.def_yfirst = true;	      
+	    }
+	}
+    }
+  else if ( gridname[0] == 'r' ) /* r<LON>x<LAT> */
+    {
+      pline = &gridname[1];
+      if ( isdigit((int) *pline) )
+	{
+	  grid.type = GRID_LONLAT;
+	  grid.xsize = atoi(pline);
+	  while ( isdigit((int) *pline) ) pline++;
+	  pline++;
+	  grid.ysize = atoi(pline);
+	  while ( isdigit((int) *pline) ) pline++;
+
+	  grid.def_xfirst = true;
+	  grid.def_yfirst = true;
+	}
+    }
+  else if ( gridname[0] == 'l' &&  gridname[1] == 'o' && gridname[2] == 'n' ) /* lon=<LON>_lat=<LAT> */
+    {
+      /* only one gridpoint */
+      pline = &gridname[3];
+      if ( *pline == '=' ) pline++;
+      if ( isdigit((int) *pline) || ispunct((int) *pline) || *pline == '-' )
+	{
+	  grid.type = GRID_LONLAT;
+	  grid.xsize = 1;
+	  grid.ysize = 1;
+	  grid.xvals = (double*) Malloc(sizeof(double));
+	  grid.yvals = (double*) Malloc(sizeof(double));
+	  grid.xvals[0] = atof(pline);
+	  while ( isdigit((int) *pline) || ispunct((int) *pline) || *pline == '-' ) pline++;
+	  if ( *pline == '_' ) pline++;
+	  if ( ! (pline[0] == 'l' &&  pline[1] == 'a' && pline[2] == 't') ) return gridID;
+	  pline += 3;
+	  if ( *pline == '=' ) pline++;
+	  if ( isdigit((int) *pline) || ispunct((int) *pline) || *pline == '-' )
+	    grid.yvals[0] = atof(pline);
+	  else
+	    return gridID;
+	}
+    }
+  else if ( gridname[0] == 'g' && gridname[1] == 'm' && gridname[2] == 'e' ) /* gme<NI> */
+    {
+      pline = &gridname[3];
+      if ( isdigit((int) *pline) )
+	{
+	  long ni = strtol(pline, &endptr, 10);
+	  if ( *endptr == 0 )
+	    {
+	      grid.type = GRID_GME;
+	      grid.ni   = ni;
+	      grid.nd   = 10;
+	      factorni(grid.ni, &grid.ni2, &grid.ni3);
+	      grid.size = (grid.ni+1)*(grid.ni+1)*10;
+	    }
+	}
+    }
+  else if ( gridname[0] == 'n' && gridname[1] == 'i' ) /* ni<NI> */
+    {
+      pline = &gridname[2];
+      if ( isdigit((int) *pline) )
+	{
+	  long ni = strtol(pline, &endptr, 10);
+	  if ( *endptr == 0 )
+	    {
+	      grid.type = GRID_GME;
+	      grid.ni   = ni;
+	      grid.nd   = 10;
+	      factorni(grid.ni, &grid.ni2, &grid.ni3);
+	      grid.size = (grid.ni+1)*(grid.ni+1)*10;
+	    }
+	}
+    }
+  else if ( gridname[0] == 'n' ) /* n<N> */
+    {
+      pline = &gridname[1];
+      if ( isdigit((int) *pline) )
+	{
+	  long np = strtol(pline, &endptr, 10);
+	  pline = endptr;
+
+	  if ( cmpstrlen(pline, "zon",  len) == 0 )
+	    {
+	      grid.xsize = 1;
+	      pline += 3;
+	    }
+	  else if ( *pline == 'b' )
+	    {
+	      grid.genBounds = true;
+	      pline++;
+	    }
+
+	  if ( *pline == 0 )
+	    {
+	      grid.type  = GRID_GAUSSIAN;
+	      grid.np    = np;
+	      grid.ysize = np*2;
+	      if ( !grid.xsize ) grid.xsize = nlat_to_nlon(grid.ysize);
+
+	      grid.def_xfirst = true;
+	      grid.def_yfirst = true;	      
+	    }
+	}
+    }
+  else if ( gridname[0] == 'g' && isdigit(gridname[1])) /* g<LON>x<LAT> or g<SIZE> */
+    {
+      pline = &gridname[1];
+      if ( isdigit((int) *pline) )
+	{
+	  grid.type = GRID_GENERIC;
+	  grid.xsize = atoi(pline);
+	  while ( isdigit((int) *pline) ) pline++;
+	  if ( *pline )
+	    {
+	      pline++;
+	      grid.ysize = atoi(pline);
+	      while ( isdigit((int) *pline) ) pline++;
+	    }
+	  else if ( grid.xsize == 1 )
+	    {
+	      grid.size  = 1;
+	      grid.xsize = 0;
+	    }
+	}
+    }
+  else if ( cmpstrlen(gridname, "germany", len) == 0 ) /* germany_Xdeg */
+    {
+      double lon1 =   5.6, lon2 = 15.2;
+      double lat1 =  47.1, lat2 = 55.1;
+      double dll = 0.1;
+
+      pline = &gridname[len];
+      gen_grid_lonlat(&grid, pline, dll, lon1, lon2, lat1, lat2);
+    }
+  else if ( cmpstrlen(gridname, "europe", len) == 0 ) /* europe_Xdeg */
+    {
+      double lon1 = -30, lon2 = 60;
+      double lat1 =  30, lat2 = 80;
+      double dll = 1;
+
+      pline = &gridname[len];
+      gen_grid_lonlat(&grid, pline, dll, lon1, lon2, lat1, lat2);
+    }
+  else if ( cmpstrlen(gridname, "africa", len) == 0 ) /* africa_Xdeg */
+    {
+      double lon1 = -20, lon2 = 60;
+      double lat1 = -40, lat2 = 40;
+      double dll = 1;
+
+      pline = &gridname[len];
+      gen_grid_lonlat(&grid, pline, dll, lon1, lon2, lat1, lat2);
+    }
+  else if ( cmpstrlen(gridname, "global", len) == 0 ) /* global_Xdeg */
+    {
+      double lon1 = -180, lon2 = 180;
+      double lat1 =  -90, lat2 =  90;
+      double dll = 1;
+
+      pline = &gridname[len];
+      gen_grid_lonlat(&grid, pline, dll, lon1, lon2, lat1, lat2);
+    }
+
+  if ( grid.type != -1 ) gridID = gridDefine(grid);
+
+  free(gridname);
+
+  return gridID;
+}
diff --git a/src/grid_gme.c b/src/grid_gme.c
index 0936d5e..d828d8f 100644
--- a/src/grid_gme.c
+++ b/src/grid_gme.c
@@ -32,13 +32,13 @@ struct polygon {
   struct geo boundary[6];
 };
 
-const double pid5   =   0.2*M_PI;
-const double pid180 = 180.0/M_PI;
+static const double pid5   =   0.2*M_PI;
+//const double pid180 = 180.0/M_PI;
 
-const int ispokes[12] = { 1,0,-1,-1,0,1,0,1,1,0,-1,-1,};
+static const int ispokes[12] = { 1,0,-1,-1,0,1,0,1,1,0,-1,-1,};
 
-const int pentagon = 5;
-const int hexagon  = 6;
+static const int pentagon = 5;
+static const int hexagon  = 6;
 
 /*****************************************************************************/
 
@@ -130,36 +130,32 @@ struct cart circum_center(struct cart *v0, struct cart *v1, struct cart *v2)
   struct cart e2;
   struct cart cu;
 
-  double *ptmp1;
-  double *ptmp2;
-  double *ptmp3;
+  double *ptmp1 = ((double *)e1.x);
+  double *ptmp2 = ((double *)v1->x);
+  double *ptmp3 = ((double *)v0->x);
 
-  int j;
-
-  ptmp1 = ((double *)e1.x);
-  ptmp2 = ((double *)v1->x);
-  ptmp3 = ((double *)v0->x);
-
-  for (j = 0; j < 3; j++) {
+  for ( int j = 0; j < 3; j++ )
     {
-      *ptmp1 = *ptmp2 - *ptmp3;
-      ptmp1++;
+      {
+        *ptmp1 = *ptmp2 - *ptmp3;
+        ptmp1++;
+      }
+      ptmp3++;
+      ptmp2++;
     }
-    ptmp3++;
-    ptmp2++;
-  }
   
   ptmp1 = ((double *)e2.x);
   ptmp2 = ((double *)v2->x);
   ptmp3 = ((double *)v0->x);
-  for (j = 0; j < 3; j++) {
-    { 
-      *ptmp1 = *ptmp2 - *ptmp3;
-      ptmp1++;
+  for ( int j = 0; j < 3; j++ )
+    {
+      { 
+        *ptmp1 = *ptmp2 - *ptmp3;
+        ptmp1++;
+      }
+      ptmp3++;
+      ptmp2++;
     }
-    ptmp3++;
-    ptmp2++;
-  }
 
   cu.x[0] = e1.x[1]*e2.x[2] - e1.x[2]*e2.x[1];
   cu.x[1] = e1.x[2]*e2.x[0] - e1.x[0]*e2.x[2];
@@ -171,13 +167,14 @@ struct cart circum_center(struct cart *v0, struct cart *v1, struct cart *v2)
 
   ptmp1 = ((double *)center.x);
   ptmp2 = ((double *)cu.x);
-  for (j = 0; j < 3; j++) {
+  for ( int j = 0; j < 3; j++ )
     {
-      *ptmp1 = *ptmp2/cnorm;
-      ptmp1++;
+      {
+        *ptmp1 = *ptmp2/cnorm;
+        ptmp1++;
+      }
+      ptmp2++;
     }
-    ptmp2++;
-  }
   
   return center;
 }
@@ -209,7 +206,6 @@ struct geo cc2gc(struct cart *x)
 
   double tln;
   double tlt;
-  double r;
 
   if ( !(fabs(x->x[0]) > 0.0) ) {
     if (x->x[1] >= 0.0) {
@@ -228,7 +224,7 @@ struct geo cc2gc(struct cart *x)
     }
   }
 
-  r = sqrt(x->x[0]*x->x[0] + x->x[1]*x->x[1]);
+  double r = sqrt(x->x[0]*x->x[0] + x->x[1]*x->x[1]);
 
   if ( !(fabs(r) > 0.0) ) {
     if (x->x[2] > 0.0) {
@@ -636,18 +632,17 @@ void tricntr(double *pxn,
              int kjd, int kni)
 {
   (void) knd;
-  int id1, id2, id3, ioffset;
   double r1, r2, r3;
 
-  int j, mi1, mi2;
+  int mi1, mi2;
   double zxnorm;
 
-  id1 = kig1e-kig1s+1;
-  id2 = id1*(kig2e-kig2s+1);
-  id3 = id2*3;
-  ioffset = -(id1+id2+id3);
+  int id1 = kig1e-kig1s+1;
+  int id2 = id1*(kig2e-kig2s+1);
+  int id3 = id2*3;
+  int ioffset = -(id1+id2+id3);
     
-  for (j = 1; j <= 2; ++j) 
+  for (int j = 1; j <= 2; ++j) 
     {
       mi1 = j*kni/3;
       mi2 = (j-1)*kni+1;
@@ -690,34 +685,30 @@ void gcpt(double *pxn,
           int ki1, int kj1, int ki2, int kj2, int ki, int kj)
 {
   (void) knd;
-  int id1, id2, id3, ioffset;
-  double r1, r2, r3;
-    
-  double zbeta, zalpha, zchord, ztheta;
     
   /* Calculate "zchord", the Cartesian distance between x1 and x2 */
 
-  id1 = kig1e-kig1s+1;
-  id2 = id1*(kig2e-kig2s+1);
-  id3 = id2*3;
-  ioffset = -(id1+id2+id3);
-
-  r1 = (pxn[ki2+id1*kj2+id2*1+id3*kjd+ioffset] 
-	-pxn[ki1+id1*kj1+id2*1+id3*kjd+ioffset]);
-  r2 = (pxn[ki2+id1*kj2+id2*2+id3*kjd+ioffset] 
-	-pxn[ki1+id1*kj1+id2*2+id3*kjd+ioffset]);
-  r3 = (pxn[ki2+id1*kj2+id2*3+id3*kjd+ioffset] 
-	-pxn[ki1+id1*kj1+id2*3+id3*kjd+ioffset]);
+  int id1 = kig1e-kig1s+1;
+  int id2 = id1*(kig2e-kig2s+1);
+  int id3 = id2*3;
+  int ioffset = -(id1+id2+id3);
+
+  double r1 = (pxn[ki2+id1*kj2+id2*1+id3*kjd+ioffset] 
+               -pxn[ki1+id1*kj1+id2*1+id3*kjd+ioffset]);
+  double r2 = (pxn[ki2+id1*kj2+id2*2+id3*kjd+ioffset] 
+               -pxn[ki1+id1*kj1+id2*2+id3*kjd+ioffset]);
+  double r3 = (pxn[ki2+id1*kj2+id2*3+id3*kjd+ioffset] 
+               -pxn[ki1+id1*kj1+id2*3+id3*kjd+ioffset]);
   
-  zchord = sqrt((r1*r1)+(r2*r2)+(r3*r3));
+  double zchord = sqrt((r1*r1)+(r2*r2)+(r3*r3));
     
   /* Calculate "ztheta", the great circle angle between x1 and x2 */
-  ztheta = 2.0*asin(zchord*0.5);
+  double ztheta = 2.0*asin(zchord*0.5);
     
   /* Calculate the weighting factors which follow from the condition */
   /* that x is a point on the unit-sphere, too. */
-  zbeta = sin(pgamma*ztheta)/sin(ztheta);
-  zalpha = sin((1.0-pgamma)*ztheta)/sin(ztheta);
+  double zbeta = sin(pgamma*ztheta)/sin(ztheta);
+  double zalpha = sin((1.0-pgamma)*ztheta)/sin(ztheta);
     
   /* Store the (x,y,z) coordinates of the point x into the array pxn */
   pxn[ki+id1*kj+id2*1+id3*kjd+ioffset] 
@@ -740,14 +731,12 @@ void glo_coor(double *pxn, double *prlon, double *prlat,
               int kig1s, int kig1e, int kig2s, int kig2e, int knd, 
               int kni2, int kni3)
 {
-  int id1, id2, id3, ioffset, joffset;
-
   double zsgn;
   int j1, j2;
-  double zrlon, zcosw, zsinw;
+  double zrlon;
   int jb, jd, ml, mm;
-  double zgamma, zw;
-  int mi1, mi2, ml2, ml3, mni;
+  double zgamma;
+  int mi1, mi2, ml2, ml3;
 
   int *mcosv;
 
@@ -764,18 +753,18 @@ void glo_coor(double *pxn, double *prlon, double *prlat,
       exit (-1);
     }
 
-  id1 = kig1e-kig1s+1;
-  id2 = id1*(kig2e-kig2s+1);
-  id3 = id2*3;
-  ioffset = -(id1+id2+id3);
-  joffset = -(id1+id2);
+  int id1 = kig1e-kig1s+1;
+  int id2 = id1*(kig2e-kig2s+1);
+  int id3 = id2*3;
+  int ioffset = -(id1+id2+id3);
+  int joffset = -(id1+id2);
 
   /* Compute angles associated with the icosahedron. */
 
-  zw = acos(1.0/(sin(pid5)*2.0))*2.0;
-  zcosw = cos(zw);
-  zsinw = sin(zw);
-  mni = pow_ii(2, kni2)*pow_ii(3, kni3);
+  double zw = acos(1.0/(sin(pid5)*2.0))*2.0;
+  double zcosw = cos(zw);
+  double zsinw = sin(zw);
+  int mni = pow_ii(2, kni2)*pow_ii(3, kni3);
   
   /*     Compute the local array mcosv, i.e. the meridian angle locations */
 
@@ -987,8 +976,6 @@ void glo_coor(double *pxn, double *prlon, double *prlat,
 static
 void initmask(int *mask, int ni, int nd)
 {
-  int jd;
-
   int tmp1, tmp2, /*tmp3, tmp4, tmp5,*/ tmp6, tmp7, tmp8, tmp9;
 
   int *ptmp1;
@@ -1034,7 +1021,7 @@ void initmask(int *mask, int ni, int nd)
     }
   }
 
-  for (jd = 1; jd <= 10; jd++) {
+  for (int jd = 1; jd <= 10; jd++) {
     switch (jd) {
     case 1:
       break;
@@ -1225,20 +1212,19 @@ void initmask(int *mask, int ni, int nd)
 
 void gme_grid_restore(double *p, int ni, int nd)
 {
-  int j, jd;
-  int tmp1, tmp2, tmp3, tmp4, tmp5;
+  int j;
 
   struct array pinfo;
 
   pinfo.rank = 3;
   pinfo.offset = 0;
   pinfo.dim[0].lower = 0;
-  tmp1 = ni+1;
+  int tmp1 = ni+1;
   if (tmp1 < 0) tmp1 = 0;
   pinfo.dim[0].extent = tmp1;
   pinfo.dim[0].mult = 1;
   pinfo.offset -= 0;
-  tmp2 = tmp1;
+  int tmp2 = tmp1;
   pinfo.dim[1].lower = 1;
   tmp1 = ni+1;
   if (tmp1 < 0) tmp1 = 0;
@@ -1252,11 +1238,11 @@ void gme_grid_restore(double *p, int ni, int nd)
   pinfo.dim[2].extent = tmp1;
   pinfo.dim[2].mult = tmp2;
   pinfo.offset -= pinfo.dim[2].mult;
-  tmp4 = pinfo.dim[1].mult;
-  tmp5 = pinfo.dim[2].mult;
-  tmp3 = pinfo.offset;
+  int tmp4 = pinfo.dim[1].mult;
+  int tmp5 = pinfo.dim[2].mult;
+  int tmp3 = pinfo.offset;
 
-  for (jd = 1; jd <= 10; jd++) {
+  for (int jd = 1; jd <= 10; jd++) {
     switch (jd) {
     case 1:
       break;
@@ -1299,11 +1285,6 @@ void gme_grid(int lbounds, int gridsize, double *rlon, double *rlat,
 	      double *blon, double *blat, int *imask,
               int ni, int nd, int ni2, int ni3)
 {
-  int im1s, im1e, im2s, im2e;
-  int i, j;
-  double *xn;
-  double *rlonx, *rlatx;
-
   /* check gridsize */
   if ( (ni+1)*(ni+1)*nd != gridsize )
     {
@@ -1316,14 +1297,14 @@ void gme_grid(int lbounds, int gridsize, double *rlon, double *rlat,
       exit (-1);
     }
 
-  xn    = (double*) Malloc(gridsize*3*sizeof(double));
-  rlonx = (double*) Malloc((ni+3)*(ni+3)*nd*sizeof(double));
-  rlatx = (double*) Malloc((ni+3)*(ni+3)*nd*sizeof(double));
+  double *xn    = (double*) Malloc(gridsize*3*sizeof(double));
+  double *rlonx = (double*) Malloc((ni+3)*(ni+3)*nd*sizeof(double));
+  double *rlatx = (double*) Malloc((ni+3)*(ni+3)*nd*sizeof(double));
 
-  im1s = 0;
-  im1e = ni;
-  im2s = 1;
-  im2e = ni+1;
+  int im1s = 0;
+  int im1e = ni;
+  int im2s = 1;
+  int im2e = ni+1;
 
   glo_coor(xn, rlon, rlat, im1s, im1e, im2s, im2e, nd, ni2, ni3);
 
@@ -1333,18 +1314,16 @@ void gme_grid(int lbounds, int gridsize, double *rlon, double *rlat,
   initmask(imask,ni,nd);
 
   if ( lbounds )
-    {
-      struct polygon *poly;
-      
-      poly  = (struct polygon*) Malloc((ni+1)*(ni+1)*nd*sizeof(struct polygon));
+    {      
+      struct polygon *poly = (struct polygon*) Malloc((ni+1)*(ni+1)*nd*sizeof(struct polygon));
 
       neighbours(rlonx,rlatx,im1s-1,im1e+1,im2s-1,im2e+1,nd, poly,im1s,im1e,im2s,im2e,nd);
 
       boundary(poly,im1s,im1e,im2s,im2e,nd);
 
-      for ( i = 0; i < gridsize; i++ )
+      for ( int i = 0; i < gridsize; i++ )
 	{
-	  for ( j = 0; j < poly[i].type; j++ )
+	  for ( int j = 0; j < poly[i].type; j++ )
 	    {
 	      blon[i*6+j] = poly[i].boundary[j].lon;
 	      blat[i*6+j] = poly[i].boundary[j].lat;
diff --git a/src/grid_print.c b/src/grid_print.c
new file mode 100644
index 0000000..f6a6fb2
--- /dev/null
+++ b/src/grid_print.c
@@ -0,0 +1,422 @@
+#include <cdi.h>
+#include "cdi_uuid.h"
+#include "cdo_int.h"
+
+static
+void printDblsPrefixAutoBrk(FILE *fp, int dig, const char prefix[], int nbyte0, size_t n, const double vals[])
+{
+  fputs(prefix, fp);
+  int nbyte = nbyte0;
+  for ( size_t i = 0; i < n; i++ )
+    {
+      if ( nbyte > 80 )
+        {
+          fprintf(fp, "\n%*s", nbyte0, "");
+          nbyte = nbyte0;
+        }
+      nbyte += fprintf(fp, "%.*g ", dig, vals[i]);
+    }
+  fputs("\n", fp);
+}
+
+static
+void printIntsPrefixAutoBrk(FILE *fp, const char prefix[], int nbyte0, size_t n, const int vals[])
+{
+  fputs(prefix, fp);
+  int nbyte = nbyte0;
+  for ( size_t i = 0; i < n; i++ )
+    {
+      if ( nbyte > 80 )
+        {
+          fprintf(fp, "\n%*s", nbyte0, "");
+          nbyte = nbyte0;
+        }
+      nbyte += fprintf(fp, "%d ", vals[i]);
+    }
+  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);
+  for ( size_t i = 0; i < n; i++ )
+    {
+      if ( i > 0 ) 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);
+}
+
+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++ )
+    {
+      if ( nbyte > 80 )
+        {
+          fprintf(fp, "\n%*s", (int)nbyte0, "");
+          nbyte = nbyte0;
+        }
+      nbyte += (size_t)fprintf(fp, "%d ", mask[i]);
+    }
+  fputs("\n", fp);
+}
+
+static inline
+void *resizeBuffer(void **buf, size_t *bufSize, size_t reqSize)
+{
+  if (reqSize > *bufSize)
+    {
+      *buf = Realloc(*buf, reqSize);
+      *bufSize = reqSize;
+    }
+  return *buf;
+}
+
+static
+void grid_print_attributes(FILE *fp, int gridID)
+{
+  int cdiID = gridID;
+  int varID = CDI_GLOBAL;
+  int atttype, attlen;
+  char attname[CDI_MAX_NAME+1];
+  void *attBuf = NULL;
+  size_t attBufSize = 0;
+  char fltstr[128];
+
+  int natts;
+  cdiInqNatts(cdiID, varID, &natts);
+
+  for ( int iatt = 0; iatt < natts; ++iatt )
+    {
+      cdiInqAtt(cdiID, varID, iatt, attname, &atttype, &attlen);
+
+      if ( attlen == 0 ) continue;
+
+      if ( strcmp(attname, "grid_mapping_name") == 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, "%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]);
+          fprintf(fp, "%s =", 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);
+          cdiInqAttFlt(cdiID, varID, attname, attlen, attflt);
+          fprintf(fp, "%s =", attname);
+          if ( atttype == CDI_DATATYPE_FLT32 )
+            for ( int i = 0; i < attlen; ++i ) fprintf(fp, " %sf", double_to_attstr(CDO_flt_digits, fltstr, sizeof(fltstr), attflt[i]));
+          else
+            for ( int i = 0; i < attlen; ++i ) fprintf(fp, " %s", double_to_attstr(CDO_dbl_digits, fltstr, sizeof(fltstr), attflt[i]));
+          fprintf(fp, "\n");
+        }
+    }
+
+  Free(attBuf);
+}
+
+static
+void grid_print_kernel(int gridID, int opt, FILE *fp)
+{
+  int 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 nxbounds = (size_t) gridInqXbounds(gridID, NULL);
+  size_t nybounds = (size_t) gridInqYbounds(gridID, NULL);
+
+  int type     = gridInqType(gridID);
+  int gridsize = gridInqSize(gridID);
+  int xsize    = gridInqXsize(gridID);
+  int ysize    = gridInqYsize(gridID);
+  int nvertex  = gridInqNvertex(gridID);
+  int prec     = gridInqPrec(gridID);
+
+  int dig = (prec == CDI_DATATYPE_FLT64) ? CDO_dbl_digits : CDO_flt_digits;
+
+  fprintf(fp, "gridtype  = %s\n" "gridsize  = %d\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 ( nxvals > 0 )
+        {
+          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 )
+        {
+          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:
+      {
+        if ( type == GRID_GAUSSIAN || type == GRID_GAUSSIAN_REDUCED ) fprintf(fp, "np        = %d\n", gridInqNP(gridID));
+
+	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 )
+          {
+            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);
+              }
+
+            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, (int)sizeof(prefix)-1, nxvals, xvals);
+                Free(xvals);
+	      }
+	  }
+
+	if ( nxbounds )
+	  {
+            double *xbounds = (double*) Malloc(nxbounds*sizeof(double));
+            gridInqXbounds(gridID, xbounds);
+            static const char prefix[] = "xbounds   = ";
+            printBounds(fp, dig, prefix, sizeof(prefix)-1, xdim, 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, (int)sizeof(prefix)-1, nyvals, yvals);
+                Free(yvals);
+	      }
+	  }
+
+	if ( nybounds )
+	  {
+            double *ybounds = (double*) Malloc(nybounds*sizeof(double));
+            gridInqYbounds(gridID, ybounds);
+            static const char prefix[] = "ybounds   = ";
+            printBounds(fp, dig, prefix, sizeof(prefix)-1, ydim, nvertex, ybounds);
+            Free(ybounds);
+	  }
+
+	if ( gridHasArea(gridID) )
+	  {
+            double *area = (double*) Malloc(gridsize*sizeof(double));
+            gridInqArea(gridID, area);
+            static const char prefix[] = "area      = ";
+            printDblsPrefixAutoBrk(fp, dig, prefix, (int)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));
+            gridInqRowlon(gridID, rowlon);
+            printIntsPrefixAutoBrk(fp, prefix, (int)sizeof(prefix)-1,
+                                   (size_t)(ysize > 0 ? ysize : 0), rowlon);
+            Free(rowlon);
+          }
+
+        if ( type == GRID_PROJECTION )
+          {
+            attstr[0] = 0; cdiGridInqKeyStr(gridID, CDI_KEY_MAPPING, CDI_MAX_NAME, attstr);
+            if ( attstr[0] ) fprintf(fp, "grid_mapping = %s\n", attstr);
+            attstr[0] = 0; cdiGridInqKeyStr(gridID, CDI_KEY_MAPNAME, CDI_MAX_NAME, attstr);
+            if ( attstr[0] ) fprintf(fp, "grid_mapping_name = %s\n", attstr);
+            grid_print_attributes(fp, gridID);
+          }
+
+	break;
+      }
+    case GRID_LCC:
+      {
+	double originLon = 0, originLat = 0, lonParY = 0, lat1 = 0, lat2 = 0, xincm = 0, yincm = 0;
+	int projflag = 0, scanflag = 0;
+	gridInqParamLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
+                        &projflag, &scanflag);
+
+	fprintf(fp,
+                "originLon = %.*g\n"
+                "originLat = %.*g\n"
+                "lonParY   = %.*g\n"
+                "lat1      = %.*g\n"
+                "lat2      = %.*g\n"
+                "xinc      = %.*g\n"
+                "yinc      = %.*g\n"
+                "projection = %s\n",
+                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", 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;
+      }
+    }
+
+  unsigned char uuid[CDI_UUID_SIZE];
+  gridInqUUID(gridID, uuid);
+  if ( !cdiUUIDIsNull(uuid) )
+    {
+      char uuidStr[37];
+      cdiUUID2Str(uuid, uuidStr);
+      if ( uuidStr[0] != 0 && strlen(uuidStr) == 36 )
+        fprintf(fp, "uuid      = %s\n", uuidStr);
+    }
+
+  if ( gridInqMask(gridID, NULL) )
+    {
+      int *mask = (gridsize>0) ? (int*) Malloc((size_t)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);
+      if ( mask ) Free(mask);
+    }
+
+  int projID = gridInqProj(gridID);
+  if ( projID != CDI_UNDEFID && gridInqType(projID) == GRID_PROJECTION )
+    grid_print_kernel(projID, opt, fp);
+}
+
+
+void cdo_print_grid(int gridID, int opt)
+{
+  grid_print_kernel(gridID, opt, stdout);
+}
diff --git a/src/grid_read.c b/src/grid_read.c
new file mode 100644
index 0000000..eb1263d
--- /dev/null
+++ b/src/grid_read.c
@@ -0,0 +1,335 @@
+/*
+  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 <cdi.h>
+#include "cdi_uuid.h"
+#include "cdo_int.h"
+#include "griddes.h"
+
+
+#define MAX_LINE_LEN 65536
+
+void cdo_read_field(const char *name, char *pline, int size, double *field, int *lineno, FILE *fp, const char *dname)
+{
+  char line[MAX_LINE_LEN];
+  double fval;
+  char *endptr;
+  for ( int i = 0; i < size; i++ )
+    {
+      endptr = pline;
+      fval = strtod(pline, &endptr);
+      if ( pline == endptr )
+        {
+          (*lineno)++;
+          if ( ! readline(fp, line, MAX_LINE_LEN) )
+            cdoAbort("Incomplete command: >%s< (line: %d file: %s)", name, *lineno, dname);
+          pline = line;
+          fval = strtod(pline, &endptr);
+        }
+      field[i] = fval;
+      pline = endptr;
+    }
+}
+
+
+typedef struct {
+  keyValues_t *kv;
+  bool isValid;
+} kvmap_t;
+
+static
+void grid_read_data(size_t ikv, size_t nkv, kvmap_t *kvmap, griddes_t *grid, size_t *iproj, size_t *igmap, const char *dname)
+{
+  char uuidStr[256];
+
+  for ( size_t ik = ikv; ik < nkv; ++ik )
+    {
+      if ( !kvmap[ik].isValid ) continue;
+
+      keyValues_t *kv = kvmap[ik].kv;
+      const char *key = kv->key;
+      size_t nvalues = kv->nvalues;
+      const char *value = (kv->nvalues > 0) ? kv->values[0] : NULL;
+      //bool lv1 = (kv->nvalues == 1);
+
+      // printf("%s = ", key); if ( value  ) printf("%s", kv->value); printf("\n");
+
+      if ( STR_IS_EQ(key, "gridtype") )
+        {
+          const char *gridtype = parameter2word(value);
+
+          if ( grid->type != CDI_UNDEFID )
+            {
+              if ( STR_IS_EQ(gridtype, "projection") ) *iproj = ik;
+              return;
+            }
+
+          if      ( STR_IS_EQ(gridtype, "lonlat") )       grid->type = GRID_LONLAT;
+          else if ( STR_IS_EQ(gridtype, "latlon") )       grid->type = GRID_LONLAT;
+          else if ( STR_IS_EQ(gridtype, "gaussian") )     grid->type = GRID_GAUSSIAN;
+          else if ( STR_IS_EQ(gridtype, "curvilinear") )  grid->type = GRID_CURVILINEAR;
+          else if ( STR_IS_EQ(gridtype, "unstructured") ) grid->type = GRID_UNSTRUCTURED;
+          else if ( STR_IS_EQ(gridtype, "cell") )         grid->type = GRID_UNSTRUCTURED;
+          else if ( STR_IS_EQ(gridtype, "spectral") )     grid->type = GRID_SPECTRAL;
+          else if ( STR_IS_EQ(gridtype, "gme") )          grid->type = GRID_GME;
+          else if ( STR_IS_EQ(gridtype, "lcc") )          grid->type = GRID_LCC;
+          else if ( STR_IS_EQ(gridtype, "lambert") )      grid->type = GRID_LCC;
+          else if ( STR_IS_EQ(gridtype, "projection") )   grid->type = GRID_PROJECTION;
+          else if ( STR_IS_EQ(gridtype, "generic") )      grid->type = GRID_GENERIC;
+	  else cdoAbort("Invalid gridtype : %s (grid description file: %s)", gridtype, dname);
+            
+          if ( grid->type == GRID_LONLAT || grid->type == GRID_GAUSSIAN ) grid->nvertex = 2;
+          else if ( grid->type == GRID_CURVILINEAR ) grid->nvertex = 4;
+        }
+      else if ( STR_IS_EQ(key, "gridprec") )       grid->prec = parameter2int(value);
+      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, "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);
+      else if ( STR_IS_EQ(key, "nvertex") )        grid->nvertex = parameter2int(value);
+      else if ( STR_IS_EQ(key, "ni") )           { grid->ni = parameter2int(value); grid->nd = 10; }
+      else if ( STR_IS_EQ(key, "position") )       grid->position = parameter2int(value);
+      else if ( STR_IS_EQ(key, "number") )         grid->number = parameter2int(value);
+      else if ( STR_IS_EQ(key, "xname") )     strcpy(grid->xname, parameter2word(value));
+      else if ( STR_IS_EQ(key, "yname") )     strcpy(grid->yname, parameter2word(value));
+      else if ( STR_IS_EQ(key, "xdimname") )  strcpy(grid->xdimname, parameter2word(value));
+      else if ( STR_IS_EQ(key, "ydimname") )  strcpy(grid->ydimname, parameter2word(value));
+      else if ( STR_IS_EQ(key, "vdimname") )  strcpy(grid->vdimname, parameter2word(value));
+      else if ( STR_IS_EQ(key, "xlongname") ) strcpy(grid->xlongname, value);
+      else if ( STR_IS_EQ(key, "ylongname") ) strcpy(grid->ylongname, value);
+      else if ( STR_IS_EQ(key, "xunits") )    strcpy(grid->xunits, value);
+      else if ( STR_IS_EQ(key, "yunits") )    strcpy(grid->yunits, value);
+      else if ( STR_IS_EQ(key, "path") )      strcpy(grid->path, value);
+      else if ( STR_IS_EQ(key, "uuid") )      { strcpy(uuidStr, value); cdiStr2UUID(uuidStr, grid->uuid); }
+      else if ( STR_IS_EQ(key, "xfirst") )    { grid->xfirst = parameter2double(value); grid->def_xfirst = true; }
+      else if ( STR_IS_EQ(key, "yfirst") )    { grid->yfirst = parameter2double(value); grid->def_yfirst = true; }
+      else if ( STR_IS_EQ(key, "xlast") )     { grid->xlast = parameter2double(value); grid->def_xlast = true; }
+      else if ( STR_IS_EQ(key, "ylast") )     { grid->ylast = parameter2double(value); grid->def_ylast = true; }
+      else if ( STR_IS_EQ(key, "xinc") )      { grid->xinc = parameter2double(value); grid->def_xinc = true; }
+      else if ( STR_IS_EQ(key, "yinc") )      { grid->yinc = parameter2double(value); grid->def_yinc = true; }
+      else if ( STR_IS_EQ(key, "originLon") ) { grid->originLon = parameter2double(value); grid->def_originLon = true; }
+      else if ( STR_IS_EQ(key, "originLat") ) { grid->originLat = parameter2double(value); grid->def_originLat = true; }
+      else if ( STR_IS_EQ(key, "lonParY") )   { grid->lonParY = parameter2double(value); grid->def_lonParY = true; }
+      else if ( STR_IS_EQ(key, "lat1") )      { grid->lat1 = parameter2double(value); grid->def_lat1 = true; }
+      else if ( STR_IS_EQ(key, "lat2") )      { grid->lat2 = parameter2double(value); grid->def_lat2 = true; }
+      else if ( STR_IS_EQ(key, "lat_0") )     { grid->lat_0 = parameter2double(value); grid->def_lat_0 = true; }
+      else if ( STR_IS_EQ(key, "lat_1") )     { grid->lat_1 = parameter2double(value); grid->def_lat_1 = true; }
+      else if ( STR_IS_EQ(key, "lat_2") )     { grid->lat_2 = parameter2double(value); grid->def_lat_2 = true; }
+      else if ( STR_IS_EQ(key, "a") )         grid->a = parameter2double(value);
+      else if ( STR_IS_EQ(key, "projection") )
+        {
+          if      ( STR_IS_EQ(value, "north") ) { grid->projflag = 0;    grid->scanflag = 64; }
+	  else if ( STR_IS_EQ(value, "south") ) { grid->projflag = 128;  grid->scanflag = 64; }
+	  else cdoAbort("Invalid projection : %s (grid description file: %s)", value, dname);
+        }
+      else if ( STR_IS_EQ(key, "xvals") )
+        {
+          size_t size = (grid->type == GRID_CURVILINEAR || grid->type == GRID_UNSTRUCTURED) ? grid->size : grid->xsize;
+          if ( size == 0 ) cdoAbort("xsize or gridsize undefined (grid description file: %s)!", dname);
+          if ( size != nvalues )
+            cdoAbort("Number of xvals=%zu and size of xvals=%zu differ (grid description file: %s)!", nvalues, size, dname);
+
+          grid->xvals = (double*) Malloc(size*sizeof(double));
+          for ( size_t i = 0; i < size; ++i ) grid->xvals[i] = parameter2double(kv->values[i]);
+        }
+      else if ( STR_IS_EQ(key, "yvals") )
+        {
+          size_t size = (grid->type == GRID_CURVILINEAR || grid->type == GRID_UNSTRUCTURED) ? grid->size : grid->ysize;
+          if ( size == 0 ) cdoAbort("ysize or gridsize undefined (grid description file: %s)!", dname);
+          if ( size != nvalues )
+            cdoAbort("Number of yvals=%zu and size of yvals=%zu differ (grid description file: %s)!", nvalues, size, dname);
+
+          grid->yvals = (double*) Malloc(size*sizeof(double));
+          for ( size_t i = 0; i < size; ++i ) grid->yvals[i] = parameter2double(kv->values[i]);
+        }
+      else if ( STR_IS_EQ(key, "xbounds") )
+        {
+          size_t size = (grid->type == GRID_CURVILINEAR || grid->type == GRID_UNSTRUCTURED) ? grid->size : grid->xsize;
+          if ( size == 0 ) cdoAbort("xsize or gridsize undefined (grid description file: %s)!", dname);
+          if ( grid->nvertex == 0 ) cdoAbort("nvertex undefined (grid description file: %s)!", dname);
+          if ( grid->nvertex*size != nvalues )
+            cdoAbort("Number of xbounds=%zu and size of xbounds=%zu differ (grid description file: %s)!", nvalues, grid->nvertex*size, dname);
+
+          grid->xbounds = (double*) Malloc(grid->nvertex*size*sizeof(double));
+          for ( size_t i = 0; i < grid->nvertex*size; ++i ) grid->xbounds[i] = parameter2double(kv->values[i]);
+        }
+      else if ( STR_IS_EQ(key, "ybounds") )
+        {
+          size_t size = (grid->type == GRID_CURVILINEAR || grid->type == GRID_UNSTRUCTURED) ? grid->size : grid->ysize;
+          if ( size == 0 ) cdoAbort("ysize or gridsize undefined (grid description file: %s)!", dname);
+          if ( grid->nvertex == 0 ) cdoAbort("nvertex undefined (grid description file: %s)!", dname);
+          if ( grid->nvertex*size != nvalues )
+            cdoAbort("Number of ybounds=%zu and size of ybounds=%zu differ (grid description file: %s)!", nvalues, grid->nvertex*size, dname);
+
+          grid->ybounds = (double*) Malloc(grid->nvertex*size*sizeof(double));
+          for ( size_t i = 0; i < grid->nvertex*size; ++i ) grid->ybounds[i] = parameter2double(kv->values[i]);
+        }
+      else if ( STR_IS_EQ(key, "gridlatlon") )
+        {
+	  if ( grid->size == 0 ) grid->size = grid->xsize * grid->ysize;
+          if ( grid->size == 0 ) cdoAbort("gridsize undefined (grid description file: %s)!", dname);
+          if ( (size_t)grid->size*2 != nvalues )
+            cdoAbort("Number of gridlonlat values=%zu and size of grid=%zu differ (grid description file: %s)!", nvalues, grid->size*2, dname);
+	  grid->xvals = (double*) Malloc(grid->size*sizeof(double));
+	  grid->yvals = (double*) Malloc(grid->size*sizeof(double));
+          for ( size_t i = 0; i < (size_t)grid->size; ++i )
+            {
+	      grid->yvals[i] = parameter2double(kv->values[2*i]);
+	      grid->xvals[i] = parameter2double(kv->values[2*i+1]);
+            }
+        }
+      else if ( STR_IS_EQ(key, "mask") )
+        {
+          size_t size = grid->size;
+          if ( grid->size == 0 ) cdoAbort("gridsize undefined (grid description file: %s)!", dname);
+          if ( size != nvalues )
+            cdoAbort("Number of mask values=%zu and size of grid=%zu differ (grid description file: %s)!", nvalues, size, dname);
+          grid->mask = (int*) Malloc(size*sizeof(int));
+          size_t count = 0;
+          for ( size_t i = 0; i < size; ++i )
+            {
+              grid->mask[i] = parameter2int(kv->values[i]);
+              if ( grid->mask[i] == 1 ) count++;
+            }
+          if ( count == size ) { Free(grid->mask); grid->mask = NULL; }
+        }
+      else if ( STR_IS_EQ(key, "grid_mapping_name") ) { *igmap = ik; break; }
+      else if ( STR_IS_EQ(key, "grid_mapping") ) { *igmap = ik; break; }
+      else cdoAbort("Invalid parameter : >%s< (grid description file: %s)", key, dname);
+    }
+}
+
+static
+void grid_read_mapping(size_t igmap, size_t nkv, kvmap_t *kvmap, int gridID)
+{
+  for ( size_t ik = igmap; ik < nkv; ++ik )
+    {
+      if ( !kvmap[ik].isValid ) continue;
+
+      keyValues_t *kv = kvmap[ik].kv;
+      const char *key = kv->key;
+      size_t nvalues = kv->nvalues;
+      const char *value = (kv->nvalues > 0) ? kv->values[0] : NULL;
+      // bool lv1 = (kv->nvalues == 1);
+
+      // printf("%s = ", key); if ( value  ) printf("%s", kv->value); printf("\n");
+
+      if ( STR_IS_EQ(key, "grid_mapping") )
+        {
+          cdiGridDefKeyStr(gridID, CDI_KEY_MAPPING, (int)strlen(value)+1, value);
+          continue;
+        }
+
+      if ( STR_IS_EQ(key, "grid_mapping_name") )
+        cdiGridDefKeyStr(gridID, CDI_KEY_MAPNAME, (int)strlen(value)+1, value);
+
+      int dtype = literals_find_datatype(nvalues, kv->values);
+
+      if ( dtype == CDI_DATATYPE_INT8 || dtype == CDI_DATATYPE_INT16 || dtype == CDI_DATATYPE_INT32 )
+        {
+          int *ivals = (int*) Malloc(nvalues*sizeof(int));
+          for ( size_t i = 0; i < nvalues; ++i ) ivals[i] = literal_to_int(kv->values[i]);
+          cdiDefAttInt(gridID, CDI_GLOBAL, key, dtype, nvalues, ivals);
+          Free(ivals);
+        }
+      else if ( dtype == CDI_DATATYPE_FLT32 || dtype == CDI_DATATYPE_FLT64 )
+        {
+          double *dvals = (double*) Malloc(nvalues*sizeof(double));
+          for ( size_t i = 0; i < nvalues; ++i ) dvals[i] = literal_to_double(kv->values[i]);
+          cdiDefAttFlt(gridID, CDI_GLOBAL, key, dtype, nvalues, dvals);
+          Free(dvals);
+        }
+      else
+        {
+          int len = (value && *value) ? (int) strlen(value) : 0;
+          cdiDefAttTxt(gridID, CDI_GLOBAL, key, len, value);
+        }
+    }
+}
+
+
+int grid_read(FILE *gfp, const char *dname)
+{
+  list_t *pmlist = namelist_to_pmlist(gfp, dname);
+  if ( pmlist == NULL ) return -1;
+  list_t *kvlist = *(list_t **)pmlist->head->data;
+  if ( kvlist == NULL ) return -1;
+
+  size_t nkv = list_size(kvlist);
+  if ( nkv == 0 ) return -1;
+  kvmap_t *kvmap = (kvmap_t*) Malloc(nkv*sizeof(kvmap_t));
+  for ( size_t i = 0; i < nkv; ++i ) kvmap[i].isValid = false;
+
+  size_t ik = 0;
+  for ( listNode_t *kvnode = kvlist->head; kvnode; kvnode = kvnode->next )
+    {
+      keyValues_t *kv = *(keyValues_t **)kvnode->data;
+      if ( ik == 0 && !STR_IS_EQ(kv->key, "gridtype") )
+        cdoAbort("First grid description parameter must be >gridtype< (found: %s)!", kv->key);
+
+      if ( kv->nvalues == 0 )
+        {
+          cdoWarning("Grid description parameter %s has no values, skipped!", kv->key);
+        }
+      else
+        {
+          kvmap[ik].isValid = true;
+          kvmap[ik].kv = kv;
+        }
+      ik++;
+    }
+
+  griddes_t grid;
+  gridInit(&grid);
+
+  size_t iproj = 0;
+  size_t igmap = 0;
+  grid_read_data(0, nkv, kvmap, &grid, &iproj, &igmap, dname);
+
+  int gridID = (grid.type == CDI_UNDEFID) ? CDI_UNDEFID : gridDefine(grid);
+
+  if ( gridID != CDI_UNDEFID )
+    {
+      int gridprojID = gridID;
+
+      if ( iproj > 0 )
+        {
+          griddes_t proj;
+          gridInit(&proj);
+          grid_read_data(iproj, nkv, kvmap, &proj, &iproj, &igmap, dname);
+
+          int projID = (proj.type == CDI_UNDEFID) ? CDI_UNDEFID : gridDefine(proj);
+          if ( projID != CDI_UNDEFID )
+            {
+              gridDefProj(gridID, projID);
+              gridprojID = projID;
+            }
+        }
+
+      if ( igmap > 0 ) grid_read_mapping(igmap, nkv, kvmap, gridprojID);
+    }
+
+  list_destroy(pmlist);
+
+  Free(kvmap);
+
+  return gridID;
+}
diff --git a/src/grid_read_pingo.c b/src/grid_read_pingo.c
new file mode 100644
index 0000000..035649a
--- /dev/null
+++ b/src/grid_read_pingo.c
@@ -0,0 +1,192 @@
+/*
+  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 <cdi.h>
+#include "cdo_int.h"
+#include "grid.h"
+#include "griddes.h"
+
+
+static
+void skip_nondigit_lines(FILE *gfp)
+{
+  int c;
+
+  if ( feof(gfp) ) return;
+
+  while (1)
+    {
+      do
+	c = fgetc(gfp);
+      while ( (isspace(c) || c == ',') && c != EOF );
+
+      if ( c == EOF || isdigit (c) || c == '.' || c == '+' || c == '-' ) break;
+      else
+	while ( c != '\n' && c != EOF )
+	  c = fgetc(gfp);
+    }
+
+  ungetc(c, gfp);
+}
+
+static
+int input_ival(FILE *gfp, int *ival)
+{
+  skip_nondigit_lines(gfp);
+
+  if ( feof(gfp) ) return 0;
+
+  *ival = 0;
+  int read_items = fscanf(gfp, "%d", ival);
+
+  return read_items;
+}
+
+
+int input_darray(FILE *gfp, int n_values, double *array)
+{
+  if ( n_values <= 0 ) return 0;
+
+  int read_items = 0;
+  for ( int i = 0; i < n_values; i++ )
+    {
+      skip_nondigit_lines(gfp);
+
+      if ( feof(gfp) ) break;
+
+      read_items += fscanf(gfp, "%lg", &array[i]);
+
+      if ( feof(gfp) ) break;
+    }
+
+  return read_items;
+}
+
+
+int grid_read_pingo(FILE *gfp, const char *dname)
+{
+  UNUSED(dname);
+  int gridID = -1;
+  int i;
+
+  griddes_t grid;
+  gridInit(&grid);
+
+  int nlon, nlat;
+  if ( ! input_ival(gfp, &nlon) ) return gridID;
+  if ( ! input_ival(gfp, &nlat) ) return gridID;
+
+  if ( nlon > 0 && nlon < 9999 && nlat > 0 && nlat < 9999 )
+    {
+      grid.xsize = nlon;
+      grid.ysize = nlat;
+
+      grid.xvals = (double*) Malloc(grid.xsize*sizeof(double));
+      grid.yvals = (double*) Malloc(grid.ysize*sizeof(double));
+
+      if ( ! input_ival(gfp, &nlon) ) return gridID;
+      if ( nlon == 2 )
+	{
+	  if ( input_darray(gfp, 2, grid.xvals) != 2 ) return gridID;
+	  grid.xvals[1] -= 360 * floor((grid.xvals[1] - grid.xvals[0]) / 360);
+
+	  if ( grid.xsize > 1 )
+	    if ( IS_EQUAL(grid.xvals[0], grid.xvals[1]) )
+	      grid.xvals[1] += 360;
+
+	  for ( i = 0; i < (int)grid.xsize; i++ )
+	    grid.xvals[i] = grid.xvals[0] + i*(grid.xvals[1] - grid.xvals[0]);
+	}
+      else if ( nlon == (int)grid.xsize )
+	{
+	  if ( input_darray(gfp, nlon, grid.xvals) != nlon ) return gridID;
+	  for ( i = 0; i < nlon - 1; i++ )
+	    if ( grid.xvals[i+1] <= grid.xvals[i] ) break;
+
+	  for ( i++; i < nlon; i++ )
+	    {
+	      grid.xvals[i] += 360;
+	      if ( i < nlon - 1 && grid.xvals[i+1] + 360 <= grid.xvals[i] )
+		{
+		  cdoPrint("Longitudes are not in ascending order!");
+		  return gridID;
+		}
+	    }
+	}
+      else
+	return gridID;
+
+      if ( ! input_ival(gfp, &nlat) ) return gridID;
+      if ( nlat == 2 )
+	{
+	  if ( input_darray(gfp, 2, grid.yvals) != 2 ) return gridID;
+	  for ( i = 0; i < (int)grid.ysize; i++ )
+	    grid.yvals[i] = grid.yvals[0] + i*(grid.yvals[1] - grid.yvals[0]);
+	}
+      else if ( nlat == (int)grid.ysize )
+	{
+	  if ( input_darray(gfp, nlat, grid.yvals) != nlat ) return gridID;
+	}
+      else
+	return gridID;
+
+      if ( grid.yvals[0]      >  90.001  || 
+	   grid.yvals[nlat-1] >  90.001  || 
+	   grid.yvals[0]      < -90.001  || 
+	   grid.yvals[nlat-1] < -90.001 )
+	{
+	  cdoPrint("Latitudes must be between 90 and -90!");
+	  return gridID;
+	}
+
+      for ( i = 0; i < nlat - 1; i++ )
+	if ( IS_EQUAL(grid.yvals[i+1], grid.yvals[i]) || (i < nlat - 2 &&
+	    ((grid.yvals[i+1] > grid.yvals[i]) != (grid.yvals[i+2] > grid.yvals[i+1]))) )
+	  {
+	    cdoPrint("Latitudes must be in descending or ascending order!");
+	    return gridID;
+	  }
+		    
+      bool lgauss = false;
+      if ( nlat > 2 ) /* check if gaussian */
+	{
+	  double *yvals, *yw;
+	  yvals = (double*) Malloc(grid.ysize*sizeof(double));
+	  yw    = (double*) Malloc(grid.ysize*sizeof(double));
+	  gaussaw(yvals, yw, grid.ysize);
+	  Free(yw);
+	  for ( i = 0; i < (int) grid.ysize; i++ )
+	    yvals[i] = asin(yvals[i])*RAD2DEG;
+
+	  for ( i = 0; i < (int) grid.ysize; i++ )
+	    if ( fabs(yvals[i] - grid.yvals[i]) > ((yvals[0] - yvals[1])/500) ) break;
+		      
+	  if ( i == (int) grid.ysize ) lgauss = true;
+
+	  Free(yvals);
+	}
+
+      if ( lgauss )
+	grid.type = GRID_GAUSSIAN;
+      else
+	grid.type = GRID_LONLAT;
+    }
+  
+  if ( grid.type != CDI_UNDEFID ) gridID = gridDefine(grid);
+
+  return gridID;
+}
diff --git a/src/grid_rot.c b/src/grid_rot.c
index df2a074..9d707dd 100644
--- a/src/grid_rot.c
+++ b/src/grid_rot.c
@@ -19,18 +19,17 @@ double lamrot_to_lam(double phirot, double lamrot, double polphi, double pollam,
 
     result : longitude in the geographical system
   */
-  double zsinpol, zcospol, zlampol;
-  double zphirot, zlamrot, zarg1, zarg2;
+  double zarg1, zarg2;
   double zgam;
   double result = 0;
 
-  zsinpol = sin(DEG2RAD*polphi);
-  zcospol = cos(DEG2RAD*polphi);
+  double zsinpol = sin(DEG2RAD*polphi);
+  double zcospol = cos(DEG2RAD*polphi);
 
-  zlampol = DEG2RAD*pollam;
-  zphirot = DEG2RAD*phirot;
+  double zlampol = DEG2RAD*pollam;
+  double zphirot = DEG2RAD*phirot;
   if ( lamrot > 180.0 ) lamrot -= 360.0;
-  zlamrot = DEG2RAD*lamrot;
+  double zlamrot = DEG2RAD*lamrot;
 
   if ( fabs(polgam) > 0 )
     {
@@ -58,7 +57,7 @@ double lamrot_to_lam(double phirot, double lamrot, double polphi, double pollam,
   if ( fabs(zarg2) > 0 ) result = RAD2DEG*atan2(zarg1, zarg2);
   if ( fabs(result) < 9.e-14 ) result = 0;
 
-  return (result);
+  return result;
 }
 
 
@@ -79,16 +78,15 @@ double phirot_to_phi(double phirot, double lamrot, double polphi, double polgam)
 
     result : latitude in the geographical system
   */
-  double zsinpol, zcospol;
-  double zphirot, zlamrot, zarg;
+  double zarg;
   double zgam;
 
-  zsinpol = sin(DEG2RAD*polphi);
-  zcospol = cos(DEG2RAD*polphi);
+  double zsinpol = sin(DEG2RAD*polphi);
+  double zcospol = cos(DEG2RAD*polphi);
 
-  zphirot   = DEG2RAD*phirot;
+  double zphirot   = DEG2RAD*phirot;
   if ( lamrot > 180.0 ) lamrot -= 360.0;
-  zlamrot   = DEG2RAD*lamrot;
+  double zlamrot   = DEG2RAD*lamrot;
 
   if ( fabs(polgam) > 0 )
     {
@@ -99,7 +97,7 @@ double phirot_to_phi(double phirot, double lamrot, double polphi, double polgam)
   else
     zarg   = zcospol*cos(zphirot)*cos(zlamrot) + zsinpol*sin(zphirot);
 
-  return (RAD2DEG*asin(zarg));
+  return RAD2DEG*asin(zarg);
 }
 
 static
@@ -115,24 +113,21 @@ double rl_to_rls(double phi, double rla, double polphi, double pollam)
 
     result : Rotierte Laenge
   */
-  double zsinpol, zcospol, zlampol;
-  double zphi, zrla, zarg1, zarg2;
-
-  zsinpol = sin(DEG2RAD*polphi);
-  zcospol = cos(DEG2RAD*polphi);
-  zlampol =     DEG2RAD*pollam;
+  double zsinpol = sin(DEG2RAD*polphi);
+  double zcospol = cos(DEG2RAD*polphi);
+  double zlampol =     DEG2RAD*pollam;
 
   if ( rla > 180.0 ) rla -= 360.0;
 
-  zrla = DEG2RAD*rla;
-  zphi = DEG2RAD*phi;
+  double zrla = DEG2RAD*rla;
+  double zphi = DEG2RAD*phi;
 
-  zarg1  = - sin(zrla-zlampol)*cos(zphi);
-  zarg2  = - zsinpol*cos(zphi)*cos(zrla-zlampol)+zcospol*sin(zphi);
+  double zarg1  = - sin(zrla-zlampol)*cos(zphi);
+  double zarg2  = - zsinpol*cos(zphi)*cos(zrla-zlampol)+zcospol*sin(zphi);
 
   if ( fabs(zarg2) < 1.0e-20 ) zarg2 = 1.0e-20;
 
-  return (RAD2DEG*atan2(zarg1,zarg2));
+  return RAD2DEG*atan2(zarg1,zarg2);
 }
 
 static
@@ -148,20 +143,17 @@ double ph_to_phs(double phi, double rla, double polphi, double pollam)
 
     result : Rotierte Breite
   */
-  double zsinpol, zcospol, zlampol;
-  double zphi, zrla, zarg;
-
-  zsinpol = sin(DEG2RAD*polphi);
-  zcospol = cos(DEG2RAD*polphi);
-  zlampol =     DEG2RAD*pollam;
+  double zsinpol = sin(DEG2RAD*polphi);
+  double zcospol = cos(DEG2RAD*polphi);
+  double zlampol =     DEG2RAD*pollam;
 
-  zphi = DEG2RAD*phi;
+  double zphi = DEG2RAD*phi;
   if ( rla > 180.0 ) rla -= 360.0;
-  zrla = DEG2RAD*rla;
+  double zrla = DEG2RAD*rla;
 
-  zarg = zcospol*cos(zphi)*cos(zrla-zlampol) + zsinpol*sin(zphi);
+  double zarg = zcospol*cos(zphi)*cos(zrla-zlampol) + zsinpol*sin(zphi);
 
-  return (RAD2DEG*asin(zarg));
+  return RAD2DEG*asin(zarg);
 }
 
 
@@ -182,28 +174,26 @@ void usvs_to_uv(double us, double vs, double phi, double rla,
     u      : zonaler wind im geographischen system
     v      : merid. wind im geographischen system
   */
-  double zpolphi, zpollam, zrla, pollamd, zrlas, zarg, zbeta;
-
   /* umrechnung von grad in bogenmass */
-  zpolphi = polphi*DEG2RAD;
-  zpollam = pollam*DEG2RAD;
+  double zpolphi = polphi*DEG2RAD;
+  double zpollam = pollam*DEG2RAD;
   if ( rla < 0.0 ) rla += 360.0;
-  zrla    = rla   *DEG2RAD;
-  pollamd = pollam;
+  double zrla    = rla   *DEG2RAD;
+  double pollamd = pollam;
   if ( pollamd < 0.0 ) pollamd += 360.0;
 
   /* laenge im rotierten system berechnen */
-  zrlas = rl_to_rls(phi, rla, polphi, pollam)*DEG2RAD;
+  double zrlas = rl_to_rls(phi, rla, polphi, pollam)*DEG2RAD;
 
   /* winkel zbeta berechen (schnittwinkel der breitenkreise) */
-  zarg = - sin(zpolphi)*sin(zrla-zpollam)*sin(zrlas) - cos(zrla-zpollam)*cos(zrlas);
+  double zarg = - sin(zpolphi)*sin(zrla-zpollam)*sin(zrlas) - cos(zrla-zpollam)*cos(zrlas);
   if ( zarg >  1.0 ) zarg =  1.0;
   if ( zarg < -1.0 ) zarg = -1.0;
   /*
   zbeta = acos(zarg);
   zbeta = sign(zbeta, -(rla - (pollamd-180.0)));
   */
-  zbeta = fabs(acos(zarg));
+  double zbeta = fabs(acos(zarg));
   /*  if ( -(rla - (pollamd-180.0)) < 0 ) zbeta = -zbeta;*/
   if ( (-(rla - (pollamd-180.0)) < 0) && (-(rla - (pollamd-180.0)) >= -180) ) zbeta = -zbeta;
 
diff --git a/src/grid_search.c b/src/grid_search.c
index cd23e52..ff7cb1c 100644
--- a/src/grid_search.c
+++ b/src/grid_search.c
@@ -543,7 +543,7 @@ struct gsknn *gridsearch_knn_new(unsigned size)
   
   knn->ndist   = size;
   knn->size    = size;
-  knn->mask    = (int*) Malloc(size*sizeof(int));       // mask at nearest neighbors
+  knn->mask    = (bool*) Malloc(size*sizeof(bool));     // mask at nearest neighbors
   knn->add     = (int*) Malloc(size*sizeof(int));       // source address at nearest neighbors
   knn->dist    = (double*) Malloc(size*sizeof(double)); // angular distance of the nearest neighbors
   knn->tmpadd  = NULL;
diff --git a/src/grid_search.h b/src/grid_search.h
index dbc8729..e070234 100644
--- a/src/grid_search.h
+++ b/src/grid_search.h
@@ -46,7 +46,7 @@ struct gridsearch {
 struct gsknn {
   unsigned ndist;
   unsigned size;
-  int     *mask;
+  bool    *mask;
   int     *add;
   int     *tmpadd;
   double  *dist;
diff --git a/src/griddes.c b/src/griddes.c
index 29e8bed..98e3bf2 100644
--- a/src/griddes.c
+++ b/src/griddes.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -15,17 +15,6 @@
   GNU General Public License for more details.
 */
 
-#if defined(HAVE_CONFIG_H)
-#  include "config.h"
-#endif
-
-#if defined(HAVE_LIBNETCDF)
-#  include "netcdf.h"
-#endif
-
-#include <ctype.h>
-
-#include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
@@ -34,24 +23,13 @@
 #include <cdi.h>
 #include "cdo.h"
 #include "cdo_int.h"
-#include "cdi_uuid.h"
 #include "grid.h"
 #include "griddes.h"
 #include "error.h"
 
-/*
-int  extInqPrec(int fileID);
-
-int  extReadHeader(int fileID, int *header);
-int  extReadDataDP(int fileID, double *data);
-
-int  extOpen(const char *filename, const char *mode);
-void extClose(int fileID);
-*/
-
-#define UNDEFID -1
 
-#define MAX_LINE_LEN 65536
+int grid_read(FILE *gfp, const char *dname);
+int grid_read_pingo(FILE *gfp, const char *dname);
 
 
 void gridInit(griddes_t *grid)
@@ -62,19 +40,16 @@ void gridInit(griddes_t *grid)
   grid->xbounds       = NULL;
   grid->ybounds       = NULL;
   grid->area          = NULL;
-  grid->type          = UNDEFID;
+  grid->type          = CDI_UNDEFID;
   grid->size          = 0;
   grid->xsize         = 0;
   grid->ysize         = 0;
   grid->np            = 0;
   grid->lcomplex      = 1;
-  grid->xpole         = 0;
-  grid->ypole         = 0;
   grid->prec          = 0;
-  grid->isRotated     = FALSE;
   grid->ntr           = 0;
   grid->nvertex       = 0;
-  grid->genBounds     = FALSE;
+  grid->genBounds     = false;
 
   grid->originLon     = 0;
   grid->originLat     = 0;
@@ -83,28 +58,28 @@ void gridInit(griddes_t *grid)
   grid->lat2          = 0;
   grid->projflag      = 0;
   grid->scanflag      = 64;
-  grid->def_originLon = FALSE;
-  grid->def_originLat = FALSE;
-  grid->def_lonParY   = FALSE;
-  grid->def_lat1      = FALSE;
-  grid->def_lat2      = FALSE;
+  grid->def_originLon = false;
+  grid->def_originLat = false;
+  grid->def_lonParY   = false;
+  grid->def_lat1      = false;
+  grid->def_lat2      = false;
 
   grid->a             = 0;
   grid->lon_0         = 0;
   grid->lat_0         = 0;
   grid->lat_1         = 0;
   grid->lat_2         = 0;
-  grid->def_lon_0     = FALSE;
-  grid->def_lat_0     = FALSE;
-  grid->def_lat_1     = FALSE;
-  grid->def_lat_2     = FALSE;
-
-  grid->def_xfirst    = FALSE;
-  grid->def_yfirst    = FALSE;
-  grid->def_xlast     = FALSE;
-  grid->def_ylast     = FALSE;
-  grid->def_xinc      = FALSE;
-  grid->def_yinc      = FALSE;
+  grid->def_lon_0     = false;
+  grid->def_lat_0     = false;
+  grid->def_lat_1     = false;
+  grid->def_lat_2     = false;
+
+  grid->def_xfirst    = false;
+  grid->def_yfirst    = false;
+  grid->def_xlast     = false;
+  grid->def_ylast     = false;
+  grid->def_xinc      = false;
+  grid->def_yinc      = false;
   grid->xfirst        = 0;
   grid->yfirst        = 0;
   grid->xlast         = 0;
@@ -125,20 +100,19 @@ void gridInit(griddes_t *grid)
   grid->yname[0]      = 0;
   grid->ylongname[0]  = 0;
   grid->yunits[0]     = 0;
+  grid->xdimname[0]   = 0;
+  grid->ydimname[0]   = 0;
+  grid->vdimname[0]   = 0;
 }
 
 
 int getoptname(char *optname, const char *optstring, int nopt)
 {
-  int i, nerr = 0;
-  size_t namelen;
-  const char *pname;
-  const char *pend;
+  int nerr = 0;
+  const char *pname = optstring;
+  const char *pend  = optstring;
 
-  pname = optstring;
-  pend  = optstring;
-
-  for ( i = 0; i < nopt; i++ )
+  for ( int i = 0; i < nopt; i++ )
     {
       pend = strchr(pname, ',');
       if ( pend == NULL )
@@ -150,6 +124,7 @@ int getoptname(char *optname, const char *optstring, int nopt)
   if ( pend )
     {
       pend = strchr(pname, ',');
+      size_t namelen;
       if ( pend == NULL )
 	namelen = strlen(pname);
       else
@@ -167,7 +142,7 @@ int getoptname(char *optname, const char *optstring, int nopt)
 
 int gridDefine(griddes_t grid)
 {
-  int gridID = UNDEFID;
+  int gridID = CDI_UNDEFID;
   int i;
 
   switch ( grid.type )
@@ -175,8 +150,7 @@ int gridDefine(griddes_t grid)
     case GRID_GENERIC:
     case GRID_LONLAT:
     case GRID_GAUSSIAN:
-    case GRID_SINUSOIDAL:
-    case GRID_LAEA:
+    case GRID_PROJECTION:
       {
 	if ( grid.size != 1 )
 	  {
@@ -275,24 +249,12 @@ int gridDefine(griddes_t grid)
 	    Free(grid.ybounds);
 	  }
 
-	if ( grid.isRotated )
-	  {
-	    gridDefXpole(gridID, grid.xpole);
-	    gridDefYpole(gridID, grid.ypole);
-	    gridDefAngle(gridID, grid.angle);
-	  }
-
 	if ( grid.mask )
 	  {
 	    gridDefMask(gridID, grid.mask);
 	    Free(grid.mask);
 	  }
 
-	if ( grid.type == GRID_LAEA )
-	  {
-	    if ( grid.a > 0 ) gridDefLaea(gridID, grid.a, grid.lon_0, grid.lat_0);
-	  }
-
 	break;
       }
     case GRID_CURVILINEAR:
@@ -380,15 +342,15 @@ int gridDefine(griddes_t grid)
 	gridDefXsize(gridID, grid.xsize);
 	gridDefYsize(gridID, grid.ysize);
 
-	if ( grid.def_originLon == FALSE ) Error("originLon undefined!");
-	if ( grid.def_originLat == FALSE ) Error("originLat undefined!");
-	if ( grid.def_lonParY   == FALSE ) Error("lonParY undefined!");
-	if ( grid.def_lat1      == FALSE ) Error("lat1 undefined!");
-	if ( grid.def_lat2      == FALSE ) Error("lat2 undefined!");
-	if ( grid.def_xinc      == FALSE ) Error("xinc undefined!");
-	if ( grid.def_yinc      == FALSE ) Error("yinc undefined!");
+	if ( grid.def_originLon == false ) Error("originLon undefined!");
+	if ( grid.def_originLat == false ) Error("originLat undefined!");
+	if ( grid.def_lonParY   == false ) Error("lonParY undefined!");
+	if ( grid.def_lat1      == false ) Error("lat1 undefined!");
+	if ( grid.def_lat2      == false ) Error("lat2 undefined!");
+	if ( grid.def_xinc      == false ) Error("xinc undefined!");
+	if ( grid.def_yinc      == false ) Error("yinc undefined!");
 
-	gridDefLCC(gridID, grid.originLon, grid.originLat, grid.lonParY,
+	gridDefParamLCC(gridID, grid.originLon, grid.originLat, grid.lonParY,
 		   grid.lat1, grid.lat2, grid.xinc, grid.yinc, grid.projflag, grid.scanflag);
 
 	if ( grid.mask )
@@ -399,61 +361,6 @@ int gridDefine(griddes_t grid)
 
 	break;
       }
-    case GRID_LCC2:
-      {
-	if ( grid.xsize == 0 ) Error("xsize undefined!");
-	if ( grid.ysize == 0 ) Error("ysize undefined!");
-
-	if ( grid.size == 0 ) grid.size = grid.xsize*grid.ysize;
-
-	gridID = gridCreate(grid.type, grid.size);
-
-	gridDefPrec(gridID, grid.prec);
-
-	gridDefXsize(gridID, grid.xsize);
-	gridDefYsize(gridID, grid.ysize);
-
-	if ( grid.def_xfirst && grid.def_xinc && grid.xvals == NULL )
-	  {
-	    grid.xvals = (double*) Malloc(grid.xsize*sizeof(double));
-	    for ( i = 0; i < grid.xsize; ++i )
-	      grid.xvals[i] = grid.xfirst + i*grid.xinc;
-	  }
-
-	if ( grid.def_yfirst && grid.def_yinc && grid.yvals == NULL )
-	  {
-	    grid.yvals = (double*) Malloc(grid.ysize*sizeof(double));
-	    for ( i = 0; i < grid.ysize; ++i )
-	      grid.yvals[i] = grid.yfirst + i*grid.yinc;
-	  }
-
-	if ( grid.xvals )
-	  {
-	    gridDefXvals(gridID, grid.xvals);
-	    Free(grid.xvals);
-	  }
-
-	if ( grid.yvals )
-	  {
-	    gridDefYvals(gridID, grid.yvals);
-	    Free(grid.yvals);
-	  }	
-
-	if ( grid.def_lon_0     == FALSE ) Error("lon_0 undefined!");
-	if ( grid.def_lat_0     == FALSE ) Error("lat_0 undefined!");
-	if ( grid.def_lat_1     == FALSE ) Error("lat_1 undefined!");
-	if ( grid.def_lat_2     == FALSE ) grid.def_lat_2 = grid.def_lat_1;
-
-	gridDefLcc2(gridID, grid.a, grid.lon_0, grid.lat_0, grid.lat_1, grid.lat_2);
-
-	if ( grid.mask )
-	  {
-	    gridDefMask(gridID, grid.mask);
-	    Free(grid.mask);
-	  }
-
-	break;
-      }
     case GRID_SPECTRAL:
       {
 	if ( grid.ntr == 0 )
@@ -481,10 +388,7 @@ int gridDefine(griddes_t grid)
 
 	gridDefPrec(gridID, grid.prec);
 
-	gridDefGMEnd(gridID, grid.nd);
-	gridDefGMEni(gridID, grid.ni);
-	gridDefGMEni2(gridID, grid.ni2);
-	gridDefGMEni3(gridID, grid.ni3);
+	gridDefParamGME(gridID, grid.nd, grid.ni, grid.ni2, grid.ni3);
 	
 	if ( grid.mask )
 	  {
@@ -507,1351 +411,15 @@ int gridDefine(griddes_t grid)
 
   if ( grid.uuid[0] )      gridDefUUID(gridID, grid.uuid);
 
-  if ( grid.xname[0]     ) gridDefXname(gridID, grid.xname);
-  if ( grid.xlongname[0] ) gridDefXlongname(gridID, grid.xlongname);
-  if ( grid.xunits[0]    ) gridDefXunits(gridID, grid.xunits);
-  if ( grid.yname[0]     ) gridDefYname(gridID, grid.yname);
-  if ( grid.ylongname[0] ) gridDefYlongname(gridID, grid.ylongname);
-  if ( grid.yunits[0]    ) gridDefYunits(gridID, grid.yunits);
-
-  return gridID;
-}
-
-static
-char *skipSeparator(char *pline)
-{
-  while ( isspace((int) *pline) ) pline++;
-  if ( *pline == '=' || *pline == ':' ) pline++;
-  while ( isspace((int) *pline) ) pline++;
-
-  return pline;
-}
-
-
-void fnmexp2(char *out, char *in1, const char *in2)
-{
-  const char *pos, *ch;
-  char envv[20], *envr;
-  int i,j;
-
-  if ( *in1=='$' )
-    {
-      in1++;
-      i = 0;
-      while (*in1!='/' && *in1!='\0' && i<16)
-	{
-	  envv[i] = *in1;
-	  i++; in1++;
-	}
-      envv[i] = '\0';
-      envr = getenv(envv);
-      if (envr)
-	{
-	  i = 0; j = 0;
-	  while (*(envr+j))
-	    {
-	      *(out+i) = *(envr+j);
-	      i++; j++;
-	    }
-	  while (*in1!='\0' && *in1!=' ' && *in1!='\n')
-	    {
-	      *(out+i) = *in1;
-	      i++; in1++;
-	    }
-	  *(out+i) = '\0';
-	}
-      return;
-    }
-  ch = in2;
-  pos=NULL;
-  while (*ch!='\0' && *ch!=' ' && *ch!='\n')
-    {
-      if (*ch=='/') pos=ch;
-      ch++;
-    }
-  if (pos) pos++;
-  while (pos!=NULL && in2<pos)
-    {
-      *out = *in2;
-      out++; in2++;
-    }
-  in1++;
-  while (*in1!='\0' && *in1!=' ' && *in1!='\n')
-    {
-      *out = *in1;
-      out++; in1++;
-    }
-  *out = '\0';
-}
-
-/*
-double *readfield(griddes_t *grid, int record, char *format, char *filename)
-{
-  int fileID, rxysize, ierr, irec;
-  double *vals;
-
-  if ( grid->size == 0 )  Error("grid size = 0!");
-  if ( format == NULL )   Error("format undefined!");
-  if ( filename == NULL ) Error("file name undefined!");
-
-  vals = (double*) Malloc(grid->size*sizeof(double));
-
-  if ( strcmp(format, "extra") == 0 )
-    {
-      int header[4];
-      fileID = extOpen(filename, "r");
-      if ( fileID == UNDEFID ) SysError(filename);
-
-      for ( irec = 0; irec < record; irec++ )
-	{
-	  ierr = extReadHeader(fileID, header);
-	  if ( ierr <= 0 ) Error("Record %d unexpected EOF in file %s", irec+1, filename);
-	}
-      grid->prec   = extInqPrec(fileID);
-      rxysize = header[3];
-      if ( rxysize != (int) grid->size ) Error("unexpected record size of %d!", rxysize);
-      ierr = extReadDataDP(fileID, vals);
-      extClose(fileID);
-    }
-  else
-    Error("format %s unsupported!", format);
-
-  return vals;
-}
-*/
-/*
-double *readfield4(griddes_t *grid, int record, char *format, char *filename)
-{
-  int fileID, rxysize, ierr, irec;
-  double *vals;
-
-  if ( grid->size == 0 )  Error("grid size = 0!");
-  if ( format == NULL )   Error("format undefined!");
-  if ( filename == NULL ) Error("file name undefined!");
-
-  vals  = (double*) Malloc(4*grid->size*sizeof(double));
-
-  if ( strcmp(format, "extra") == 0 )
-    {
-      int header[4];
-      fileID = extOpen(filename, "r");
-      if ( fileID == UNDEFID ) SysError(filename);
-
-      for ( irec = 0; irec < record; irec++ )
-	{
-	  ierr = extReadHeader(fileID, header);
-	  if ( ierr <= 0 ) Error("Record %d unexpected EOF in file %s", irec+1, filename);
-	}
-      grid->prec   = extInqPrec(fileID);
-      rxysize = header[3];
-      if ( rxysize != (int) (4*grid->size) ) Error("unexpected record size of %d!", rxysize);
-      ierr = extReadDataDP(fileID, vals);
-
-      extClose(fileID);
-    }
-  else
-    Error("format %s unsupported!", format);
-
-  return vals;
-}
-*/
-
-double readflt(const char *filename, const char *name, const char *pline)
-{
-  double val;
-  char *endptr;
-
-  val = strtod(pline, &endptr);
-  if ( pline == endptr )
-    cdoAbort("Couldn't read value for %s (grid description file: %s)!", name, filename);
- 
-  return val;
-}
-
-
-int gridFromFile(FILE *gfp, const char *dname)
-{
-  char line[MAX_LINE_LEN], *pline;
-  int gridID = -1;
-  int size;
-  int lerror;
-  size_t i, len;
-  griddes_t grid;
-  int lineno = 0;
-
-  gridInit(&grid);
-
-  while ( readline(gfp, line, MAX_LINE_LEN) )
-    {
-      lineno++;
-      if ( line[0] == '#' ) continue;
-      if ( line[0] == '\0' ) continue;
-      len = strlen(line);
-
-      lerror = FALSE;
-      for ( i = 0; i < len; ++i )
-	if ( !(line[i] == 9 || (line[i] > 31 && line[i] < 127)) )
-	  {
-	    lerror = TRUE;
-	    line[i] = '#';
-	  }
-      if ( lerror ) cdoAbort("Grid description file >%s< contains illegal characters (line: %s)!", dname, line);
-
-      pline = line;
-      while ( isspace((int) *pline) ) pline++;
-      if ( pline[0] == '\0' ) continue;
-      if ( cmpstrlen(pline, "gridtype", len) == 0 )
-	{
-	  pline = skipSeparator(pline + len);
-	  if ( cmpstrlen(pline, "lonlat", len)  == 0 ||
-	       cmpstrlen(pline, "latlon", len)  == 0 )
-	    {
-	      grid.type = GRID_LONLAT;
-	      grid.nvertex = 2;
-	    }
-	  else if ( cmpstrlen(pline, "gaussian", len)  == 0 )
-	    {
-	      grid.type = GRID_GAUSSIAN;
-	      grid.nvertex = 2;
-	    }
-	  else if ( cmpstrlen(pline, "curvilinear", len)  == 0 )
-	    {
-	      grid.type = GRID_CURVILINEAR;
-	      grid.nvertex = 4;
-	    }
-	  else if ( cmpstrlen(pline, "spectral", len)  == 0 )
-	    grid.type = GRID_SPECTRAL;
-	  else if ( cmpstrlen(pline, "unstructured", len)  == 0 )
-	    grid.type = GRID_UNSTRUCTURED;
-	  else if ( cmpstrlen(pline, "cell", len)  == 0 )
-	    grid.type = GRID_UNSTRUCTURED;
-	  else if ( cmpstrlen(pline, "gme", len)  == 0 )
-	    grid.type = GRID_GME;
-	  else if ( cmpstrlen(pline, "lcc2", len)  == 0 )
-	    grid.type = GRID_LCC2;
-	  else if ( cmpstrlen(pline, "lcc", len)  == 0 )
-	    grid.type = GRID_LCC;
-	  else if ( cmpstrlen(pline, "lambert", len)  == 0 )
-	    grid.type = GRID_LCC;
-	  else if ( cmpstrlen(pline, "sinusoidal", len)  == 0 )
-	    grid.type = GRID_SINUSOIDAL;
-	  else if ( cmpstrlen(pline, "laea", len)  == 0 )
-	    grid.type = GRID_LAEA;
-	  else if ( cmpstrlen(pline, "generic", len)  == 0 )
-	    grid.type = GRID_GENERIC;
-	  else
-	    cdoAbort("Invalid grid name : %s (grid description file: %s)", pline, dname);
-	}
-      else if ( cmpstrlen(pline, "gridprec", len)  == 0 )
-	{
-	  grid.prec = atol(skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "gridsize", len)  == 0 )
-	{
-	  grid.size = atol(skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "truncation", len)  == 0 )
-	{
-	  grid.ntr = atoi(skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "np", len)  == 0 )
-	{
-	  grid.np = atoi(skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "complexpacking", len)  == 0 )
-	{
-	  grid.lcomplex = atoi(skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "xname", len)  == 0 )
-	{
-	  strcpy(grid.xname, skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "xlongname", len)  == 0 )
-	{
-	  strcpy(grid.xlongname, skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "xunits", len)  == 0 )
-	{
-	  strcpy(grid.xunits, skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "yname", len)  == 0 )
-	{
-	  strcpy(grid.yname, skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "ylongname", len)  == 0 )
-	{
-	  strcpy(grid.ylongname, skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "yunits", len)  == 0 )
-	{
-	  strcpy(grid.yunits, skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "nvertex", len)  == 0 )
-	{
-	  grid.nvertex = atol(skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "ni", len)  == 0 )
-	{
-	  grid.ni = atol(skipSeparator(pline + len));
-          grid.nd = 10;
-	}
-      else if ( cmpstrlen(pline, "position", len)  == 0 )
-	{
-	  grid.position = atol(skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "number", len)  == 0 )
-	{
-	  grid.number = atol(skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "path", len)  == 0 )
-	{
-	  strcpy(grid.path, skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "uuid", len)  == 0 )
-	{
-	  char uuidOfHGridStr[256];
-	  strcpy(uuidOfHGridStr, skipSeparator(pline + len));
-	  cdiStr2UUID(uuidOfHGridStr, grid.uuid);
-	}
-      else if ( cmpstrlen(pline, "xsize", len)  == 0 )
-	{
-	  grid.xsize = atol(skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "nlon", len)  == 0 )
-	{
-	  grid.xsize = atol(skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "ysize", len)  == 0 )
-	{
-	  grid.ysize = atol(skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "nlat", len)  == 0 )
-	{
-	  grid.ysize = atol(skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "xfirst", len)  == 0 )
-	{
-	  grid.xfirst = readflt(dname, "xfirst", skipSeparator(pline + len));
-	  grid.def_xfirst = TRUE;
-	}
-      else if ( cmpstrlen(pline, "lonfirst", len)  == 0 )
-	{
-	  grid.xfirst = readflt(dname, "lonfirst", skipSeparator(pline + len));
-	  grid.def_xfirst = TRUE;
-	}
-      else if ( cmpstrlen(pline, "yfirst", len)  == 0 )
-	{
-	  grid.yfirst = readflt(dname, "yfirst", skipSeparator(pline + len));
-	  grid.def_yfirst = TRUE;
-	}
-      else if ( cmpstrlen(pline, "latfirst", len)  == 0 )
-	{
-	  grid.yfirst = readflt(dname, "latfirst", skipSeparator(pline + len));
-	  grid.def_yfirst = TRUE;
-	}
-      else if ( cmpstrlen(pline, "xlast", len)  == 0 )
-	{
-	  grid.xlast = readflt(dname, "xlast", skipSeparator(pline + len));
-	  grid.def_xlast = TRUE;
-	}
-      else if ( cmpstrlen(pline, "lonlast", len)  == 0 )
-	{
-	  grid.xlast = readflt(dname, "lonlast", skipSeparator(pline + len));
-	  grid.def_xlast = TRUE;
-	}
-      else if ( cmpstrlen(pline, "ylast", len)  == 0 )
-	{
-	  grid.ylast = readflt(dname, "ylast", skipSeparator(pline + len));
-	  grid.def_ylast = TRUE;
-	}
-      else if ( cmpstrlen(pline, "latlast", len)  == 0 )
-	{
-	  grid.ylast = readflt(dname, "latlast", skipSeparator(pline + len));
-	  grid.def_ylast = TRUE;
-	}
-      else if ( cmpstrlen(pline, "xinc", len)  == 0 )
-	{
-	  grid.xinc = readflt(dname, "xinc", skipSeparator(pline + len));
-	  grid.def_xinc = TRUE;
-	}
-      else if ( cmpstrlen(pline, "loninc", len)  == 0 )
-	{
-	  grid.xinc = readflt(dname, "loninc", skipSeparator(pline + len));
-	  grid.def_xinc = TRUE;
-	}
-      else if ( cmpstrlen(pline, "yinc", len)  == 0 )
-	{
-	  grid.yinc = readflt(dname, "yinc", skipSeparator(pline + len));
-	  grid.def_yinc = TRUE;
-	}
-      else if ( cmpstrlen(pline, "latinc", len)  == 0 )
-	{
-	  grid.yinc = readflt(dname, "latinc", skipSeparator(pline + len));
-	  grid.def_yinc = TRUE;
-	}
-      else if ( cmpstrlen(pline, "originLon", len)  == 0 )
-	{
-	  grid.originLon = readflt(dname, "originLon", skipSeparator(pline + len));
-	  grid.def_originLon = TRUE;
-	}
-      else if ( cmpstrlen(pline, "originLat", len)  == 0 )
-	{
-	  grid.originLat = readflt(dname, "originLat", skipSeparator(pline + len));
-	  grid.def_originLat = TRUE;
-	}
-      else if ( cmpstrlen(pline, "lonParY", len)  == 0 )
-	{
-	  grid.lonParY = readflt(dname, "lonParY", skipSeparator(pline + len));
-	  grid.def_lonParY = TRUE;
-	}
-      else if ( cmpstrlen(pline, "lat1", len)  == 0 )
-	{
-	  grid.lat1 = readflt(dname, "lat1", skipSeparator(pline + len));
-	  grid.def_lat1 = TRUE;
-	}
-      else if ( cmpstrlen(pline, "lat2", len)  == 0 )
-	{
-	  grid.lat2 = readflt(dname, "lat2", skipSeparator(pline + len));
-	  grid.def_lat2 = TRUE;
-	}
-      else if ( cmpstrlen(pline, "projection", len)  == 0 )
-	{
-	  pline = skipSeparator(pline + len);
-	  if      ( cmpstrlen(pline, "north", len) == 0 )
-	    {
-	      grid.projflag = 0;
-	      grid.scanflag = 64;
-	    }
-	  else if ( cmpstrlen(pline, "south", len) == 0 )
-	    {
-	      grid.projflag = 128;
-	      grid.scanflag = 64;
-	    }
-	  else
-	    cdoAbort("Invalid projection : %s (grid description file: %s)", pline, dname);
-	}
-      else if ( cmpstrlen(pline, "lon_0", len)  == 0 )
-	{
-	  grid.lon_0 = readflt(dname, "lon_0", skipSeparator(pline + len));
-	  grid.def_lon_0 = TRUE;
-	}
-      else if ( cmpstrlen(pline, "lat_0", len)  == 0 )
-	{
-	  grid.lat_0 = readflt(dname, "lat_0", skipSeparator(pline + len));
-	  grid.def_lat_0 = TRUE;
-	}
-      else if ( cmpstrlen(pline, "lat_1", len)  == 0 )
-	{
-	  grid.lat_1 = readflt(dname, "lat_1", skipSeparator(pline + len));
-	  grid.def_lat_1 = TRUE;
-	}
-      else if ( cmpstrlen(pline, "lat_2", len)  == 0 )
-	{
-	  grid.lat_2 = readflt(dname, "lat_2", skipSeparator(pline + len));
-	  grid.def_lat_2 = TRUE;
-	}
-      else if ( cmpstrlen(pline, "xnpole", len)  == 0 )
-	{
-	  grid.xpole = readflt(dname, "xnpole", skipSeparator(pline + len));
-	  grid.isRotated = TRUE;
-	}
-      else if ( cmpstrlen(pline, "lonpole", len)  == 0 )
-	{
-	  grid.xpole = readflt(dname, "lonpole", skipSeparator(pline + len));
-	  grid.isRotated = TRUE;
-	}
-      else if ( cmpstrlen(pline, "ynpole", len)  == 0 )
-	{
-	  grid.ypole = readflt(dname, "ynpole", skipSeparator(pline + len));
-	  grid.isRotated = TRUE;
-	}
-      else if ( cmpstrlen(pline, "latpole", len)  == 0 )
-	{
-	  grid.ypole = readflt(dname, "latpole", skipSeparator(pline + len));
-	  grid.isRotated = TRUE;
-	}
-      else if ( cmpstrlen(pline, "angle", len)  == 0 )
-	{
-	  grid.angle = readflt(dname, "angle", skipSeparator(pline + len));
-	  grid.isRotated = TRUE;
-	}
-      else if ( cmpstrlen(pline, "a", len)  == 0 )
-	{
-	  grid.a = readflt(dname, "a", skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "gridlatlon", len)  == 0 )
-	{
-	  int i;
-	  double flat = 0, flon = 0;
-	  if ( grid.size == 0 ) grid.size = grid.xsize * grid.ysize;
-	  
-	  grid.xvals = (double*) Malloc(grid.size*sizeof(double));
-	  grid.yvals = (double*) Malloc(grid.size*sizeof(double));
-	  for ( i = 0; i < (int) grid.size; i++ )
-	    {
-              lineno++;
-	      if ( ! readline(gfp, line, MAX_LINE_LEN) )
-		cdoAbort("Incomplete command: >gridlatlon< (line: %d file: %s)", lineno, dname);
-
-	      sscanf(line, "%lg %lg", &flat, &flon);
-	      grid.yvals[i] = flat;
-	      grid.xvals[i] = flon;
-	    }
-	}
-      else if ( cmpstrlen(pline, "mask", len)  == 0 )
-	{
-	  int i = 0;
-	  long lval;
-	  char *endptr;
-
-	  size = grid.size;
-
-	  if ( size > 0 )
-	    {
-	      long count = 0;
-	      pline = skipSeparator(pline + len);
-	      grid.mask = (int*) Malloc(size*sizeof(int));
-
-	      for ( i = 0; i < size; i++ )
-		{
-		  endptr = pline;
-		  lval = strtol(pline, &endptr, 10);
-		  if ( pline == endptr )
-		    {
-                      lineno++;
-		      if ( ! readline(gfp, line, MAX_LINE_LEN) )
-			cdoAbort("Incomplete command: >mask< (line: %d file: %s)", lineno, dname);
-
-		      pline = line;
-		      lval = strtol(pline, &endptr, 10);
-		    }
-		  grid.mask[i] = (int)lval;
-		  if ( grid.mask[i] == 1 ) count++;
-		  pline = endptr;
-		}
-
-	      if ( count == size )
-		{
-		  Free(grid.mask);
-		  grid.mask = NULL;
-		}
-	    }
-	  else
-	    cdoAbort("gridsize undefined (grid description file: %s)!", dname);
-	}
-      else if ( cmpstrlen(pline, "xvals", len)  == 0 )
-	{
-	  int i = 0;
-	  double fval;
-	  char *endptr;
-
-	  if ( grid.type == GRID_CURVILINEAR || grid.type == GRID_UNSTRUCTURED )
-	    size = grid.size;
-	  else
-	    size = grid.xsize;
-
-	  if ( size > 0 )
-	    {
-	      pline = skipSeparator(pline + len);
-	      grid.xvals = (double*) Malloc(size*sizeof(double));
-
-	      for ( i = 0; i < size; i++ )
-		{
-		  endptr = pline;
-		  fval = strtod(pline, &endptr);
-		  if ( pline == endptr )
-		    {
-                      lineno++;
-		      if ( ! readline(gfp, line, MAX_LINE_LEN) )
-			cdoAbort("Incomplete command: >xvals< (line: %d file: %s)", lineno, dname);
-                      printf("%d %s\n", lineno, line);
-
-		      pline = line;
-		      fval = strtod(pline, &endptr);
-		    }
-		  grid.xvals[i] = fval;
-		  pline = endptr;
-		}
-	    }
-	  else
-	    cdoAbort("xsize or gridsize undefined (file: %s)!", dname);
-	}
-      else if ( cmpstrlen(pline, "yvals", len)  == 0 )
-	{
-	  int i = 0;
-	  double fval;
-	  char *endptr;
-
-	  if ( grid.type == GRID_CURVILINEAR || grid.type == GRID_UNSTRUCTURED )
-	    size = grid.size;
-	  else
-	    size = grid.ysize;
-
-	  if ( size > 0 )
-	    {
-	      pline = skipSeparator(pline + len);
-	      grid.yvals = (double*) Malloc(size*sizeof(double));
-
-	      for ( i = 0; i < size; i++ )
-		{
-		  endptr = pline;
-		  fval = strtod(pline, &endptr);
-		  if ( pline == endptr )
-		    {
-                      lineno++;
-		      if ( ! readline(gfp, line, MAX_LINE_LEN) )
-			cdoAbort("Incomplete command: >yvals< (line %d file: %s)", lineno, dname);
-
-		      pline = line;
-		      fval = strtod(pline, &endptr);
-		    }
-		  grid.yvals[i] = fval;
-		  pline = endptr;
-		}
-	    }
-	  else
-	    cdoAbort("ysize or gridsize undefined (grid description file: %s)!", dname);
-	}
-      else if ( cmpstrlen(pline, "xbounds", len)  == 0 )
-	{
-	  int i = 0;
-	  double fval;
-	  char *endptr;
-
-	  if ( grid.nvertex == 0 )
-	    {
-	      if ( grid.type == GRID_LONLAT      ) grid.nvertex = 2;
-	      if ( grid.type == GRID_CURVILINEAR ) grid.nvertex = 4;
-	    }
-
-	  if ( grid.type == GRID_CURVILINEAR || grid.type == GRID_UNSTRUCTURED )
-	    size = grid.size;
-	  else
-	    size = grid.xsize;
-
-	  if ( size > 0 && grid.nvertex > 0 )
-	    {	  
-	      pline = skipSeparator(pline + len);
-	      grid.xbounds = (double*) Malloc(size*grid.nvertex*sizeof(double));
-
-	      for ( i = 0; i < (int) (size*grid.nvertex); i++ )
-		{
-		  endptr = pline;
-		  fval = strtod(pline, &endptr);
-		  if ( pline == endptr )
-		    {
-                      lineno++;
-		      if ( ! readline(gfp, line, MAX_LINE_LEN) )
-			cdoAbort("Incomplete command: >xbounds< (line %d file: %s)", lineno, dname);
-
-		      pline = line;
-		      fval = strtod(pline, &endptr);
-		    }
-		  grid.xbounds[i] = fval;
-		  pline = endptr;
-		}
-	    }
-	  else
-	    {
-	      if ( size         == 0 ) cdoAbort("xsize or gridsize undefined (file: %s)!", dname);
-	      if ( grid.nvertex == 0 ) cdoAbort("nvertex undefined (file: %s)!", dname);
-	    }
-	}
-      else if ( cmpstrlen(pline, "ybounds", len)  == 0 )
-	{
-	  int i = 0;
-	  double fval;
-	  char *endptr;
-
-	  if ( grid.nvertex == 0 )
-	    {
-	      if ( grid.type == GRID_LONLAT      ) grid.nvertex = 2;
-	      if ( grid.type == GRID_CURVILINEAR ) grid.nvertex = 4;
-	    }
-
-	  if ( grid.type == GRID_CURVILINEAR || grid.type == GRID_UNSTRUCTURED )
-	    size = grid.size;
-	  else
-	    size = grid.ysize;
-
-	  if ( size > 0 && grid.nvertex > 0 )
-	    {	  
-	      pline = skipSeparator(pline + len);
-	      grid.ybounds = (double*) Malloc(size*grid.nvertex*sizeof(double));
-
-	      for ( i = 0; i < (int) (size*grid.nvertex); i++ )
-		{
-		  endptr = pline;
-		  fval = strtod(pline, &endptr);
-		  if ( pline == endptr )
-		    {
-                      lineno++;
-		      if ( ! readline(gfp, line, MAX_LINE_LEN) )
-			cdoAbort("Incomplete command: >ybounds< (line %d file: %s)", lineno, dname);
-                      
-		      pline = line;
-		      fval = strtod(pline, &endptr);
-		    }
-		  grid.ybounds[i] = fval;
-		  pline = endptr;
-		}
-	    }
-	  else
-	    {
-	      if ( grid.ysize   == 0 ) cdoAbort("ysize or gridsize undefined (grid description file: %s)!", dname);
-	      if ( grid.nvertex == 0 ) cdoAbort("nvertex undefined!", dname);
-	    }
-	}
-      else
-	{
-	  if ( grid.type != UNDEFID )
-	    cdoAbort("Invalid grid command : >%s< (line %d file: %s)", pline, lineno, dname);
-	}
-    }
-  /*
-  printf("gridtype %d\n", grid.type);
-  printf("gridsize %d\n", grid.size);
-  printf("xsize %d\n", grid.xsize);
-  printf("ysize %d\n", grid.ysize);
-  */
-  if ( grid.type != UNDEFID ) gridID = gridDefine(grid);
-
-  return gridID;
-}
-
-
-void skip_nondigit_lines(FILE *gfp)
-{
-  int c;
-
-  if ( feof(gfp) ) return;
-
-  while (1)
-    {
-      do
-	c = fgetc(gfp);
-      while ( (isspace(c) || c == ',') && c != EOF );
-
-      if ( c == EOF || isdigit (c) || c == '.' || c == '+' || c == '-' ) break;
-      else
-	while ( c != '\n' && c != EOF )
-	  c = fgetc(gfp);
-    }
-
-  ungetc(c, gfp);
-}
-
-
-int input_ival(FILE *gfp, int *ival)
-{
-  skip_nondigit_lines(gfp);
-
-  if ( feof(gfp) ) return 0;
-
-  *ival = 0;
-  int read_items = fscanf(gfp, "%d", ival);
-
-  return read_items;
-}
-
-
-int input_darray(FILE *gfp, int n_values, double *array)
-{
-  if ( n_values <= 0 ) return 0;
-
-  int read_items = 0;
-  for ( int i = 0; i < n_values; i++ )
-    {
-      skip_nondigit_lines(gfp);
-
-      if ( feof(gfp) ) break;
-
-      read_items += fscanf(gfp, "%lg", &array[i]);
-
-      if ( feof(gfp) ) break;
-    }
-
-  return read_items;
-}
-
-
-int gridFromPingo(FILE *gfp, const char *dname)
-{
-  int gridID = -1;
-  int i;
-  int nlon, nlat;
-  int lgauss = FALSE;
-  griddes_t grid;
-
-  gridInit(&grid);
-
-  if ( ! input_ival(gfp, &nlon) ) return gridID;
-  if ( ! input_ival(gfp, &nlat) ) return gridID;
-
-  if ( nlon > 0 && nlon < 9999 && nlat > 0 && nlat < 9999 )
-    {
-      grid.xsize = nlon;
-      grid.ysize = nlat;
-
-      grid.xvals = (double*) Malloc(grid.xsize*sizeof(double));
-      grid.yvals = (double*) Malloc(grid.ysize*sizeof(double));
-
-      if ( ! input_ival(gfp, &nlon) ) return gridID;
-      if ( nlon == 2 )
-	{
-	  if ( input_darray(gfp, 2, grid.xvals) != 2 ) return gridID;
-	  grid.xvals[1] -= 360 * floor((grid.xvals[1] - grid.xvals[0]) / 360);
-
-	  if ( grid.xsize > 1 )
-	    if ( IS_EQUAL(grid.xvals[0], grid.xvals[1]) )
-	      grid.xvals[1] += 360;
-
-	  for ( i = 0; i < (int)grid.xsize; i++ )
-	    grid.xvals[i] = grid.xvals[0] + i*(grid.xvals[1] - grid.xvals[0]);
-	}
-      else if ( nlon == (int)grid.xsize )
-	{
-	  if ( input_darray(gfp, nlon, grid.xvals) != nlon ) return gridID;
-	  for ( i = 0; i < nlon - 1; i++ )
-	    if ( grid.xvals[i+1] <= grid.xvals[i] ) break;
-
-	  for ( i++; i < nlon; i++ )
-	    {
-	      grid.xvals[i] += 360;
-	      if ( i < nlon - 1 && grid.xvals[i+1] + 360 <= grid.xvals[i] )
-		{
-		  Message("Longitudes are not in ascending order!");
-		  return gridID;
-		}
-	    }
-	}
-      else
-	return gridID;
-
-      if ( ! input_ival(gfp, &nlat) ) return gridID;
-      if ( nlat == 2 )
-	{
-	  if ( input_darray(gfp, 2, grid.yvals) != 2 ) return gridID;
-	  for ( i = 0; i < (int)grid.ysize; i++ )
-	    grid.yvals[i] = grid.yvals[0] + i*(grid.yvals[1] - grid.yvals[0]);
-	}
-      else if ( nlat == (int)grid.ysize )
-	{
-	  if ( input_darray(gfp, nlat, grid.yvals) != nlat ) return gridID;
-	}
-      else
-	return gridID;
-
-      if ( grid.yvals[0]      >  90.001  || 
-	   grid.yvals[nlat-1] >  90.001  || 
-	   grid.yvals[0]      < -90.001  || 
-	   grid.yvals[nlat-1] < -90.001 )
-	{
-	  Message("Latitudes must be between 90 and -90!");
-	  return gridID;
-	}
-
-      for ( i = 0; i < nlat - 1; i++ )
-	if ( IS_EQUAL(grid.yvals[i+1], grid.yvals[i]) || (i < nlat - 2 &&
-	    ((grid.yvals[i+1] > grid.yvals[i]) != (grid.yvals[i+2] > grid.yvals[i+1]))) )
-	  {
-	    Message("Latitudes must be in descending or ascending order!");
-	    return gridID;
-	  }
-		    
-      if ( nlat > 2 ) /* check if gaussian */
-	{
-	  double *yvals, *yw;
-	  yvals = (double*) Malloc(grid.ysize*sizeof(double));
-	  yw    = (double*) Malloc(grid.ysize*sizeof(double));
-	  gaussaw(yvals, yw, grid.ysize);
-	  Free(yw);
-	  for ( i = 0; i < (int) grid.ysize; i++ )
-	    yvals[i] = asin(yvals[i])*RAD2DEG;
-
-	  for ( i = 0; i < (int) grid.ysize; i++ )
-	    if ( fabs(yvals[i] - grid.yvals[i]) > ((yvals[0] - yvals[1])/500) ) break;
-		      
-	  if ( i == (int) grid.ysize ) lgauss = TRUE;
-
-	  Free(yvals);
-	}
-
-      if ( lgauss )
-	grid.type = GRID_GAUSSIAN;
-      else
-	grid.type = GRID_LONLAT;
-    }
-  
-  if ( grid.type != UNDEFID ) gridID = gridDefine(grid);
-
-  return gridID;
-}
-
-
-int nfc2nlat(int nfc, int ntr)
-{
-  int nlat = nfc / (ntr+1);
-  nlat /= 2;
-
-  return nlat;
-}
-
-
-int nlat2ntr(int nlat)
-{
-  int ntr = (nlat*2 - 1) / 3;
-
-  return ntr;
-}
-
-
-int nlat2ntr_linear(int nlat)
-{
-  int ntr = (nlat*2 - 1) / 2;
-
-  return ntr;
-}
-
-
-int ntr2nlat(int ntr)
-{
-  int nlat = (int)lround((ntr*3.+1.)/2.);
-  if ( (nlat % 2) > 0 )
-    {
-      nlat  = nlat + 1;
-      /*
-      int nlat2 = (int)lround(((ntr+1)*3.+1.)/2.);
-      if ( nlat == nlat2 )
-	Error("Computation of latitudes failed for truncation %d", ntr);
-      */
-    }
-
-  return nlat;
-}
-
-
-int ntr2nlat_linear(int ntr)
-{
-  int nlat = (int)lround((ntr*2.+1.)/2.);
-  if ( (nlat % 2) > 0 )
-    {
-      nlat  = nlat + 1;
-      /*
-      int nlat2 = (int)lround(((ntr+1)*2.+1.)/2.);
-      if ( nlat == nlat2 )
-	Error("Computation of latitudes failed for truncation %d", ntr);
-      */
-    }
-
-  return nlat;
-}
-
-
-int compNlon(int nlat)
-{
-  int n;
-  int nlon = 2 * nlat;
-
-  /* check that FFT works with nlon */
-  while ( 1 )
-    {
-      n = nlon;
-      if    ( n % 8 == 0 )  { n /= 8; }
-      while ( n % 6 == 0 )  { n /= 6; }
-      while ( n % 5 == 0 )  { n /= 5; }
-      while ( n % 4 == 0 )  { n /= 4; }
-      while ( n % 3 == 0 )  { n /= 3; }
-      if    ( n % 2 == 0 )  { n /= 2; }
-
-      if ( n <= 8 ) break;
-
-      nlon = nlon + 2;
-
-      if ( nlon > 9999 )
-	{
-	  nlon = 2 * nlat;
-	  fprintf(stderr, "FFT does not work with len %d!\n", nlon);
-	  break;
-	}
-    }
-
-  return nlon;
-}
-
-static
-void gen_grid_lonlat(griddes_t *grid, const char *pline, double inc, double lon1, double lon2, double lat1, double lat2)
-{
-  int gridtype = GRID_LONLAT;
-  bool lbounds = true;
-
-  if ( *pline != 0 && (*pline == '+' || *pline == '-') && (isdigit((int) *(pline+1)) || ispunct((int) *(pline+1))) )
-    {
-      char *endptr = (char *) pline;
-      double off = strtod(pline, &endptr);
-      pline = endptr;
-      
-      lon1 -= off;
-      lon2 += off;
-      lat1 -= off;
-      lat2 += off;
-      if ( lat1 < -90 ) lat1 = -90;
-      if ( lat2 >  90 ) lat2 =  90;
-    }
-
-  if ( *pline != 0 )
-    {
-      if ( *pline == '_' ) pline++;
-      else return;
-
-      if ( *pline == 0 ) return;
-
-      if ( ! isdigit((int) *pline) && !ispunct((int) *pline) ) return;
-
-      char *endptr = (char *) pline;
-      inc = strtod(pline, &endptr);
-      if ( *endptr != 0 )
-        {
-          pline = endptr;
-          if ( *pline == '_' ) pline++;
-          else return;
-          
-          if ( *pline == 0 ) return;
-          if ( *pline == 'c' )
-            {
-              gridtype = GRID_CURVILINEAR;
-              pline++;
-              if ( *pline == '0' )
-                {
-                  lbounds = false;
-                  pline++;
-                }
-            }
-          else if ( *pline == 'u' )
-            {
-              gridtype = GRID_UNSTRUCTURED;
-              pline++;
-              if ( *pline == '0' )
-                {
-                  lbounds = false;
-                  pline++;
-                }
-            }
-          if ( *pline != 0 ) return;          
-        }
-
-      if ( inc < 1e-9 ) inc = 1;
-    }
-
-  grid->type = gridtype;
-
-  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);
-
-  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;
-
-  if ( gridtype == GRID_LONLAT )
-    {
-      grid->xsize = nlon;
-      grid->ysize = nlat;
-      grid->xvals = xvals;
-      grid->yvals = yvals;
-      xvals = NULL;
-      yvals = NULL;
-    }
-  else
-    {
-      double 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++ )
-          {
-            xvals2D[j*nlon+i] = xvals[i];
-            yvals2D[j*nlon+i] = yvals[j];
-          }
-
-      if ( gridtype == GRID_CURVILINEAR )
-        {
-          grid->xsize = nlon;
-          grid->ysize = nlat;
-        }
-      else
-        {
-          grid->xsize = gridsize;
-          grid->ysize = gridsize;
-          if ( lbounds ) grid->nvertex = 4;
-        }
-      
-      grid->xvals = xvals2D;
-      grid->yvals = yvals2D;
-      
-      if ( lbounds && nlon > 1 && nlat > 1 )
-        {
-          double *xbounds = (double*) Malloc(2*nlon*sizeof(double));
-          grid_gen_bounds(nlon, xvals, xbounds);
-          
-          double *ybounds = (double*) Malloc(2*nlat*sizeof(double));
-          grid_gen_bounds(nlat, yvals, ybounds);
-          grid_check_lat_borders(2*nlat, ybounds);
-
-          double *xbounds2D = (double*) Malloc(4*gridsize*sizeof(double));
-          double *ybounds2D = (double*) Malloc(4*gridsize*sizeof(double));
-
-          grid_gen_xbounds2D(nlon, nlat, xbounds, xbounds2D);
-          grid_gen_ybounds2D(nlon, nlat, ybounds, ybounds2D);
-
-          Free(xbounds);
-          Free(ybounds);
-          grid->xbounds = xbounds2D;
-          grid->ybounds = ybounds2D;
-        }
-   }
-
-  if ( xvals ) Free(xvals);
-  if ( yvals ) Free(yvals);
-}
-
-
-int gridFromName(const char *gridname)
-{
-  const char *pline;
-  int gridID = UNDEFID;
-  griddes_t grid;
-  size_t len;
-  char *endptr;
-
-  gridInit(&grid);
-
-  if ( gridname[0] == 't' && gridname[1] == 'l' ) /* tl<RES>grid or tl<RES>spec */
-    {
-      pline = &gridname[2];
-      if ( isdigit((int) *pline) )
-	{
-	  grid.ntr = atoi(pline);
-	  while ( isdigit((int) *pline) ) pline++;
-	  if      ( cmpstrlen(pline, "grid", len) == 0 ) grid.type = GRID_GAUSSIAN;
-	  else if ( cmpstrlen(pline, "zon",  len) == 0 ) grid.type = GRID_GAUSSIAN;
-	  else if ( cmpstrlen(pline, "spec", len) == 0 ) grid.type = GRID_SPECTRAL;
-	  else if ( cmpstrlen(pline, "",     len) == 0 ) grid.type = GRID_SPECTRAL;
-      
-	  if ( pline[len] != 0 ) return gridID;
-
-	  if ( grid.type == GRID_GAUSSIAN )
-	    {
-	      grid.ysize = ntr2nlat_linear(grid.ntr);
-	      grid.np    = grid.ysize/2;
-	      if ( cmpstrlen(pline, "zon",  len) == 0 )
-		grid.xsize = 1;
-	      else
-		grid.xsize = compNlon(grid.ysize);
-
-	      grid.def_xfirst = TRUE;
-	      grid.def_yfirst = TRUE;	      
-	    }
-	}
-    }
-  else if ( gridname[0] == 't' ) /* t<RES>grid or t<RES>spec */
-    {
-      pline = &gridname[1];
-      if ( isdigit((int) *pline) )
-	{
-	  grid.ntr = atoi(pline);
-	  while ( isdigit((int) *pline) ) pline++;
-	  if      ( cmpstrlen(pline, "grid", len) == 0 ) grid.type = GRID_GAUSSIAN;
-	  else if ( cmpstrlen(pline, "zon",  len) == 0 ) grid.type = GRID_GAUSSIAN;
-	  else if ( cmpstrlen(pline, "spec", len) == 0 ) grid.type = GRID_SPECTRAL;
-	  else if ( cmpstrlen(pline, "",     len) == 0 ) grid.type = GRID_SPECTRAL;
-     
-	  if ( pline[len] != 0 ) return gridID;
-
-	  if ( grid.type == GRID_GAUSSIAN )
-	    {
-	      grid.ysize = ntr2nlat(grid.ntr);
-	      grid.np    = grid.ysize/2;
-	      if ( cmpstrlen(pline, "zon",  len) == 0 )
-		grid.xsize = 1;
-	      else
-		grid.xsize = compNlon(grid.ysize);
-
-	      grid.def_xfirst = TRUE;
-	      grid.def_yfirst = TRUE;	      
-	    }
-	}
-    }
-  else if ( gridname[0] == 'r' ) /* r<LON>x<LAT> */
-    {
-      pline = &gridname[1];
-      if ( isdigit((int) *pline) )
-	{
-	  grid.type = GRID_LONLAT;
-	  grid.xsize = atoi(pline);
-	  while ( isdigit((int) *pline) ) pline++;
-	  pline++;
-	  grid.ysize = atoi(pline);
-	  while ( isdigit((int) *pline) ) pline++;
-
-	  grid.def_xfirst = TRUE;
-	  grid.def_yfirst = TRUE;
-	}
-    }
-  else if ( gridname[0] == 'l' &&  gridname[1] == 'o' && gridname[2] == 'n' ) /* lon=<LON>_lat=<LAT> */
-    {
-      /* only one gridpoint */
-      pline = &gridname[3];
-      if ( *pline == '=' ) pline++;
-      if ( isdigit((int) *pline) || ispunct((int) *pline) || *pline == '-' )
-	{
-	  grid.type = GRID_LONLAT;
-	  grid.xsize = 1;
-	  grid.ysize = 1;
-	  grid.xvals = (double*) Malloc(sizeof(double));
-	  grid.yvals = (double*) Malloc(sizeof(double));
-	  grid.xvals[0] = atof(pline);
-	  while ( isdigit((int) *pline) || ispunct((int) *pline) || *pline == '-' ) pline++;
-	  if ( *pline == '_' ) pline++;
-	  if ( ! (pline[0] == 'l' &&  pline[1] == 'a' && pline[2] == 't') ) return gridID;
-	  pline += 3;
-	  if ( *pline == '=' ) pline++;
-	  if ( isdigit((int) *pline) || ispunct((int) *pline) || *pline == '-' )
-	    grid.yvals[0] = atof(pline);
-	  else
-	    return gridID;
-	}
-    }
-  else if ( gridname[0] == 'g' && gridname[1] == 'm' && gridname[2] == 'e' ) /* gme<NI> */
-    {
-      pline = &gridname[3];
-      if ( isdigit((int) *pline) )
-	{
-	  long ni = strtol(pline, &endptr, 10);
-	  if ( *endptr == 0 )
-	    {
-	      grid.type = GRID_GME;
-	      grid.ni   = ni;
-	      grid.nd   = 10;
-	      factorni(grid.ni, &grid.ni2, &grid.ni3);
-	      grid.size = (grid.ni+1)*(grid.ni+1)*10;
-	    }
-	}
-    }
-  else if ( gridname[0] == 'n' && gridname[1] == 'i' ) /* ni<NI> */
-    {
-      pline = &gridname[2];
-      if ( isdigit((int) *pline) )
-	{
-	  long ni = strtol(pline, &endptr, 10);
-	  if ( *endptr == 0 )
-	    {
-	      grid.type = GRID_GME;
-	      grid.ni   = ni;
-	      grid.nd   = 10;
-	      factorni(grid.ni, &grid.ni2, &grid.ni3);
-	      grid.size = (grid.ni+1)*(grid.ni+1)*10;
-	    }
-	}
-    }
-  else if ( gridname[0] == 'n' ) /* n<N> */
-    {
-      pline = &gridname[1];
-      if ( isdigit((int) *pline) )
-	{
-	  long np = strtol(pline, &endptr, 10);
-	  pline = endptr;
-
-	  if ( cmpstrlen(pline, "zon",  len) == 0 )
-	    {
-	      grid.xsize = 1;
-	      pline += 3;
-	    }
-	  else if ( *pline == 'b' )
-	    {
-	      grid.genBounds = TRUE;
-	      pline++;
-	    }
-
-	  if ( *pline == 0 )
-	    {
-	      grid.type  = GRID_GAUSSIAN;
-	      grid.np    = np;
-	      grid.ysize = np*2;
-	      if ( !grid.xsize ) grid.xsize = compNlon(grid.ysize);
-
-	      grid.def_xfirst = TRUE;
-	      grid.def_yfirst = TRUE;	      
-	    }
-	}
-    }
-  else if ( gridname[0] == 'g' && isdigit(gridname[1])) /* g<LON>x<LAT> or g<SIZE> */
-    {
-      pline = &gridname[1];
-      if ( isdigit((int) *pline) )
-	{
-	  grid.type = GRID_GENERIC;
-	  grid.xsize = atoi(pline);
-	  while ( isdigit((int) *pline) ) pline++;
-	  if ( *pline )
-	    {
-	      pline++;
-	      grid.ysize = atoi(pline);
-	      while ( isdigit((int) *pline) ) pline++;
-	    }
-	  else if ( grid.xsize == 1 )
-	    {
-	      grid.size  = 1;
-	      grid.xsize = 0;
-	    }
-	}
-    }
-  else if ( strncmp(gridname, "germany", 7) == 0 ) /* germany_Xdeg */
-    {
-      double lon1 =   5.6, lon2 = 15.2;
-      double lat1 =  47.1, lat2 = 55.1;
-      double dll = 0.1;
-
-      pline = &gridname[7];
-
-      gen_grid_lonlat(&grid, pline, dll, lon1, lon2, lat1, lat2);
-    }
-  else if ( strncmp(gridname, "europe", 6) == 0 ) /* europe_Xdeg */
-    {
-      double lon1 = -30, lon2 = 60;
-      double lat1 =  30, lat2 = 80;
-      double dll = 1;
-
-      pline = &gridname[6];
-
-      gen_grid_lonlat(&grid, pline, dll, lon1, lon2, lat1, lat2);
-    }
-  else if ( strncmp(gridname, "africa", 6) == 0 ) /* africa_Xdeg */
-    {
-      double lon1 = -20, lon2 = 60;
-      double lat1 = -40, lat2 = 40;
-      double dll = 1;
-
-      pline = &gridname[6];
-
-      gen_grid_lonlat(&grid, pline, dll, lon1, lon2, lat1, lat2);
-    }
-  else if ( strncmp(gridname, "global", 6) == 0 ) /* global_Xdeg */
-    {
-      double lon1 = -180, lon2 = 180;
-      double lat1 =  -90, lat2 =  90;
-      double dll = 1;
-
-      pline = &gridname[6];
-  
-      gen_grid_lonlat(&grid, pline, dll, lon1, lon2, lat1, lat2);
-    }
-
-  if ( grid.type != -1 ) gridID = gridDefine(grid);
+  if ( grid.xname[0]     ) cdiGridDefKeyStr(gridID, CDI_KEY_XNAME,     strlen(grid.xname)+1, grid.xname);
+  if ( grid.xlongname[0] ) cdiGridDefKeyStr(gridID, CDI_KEY_XLONGNAME, strlen(grid.xlongname)+1, grid.xlongname);
+  if ( grid.xunits[0]    ) cdiGridDefKeyStr(gridID, CDI_KEY_XUNITS,    strlen(grid.xunits)+1, grid.xunits);
+  if ( grid.yname[0]     ) cdiGridDefKeyStr(gridID, CDI_KEY_YNAME,     strlen(grid.yname)+1, grid.yname);
+  if ( grid.ylongname[0] ) cdiGridDefKeyStr(gridID, CDI_KEY_YLONGNAME, strlen(grid.ylongname)+1, grid.ylongname);
+  if ( grid.yunits[0]    ) cdiGridDefKeyStr(gridID, CDI_KEY_YUNITS,    strlen(grid.yunits)+1, grid.yunits);
+  if ( grid.xdimname[0]  ) cdiGridDefKeyStr(gridID, CDI_KEY_XDIMNAME,  strlen(grid.xdimname)+1, grid.xdimname);
+  if ( grid.ydimname[0]  ) cdiGridDefKeyStr(gridID, CDI_KEY_YDIMNAME,  strlen(grid.ydimname)+1, grid.ydimname);
+  if ( grid.vdimname[0]  ) cdiGridDefKeyStr(gridID, CDI_KEY_VDIMNAME,  strlen(grid.vdimname)+1, grid.vdimname);
 
   return gridID;
 }
@@ -1868,7 +436,7 @@ int cdoDefineGrid(const char *gridfile)
   if ( filename )
     lalloc = true;
   else
-    filename =  (char *) gridfile;
+    filename = (char *) gridfile;
 
   int fileno = open(filename, O_RDONLY);
   if ( fileno >= 0 )
@@ -1882,7 +450,7 @@ int cdoDefineGrid(const char *gridfile)
     {
       if ( isreg ) close(fileno);
 
-      gridID = gridFromName(gridfile);
+      gridID = grid_from_name(gridfile);
 
       if ( gridID == -1 ) cdoAbort("Open failed on %s!", gridfile);
     }
@@ -1939,7 +507,7 @@ int cdoDefineGrid(const char *gridfile)
 	  //size_t buffersize = 20*1024*1024;
 	  //char *buffer = (char*) Malloc(buffersize);
 	  //setvbuf(gfp, buffer, _IOFBF, buffersize);
-	  gridID = gridFromFile(gfp, filename);
+	  gridID = grid_read(gfp, filename);
 	  fclose(gfp);
 	  //free(buffer);
 	}
@@ -1948,7 +516,7 @@ int cdoDefineGrid(const char *gridfile)
 	{
 	  if ( cdoDebug ) cdoPrint("grid from PINGO file");
 	  FILE *gfp = fopen(filename, "r");
-	  gridID = gridFromPingo(gfp, filename);
+	  gridID = grid_read_pingo(gfp, filename);
 	  fclose(gfp);
 	}
 
@@ -1961,7 +529,7 @@ int cdoDefineGrid(const char *gridfile)
 }
 
 
-void defineGrid(const char *gridarg)
+void cdo_set_grids(const char *gridarg)
 {
   char gridfile[4096];
   int nfile = 0;
diff --git a/src/griddes.h b/src/griddes.h
index 2e243db..7873dfe 100644
--- a/src/griddes.h
+++ b/src/griddes.h
@@ -1,6 +1,8 @@
 #ifndef _GRIDDES_H
 #define _GRIDDES_H
 
+#include <stdbool.h>
+
 typedef struct {
   int    *mask;
   double *xvals;
@@ -19,38 +21,38 @@ typedef struct {
   double  lat2;
   int     projflag;
   int     scanflag;
-  int     def_originLon;
-  int     def_originLat;
-  int     def_lonParY;
-  int     def_lat1;
-  int     def_lat2;
+  bool    def_originLon;
+  bool    def_originLat;
+  bool    def_lonParY;
+  bool    def_lat1;
+  bool    def_lat2;
   double  a;
   double  lon_0;
   double  lat_0;
   double  lat_1;
   double  lat_2;
-  int     def_lon_0;
-  int     def_lat_0;
-  int     def_lat_1;
-  int     def_lat_2;
+  bool    def_lon_0;
+  bool    def_lat_0;
+  bool    def_lat_1;
+  bool    def_lat_2;
   int     prec;
   int     isRotated;              /* TRUE for rotated grids         */
   int     type;
   int     ntr;
   int    *rowlon;
-  int     genBounds;
+  bool    genBounds;
   int     nvertex;
   long    size;
   int     xsize;
   int     ysize;
   int     np;
   int     lcomplex;
-  int     def_xfirst;
-  int     def_yfirst;
-  int     def_xlast;
-  int     def_ylast;
-  int     def_xinc;
-  int     def_yinc;
+  bool    def_xfirst;
+  bool    def_yfirst;
+  bool    def_xlast;
+  bool    def_ylast;
+  bool    def_xinc;
+  bool    def_yinc;
   int     nd, ni, ni2, ni3;
   int     number, position;
   unsigned char uuid[CDI_UUID_SIZE];
@@ -58,9 +60,12 @@ typedef struct {
   char    xname[CDI_MAX_NAME];
   char    xlongname[CDI_MAX_NAME];
   char    xunits[CDI_MAX_NAME];
+  char    xdimname[CDI_MAX_NAME];
   char    yname[CDI_MAX_NAME];
   char    ylongname[CDI_MAX_NAME];
   char    yunits[CDI_MAX_NAME];
+  char    ydimname[CDI_MAX_NAME];
+  char    vdimname[CDI_MAX_NAME];
 }
 griddes_t;
 
diff --git a/src/griddes_h5.c b/src/griddes_h5.c
index 1725746..f2c6629 100644
--- a/src/griddes_h5.c
+++ b/src/griddes_h5.c
@@ -16,30 +16,29 @@
 
 
 #if defined(HAVE_LIBHDF5)
-static herr_t
-obj_info(hid_t loc_id, const char *name, void *objname)
+static
+herr_t obj_info(hid_t loc_id, const char *name, void *objname)
 {
-  H5G_obj_t obj_type;
-  H5G_stat_t statbuf;
   herr_t lexist = 0;
 
+  H5G_stat_t statbuf;
   H5Gget_objinfo(loc_id, name, FALSE, &statbuf);
 
   if ( strcmp(name, (char *) objname) == 0 )
     {
       lexist = 1;
 
-      obj_type = statbuf.type;
+      H5G_obj_t obj_type = statbuf.type;
 
       switch (obj_type) {
       case H5G_GROUP:
-	if ( cdoVerbose ) cdoPrint(" Object with name %s is a group", name);
+	if ( cdoVerbose ) cdoPrint("HDF5 object '%s' is a group", name);
 	break;
       case H5G_DATASET: 
-	if ( cdoVerbose ) cdoPrint(" Object with name %s is a dataset", name);
+	if ( cdoVerbose ) cdoPrint("HDF5 object '%s' is a dataset", name);
 	break;
       case H5G_TYPE: 
-	if ( cdoVerbose ) cdoPrint(" Object with name %s is a named datatype", name);
+	if ( cdoVerbose ) cdoPrint("HDF5 object '%s' is a named datatype", name);
 	break;
       default:
 	/*cdoAbort(" Unable to identify an object %s", name);*/
@@ -54,13 +53,9 @@ obj_info(hid_t loc_id, const char *name, void *objname)
 
 #if defined(HAVE_LIBHDF5)
 static
-int h5find_object(hid_t file_id, char *name)
+int h5find_object(hid_t file_id, const  char *name)
 {
-  int lexist = 0;
-
-  lexist = (int) H5Giterate(file_id, "/", NULL, obj_info, (void *) name);
-
-  return lexist;
+  return (int) H5Giterate(file_id, "/", NULL, obj_info, (void *) name);
 }
 #endif
 
@@ -69,12 +64,11 @@ void fill_gridvals(int xsize, int ysize, double *xvals, double *yvals)
 {
   int i, j, ii, jj;
   int index, index2;
-  double xmin, xmax, ymin, ymax;
 
-  xmin = -180;
-  xmax =  180;
-  ymin = -90;
-  ymax =  90;
+  double xmin = -180;
+  double xmax =  180;
+  double ymin = -90;
+  double ymax =  90;
 
   for ( ii = 0; ii < xsize/2; ++ii )
     {
@@ -238,10 +232,9 @@ void fill_gridvals(int xsize, int ysize, double *xvals, double *yvals)
 void correct_sinxvals(int xsize, int ysize, double *xvals)
 {
   long i, j, istart, index;
-  double xmin, xmax;
 
-  xmin = -180;
-  xmax =  180;
+  double xmin = -180;
+  double xmax =  180;
 
   for ( j = 0; j < ysize; ++j )
     {
@@ -292,8 +285,6 @@ int gridFromH5file(const char *gridfile)
 {
   int       gridID = -1;
 #if defined(HAVE_LIBHDF5)
-  hid_t     fapl_id = H5P_DEFAULT;
-  hid_t	    file_id;	    /* HDF5 File ID	        	*/
   hid_t	    lon_id = -1;    /* Dataset ID	        	*/
   hid_t	    lat_id = -1;    /* Dataset ID	        	*/
   hid_t     att_id;
@@ -306,15 +297,15 @@ int gridFromH5file(const char *gridfile)
 
   gridInit(&grid);
 
-  fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+  hid_t fapl_id = H5Pcreate(H5P_FILE_ACCESS);
   H5Pset_fclose_degree(fapl_id, H5F_CLOSE_STRONG);
 
   /* Open an existing file. */
-  file_id = H5Fopen(gridfile, H5F_ACC_RDONLY, fapl_id);
+  hid_t file_id = H5Fopen(gridfile, H5F_ACC_RDONLY, fapl_id);
 
   H5Pclose(fapl_id);
 
-  if ( file_id < 0 ) return(gridID);
+  if ( file_id < 0 ) return gridID;
 
   if ( h5find_object(file_id, "lon") > 0 && 
        h5find_object(file_id, "lat") > 0 )
@@ -331,10 +322,6 @@ int gridFromH5file(const char *gridfile)
   
   if ( lon_id >= 0 && lat_id >= 0 )
     {
-      hid_t type_id;
-      hid_t native_type;
-      int ftype = 0;
-
       dataspace = H5Dget_space(lon_id);    /* dataspace handle */
       rank      = H5Sget_simple_extent_ndims(dataspace);
       status    = H5Sget_simple_extent_dims(dataspace, dims_out, NULL);
@@ -345,28 +332,22 @@ int gridFromH5file(const char *gridfile)
 	  goto RETURN;
 	}
 
-      att_id = H5Aopen_name(lon_id, "bounds");
-      if ( att_id >= 0 )
-	{
-	  H5Aclose(att_id);
-	  goto RETURN;
-	}
+      // check for netcdf4 attribute
+      if ( H5Aexists(lon_id, "DIMENSION_LIST") ) goto RETURN;
+      if ( H5Aexists(lat_id, "DIMENSION_LIST") ) goto RETURN;
 
-      att_id = H5Aopen_name(lat_id, "bounds");
-      if ( att_id >= 0 )
-	{
-	  H5Aclose(att_id);
-	  goto RETURN;
-	}
+      if ( H5Aexists(lon_id, "bounds") ) goto RETURN;
+      if ( H5Aexists(lat_id, "bounds") ) goto RETURN;
 
       /*
       printf("\nRank: %d\nDimensions: %lu x %lu \n", rank,
 	     (unsigned long)(dims_out[1]), (unsigned long)(dims_out[0]));
       */
 
-      type_id = H5Dget_type(lon_id);  /* get datatype*/
+      hid_t type_id = H5Dget_type(lon_id);  /* get datatype*/
 
-      native_type = H5Tget_native_type(type_id, H5T_DIR_ASCEND);
+      hid_t native_type = H5Tget_native_type(type_id, H5T_DIR_ASCEND);
+      int ftype = 0;
       if      ( H5Tequal(native_type, H5T_NATIVE_SCHAR)  > 0 ) {ftype=0;}
       else if ( H5Tequal(native_type, H5T_NATIVE_UCHAR)  > 0 ) {ftype=0;}
       else if ( H5Tequal(native_type, H5T_NATIVE_SHORT)  > 0 ) {ftype=0;}
@@ -396,12 +377,11 @@ int gridFromH5file(const char *gridfile)
 	}
       else
 	{
-	  int *iarray, i;
-	  iarray = (int*) Malloc(grid.size*sizeof(int));
+	  int *iarray = (int*) Malloc(grid.size*sizeof(int));
 	  status = H5Dread(lon_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, iarray);
-	  for ( i = 0; i < grid.size; ++i ) grid.xvals[i] = iarray[i];
+	  for ( int 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 ( i = 0; i < grid.size; ++i ) grid.yvals[i] = iarray[i];
+	  for ( int i = 0; i < grid.size; ++i ) grid.yvals[i] = iarray[i];
 	  Free(iarray);
 	}
 
@@ -414,7 +394,7 @@ int gridFromH5file(const char *gridfile)
       fill_gridvals(grid.xsize, grid.ysize, grid.xvals, grid.yvals);
 
       grid.type = GRID_CURVILINEAR;
-      grid.prec = DATATYPE_FLT32;
+      grid.prec = CDI_DATATYPE_FLT32;
 
       gridID = gridDefine(grid);
     }
@@ -472,10 +452,6 @@ int gridFromH5file(const char *gridfile)
 
       if ( lon_id >= 0 && lat_id >= 0 )
 	{
-	  hid_t type_id;
-	  hid_t native_type;
-	  int ftype = 0;
-
 	  dataspace = H5Dget_space(lon_id);    /* dataspace handle */
 	  rank      = H5Sget_simple_extent_ndims(dataspace);
 	  status    = H5Sget_simple_extent_dims(dataspace, dims_out, NULL);
@@ -490,9 +466,10 @@ int gridFromH5file(const char *gridfile)
 		 (unsigned long)(dims_out[1]), (unsigned long)(dims_out[0]));
 	  */
 
-	  type_id = H5Dget_type(lon_id);  /* get datatype*/
+	  hid_t type_id = H5Dget_type(lon_id);  /* get datatype*/
 
-	  native_type = H5Tget_native_type(type_id, H5T_DIR_ASCEND);
+	  hid_t native_type = H5Tget_native_type(type_id, H5T_DIR_ASCEND);
+	  int ftype = 0;
 	  if      ( H5Tequal(native_type, H5T_NATIVE_SCHAR)  > 0 ) {ftype=0;}
 	  else if ( H5Tequal(native_type, H5T_NATIVE_UCHAR)  > 0 ) {ftype=0;}
 	  else if ( H5Tequal(native_type, H5T_NATIVE_SHORT)  > 0 ) {ftype=0;}
@@ -522,12 +499,11 @@ int gridFromH5file(const char *gridfile)
 	    }
 	  else
 	    {
-	      int *iarray, i;
-	      iarray = (int*) Malloc(grid.size*sizeof(int));
+	      int *iarray = (int*) Malloc(grid.size*sizeof(int));
 	      status = H5Dread(lon_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, iarray);
-	      for ( i = 0; i < grid.size; ++i ) grid.xvals[i] = iarray[i];
+	      for ( int 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 ( i = 0; i < grid.size; ++i ) grid.yvals[i] = iarray[i];
+	      for ( int i = 0; i < grid.size; ++i ) grid.yvals[i] = iarray[i];
 	      Free(iarray);
 	    }
 
@@ -541,7 +517,7 @@ int gridFromH5file(const char *gridfile)
 	  for ( i = 0; i < grid.size; ++i ) grid.yvals[i] = grid.yvals[i]*yscale + yoffset;
 
 	  grid.type = GRID_CURVILINEAR;
-	  grid.prec = DATATYPE_FLT32;
+	  grid.prec = CDI_DATATYPE_FLT32;
 
 	  gridID = gridDefine(grid);
 	}
@@ -552,9 +528,13 @@ int gridFromH5file(const char *gridfile)
   /* Close file */
   if ( file_id >= 0 )  status = H5Fclose(file_id);
 
+  (void)status;
+
+  if ( gridID != -1 && cdoVerbose ) cdoPrint("%s: grid created.", __func__);
+
 #else
   cdoWarning("HDF5 support not compiled in!");
 #endif
 
-  return (gridID);
+  return gridID;
 }
diff --git a/src/griddes_nc.c b/src/griddes_nc.c
index 5d185bc..0f07f5b 100644
--- a/src/griddes_nc.c
+++ b/src/griddes_nc.c
@@ -42,7 +42,7 @@ int cdf_openread(const char *filename)
   cdoWarning("NetCDF support not compiled in!");
 #endif
 
-  return (fileID);
+  return fileID;
 }
 
 
@@ -87,7 +87,7 @@ int gridFromNCfile(const char *gridfile)
 	   nc_inq_varid(nc_file_id, "grid_center_lat", &nc_gridlat_id)  != NC_NOERR || 
 	   nc_inq_varid(nc_file_id, "grid_center_lon", &nc_gridlon_id)  != NC_NOERR || 
 	   nc_inq_varid(nc_file_id, "grid_corner_lat", &nc_gridclat_id) != NC_NOERR || 
-	   nc_inq_varid(nc_file_id, "grid_corner_lon", &nc_gridclon_id) != NC_NOERR ) return (gridID);
+	   nc_inq_varid(nc_file_id, "grid_corner_lon", &nc_gridclon_id) != NC_NOERR ) return gridID;
 
       nce(nc_get_var_int(nc_file_id, nc_griddims_id, grid_dims));
 
@@ -115,8 +115,8 @@ int gridFromNCfile(const char *gridfile)
       grid.ybounds = (double*) Malloc(grid.nvertex*grid.size*sizeof(double));
 
       nce(nc_inq_vartype(nc_file_id, nc_gridlat_id, &xtype));
-      if ( xtype == NC_FLOAT )  grid.prec = DATATYPE_FLT32;
-      else                      grid.prec = DATATYPE_FLT64;
+      if ( xtype == NC_FLOAT )  grid.prec = CDI_DATATYPE_FLT32;
+      else                      grid.prec = CDI_DATATYPE_FLT64;
 
       nce(nc_get_var_double(nc_file_id, nc_gridlon_id, grid.xvals));
       nce(nc_get_var_double(nc_file_id, nc_gridlat_id, grid.yvals));
@@ -154,7 +154,7 @@ int gridFromNCfile(const char *gridfile)
   cdoWarning("NetCDF support not compiled in!");
 #endif
 
-  return (gridID);
+  return gridID;
 }
 
 
@@ -185,7 +185,7 @@ void writeNCgrid(const char *gridfile, int gridID, int *grid_imask)
   gridtype = gridInqType(gridID);
   gridsize = gridInqSize(gridID);
 
-  if ( gridInqPrec(gridID) == DATATYPE_FLT64 ) xtype = NC_DOUBLE;
+  if ( gridInqPrec(gridID) == CDI_DATATYPE_FLT64 ) xtype = NC_DOUBLE;
   else                                         xtype = NC_FLOAT;
 
   if ( gridtype == GRID_CURVILINEAR )
diff --git a/src/gridreference.c b/src/gridreference.c
index 5c4d049..a4ed8e5 100644
--- a/src/gridreference.c
+++ b/src/gridreference.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -15,7 +15,7 @@
 */
 
 #if defined(HAVE_CONFIG_H)
-#  include "config.h"
+#include "config.h"
 #endif
 
 #if defined(HAVE_LIBCURL)
@@ -34,8 +34,7 @@
 static
 size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream)
 {
-  size_t written;
-  written = fwrite(ptr, size, nmemb, stream);
+  size_t written = fwrite(ptr, size, nmemb, stream);
   return written;
 }
 #endif
@@ -48,24 +47,20 @@ int download_gridfile(const char *restrict uri, const char *restrict basename)
   // As curl_easy_init calls non-thread safe curl_global_init the libcurl developer advice
   // to call curl_global_init first and before potential thread spawning.
 
-  CURLcode ret;  
-  CURL *hd;
-  double length;
-  int status;
   int curlflags = CURL_GLOBAL_DEFAULT;
 
 #if defined(CURL_GLOBAL_ACK_EINTR)
   curlflags |= CURL_GLOBAL_ACK_EINTR;
 #endif
 
-  ret = curl_global_init(curlflags);
+  CURLcode ret = curl_global_init(curlflags);
   if(ret != 0)
     {
       fprintf(stderr, "ERROR: %s!\n", curl_easy_strerror(ret));
       return -1;
     }
 
-  hd = curl_easy_init();
+  CURL *hd = curl_easy_init();
   if (hd == NULL)
     {
       fprintf(stderr, "ERROR: could not get curl handler.\n");
@@ -73,8 +68,7 @@ int download_gridfile(const char *restrict uri, const char *restrict basename)
     }
   else
     {
-      FILE *fp;
-      fp = fopen(basename, "w");
+      FILE *fp = fopen(basename, "w");
       if (fp == NULL)
 	{
 	  fprintf(stderr, "ERROR: could not open local output file %s. %s.\n", basename, strerror(errno));
@@ -99,20 +93,21 @@ int download_gridfile(const char *restrict uri, const char *restrict basename)
 
 	  if ( strstr(ctype, "html") == NULL ) // no html content
 	    {
+              double length;
 	      curl_easy_getinfo(hd, CURLINFO_SIZE_DOWNLOAD, &length);
 	      if ( cdoVerbose ) cdoPrint("File %s downloaded - size: %.0lf byte", basename, length); 
 	      rval = 0;
 	    }
 	  else
 	    {
-	      status = remove(basename);
+	      int status = remove(basename);
 	      if (status == -1) perror(basename);
 	      if ( cdoVerbose ) cdoPrint("The requested URL was not found on this server!");
 	    }
 	}
       else
 	{
-	  status = remove(basename);
+	  int status = remove(basename);
 	  if (status == -1) perror(basename);
 	  fprintf(stderr, "ERROR: %s. Download %s failed.\n\n", curl_easy_strerror(ret), basename);
 	}
@@ -120,6 +115,9 @@ int download_gridfile(const char *restrict uri, const char *restrict basename)
       curl_easy_cleanup(hd);
     }
 #else
+  (void) uri;
+  (void) basename;
+
   cdoWarning("CURL support not compiled in!");
 #endif  
 
@@ -174,16 +172,16 @@ int referenceToGrid(int gridID1)
     }
   else
     {
-      int lgriduri = TRUE;
+      bool lgriduri = true;
       int status;
       int streamID;
-      int number, position;
+      int position;
 
       char *basename = strrchr(griduri, '/');
       if ( basename == NULL )
 	{
 	  basename = griduri;
-	  lgriduri = FALSE;
+	  lgriduri = false;
 	}
       else
 	{
@@ -225,7 +223,7 @@ int referenceToGrid(int gridID1)
       
 	  gridsize = gridInqSize(gridID1);
 
-	  number = gridInqNumber(gridID1);
+	  // int number = gridInqNumber(gridID1);
 	  position = gridInqPosition(gridID1);
 
 	  streamID = streamOpenRead(gridpath);
@@ -283,5 +281,5 @@ int referenceToGrid(int gridID1)
 	}
     }
 
-  return (gridID2);
+  return gridID2;
 }
diff --git a/src/hetaeta.c b/src/hetaeta.c
index 0611913..3695eb1 100644
--- a/src/hetaeta.c
+++ b/src/hetaeta.c
@@ -11,22 +11,19 @@
 #include "cdo_int.h"
 #include "hetaeta.h"
 
-const double ap0  = 100000.0;
-const double apr  = 101325.0;   /* reference pressure */
-const double aipr = 1.0/101325.0;
+static const double apr  = 101325.0;   /* reference pressure */
+static const double aipr = 1.0/101325.0;
 
-const double p_firef = 40000.0; /* pressure of reference geopotential */
+static const double p_firef = 40000.0; /* pressure of reference geopotential */
 
-const double epsilon = 0.622;
-const double rair    = 287.04;
-const double cpair   = 1004.6;
+static const double epsilon = 0.622;
+static const double rair    = 287.04;
+static const double cpair   = 1004.6;
 
-const double eta_pbl = 0.8;     /* upper limit of BPL eta coordiante */
-
-const double g = 9.81;
+static const double eta_pbl = 0.8;     /* upper limit of BPL eta coordiante */
 
 #if defined(OUTPUT)
-FILE *old, *new;
+static FILE *old, *new;
 #endif
 
 
@@ -76,7 +73,8 @@ double esat(double temperature)
 
 /* Source from INTERA */
 
-void hetaeta_sc(int ltq, int lpsmod, long ij, long ngp, long nlev1, long nlev2, long nvars,
+static
+void hetaeta_sc(bool ltq, int lpsmod, long ij, long ngp, long nlev1, long nlev2, long nvars,
 		const double *restrict af1, const double *restrict bf1, const double *restrict etah2,
 		const double *restrict af2, const double *restrict bf2, const double *restrict w1, 
 		const double *restrict w2, const long *restrict jl1, const long *restrict jl2,
@@ -98,10 +96,7 @@ void hetaeta_sc(int ltq, int lpsmod, long ij, long ngp, long nlev1, long nlev2,
   long klo;
   long jjblt;
   double zq1, zt1;
-  double zdff, zdffl, ztv, zb, zbb, zc, zps;
-  double zsump, zsumpp, zsumt, zsumtp;
   double dfi, fiadj = 0, dteta = 0;
-  double pbl_lim, pbl_lim_need;
 
   double rair_d_cpair = rair/cpair;
 
@@ -111,8 +106,8 @@ void hetaeta_sc(int ltq, int lpsmod, long ij, long ngp, long nlev1, long nlev2,
   /******* initialise atmospheric fields in old system */
   
   /* pressure */
-  ph1[0]       =  0.0;
-  lnph1[0]     = -1.0; 
+  ph1[0]   =  0.0;
+  lnph1[0] = -1.0; 
   for ( k = 1; k < nlev1p1; ++k )
     {
       ph1[k]   = ah1[k]+bh1[k]*ps1[ij];
@@ -173,15 +168,16 @@ void hetaeta_sc(int ltq, int lpsmod, long ij, long ngp, long nlev1, long nlev2,
 	  jlev = k;
 	  if (fis2[ij] < fi1[k]) break;
 	}
-      zdff = fi1[jlev+1]-fis2[ij];
+
+      double zdff = fi1[jlev+1]-fis2[ij];
       
       /* get the number of points used for estimation of regression coefficients */
       jlevr = 0;
       for ( k = jlev-1; k > 0; --k )
 	{
 	  jlevr = k;
-	  zdffl = fi1[k]-fi1[jlev+1];
-	  if (zdffl >= zdff) break;
+	  double zdffl = fi1[k]-fi1[jlev+1];
+	  if ( zdffl >= zdff ) break;
 	}
 
       jnop = jlev+1-jlevr+1;
@@ -190,10 +186,10 @@ void hetaeta_sc(int ltq, int lpsmod, long ij, long ngp, long nlev1, long nlev2,
 	get coefficients of regression between Tv and lnP ::Tv = B*lnP + C
 	using three levels surounding new orography geopotential
       */
-      zsumt  = 0.0;
-      zsump  = 0.0;
-      zsumpp = 0.0;
-      zsumtp = 0.0;
+      double zsumt  = 0.0;
+      double zsump  = 0.0;
+      double zsumpp = 0.0;
+      double zsumtp = 0.0;
 
       for ( k = jlevr; k <= jlev+1; ++k )
 	{
@@ -204,12 +200,12 @@ void hetaeta_sc(int ltq, int lpsmod, long ij, long ngp, long nlev1, long nlev2,
 	}
 
       /* final regression coefficients */
-      zb = jnop*zsumpp - zsump*zsump;
-      zc = (zsumt*zsumpp-zsump*zsumtp)/zb;
+      double zb = jnop*zsumpp - zsump*zsump;
+      double zc = (zsumt*zsumpp-zsump*zsumtp)/zb;
       zb = (jnop*zsumtp-zsump*zsumt)/zb;
 
       /* calculate preliminary surface pressure, adjust to middle level */
-      zps = lnph1[jlev];
+      double zps = lnph1[jlev];
 
       /* calculate preliminary pressure */
       if ( fabs(zb) < 1.0e-20 )
@@ -220,7 +216,7 @@ void hetaeta_sc(int ltq, int lpsmod, long ij, long ngp, long nlev1, long nlev2,
       else
 	{
 	  /* virtual temperatur not constant near new surface */
-	  zbb = zc*zc + zb*(zps*(zb*zps+2.0*zc)+2.0*(fi1[jlev]-fis2[ij])/rair);
+	  double zbb = zc*zc + zb*(zps*(zb*zps+2.0*zc)+2.0*(fi1[jlev]-fis2[ij])/rair);
 	  ps2[ij] = exp((sqrt(zbb)-zc)/zb);
 	}
     }
@@ -263,12 +259,12 @@ void hetaeta_sc(int ltq, int lpsmod, long ij, long ngp, long nlev1, long nlev2,
   /******* find the new boundary layer top */
 
   /* using the pressure from the old system */
-  pbl_lim = ps1[ij]*eta_pbl;
+  double pbl_lim = ps1[ij]*eta_pbl;
   jjblt = nlev2-1;
   for ( k = nlev2-1; k > 0; --k )
     {
       /* find the next upper level in new system */
-      pbl_lim_need = ps2[ij] *etah2[k];
+      double pbl_lim_need = ps2[ij] *etah2[k];
       if (pbl_lim > pbl_lim_need) break;
       jjblt = jjblt-1;
     }
@@ -399,7 +395,7 @@ void hetaeta_sc(int ltq, int lpsmod, long ij, long ngp, long nlev1, long nlev2,
       /* correct surface pressure */
       dfi = fiadj-(fi2[jlev+1]+(fi2[jlev]-fi2[jlev+1])* 
 		   log(ph2[jlev+1]/p_firef)/log(ph2[jlev+1]/ph2[jlev]));
-      ztv     = (1.0+epsm1i*zq2[nlev2-1])*zt2[nlev2-1];
+      double ztv = (1.0+epsm1i*zq2[nlev2-1])*zt2[nlev2-1];
       ps2[ij] = ps2[ij] *exp(dfi/(rair*ztv));
     }
 
@@ -447,15 +443,15 @@ void hetaeta_sc(int ltq, int lpsmod, long ij, long ngp, long nlev1, long nlev2,
 }
 
 
-void hetaeta(int ltq, int ngp, const int *imiss,
-	     int nlev1, const double *restrict ah1, const double *restrict bh1,
-             const double *restrict fis1, const double *restrict ps1, 
-             const double *restrict t1, const double *restrict q1,
-             int nlev2, const double *restrict ah2, const double *restrict bh2, 
-             const double *restrict fis2, double *restrict ps2, 
-             double *restrict t2, double *restrict q2,
-	     int nvars, double *restrict *restrict vars1, double *restrict *restrict vars2,
-	     double *restrict tscor, double *restrict pscor, double *restrict secor)
+void hetaeta(bool ltq, int ngp, const int *imiss,
+	     int nlev1, const double *ah1, const double *bh1,
+             const double *fis1, const double *ps1, 
+             const double *t1, const double *q1,
+             int nlev2, const double *ah2, const double *bh2, 
+             const double *fis2, double *ps2, 
+             double *t2, double *q2,
+	     int nvars, double **vars1, double **vars2,
+	     double *tscor, double *pscor, double *secor)
 {
   double epsm1i;
   long jblt;
@@ -947,7 +943,7 @@ int main (int argc, char *argv[])
   double *vars2[5];
 
   int ij, k;
-  int ltq = 1;
+  bool ltq = true;
 
   double *fis1 = (double*) Malloc(NGP*sizeof(double));
   double *ps1  = (double*) Malloc(NGP*sizeof(double));
diff --git a/src/hetaeta.h b/src/hetaeta.h
index 6cd1d33..e20f072 100644
--- a/src/hetaeta.h
+++ b/src/hetaeta.h
@@ -5,15 +5,16 @@
 #include "config.h"
 #endif
 
-void hetaeta(int ltq, int ngp, const int *imiss,
-	     int nlev1, const double *restrict ah1, const double *restrict bh1,
-             const double *restrict fis1, const double *restrict ps1, 
-             const double *restrict t1, const double *restrict q1,
-             int nlev2, const double *restrict ah2, const double *restrict bh2, 
-             const double *restrict fis2, double *restrict ps2, 
-             double *restrict t2, double *restrict q2,
-	     int nvars, double *restrict *restrict vars1, double *restrict *restrict vars2,
-	     double *restrict tscor, double *restrict pscor,
-	     double *restrict secor);
+#include <stdbool.h>
+
+void hetaeta(bool ltq, int ngp, const int *imiss,
+	     int nlev1, const double *ah1, const double *bh1,
+             const double *fis1, const double *ps1, 
+             const double *t1, const double *q1,
+             int nlev2, const double *ah2, const double *bh2, 
+             const double *fis2, double *ps2, 
+             double *t2, double *q2,
+	     int nvars, double **vars1, double **vars2,
+	     double *tscor, double *pscor, double *secor);
 
 #endif  /* _HETAETA_H */
diff --git a/src/institution.c b/src/institution.c
index 5ceaf5a..93f0f07 100644
--- a/src/institution.c
+++ b/src/institution.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
diff --git a/src/interpol.c b/src/interpol.c
index aaf1867..7a79f76 100644
--- a/src/interpol.c
+++ b/src/interpol.c
@@ -30,7 +30,7 @@ long find_element(double x, long nelem, const double *restrict array)
   if ( array[0] < array[nelem-1] ) // ascending order
     {
       /* return the length of the array if x is out of bounds */
-      if ( x < array[0] || x > array[nelem-1] ) return (nelem);
+      if ( x < array[0] || x > array[nelem-1] ) return nelem;
 
       /* search for the interval in which x fits */
       // implementation: binary search algorithm
@@ -56,7 +56,7 @@ long find_element(double x, long nelem, const double *restrict array)
   else
     {
       /* return the length of the array if x is out of bounds */
-      if ( x < array[nelem-1] || x > array[0] ) return (nelem);
+      if ( x < array[nelem-1] || x > array[0] ) return nelem;
 
       /* search for the interval in which x fits */
       // implementation: binary search algorithm
@@ -82,7 +82,7 @@ long find_element(double x, long nelem, const double *restrict array)
 
   if ( mid > 1 && IS_EQUAL(x,array[mid-1]) ) mid--;
 
-  return (mid);
+  return mid;
 }
 
 /*
@@ -101,7 +101,7 @@ long find_element(double x, long nelem, const double *array)
 	if ( x >= array[ii] && x <= array[ii-1] ) break;
     }
 
-  return (ii);
+  return ii;
 }
 */
 
@@ -118,7 +118,7 @@ int rect_grid_search(long *ii, long *jj, double x, double y, long nxm, long nym,
       if ( *ii < nxm ) lfound = 1;
     }
 
-  return (lfound);
+  return lfound;
 }
 
 
@@ -171,7 +171,7 @@ int rect_grid_search2(long *imin, long *imax, double xmin, double xmax, long nxm
 	}
     }
 
-  return (lfound);
+  return lfound;
 }
 
 
@@ -203,59 +203,30 @@ double intlinarr2p(long nxm, long nym, double **fieldm, const double *xm, const
 }
 
 static
-void rect_find_ij_weights(double plon, double plat, long ii, long jj, const double *restrict xm, const double *restrict ym, double *ig, double *jg)
-{
-  /*
-    wgts[0] = (plon-xm[ii])   * (plat-ym[jj])   / ((xm[ii-1]-xm[ii]) * (ym[jj-1]-ym[jj]));
-    wgts[1] = (plon-xm[ii-1]) * (plat-ym[jj])   / ((xm[ii]-xm[ii-1]) * (ym[jj-1]-ym[jj]));
-    wgts[2] = (plon-xm[ii-1]) * (plat-ym[jj-1]) / ((xm[ii]-xm[ii-1]) * (ym[jj]-ym[jj-1]));
-    wgts[3] = (plon-xm[ii])   * (plat-ym[jj-1]) / ((xm[ii-1]-xm[ii]) * (ym[jj]-ym[jj-1]));
-  */
-  double iw, jw;
-  double wgts0 = (plon-xm[ii])   * (plat-ym[jj])   / ((xm[ii-1]-xm[ii]) * (ym[jj-1]-ym[jj]));
-  double wgts1 = (plon-xm[ii-1]) * (plat-ym[jj])   / ((xm[ii]-xm[ii-1]) * (ym[jj-1]-ym[jj]));
-
-  iw = 1./(wgts0/wgts1 + 1.);
-  jw = 1. - wgts1/iw;
-
-  *ig = iw;
-  *jg = jw;
-}
-
-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)
 {
-  long ii, jj;
-  long gridsize1;
   long nlon1 = nxm;
   double findex = 0;
-  int *grid1_mask = NULL;
 
   if ( lon_is_circular ) nlon1--;
-  gridsize1 = nlon1*nym;
+  long gridsize1 = nlon1*nym;
 
-  grid1_mask = (int*) Calloc(1, gridsize1*sizeof(int));
-  for ( jj = 0; jj < nym; ++jj )
-    for ( ii = 0; ii < nlon1; ++ii )
-      {
-	if ( !DBL_IS_EQUAL(fieldm[jj*nlon1+ii], missval) ) grid1_mask[jj*nlon1+ii] = 1;
-      }
+  bool *grid1_mask = (bool*) Malloc(gridsize1*sizeof(bool));
+  for ( long jj = 0; jj < nym; ++jj )
+    for ( long ii = 0; ii < nlon1; ++ii )
+      grid1_mask[jj*nlon1+ii] = !DBL_IS_EQUAL(fieldm[jj*nlon1+ii], missval);
 
   progressInit();
 
 #if defined(_OPENMP)
 #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) \
-  private(jj,ii)
+  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 )
     {
       int src_add[4];                /*  address for the four source points    */
-      long n;
-      long iix;
-      int lfound;
       int lprogress = 1;
       if ( cdo_omp_get_thread_num() != 0 ) lprogress = 0;
 
@@ -267,11 +238,12 @@ void intlinarr2(double missval, int lon_is_circular,
       findex++;
       if ( lprogress ) progressStatus(0, 1, findex/gridsize2);
 
-      lfound = rect_grid_search(&ii, &jj, x[i], y[i], nxm, nym, xm, ym); 
+      long ii, jj;
+      int lfound = rect_grid_search(&ii, &jj, x[i], y[i], nxm, nym, xm, ym); 
 
       if ( lfound )
 	{
-	  iix = ii;
+	  long 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);
@@ -279,14 +251,13 @@ void intlinarr2(double missval, int lon_is_circular,
 	  src_add[3] = (jj)*nlon1+(iix);
 
 	  /* Check to see if points are missing values */
-	  for ( n = 0; n < 4; ++n )
+	  for ( int n = 0; n < 4; ++n )
 	    if ( ! grid1_mask[src_add[n]] ) lfound = 0;
 	}
 
       if ( lfound )
 	{
 	  double wgts[4];
-
 	  wgts[0] = (x[i]-xm[ii])   * (y[i]-ym[jj])   / ((xm[ii-1]-xm[ii]) * (ym[jj-1]-ym[jj]));
 	  wgts[1] = (x[i]-xm[ii-1]) * (y[i]-ym[jj])   / ((xm[ii]-xm[ii-1]) * (ym[jj-1]-ym[jj]));
 	  wgts[3] = (x[i]-xm[ii-1]) * (y[i]-ym[jj-1]) / ((xm[ii]-xm[ii-1]) * (ym[jj]-ym[jj-1]));
@@ -309,7 +280,7 @@ void intlinarr2(double missval, int lon_is_circular,
 
 	  
 	  field[i] = 0;
-	  for ( n = 0; n < 4; ++n )
+	  for ( int n = 0; n < 4; ++n )
 	    field[i] += fieldm[src_add[n]] * wgts[n];
 	}
     }
@@ -319,342 +290,6 @@ void intlinarr2(double missval, int lon_is_circular,
   if ( grid1_mask ) Free(grid1_mask);
 }
 
-static
-void restrict_boundbox(const double *restrict grid_bound_box, double *restrict bound_box)
-{
-  if ( bound_box[0] < grid_bound_box[0] && bound_box[1] > grid_bound_box[0] ) bound_box[0] = grid_bound_box[0];
-  if ( bound_box[1] > grid_bound_box[1] && bound_box[0] < grid_bound_box[1] ) bound_box[1] = grid_bound_box[1];
-  //  if ( bound_box[2] < grid_bound_box[2] && bound_box[3] > grid_bound_box[2] ) bound_box[2] = grid_bound_box[2];
-  //  if ( bound_box[3] > grid_bound_box[3] && bound_box[2] < grid_bound_box[3] ) bound_box[3] = grid_bound_box[3];
-}
-
-static
-void boundbox_from_corners(long ic, long nc, const double *restrict corner_lon,
-			   const double *restrict corner_lat, double *restrict bound_box)
-{
-  long inc, j;
-  double clon, clat;
-
-  inc = ic*nc;
-  clat = corner_lat[inc];
-  clon = corner_lon[inc];
-
-  bound_box[0] = clat;
-  bound_box[1] = clat;
-  bound_box[2] = clon;
-  bound_box[3] = clon;
-
-  for ( j = 1; j < nc; ++j )
-    {
-      clat = corner_lat[inc+j];
-      clon = corner_lon[inc+j];
-      if ( clat < bound_box[0] ) bound_box[0] = clat;
-      if ( clat > bound_box[1] ) bound_box[1] = clat;
-      if ( clon < bound_box[2] ) bound_box[2] = clon;
-      if ( clon > bound_box[3] ) bound_box[3] = clon;
-    }
-}
-
-#if defined(HAVE_LIBYAC)
-#include "clipping.h"
-#include "area.h"
-#endif
-
-static
-void intconarr2(double missval, int lon_is_circular,
-		long nxm, long nym,  const double *restrict fieldm, const double *restrict xm, const double *restrict ym,
-		long nc2, long gridsize2, double *field, const double *restrict x, const double *restrict y)
-{
-  long ndeps;
-  int *deps;
-  long ii = -1, jj = -1;
-  long gridsize1;
-  long nlon1 = nxm;
-  long nx, ny;
-  double findex = 0;
-  int *grid1_mask = NULL;
-
-  nx = nxm - 1;
-  ny = nym - 1;
-  printf(" nx, ny %ld %ld\n", nx, ny);
-  //if ( lon_is_circular ) nlon1--;
-  gridsize1 = nx*ny;
-
-  deps = (int*) Malloc(gridsize1*sizeof(int));
-
-  grid1_mask = (int*) Calloc(1, gridsize1*sizeof(int));
-  for ( jj = 0; jj < ny; ++jj )
-    for ( ii = 0; ii < nx; ++ii )
-      {
-	if ( !DBL_IS_EQUAL(fieldm[jj*nx+ii], missval) ) grid1_mask[jj*nx+ii] = 1;
-      }
-
-  double grid1_bound_box[4];
-  grid1_bound_box[0] = ym[0];
-  grid1_bound_box[1] = ym[ny];
-  if ( ym[0] > ym[ny] )
-    {
-      grid1_bound_box[0] = ym[ny];
-      grid1_bound_box[1] = ym[0];
-    }
-  grid1_bound_box[2] = xm[0];
-  grid1_bound_box[3] = xm[nx];
- 
-  progressInit();
-
-#if defined(HAVE_LIBYAC)
-  enum edge_type quad_type[] = {GREAT_CIRCLE, GREAT_CIRCLE, GREAT_CIRCLE, GREAT_CIRCLE}; // not used !
-  // enum edge_type quad_type[] = {LON_CIRCLE, LON_CIRCLE, LON_CIRCLE, LON_CIRCLE};
-
-  int n;
-  double weight_sum;
-
-  double *weight;
-  weight = (double*) Malloc(gridsize1*sizeof(double));
-
-  double tgt_area;
-  double *area;
-  area = (double*) Malloc(gridsize1*sizeof(double));
-
-  struct grid_cell *SourceCell;
-  SourceCell = (struct grid_cell*) Malloc(gridsize1  * sizeof(struct grid_cell));
-
-  for ( int n = 0; n <  gridsize1; n++ ) {
-    SourceCell[n].num_corners   = 4;
-    SourceCell[n].edge_type     = quad_type;
-    SourceCell[n].coordinates_x = (double*) Malloc(4 * sizeof(double));
-    SourceCell[n].coordinates_y = (double*) Malloc(4 * sizeof(double));
-  }
-
-  struct grid_cell  TargetCell;
-
-  TargetCell.num_corners   = nc2;
-  TargetCell.edge_type     = quad_type;
-  TargetCell.coordinates_x = (double*) Malloc(nc2 * sizeof(double));
-  TargetCell.coordinates_y = (double*) Malloc(nc2 * sizeof(double));
-
-  unsigned const * curr_deps;
-#endif
-
-  /*
-#if defined(_OPENMP)
-#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, nc2) \
-  private(jj, ii)
-#endif
-  */
-  for ( int i = 0; i < gridsize2; ++i )
-    {
-      int src_add[4];                /*  address for the four source points    */
-      long n;
-      long iix;
-      int lfound;
-      int lprogress = 1;
-      ndeps = 0;
-      /*
-#if defined(_OPENMP)
-      if ( cdo_omp_get_thread_num() != 0 ) lprogress = 0;
-#endif
-      */
-      field[i] = missval;
-      
-      // printf("%ld lonb: %g %g %g %g latb: %g %g %g %g\n", i+1, x[i*nc2]*RAD2DEG, x[i*nc2+1]*RAD2DEG, x[i*nc2+2]*RAD2DEG, x[i*nc2+3]*RAD2DEG, y[i*nc2]*RAD2DEG, y[i*nc2+1]*RAD2DEG, y[i*nc2+2]*RAD2DEG, y[i*nc2+3]*RAD2DEG);
-
-
-      double bound_lon1, bound_lon2;
-      double bound_box[4];
-      boundbox_from_corners(i, nc2, x, y, bound_box);
-      restrict_boundbox(grid1_bound_box, bound_box);
-      bound_lon1 = bound_box[2];
-      bound_lon2 = bound_box[3];
-      //printf("bound_box %ld  lon: %g %g lat: %g %g\n", i, bound_box[2]*RAD2DEG, bound_box[3]*RAD2DEG, bound_box[0]*RAD2DEG, bound_box[1]*RAD2DEG);
-      /*
-#if defined(_OPENMP)
-#include "pragma_omp_atomic_update.h"
-#endif
-      */
-      findex++;
-      if ( lprogress ) progressStatus(0, 1, findex/gridsize2);
-
-      //      lfound = rect_grid_search(&ii, &jj, x[i], y[i], nxm, nym, xm, ym);
-      //     for ( int k = 0; k < nxm; ++k ) printf("x: %d %g\n", k+1, xm[k]);
-      //    for ( int k = 0; k < nym; ++k ) printf("y: %d %g\n", k+1, ym[k]*RAD2DEG);
-      long imin = nxm, imax = -1, jmin = nym, jmax = -1;
-      long im, jm;
-
-      lfound = rect_grid_search2(&jmin, &jmax, bound_box[0], bound_box[1], nym, ym);
-      bound_lon1 = bound_box[2];
-      bound_lon2 = bound_box[3];
-      if ( bound_lon1 <= grid1_bound_box[3] && bound_lon2 >= grid1_bound_box[2] )
-	{
-	  //printf("b1 %g %g\n", bound_lon1*RAD2DEG, bound_lon2*RAD2DEG);
-	  if ( bound_lon1 < grid1_bound_box[2] && bound_lon2 > grid1_bound_box[2] ) bound_lon1 = grid1_bound_box[2];
-	  if ( bound_lon2 > grid1_bound_box[3] && bound_lon1 < grid1_bound_box[3] ) bound_lon2 = grid1_bound_box[3];
-	  lfound = rect_grid_search2(&imin, &imax, bound_lon1, bound_lon2, nxm, xm);
-	  //printf("imin %ld  imax %ld  jmin %ld jmax %ld\n", imin, imax, jmin, jmax);
-	  for ( jm = jmin; jm <= jmax; ++jm )
-	    for ( im = imin; im <= imax; ++im )
-	      deps[ndeps++] = jm*nx + im;
-	}
-
-
-      bound_lon1 = bound_box[2];
-      bound_lon2 = bound_box[3];
-      if ( bound_lon1 <= grid1_bound_box[2] && bound_lon2 > grid1_bound_box[2] )
-	{
-	  bound_lon1 += 2*M_PI;
-	  bound_lon2 += 2*M_PI;
-	  //printf("b2 %g %g\n", bound_lon1*RAD2DEG, bound_lon2*RAD2DEG);
-	  if ( bound_lon1 < grid1_bound_box[2] && bound_lon2 > grid1_bound_box[2] ) bound_lon1 = grid1_bound_box[2];
-	  if ( bound_lon2 > grid1_bound_box[3] && bound_lon1 < grid1_bound_box[3] ) bound_lon2 = grid1_bound_box[3];
-	  lfound = rect_grid_search2(&imin, &imax, bound_lon1, bound_lon2, nxm, xm);
-	  //printf("imin %ld  imax %ld  jmin %ld jmax %ld\n", imin, imax, jmin, jmax);
-	  for ( jm = jmin; jm <= jmax; ++jm )
-	    for ( im = imin; im <= imax; ++im )
-	      deps[ndeps++] = jm*nx + im;
-	}
-
-      bound_lon1 = bound_box[2];
-      bound_lon2 = bound_box[3];
-      if ( bound_lon1 < grid1_bound_box[3] && bound_lon2 >= grid1_bound_box[3] )
-	{
-	  bound_lon1 -= 2*M_PI;
-	  bound_lon2 -= 2*M_PI;
-	  //printf("b3 %g %g\n", bound_lon1*RAD2DEG, bound_lon2*RAD2DEG);
-	  if ( bound_lon1 < grid1_bound_box[2] && bound_lon2 > grid1_bound_box[2] ) bound_lon1 = grid1_bound_box[2];
-	  if ( bound_lon2 > grid1_bound_box[3] && bound_lon1 < grid1_bound_box[3] ) bound_lon2 = grid1_bound_box[3];
-	  lfound = rect_grid_search2(&imin, &imax, bound_lon1, bound_lon2, nxm, xm);
-	  //printf("imin %ld  imax %ld  jmin %ld jmax %ld\n", imin, imax, jmin, jmax);
-	  for ( jm = jmin; jm <= jmax; ++jm )
-	    for ( im = imin; im <= imax; ++im )
-	      deps[ndeps++] = jm*nx + im;
-	}
-
-      //for ( long id = 0; id < ndeps; ++id )
-	//	printf("dep %ld %d\n", id+1, deps[id]);
-      /*
-      if ( bound_lon1 < grid1_bound_box[2] && bound_box[3] >= grid1_bound_box[2] )
-	lfound = rect_grid_search2(&imin, &imax, bound_box[2], bound_box[3], nxm, xm);
-      */
-
-#if defined(HAVE_LIBYAC)
-      int index2 = i;
-      /*
-      int ilat2 = index2/nlonOut;
-      int ilon2 = index2 - ilat2*nlonOut;
-      */
-      double addtest = 0;
-      //if ( i == 296 ) addtest = 360*DEG2RAD;
-      for ( int ic = 0; ic < nc2; ++ic )
-	{
-	  TargetCell.coordinates_x[ic] =  addtest+x[index2*nc2+ic];
-	  TargetCell.coordinates_y[ic] =          y[index2*nc2+ic];
-	}
-
-      if ( cdoVerbose )
-	{
-	  printf("target:       ");
-	  for ( int n = 0; n < nc2; ++n )
-	    printf(" %g %g", TargetCell.coordinates_x[n]/DEG2RAD, TargetCell.coordinates_y[n]/DEG2RAD);
-	  printf("\n");
-	}
-      /*
-      if ( cdoVerbose )
-	printf("num_deps_per_element %d %d\n", i, ndeps);
-      */
-      int num_deps = ndeps;
-      int nSourceCells = num_deps;
-
-      for ( int k = 0; k < num_deps; ++k )
-	{
-	  int index1 = deps[k];
-	  int ilat1 = index1/nx;
-	  int ilon1 = index1 - ilat1*nx;
-	  /*
-	  if ( cdoVerbose )
-	    printf("  dep: %d %d %d %d %d %d\n", k, nlonOut, nlatOut, index1, ilon1, ilat1);
-	  */
-	  if ( ym[ilat1] < ym[ilat1+1] )
-	    {
-	      SourceCell[k].coordinates_x[0] =  addtest+xm[ilon1];
-	      SourceCell[k].coordinates_y[0] =          ym[ilat1];
-	      SourceCell[k].coordinates_x[1] =  addtest+xm[ilon1+1];
-	      SourceCell[k].coordinates_y[1] =          ym[ilat1];
-	      SourceCell[k].coordinates_x[2] =  addtest+xm[ilon1+1];
-	      SourceCell[k].coordinates_y[2] =          ym[ilat1+1];
-	      SourceCell[k].coordinates_x[3] =  addtest+xm[ilon1];
-	      SourceCell[k].coordinates_y[3] =          ym[ilat1+1];
-	    }
-	  else
-	    {
-	      SourceCell[k].coordinates_x[0] =  addtest+xm[ilon1];
-	      SourceCell[k].coordinates_y[0] =          ym[ilat1+1];
-	      SourceCell[k].coordinates_x[1] =  addtest+xm[ilon1+1];
-	      SourceCell[k].coordinates_y[1] =          ym[ilat1+1];
-	      SourceCell[k].coordinates_x[2] =  addtest+xm[ilon1+1];
-	      SourceCell[k].coordinates_y[2] =          ym[ilat1];
-	      SourceCell[k].coordinates_x[3] =  addtest+xm[ilon1];
-	      SourceCell[k].coordinates_y[3] =          ym[ilat1];
-	    }
-	  if ( cdoVerbose )
-	    {
-	      printf("source: %d %d", num_deps, k);
-	      for ( int n = 0; n < 4; ++n )
-		printf(" %g %g", SourceCell[k].coordinates_x[n]/DEG2RAD, SourceCell[k].coordinates_y[n]/DEG2RAD);
-	      printf("\n");
-	    }
-	}
-      
-      compute_overlap_areas ( nSourceCells, SourceCell, TargetCell, area);
-
-      tgt_area = huiliers_area(TargetCell);
-      // tgt_area = cell_area(TargetCell);
-      for (n = 0; n < nSourceCells; ++n)
-	weight[n] = area[n] / tgt_area;
-
-      correct_weights ( nSourceCells, weight );
-
-      field[i] = missval;
-      if ( num_deps ) field[i] = 0;
-      for ( int k = 0; k < num_deps; ++k )
-	{
-	  int index1 = deps[k];
-	  /*
-	  int ilat1 = index1/nx;
-	  int ilon1 = index1 - ilat1*nx;
-	  long add1, add2;
-
-	  add1 = index1;
-	  add2 = index2;
-
-	  yar_store_link_cnsrv(&remap.vars, add1, add2, weight[k]);
-	  */
-	  if ( weight[k] > 0 )
-	    {
-	      if ( cdoVerbose )
-		printf("tgt_cell_add %ld, src_cell_add %ld,  weight[n] %g, tgt_area  %g\n", i, index1,  weight[k], tgt_area);
-	      //printf("tgt_cell_add %ld, n %ld, src_cell_add %ld,  weight[n] %g, tgt_area  %g\n", i, k, index1,  weight[k], tgt_area);
-	      field[i] += fieldm[index1] * weight[k];
-	    }
-	  /*
-	  if ( cdoVerbose )
-	    printf("  result dep: %ld %d %d  %g\n", i, k, index1, weight[k]);
-	  */
-	}
-#endif
-    }
- 
-#if defined(HAVE_LIBYAC)
-  Free(weight);
-  Free(area);
-#endif
-
-  if ( findex < gridsize2 ) progressStatus(0, 1, 1);
-
-  if ( deps ) Free(deps);
-  if ( grid1_mask ) Free(grid1_mask);
-}
-
 
 double intlin(double x, double y1, double x1, double y2, double x2)
 {
@@ -663,11 +298,9 @@ double intlin(double x, double y1, double x1, double y2, double x2)
 
     Uwe Schulzweida  04/05/1995
   */
-  double value;
-  
-  value = (y2*(x-x1)+y1*(x2-x)) / (x2-x1);
+  double value = (y2*(x-x1)+y1*(x2-x)) / (x2-x1);
 
-  return (value);
+  return value;
 }
 
 
@@ -678,28 +311,22 @@ void intlinarr(long nxm, double *ym, double *xm, int nx, double *y, double *x)
 
     Uwe Schulzweida  04/05/1995
   */
-  long j, jj;
-
-  for ( jj = 1; jj < nxm; jj++ )
-    for ( j = 0; j < nx; j++ )
+  for ( long jj = 1; jj < nxm; jj++ )
+    for ( long j = 0; j < nx; j++ )
       if ( x[j] >= xm[jj-1] && x[j] <= xm[jj] )
 	y[j] = intlin(x[j], ym[jj-1], xm[jj-1], ym[jj], xm[jj]);
 }
 
 
-void intgridbil(field_t *field1, field_t *field2)
+void intgridbil(field_type *field1, field_type *field2)
 {
-  char units[CDI_MAX_NAME];
-
+  char xunits[CDI_MAX_NAME];
   int gridID1 = field1->grid;
   int gridID2 = field2->grid;
   double *array1 = field1->ptr;
   double *array2 = field2->ptr;
   double missval = field1->missval;
 
-  int gridtype1 = gridInqType(gridID1);
-  int gridtype2 = gridInqType(gridID2);
-
   int nlon1 = gridInqXsize(gridID1);
   int nlat1 = gridInqYsize(gridID1);
 
@@ -731,10 +358,10 @@ void intgridbil(field_t *field1, field_t *field2)
     {
       if ( lon_is_circular ) lon1[nlon1-1] = 0;
 
-      gridInqXunits(gridID1, units);
+      gridInqXunits(gridID1, xunits);
 
-      grid_to_radian(units, nlon1, lon1, "grid1 center lon"); 
-      grid_to_radian(units, nlat1, lat1, "grid1 center lat"); 
+      grid_to_radian(xunits, nlon1, lon1, "grid1 center lon"); 
+      grid_to_radian(xunits, nlat1, lat1, "grid1 center lat"); 
 
       if ( lon_is_circular ) lon1[nlon1-1] = lon1[0] + 2*M_PI;
     }
@@ -745,14 +372,13 @@ void intgridbil(field_t *field1, field_t *field2)
   if ( xsize2 == 1 && ysize2 == 1 )
     {
       double lon2, lat2;
-
       gridInqXvals(gridID2, &lon2);
       gridInqYvals(gridID2, &lat2);
 
-      gridInqXunits(gridID2, units);
+      gridInqXunits(gridID2, xunits);
 
-      grid_to_radian(units, xsize2, &lon2, "grid2 center lon"); 
-      grid_to_radian(units, ysize2, &lat2, "grid2 center lat"); 
+      grid_to_radian(xunits, xsize2, &lon2, "grid2 center lon"); 
+      grid_to_radian(xunits, ysize2, &lat2, "grid2 center lat"); 
 
       if ( lon2 < lon1[0] ) lon2 += 2*M_PI;
 
@@ -810,10 +436,10 @@ void intgridbil(field_t *field1, field_t *field2)
           gridInqXvals(gridID2, xvals2);
           gridInqYvals(gridID2, yvals2);
 
-          gridInqXunits(gridID2, units);
+          gridInqXunits(gridID2, xunits);
           
-          grid_to_radian(units, gridsize2, xvals2, "grid2 center lon"); 
-          grid_to_radian(units, gridsize2, yvals2, "grid2 center lat"); 
+          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 )
             {
@@ -859,135 +485,8 @@ void intgridbil(field_t *field1, field_t *field2)
   Free(array1_2D);
 }
 
-
-void intgridcon(field_t *field1, field_t *field2)
-{
-  int nlon1, nlat1;
-  int nlon1b, nlat1b;
-  int nlon2, nlat2;
-  int ilat;
-  int gridID1, gridID2;
-  int i, nmiss;
-  int lon_is_circular;
-  double *lon1, *lat1;
-  double *lon1bounds, *lat1bounds;
-  double **field;
-  double *array = NULL;
-  double *array1, *array2;
-  double missval;
-  char units[CDI_MAX_NAME];
-  /* static int index = 0; */
-
-  gridID1 = field1->grid;
-  gridID2 = field2->grid;
-  array1  = field1->ptr;
-  array2  = field2->ptr;
-  missval = field1->missval;
-
-  if ( ! (gridInqXvals(gridID1, NULL) && gridInqYvals(gridID1, NULL)) )
-    cdoAbort("Source grid has no values");
-
-  lon_is_circular = gridIsCircular(gridID1);
-
-  nlon1 = gridInqXsize(gridID1);
-  nlat1 = gridInqYsize(gridID1);
-
-  lon1 = (double*) Malloc(nlon1*sizeof(double));
-  lat1 = (double*) Malloc(nlat1*sizeof(double));
-  gridInqXvals(gridID1, lon1);
-  gridInqYvals(gridID1, lat1);
-
-  gridInqXunits(gridID1, units);
-
-  grid_to_radian(units, nlon1, lon1, "grid1 center lon"); 
-  grid_to_radian(units, nlat1, lat1, "grid1 center lat"); 
-
-  nlon1b = nlon1 + 1;
-  nlat1b = nlat1 + 1;
-  lon1bounds = (double*) Malloc(nlon1b*sizeof(double));
-  lat1bounds = (double*) Malloc(nlat1b*sizeof(double));
-
-  grid_gen_corners(nlon1, lon1, lon1bounds);
-  grid_gen_corners(nlat1, lat1, lat1bounds);
-
-  if ( cdoVerbose )
-    {
-      for ( int i = 0; i < nlat1; ++i )
-	printf("lat1 %d %g\n", i+1, lat1[i]*RAD2DEG);
-      printf("lat1bounds: %g %g %g ... %g %g %g\n", lat1bounds[0]*RAD2DEG, lat1bounds[1]*RAD2DEG, lat1bounds[2]*RAD2DEG, lat1bounds[nlat1b-3]*RAD2DEG, lat1bounds[nlat1b-2]*RAD2DEG, lat1bounds[nlat1b-1]*RAD2DEG);
-      printf("lon1bounds: %g %g %g ... %g %g %g\n", lon1bounds[0]*RAD2DEG, lon1bounds[1]*RAD2DEG, lon1bounds[2]*RAD2DEG, lon1bounds[nlon1b-3]*RAD2DEG, lon1bounds[nlon1b-2]*RAD2DEG, lon1bounds[nlon1b-1]*RAD2DEG);
-    }
-
-  nlon2 = gridInqXsize(gridID2);
-  nlat2 = gridInqYsize(gridID2);
-
-  int gridsize2;
-
-  if ( gridInqType(gridID2) == GRID_GME ) gridID2 = gridToUnstructured(gridID2, 0);
-
-  if ( gridInqType(gridID2) != GRID_UNSTRUCTURED && gridInqType(gridID2) != GRID_CURVILINEAR )
-    gridID2 = gridToCurvilinear(gridID2, 0);
-
-  if ( ! (gridInqXvals(gridID2, NULL) && gridInqYvals(gridID2, NULL)) )
-    cdoAbort("Target grid has no values");
-
-  gridsize2 = gridInqSize(gridID2);
-
-  int nc2;
-
-  if ( gridInqType(gridID2) == GRID_UNSTRUCTURED )
-    nc2 = gridInqNvertex(gridID2);
-  else
-    nc2 = 4;
-
-  double *grid2_corner_lon = NULL, *grid2_corner_lat = NULL;
-
-  if ( gridInqYbounds(gridID2, NULL) && gridInqXbounds(gridID2, NULL) )
-    {
-      grid2_corner_lon = (double*) Malloc(nc2*gridsize2*sizeof(double));
-      grid2_corner_lat = (double*) Malloc(nc2*gridsize2*sizeof(double));
-      gridInqXbounds(gridID2, grid2_corner_lon);
-      gridInqYbounds(gridID2, grid2_corner_lat);
-    }
-  else
-    {
-      cdoAbort("grid2 corner missing!");
-    }
- 
-  gridInqXunits(gridID2, units);
-
-  grid_to_radian(units, nc2*gridsize2, grid2_corner_lon, "grid2 corner lon"); 
-  grid_to_radian(units, nc2*gridsize2, grid2_corner_lat, "grid2 corner lat"); 
-  /*
-  for ( int i = 0; i < gridsize2; ++i )
-    {
-      if ( lon2[i] < lon1[0]       ) lon2[i] += 2*M_PI;
-      if ( lon2[i] > lon1[nlon1-1] ) lon2[i] -= 2*M_PI;
-    }
-  */
-  for ( i = 0; i < gridsize2; ++i ) array2[i] = missval;
-
-  intconarr2(missval, lon_is_circular, 
-	     nlon1b, nlat1b, array1, lon1bounds, lat1bounds,
-	     nc2, gridsize2, array2, grid2_corner_lon, grid2_corner_lat);
-
-  nmiss = 0;
-  for ( i = 0; i < gridsize2; ++i )
-    if ( DBL_IS_EQUAL(array2[i], missval) ) nmiss++;
-
-  field2->nmiss = nmiss;
-
-  if (grid2_corner_lon) Free(grid2_corner_lon);
-  if (grid2_corner_lat) Free(grid2_corner_lat);
-
-  if (array) Free(array);
-  Free(lon1);
-  Free(lat1);
-}
-
-
 /* source code from pingo */
-void interpolate(field_t *field1, field_t *field2)
+void interpolate(field_type *field1, field_type *field2)
 {
   int i;
   double *lono_array, *lato_array, *lono, *lato;
diff --git a/src/interpol.h b/src/interpol.h
index 9328198..0971f54 100644
--- a/src/interpol.h
+++ b/src/interpol.h
@@ -1,4 +1,4 @@
 
-void intgridbil(field_t *field1, field_t *field2);
-void intgridcon(field_t *field1, field_t *field2);
-void interpolate(field_t *field1, field_t *field2);
+void intgridbil(field_type *field1, field_type *field2);
+void intgridcon(field_type *field1, field_type *field2);
+void interpolate(field_type *field1, field_type *field2);
diff --git a/src/json/jsmn.c b/src/json/jsmn.c
new file mode 100644
index 0000000..22aa8d5
--- /dev/null
+++ b/src/json/jsmn.c
@@ -0,0 +1,331 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "jsmn.h"
+
+static
+void jsmn_init(jsmn_parser *parser)
+{
+  parser->tokens = NULL;
+  parser->num_tokens = 0;
+  parser->toksuper = -1;
+  parser->toknext = 0;
+  parser->pos = 0;
+  parser->lineno = 0;
+}
+
+
+jsmn_parser *jsmn_new(void)
+{
+  jsmn_parser *parser = (jsmn_parser *) malloc(sizeof(jsmn_parser));
+  jsmn_init(parser);
+
+  return parser;
+}
+
+
+void jsmn_destroy(jsmn_parser *parser)
+{
+  if ( parser )
+    {
+      if ( parser->tokens ) free(parser->tokens);
+      jsmn_init(parser);
+      free(parser);
+    }
+}
+
+/**
+ * Allocates a fresh unused token from the token pull.
+ */
+static
+jsmntok_t *jsmn_alloc_token(jsmn_parser *parser)
+{
+  const unsigned int TOK_MEM_INCR = 64;
+
+  if ( parser->toknext >= parser->num_tokens )
+    {
+      parser->num_tokens += TOK_MEM_INCR;
+      parser->tokens = (jsmntok_t *) realloc(parser->tokens, sizeof(jsmntok_t) * parser->num_tokens);
+      if ( parser->tokens == NULL )
+        {
+          fprintf(stderr, "%s: Failed to allocated more memory!", __func__);
+          exit(-1);
+        }
+    }
+
+  jsmntok_t *tok = &parser->tokens[parser->toknext++];
+  tok->start = tok->end = -1;
+  tok->size = 0;
+#ifdef JSMN_PARENT_LINKS
+  tok->parent = -1;
+#endif
+  
+  return tok;
+}
+
+/**
+ * Fills token type and boundaries.
+ */
+static
+void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, int start, int end)
+{
+  token->type = type;
+  token->start = start;
+  token->end = end;
+  token->size = 0;
+}
+
+// Fills next available token with JSON primitive.
+static
+int jsmn_parse_primitive(jsmn_parser *parser, const char *js, size_t len)
+{
+  jsmntok_t *token;
+  int start = parser->pos;
+
+  for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++)
+    {
+      switch (js[parser->pos])
+        {
+#ifndef JSMN_STRICT
+        /* In strict mode primitive must be followed by "," or "}" or "]" */
+        case ':':
+#endif
+        case '\t' : case '\r' : case '\n' : case ' ' :
+        case ','  : case ']'  : case '}' :
+          goto found;
+        }
+      if (js[parser->pos] < 32 || js[parser->pos] >= 127)
+        {
+          parser->pos = start;
+          return JSMN_ERROR_INVAL;
+        }
+    }
+#ifdef JSMN_STRICT
+  /* In strict mode primitive must be followed by a comma/object/array */
+  parser->pos = start;
+  return JSMN_ERROR_PART;
+#endif
+
+found:
+
+  token = jsmn_alloc_token(parser);
+  jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
+#ifdef JSMN_PARENT_LINKS
+  token->parent = parser->toksuper;
+#endif
+  parser->pos--;
+
+  return 0;
+}
+
+/**
+ * Fills next token with JSON string.
+ */
+static int jsmn_parse_string(jsmn_parser *parser, const char *js, size_t len)
+{
+  jsmntok_t *token;
+  int start = parser->pos;
+
+  parser->pos++;
+
+  /* Skip starting quote */
+  for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++)
+    {
+      char c = js[parser->pos];
+
+      /* Quote: end of string */
+      if (c == '\"')
+        {
+          token = jsmn_alloc_token(parser);
+          jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
+#ifdef JSMN_PARENT_LINKS
+          token->parent = parser->toksuper;
+#endif
+          return 0;
+        }
+
+      /* Backslash: Quoted symbol expected */
+      if (c == '\\' && parser->pos + 1 < len)
+        {
+          parser->pos++;
+          switch (js[parser->pos]) {
+            /* Allowed escaped symbols */
+          case '\"': case '/' : case '\\' : case 'b' :
+          case 'f' : case 'r' : case 'n'  : case 't' :
+            break;
+            /* Allows escaped symbol \uXXXX */
+          case 'u':
+            parser->pos++;
+            for(int i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++)
+              {
+                /* If it isn't a hex character we have an error */
+                if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
+                     (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
+                     (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
+                  parser->pos = start;
+                  return JSMN_ERROR_INVAL;
+                }
+                parser->pos++;
+              }
+            parser->pos--;
+            break;
+            /* Unexpected symbol */
+          default:
+            parser->pos = start;
+            return JSMN_ERROR_INVAL;
+          }
+        }
+    }
+  parser->pos = start;
+  return JSMN_ERROR_PART;
+}
+
+// Parse JSON string and fill tokens.
+int jsmn_parse(jsmn_parser *parser, const char *js, size_t len)
+{
+  int r;
+  int i;
+  jsmntok_t *token;
+
+  parser->lineno = 1;
+
+  for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++)
+    {
+      jsmntype_t type;
+
+      char c = js[parser->pos];
+      switch (c)
+        {
+        case '{': case '[':
+          token = jsmn_alloc_token(parser);
+          if (parser->toksuper != -1)
+            {
+              parser->tokens[parser->toksuper].size++;
+#ifdef JSMN_PARENT_LINKS
+              token->parent = parser->toksuper;
+#endif
+            }
+          token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
+          token->start = parser->pos;
+          parser->toksuper = parser->toknext - 1;
+          break;
+        case '}': case ']':
+          type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
+#ifdef JSMN_PARENT_LINKS
+          if (parser->toknext < 1) return JSMN_ERROR_INVAL;
+          token = &parser->tokens[parser->toknext - 1];
+          for (;;)
+            {
+              if (token->start != -1 && token->end == -1)
+                {
+                  if (token->type != type) return JSMN_ERROR_INVAL;
+                  token->end = parser->pos + 1;
+                  parser->toksuper = token->parent;
+                  break;
+                }
+              if (token->parent == -1)
+                {
+                  if (token->type != type || parser->toksuper == -1) return JSMN_ERROR_INVAL;
+                  break;
+                }
+              token = &parser->tokens[token->parent];
+            }
+#else
+          for (i = parser->toknext - 1; i >= 0; i--)
+            {
+              token = &parser->tokens[i];
+              if (token->start != -1 && token->end == -1)
+                {
+                  if (token->type != type) return JSMN_ERROR_INVAL;
+                  parser->toksuper = -1;
+                  token->end = parser->pos + 1;
+                  break;
+                }
+            }
+          /* Error if unmatched closing bracket */
+          if (i == -1) return JSMN_ERROR_INVAL;
+          for (; i >= 0; i--)
+            {
+              token = &parser->tokens[i];
+              if (token->start != -1 && token->end == -1) {
+                parser->toksuper = i;
+                break;
+              }
+            }
+#endif
+          break;
+        case '\"':
+          r = jsmn_parse_string(parser, js, len);
+          if (r < 0) return r;
+          if ( parser->toksuper != -1 )
+            parser->tokens[parser->toksuper].size++;
+          break;
+        case '\r':
+          if ( parser->pos+1 < len && js[parser->pos+1] == '\n' ) parser->pos++;
+        case '\n':
+          parser->lineno++;
+          break;
+        case '\t': case ' ':
+          break;
+        case ':':
+          parser->toksuper = parser->toknext - 1;
+          break;
+        case ',':
+          if (parser->toksuper != -1 &&
+              parser->tokens[parser->toksuper].type != JSMN_ARRAY &&
+              parser->tokens[parser->toksuper].type != JSMN_OBJECT)
+            {
+#ifdef JSMN_PARENT_LINKS
+              parser->toksuper = parser->tokens[parser->toksuper].parent;
+#else
+              for (i = parser->toknext - 1; i >= 0; i--)
+                {
+                  if (parser->tokens[i].type == JSMN_ARRAY || parser->tokens[i].type == JSMN_OBJECT)
+                    {
+                      if (parser->tokens[i].start != -1 && parser->tokens[i].end == -1)
+                        {
+                          parser->toksuper = i;
+                          break;
+                        }
+                    }
+                }
+#endif
+            }
+          break;
+#ifdef JSMN_STRICT
+          /* In strict mode primitives are: numbers and booleans */
+        case '-': case '0': case '1' : case '2': case '3' : case '4':
+        case '5': case '6': case '7' : case '8': case '9':
+        case 't': case 'f': case 'n' :
+          /* And they must not be keys of the object */
+          if (parser->toksuper != -1)
+            {
+              jsmntok_t *t = &parser->tokens[parser->toksuper];
+              if (t->type == JSMN_OBJECT || (t->type == JSMN_STRING && t->size != 0))
+                return JSMN_ERROR_INVAL;
+            }
+#else
+          /* In non-strict mode every unquoted value is a primitive */
+        default:
+#endif
+          r = jsmn_parse_primitive(parser, js, len);
+          if (r < 0) return r;
+          if ( parser->toksuper != -1 )
+            parser->tokens[parser->toksuper].size++;
+          break;
+
+#ifdef JSMN_STRICT
+          /* Unexpected char in strict mode */
+        default:
+          return JSMN_ERROR_INVAL;
+#endif
+        }
+    }
+
+  for (i = parser->toknext - 1; i >= 0; i--)
+    {
+      /* Unmatched opened object or array */
+      if (parser->tokens[i].start != -1 && parser->tokens[i].end == -1) return JSMN_ERROR_PART;
+    }
+
+  return 0;
+}
diff --git a/src/json/jsmn.h b/src/json/jsmn.h
new file mode 100644
index 0000000..07a5d77
--- /dev/null
+++ b/src/json/jsmn.h
@@ -0,0 +1,79 @@
+#ifndef __JSMN_H_
+#define __JSMN_H_
+
+#define JSMN_PARENT_LINKS
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * JSON type identifier. Basic types are:
+ * 	o Object
+ * 	o Array
+ * 	o String
+ * 	o Other primitive: number, boolean (true/false) or null
+ */
+typedef enum {
+	JSMN_UNDEFINED = 0,
+	JSMN_OBJECT = 1,
+	JSMN_ARRAY = 2,
+	JSMN_STRING = 3,
+	JSMN_PRIMITIVE = 4
+} jsmntype_t;
+
+enum jsmnerr {
+	/* Not enough tokens were provided */
+	JSMN_ERROR_NOMEM = -1,
+	/* Invalid character inside JSON string */
+	JSMN_ERROR_INVAL = -2,
+	/* The string is not a full JSON packet, more bytes expected */
+	JSMN_ERROR_PART = -3
+};
+
+/**
+ * JSON token description.
+ * type		type (object, array, string etc.)
+ * start	start position in JSON data string
+ * end		end position in JSON data string
+ */
+typedef struct {
+  jsmntype_t type;
+  int start;
+  int end;
+  int size;
+#ifdef JSMN_PARENT_LINKS
+  int parent;
+#endif
+} jsmntok_t;
+
+/**
+ * JSON parser. Contains an array of token blocks available. Also stores
+ * the string being parsed now and current position in that string
+ */
+typedef struct {
+  jsmntok_t *tokens;
+  unsigned int num_tokens;
+  unsigned int pos; /* offset in the JSON string */
+  unsigned int lineno;
+  unsigned int toknext; /* next token to allocate */
+  int toksuper; /* superior token node, e.g parent object or array */
+} jsmn_parser;
+
+/**
+ * Run JSON parser. It parses a JSON data string into and array of tokens, each describing
+ * a single JSON object.
+ */
+int jsmn_parse(jsmn_parser *parser, const char *js, size_t len);
+
+jsmn_parser *jsmn_new(void);
+
+void jsmn_destroy(jsmn_parser *parser);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __JSMN_H_ */
diff --git a/src/kdtreelib/kdtree.h b/src/kdtreelib/kdtree.h
index ee24ef0..1405968 100644
--- a/src/kdtreelib/kdtree.h
+++ b/src/kdtreelib/kdtree.h
@@ -48,6 +48,17 @@ typedef struct kd_point {
     unsigned index;
 } kd_point;
 
+
+static inline
+int qcmp(struct kd_point *a, struct kd_point *b, int axis)
+{
+  int ret = (a->point[axis] > b->point[axis]) ? 1 : (a->point[axis] < b->point[axis]) ? -1 : 0;
+  if ( ret == 0 ) ret = (a->index > b->index) ? 1 : (a->index < b->index) ? -1 : 0;
+
+  return ret;
+}
+
+
 /*!
  * \struct kdNode 
  * \brief kd-tree node structure definition 
diff --git a/src/kdtreelib/kdtree_common.c b/src/kdtreelib/kdtree_common.c
index 5c1317e..b730c4d 100644
--- a/src/kdtreelib/kdtree_common.c
+++ b/src/kdtreelib/kdtree_common.c
@@ -7,9 +7,7 @@
 #include "pqueue.h"
 
 
-extern int pmergesort(void *base, size_t nmemb, size_t size,
-                      int (*compar) (const void *, const void *),
-                      int max_threads);
+extern int pmergesort(struct kd_point *base, size_t nmemb, int axis, int max_threads);
 
 
 /* ********************************************************************
@@ -30,7 +28,7 @@ kd_malloc(size_t size, const char *msg)
 kdata_t
 kd_sqr(kdata_t x)
 {
-    return x == 0 ? 0 : x * x;
+  return (x < 0 || x > 0) ? x * x : 0;
 }
 
 int
@@ -87,44 +85,7 @@ kd_printTree(struct kdNode *node)
 
    ******************************************************************** */
 
-static int
-_compPoints0(const void *p1, const void *p2)
-{
-    struct kd_point *a = (struct kd_point *) p1;
-    struct kd_point *b = (struct kd_point *) p2;
-
-    int ret = (a->point[0] > b->point[0]) ? 1 : (a->point[0] < b->point[0]) ? -1 : 0;
-    if ( ret == 0 ) ret = (a->index > b->index) ? 1 : (a->index < b->index) ? -1 : 0;
-
-    return ret;
-}
-
-static int
-_compPoints1(const void *p1, const void *p2)
-{
-    struct kd_point *a = (struct kd_point *) p1;
-    struct kd_point *b = (struct kd_point *) p2;
-
-    int ret = (a->point[1] > b->point[1]) ? 1 : (a->point[1] < b->point[1]) ? -1 : 0;
-    if ( ret == 0 ) ret = (a->index > b->index) ? 1 : (a->index < b->index) ? -1 : 0;
-
-    return ret;
-}
-
-static int
-_compPoints2(const void *p1, const void *p2)
-{
-    struct kd_point *a = (struct kd_point *) p1;
-    struct kd_point *b = (struct kd_point *) p2;
-
-    int ret = (a->point[2] > b->point[2]) ? 1 : (a->point[2] < b->point[2]) ? -1 : 0;
-    if ( ret == 0 ) ret = (a->index > b->index) ? 1 : (a->index < b->index) ? -1 : 0;
-
-    return ret;
-}
-
-void *
-kd_doBuildTree(void *threadarg)
+void *kd_doBuildTree(void *threadarg)
 {
     int sortaxis;
     unsigned long pivot;
@@ -163,12 +124,7 @@ kd_doBuildTree(void *threadarg)
      * If this iteration is allowed to start more threads, we first
      * use them to parallelize the sorting 
      */
-    int (*qcomp) (const void *, const void *);
-    if      ( sortaxis == 0 ) qcomp = _compPoints0;
-    else if ( sortaxis == 1 ) qcomp = _compPoints1;
-    else                      qcomp = _compPoints2;
-
-    pmergesort(points, nPoints, sizeof(struct kd_point), qcomp, max_threads);
+    pmergesort(points, nPoints, sortaxis, max_threads);
 
     pivot = nPoints / 2;
     if ((node = kd_allocNode(points, pivot, min, max, sortaxis, dim)) == NULL)
diff --git a/src/kdtreelib/pmergesort.c b/src/kdtreelib/pmergesort.c
index 31bd897..57e6968 100644
--- a/src/kdtreelib/pmergesort.c
+++ b/src/kdtreelib/pmergesort.c
@@ -3,46 +3,40 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "kdtree.h"
+
 
 typedef struct param_t {
-    char *a;
-    char *b;
+    struct kd_point *a;
+    struct kd_point *b;
     size_t first;
     size_t nmemb;
-    size_t size;
-    int (*cmp) (const void *, const void *);
+    int axis;
     int max_threads;
 } param_t;
 
+extern void qsortR(void *base0, size_t n, int axis);
 
-void pm_buildparams(struct param_t *p, void *a, void *b, size_t first,
-                    size_t nmemb, size_t size,
-                    int (*cmp) (const void *, const void *),
-                    int max_threads);
-int pmergesort(void *base, size_t nmemb, size_t size,
-               int (*compar) (const void *, const void *),
-               int max_threads);
+void pm_buildparams(struct param_t *p, struct kd_point *a, struct kd_point *b, size_t first,
+                    size_t nmemb, int axis, int max_threads);
+int pmergesort(struct kd_point *base, size_t nmemb, int axis, int max_threads);
 void *mergesort_t(void *args);
 
 
-int
-pmergesort(void *base, size_t nmemb, size_t size,
-           int (*compar) (const void *, const void *),
-           int max_threads)
+int pmergesort(struct kd_point *base, size_t nmemb, int axis, int max_threads)
 {
-    void *tmp;
+    struct kd_point *tmp;
     param_t args;
 
-    if ((tmp = calloc(nmemb, size)) == NULL) {
+    if ((tmp = (struct kd_point*)calloc(nmemb, sizeof(struct kd_point))) == NULL) {
         perror("malloc");
         return 0;
     }
-    args.a = (char *) base;
-    args.b = (char *) tmp;
+    args.a = base;
+    args.b = tmp;
     args.first = 0;
     args.nmemb = nmemb;
-    args.size = size;
-    args.cmp = compar;
+    args.axis = axis;
     args.max_threads = max_threads;
 
     mergesort_t(&args);
@@ -52,18 +46,14 @@ pmergesort(void *base, size_t nmemb, size_t size,
 }
 
 void
-pm_buildparams(struct param_t *p, void *a, void *b, size_t first,
-               size_t nmemb, size_t size,
-               int (*cmp) (const void *, const void *),
-               int max_threads)
+pm_buildparams(struct param_t *p, struct kd_point *a, struct kd_point *b, size_t first,
+               size_t nmemb, int axis, int max_threads)
 {
-
-    p->a = (char *)a;
-    p->b = (char *)b;
+    p->a = a;
+    p->b = b;
     p->first = first;
     p->nmemb = nmemb;
-    p->size = size;
-    p->cmp = cmp;
+    p->axis = axis;
     p->max_threads = max_threads;
 }
 
@@ -81,13 +71,12 @@ mergesort_t(void *args)
          * Reached maximum number of threads allocated to this
          * branch. Proceed with sequential sort of this chunk. 
          */
-        qsort(mya->a + mya->first * mya->size, mya->nmemb, mya->size, mya->cmp);
+        qsortR(mya->a + mya->first, mya->nmemb, mya->axis);
     } else {
         /*
          * Start two new threads, each sorting half of array a 
          */
-        pm_buildparams(&larg, mya->a, mya->b, mya->first, mya->nmemb / 2,
-                       mya->size, mya->cmp, mya->max_threads / 2);
+        pm_buildparams(&larg, mya->a, mya->b, mya->first, mya->nmemb / 2, mya->axis, mya->max_threads / 2);
         /*
          * Recursively sort the left half 
          */
@@ -97,8 +86,7 @@ mergesort_t(void *args)
         }
 
         pm_buildparams(&rarg, mya->a, mya->b, mya->first + mya->nmemb / 2,
-                       mya->nmemb - mya->nmemb / 2, mya->size,
-                       mya->cmp, mya->max_threads / 2);
+                       mya->nmemb - mya->nmemb / 2, mya->axis, mya->max_threads / 2);
         /*
          * Recursively sort the right half 
          */
@@ -121,38 +109,31 @@ mergesort_t(void *args)
                  * We already copied everything from the left chunk,
                  * now copy from the right 
                  */
-                memcpy(mya->b + i * mya->size, mya->a + ri * mya->size,
-                       mya->size);
+                memcpy(mya->b + i, mya->a + ri, sizeof(struct kd_point));
                 ri++;
             } else if (ri >= rarg.first + rarg.nmemb) {
                 /*
                  * We already copied everything from the right chunk,
                  * now copy from the left 
                  */
-                memcpy(mya->b + i * mya->size, mya->a + li * mya->size,
-                       mya->size);
+                memcpy(mya->b + i, mya->a + li, sizeof(struct kd_point));
                 li++;
             }
             /*
-             * We can still copy from both chunks, copy the smaller
-             * element 
+             * We can still copy from both chunks, copy the smaller element 
              */
-            else if (mya->cmp(mya->a + li * mya->size,
-                              mya->a + ri * mya->size) < 1) {
-                memcpy(mya->b + i * mya->size, mya->a + li * mya->size,
-                       mya->size);
+            else if ( qcmp(mya->a + li, mya->a + ri, mya->axis) < 1) {
+                memcpy(mya->b + i, mya->a + li, sizeof(struct kd_point));
                 li++;
             } else {
-                memcpy(mya->b + i * mya->size, mya->a + ri * mya->size,
-                       mya->size);
+                memcpy(mya->b + i, mya->a + ri, sizeof(struct kd_point));
                 ri++;
             }
         }
         /*
          * Now b is sorted, copy it back to a 
          */
-        memcpy(mya->a + mya->size * mya->first,
-               mya->b + mya->size * mya->first, mya->size * mya->nmemb);
+        memcpy(mya->a + mya->first, mya->b + mya->first, mya->nmemb*sizeof(struct kd_point));
     }
     return NULL;
 }
diff --git a/src/kdtreelib/qsort.c b/src/kdtreelib/qsort.c
new file mode 100644
index 0000000..a6d3c21
--- /dev/null
+++ b/src/kdtreelib/qsort.c
@@ -0,0 +1,321 @@
+/* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details (qsort.c
+   is used to build libc.a and as such is covered by the LGPL -- Joerg
+   Dietrich 2008)*/
+#include <stdlib.h>
+
+#include "kdtree.h"
+
+/*-
+ * Copyright (c) 1980, 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * qsort.c:
+ * Our own version of the system qsort routine which is faster by an average
+ * of 25%, with lows and highs of 10% and 50%.
+ * The THRESHold below is the insertion sort threshold, and has been adjusted
+ * for records of size 48 bytes.
+ * The MTHREShold is where we stop finding a better median.
+ */
+
+#define		THRESH		4       /* threshold for insertion */
+#define		MTHRESH		6       /* threshold for median */
+
+static int thresh;              /* THRESHold */
+static int mthresh;             /* MTHRESHold */
+
+void qsortR(void *base0, size_t n, int axis);
+
+/*
+ * qst:
+ * Do a quicksort
+ * First, find the median element, and put that one in the first place as the
+ * discriminator.  (This "median" is just the median of the first, last and
+ * middle elements).  (Using this median instead of the first element is a big
+ * win).  Then, the usual partitioning/swapping, followed by moving the
+ * discriminator into the right place.  Then, figure out the sizes of the two
+ * partions, do the smaller one recursively and the larger one via a repeat of
+ * this code.  Stopping when there are less than THRESH elements in a partition
+ * and cleaning up with an insertion sort (in our caller) is a huge win.
+ * All data swaps are done in-line, which is space-losing but time-saving.
+ * (And there are only three places where this is done).
+ */
+
+static
+void qst(struct kd_point *base, struct kd_point *max, int axis)
+{
+  struct kd_point c, *i, *j, *jj;
+  int ii;
+  struct kd_point *mid, *tmp;
+  int lo, hi;
+
+  /*
+   * At the top here, lo is the number of characters of elements in the
+   * current partition.  (Which should be max - base).
+   * Find the median of the first, last, and middle element and make
+   * that the middle element.  Set j to largest of first and middle.
+   * If max is larger than that guy, then it's that guy, else compare
+   * max with loser of first and take larger.  Things are set up to
+   * prefer the middle, then the first in case of ties.
+   */
+  lo = max - base;            /* number of elements */
+  do {
+    mid = i = base + (lo >> 1);
+    if ( lo >= mthresh )
+      {
+        j = (qcmp((jj = base), i, axis) > 0 ? jj : i);
+        if ( qcmp(j, (tmp = max - 1), axis) > 0 )
+          {
+            /*
+             * switch to first loser 
+             */
+            j = (j == jj ? i : jj);
+            if ( qcmp(j, tmp, axis) < 0 ) j = tmp;
+          }
+        if ( j != i )
+          {
+            ii = 1;
+            do {
+              c = *i;
+              *i++ = *j;
+              *j++ = c;
+            } while (--ii);
+          }
+      }
+    /*
+     * Semi-standard quicksort partitioning/swapping
+     */
+    for ( i = base, j = max - 1;; )
+      {
+        while ( i < mid && qcmp(i, mid, axis) <= 0 ) ++i;
+        
+        while ( j > mid )
+          {
+            if ( qcmp(mid, j, axis) <= 0 )
+              {
+                --j;
+                continue;
+              }
+            tmp = i + 1;  /* value of i after swap */
+            if ( i == mid )
+              {
+                /*
+                 * j <-> mid, new mid is j 
+                 */
+                mid = jj = j;
+              }
+            else
+              {
+                /*
+                 * i <-> j 
+                 */
+                jj = j;
+                --j;
+              }
+            goto swap;
+          }
+        if ( i == mid )
+          {
+            break;
+          }
+        else
+          {
+            /*
+             * i <-> mid, new mid is i 
+             */
+            jj = mid;
+            tmp = mid = i;  /* value of i after swap */
+            --j;
+          }
+      swap:
+        ii = 1;
+        do {
+          c = *i;
+          *i++ = *jj;
+          *jj++ = c;
+        } while ( --ii );
+        i = tmp;
+      }
+    /*
+     * Look at sizes of the two partitions, do the smaller
+     * one first by recursion, then do the larger one by
+     * making sure lo is its size, base and max are update
+     * correctly, and branching back.  But only repeat
+     * (recursively or by branching) if the partition is
+     * of at least size THRESH.
+     */
+    i = (j = mid) + 1;
+    if ( (lo = j - base) <= (hi = max - i) )
+      {
+        if ( lo >= thresh ) qst(base, j, axis);
+        base = i;
+        lo = hi;
+      }
+    else
+      {
+        if ( hi >= thresh ) qst(i, max, axis);
+        max = j;
+      }
+  } while ( lo >= thresh );
+}
+
+/*
+ * qsort:
+ * First, set up some global parameters for qst to share.  Then, quicksort
+ * with qst(), and then a cleanup insertion sort ourselves.  Sound simple?
+ * It's not...
+ */
+
+void NotUsed_qsortR(void *base0, size_t n, int axis)
+{
+  struct kd_point *base = (struct kd_point *) base0;
+  struct kd_point c, *i, *j, *lo, *hi;
+  struct kd_point *min, *max;
+
+  if ( n <= 1 ) return;
+    
+  thresh = THRESH;
+  mthresh = MTHRESH;
+  max = base + n;
+  if ( n >= THRESH )
+    {
+      qst(base, max, axis);
+      hi = base + thresh;
+    }
+  else
+    {
+      hi = max;
+    }
+  /*
+   * First put smallest element, which must be in the first THRESH, in
+   * the first position as a sentinel.  This is done just by searching
+   * the first THRESH elements (or the first n if n < THRESH), finding
+   * the min, and swapping it into the first position.
+   */
+  for ( j = lo = base; (lo += 1) < hi; )
+    if ( qcmp(j, lo, axis) > 0 )
+      j = lo;
+
+  if ( j != base )
+    {
+      /*
+       * swap j into place 
+       */
+      for ( i = base, hi = base + 1; i < hi; )
+        {
+          c = *j;
+          *j++ = *i;
+          *i++ = c;
+        }
+    }
+  /*
+   * With our sentinel in place, we now run the following hyper-fast
+   * insertion sort.  For each remaining element, min, from [1] to [n-1],
+   * set hi to the index of the element AFTER which this one goes.
+   * Then, do the standard insertion sort shift on a character at a time
+   * basis for each element in the frob.
+   */
+  for ( min = base; (hi = min += 1) < max; )
+    {
+      while ( qcmp(hi -= 1, min, axis) > 0 )
+        /*
+         * void 
+         */ ;
+      if ( (hi += 1) != min )
+        {
+          for ( lo = min + 1; --lo >= min; )
+            {
+              c = *lo;
+              for ( i = j = lo; (j -= 1) >= hi; i = j ) *i = *j;
+              *i = c;
+            }
+        }
+    }
+}
+
+//  quickSort
+//
+//  This public-domain C implementation by Darel Rex Finley.
+//
+//  * This function assumes it is called with valid parameters.
+//
+//  Code from: http://alienryderflex.com/quicksort
+
+void qsortR(void *base0, size_t n, int axis)
+{
+  struct kd_point *base = (struct kd_point *) base0;
+  struct kd_point piv;
+
+#define  MAX_LEVELS  300
+  int beg[MAX_LEVELS], end[MAX_LEVELS], L, R, swap, i = 0;
+
+  beg[0] = 0; end[0] = (int)n;
+  while ( i >= 0 )
+    {
+      L = beg[i]; R = end[i]-1;
+      if ( L < R )
+        {
+          piv = base[L];
+          while ( L < R )
+            {
+              while ( L < R && qcmp(&base[R], &piv, axis) >= 0 ) R--;
+              if ( L < R ) base[L++] = base[R];
+
+              while ( L < R && qcmp(&base[L], &piv, axis) <= 0 ) L++;
+              if ( L < R ) base[R--] = base[L];
+            }
+          
+          base[L] = piv; beg[i+1] = L+1; end[i+1] = end[i]; end[i++] = L;
+          
+          if ( end[i]-beg[i] > end[i-1]-beg[i-1] )
+            {
+              swap = beg[i]; beg[i] = beg[i-1]; beg[i-1] = swap;
+              swap = end[i]; end[i] = end[i-1]; end[i-1] = swap;
+            }
+        }
+      else
+        {
+          i--;
+        }
+    }
+}
+
+
+void XqsortR(void *base0, size_t n, int idx)
+{
+  if ( n < 2 ) return;
+  struct kd_point *a = (struct kd_point *) base0;
+  struct kd_point t;
+  // kdata_t p = a[n/2].point[idx];
+  kd_point p = a[n/2];
+  int i, j;
+  for ( i = 0, j = n - 1;; i++, j-- )
+    {
+      // while ( a[i].point[idx] < p ) i++;
+      // while ( p < a[j].point[idx] ) j--;
+      while ( qcmp(a+i, &p, idx) < 0 ) i++;
+      while ( qcmp(&p, a+j, idx) < 0 ) j--;
+      if ( i >= j ) break;
+      t = a[i];
+      a[i] = a[j];
+      a[j] = t;
+    }
+  qsortR(a, i, idx);
+  qsortR(a + i, n - i, idx);
+}
+
diff --git a/src/kvlist.c b/src/kvlist.c
deleted file mode 100644
index f6e5e4a..0000000
--- a/src/kvlist.c
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
-  This file is part of CDO. CDO is a collection of Operators to
-  manipulate and analyse Climate model Data.
-
-  Copyright (C) 2003-2016 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.
-*/
-
-/* key value list */
-
-/*
-  list type 1:
-  ============
-
-  &parameter
-    name:              ps
-    standard_name:     surface_air_pressure
-    units:             Pa
-    cell_methods:      "time: mean"
-    cell_measures:     "area: areacella"
-    long_name:         "Surface Air Pressure"
-    comment:           "not, in general, the same as mean sea-level pressure"
-    valid_min:         4.791e+04
-    valid_max:         1.119e+05
-
-  list type 2: one entry on each line
-  ============
-
-  variable_entry:    ps
-    standard_name:     surface_air_pressure
-    units:             Pa
-    cell_methods:      time: mean
-    cell_measures:     area: areacella
-    long_name:         Surface Air Pressure
-    comment:           not, in general, the same as mean sea-level pressure
-    valid_min:         4.791e+04
-    valid_max:         1.119e+05
-*/
-
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 600 /* strdup */
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <errno.h>
-#include <assert.h>
-#include "cdo_int.h"
-
-#define MAX_KVLISTS    4096
-#define MAX_KVELEMENTS 1024
-
-typedef struct {
-  char name[128];
-  char *value;
-} kvelement_t;
-
-typedef struct {
-  char name[128];
-  int num_elements;
-  kvelement_t elements[MAX_KVELEMENTS];
-} kvlist_t;
-
-typedef struct {
-  char *filename;
-  char *buffer;
-  char *bufferp;
-  size_t buffersize;
-  int num_lists;
-  kvlist_t lists[MAX_KVLISTS];
-} kvl_t;
-
-
-static
-int kvlNewList(kvl_t *kvl)
-{
-  assert(kvl != NULL);
-
-  kvl->num_lists++;
-  assert(kvl->num_lists < MAX_KVLISTS);
-
-  return (kvl->num_lists-1);
-}
-
-static
-int kvlNewListElement(kvl_t *kvl, int listID)
-{
-  assert(kvl != NULL);
-
-  kvl->lists[listID].num_elements++;
-  assert(kvl->lists[listID].num_elements < MAX_KVELEMENTS);
-
-  return (kvl->lists[listID].num_elements-1);
-}
-
-static
-int kvlAddList(kvl_t *kvl, const char *name)
-{
-  int listID = kvlNewList(kvl);
-
-  strcpy(kvl->lists[listID].name, name);
-
-  return (listID);
-}
-
-static
-void kvlAddListElement(kvl_t *kvl, int listID, const char *name, const char *value)
-{
-  int elemID = kvlNewListElement(kvl, listID);
-
-  strcpy(kvl->lists[listID].elements[elemID].name, name);
-  kvl->lists[listID].elements[elemID].value = strdup(value);
-}
-
-static
-char *readLineFromBuffer(char *buffer, size_t *buffersize, char *line, size_t len)
-{
-  int ichar;
-  size_t ipos = 0;
-
-  while ( *buffersize )
-    {
-      ichar = *buffer;
-      (*buffersize)--;
-      buffer++;
-      if ( ichar == '\r' ) break;
-      if ( ichar == '\n' ) break;
-      line[ipos++] = ichar;
-      if ( ipos >= len )
-        {
-          fprintf(stderr, "readLineFromBuffer: end of line not found (maxlen = %ld)!\n", len);
-          break;
-        }
-    }
-  line[ipos] = 0;
-
-  if ( *buffersize == 0 && ipos == 0 ) buffer = NULL;
-
-  return (buffer);
-}
-
-static
-void pfree(void *ptr)
-{
-  if ( ptr ) Free(ptr);
-}
-
-static
-char *skipSeparator(char *pline)
-{
-  while ( isspace((int) *pline) ) pline++;
-  if ( *pline == '=' || *pline == ':' ) pline++;
-  while ( isspace((int) *pline) ) pline++;
-
-  return (pline);
-}
-
-static
-char *getElementName(char *pline, char *name)
-{
-  int pos = 0, len;
-
-  while ( isspace((int) *pline) ) pline++;
-  len = strlen(pline);
-  while ( pos < len && !isspace((int) *(pline+pos)) && *(pline+pos) != '=' && *(pline+pos) != ':' ) pos++;
-
-  strncpy(name, pline, pos);
-  name[pos] = 0;
-
-  pline += pos;
-  return (pline);
-}
-
-static
-char *getElementValue(char *pline)
-{
-  int len;
-
-  while ( isspace((int) *pline) ) pline++;
-  len = strlen(pline);
-  while ( isspace((int) *(pline+len-1)) && len ) { *(pline+len-1) = 0; len--;}
-
-  return (pline);
-}
-
-static
-void kvlParseBuffer(kvl_t *kvl)
-{
-  char line[4096];
-  char name[256];
-  char *pline;
-  char *buffer = kvl->buffer;
-  size_t buffersize = kvl->buffersize;
-  int linenumber = 0;
-  char listkey1[] = "axis_entry:";
-  char listkey2[] = "variable_entry:";
-  int listtype = 0;
-  int listID = -1;
-
-  while ( (buffer = readLineFromBuffer(buffer, &buffersize, line, sizeof(line))) )
-    {
-      linenumber++;
-      pline = line;
-      while ( isspace((int) *pline) ) pline++;
-      if ( *pline == '#' || *pline == '!' || *pline == '\0' ) continue;
-      //  len = (int) strlen(pline);
-      if ( listtype == 0 && *pline == '&' )
-	{
-	  listtype = 1;
-	}
-      
-      if ( strncmp(pline, listkey1, strlen(listkey1)) == 0 )
-	{
-	  pline += strlen(listkey1);
-
-	  listtype = 2;
-
-	  listID = kvlAddList(kvl, "axis");
-
-	  pline = skipSeparator(pline);
-	  pline = getElementValue(pline);
-
-	  if ( *pline ) kvlAddListElement(kvl, listID, "name", pline);
-	}
-      else if ( strncmp(pline, listkey2, strlen(listkey2)) == 0 )
-	{
-	  pline += strlen(listkey2);
-
-	  listtype = 2;
-
-	  listID = kvlAddList(kvl, "variable");
-
-	  pline = skipSeparator(pline);
-	  pline = getElementValue(pline);
-
-	  if ( *pline ) kvlAddListElement(kvl, listID, "name", pline);
-	}
-      else
-	{
-	  pline = getElementName(pline, name);
-	  pline = skipSeparator(pline);
-	  pline = getElementValue(pline);
-
-	  if ( listID == -1 ) listID = kvlAddList(kvl, "global");
-
-	  if ( *pline ) kvlAddListElement(kvl, listID, name, pline);
-
-	    {
-	      //fprintf(stderr, "%d skip line %3d: %s\n", newlist, linenumber, pline);
-	    }
-	}
-
-      //   printf("%s\n", pline);
-    }
-}
-
-
-void *kvlParseFile(const char *filename)
-{
-  kvl_t *kvl = NULL;
-  FILE *fp;
-  char *buffer;
-  size_t filesize;
-  size_t nitems;
-
-  assert(filename != NULL);
-
-  filesize = fileSize(filename);
-
-  fp = fopen(filename, "r");
-  if ( fp == NULL )
-    {
-      fprintf(stderr, "Open failed on %s: %s\n", filename, strerror(errno));
-      return (kvl);
-    }
-
-  buffer = (char*) Malloc(filesize);
-  nitems = fread(buffer, 1, filesize, fp);
-
-  fclose(fp);
-
-  if ( nitems != filesize )
-    {
-      fprintf(stderr, "Read failed on %s!\n", filename);
-      return (kvl);
-    }
- 
-  kvl = (kvl_t*) Calloc(1, sizeof(kvl_t));
-  kvl->buffer = buffer;
-  kvl->buffersize = filesize;
-  kvl->filename = strdup(filename);
-
-  kvlParseBuffer(kvl);
-  
-  return ((void *) kvl);
-}
-
-
-void kvlDelete(void *kvlist)
-{
-  kvl_t *kvl = (kvl_t *) kvlist;
-
-  assert(kvl != NULL);
-
-  pfree(kvl->filename);
-  pfree(kvl->buffer);
-
-  Free(kvl);
-}
-
-
-int kvlGetNumLists(void *kvlist)
-{
-  kvl_t *kvl = (kvl_t *) kvlist;
-
-  assert(kvl != NULL);
-
-  return(kvl->num_lists);
-}
-
-
-const char *kvlGetListName(void *kvlist, int listID)
-{
-  kvl_t *kvl = (kvl_t *) kvlist;
-  char *listname = NULL;
-  
-  assert(listID < kvl->num_lists);
-  
-  listname = kvl->lists[listID].name;
-
-  return (listname);
-}
-
-int kvlGetListNumElements(void *kvlist, int listID)
-{
-  kvl_t *kvl = (kvl_t *) kvlist;
-  int nelements = 0;
-
-  assert(listID < kvl->num_lists);
-
-  nelements = kvl->lists[listID].num_elements;
-
-  return (nelements);
-}
-
-
-const char *kvlGetListElementName(void *kvlist, int listID, int elemID)
-{
-  kvl_t *kvl = (kvl_t *) kvlist;
-  char *ename = NULL;
-
-  assert(listID < kvl->num_lists);
-  assert(elemID < kvl->lists[listID].num_elements);
-
-  ename = kvl->lists[listID].elements[elemID].name;
-
-  return (ename);
-}
-
-
-const char *kvlGetListElementValue(void *kvlist, int listID, int elemID)
-{
-  kvl_t *kvl = (kvl_t *) kvlist;
-  char *evalue = NULL;
-
-  assert(listID < kvl->num_lists);
-  assert(elemID < kvl->lists[listID].num_elements);
-
-  evalue = kvl->lists[listID].elements[elemID].value;
-
-  return (evalue);
-}
-
-/*
-int main(int argc, char *argv[])
-{
-  char *filename;
-  void *kvlist;
-  int nlists, listID;
-  int nelements, elemID;
-  const char *listname;
-  const char *ename;
-  const char *evalue;
-
-  if ( argc != 2 ) 
-    {
-      fprintf(stderr, "usage: kvlist filename\n");
-      return (1);
-    }
-
-  filename = argv[1];
-
-  printf("Parse file: %s\n", filename);
-
-  kvlist = kvlParseFile(filename);
-  nlists = kvlGetNumLists(kvlist);
-  printf("# Number of lists: %d\n", nlists);
-  for ( listID = 0; listID < nlists; ++listID )
-    {
-      listname = kvlGetListName(kvlist, listID);
-      nelements = kvlGetListNumElements(kvlist, listID);
-      printf("# list ID: %d;   Number of elements: %d\n", listID, nelements);
-      printf("&%s\n", listname);
-      for ( elemID = 0; elemID < nelements; ++elemID )
-	{
-	  ename  = kvlGetListElementName(kvlist, listID, elemID);
-	  evalue = kvlGetListElementValue(kvlist, listID, elemID);
-	  printf("  %s = %s\n", ename, evalue);
-	}
-      printf("/\n");
-    }
-
-  kvlDelete(kvlist);
-
-  return 0;
-}
-*/
diff --git a/src/kvlist.h b/src/kvlist.h
deleted file mode 100644
index 53d8ecd..0000000
--- a/src/kvlist.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
-  This file is part of CDO. CDO is a collection of Operators to
-  manipulate and analyse Climate model Data.
-
-  Copyright (C) 2003-2016 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.
-*/
-
-#ifndef _KVLIST_H
-#define _KVLIST_H
-
-void *kvlParseFile(const char *filename);
-
-void kvlDelete(void *kvlist);
-
-int kvlGetNumLists(void *kvlist);
-const char *kvlGetListName(void *kvlist, int listID);
-
-int kvlGetListNumElements(void *kvlist, int listID);
-const char *kvlGetListElementName(void *kvlist, int listID, int elemID);
-const char *kvlGetListElementValue(void *kvlist, int listID, int elemID);
-
-#endif  /* _KVLIST_H */
diff --git a/src/list.c b/src/list.c
index 607d7aa..8330a2d 100644
--- a/src/list.c
+++ b/src/list.c
@@ -1,239 +1,140 @@
-/*
-  This file is part of CDO. CDO is a collection of Operators to
-  manipulate and analyse Climate model Data.
-
-  Copyright (C) 2003-2016 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 <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include <ctype.h>
-#include <float.h>
-#include "cdo_int.h"
-#include "dmemory.h"
+#include <assert.h>
+ 
 #include "list.h"
 
-
-#define  DEFAULT_ALLINC  1024
-
-
-static void listInit(LIST *list, int type)
+list_t *list_new(size_t elementSize, freeFunction_t freeFunc, const char *name)
 {
-  list->array  = NULL;
-  list->nalloc = 0;
-  list->allinc = DEFAULT_ALLINC;
-  list->type   = type;
-}
+  assert(elementSize > 0);
 
+  list_t *list = (list_t*) malloc(sizeof(list_t));
 
-LIST *listNew(int type)
-{
-  LIST *list = NULL;
-
-  if ( type != INT_LIST && type != FLT_LIST )
-    {
-      fprintf(stderr, "%s: type %d unsupported!\n", __func__, type);
-    }
-  else
-    {
-      list = (LIST*) Malloc(sizeof(LIST));
-      listInit(list, type);
-    }
+  list->logicalLength = 0;
+  list->elementSize = elementSize;
+  list->head = list->tail = NULL;
+  list->freeFunc = freeFunc;
+  list->name = name ? strdup(name) : NULL;
 
-  return (list);
+  return list;
 }
 
-
-void listDelete(LIST *list)
+void list_destroy(list_t *list)
 {
   if ( list )
     {
-      if ( list->array ) Free(list->array);
-      Free(list);
+      listNode_t *current;
+      while ( list->head )
+        {
+          current = list->head;
+          list->head = current->next;
+        
+          if ( list->freeFunc )
+            list->freeFunc(current->data);
+
+          free(current->data);
+          free(current);
+        }
+      if ( list->name ) free(list->name);
+      free(list);
     }
 }
 
-
-void *listArrayPtr(LIST *list)
+void list_prepend(list_t *list, void *element)
 {
-  return (list->array);
-}
-
-
-static void listCheck(LIST *list, int num)
-{
-  while ( list->nalloc < (num+1) )
-    {
-      list->nalloc += list->allinc;
-      if ( list->type == INT_LIST )
-	list->array = (int*) Realloc(list->array, list->nalloc*sizeof(int));
-      else
-	list->array = (double*) Realloc(list->array, list->nalloc*sizeof(double));
-    }
-}
+  listNode_t *node = (listNode_t *) malloc(sizeof(listNode_t));
+  node->data = malloc(list->elementSize);
+  memcpy(node->data, element, list->elementSize);
 
+  node->next = list->head;
+  list->head = node;
 
-void listSetInt(LIST *list, int num, int ival)
-{
-  listCheck(list, num);
+  if ( !list->tail ) list->tail = list->head;
 
-  ((int *) list->array)[num] = ival;
+  list->logicalLength++;
 }
 
-
-void listSetFlt(LIST *list, int num, double fval)
+void list_append(list_t *list, void *element)
 {
-  listCheck(list, num);
-
-  ((double *) list->array)[num] = fval;
-}
+  listNode_t *node = (listNode_t *) malloc(sizeof(listNode_t));
+  node->data = malloc(list->elementSize);
+  node->next = NULL;
 
+  memcpy(node->data, element, list->elementSize);
 
-int listGetInt(LIST *list, int num)
-{
-  int ival;
-
-  ival = ((int *) list->array)[num];
-
-  return (ival);
-}
-
-
-double listGetFlt(LIST *list, int num)
-{
-  double fval;
-
-  fval = ((double *) list->array)[num];
+  if ( list->logicalLength == 0 )
+    {
+      list->head = list->tail = node;
+    }
+  else
+    {
+      list->tail->next = node;
+      list->tail = node;
+    }
 
-  return (fval);
+  list->logicalLength++;
 }
 
-static
-int get_ival(const char *intstr, int idefault, int istart, int iend, int *ilast)
+void list_for_each(list_t *list, listIterator_t iterator)
 {
-  int ival = idefault;
-  int i;
-
-  for ( i = istart; i < iend; i++ )
+  assert(iterator != NULL);
+ 
+  listNode_t *node = list->head;
+  bool result = true;
+  while ( node && result )
     {
-      if ( ! (isdigit(intstr[i]) || intstr[i] == '-') )
-	{
-	  if ( intstr[i] == '/' )
-	    ival = parameter2intlist(intstr+i+1);
-	  else
-	    fprintf(stderr, "Syntax error in >%.*s<! Character %c not allowed.\n", iend, intstr, intstr[i]);
-	  break;
-	}
+      result = iterator(node->data);
+      node = node->next;
     }
-
-  *ilast = i;
-
-  return (ival);
 }
 
-
-void split_intstring(const char *intstr, int *first, int *last, int *inc)
+void list_head(list_t *list, void *element, bool removeFromList)
 {
-  int i, start;
-  int istrlen;
-
-  istrlen = strlen(intstr);
-  *first = parameter2intlist(intstr);
-  *last  = *first;
-  *inc   = 1;
-
-  start = 1;
-  *last = get_ival(intstr, *first, start, istrlen, &i);
-
-  if ( i < istrlen )
+  assert(list->head != NULL);
+ 
+  listNode_t *node = list->head;
+  memcpy(element, node->data, list->elementSize);
+ 
+  if ( removeFromList )
     {
-      start = i+1;
-      *inc = get_ival(intstr, 1, start, istrlen, &i);
+      list->head = node->next;
+      list->logicalLength--;
+ 
+      free(node->data);
+      free(node);
     }
 }
 
-
-int args2intlist(int argc, char **argv, LIST *list)
+void list_tail(list_t *list, void *element)
 {
-  int nint = 0;
-  int ival;
-  int first, last, inc;
-  int iarg;
+  assert(list->tail != NULL);
+  listNode_t *node = list->tail;
+  memcpy(element, node->data, list->elementSize);
+}
 
-  for ( iarg = 0; iarg < argc; iarg++ )
+void *list_entry(list_t *list, int index)
+{
+  if ( list )
     {
-      split_intstring(argv[iarg], &first, &last, &inc);
-
-      if ( inc >= 0 )
-	{
-	  for ( ival = first; ival <= last; ival += inc )
-	    listSetInt(list, nint++, ival);
-	}
-      else
-	{
-	  for ( ival = first; ival >= last; ival += inc )
-	    listSetInt(list, nint++, ival);
-	}
+      int i = 0;
+      listNode_t *node = list->head;
+      while ( node )
+        {
+          if ( i == index ) return *(void **)node->data;
+          node = node->next;
+          ++i;
+        }
     }
 
-  return (nint);
+  return NULL;
 }
 
-
-int args2fltlist(int argc, char **argv, LIST *list)
+int list_size(list_t *list)
 {
-  int i, nint = 0;
-  int ival;
-  int first, last, inc;
-  int iarg;
-  int len;
-  double tmp_val;
-
-  for ( iarg = 0; iarg < argc; iarg++ )
-    {
-      len = (int) strlen(argv[iarg]);
-      for ( i = 0; i < len; i++ )
-	if ( argv[iarg][i] != '/' && argv[iarg][i] != '-' && ! isdigit(argv[iarg][i]) ) break;
-      
-      if ( i != len )
-	{
-	  /*
-	  if      ( strcmp(argv[iarg],  "inf") == 0 )
-	    tmp_val =  DBL_MAX;
-	  else if ( strcmp(argv[iarg], "-inf") == 0 )
-	    tmp_val = -DBL_MAX;
-	  else  
-	  */                                    
-	    tmp_val = parameter2double(argv[iarg]);
-
-	  listSetFlt(list, nint++, tmp_val);
-	}
-      else
-	{
-	  split_intstring(argv[iarg], &first, &last, &inc);
-
-	  if ( inc >= 0 )
-	    {
-	      for ( ival = first; ival <= last; ival += inc )
-		listSetFlt(list, nint++, (double) ival);
-	    }
-	  else
-	    {
-	      for ( ival = first; ival >= last; ival += inc )
-		listSetFlt(list, nint++, (double) ival);
-	    }
-	}
-    }
+  return list->logicalLength;
+}
 
-  return (nint);
+const char *list_name(list_t *list)
+{
+  return list->name;
 }
diff --git a/src/list.h b/src/list.h
index e42a55c..e290729 100644
--- a/src/list.h
+++ b/src/list.h
@@ -1,44 +1,39 @@
-/*
-  This file is part of CDO. CDO is a collection of Operators to
-  manipulate and analyse Climate model Data.
-
-  Copyright (C) 2003-2016 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.
-*/
-
 #ifndef _LIST_H
 #define _LIST_H
 
-#define  INT_LIST  1
-#define  FLT_LIST  2
-
-
+#include <stdio.h>
+#include <stdbool.h>
+
+// a common function used to free malloc'd objects
+typedef void (*freeFunction_t)(void *);
+ 
+typedef bool (*listIterator_t)(void *);
+ 
+typedef struct _listNode_t {
+  void *data;
+  struct _listNode_t *next;
+} listNode_t;
+ 
 typedef struct {
-  void *array;
-  int nalloc;
-  int allinc;
-  int type;
-}
-LIST;
-
-
-LIST *listNew(int type);
-void listDelete(LIST *list);
-void *listArrayPtr(LIST *list);
-void listSetInt(LIST *list, int num, int ival);
-void listSetFlt(LIST *list, int num, double fval);
-int listGetInt(LIST *list, int num);
-double listGetFlt(LIST *list, int num);
-int args2intlist(int argc, char **argv, LIST *list);
-int args2fltlist(int argc, char **argv, LIST *list);
-
-#endif  /* _LIST_H */
+  size_t logicalLength;
+  size_t elementSize;
+  char *name;
+  listNode_t *head;
+  listNode_t *tail;
+  freeFunction_t freeFunc;
+} list_t;
+ 
+list_t *list_new(size_t elementSize, freeFunction_t freeFunc, const char *name);
+void list_destroy(list_t *list);
+ 
+void list_prepend(list_t *list, void *element);
+void list_append(list_t *list, void *element);
+int list_size(list_t *list);
+const char *list_name(list_t *list);
+
+void list_for_each(list_t *list, listIterator_t iterator);
+void list_head(list_t *list, void *element, bool removeFromList);
+void list_tail(list_t *list, void *element);
+void *list_entry(list_t *list, int index);
+
+#endif
diff --git a/src/list.c b/src/listarray.c
similarity index 61%
copy from src/list.c
copy to src/listarray.c
index 607d7aa..a786402 100644
--- a/src/list.c
+++ b/src/listarray.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -21,108 +21,104 @@
 #include <float.h>
 #include "cdo_int.h"
 #include "dmemory.h"
-#include "list.h"
+#include "listarray.h"
 
 
 #define  DEFAULT_ALLINC  1024
 
 
-static void listInit(LIST *list, int type)
+static void listaInit(lista_t *lista, int type)
 {
-  list->array  = NULL;
-  list->nalloc = 0;
-  list->allinc = DEFAULT_ALLINC;
-  list->type   = type;
+  lista->array  = NULL;
+  lista->nalloc = 0;
+  lista->allinc = DEFAULT_ALLINC;
+  lista->type   = type;
 }
 
 
-LIST *listNew(int type)
+lista_t *lista_new(int type)
 {
-  LIST *list = NULL;
+  lista_t *lista = NULL;
 
-  if ( type != INT_LIST && type != FLT_LIST )
+  if ( type != INT_LISTA && type != FLT_LISTA )
     {
       fprintf(stderr, "%s: type %d unsupported!\n", __func__, type);
     }
   else
     {
-      list = (LIST*) Malloc(sizeof(LIST));
-      listInit(list, type);
+      lista = (lista_t*) Malloc(sizeof(lista_t));
+      listaInit(lista, type);
     }
 
-  return (list);
+  return lista;
 }
 
 
-void listDelete(LIST *list)
+void lista_destroy(lista_t *lista)
 {
-  if ( list )
+  if ( lista )
     {
-      if ( list->array ) Free(list->array);
-      Free(list);
+      if ( lista->array ) Free(lista->array);
+      Free(lista);
     }
 }
 
 
-void *listArrayPtr(LIST *list)
+void *lista_dataptr(lista_t *lista)
 {
-  return (list->array);
+  return lista->array;
 }
 
 
-static void listCheck(LIST *list, int num)
+static void listaCheck(lista_t *lista, int num)
 {
-  while ( list->nalloc < (num+1) )
+  while ( lista->nalloc < (num+1) )
     {
-      list->nalloc += list->allinc;
-      if ( list->type == INT_LIST )
-	list->array = (int*) Realloc(list->array, list->nalloc*sizeof(int));
+      lista->nalloc += lista->allinc;
+      if ( lista->type == INT_LISTA )
+	lista->array = (int*) Realloc(lista->array, lista->nalloc*sizeof(int));
       else
-	list->array = (double*) Realloc(list->array, list->nalloc*sizeof(double));
+	lista->array = (double*) Realloc(lista->array, lista->nalloc*sizeof(double));
     }
 }
 
 
-void listSetInt(LIST *list, int num, int ival)
+void lista_set_int(lista_t *lista, int num, int ival)
 {
-  listCheck(list, num);
+  listaCheck(lista, num);
 
-  ((int *) list->array)[num] = ival;
+  ((int *) lista->array)[num] = ival;
 }
 
 
-void listSetFlt(LIST *list, int num, double fval)
+void lista_set_flt(lista_t *lista, int num, double fval)
 {
-  listCheck(list, num);
+  listaCheck(lista, num);
 
-  ((double *) list->array)[num] = fval;
+  ((double *) lista->array)[num] = fval;
 }
 
 
-int listGetInt(LIST *list, int num)
+int listaGetInt(lista_t *lista, int num)
 {
-  int ival;
-
-  ival = ((int *) list->array)[num];
+  int ival = ((int *) lista->array)[num];
 
-  return (ival);
+  return ival;
 }
 
 
-double listGetFlt(LIST *list, int num)
+double listaGetFlt(lista_t *lista, int num)
 {
-  double fval;
-
-  fval = ((double *) list->array)[num];
+  double fval = ((double *) lista->array)[num];
 
-  return (fval);
+  return fval;
 }
 
 static
 int get_ival(const char *intstr, int idefault, int istart, int iend, int *ilast)
 {
-  int ival = idefault;
   int i;
+  int ival = idefault;
 
   for ( i = istart; i < iend; i++ )
     {
@@ -138,21 +134,18 @@ int get_ival(const char *intstr, int idefault, int istart, int iend, int *ilast)
 
   *ilast = i;
 
-  return (ival);
+  return ival;
 }
 
 
 void split_intstring(const char *intstr, int *first, int *last, int *inc)
 {
-  int i, start;
-  int istrlen;
-
-  istrlen = strlen(intstr);
+  int istrlen = strlen(intstr);
   *first = parameter2intlist(intstr);
   *last  = *first;
   *inc   = 1;
 
-  start = 1;
+  int i, start = 1;
   *last = get_ival(intstr, *first, start, istrlen, &i);
 
   if ( i < istrlen )
@@ -163,7 +156,7 @@ void split_intstring(const char *intstr, int *first, int *last, int *inc)
 }
 
 
-int args2intlist(int argc, char **argv, LIST *list)
+int args2int_lista(int argc, char **argv, lista_t *lista)
 {
   int nint = 0;
   int ival;
@@ -177,20 +170,20 @@ int args2intlist(int argc, char **argv, LIST *list)
       if ( inc >= 0 )
 	{
 	  for ( ival = first; ival <= last; ival += inc )
-	    listSetInt(list, nint++, ival);
+	    lista_set_int(lista, nint++, ival);
 	}
       else
 	{
 	  for ( ival = first; ival >= last; ival += inc )
-	    listSetInt(list, nint++, ival);
+	    lista_set_int(lista, nint++, ival);
 	}
     }
 
-  return (nint);
+  return nint;
 }
 
 
-int args2fltlist(int argc, char **argv, LIST *list)
+int args2flt_lista(int argc, char **argv, lista_t *lista)
 {
   int i, nint = 0;
   int ival;
@@ -216,7 +209,7 @@ int args2fltlist(int argc, char **argv, LIST *list)
 	  */                                    
 	    tmp_val = parameter2double(argv[iarg]);
 
-	  listSetFlt(list, nint++, tmp_val);
+	  lista_set_flt(lista, nint++, tmp_val);
 	}
       else
 	{
@@ -225,15 +218,15 @@ int args2fltlist(int argc, char **argv, LIST *list)
 	  if ( inc >= 0 )
 	    {
 	      for ( ival = first; ival <= last; ival += inc )
-		listSetFlt(list, nint++, (double) ival);
+		lista_set_flt(lista, nint++, (double) ival);
 	    }
 	  else
 	    {
 	      for ( ival = first; ival >= last; ival += inc )
-		listSetFlt(list, nint++, (double) ival);
+		lista_set_flt(lista, nint++, (double) ival);
 	    }
 	}
     }
 
-  return (nint);
+  return nint;
 }
diff --git a/src/list.h b/src/listarray.h
similarity index 54%
copy from src/list.h
copy to src/listarray.h
index e42a55c..c3c955b 100644
--- a/src/list.h
+++ b/src/listarray.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -15,11 +15,11 @@
   GNU General Public License for more details.
 */
 
-#ifndef _LIST_H
-#define _LIST_H
+#ifndef _LISTA_H
+#define _LISTA_H
 
-#define  INT_LIST  1
-#define  FLT_LIST  2
+#define  INT_LISTA  1
+#define  FLT_LISTA  2
 
 
 typedef struct {
@@ -28,17 +28,17 @@ typedef struct {
   int allinc;
   int type;
 }
-LIST;
+lista_t;
 
 
-LIST *listNew(int type);
-void listDelete(LIST *list);
-void *listArrayPtr(LIST *list);
-void listSetInt(LIST *list, int num, int ival);
-void listSetFlt(LIST *list, int num, double fval);
-int listGetInt(LIST *list, int num);
-double listGetFlt(LIST *list, int num);
-int args2intlist(int argc, char **argv, LIST *list);
-int args2fltlist(int argc, char **argv, LIST *list);
+lista_t *lista_new(int type);
+void lista_destroy(lista_t *lista);
+void *lista_dataptr(lista_t *lista);
+void lista_set_int(lista_t *lista, int num, int ival);
+void lista_set_flt(lista_t *lista, int num, double fval);
+int listaGetInt(lista_t *lista, int num);
+double listaGetFlt(lista_t *lista, int num);
+int args2int_lista(int argc, char **argv, lista_t *lista);
+int args2flt_lista(int argc, char **argv, lista_t *lista);
 
-#endif  /* _LIST_H */
+#endif  /* _LISTA_H */
diff --git a/src/listbuf.c b/src/listbuf.c
new file mode 100644
index 0000000..d3295ee
--- /dev/null
+++ b/src/listbuf.c
@@ -0,0 +1,70 @@
+#include <string.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include "listbuf.h"
+
+listbuf_t *listbuf_new(void)
+{
+  listbuf_t *listbuf = (listbuf_t *) malloc(sizeof(listbuf_t));
+  if ( listbuf )
+    {
+      listbuf->size = 0;
+      listbuf->buffer = NULL;
+      listbuf->name = NULL;
+    }
+
+  return listbuf;
+}
+
+
+int listbuf_read(listbuf_t *listbuf, FILE *fp, const char *name)
+{
+  int filedes = fileno(fp);
+  struct stat buf;
+  size_t filesize = 0;
+  if ( fstat(filedes, &buf) == 0 ) filesize = (size_t) buf.st_size;
+
+  if ( filesize > MAX_LISTBUF_SIZE )
+    {
+      fprintf(stderr, "%s: max buffer size of %d exceeded (%s)!\n", __func__, (int)MAX_LISTBUF_SIZE, name);
+      return -1;
+    }
+  else if ( filesize == 0 )
+    {
+      fprintf(stderr, "%s: empty stream: %s\n", __func__, name);
+      return -1;
+    }
+
+  char *buffer = (char*) malloc(filesize);
+  size_t nitems = fread(buffer, 1, filesize, fp);
+
+  if ( nitems != filesize )
+    {
+      free(buffer);
+      fprintf(stderr, "%s: read failed on %s!\n", __func__, name);
+      return -1;
+    }
+
+  listbuf->size = filesize;
+  listbuf->buffer = buffer;
+
+  if ( name ) listbuf->name = strdup(name);
+
+  return 0;
+}
+
+
+void listbuf_destroy(listbuf_t *listbuf)
+{
+  if ( listbuf )
+    {
+      if ( listbuf->buffer ) free(listbuf->buffer);
+      if ( listbuf->name ) free(listbuf->name);
+      listbuf->size = 0;
+      listbuf->buffer = NULL;
+      listbuf->name = NULL;
+      free(listbuf);
+    }
+}
+
+
diff --git a/src/listbuf.h b/src/listbuf.h
new file mode 100644
index 0000000..37ea78e
--- /dev/null
+++ b/src/listbuf.h
@@ -0,0 +1,20 @@
+#ifndef _LISTBUF_H
+#define _LISTBUF_H
+
+#include <stdio.h>
+
+#define MAX_LISTBUF_SIZE (128*1024*1024)
+
+typedef struct
+{
+  size_t size;
+  char *buffer;
+  char *name;
+} listbuf_t;
+
+
+listbuf_t *listbuf_new();
+void listbuf_destroy(listbuf_t *listbuf);
+int listbuf_read(listbuf_t *listbuf, FILE *fp, const char *name);
+
+#endif
diff --git a/src/merge_sort2.c b/src/merge_sort2.c
index 91770e4..6689b50 100644
--- a/src/merge_sort2.c
+++ b/src/merge_sort2.c
@@ -57,9 +57,9 @@ void sort_par(long num_links, double *restrict add1, int parent, int par_depth)
   int nsplit = NSPLIT;                      /* (only 2 allowed) number of segments to split 
 						the data */
   int nl[NSPLIT];                            /* number of links in each sub-array              */
-  int who_am_i,depth,my_depth;               /* current depth, depth of children and index
+  int who_am_i,depth;                        /* current depth, depth of children and index
 						to be parent in next call to sort_par          */
-  int add_srt[NSPLIT], add_end[NSPLIT];      /* arrays for start and end index of sub array    */
+  int add_srt[NSPLIT];                       /* array for start index of sub array    */
   double *add1s[NSPLIT];                     /* pointers to sub arrays for sort and merge step */
   double *tmp;                               /* pointer to buffer for merging of address lists */
   long *idx;                                 /* index list to merge sub-arrays                 */
@@ -77,7 +77,6 @@ void sort_par(long num_links, double *restrict add1, int parent, int par_depth)
   add_srt[0] = 0;                  add_srt[1] = num_links/nsplit;
   add1s[0]   = &add1[add_srt[0]];  add1s[1]   = &add1[add_srt[1]];
   nl[0]      = num_links/nsplit;   nl[1]      = num_links-nl[0];
-  add_end[0] = nl[0];              add_end[1] = num_links;
 
   depth = (int) (log(parent)/log(2));
 
@@ -94,18 +93,20 @@ void sort_par(long num_links, double *restrict add1, int parent, int par_depth)
 
 #if defined(_OPENMP)
 #pragma omp parallel for if(depth<par_depth) \
-  private(i,who_am_i,my_depth) \
+  private(i,who_am_i) \
   num_threads(2)
 #endif
   for ( i=0; i < nsplit; i++ )
     {
       who_am_i = nsplit*parent+i;
-      my_depth = (int) (log(parent)/log(2))+1;
 
 #if defined(_OPENMP)
       /*      if ( 0 )
-      	cdoPrint("I am %i (parent %i), my_depth is: %i thread_num %i (%i)",
-	who_am_i,parent,my_depth,omp_get_thread_num()+1,omp_get_num_threads());
+        {
+          int my_depth = (int) (log(parent)/log(2))+1;
+      	  cdoPrint("I am %i (parent %i), my_depth is: %i thread_num %i (%i)",
+	  who_am_i,parent,my_depth,omp_get_thread_num()+1,omp_get_num_threads());
+        }
       */
 #endif
             
@@ -322,7 +323,7 @@ void sort_iter_single(long num_links, double *restrict add1, int parent)
 
   static int MERGE_SORT_LIMIT_SIZE = 16384; 
   static int first_sort_iter_call = 1;
-  static double merge_time;
+  // static double merge_time;
 
   int par_depth = 1;
               
@@ -347,7 +348,7 @@ void sort_iter_single(long num_links, double *restrict add1, int parent)
     //    merge_time = merge_time * (info.numer / info.denom)/1000./num_links;
     //    fprintf(stderr,"%12.8g ",merge_time);
     
-    merge_time = 0;
+    // merge_time = 0;
   }
 
   return;
diff --git a/src/modules.c b/src/modules.c
index 7421315..20e706e 100644
--- a/src/modules.c
+++ b/src/modules.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -54,6 +54,8 @@ void *Change(void *argument);
 void *Change_e5slm(void *argument);
 void *Cloudlayer(void *argument);
 void *CMOR(void *argument);
+void *CMOR_lite(void *argument);
+void *CMOR_table(void *argument);
 void *Collgrid(void *argument);
 void *Command(void *argument);
 void *Comp(void *argument);
@@ -64,6 +66,7 @@ void *Cond2(void *argument);
 void *Condc(void *argument);
 void *Consecstat(void *argument);
 void *Copy(void *argument);
+void *Deltat(void *argument);
 void *Deltime(void *argument);
 void *Derivepar(void *argument);
 void *Detrend(void *argument);
@@ -112,7 +115,6 @@ void *Intyear(void *argument);
 void *Invert(void *argument);
 void *Invertlev(void *argument);
 void *Isosurface(void *argument);
-void *Kvl(void *argument);
 void *Log(void *argument);
 void *MapReduce(void *argument);
 void *Maskbox(void *argument);
@@ -126,7 +128,7 @@ void *Monarith(void *argument);
 void *Mrotuv(void *argument);
 void *Mrotuvb(void *argument);
 void *Ninfo(void *argument);
-void *Nmltest(void *argument);
+void *Nmldump(void *argument);
 void *Output(void *argument);
 void *Outputgmt(void *argument);
 void *Pack(void *argument);
@@ -146,12 +148,14 @@ void *Seascount(void *argument);
 void *Seaspctl(void *argument);
 void *Seasstat(void *argument);
 void *Selbox(void *argument);
+void *Selindex(void *argument);
 void *Select(void *argument);
 void *Selvar(void *argument);
 void *Seloperator(void *argument);
 void *Selrec(void *argument);
 void *Seltime(void *argument);
 void *Set(void *argument);
+void *Setattribute(void *argument);
 void *Setbox(void *argument);
 void *Setgatt(void *argument);
 void *Setgrid(void *argument);
@@ -161,6 +165,7 @@ void *Setpartab(void *argument);
 void *Setrcaname(void *argument);
 void *Settime(void *argument);
 void *Setzaxis(void *argument);
+void *Shiftxy(void *argument);
 void *Showinfo(void *argument);
 void *Sinfo(void *argument);
 void *Smooth(void *argument);
@@ -182,9 +187,9 @@ void *Test(void *argument);
 void *Test2(void *argument);
 void *Testdata(void *argument);
 void *Tests(void *argument);
-void *Timedt(void *argument);
 void *Timsort(void *argument);
 void *Timcount(void *argument);
+void *Timcumsum(void *argument);
 void *Timpctl(void *argument);
 void *Timselpctl(void *argument);
 void *Timselstat(void *argument);
@@ -289,6 +294,8 @@ void *Maggraph(void *argument);
 #define  Change_e5slmOperators  {"change_e5slm", "change_e5lsm", "change_e5mask"}
 #define  CloudlayerOperators    {"cloudlayer"}
 #define  CMOROperators          {"cmor"}
+#define  CMORliteOperators      {"cmorlite"}
+#define  CMORtableOperators     {"dump_cmor_table", "conv_cmor_table"}
 #define  CollgridOperators      {"collgrid"}
 #define  CommandOperators       {"command", "com", "cmd"}
 #define  CompOperators          {"eq",  "ne",  "le",  "lt",  "ge",  "gt"}
@@ -299,14 +306,14 @@ void *Maggraph(void *argument);
 #define  CondcOperators         {"ifthenc", "ifnotthenc"}
 #define  ConsecstatOperators    {"consects", "consecsum"}
 #define  CopyOperators          {"copy", "selall", "szip"}
+#define  DeltatOperators        {"deltat"}
 #define  DeltimeOperators       {"delday", "del29feb"}
 #define  DeriveparOperators     {"gheight", "sealevelpressure"}
 #define  DetrendOperators       {"detrend"}
 #define  DiffOperators          {"diff", "diffp", "diffn", "diffc"}
 #define  DistgridOperators      {"distgrid"}
 #define  DuplicateOperators     {"duplicate"}
-#define  Echam5iniOperators     {"import_e5ml", "import_e5res", \
-                                 "export_e5ml", "export_e5res"}
+#define  Echam5iniOperators     {"import_e5ml", "import_e5res", "export_e5ml", "export_e5res"}
 #define  EnlargeOperators       {"enlarge"}
 #define  EnlargegridOperators   {"enlargegrid"}
 #define  EnsstatOperators       {"ensmin", "ensmax", "enssum", "ensmean", "ensavg", "ensvar", "ensvar1", "ensstd", "ensstd1", "enspctl"}
@@ -323,7 +330,7 @@ void *Maggraph(void *argument);
 #define  FillmissOperators      {"fillmiss", "fillmiss2"}
 #define  FilterOperators        {"bandpass", "highpass", "lowpass"}
 #define  FldrmsOperators        {"fldrms"}
-#define  FldstatOperators       {"fldmin", "fldmax", "fldsum", "fldmean", "fldavg", "fldstd", "fldstd1", "fldvar", "fldvar1", "fldpctl"}
+#define  FldstatOperators       {"fldrange", "fldmin", "fldmax", "fldsum", "fldmean", "fldavg", "fldstd", "fldstd1", "fldvar", "fldvar1", "fldpctl"}
 #define  FldcorOperators        {"fldcor"}
 #define  FldcovarOperators      {"fldcovar"}
 #define  FourierOperators       {"fourier"}
@@ -340,7 +347,7 @@ void *Maggraph(void *argument);
 #define  ImportobsOperators     {"import_obs"}
 #define  InfoOperators          {"info", "infop", "infon", "infoc", "map"}
 #define  InputOperators         {"input", "inputsrv", "inputext"}
-#define  IntgridOperators       {"intgridbil", "intgridcon", "intpoint", "interpolate", "boxavg", "thinout"}
+#define  IntgridOperators       {"intgridbil", "intpoint", "interpolate", "boxavg", "thinout"}
 #define  IntgridtrajOperators   {"intgridtraj"}
 #define  IntlevelOperators      {"intlevel", "intlevelx"}
 #define  Intlevel3dOperators    {"intlevel3d", "intlevelx3d"}
@@ -350,7 +357,6 @@ void *Maggraph(void *argument);
 #define  InvertOperators        {"invertlat", "invertlon", "invertlatdes", "invertlondes", "invertlatdata", "invertlondata"}
 #define  InvertlevOperators     {"invertlev"}
 #define  IsosurfaceOperators    {"isosurface"}
-#define  KvlOperators           {"read_cmor_table", "conv_cmor_table"}
 #define  LogOperators           {"dumplogs", "daylogs", "monlogs", "dumplogo", "snamelogo", "scalllogo", "smemlogo", "stimelogo", "sperclogo"}
 #define  MapReduceOperators     {"reducegrid"}
 #define  MaskboxOperators       {"masklonlatbox", "maskindexbox"}
@@ -366,7 +372,7 @@ void *Maggraph(void *argument);
 #define  MrotuvOperators        {"mrotuv"}
 #define  MrotuvbOperators       {"mrotuvb"}
 #define  NinfoOperators         {"nyear", "nmon", "ndate", "ntime", "ncode", "npar", "nlevel", "ngridpoints", "ngrids"}
-#define  NmltestOperators       {"nmltest"}
+#define  NmldumpOperators       {"nmldump", "kvldump"}
 #define  OutputOperators        {"output", "outputint", "outputsrv", "outputext", "outputf", "outputts", \
                                  "outputfld", "outputarr", "outputxyz"}
 #define  OutputtabOperators     {"outputtab"}
@@ -398,6 +404,7 @@ void *Maggraph(void *argument);
 #define  SeaspctlOperators      {"seaspctl"}
 #define  SeasstatOperators      {"seasmin", "seasmax", "seassum", "seasmean", "seasavg", "seasstd", "seasstd1", "seasvar", "seasvar1"}
 #define  SelboxOperators        {"sellonlatbox", "selindexbox"}
+#define  SelindexOperators      {"selindex"}
 #define  SelectOperators        {"select", "delete"}
 #define  SelvarOperators        {"selparam", "selcode", "selname", "selstdname", "sellevel", "sellevidx", "selgrid", \
                                  "selzaxis", "selzaxisname", "seltabnum", "delparam", "delcode", "delname", "selltype"}
@@ -406,6 +413,7 @@ void *Maggraph(void *argument);
 #define  SeltimeOperators       {"seltimestep", "selyear", "selseason", "selmonth", "selday", "selhour", "seldate", \
                                  "seltime", "selsmon"}
 #define  SetOperators           {"setcode", "setparam", "setname", "setunit", "setlevel", "setltype", "settabnum"}
+#define  SetattributeOperators  {"setattribute"}
 #define  SetboxOperators        {"setclonlatbox", "setcindexbox"}
 #define  SetgattOperators       {"setgatt", "setgatts"}
 #define  SetgridOperators       {"setgrid", "setgridtype", "setgridarea", "setgridmask", "unsetgridmask", "setgridnumber", "setgriduri"}
@@ -418,6 +426,7 @@ void *Maggraph(void *argument);
 #define  SettimeOperators       {"setyear", "setmon", "setday", "setdate", "settime", "settunits", \
                                  "settaxis", "settbounds", "setreftime", "setcalendar", "shifttime"}
 #define  SetzaxisOperators      {"setzaxis", "genlevelbounds"}
+#define  ShiftxyOperators       {"shiftx", "shifty"}
 #define  ShowinfoOperators      {"showyear", "showmon", "showdate", "showtime", "showtimestamp", "showcode", "showunit", \
                                  "showparam", "showname", "showstdname", "showlevel", "showltype", "showformat"}
 #define  SinfoOperators         {"sinfo", "sinfop", "sinfon", "sinfoc", "seinfo", "seinfop", "seinfon", "seinfoc"}
@@ -440,13 +449,13 @@ void *Maggraph(void *argument);
 #define  Test2Operators         {"test2"}
 #define  TestdataOperators      {"testdata"}
 #define  TestsOperators         {"normal", "studentt", "chisquare", "beta", "fisher"}
-#define  TimedtOperators        {"timedt"}
 #define  TimsortOperators       {"timsort"}
 #define  TimcountOperators      {"timcount"}
 #define    YearcountOperators   {"yearcount"}
 #define    MoncountOperators    {"moncount"}
 #define    DaycountOperators    {"daycount"}
 #define    HourcountOperators   {"hourcount"}
+#define  TimcumsumOperators     {"timcumsum"}
 #define  TimpctlOperators       {"timpctl"}
 #define    YearpctlOperators    {"yearpctl"}
 #define    MonpctlOperators     {"monpctl"}
@@ -457,11 +466,11 @@ void *Maggraph(void *argument);
 #define  XTimstatOperators      {"xtimmin",  "xtimmax",  "xtimsum",  "xtimmean",  "xtimavg",  "xtimvar",  "xtimvar1",  "xtimstd",  "xtimstd1", \
                                  "xyearmin", "xyearmax", "xyearsum", "xyearmean", "xyearavg", "xyearvar", "xyearvar1", "xyearstd", "xyearstd1", \
                                  "xmonmin",  "xmonmax",  "xmonsum",  "xmonmean",  "xmonavg",  "xmonvar",  "xmonvar1",  "xmonstd",  "xmonstd1"}
-#define  TimstatOperators       {"timmin",  "timmax",  "timsum",  "timmean",  "timavg",  "timvar",  "timvar1",  "timstd",  "timstd1"}
-#define    YearstatOperators    {"yearmin", "yearmax", "yearsum", "yearmean", "yearavg", "yearvar", "yearvar1", "yearstd", "yearstd1"}
-#define    MonstatOperators     {"monmin",  "monmax",  "monsum",  "monmean",  "monavg",  "monvar",  "monvar1",  "monstd",  "monstd1"}
-#define    DaystatOperators     {"daymin",  "daymax",  "daysum",  "daymean",  "dayavg",  "dayvar",  "dayvar1",  "daystd",  "daystd1"}
-#define    HourstatOperators    {"hourmin", "hourmax", "hoursum", "hourmean", "houravg", "hourvar", "hourvar1", "hourstd", "hourstd1"}
+#define  TimstatOperators       {"timrange",  "timmin",  "timmax",  "timsum",  "timmean",  "timavg",  "timvar",  "timvar1",  "timstd",  "timstd1"}
+#define    YearstatOperators    {"yearrange", "yearmin", "yearmax", "yearsum", "yearmean", "yearavg", "yearvar", "yearvar1", "yearstd", "yearstd1"}
+#define    MonstatOperators     {"monrange",  "monmin",  "monmax",  "monsum",  "monmean",  "monavg",  "monvar",  "monvar1",  "monstd",  "monstd1"}
+#define    DaystatOperators     {"dayrange",  "daymin",  "daymax",  "daysum",  "daymean",  "dayavg",  "dayvar",  "dayvar1",  "daystd",  "daystd1"}
+#define    HourstatOperators    {"hourrange", "hourmin", "hourmax", "hoursum", "hourmean", "houravg", "hourvar", "hourvar1", "hourstd", "hourstd1"}
 #define  TimcorOperators        {"timcor"}
 #define  TimcovarOperators      {"timcovar"}
 #define  Timstat3Operators      {"meandiff2test", "varquot2test"}
@@ -575,6 +584,8 @@ static modules_t Modules[] =
   { Change_e5slm,   NULL,              Change_e5slmOperators,  0,   CDI_REAL,  1,  1 },
   { Cloudlayer,     NULL,              CloudlayerOperators,    1,   CDI_REAL,  1,  1 },
   { CMOR,           NULL,              CMOROperators,          1,   CDI_REAL,  1,  0 },
+  { CMOR_lite,      CMORliteHelp,      CMORliteOperators,      1,   CDI_REAL,  1,  1 },
+  { CMOR_table,     NULL,              CMORtableOperators,     1,   CDI_REAL,  0,  0 },
   { Collgrid,       CollgridHelp,      CollgridOperators,      1,   CDI_REAL, -1,  1 },
   { Command,        NULL,              CommandOperators,       0,   CDI_REAL,  1,  0 },
   { Comp,           CompHelp,          CompOperators,          1,   CDI_REAL,  2,  1 },
@@ -585,6 +596,7 @@ static modules_t Modules[] =
   { Condc,          CondcHelp,         CondcOperators,         1,   CDI_REAL,  1,  1 },
   { Consecstat,     ConsecstatHelp,    ConsecstatOperators,    1,   CDI_REAL,  1,  1 },
   { Copy,           CopyHelp,          CopyOperators,          1,   CDI_REAL, -1,  1 },
+  { Deltat,         NULL,              DeltatOperators,        1,   CDI_REAL,  1,  1 },
   { Deltime,        NULL,              DeltimeOperators,       1,   CDI_REAL,  1,  1 },
   { Derivepar,      DeriveparHelp,     DeriveparOperators,     1,   CDI_REAL,  1,  1 },
   { Detrend,        DetrendHelp,       DetrendOperators,       1,   CDI_REAL,  1,  1 },
@@ -634,7 +646,6 @@ static modules_t Modules[] =
   { Invert,         InvertHelp,        InvertOperators,        1,   CDI_REAL,  1,  1 },
   { Invertlev,      InvertlevHelp,     InvertlevOperators,     1,   CDI_REAL,  1,  1 },
   { Isosurface,     NULL,              IsosurfaceOperators,    1,   CDI_REAL,  1,  1 },
-  { Kvl,            NULL,              KvlOperators,           1,   CDI_REAL,  0,  0 },
   { Log,            NULL,              LogOperators,           0,   CDI_REAL,  1,  0 },
   { MapReduce,      MapReduceHelp,     MapReduceOperators,     1,   CDI_REAL,  1,  1 },
   { Maskbox,        MaskboxHelp,       MaskboxOperators,       1,   CDI_REAL,  1,  1 },
@@ -649,7 +660,7 @@ static modules_t Modules[] =
   { Mrotuv,         NULL,              MrotuvOperators,        1,   CDI_REAL,  1,  2 },
   { Mrotuvb,        NULL,              MrotuvbOperators,       1,   CDI_REAL,  2,  1 },
   { Ninfo,          NinfoHelp,         NinfoOperators,         1,   CDI_BOTH,  1,  0 },
-  { Nmltest,        NULL,              NmltestOperators,       0,   CDI_REAL,  0,  0 },
+  { Nmldump,        NULL,              NmldumpOperators,       0,   CDI_REAL,  0,  0 },
   { Output,         OutputHelp,        OutputOperators,        1,   CDI_REAL, -1,  0 },
   { Output,         OutputtabHelp,     OutputtabOperators,     1,   CDI_REAL, -1,  0 },
   { Outputgmt,      OutputgmtHelp,     OutputgmtOperators,     1,   CDI_REAL,  1,  0 },
@@ -679,14 +690,16 @@ static modules_t Modules[] =
   { Seaspctl,       SeaspctlHelp,      SeaspctlOperators,      1,   CDI_REAL,  3,  1 },
   { Seasstat,       SeasstatHelp,      SeasstatOperators,      1,   CDI_REAL,  1,  1 },
   { Selbox,         SelboxHelp,        SelboxOperators,        1,   CDI_BOTH,  1,  1 },
+  { Selindex,       NULL,              SelindexOperators,      1,   CDI_BOTH,  1,  1 },
   { Select,         SelectHelp,        SelectOperators,        1,   CDI_BOTH, -1,  1 },
   { Selvar,         SelvarHelp,        SelvarOperators,        1,   CDI_BOTH,  1,  1 },
   { Selrec,         SelvarHelp,        SelrecOperators,        1,   CDI_BOTH,  1,  1 },
   { Seloperator,    NULL,              SeloperatorOperators,   1,   CDI_REAL,  1,  1 },
   { Seltime,        SeltimeHelp,       SeltimeOperators,       1,   CDI_BOTH,  1,  1 },
   { Set,            SetHelp,           SetOperators,           1,   CDI_BOTH,  1,  1 },
+  { Setattribute,   SetattributeHelp,  SetattributeOperators,  1,   CDI_BOTH,  1,  1 },
   { Setbox,         SetboxHelp,        SetboxOperators,        1,   CDI_REAL,  1,  1 },
-  { Setgatt,        SetgattHelp,       SetgattOperators,       1,   CDI_BOTH,  1,  1 },
+  { Setgatt,        NULL,              SetgattOperators,       1,   CDI_BOTH,  1,  1 },
   { Setgrid,        SetgridHelp,       SetgridOperators,       1,   CDI_BOTH,  1,  1 },
   { Sethalo,        SethaloHelp,       SethaloOperators,       1,   CDI_REAL,  1,  1 },
   { Setmiss,        SetmissHelp,       SetmissOperators,       1,   CDI_REAL,  1,  1 },
@@ -696,6 +709,7 @@ static modules_t Modules[] =
   { Setrcaname,     NULL,              SetrcanameOperators,    1,   CDI_REAL,  1,  1 },
   { Settime,        SettimeHelp,       SettimeOperators,       1,   CDI_BOTH,  1,  1 },
   { Setzaxis,       SetzaxisHelp,      SetzaxisOperators,      1,   CDI_BOTH,  1,  1 },
+  { Shiftxy,        ShiftxyHelp,       ShiftxyOperators,       1,   CDI_REAL,  1,  1 },
   { Showinfo,       ShowinfoHelp,      ShowinfoOperators,      1,   CDI_BOTH,  1,  0 },
   { Sinfo,          SinfoHelp,         SinfoOperators,         1,   CDI_BOTH, -1,  0 },
   { Smooth,         SmoothHelp,        SmoothOperators,        1,   CDI_REAL,  1,  1 },
@@ -722,13 +736,13 @@ static modules_t Modules[] =
   { Timcount,       NULL,              MoncountOperators,      1,   CDI_BOTH,  1,  1 },
   { Timcount,       NULL,              DaycountOperators,      1,   CDI_BOTH,  1,  1 },
   { Timcount,       NULL,              HourcountOperators,     1,   CDI_BOTH,  1,  1 },
+  { Timcumsum,      TimcumsumHelp,     TimcumsumOperators,     1,   CDI_BOTH,  1,  1 },
   { Timpctl,        TimpctlHelp,       TimpctlOperators,       1,   CDI_REAL,  3,  1 },
   { Timpctl,        YearpctlHelp,      YearpctlOperators,      1,   CDI_REAL,  3,  1 },
   { Timpctl,        MonpctlHelp,       MonpctlOperators,       1,   CDI_REAL,  3,  1 },
   { Timpctl,        DaypctlHelp,       DaypctlOperators,       1,   CDI_REAL,  3,  1 },
   { Timpctl,        HourpctlHelp,      HourpctlOperators,      1,   CDI_REAL,  3,  1 },
   { Timselpctl,     TimselpctlHelp,    TimselpctlOperators,    1,   CDI_REAL,  3,  1 },
-  { Timedt,         NULL,              TimedtOperators,        1,   CDI_REAL,  1,  1 },
   { Timsort,        TimsortHelp,       TimsortOperators,       1,   CDI_REAL,  1,  1 },
   { Timselstat,     TimselstatHelp,    TimselstatOperators,    1,   CDI_REAL,  1,  1 },
   { XTimstat,       NULL,              XTimstatOperators,      0,   CDI_BOTH,  1,  1 },
@@ -880,10 +894,10 @@ static int nopalias = sizeof(opalias) / (2*sizeof(opalias[0][0]));
 
 
 static
-int similar(const char *a, const char *b, int alen, int blen)
+bool similar(const char *a, const char *b, int alen, int blen)
 {
   if ( alen > 2 && blen > 2 && strstr(b, a) )
-    return TRUE;
+    return true;
 
   while ( *a && *b && *a == *b )
     { 
@@ -891,21 +905,21 @@ int similar(const char *a, const char *b, int alen, int blen)
       b++;
     }
   if ( !*a && !*b )
-    return TRUE;
+    return true;
   /*
     printf("%d %d %s %s\n", alen, blen, a, b);
   */
   if ( alen >= 2 && blen >= 1 && *a && similar(a+1, b, alen-2, blen-1) )
-    return TRUE;
+    return true;
 
   if ( alen >= 1 && blen >= 2 && *b && similar(a, b+1, alen-1, blen-2) )
-    return TRUE;
+    return true;
 
-  return FALSE; 
+  return false; 
 }
 
 
-const char *operatorAlias(char *operatorName)
+const char *operatorAlias(const char *operatorName)
 {
   int i;
 
@@ -957,41 +971,47 @@ int operatorInqModID(const char *operatorName)
 
   if ( modID == -1 )
     {
-      int nbyte;
-      int error = TRUE;
+      bool lfound = false;
       FILE *fp = fopen(operatorName, "r");
       if ( fp )
 	{
 	  fclose(fp);
 	  fprintf(stderr, "Use commandline option -h for help.");
-	  Error("operator missing! %s is a file on disk!", operatorName);
+	  Error("Operator missing, %s is a file on disk!", operatorName);
 	}
 
       fprintf(stderr, "Operator >%s< not found!\n", operatorName);
       fprintf(stderr, "Similar operators are:\n");
-      nbyte = fprintf(stderr, "   ");
+      int nbyte = fprintf(stderr, "   ");
       if ( operatorName )
-	for ( i = 0; i < NumModules; i++ )
-	  {
-	    if ( Modules[i].help == NULL ) continue;
-	    j = 0;
-	    while ( Modules[i].operators[j] )
-	      {
-		if( similar(operatorName, Modules[i].operators[j],
-			    strlen(operatorName), strlen(Modules[i].operators[j])) )
-		  {
-		    if ( nbyte > 75 )
-		      {
-			fprintf(stdout, "\n");
-			nbyte = fprintf(stderr, "   ");
-		      }
-		    nbyte += fprintf(stderr, " %s", Modules[i].operators[j]);
-		    error = FALSE ;
-		  }
-		j++;
-	      }
-	  }
-      if ( error )
+        {
+          int len = strlen(operatorName);
+          char *opname = strdup(operatorName);
+          strtolower(opname);
+          for ( i = 0; i < NumModules; i++ )
+            {
+              if ( Modules[i].help == NULL ) continue;
+              j = 0;
+              while ( Modules[i].operators[j] )
+                {
+                  if ( similar(opname, Modules[i].operators[j],
+                               len, strlen(Modules[i].operators[j])) )
+                    {
+                      if ( nbyte > 75 )
+                        {
+                          fprintf(stdout, "\n");
+                          nbyte = fprintf(stderr, "   ");
+                        }
+                      nbyte += fprintf(stderr, " %s", Modules[i].operators[j]);
+                      lfound = true;
+                    }
+                  j++;
+                }
+            }
+          free(opname);
+        }
+
+      if ( !lfound )
 	fprintf(stderr, "(not found)\n") ;
       else
 	fprintf(stderr, "\n");
@@ -1006,31 +1026,31 @@ int operatorInqModID(const char *operatorName)
   return modID;
 }
 
-void *(*operatorModule(char *operatorName))(void *)
+void *(*operatorModule(const char *operatorName))(void *)
 {
   int modID = operatorInqModID(operatorName);
   return Modules[modID].func;
 }
 
-const char **operatorHelp(char *operatorName)
+const char **operatorHelp(const char *operatorName)
 {
   int modID = operatorInqModID(operatorName);
   return Modules[modID].help;
 }
 
-int operatorStreamInCnt(char *operatorName)
+int operatorStreamInCnt(const char *operatorName)
 {
   int modID = operatorInqModID(operatorAlias(operatorName));
   return Modules[modID].streamInCnt;
 }
 
-int operatorStreamOutCnt(char *operatorName)
+int operatorStreamOutCnt(const char *operatorName)
 {
   int modID = operatorInqModID(operatorAlias(operatorName));
   return Modules[modID].streamOutCnt;
 }
 
-int operatorStreamNumber(char *operatorName)
+int operatorStreamNumber(const char *operatorName)
 {
   int modID = operatorInqModID(operatorAlias(operatorName));
   return Modules[modID].number;
@@ -1082,7 +1102,7 @@ void operatorPrintAll(void)
 }
 
 
-void operatorPrintList(void)
+void operatorPrintList(bool print_no_output)
 {
   int i, j, nbyte, nop = 0;
   const char *opernames[4096];
@@ -1099,10 +1119,7 @@ void operatorPrintList(void)
     }
 
   // Add operator aliases
-  for ( i = 0; i < nopalias; i++ )
-    {
-      opernames[nop++] = opalias[i][0];
-    }
+  for ( i = 0; i < nopalias; i++ ) opernames[nop++] = opalias[i][0];
 
   qsort(opernames, nop, sizeof(char *), cmpname);
 
@@ -1182,10 +1199,13 @@ void operatorPrintList(void)
             }      
         }
 
-      nbyte = fprintf(pout, "%s ", opernames[i]);
-      for ( int i = nbyte; i <= 16; ++i ) fprintf(pout, " ");
-      if ( pdes ) fprintf(pout, "%s", pdes);
-      else if ( ialias >= 0 )  fprintf(pout, "--> %s", opalias[ialias][1]);
-      fprintf(pout, "\n");
+      if ( !print_no_output || operatorStreamOutCnt(opernames[i]) == 0 )
+        {
+          nbyte = fprintf(pout, "%s ", opernames[i]);
+          for ( int i = nbyte; i <= 16; ++i ) fprintf(pout, " ");
+          if ( pdes ) fprintf(pout, "%s", pdes);
+          else if ( ialias >= 0 )  fprintf(pout, "--> %s", opalias[ialias][1]);
+          fprintf(pout, "\n");
+        }
     }
 }
diff --git a/src/modules.h b/src/modules.h
index 1820184..1881a58 100644
--- a/src/modules.h
+++ b/src/modules.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -18,15 +18,17 @@
 #ifndef _MODULES_H
 #define _MODULES_H
 
-void *(*operatorModule(char *operatorName))(void *);
+#include <stdbool.h>
 
-const char **operatorHelp(char *operatorName);
+void *(*operatorModule(const char *operatorName))(void *);
 
-int operatorStreamInCnt(char *operatorName);
-int operatorStreamOutCnt(char *operatorName);
-int operatorStreamNumber(char *operatorName);
+const char **operatorHelp(const char *operatorName);
+
+int operatorStreamInCnt(const char *operatorName);
+int operatorStreamOutCnt(const char *operatorName);
+int operatorStreamNumber(const char *operatorName);
 
 void operatorPrintAll(void);
-void operatorPrintList(void);
+void operatorPrintList(bool print_no_output);
 
 #endif  /* _MODULES_H */
diff --git a/src/namelist.c b/src/namelist.c
index f6f35fd..715599f 100644
--- a/src/namelist.c
+++ b/src/namelist.c
@@ -1,581 +1,305 @@
-/*
-  This file is part of CDO. CDO is a collection of Operators to
-  manipulate and analyse Climate model Data.
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
 
-  Copyright (C) 2003-2016 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 "cdo_int.h"
 #include "namelist.h"
 
 
-#ifndef strdupx
-#ifndef strdup
-char *strdup(const char *s);
-#endif
-#define strdupx  strdup
-#endif
-
-
-#define  func_1         -1 /* nptype */
-#define  func_2         -2 /* nptype */
-#define  func_3         -3 /* nptype */
-#define  NML_NIX         0 /* nptype */
-#define  NML_TEXTU       5
-#define  NML_TEXTL       6
-#define  NML_NPR         7
-#define  NML_NUMBER      8 /* nptype */
-#define  NML_KEYWORD     9 /* nptype */
-
-#define  PRINT_ALL       2
-#define  PRINT_MIN       3
-
-#undef   TRUE
-#define  TRUE   1
-#undef   FALSE
-#define  FALSE  0
-
-#undef   MIN
-#define  MIN(a,b)  ((a) < (b) ? (a) : (b))
-#undef   MAX
-#define  MAX(a,b)  ((a) > (b) ? (a) : (b))
-
-
-static void namelist_init(namelist_t *namelist, const char *name)
+static
+void namelist_init(namelist_parser *parser)
 {
-  namelist->size = 0;
-  namelist->dis  = 1;
-  namelist->name = strdup(name);
+  parser->tokens = NULL;
+  parser->num_tokens = 0;
+  parser->toknext = 0;
+  parser->pos = 0;
+  parser->lineno = 0;
 }
 
 
-namelist_t *namelistNew(const char *name)
+namelist_parser *namelist_new(void)
 {
-  namelist_t *namelist;
+  namelist_parser *parser = (namelist_parser *) malloc(sizeof(namelist_parser));
+  namelist_init(parser);
 
-  namelist = (namelist_t*) Malloc(sizeof(namelist_t));
-
-  namelist_init(namelist, name);
-
-  return (namelist);
+  return parser;
 }
 
 
-void namelistDelete(namelist_t *nml)
+void namelist_destroy(namelist_parser *parser)
 {
-  int i, iocc;
-
-  if ( nml )
+  if ( parser )
     {
-      for ( i = 0; i < nml->size; i++ )
-	{
-	  if ( nml->entry[i]->name ) Free(nml->entry[i]->name);
-	  if ( nml->entry[i]->type == NML_WORD )
-	    for ( iocc = 0; iocc < nml->entry[i]->occ; iocc++ )
-	      {
-		if ( ((char **)nml->entry[i]->ptr)[iocc] )
-		  {
-		    Free(((char **)nml->entry[i]->ptr)[iocc]);
-		    ((char **)nml->entry[i]->ptr)[iocc] = NULL;
-		  }
-	      }
-
-	  Free(nml->entry[i]);
-	}
-      
-      if ( nml->name ) Free(nml->name);
-      Free(nml);
+      if ( parser->tokens ) free(parser->tokens);
+      namelist_init(parser);
+      free(parser);
     }
 }
 
-
-void namelistReset(namelist_t *nml)
+// Allocates a fresh unused token from the token pull.
+static
+namelisttok_t *namelist_alloc_token(namelist_parser *parser)
 {
-  int i, iocc;
+  const unsigned int TOK_MEM_INCR = 64;
 
-  if ( nml )
+  if ( parser->toknext >= parser->num_tokens )
     {
-      for ( i = 0; i < nml->size; i++ )
-	{
-	  if ( nml->entry[i]->type == NML_WORD )
-	    for ( iocc = 0; iocc < nml->entry[i]->occ; iocc++ )
-	      {
-		if ( ((char **)nml->entry[i]->ptr)[iocc] )
-		  {
-		    Free(((char **)nml->entry[i]->ptr)[iocc]);
-		    ((char **)nml->entry[i]->ptr)[iocc] = NULL;
-		  }
-	      }
-	  else if ( nml->entry[i]->type == NML_TEXT )
-	    ((char *)nml->entry[i]->ptr)[0] = 0;
-
-	  nml->entry[i]->occ = 0;
-	}
+      parser->num_tokens += TOK_MEM_INCR;
+      parser->tokens = (namelisttok_t *) realloc(parser->tokens, sizeof(namelisttok_t) * parser->num_tokens);
+      if ( parser->tokens == NULL )
+        {
+          fprintf(stderr, "%s: Failed to allocated more memory!", __func__);
+          exit(-1);
+        }
     }
-}
 
+  namelisttok_t *tok = &parser->tokens[parser->toknext++];
+  tok->start = tok->end = -1;
+  return tok;
+}
 
-void namelistPrint(namelist_t *nml)
+// Fills token type and boundaries.
+static
+void namelist_fill_token(namelisttok_t *token, int type, int start, int end)
 {
-  nml_entry_t *entry;
-  int i, j, nout;
-
-  if ( nml == NULL ) return;
-
-  fprintf(stdout, "Namelist: %s\n", nml->name);
-  fprintf(stdout, " Num  Name             Type  Size   Dis   Occ  Entries\n");
-
-  for ( i = 0; i < nml->size; i++ )
-    {
-      entry = nml->entry[i];
-      fprintf(stdout, "%4d  %-16s %4d  %4d  %4d  %4d ",
-	      i+1, nml->entry[i]->name, nml->entry[i]->type, (int)nml->entry[i]->size,
-	      nml->entry[i]->dis, nml->entry[i]->occ);
-      nout = nml->entry[i]->occ;
-      if ( entry->type >= NML_TEXT )
-	{
-	  if ( nout > 32 ) nout = 32;
-	}
-      else
-	{
-	  if ( nout > 8 ) nout = 8;
-	}
-
-      if      ( entry->type >= NML_TEXT )
-	fprintf(stdout, "'%s'", ((char *)entry->ptr));
-      else if ( entry->type == NML_WORD )
-	for ( j = 0; j < nout; j++ )
-	  fprintf(stdout, " %s", ((char **)entry->ptr)[j]);
-      else if ( entry->type == NML_INT )
-	for ( j = 0; j < nout; j++ )
-	  fprintf(stdout, " %d", ((int *)entry->ptr)[j]);
-      else if ( entry->type == NML_FLT )
-	for ( j = 0; j < nout; j++ )
-	  fprintf(stdout, " %g", ((double *)entry->ptr)[j]);
-      
-      fprintf(stdout, "\n");
-    }
+  token->type = type;
+  token->start = start;
+  token->end = end;
 }
 
 
-int namelistAdd(namelist_t *nml, const char *name, int type, int dis, void *ptr, size_t size)
+void namelist_new_object(namelist_parser *parser)
 {
-  nml_entry_t *nml_entry;
-  int entry = 0;
-
-  if ( nml->size >= MAX_NML_ENTRY )
-    {
-      fprintf(stderr, "Too many namelist entries in %s! (Max = %d)\n", nml->name, MAX_NML_ENTRY);
-      return -1;
-    }
-
-  nml_entry = (nml_entry_t*) Malloc(sizeof(nml_entry_t));
-
-  nml_entry->name = strdup(name);
-  nml_entry->type = type;
-  nml_entry->ptr  = ptr;
-  nml_entry->size = size;
-  nml_entry->dis  = dis;
-  nml_entry->occ  = 0;
-
-  entry = nml->size;
-  nml->entry[nml->size++] = nml_entry;
-
-  return (entry);
+  namelisttok_t *token;
+  token = namelist_alloc_token(parser);
+  token->type = NAMELIST_OBJECT;
+  token->start = parser->pos;
 }
 
-
-int namelistNum(namelist_t *nml, const char *name)
+// Fills next available token with NAMELIST word.
+static
+int namelist_parse_word(namelist_parser *parser, const char *buf, size_t len)
 {
-  nml_entry_t *entry;
-  int i, nocc = 0;
-
-  if ( nml == NULL ) return (nocc);
+  namelisttok_t *token;
+  int start = parser->pos;
 
-  for ( i = 0; i < nml->size; i++ )
+  for ( ; parser->pos < len && buf[parser->pos] != '\0'; parser->pos++ )
     {
-      entry = nml->entry[i];
-      if ( strcmp(name, entry->name) == 0 )
-	{
-	  nocc = entry->occ;
-	  break;
-	}
+      switch (buf[parser->pos])
+        {
+        case ':': case '=':
+        case ',': case '&': case '/': 
+        case '\r': case '\n': case '\t': case ' ':
+          goto found;
+        }
+
+      if ( buf[parser->pos] < 32 || buf[parser->pos] >= 127 )
+        {
+          parser->pos = start;
+          return NAMELIST_ERROR_INVAL;
+        }
     }
 
-  if ( i == nml->size )
-    fprintf(stderr, "Namelist entry %s not found in %s\n", name, nml->name);
+ found:
 
-  return (nocc);
+  token = namelist_alloc_token(parser);
+  namelist_fill_token(token, NAMELIST_WORD, start, parser->pos);
+  parser->pos--;
+
+  return 0;
 }
 
+// Fills next token with NAMELIST string.
 static
-void getnite(FILE *nmlfp, namelist_t *nml)
+int namelist_parse_string(namelist_parser *parser, const char *buf, size_t len)
 {
-  int nst, i, j;
-  int linelen;
+  int start = parser->pos;
 
-  nst = nml->line.namitl + 1;
+  parser->pos++;
 
-  while ( TRUE )
+  /* Skip starting quote */
+  for ( ; parser->pos < len && buf[parser->pos] != '\0'; parser->pos++ )
     {
-      for ( i = nst; i < MAX_LINE_LEN; i++ )
-	{
-	  char *linelc = nml->line.linelc;
-	  int ch = (int) linelc[i];
-
-	  if ( ch == 0 ) break;
-
-          if      (   ch == ' ' ) continue;
-	  else if (   ch == '=' ) continue;
-          else if (   ch == ',' ) continue;
-          else if ( ((ch >= 'a')  && (ch <= 'z')) ||
-	             (ch == '_')  || (ch == '/')  ||
-	             (ch == '$')  || (ch == '&') )
-	    {
-	      nml->line.nptype = NML_KEYWORD;
-	      nml->line.namitf = i;
-	      for ( j = nml->line.namitf+1; j < MAX_LINE_LEN; j++ )
-		{
-		  if ( !(islower((int) linelc[j]) ||
-			 (((int) linelc[j]) == '_') ||
-			 (((int) linelc[j]) == '-') ||
-			 (((int) linelc[j]) == '+') ||
-			 isdigit((int) linelc[j])) )
-		    {
-		      nml->line.namitl = j - 1;
-		      return;
-		    }
-		}
-	      nml->line.namitl = MAX_LINE_LEN;
-	      return;
-	    }
-          else if ( ch == '\'' ||
-		    ch == '\"' ||
-		    ch == '`')
-	    {
-	      nml->line.nptype = NML_TEXT;
-	      nml->line.namitf = i;
-	      for ( j = nml->line.namitf+1; j < MAX_LINE_LEN; j++ )
-		if ( linelc[j] == linelc[nml->line.namitf])
-		  {
- 		    nml->line.namitl = j;
-		    return;
-		  }
-	      nml->line.namitl = MAX_LINE_LEN + 1;
-	      return;
-	    }
-          else if ( (ch >= '0'  && ch <= '9') ||
-		     ch == '+'  || ch == '-'  || ch == '.' )
-	    {
-	      nml->line.nptype = NML_NUMBER;
-	      nml->line.namitf = i;
-	      for ( j = i+1; j < MAX_LINE_LEN; j++)
-		{
-		  if ( linelc[j] >= '0' && linelc[j] <= '9' ) continue;
-	          else if ( linelc[j] == '+' ) continue;
-		  else if ( linelc[j] == '-' ) continue;
-         	  else if ( linelc[j] == '.' ) continue;
-		  else if ( linelc[j] == 'e' ) continue;
-                  else
-		    {
-		      nml->line.namitl = j - 1;
-		      return;
-		    }
-		}
-	      nml->line.namitl = MAX_LINE_LEN;
-	      return;
-	    }
+      char c = buf[parser->pos];
+
+      /* Quote: end of string */
+      if ( c == '\"' )
+        {
+          namelisttok_t *token = namelist_alloc_token(parser);
+          namelist_fill_token(token, NAMELIST_STRING, start+1, parser->pos);
+          return 0;
         }
 
-    LABEL_READLINE:
-
-      if ( ! readline(nmlfp, nml->line.lineac, MAX_LINE_LEN) ) break;
-
-      linelen = strlen(nml->line.lineac);
-
-      if ( linelen == 0 || nml->line.lineac[0] == '#' || nml->line.lineac[0] == '!' ) goto LABEL_READLINE; 
-
-      for ( i = 0; i < linelen+1; i++ )
-	{
-	  nml->line.linelc[i] = tolower(nml->line.lineac[i]);
-	  nml->line.lineuc[i] = toupper(nml->line.lineac[i]);
+      /* Backslash: Quoted symbol expected */
+      if ( c == '\\' && parser->pos + 1 < len )
+        {
+          parser->pos++;
+          switch (buf[parser->pos])
+            {
+              // Allowed escaped symbols
+            case '\"': case '\\' : case 'b' :
+            case 'f' : case 'r' : case 'n'  : case 't' :
+              break;
+              // Allows escaped symbol \uXXXX
+            case 'u':
+              parser->pos++;
+              for ( int i = 0; i < 4 && parser->pos < len && buf[parser->pos] != '\0'; i++ )
+                {
+                  // If it isn't a hex character we have an error
+                  if ( !((buf[parser->pos] >= 48 && buf[parser->pos] <= 57) || // 0-9
+                         (buf[parser->pos] >= 65 && buf[parser->pos] <= 70) || // A-F
+                         (buf[parser->pos] >= 97 && buf[parser->pos] <= 102)) ) // a-f
+                    {
+                      return NAMELIST_ERROR_INVAL;
+                    }
+                  parser->pos++;
+                }
+              parser->pos--;
+              break;
+              // Unexpected symbol
+            default:
+              return NAMELIST_ERROR_INVAL;
+            }
         }
-      nst = 0;
     }
+  
+  parser->pos = start;
+  return NAMELIST_ERROR_PART;
 
-  nml->line.nptype = NML_NIX;
+  return 0;
 }
 
 static
-void rdnlsgl(namelist_t *nml, void *var, int ntyp, int nlen, int *nocc)
+int namelist_check_keyname(const char *buf, namelisttok_t *t)
 {
-  if ( nml->line.nptype == NML_NUMBER )
+  switch (t->type)
     {
-      if ( *nocc >= nlen )
-	{
-	  nml->line.nptype = func_1;
-          return;
-	}
-      else if ( ntyp == NML_INT )
-	{
-	  ((int *)var)[*nocc] = atoi(&nml->line.lineac[nml->line.namitf]);
-          *nocc += 1;
-	}
-      else if ( ntyp == NML_FLT )
-	{
-	  ((double *)var)[*nocc] = atof(&nml->line.lineac[nml->line.namitf]);
-          *nocc += 1;
-	}
-      else if ( ntyp == NML_WORD )
-	{
-	  int i, len;
-
-	  if ( *nocc < nlen )
-	    {
-	      len = nml->line.namitl - nml->line.namitf + 1;
-	      ((char **)var)[*nocc] = (char*) Calloc((size_t)len+1, sizeof(char));
-	      for ( i = 0; i < len; i++ )
-		((char **)var)[*nocc][i] = nml->line.lineac[nml->line.namitf+i];
-	      *nocc += 1;
-	    }
-	}
-      else
-	{
-          nml->line.nptype = func_2;
-          return;
-        }
-    }
-  else if ( nml->line.nptype == NML_TEXT )
-    {
-      int i, j=0, newnocc;
-
-      newnocc = MIN(nlen, *nocc+nml->line.namitl-nml->line.namitf-1);
-
-      ((char *)var)[newnocc] = 0;
-      if      ( ntyp == NML_TEXT )
-	for (i=*nocc; i<newnocc; i++)
-	  ((char *)var)[i] = nml->line.lineac[nml->line.namitf+1+j++];
-      else if ( ntyp == NML_TEXTU )
-	for (i=*nocc; i<newnocc; i++)
-	  ((char *)var)[i] = nml->line.lineuc[nml->line.namitf+1+j++];
-      else if ( ntyp == NML_TEXTL )
-	for (i=*nocc; i<newnocc; i++)
-	  ((char *)var)[i] = nml->line.linelc[nml->line.namitf+1+j++];
-      else
-	{
-	  nml->line.nptype = func_3;
-	  return;
-	}
-
-      *nocc = newnocc;
+    case NAMELIST_STRING:
+      while ( isspace((int) buf[t->start]) && t->start < t->end ) t->start++;
+      while ( isspace((int) buf[t->end-1]) && t->start < t->end ) t->end--;
+      if ( (t->end - t->start) < 1 ) return NAMELIST_ERROR_EMKEY;
+      for ( int i = t->start; i < t->end; ++i )
+        if ( isspace((int)buf[i]) ) return NAMELIST_ERROR_INKEY;
+    case NAMELIST_WORD:
+      t->type = NAMELIST_KEY;
+      break;
+    default:
+      return NAMELIST_ERROR_INTYP;
+      break;
     }
-  else if ( nml->line.nptype == NML_WORD )
-    {
-      int i, len;
-
-      if ( *nocc < nlen )
-	{
-	  len = nml->line.namitl - nml->line.namitf + 1;
-	  ((char **)var)[*nocc] = (char*) Calloc((size_t)len+1, sizeof(char));
-	  for ( i = 0; i < len; i++ )
-	    ((char **)var)[*nocc][i] = nml->line.lineac[nml->line.namitf+i];
-	  *nocc += 1;
-	}
-    }
-  else
-    {
-      fprintf(stderr, "Namelist parameter type %d unknown!\n", nml->line.nptype);
-      return;
-    }
-
-  nml->line.nptype = ntyp;
+  
+  return 0;
 }
 
 
-static void nml_print_entry(nml_entry_t *entry, int ife)
+int namelist_parse(namelist_parser *parser, const char *buf, size_t len)
 {
-  int nout, j;
-
-  if ( entry->size == 0 ) return;
-
-  if ( entry->type == NML_NPR ) return;
-
-  nout = entry->occ;
+  int status = 0;
+  namelisttok_t *token;
 
-  if ( ife != PRINT_ALL )
-    if ( entry->occ > entry->dis ) nout = entry->dis;
-
-  if ( nout == 0 ) return;
-
-  printf(" %-24s", entry->name);
-
-  if      ( entry->type >= NML_TEXT )
-    printf("'%s'", ((char *)entry->ptr));
-  else if ( entry->type == NML_WORD )
-    for ( j = 0; j < nout; j++ )
-      printf(" %s", ((char **)entry->ptr)[j]);
-  else if ( entry->type == NML_INT )
-    for ( j = 0; j < nout; j++ )
-      printf(" %d", ((int *)entry->ptr)[j]);
-  else if ( entry->type == NML_FLT )
-    for ( j = 0; j < nout; j++ )
-      printf(" %g", ((double *)entry->ptr)[j]);
-
-  printf("\n");
-}
+  parser->lineno = 1;
 
+  for ( ; parser->pos < len && buf[parser->pos] != '\0'; parser->pos++ )
+    {
+      char c = buf[parser->pos];
+      switch (c)
+        {
+        case '&':
+          namelist_new_object(parser);
+          break;
+        case '/':
+          for ( int i = parser->toknext - 1; i >= 0; i-- )
+            {
+              token = &parser->tokens[i];
+              if ( token->start != -1 && token->end == -1 )
+                {
+                  if ( token->type != NAMELIST_OBJECT ) return NAMELIST_ERROR_INOBJ;
+                  token->end = parser->pos + 1;
+                  break;
+                }
+            }
+          break;
+        case '\t': case ' ':
+          break;
+        case '\r':
+          if ( parser->pos+1 < len && buf[parser->pos+1] == '\n' ) parser->pos++;
+        case '\n':
+          parser->lineno++;
+          break;
+        case ',':
+          break;
+        case '#': case '!': // Skip to end of line
+          for ( ; parser->pos < len && buf[parser->pos] != '\0'; parser->pos++ )
+            if ( buf[parser->pos] == '\r' || buf[parser->pos] == '\n' )
+              {
+                parser->pos--;
+                break;
+              }
+          break;
+        case ':': case '=':
+          status = namelist_check_keyname(buf, &parser->tokens[parser->toknext-1]);
+          break;
+        case '\"':
+          status = namelist_parse_string(parser, buf, len);
+          break;
+        default:
+          status = namelist_parse_word(parser, buf, len);
+          break;
+        }
 
-static void nml_print(namelist_t *nml, int ife)
-{
-  int i;
+      if ( status ) return status;
+    }
 
-  for ( i = 0; i < nml->size; i++ )
-    nml_print_entry(nml->entry[i], ife);
+  return status;
 }
 
-#define  MAX_WORD_LEN  256
 
-void namelistRead(FILE *nmlfp, namelist_t *nml)
+void namelist_dump(namelist_parser *parser, const char *buf)
 {
-  /*
-    cn  name
-    nt  type
-    nl  size length
-    nc  occ count
-    no  dis list
-  */
-  int clear = FALSE;
-  int j, jj, match = -1, wordmatch = -1;
-  size_t len;
-  char namecx[MAX_WORD_LEN], *pnamecx = NULL;
-  int nparam;
-
-  nparam = nml->size;
+  unsigned int ntok = parser->toknext;
+  printf("Number of tokens %d\n", ntok);
 
-  nml->line.namitl = MAX_LINE_LEN;
-
- L2000:
-
-  getnite(nmlfp, nml);
-
-  if ( nml->line.nptype == NML_NIX )
+  for ( unsigned int it = 0; it < ntok; ++it )
     {
-      goto L3000;
-    }
-  else if ( nml->line.nptype == NML_KEYWORD )
-    {
-      memset(namecx, '\0', MAX_WORD_LEN);
-      len = (size_t) (nml->line.namitl - nml->line.namitf + 1);
-
-      if ( nml->line.lineac[nml->line.namitf] == '/' || 
-	   nml->line.lineac[nml->line.namitf] == '$' || 
-	   nml->line.lineac[nml->line.namitf] == '&' )
-	{
-          if ( nml->line.namitl-nml->line.namitf > MAX_WORD_LEN ) goto L3000;
-
-          if ( nml->line.namitf < nml->line.namitl)
-	    pnamecx = &nml->line.linelc[nml->line.namitf+1];
-
-	  if ( pnamecx )
-	    if ( memcmp(pnamecx, "select", 6) == 0 || 
-		 memcmp(pnamecx, "params", 6) == 0 || 
-		 memcmp(pnamecx, nml->name, strlen(nml->name)) == 0 )
-	      goto L2000;
-
-	  goto L3000;
+      namelisttok_t *t = &parser->tokens[it];
+      int length = t->end - t->start;
+      const char *start = buf+t->start;
+      printf("Token %u", it+1);
+      if ( t->type == NAMELIST_OBJECT )
+        {
+          printf(" NAMELIST=");
+          if ( length > 80 ) length = 80;
+          printf("'%.*s'", length, start);
         }
-
-      if ( nml->line.namitl-nml->line.namitf >= MAX_WORD_LEN ) goto L3000;
-
-      pnamecx = &nml->line.linelc[nml->line.namitf];
-      memcpy(namecx, pnamecx, len);
-
-      if ( len == 5 )
-	if ( memcmp(pnamecx, "clear", len) == 0 )
-	  {
-	    clear = TRUE;
-	    goto L2000;
-	  }
-
-      match = -1;
-      for ( j = 0; j < nparam; j++ )
-	{
-	  if ( strlen(nml->entry[j]->name) == len )
-	    if ( memcmp(pnamecx, nml->entry[j]->name, len) == 0 )
-	      {
-		jj = j;
-		while ( nml->entry[jj]->type == NML_NPR ) jj--;
-		if ( match == -1 )
-		  match = jj;
-		else if ( match != jj )
-		  match = -2;
-		break;
-	      }
-	}
-
-      if ( match < 0 )
-	{
-	  if ( wordmatch >= 0 )
-	    {
-	      match = wordmatch;
-	      nml->line.nptype = NML_WORD;
-	      goto L777;
-	    }
-
-          printf(" * unidentified or ambiguous parameter <%s>\n", namecx);
-	  printf(" * valid parameters and values specified so far are\n");
-
-	  nml_print(nml, PRINT_ALL);
+      else if ( t->type == NAMELIST_KEY )
+        {
+          printf(" KEY=");
+          printf("'%.*s'", length, start);
         }
-      else
-	{
-          if ( clear ) nml->entry[match]->occ = 0;
-	  if ( nml->entry[match]->type == NML_WORD )
-	    wordmatch = match;
-	  else
-	    wordmatch = -1;
+      else if ( t->type == NAMELIST_WORD )
+        {
+          printf(" WORD=");
+          printf("'%.*s'", length, start);
         }
-      clear = FALSE;
-    }
-  else
-    {
-    L777:
-      j = match;
-      wordmatch = -1;
-
-      if ( j < 0 )
-	{
-	  fprintf(stderr, "Error in namelist!\n");
-	  goto L3000;
-	}
-
-      rdnlsgl(nml, nml->entry[j]->ptr, nml->entry[j]->type, (int)nml->entry[j]->size, &nml->entry[j]->occ);
-
-      if ( nml->line.nptype != nml->entry[j]->type )
-	{
-	  printf(" * value ignored for parameter <%s> %d\n", namecx, nml->line.nptype);
-	  printf(" * valid parameters and values specified so far are\n");
-
-	  nml_print(nml, PRINT_ALL);
+      else if ( t->type == NAMELIST_STRING )
+        {
+          printf(" STRING=");
+          printf("'%.*s'", length, start);
         }
+      printf("\n");
     }
+}
 
-  goto L2000;
 
- L3000:
+int namelist_verify(namelist_parser *parser, const char *buf)
+{
+  unsigned int ntok = parser->toknext;
 
-  if ( nml->dis == 0 ) return;
+  if ( ntok )
+    {
+      namelisttok_t *t = &parser->tokens[0];
+      if ( t->type != NAMELIST_OBJECT && t->type != NAMELIST_KEY )
+        return -1;
+    }
 
-  nml_print(nml, PRINT_MIN);
+  return 0;
 }
-
diff --git a/src/namelist.h b/src/namelist.h
index 60b5017..3980c8b 100644
--- a/src/namelist.h
+++ b/src/namelist.h
@@ -1,74 +1,49 @@
-/*
-  This file is part of CDO. CDO is a collection of Operators to
-  manipulate and analyse Climate model Data.
+#ifndef __NAMELIST_H_
+#define __NAMELIST_H_
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
-  See COPYING file for copying and redistribution conditions.
+enum namelisttype {
+  NAMELIST_UNDEFINED = 0,
+  NAMELIST_OBJECT    = 1,
+  NAMELIST_KEY       = 2,
+  NAMELIST_STRING    = 3,
+  NAMELIST_WORD      = 4
+};
 
-  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.
-*/
+enum namelisterr {
+  NAMELIST_ERROR_INVAL = -1,   // Invalid character inside NAMELIST string/word
+  NAMELIST_ERROR_PART  = -2,   // The string is not a full NAMELIST packet, more bytes expected 
+  NAMELIST_ERROR_INKEY = -3,   // Invalid character inside NAMELIST key
+  NAMELIST_ERROR_INTYP = -4,   // Invalid NAMELIST key type
+  NAMELIST_ERROR_INOBJ = -5,   // Invalid NAMELIST object
+  NAMELIST_ERROR_EMKEY = -6    // Empty key name
+};
 
-#ifndef _NAMELIST_H
-#define _NAMELIST_H
+// NAMELIST token description.
+typedef struct {
+  int type;            // type (object, key, string word)
+  int start;           // start position in NAMELIST buffer
+  int end;             // end position in NAMELIST buffer
+} namelisttok_t;
 
-#include <stdio.h>
 
+typedef struct {
+  namelisttok_t *tokens;
+  unsigned int num_tokens;
+  unsigned int toknext;
+  unsigned int pos;
+  unsigned int lineno;
+} namelist_parser;
 
-#define  NML_INT         1
-#define  NML_FLT      2
-#define  NML_WORD        3
-#define  NML_TEXT        4
 
-#define NML_DEF_INT(name, size, val)  int sel##name[size]; int nsel##name = 0; int name = 0
-#define NML_DEF_FLT(name, size, val)  double sel##name[size]; int nsel##name = 0; double name = 0
-#define NML_ADD_INT(nml, name) namelistAdd(nml, #name, NML_INT, 0, sel##name, sizeof(sel##name)/sizeof(int))
-#define NML_ADD_FLT(nml, name) namelistAdd(nml, #name, NML_FLT, 0, sel##name, sizeof(sel##name)/sizeof(double))
-#define NML_NUM(nml, name)   nsel##name = namelistNum(nml, #name)
-#define NML_PAR(name)        nsel##name, sel##name, name
+namelist_parser *namelist_new(void);
 
-#define MAX_NML_ENTRY  256
+void namelist_destroy(namelist_parser *parser);
 
-#define MAX_LINE_LEN  4096
+int namelist_parse(namelist_parser *parser, const char *buf, size_t len);
 
-typedef struct
-{
-  int nptype, namitf, namitl;
-  char lineac[MAX_LINE_LEN], lineuc[MAX_LINE_LEN], linelc[MAX_LINE_LEN];
-} nml_line_t;
+void namelist_dump(namelist_parser *parser, const char *buf);
 
-typedef struct
-{
-  char  *name;
-  void  *ptr;
-  int    type;
-  int    occ;
-  int    dis;
-  size_t size;
-} nml_entry_t;
+int namelist_verify(namelist_parser *parser, const char *buf);
 
-typedef struct
-{
-  int          size;
-  int          dis;
-  char        *name;
-  nml_line_t   line;
-  nml_entry_t *entry[MAX_NML_ENTRY];
-} namelist_t;
-
-
-namelist_t *namelistNew(const char *name);
-void namelistDelete(namelist_t *nml);
-void namelistReset(namelist_t *nml);
-int  namelistAdd(namelist_t *nml, const char *name, int type, int dis, void *ptr, size_t size);
-void namelistPrint(namelist_t *nml);
-void namelistRead(FILE *nmlfp, namelist_t *nml);
-int  namelistNum(namelist_t *nml, const char *name);
-
-#endif  /* _NAMELIST_H */
+#endif // __NAMELIST_H_
diff --git a/src/namelist_parser.c b/src/namelist_parser.c
new file mode 100644
index 0000000..325a8c5
--- /dev/null
+++ b/src/namelist_parser.c
@@ -0,0 +1,141 @@
+#include "cdo_int.h"
+#include "namelist.h"
+
+
+static
+void kvlist_append_namelist(list_t *kvlist, const char *key, const char *buffer, namelisttok_t *t, int nvalues)
+{
+  keyValues_t *keyval = (keyValues_t *) malloc(sizeof(keyValues_t));
+  keyval->key = strdup(key);
+  keyval->nvalues = nvalues;
+  keyval->values = NULL;
+
+  if ( nvalues > 0 ) keyval->values = (char **) malloc(nvalues*sizeof(char*));
+  for ( int i = 0; i < nvalues; ++i )
+    {
+      size_t len = t[i].end - t[i].start;
+      char *value = (char*) malloc((len+1)*sizeof(char));
+      //printf(" value >%.*s<\n", len, buffer+t[i].start);
+      snprintf(value, len+1, "%.*s", (int)len, buffer+t[i].start);
+      value[len] = 0;
+      keyval->values[i] = value;
+    }
+  list_append(kvlist, &keyval);
+}
+
+static
+int get_number_of_values(int ntok, namelisttok_t *tokens)
+{
+  int it;
+  
+  for ( it = 0; it < ntok; ++it )
+    {
+      namelisttok_t *t = &tokens[it];
+      if ( t->type != NAMELIST_WORD && t->type != NAMELIST_STRING ) break;
+    }
+  
+  return it;
+}
+
+static
+int namelist_to_pml(list_t *pmlist, namelist_parser *parser, char *buf)
+{
+  char name[4096];
+  list_t *kvlist = NULL;
+  namelisttok_t *t;
+  namelisttok_t *tokens = parser->tokens;
+  unsigned int ntok = parser->toknext;
+  // printf("Number of tokens %d\n", ntok);
+
+  for ( unsigned int it = 0; it < ntok; ++it )
+    {
+      t = &tokens[it];
+      // printf("Token %u", it+1);
+      if ( t->type == NAMELIST_OBJECT )
+        {
+          name[0] = 0;
+          if ( it+1 < ntok && tokens[it+1].type == NAMELIST_WORD )
+            {
+              it++;
+              t = &tokens[it];
+              snprintf(name, sizeof(name), "%.*s", t->end - t->start, buf+t->start);
+              name[sizeof(name)-1] = 0;
+            }
+          kvlist = kvlist_new(name);
+          list_append(pmlist, &kvlist);
+        }
+      else if ( t->type == NAMELIST_KEY )
+        {
+          if ( kvlist == NULL )
+            {
+              kvlist = kvlist_new(NULL);
+              list_append(pmlist, &kvlist);
+            }
+          // printf(" key >%.*s<\n", t->end - t->start, buf+t->start);
+          snprintf(name, sizeof(name), "%.*s", t->end - t->start, buf+t->start);
+          name[sizeof(name)-1] = 0;
+          int nvalues = get_number_of_values(ntok-it-1, &tokens[it+1]);
+          kvlist_append_namelist(kvlist, name, buf, &tokens[it+1], nvalues);
+          it += nvalues;
+        }
+      else
+        {
+          // printf(" token >%.*s<\n", t->end - t->start, buf+t->start);
+          break;
+        }
+    }
+
+  return 0;
+}
+
+
+list_t *namelistbuf_to_pmlist(listbuf_t *listbuf)
+{
+  const char *name = listbuf->name;
+  namelist_parser *p = namelist_new();
+
+  int status = namelist_parse(p, listbuf->buffer, listbuf->size);
+  if ( status )
+    {
+      switch (status)
+        {
+        case NAMELIST_ERROR_INVAL: fprintf(stderr, "Namelist error: Invalid character in %s (line=%d character='%c')!\n", name, p->lineno, listbuf->buffer[p->pos]); break;
+        case NAMELIST_ERROR_PART:  fprintf(stderr, "Namelist error: End of string not found in %s (line=%d)!\n", name, p->lineno); break;
+        case NAMELIST_ERROR_INKEY: fprintf(stderr, "Namelist error: Invalid key word in %s (line=%d)!\n", name, p->lineno); break;
+        case NAMELIST_ERROR_INTYP: fprintf(stderr, "Namelist error: Invalid key word type in %s (line=%d)!\n", name, p->lineno); break;
+        case NAMELIST_ERROR_INOBJ: fprintf(stderr, "Namelist error: Invalid object in %s (line=%d)!\n", name, p->lineno); break;
+        case NAMELIST_ERROR_EMKEY: fprintf(stderr, "Namelist error: Emtry key name in %s (line=%d)!\n", name, p->lineno); break;
+        default:                   fprintf(stderr, "Namelist error in %s (line=%d)!\n", name, p->lineno); break;
+        }
+      cdoAbort("Namelist error!");
+    }
+
+  // namelist_dump(p, listbuf->buffer);
+  status = namelist_verify(p, listbuf->buffer);
+  if ( status )
+    {
+      fprintf(stderr, "Namelist error: Invalid contents in %s!\n", name);
+      cdoAbort("Namelist error!");      
+    }
+
+  list_t *pmlist = list_new(sizeof(list_t *), free_kvlist, listbuf->name);
+
+  namelist_to_pml(pmlist, p, listbuf->buffer);
+  namelist_destroy(p);
+  
+  return pmlist;
+}
+
+
+list_t *namelist_to_pmlist(FILE *fp, const char *name)
+{
+  listbuf_t *listbuf = listbuf_new();
+  if ( listbuf_read(listbuf, fp, name) ) cdoAbort("Read error on namelist %s!", name);
+  
+  list_t *pmlist = namelistbuf_to_pmlist(listbuf);
+  if ( pmlist == NULL ) cdoAbort("Namelist not found!");
+
+  listbuf_destroy(listbuf);
+
+  return pmlist;
+}
diff --git a/src/operator_help.h b/src/operator_help.h
index 747de79..50ad2fe 100644
--- a/src/operator_help.h
+++ b/src/operator_help.h
@@ -5,7 +5,7 @@ static const char *InfoHelp[] = {
     "    info, infon, map - Information and simple statistics",
     "",
     "SYNOPSIS",
-    "    <operator>  ifiles",
+    "    <operator>  infiles",
     "",
     "DESCRIPTION",
     "    This module writes information about the structure and contents ",
@@ -37,11 +37,11 @@ static const char *SinfoHelp[] = {
     "    sinfo, sinfon - Short information",
     "",
     "SYNOPSIS",
-    "    <operator>  ifiles",
+    "    <operator>  infiles",
     "",
     "DESCRIPTION",
-    "    This module writes information about the structure of ifiles to standard output.",
-    "    ifiles is an arbitrary number of input files. All input files need to have ",
+    "    This module writes information about the structure of infiles to standard output.",
+    "    infiles is an arbitrary number of input files. All input files need to have ",
     "    the same structure with the same variables on different timesteps.",
     "    The information displayed depends on the chosen operator.",
     "",
@@ -69,7 +69,7 @@ static const char *DiffHelp[] = {
     "    diff, diffn - Compare two datasets field by field",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile1 ifile2",
+    "    <operator>  infile1 infile2",
     "",
     "DESCRIPTION",
     "    Compares the contents of two datasets field by field. The input datasets need to have the",
@@ -99,7 +99,7 @@ static const char *NinfoHelp[] = {
     "    Print the number of parameters, levels or times",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile",
+    "    <operator>  infile",
     "",
     "DESCRIPTION",
     "    This module prints the number of variables, levels or times of the ",
@@ -131,7 +131,7 @@ static const char *ShowinfoHelp[] = {
     "    showmon, showdate, showtime, showtimestamp - Show variables, levels or times",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile",
+    "    <operator>  infile",
     "",
     "DESCRIPTION",
     "    This module prints the format, variables, levels or times of the input dataset.",
@@ -167,7 +167,7 @@ static const char *FiledesHelp[] = {
     "    partab, codetab, griddes, zaxisdes, vct - Dataset description",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile",
+    "    <operator>  infile",
     "",
     "DESCRIPTION",
     "    This module provides operators to print meta information about a dataset.",
@@ -194,19 +194,19 @@ static const char *CopyHelp[] = {
     "    copy, cat - Copy datasets",
     "",
     "SYNOPSIS",
-    "    <operator>  ifiles ofile",
+    "    <operator>  infiles outfile",
     "",
     "DESCRIPTION",
     "    This module contains operators to copy or concatenate datasets.",
-    "    ifiles is an arbitrary number of input files. All input files need to have ",
+    "    infiles is an arbitrary number of input files. All input files need to have ",
     "    the same structure with the same variables on different timesteps.",
     "",
     "OPERATORS",
     "    copy  Copy datasets",
-    "          Copies all input datasets to ofile. ",
+    "          Copies all input datasets to outfile. ",
     "    cat   Concatenate datasets",
     "          Concatenates all input datasets and appends the result to the end ",
-    "          of ofile. If ofile does not exist it will be created.",
+    "          of outfile. If outfile does not exist it will be created.",
     NULL
 };
 
@@ -215,11 +215,11 @@ static const char *ReplaceHelp[] = {
     "    replace - Replace variables",
     "",
     "SYNOPSIS",
-    "    replace  ifile1 ifile2 ofile",
+    "    replace  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    The replace operator replaces variables in ifile1 by variables from ifile2 and write",
-    "    the result to ofile. Both input datasets need to have the same number of timesteps.",
+    "    The replace operator replaces variables in infile1 by variables from infile2 and write",
+    "    the result to outfile. Both input datasets need to have the same number of timesteps.",
     NULL
 };
 
@@ -228,10 +228,10 @@ static const char *DuplicateHelp[] = {
     "    duplicate - Duplicates a dataset",
     "",
     "SYNOPSIS",
-    "    duplicate[,ndup]  ifile ofile",
+    "    duplicate[,ndup]  infile outfile",
     "",
     "DESCRIPTION",
-    "    This operator duplicates the contents of ifile and writes the result to ofile.",
+    "    This operator duplicates the contents of infile and writes the result to outfile.",
     "    The optional parameter sets the number of duplicates, the default is 2.",
     "",
     "PARAMETER",
@@ -244,12 +244,12 @@ static const char *MergegridHelp[] = {
     "    mergegrid - Merge grid",
     "",
     "SYNOPSIS",
-    "    mergegrid  ifile1 ifile2 ofile",
+    "    mergegrid  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Merges grid points of all variables from ifile2 to ifile1 and write the result to ofile.",
-    "    Only the non missing values of ifile2 will be used. The horizontal grid of ifile2 should ",
-    "    be smaller or equal to the grid of ifile1 and the resolution must be the same.",
+    "    Merges grid points of all variables from infile2 to infile1 and write the result to outfile.",
+    "    Only the non missing values of infile2 will be used. The horizontal grid of infile2 should ",
+    "    be smaller or equal to the grid of infile1 and the resolution must be the same.",
     "    Only rectilinear grids are supported. Both input files need to have the same variables ",
     "    and the same number of timesteps.",
     NULL
@@ -260,15 +260,15 @@ static const char *MergeHelp[] = {
     "    merge, mergetime - Merge datasets",
     "",
     "SYNOPSIS",
-    "    <operator>  ifiles ofile",
+    "    <operator>  infiles outfile",
     "",
     "DESCRIPTION",
-    "    This module reads datasets from several input files, merges them and writes the resulting dataset to ofile.",
+    "    This module reads datasets from several input files, merges them and writes the resulting dataset to outfile.",
     "",
     "OPERATORS",
     "    merge      Merge datasets with different fields",
     "               Merges time series of different fields from several input datasets. The number ",
-    "               of fields per timestep written to ofile is the sum of the field numbers ",
+    "               of fields per timestep written to outfile is the sum of the field numbers ",
     "               per timestep in all input datasets. The time series on all input datasets are ",
     "               required to have different fields and the same number of timesteps.",
     "               The fields in each different input file either have to be different variables",
@@ -277,7 +277,7 @@ static const char *MergeHelp[] = {
     "    mergetime  Merge datasets sorted by date and time",
     "               Merges all timesteps of all input files sorted by date and time.",
     "               All input files need to have the same structure with the same variables on ",
-    "               different timesteps. After this operation every input timestep is in ofile ",
+    "               different timesteps. After this operation every input timestep is in outfile ",
     "               and all timesteps are sorted by date and time.",
     "",
     "ENVIRONMENT",
@@ -296,10 +296,10 @@ static const char *SplitHelp[] = {
     "    splittabnum - Split a dataset",
     "",
     "SYNOPSIS",
-    "    <operator>[,params]  ifile obase",
+    "    <operator>[,params]  infile obase",
     "",
     "DESCRIPTION",
-    "    This module splits ifile into pieces. The output files will be named <obase><xxx><suffix>",
+    "    This module splits infile into pieces. The output files will be named <obase><xxx><suffix>",
     "    where suffix is the filename extension derived from the file format. xxx and the contents ",
     "    of the output files depends on the chosen operator. ",
     "    params is a comma separated list of processing parameters.",
@@ -349,11 +349,11 @@ static const char *SplittimeHelp[] = {
     "    Split timesteps of a dataset",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile obase",
-    "    splitmon[,format]  ifile obase",
+    "    <operator>  infile obase",
+    "    splitmon[,format]  infile obase",
     "",
     "DESCRIPTION",
-    "    This module splits ifile into  timesteps pieces. The output files will be named",
+    "    This module splits infile into  timesteps pieces. The output files will be named",
     "    <obase><xxx><suffix> where suffix is the filename extension derived from the file format. ",
     "    xxx and the contents of the output files depends on the chosen operator. ",
     "",
@@ -397,10 +397,10 @@ static const char *SplitselHelp[] = {
     "    splitsel - Split selected timesteps",
     "",
     "SYNOPSIS",
-    "    splitsel,nsets[,noffset[,nskip]]  ifile obase",
+    "    splitsel,nsets[,noffset[,nskip]]  infile obase",
     "",
     "DESCRIPTION",
-    "    This operator splits ifile into pieces, one for each adjacent",
+    "    This operator splits infile into pieces, one for each adjacent",
     "    sequence t_1, ...., t_n of timesteps of the same selected time range.",
     "    The output files will be named <obase><nnnnnn><suffix> where nnnnnn is the ",
     "    sequence number and suffix is the filename extension derived from the file format.",
@@ -423,7 +423,7 @@ static const char *DistgridHelp[] = {
     "    distgrid - Distribute horizontal grid",
     "",
     "SYNOPSIS",
-    "    distgrid,nx[,ny]  ifile obase",
+    "    distgrid,nx[,ny]  infile obase",
     "",
     "DESCRIPTION",
     "    This operator distributes a dataset into smaller pieces. Each output file contains a different region of the horizontal ",
@@ -448,7 +448,7 @@ static const char *CollgridHelp[] = {
     "    collgrid - Collect horizontal grid",
     "",
     "SYNOPSIS",
-    "    collgrid[,nx[,names]]  ifiles ofile",
+    "    collgrid[,nx[,names]]  infiles outfile",
     "",
     "DESCRIPTION",
     "    This operator collects the data of the input files to one output file. ",
@@ -471,11 +471,11 @@ static const char *SelectHelp[] = {
     "    select, delete - Select fields",
     "",
     "SYNOPSIS",
-    "    <operator>,params  ifiles ofile",
+    "    <operator>,params  infiles outfile",
     "",
     "DESCRIPTION",
-    "    This module selects some fields from ifiles and writes them to ofile.",
-    "    ifiles is an arbitrary number of input files. All input files need to have ",
+    "    This module selects some fields from infiles and writes them to outfile.",
+    "    infiles is an arbitrary number of input files. All input files need to have ",
     "    the same structure with the same variables on different timesteps.",
     "    The fields selected depends on the chosen parameters. Parameter is a comma",
     "    separated list of \"key=value\" pairs. Wildcards can be used for string parameter.",
@@ -518,22 +518,22 @@ static const char *SelvarHelp[] = {
     "    sellevidx, selgrid, selzaxis, selzaxisname, selltype, seltabnum - Select fields",
     "",
     "SYNOPSIS",
-    "    <operator>,params  ifile ofile",
-    "    selcode,codes  ifile ofile",
-    "    delcode,codes  ifile ofile",
-    "    selname,names  ifile ofile",
-    "    delname,names  ifile ofile",
-    "    selstdname,stdnames  ifile ofile",
-    "    sellevel,levels  ifile ofile",
-    "    sellevidx,levidx  ifile ofile",
-    "    selgrid,grids  ifile ofile",
-    "    selzaxis,zaxes  ifile ofile",
-    "    selzaxisname,zaxisnames  ifile ofile",
-    "    selltype,ltypes  ifile ofile",
-    "    seltabnum,tabnums  ifile ofile",
+    "    <operator>,params  infile outfile",
+    "    selcode,codes  infile outfile",
+    "    delcode,codes  infile outfile",
+    "    selname,names  infile outfile",
+    "    delname,names  infile outfile",
+    "    selstdname,stdnames  infile outfile",
+    "    sellevel,levels  infile outfile",
+    "    sellevidx,levidx  infile outfile",
+    "    selgrid,grids  infile outfile",
+    "    selzaxis,zaxes  infile outfile",
+    "    selzaxisname,zaxisnames  infile outfile",
+    "    selltype,ltypes  infile outfile",
+    "    seltabnum,tabnums  infile outfile",
     "",
     "DESCRIPTION",
-    "    This module selects some fields from ifile and writes them to ofile.",
+    "    This module selects some fields from infile and writes them to outfile.",
     "    The fields selected depends on the chosen operator and the parameters.",
     "",
     "OPERATORS",
@@ -587,18 +587,18 @@ static const char *SeltimeHelp[] = {
     "    selsmon - Select timesteps",
     "",
     "SYNOPSIS",
-    "    seltimestep,timesteps  ifile ofile",
-    "    seltime,times  ifile ofile",
-    "    selhour,hours  ifile ofile",
-    "    selday,days  ifile ofile",
-    "    selmonth,months  ifile ofile",
-    "    selyear,years  ifile ofile",
-    "    selseason,seasons  ifile ofile",
-    "    seldate,date1[,date2]  ifile ofile",
-    "    selsmon,month[,nts1[,nts2]]  ifile ofile",
+    "    seltimestep,timesteps  infile outfile",
+    "    seltime,times  infile outfile",
+    "    selhour,hours  infile outfile",
+    "    selday,days  infile outfile",
+    "    selmonth,months  infile outfile",
+    "    selyear,years  infile outfile",
+    "    selseason,seasons  infile outfile",
+    "    seldate,date1[,date2]  infile outfile",
+    "    selsmon,month[,nts1[,nts2]]  infile outfile",
     "",
     "DESCRIPTION",
-    "    This module selects user specified timesteps from ifile and writes them to ofile.",
+    "    This module selects user specified timesteps from infile and writes them to outfile.",
     "    The timesteps selected depends on the chosen operator and the parameters.",
     "",
     "OPERATORS",
@@ -641,8 +641,8 @@ static const char *SelboxHelp[] = {
     "    sellonlatbox, selindexbox - Select a box of a field",
     "",
     "SYNOPSIS",
-    "    sellonlatbox,lon1,lon2,lat1,lat2  ifile ofile",
-    "    selindexbox,idx1,idx2,idy1,idy2  ifile ofile",
+    "    sellonlatbox,lon1,lon2,lat1,lat2  infile outfile",
+    "    selindexbox,idx1,idx2,idy1,idy2  infile outfile",
     "",
     "DESCRIPTION",
     "    Selects a box of the rectangularly understood field. All input fields need to have the same horizontal grid.",
@@ -673,15 +673,15 @@ static const char *CondHelp[] = {
     "    ifthen, ifnotthen - Conditional select one field",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile1 ifile2 ofile",
+    "    <operator>  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    This module selects field elements from ifile2 with respect to ifile1 and writes them ",
-    "    to ofile. The fields in ifile1 are handled as a mask. A value ",
+    "    This module selects field elements from infile2 with respect to infile1 and writes them ",
+    "    to outfile. The fields in infile1 are handled as a mask. A value ",
     "    not equal to zero is treated as \"true\", zero is treated as \"false\".",
-    "    The number of fields in ifile1 has either to be the same as in ifile2 or the",
-    "    same as in one timestep of ifile2 or only one.",
-    "    The fields in ofile inherit the meta data from ifile2.",
+    "    The number of fields in infile1 has either to be the same as in infile2 or the",
+    "    same as in one timestep of infile2 or only one.",
+    "    The fields in outfile inherit the meta data from infile2.",
     "",
     "OPERATORS",
     "    ifthen     If then",
@@ -700,16 +700,16 @@ static const char *Cond2Help[] = {
     "    ifthenelse - Conditional select  two fields",
     "",
     "SYNOPSIS",
-    "    ifthenelse  ifile1 ifile2 ifile3 ofile",
+    "    ifthenelse  infile1 infile2 infile3 outfile",
     "",
     "DESCRIPTION",
-    "    This operator selects field elements from ifile2 or ifile3 with respect to",
-    "    ifile1 and writes them to ofile. The fields in ifile1 are handled as a mask.",
+    "    This operator selects field elements from infile2 or infile3 with respect to",
+    "    infile1 and writes them to outfile. The fields in infile1 are handled as a mask.",
     "    A value not equal to zero is treated as \"true\", zero is treated as \"false\".",
-    "    The number of fields in ifile1 has either to be the same as in ifile2 or the ",
-    "    same as in one timestep of ifile2 or only one.",
-    "    ifile2 and ifile3 need to have the same number of fields.",
-    "    The fields in ofile inherit the meta data from ifile2.",
+    "    The number of fields in infile1 has either to be the same as in infile2 or the ",
+    "    same as in one timestep of infile2 or only one.",
+    "    infile2 and infile3 need to have the same number of fields.",
+    "    The fields in outfile inherit the meta data from infile2.",
     "    ",
     "              / i_2(t,x) if i_1([t,]x) NE 0  AND  i_1([t,]x) NE miss",
     "    o(t,x) = <  i_3(t,x) if i_1([t,]x) EQ 0  AND  i_1([t,]x) NE miss",
@@ -722,11 +722,11 @@ static const char *CondcHelp[] = {
     "    ifthenc, ifnotthenc - Conditional select a constant",
     "",
     "SYNOPSIS",
-    "    <operator>,c  ifile ofile",
+    "    <operator>,c  infile outfile",
     "",
     "DESCRIPTION",
     "    This module creates fields with a constant value or missing value.",
-    "    The fields in ifile are handled as a mask. A value not equal ",
+    "    The fields in infile are handled as a mask. A value not equal ",
     "    to zero is treated as \"true\", zero is treated as \"false\".",
     "",
     "OPERATORS",
@@ -749,7 +749,7 @@ static const char *MapReduceHelp[] = {
     "    reducegrid - Reduce fields to user-defined mask",
     "",
     "SYNOPSIS",
-    "    reducegrid,mask[,limitCoordsOutput]  ifile ofile",
+    "    reducegrid,mask[,limitCoordsOutput]  infile outfile",
     "",
     "DESCRIPTION",
     "    This module holds an operator for data reduction based on a user defined mask.",
@@ -768,14 +768,14 @@ static const char *CompHelp[] = {
     "    eq, ne, le, lt, ge, gt - Comparison of two fields",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile1 ifile2 ofile",
+    "    <operator>  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
     "    This module compares two datasets field by field. The resulting",
     "    field is a mask containing 1 if the comparison is true and 0 if not. ",
-    "    The number of fields in ifile1 should be the same as in ifile2.",
+    "    The number of fields in infile1 should be the same as in infile2.",
     "    One of the input files can contain only one timestep or one field.",
-    "    The fields in ofile inherit the meta data from ifile1 or ifile2.",
+    "    The fields in outfile inherit the meta data from infile1 or infile2.",
     "    The type of comparison depends on the chosen operator.",
     "",
     "OPERATORS",
@@ -811,7 +811,7 @@ static const char *CompcHelp[] = {
     "    eqc, nec, lec, ltc, gec, gtc - Comparison of a field with a constant",
     "",
     "SYNOPSIS",
-    "    <operator>,c  ifile ofile",
+    "    <operator>,c  infile outfile",
     "",
     "DESCRIPTION",
     "    This module compares all fields of a dataset with a constant. The resulting",
@@ -849,15 +849,50 @@ static const char *CompcHelp[] = {
     NULL
 };
 
+static const char *SetattributeHelp[] = {
+    "NAME",
+    "    setattribute - Set attributes",
+    "",
+    "SYNOPSIS",
+    "    setattribute,attributes  infile outfile",
+    "",
+    "DESCRIPTION",
+    "    This operator sets attributes of a dataset. Each attribute has the following structure:",
+    "    ",
+    "      [var_nm@]att_nm=att_val",
+    "    ",
+    "       var_nm  Variable name (optional). Example: pressure",
+    "       att_nm  Attribute name. Example: units",
+    "       att_val Comma separated list of attribute values. Example: pascal",
+    "    ",
+    "    The value of var_nm is the name of the variable containing the attribute (named att_nm) that",
+    "    you want to set. Use wildcards to set the attribute att_nm to more than one variable.",
+    "    A value of var_nm of '*' will set the attribute att_nm to all data variables.",
+    "    If var_nm is missing then att_nm refers to a global attribute.",
+    "    ",
+    "    The value of att_nm is the name of the attribute you want to set.",
+    "    ",
+    "    The value of att_val is the contents of the attribute att_nm. att_val may be a single value",
+    "    or one-dimensional array of elements. The type of the attribute value will be detected",
+    "    automaticly from the contents of the value.",
+    "    ",
+    "    A special meaning has the attribute name FILE. If this is the 1st attribute then all attributes",
+    "    are read from a file specified in the value of att_val.",
+    "",
+    "PARAMETER",
+    "    attributes  STRING  Comma separated list of attributes. ",
+    NULL
+};
+
 static const char *SetpartabHelp[] = {
     "NAME",
     "    setpartabp, setpartabn - Set parameter table",
     "",
     "SYNOPSIS",
-    "    <operator>,table[,convert]  ifile ofile",
+    "    <operator>,table[,convert]  infile outfile",
     "",
     "DESCRIPTION",
-    "    This module transforms data and metadata of ifile via a parameter table and writes the result to ofile.",
+    "    This module transforms data and metadata of infile via a parameter table and writes the result to outfile.",
     "    A parameter table is an ASCII formatted file with a set of parameter entries for each variable. Each new set have to",
     "    start with \"\\&parameter\" and to end with \"/\".",
     "    ",
@@ -884,6 +919,7 @@ static const char *SetpartabHelp[] = {
     "     delete          & INTEGER     & Set to 1 to delete variable",
     "     convert         & INTEGER     & Set to 1 to convert the unit if necessary",
     "    ",
+    "    Unsupported parameter table entries are stored as variable attributes.",
     "    The search key for the variable depends on the operator. Use setpartabn to search variables by the name.",
     "    This is typically used for NetCDF datasets. The operator setpartabp searches variables by the parameter ID.",
     "",
@@ -905,13 +941,13 @@ static const char *SetHelp[] = {
     "    Set field info",
     "",
     "SYNOPSIS",
-    "    setcodetab,table  ifile ofile",
-    "    setcode,code  ifile ofile",
-    "    setparam,param  ifile ofile",
-    "    setname,name  ifile ofile",
-    "    setunit,unit  ifile ofile",
-    "    setlevel,level  ifile ofile",
-    "    setltype,ltype  ifile ofile",
+    "    setcodetab,table  infile outfile",
+    "    setcode,code  infile outfile",
+    "    setparam,param  infile outfile",
+    "    setname,name  infile outfile",
+    "    setunit,unit  infile outfile",
+    "    setlevel,level  infile outfile",
+    "    setltype,ltype  infile outfile",
     "",
     "DESCRIPTION",
     "    This module sets some field information. Depending on the chosen operator the ",
@@ -949,17 +985,17 @@ static const char *SettimeHelp[] = {
     "    setreftime, setcalendar, shifttime - Set time",
     "",
     "SYNOPSIS",
-    "    setdate,date  ifile ofile",
-    "    settime,time  ifile ofile",
-    "    setday,day  ifile ofile",
-    "    setmon,month  ifile ofile",
-    "    setyear,year  ifile ofile",
-    "    settunits,units  ifile ofile",
-    "    settaxis,date,time[,inc]  ifile ofile",
-    "    settbounds,frequency  ifile ofile",
-    "    setreftime,date,time[,units]  ifile ofile",
-    "    setcalendar,calendar  ifile ofile",
-    "    shifttime,sval  ifile ofile",
+    "    setdate,date  infile outfile",
+    "    settime,time  infile outfile",
+    "    setday,day  infile outfile",
+    "    setmon,month  infile outfile",
+    "    setyear,year  infile outfile",
+    "    settunits,units  infile outfile",
+    "    settaxis,date,time[,inc]  infile outfile",
+    "    settbounds,frequency  infile outfile",
+    "    setreftime,date,time[,units]  infile outfile",
+    "    setcalendar,calendar  infile outfile",
+    "    shifttime,sval  infile outfile",
     "",
     "DESCRIPTION",
     "    This module sets the time axis or part of the time axis. Which part of the",
@@ -1009,17 +1045,17 @@ static const char *ChangeHelp[] = {
     "    Change field header",
     "",
     "SYNOPSIS",
-    "    chcode,oldcode,newcode[,...]  ifile ofile",
-    "    chparam,oldparam,newparam,...  ifile ofile",
-    "    chname,oldname,newname,...  ifile ofile",
-    "    chunit,oldunit,newunit,...  ifile ofile",
-    "    chlevel,oldlev,newlev,...  ifile ofile",
-    "    chlevelc,code,oldlev,newlev  ifile ofile",
-    "    chlevelv,name,oldlev,newlev  ifile ofile",
+    "    chcode,oldcode,newcode[,...]  infile outfile",
+    "    chparam,oldparam,newparam,...  infile outfile",
+    "    chname,oldname,newname,...  infile outfile",
+    "    chunit,oldunit,newunit,...  infile outfile",
+    "    chlevel,oldlev,newlev,...  infile outfile",
+    "    chlevelc,code,oldlev,newlev  infile outfile",
+    "    chlevelv,name,oldlev,newlev  infile outfile",
     "",
     "DESCRIPTION",
-    "    This module reads fields from ifile, changes some header values",
-    "    and writes the results to ofile. The kind of changes depends on ",
+    "    This module reads fields from infile, changes some header values",
+    "    and writes the results to outfile. The kind of changes depends on ",
     "    the chosen operator.",
     "",
     "OPERATORS",
@@ -1055,9 +1091,9 @@ static const char *SetgridHelp[] = {
     "    setgrid, setgridtype, setgridarea - Set grid information",
     "",
     "SYNOPSIS",
-    "    setgrid,grid  ifile ofile",
-    "    setgridtype,gridtype  ifile ofile",
-    "    setgridarea,gridarea  ifile ofile",
+    "    setgrid,grid  infile outfile",
+    "    setgridtype,gridtype  infile outfile",
+    "    setgridarea,gridarea  infile outfile",
     "",
     "DESCRIPTION",
     "    This module modifies the metadata of the horizontal grid. Depending on the ",
@@ -1073,7 +1109,8 @@ static const char *SetgridHelp[] = {
     "                 curvilinear "    "    Converts a regular grid to a curvilinear grid",
     "                 unstructured"    "    Converts a regular or curvilinear grid to an unstructured grid",
     "                 dereference "    "    Dereference a reference to a grid",
-    "                 regular     "    "    Converts a reduced Gaussian grid to a regular Gaussian grid",
+    "                 regular     "    "    Linear interpolation of a reduced Gaussian grid to a regular Gaussian grid",
+    "                 regularnn   "    "    Nearest neighbor interpolation of a reduced Gaussian grid to a regular Gaussian grid",
     "                 lonlat      "    "    Converts a regular lonlat grid stored as a curvilinear grid back to a lonlat grid",
     "    setgridarea  Set grid cell area",
     "                 Sets the grid cell area. The parameter gridarea is the path to a data file,",
@@ -1093,8 +1130,8 @@ static const char *SetzaxisHelp[] = {
     "    setzaxis, genlevelbounds - Set z-axis information",
     "",
     "SYNOPSIS",
-    "    setzaxis,zaxis  ifile ofile",
-    "    genlevelbounds[,zbot[,ztop]]  ifile ofile",
+    "    setzaxis,zaxis  infile outfile",
+    "    genlevelbounds[,zbot[,ztop]]  infile outfile",
     "",
     "DESCRIPTION",
     "    This module modifies the metadata of the vertical grid.",
@@ -1112,55 +1149,51 @@ static const char *SetzaxisHelp[] = {
     NULL
 };
 
-static const char *SetgattHelp[] = {
+static const char *InvertHelp[] = {
     "NAME",
-    "    setgatt, setgatts - Set global attribute",
+    "    invertlat - Invert latitudes",
     "",
     "SYNOPSIS",
-    "    setgatt,attname,attstring  ifile ofile",
-    "    setgatts,attfile  ifile ofile",
+    "    invertlat  infile outfile",
     "",
     "DESCRIPTION",
-    "    This module sets global text attributes of a dataset. Depending on the chosen ",
-    "    operator the attributes are read from a file or can be specified by a parameter.",
-    "",
-    "OPERATORS",
-    "    setgatt   Set global attribute",
-    "              Sets one user defined global text attribute.",
-    "    setgatts  Set global attributes",
-    "              Sets user defined global text attributes. The name and text",
-    "              of the global attributes are read from a file.",
-    "",
-    "PARAMETER",
-    "    attname,attstring  STRING  Name and text of the global attribute (without spaces!)",
-    "    attfile            STRING  File name which contains global text attributes",
-    "",
-    "NOTE",
-    "    Besides NetCDF none of the supported data formats supports global attributes.",
+    "    This operator inverts the latitudes of all fields on a rectilinear grid. ",
     NULL
 };
 
-static const char *InvertHelp[] = {
+static const char *InvertlevHelp[] = {
     "NAME",
-    "    invertlat - Invert latitudes",
+    "    invertlev - Invert levels",
     "",
     "SYNOPSIS",
-    "    invertlat  ifile ofile",
+    "    invertlev  infile outfile",
     "",
     "DESCRIPTION",
-    "    This operator inverts the latitudes of all fields on a rectilinear grid. ",
+    "    This operator inverts the levels of all 3D variables.",
     NULL
 };
 
-static const char *InvertlevHelp[] = {
+static const char *ShiftxyHelp[] = {
     "NAME",
-    "    invertlev - Invert levels",
+    "    shiftx, shifty - Shift field",
     "",
     "SYNOPSIS",
-    "    invertlev  ifile ofile",
+    "    <operator>,<nshift>,<cyclic>,<coord>  infile outfile",
     "",
     "DESCRIPTION",
-    "    This operator inverts the levels of all 3D variables.",
+    "    This module contains operators to shift all fields in x or y direction.",
+    "    All fields need to have the same horizontal rectilinear or curvilinear grid.",
+    "",
+    "OPERATORS",
+    "    shiftx  Shift x",
+    "            Shifts all fields in x direction.",
+    "    shifty  Shift y",
+    "            Shifts all fields in y direction.",
+    "",
+    "PARAMETER",
+    "    nshift  INTEGER  Number of grid cells to shift (default: 1)",
+    "    cyclic  STRING   If set, cells are filled up cyclic (default: missing value)",
+    "    coord   STRING   If set, coordinates are also shifted",
     NULL
 };
 
@@ -1169,7 +1202,7 @@ static const char *MaskregionHelp[] = {
     "    maskregion - Mask regions",
     "",
     "SYNOPSIS",
-    "    maskregion,regions  ifile ofile",
+    "    maskregion,regions  infile outfile",
     "",
     "DESCRIPTION",
     "    Masks different regions of fields with a regular lon/lat grid. The elements ",
@@ -1192,8 +1225,8 @@ static const char *MaskboxHelp[] = {
     "    masklonlatbox, maskindexbox - Mask a box",
     "",
     "SYNOPSIS",
-    "    masklonlatbox,lon1,lon2,lat1,lat2  ifile ofile",
-    "    maskindexbox,idx1,idx2,idy1,idy2  ifile ofile",
+    "    masklonlatbox,lon1,lon2,lat1,lat2  infile outfile",
+    "    maskindexbox,idx1,idx2,idy1,idy2  infile outfile",
     "",
     "DESCRIPTION",
     "    Masked a box of the rectangularly understood field. The elements inside the box are untouched, the ",
@@ -1225,8 +1258,8 @@ static const char *SetboxHelp[] = {
     "    setclonlatbox, setcindexbox - Set a box to constant",
     "",
     "SYNOPSIS",
-    "    setclonlatbox,c,lon1,lon2,lat1,lat2  ifile ofile",
-    "    setcindexbox,c,idx1,idx2,idy1,idy2  ifile ofile",
+    "    setclonlatbox,c,lon1,lon2,lat1,lat2  infile outfile",
+    "    setcindexbox,c,idx1,idx2,idy1,idy2  infile outfile",
     "",
     "DESCRIPTION",
     "    Sets a box of the rectangularly understood field to a constant value. The elements outside ",
@@ -1260,10 +1293,10 @@ static const char *EnlargeHelp[] = {
     "    enlarge - Enlarge fields",
     "",
     "SYNOPSIS",
-    "    enlarge,grid  ifile ofile",
+    "    enlarge,grid  infile outfile",
     "",
     "DESCRIPTION",
-    "    Enlarge all fields of ifile to a user given grid. Normally only the last ",
+    "    Enlarge all fields of infile to a user given horizontal grid. Normally only the last ",
     "    field element is used for the enlargement. If however the input and output",
     "    grid are regular lon/lat grids, a zonal or meridional enlargement is possible.",
     "    Zonal enlargement takes place, if the xsize of the input field is 1 and ",
@@ -1281,13 +1314,13 @@ static const char *SetmissHelp[] = {
     "    setmisstodis - Set missing value",
     "",
     "SYNOPSIS",
-    "    setmissval,newmiss  ifile ofile",
-    "    setctomiss,c  ifile ofile",
-    "    setmisstoc,c  ifile ofile",
-    "    setrtomiss,rmin,rmax  ifile ofile",
-    "    setvrange,rmin,rmax  ifile ofile",
-    "    setmisstonn  ifile ofile",
-    "    setmisstodis[,neighbors]  ifile ofile",
+    "    setmissval,newmiss  infile outfile",
+    "    setctomiss,c  infile outfile",
+    "    setmisstoc,c  infile outfile",
+    "    setrtomiss,rmin,rmax  infile outfile",
+    "    setvrange,rmin,rmax  infile outfile",
+    "    setmisstonn  infile outfile",
+    "    setmisstodis[,neighbors]  infile outfile",
     "",
     "DESCRIPTION",
     "    This module sets part of a field to missing value or missing values",
@@ -1338,10 +1371,10 @@ static const char *ExprHelp[] = {
     "    expr, exprf, aexpr, aexprf - Evaluate expressions",
     "",
     "SYNOPSIS",
-    "    expr,instr  ifile ofile",
-    "    exprf,filename  ifile ofile",
-    "    aexpr,instr  ifile ofile",
-    "    aexprf,filename  ifile ofile",
+    "    expr,instr  infile outfile",
+    "    exprf,filename  infile outfile",
+    "    aexpr,instr  infile outfile",
+    "    aexprf,filename  infile outfile",
     "",
     "DESCRIPTION",
     "    This module arithmetically processes every timestep of the input dataset.",
@@ -1358,7 +1391,7 @@ static const char *ExprHelp[] = {
     "         -      & subtraction         & x - y     & Difference of x and y    ",
     "         *      & multiplication      & x * y     & Product of x and y ",
     "         /      & division            & x / y     & Quotient of x and y",
-    "         ^      & exponentiation      & x ^ y     & Exponentiates x with y ",
+    "         ^      & exponentiation      & x ^y      & Exponentiates x with y ",
     "         ==     & equal to            & x == y    &  1, if x equal to y; else 0",
     "         !=     & not equal to        & x != y    &  1, if x not equal to y; else 0",
     "         >      & greater than        & x > y     &  1, if x greater than y; else 0",
@@ -1435,6 +1468,10 @@ static const char *ExprHelp[] = {
     "PARAMETER",
     "    instr     STRING  Processing instructions (need to be 'quoted' in most cases)",
     "    filename  STRING  File with processing instructions",
+    "",
+    "NOTE",
+    "    The expr commands sellevel(x,k) and sellevidx(x,k) are only available with exprf/aexprf.",
+    "    If the input stream contains duplicate entries of the same variable name then the last one is used.",
     NULL
 };
 
@@ -1444,7 +1481,7 @@ static const char *MathHelp[] = {
     "    atan, reci - Mathematical functions",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile ofile",
+    "    <operator>  infile outfile",
     "",
     "DESCRIPTION",
     "    This module contains some standard mathematical functions.",
@@ -1491,11 +1528,11 @@ static const char *ArithcHelp[] = {
     "    addc, subc, mulc, divc - Arithmetic with a constant",
     "",
     "SYNOPSIS",
-    "    <operator>,c  ifile ofile",
+    "    <operator>,c  infile outfile",
     "",
     "DESCRIPTION",
     "    This module performs simple arithmetic with all field elements of a dataset and ",
-    "    a constant. The fields in ofile inherit the meta data from ifile.",
+    "    a constant. The fields in outfile inherit the meta data from infile.",
     "",
     "OPERATORS",
     "    addc  Add a constant",
@@ -1517,12 +1554,12 @@ static const char *ArithHelp[] = {
     "    add, sub, mul, div, min, max, atan2 - Arithmetic on two datasets",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile1 ifile2 ofile",
+    "    <operator>  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
     "    This module performs simple arithmetic of two datasets.",
-    "    The number of fields in ifile1 should be the same as in ifile2.",
-    "    The fields in ofile inherit the meta data from ifile1.",
+    "    The number of fields in infile1 should be the same as in infile2.",
+    "    The fields in outfile inherit the meta data from infile1.",
     "    One of the input files can contain only one timestep or one variable.",
     "",
     "OPERATORS",
@@ -1551,14 +1588,14 @@ static const char *MonarithHelp[] = {
     "    monadd, monsub, monmul, mondiv - Monthly arithmetic",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile1 ifile2 ofile",
+    "    <operator>  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
     "    This module performs simple arithmetic of a time series and one",
-    "    timestep with the same month and year. For each field in ifile1",
-    "    the corresponding field of the timestep in ifile2 with the",
-    "    same month and year is used. The header information in ifile1",
-    "    have to be the same as in ifile2. Usually ifile2 is generated",
+    "    timestep with the same month and year. For each field in infile1",
+    "    the corresponding field of the timestep in infile2 with the",
+    "    same month and year is used. The header information in infile1",
+    "    have to be the same as in infile2. Usually infile2 is generated",
     "    by an operator of the module MONSTAT.",
     "",
     "OPERATORS",
@@ -1578,14 +1615,14 @@ static const char *YhourarithHelp[] = {
     "    yhouradd, yhoursub, yhourmul, yhourdiv - Multi-year hourly arithmetic",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile1 ifile2 ofile",
+    "    <operator>  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
     "    This module performs simple arithmetic of a time series and one",
-    "    timestep with the same hour and day of year. For each field in ifile1",
-    "    the corresponding field of the timestep in ifile2 with the",
-    "    same hour and day of year is used. The header information in ifile1",
-    "    have to be the same as in ifile2. Usually ifile2 is generated",
+    "    timestep with the same hour and day of year. For each field in infile1",
+    "    the corresponding field of the timestep in infile2 with the",
+    "    same hour and day of year is used. The header information in infile1",
+    "    have to be the same as in infile2. Usually infile2 is generated",
     "    by an operator of the module YHOURSTAT.",
     "",
     "OPERATORS",
@@ -1605,14 +1642,14 @@ static const char *YdayarithHelp[] = {
     "    ydayadd, ydaysub, ydaymul, ydaydiv - Multi-year daily arithmetic",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile1 ifile2 ofile",
+    "    <operator>  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
     "    This module performs simple arithmetic of a time series and one",
-    "    timestep with the same day of year. For each field in ifile1",
-    "    the corresponding field of the timestep in ifile2 with the",
-    "    same day of year is used. The header information in ifile1",
-    "    have to be the same as in ifile2. Usually ifile2 is generated",
+    "    timestep with the same day of year. For each field in infile1",
+    "    the corresponding field of the timestep in infile2 with the",
+    "    same day of year is used. The header information in infile1",
+    "    have to be the same as in infile2. Usually infile2 is generated",
     "    by an operator of the module YDAYSTAT.",
     "",
     "OPERATORS",
@@ -1632,14 +1669,14 @@ static const char *YmonarithHelp[] = {
     "    ymonadd, ymonsub, ymonmul, ymondiv - Multi-year monthly arithmetic",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile1 ifile2 ofile",
+    "    <operator>  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
     "    This module performs simple arithmetic of a time series and one timestep",
-    "    with the same month of year. For each field in ifile1 the corresponding",
-    "    field of the timestep in ifile2 with the same month of year is used.",
-    "    The header information in ifile1 have to be the same as in ifile2.",
-    "    Usually ifile2 is generated by an operator of the module YMONSTAT.",
+    "    with the same month of year. For each field in infile1 the corresponding",
+    "    field of the timestep in infile2 with the same month of year is used.",
+    "    The header information in infile1 have to be the same as in infile2.",
+    "    Usually infile2 is generated by an operator of the module YMONSTAT.",
     "",
     "OPERATORS",
     "    ymonadd  Add multi-year monthly time series",
@@ -1658,14 +1695,14 @@ static const char *YseasarithHelp[] = {
     "    yseasadd, yseassub, yseasmul, yseasdiv - Multi-year seasonal arithmetic",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile1 ifile2 ofile",
+    "    <operator>  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
     "    This module performs simple arithmetic of a time series and one timestep",
-    "    with the same season. For each field in ifile1 the corresponding",
-    "    field of the timestep in ifile2 with the same season is used.",
-    "    The header information in ifile1 have to be the same as in ifile2.",
-    "    Usually ifile2 is generated by an operator of the module YSEASSTAT.",
+    "    with the same season. For each field in infile1 the corresponding",
+    "    field of the timestep in infile2 with the same season is used.",
+    "    The header information in infile1 have to be the same as in infile2.",
+    "    Usually infile2 is generated by an operator of the module YSEASSTAT.",
     "",
     "OPERATORS",
     "    yseasadd  Add multi-year seasonal time series",
@@ -1684,7 +1721,7 @@ static const char *ArithdaysHelp[] = {
     "    muldpm, divdpm, muldpy, divdpy - Arithmetic with days",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile ofile",
+    "    <operator>  infile outfile",
     "",
     "DESCRIPTION",
     "    This module multiplies or divides each timestep of a dataset with the corresponding",
@@ -1703,15 +1740,30 @@ static const char *ArithdaysHelp[] = {
     NULL
 };
 
+static const char *TimcumsumHelp[] = {
+    "NAME",
+    "    timcumsum - Cumulative sum over all timesteps",
+    "",
+    "SYNOPSIS",
+    "    timcumsum  infile outfile",
+    "",
+    "DESCRIPTION",
+    "    The timcumsum operator calculates the cumulative sum over all timesteps.",
+    "    Missing values are treated as numeric zero when summing.",
+    "    ",
+    "    o(t,x) = sum{i(t',x), 0<t'<=t}",
+    NULL
+};
+
 static const char *ConsecstatHelp[] = {
     "NAME",
     "    consecsum, consects - Consecute timestep periods",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile ofile",
+    "    <operator>  infile outfile",
     "",
     "DESCRIPTION",
-    "    This module computes periods over all timesteps in ifile where a",
+    "    This module computes periods over all timesteps in infile where a",
     "    certain property is valid. The propery can be chosen by creating a mask from",
     "    the original data, which is the expected input format for operators of this",
     "    module. Depending on the operator full information about each period or",
@@ -1736,16 +1788,16 @@ static const char *EnsstatHelp[] = {
     "    enspctl - Statistical values over an ensemble",
     "",
     "SYNOPSIS",
-    "    <operator>  ifiles ofile",
-    "    enspctl,p  ifiles ofile",
+    "    <operator>  infiles outfile",
+    "    enspctl,p  infiles outfile",
     "",
     "DESCRIPTION",
     "    This module computes statistical values over an ensemble of input files.",
     "    Depending on the chosen operator the minimum, maximum, sum, average, variance,",
     "    standard deviation or a certain percentile over all input files is written",
-    "    to ofile.",
+    "    to outfile.",
     "    All input files need to have the same structure with the same variables.",
-    "    The date information of a timestep in ofile is the date of the first input file.",
+    "    The date information of a timestep in outfile is the date of the first input file.",
     "",
     "OPERATORS",
     "    ensmin   Ensemble minimum",
@@ -1791,14 +1843,14 @@ static const char *Ensstat2Help[] = {
     "    ensrkhistspace, ensrkhisttime, ensroc - Statistical values over an ensemble",
     "",
     "SYNOPSIS",
-    "    <operator>  obsfile ensfiles ofile",
+    "    <operator>  obsfile ensfiles outfile",
     "",
     "DESCRIPTION",
     "    This module computes statistical values over the ensemble of ensfiles using",
     "    obsfile as a reference. Depending on the operator a ranked Histogram or ",
     "    a roc-curve over all Ensembles ensfiles",
-    "    with reference to obsfile is written to ofile. ",
-    "    The date and grid information of a timestep in ofile is the date of the ",
+    "    with reference to obsfile is written to outfile. ",
+    "    The date and grid information of a timestep in outfile is the date of the ",
     "    first input file. Thus all input files are required to have the same structure in ",
     "    terms of the gridsize, variable definitions and number of timesteps. ",
     "    ",
@@ -1816,8 +1868,8 @@ static const char *Ensstat2Help[] = {
     "    ensrkhistspace computes a ranked histogram at each timestep reducing each ",
     "    horizontal grid to a 1x1 grid and keeping the time axis as in obsfile. ",
     "    Contrary ensrkhistspace  computes a histogram at each grid point keeping the ",
-    "    horizontal grid for each variable and reducing the time-axis. The time infor-",
-    "    mation is that from the last timestep in obsfile. ",
+    "    horizontal grid for each variable and reducing the time-axis. The time information",
+    "    is that from the last timestep in obsfile. ",
     "",
     "OPERATORS",
     "    ensrkhistspace  Ranked Histogram averaged over time",
@@ -1831,23 +1883,23 @@ static const char *EnsvalHelp[] = {
     "    enscrps, ensbrs - Ensemble validation tools",
     "",
     "SYNOPSIS",
-    "    enscrps  rfile ifiles ofilebase",
-    "    ensbrs,x  rfile ifiles ofilebase",
+    "    enscrps  rfile infiles outfilebase",
+    "    ensbrs,x  rfile infiles outfilebase",
     "",
     "DESCRIPTION",
     "    This module computes ensemble validation scores and their decomposition such as ",
     "    the Brier and cumulative ranked probability score (CRPS). ",
     "    The first file is used as a reference it can be a climatology, observation or ",
-    "    reanalysis against which the skill of the ensembles given in ifiles is measured. ",
+    "    reanalysis against which the skill of the ensembles given in infiles is measured. ",
     "    Depending on the operator a number of output files is generated each containing ",
     "    the skill score and its decomposition corresponding to the operator. ",
     "    The output is averaged  over horizontal fields using appropriate weights ",
     "    for each level and timestep in rfile. ",
     "    ",
     "    All input files need to have the same structure with the same variables.",
-    "    The date information of a timestep in ofile is the date of the first input file.",
+    "    The date information of a timestep in outfile is the date of the first input file.",
     "    The output files are named as ",
-    "    <ofilebase>.<type>.<filesuffix> where <type> depends on the ",
+    "    <outfilebase>.<type>.<filesuffix> where <type> depends on the ",
     "    operator and <filesuffix> is determined from the output file type. ",
     "    There are three output files for operator enscrps and four output files ",
     "    for operator ensbrs.",
@@ -1862,7 +1914,7 @@ static const char *EnsvalHelp[] = {
     "    CRPS = CRPS_{pot} + RELI",
     "    holds. 	  ",
     "    ",
-    "    The Brier score of the Ensemble given by ifiles with respect to the ",
+    "    The Brier score of the Ensemble given by infiles with respect to the ",
     "    reference given in rfile and the threshold x is calculated. ",
     "    In the four output files <type> has the following meaning: ",
     "    brs for the Brier score wrt threshold  x; ",
@@ -1895,13 +1947,13 @@ static const char *FldstatHelp[] = {
     "    fldpctl - Statistical values over a field",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile ofile",
-    "    fldpctl,p  ifile ofile",
+    "    <operator>  infile outfile",
+    "    fldpctl,p  infile outfile",
     "",
     "DESCRIPTION",
     "    This module computes statistical values of the input fields. According to the chosen ",
     "    operator the field minimum, maximum, sum, average, variance, standard deviation or ",
-    "    a certain percentile is written to ofile.",
+    "    a certain percentile is written to outfile.",
     "",
     "OPERATORS",
     "    fldmin   Field minimum",
@@ -1962,13 +2014,13 @@ static const char *ZonstatHelp[] = {
     "    zonpctl - Zonal statistical values",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile ofile",
-    "    zonpctl,p  ifile ofile",
+    "    <operator>  infile outfile",
+    "    zonpctl,p  infile outfile",
     "",
     "DESCRIPTION",
     "    This module computes zonal statistical values of the input fields.",
     "    According to the chosen operator the zonal minimum, maximum, sum, average,",
-    "    variance, standard deviation or a certain percentile is written to ofile.",
+    "    variance, standard deviation or a certain percentile is written to outfile.",
     "    This operator requires all variables on the same regular lon/lat grid.",
     "",
     "OPERATORS",
@@ -2004,13 +2056,13 @@ static const char *MerstatHelp[] = {
     "    merpctl - Meridional statistical values",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile ofile",
-    "    merpctl,p  ifile ofile",
+    "    <operator>  infile outfile",
+    "    merpctl,p  infile outfile",
     "",
     "DESCRIPTION",
     "    This module computes meridional statistical values of the input fields.",
     "    According to the chosen operator the meridional minimum, maximum, sum, average,",
-    "    variance, standard deviation or a certain percentile is written to ofile.",
+    "    variance, standard deviation or a certain percentile is written to outfile.",
     "    This operator requires all variables on the same regular lon/lat grid.",
     "",
     "OPERATORS",
@@ -2046,12 +2098,12 @@ static const char *GridboxstatHelp[] = {
     "    gridboxstd1, gridboxvar, gridboxvar1 - Statistical values over grid boxes",
     "",
     "SYNOPSIS",
-    "    <operator>,nx,ny  ifile ofile",
+    "    <operator>,nx,ny  infile outfile",
     "",
     "DESCRIPTION",
     "    This module computes statistical values over surrounding grid boxes.",
     "    According to the chosen operator the minimum, maximum, sum, average, ",
-    "    variance, or standard deviation of the neighboring grid boxes is written to ofile.",
+    "    variance, or standard deviation of the neighboring grid boxes is written to outfile.",
     "    All gridbox operators only works on quadrilateral curvilinear grids.",
     "",
     "OPERATORS",
@@ -2086,12 +2138,12 @@ static const char *VertstatHelp[] = {
     "    vertvar1 - Vertical statistical values",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile ofile",
+    "    <operator>  infile outfile",
     "",
     "DESCRIPTION",
     "    This module computes statistical values over all levels of the input variables.",
     "    According to chosen operator the vertical minimum, maximum, sum, average, variance",
-    "    or standard deviation is written to ofile.",
+    "    or standard deviation is written to outfile.",
     "",
     "OPERATORS",
     "    vertmin   Vertical minimum",
@@ -2121,58 +2173,49 @@ static const char *TimselstatHelp[] = {
     "    timselstd1, timselvar, timselvar1 - Time range statistical values",
     "",
     "SYNOPSIS",
-    "    <operator>,nsets[,noffset[,nskip]]  ifile ofile",
+    "    <operator>,nsets[,noffset[,nskip]]  infile outfile",
     "",
     "DESCRIPTION",
     "    This module computes statistical values for a selected number of timesteps. According to ",
     "    the chosen operator the minimum, maximum, sum, average, variance or standard deviation of ",
-    "    the selected timesteps is written to ofile.",
-    "    The time stamp in ofile is from the middle contributing timestep of ifile.",
+    "    the selected timesteps is written to outfile.",
+    "    The time of outfile is determined by the time in the middle of all contributing timesteps of infile.",
     "",
     "OPERATORS",
     "    timselmin   Time range minimum",
-    "                For every adjacent sequence t1, ...., tn of timesteps of the same ",
-    "                selected time range it is",
+    "                For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:",
     "                ",
     "                o(t,x) = min{i(t',x), t1 < t' <= tn}",
     "    timselmax   Time range maximum",
-    "                For every adjacent sequence t1, ...., tn of timesteps of the same ",
-    "                selected time range it is",
+    "                For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:",
     "                ",
     "                o(t,x) = max{i(t',x), t1 < t' <= tn}",
     "    timselsum   Time range sum",
-    "                For every adjacent sequence t1, ...., tn of timesteps of the same ",
-    "                selected time range it is",
+    "                For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:",
     "                ",
     "                o(t,x) = sum{i(t',x), t1 < t' <= tn}",
     "    timselmean  Time range mean",
-    "                For every adjacent sequence t1, ...., tn of timesteps of the same ",
-    "                selected time range it is",
+    "                For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:",
     "                ",
     "                o(t,x) = mean{i(t',x), t1 < t' <= tn}",
     "    timselavg   Time range average",
-    "                For every adjacent sequence t1, ...., tn of timesteps of the same ",
-    "                selected time range it is",
+    "                For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:",
     "                ",
     "                o(t,x) = avg{i(t',x), t1 < t' <= tn}",
     "    timselstd   Time range standard deviation",
-    "                Normalize by n. For every adjacent sequence t1, ...., tn of timesteps of the same ",
-    "                selected time range it is",
+    "                Normalize by n. For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:",
     "                ",
     "                o(t,x) = std{i(t',x), t1 < t' <= tn}",
     "    timselstd1  Time range standard deviation (n-1)",
-    "                Normalize by (n-1). For every adjacent sequence t1, ...., tn of timesteps of the same ",
-    "                selected time range it is",
+    "                Normalize by (n-1). For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:",
     "                ",
     "                o(t,x) = std1{i(t',x), t1 < t' <= tn}",
     "    timselvar   Time range variance",
-    "                Normalize by n. For every adjacent sequence t1, ...., tn of timesteps of the same ",
-    "                selected time range it is",
+    "                Normalize by n. For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:",
     "                ",
     "                o(t,x) = var{i(t',x), t1 < t' <= tn}",
     "    timselvar1  Time range variance (n-1)",
-    "                Normalize by (n-1). For every adjacent sequence t1, ...., tn of timesteps of the same ",
-    "                selected time range it is",
+    "                Normalize by (n-1). For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:",
     "                ",
     "                o(t,x) = var1{i(t',x), t1 < t' <= tn}",
     "",
@@ -2188,17 +2231,16 @@ static const char *TimselpctlHelp[] = {
     "    timselpctl - Time range percentile values",
     "",
     "SYNOPSIS",
-    "    timselpctl,p,nsets[,noffset[,nskip]]  ifile1 ifile2 ifile3 ofile",
+    "    timselpctl,p,nsets[,noffset[,nskip]]  infile1 infile2 infile3 outfile",
     "",
     "DESCRIPTION",
-    "    This operator computes percentile values over a selected number of timesteps in ifile1.",
-    "    The algorithm uses histograms with minimum and maximum bounds given in ifile2 and ifile3,",
+    "    This operator computes percentile values over a selected number of timesteps in infile1.",
+    "    The algorithm uses histograms with minimum and maximum bounds given in infile2 and infile3,",
     "    respectively. The default number of histogram bins is 101. The default can be overridden by setting the",
-    "    environment variable CDO_PCTL_NBINS to a different value. The files ifile2 and ifile3 ",
+    "    environment variable CDO_PCTL_NBINS to a different value. The files infile2 and infile3 ",
     "    should be the result of corresponding timselmin and timselmax operations, respectively.",
-    "    The time stamp in ofile is from the middle contributing timestep of ifile1.",
-    "    For every adjacent sequence t1, ...., tn of timesteps of the same ",
-    "    selected time range it is",
+    "    The time of outfile is determined by the time in the middle of all contributing timesteps of infile1.",
+    "    For every adjacent sequence t1, ...., tn of timesteps of the same selected time range it is:",
     "    ",
     "    o(t,x) = pth percentile {i(t',x), t1 < t' <= tn}",
     "",
@@ -2220,13 +2262,13 @@ static const char *RunstatHelp[] = {
     "    Running statistical values",
     "",
     "SYNOPSIS",
-    "    <operator>,nts  ifile ofile",
+    "    <operator>,nts  infile outfile",
     "",
     "DESCRIPTION",
     "    This module computes running statistical values over a selected number of timesteps. Depending on ",
     "    the chosen operator the minimum, maximum, sum, average, variance or standard deviation of a selected ",
-    "    number of consecutive timesteps read from ifile is written to ofile. ",
-    "    The time stamp in ofile is from the middle contributing timestep of ifile.",
+    "    number of consecutive timesteps read from infile is written to outfile. ",
+    "    The time of outfile is determined by the time in the middle of all contributing timesteps of infile.",
     "",
     "OPERATORS",
     "    runmin   Running minimum",
@@ -2261,7 +2303,7 @@ static const char *RunstatHelp[] = {
     "",
     "ENVIRONMENT",
     "    CDO_TIMESTAT_DATE",
-    "        Sets the time stamp in ofile to the \"first\", \"middle\" or \"last\" contributing timestep of ifile.",
+    "        Sets the time stamp in outfile to the \"first\", \"middle\" or \"last\" contributing timestep of infile.",
     NULL
 };
 
@@ -2270,11 +2312,11 @@ static const char *RunpctlHelp[] = {
     "    runpctl - Running percentile values",
     "",
     "SYNOPSIS",
-    "    runpctl,p,nts  ifile ofile",
+    "    runpctl,p,nts  infile outfile",
     "",
     "DESCRIPTION",
-    "    This module computes running percentiles over a selected number of timesteps in ifile.",
-    "    The time stamp in ofile is from the middle contributing timestep of ifile.",
+    "    This module computes running percentiles over a selected number of timesteps in infile.",
+    "    The time of outfile is determined by the time in the middle of all contributing timesteps of infile.",
     "    ",
     "    o(t+(nts-1)/2,x) = pth percentile {i(t,x), i(t+1,x), ..., i(t+nts-1,x)}",
     "",
@@ -2290,13 +2332,13 @@ static const char *TimstatHelp[] = {
     "    Statistical values over all timesteps",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile ofile",
+    "    <operator>  infile outfile",
     "",
     "DESCRIPTION",
-    "    This module computes statistical  values over all timesteps in ifile. Depending on ",
+    "    This module computes statistical  values over all timesteps in infile. Depending on ",
     "    the chosen operator the minimum, maximum, sum, average, variance or standard deviation of ",
-    "    all timesteps read from ifile is written to ofile.",
-    "    The time stamp in ofile is from the middle contributing timestep of ifile.",
+    "    all timesteps read from infile is written to outfile.",
+    "    The time of outfile is determined by the time in the middle of all contributing timesteps of infile.",
     "",
     "OPERATORS",
     "    timmin   Time minimum",
@@ -2333,15 +2375,15 @@ static const char *TimpctlHelp[] = {
     "    timpctl - Percentile values over all timesteps",
     "",
     "SYNOPSIS",
-    "    timpctl,p  ifile1 ifile2 ifile3 ofile",
+    "    timpctl,p  infile1 infile2 infile3 outfile",
     "",
     "DESCRIPTION",
-    "    This operator computes percentiles over all timesteps in ifile1. The algorithm uses ",
-    "    histograms with minimum and maximum bounds given in ifile2 and ifile3, respectively. ",
-    "    The default number of histogram bins is 101. The default can be overridden by setting the",
-    "    environment variable CDO_PCTL_NBINS to a different value. The files ifile2 and ifile3",
-    "    should be the result of corresponding timmin and timmax operations, respectively.",
-    "    The time stamp in ofile is from the middle contributing timestep of ifile1.",
+    "    This operator computes percentiles over all timesteps in infile1. The algorithm uses ",
+    "    histograms with minimum and maximum bounds given in infile2 and infile3, respectively. ",
+    "    The default number of histogram bins is 101. The default can be overridden by defining the",
+    "    environment variable CDO_PCTL_NBINS. The files infile2 and infile3 should be",
+    "    the result of corresponding timmin and timmax operations, respectively.",
+    "    The time of outfile is determined by the time in the middle of all contributing timesteps of infile1.",
     "    ",
     "    o(1,x) = pth percentile {i(t',x), t_1<t'<=t_n}",
     "",
@@ -2360,13 +2402,13 @@ static const char *HourstatHelp[] = {
     "    hourvar1 - Hourly statistical values",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile ofile",
+    "    <operator>  infile outfile",
     "",
     "DESCRIPTION",
     "    This module computes statistical values over timesteps of the same hour.",
     "    Depending on the chosen operator the minimum, maximum, sum, average, variance",
-    "    or standard deviation of timesteps of the same hour is written to ofile.",
-    "    The time stamp in ofile is from the middle contributing timestep of ifile.",
+    "    or standard deviation of timesteps of the same hour is written to outfile.",
+    "    The time of outfile is determined by the time in the middle of all contributing timesteps of infile.",
     "",
     "OPERATORS",
     "    hourmin   Hourly minimum",
@@ -2413,17 +2455,16 @@ static const char *HourpctlHelp[] = {
     "    hourpctl - Hourly percentile values",
     "",
     "SYNOPSIS",
-    "    hourpctl,p  ifile1 ifile2 ifile3 ofile",
+    "    hourpctl,p  infile1 infile2 infile3 outfile",
     "",
     "DESCRIPTION",
-    "    This operator computes percentiles over all timesteps of the same hour in ifile1.",
-    "    The algorithm uses histograms with minimum and maximum bounds given in",
-    "    ifile2 and ifile3, respectively. The default number of",
-    "    histogram bins is 101. The default can be overridden by setting the",
-    "    environment variable CDO_PCTL_NBINS to a different value. The files",
-    "    ifile2 and ifile3 should be the result of corresponding",
-    "    hourmin and hourmax operations, respectively.",
-    "    The time stamp in ofile is from the middle contributing timestep of ifile1.",
+    "    This operator computes percentiles over all timesteps of the same hour in infile1.",
+    "    The algorithm uses histograms with minimum and maximum bounds given in infile2 and",
+    "    infile3, respectively. The default number of histogram bins is 101.",
+    "    The default can be overridden by defining the environment variable CDO_PCTL_NBINS.",
+    "    The files infile2 and infile3 should be the result of corresponding hourmin",
+    "    and hourmax operations, respectively.",
+    "    The time of outfile is determined by the time in the middle of all contributing timesteps of infile1.",
     "    For every adjacent sequence t_1, ...,t_n of timesteps of the same hour it is:",
     "    ",
     "    o(t,x) = pth percentile {i(t',x), t_1<t'<=t_n}",
@@ -2443,49 +2484,49 @@ static const char *DaystatHelp[] = {
     "    Daily statistical values",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile ofile",
+    "    <operator>  infile outfile",
     "",
     "DESCRIPTION",
     "    This module computes statistical values over timesteps of the same day.",
     "    Depending on the chosen operator the minimum, maximum, sum, average, variance",
-    "    or standard deviation of timesteps of the same day is written to ofile.",
-    "    The time stamp in ofile is from the middle contributing timestep of ifile.",
+    "    or standard deviation of timesteps of the same day is written to outfile.",
+    "    The time of outfile is determined by the time in the middle of all contributing timesteps of infile.",
     "",
     "OPERATORS",
     "    daymin   Daily minimum",
-    "             For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is",
+    "             For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:",
     "             ",
     "             o(t,x) = min{i(t',x), t_1<t'<=t_n}",
     "    daymax   Daily maximum",
-    "             For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is",
+    "             For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:",
     "             ",
     "             o(t,x) = max{i(t',x), t_1<t'<=t_n}",
     "    daysum   Daily sum",
-    "             For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is",
+    "             For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:",
     "             ",
     "             o(t,x) = sum{i(t',x), t_1<t'<=t_n}",
     "    daymean  Daily mean",
-    "             For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is",
+    "             For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:",
     "             ",
     "             o(t,x) = mean{i(t',x), t_1<t'<=t_n}",
     "    dayavg   Daily average",
-    "             For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is",
+    "             For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:",
     "             ",
     "             o(t,x) = avg{i(t',x), t_1<t'<=t_n}",
     "    daystd   Daily standard deviation",
-    "             Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is",
+    "             Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:",
     "             ",
     "             o(t,x) = std{i(t',x), t_1<t'<=t_n}",
     "    daystd1  Daily standard deviation (n-1)",
-    "             Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is",
+    "             Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:",
     "             ",
     "             o(t,x) = std1{i(t',x), t_1<t'<=t_n}",
     "    dayvar   Daily variance",
-    "             Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is",
+    "             Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:",
     "             ",
     "             o(t,x) = var{i(t',x), t_1<t'<=t_n}",
     "    dayvar1  Daily variance (n-1)",
-    "             Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is",
+    "             Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:",
     "             ",
     "             o(t,x) = var1{i(t',x), t_1<t'<=t_n}",
     NULL
@@ -2496,18 +2537,17 @@ static const char *DaypctlHelp[] = {
     "    daypctl - Daily percentile values",
     "",
     "SYNOPSIS",
-    "    daypctl,p  ifile1 ifile2 ifile3 ofile",
+    "    daypctl,p  infile1 infile2 infile3 outfile",
     "",
     "DESCRIPTION",
-    "    This operator computes percentiles over all timesteps of the same day in ifile1.",
-    "    The algorithm uses histograms with minimum and maximum bounds given in",
-    "    ifile2 and ifile3, respectively. The default number of",
-    "    histogram bins is 101. The default can be overridden by defining the",
-    "    environment variable CDO_PCTL_NBINS. The files ifile2 and",
-    "    ifile3 should be the result of corresponding daymin and daymax",
-    "    operations, respectively.",
-    "    The time stamp in ofile is from the middle contributing timestep of ifile1.",
-    "    For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is",
+    "    This operator computes percentiles over all timesteps of the same day in infile1.",
+    "    The algorithm uses histograms with minimum and maximum bounds given in infile2 and",
+    "    infile3, respectively. The default number of histogram bins is 101.",
+    "    The default can be overridden by defining the environment variable CDO_PCTL_NBINS.",
+    "    The files infile2 and infile3 should be the result of corresponding daymin",
+    "    and daymax operations, respectively.",
+    "    The time of outfile is determined by the time in the middle of all contributing timesteps of infile1.",
+    "    For every adjacent sequence t_1, ...,t_n of timesteps of the same day it is:",
     "    ",
     "    o(t,x) = pth percentile {i(t',x), t_1<t'<=t_n}",
     "",
@@ -2526,13 +2566,13 @@ static const char *MonstatHelp[] = {
     "    Monthly statistical values",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile ofile",
+    "    <operator>  infile outfile",
     "",
     "DESCRIPTION",
     "    This module computes statistical values over timesteps of the same month.",
     "    Depending on the chosen operator the minimum, maximum, sum, average, variance",
-    "    or standard deviation of timesteps of the same month is written to ofile.",
-    "    The time stamp in ofile is from the middle contributing timestep of ifile.",
+    "    or standard deviation of timesteps of the same month is written to outfile.",
+    "    The time of outfile is determined by the time in the middle of all contributing timesteps of infile.",
     "",
     "OPERATORS",
     "    monmin   Monthly minimum",
@@ -2540,35 +2580,35 @@ static const char *MonstatHelp[] = {
     "             ",
     "             o(t,x) = min{i(t',x), t_1<t'<=t_n}",
     "    monmax   Monthly maximum",
-    "             For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is",
+    "             For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:",
     "             ",
     "             o(t,x) = max{i(t',x), t_1<t'<=t_n}",
     "    monsum   Monthly sum",
-    "             For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is",
+    "             For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:",
     "             ",
     "             o(t,x) = sum{i(t',x), t_1<t'<=t_n}",
     "    monmean  Monthly mean",
-    "             For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is",
+    "             For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:",
     "             ",
     "             o(t,x) = mean{i(t',x), t_1<t'<=t_n}",
     "    monavg   Monthly average",
-    "             For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is",
+    "             For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:",
     "             ",
     "             o(t,x) = avg{i(t',x), t_1<t'<=t_n}",
     "    monstd   Monthly standard deviation",
-    "             Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is",
+    "             Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:",
     "             ",
     "             o(t,x) = std{i(t',x), t_1 < t' <= t_n}",
     "    monstd1  Monthly standard deviation (n-1)",
-    "             Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is",
+    "             Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:",
     "             ",
     "             o(t,x) = std1{i(t',x), t_1 < t' <= t_n}",
     "    monvar   Monthly variance",
-    "             Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is",
+    "             Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:",
     "             ",
     "             o(t,x) = var{i(t',x), t_1 < t' <= t_n}",
     "    monvar1  Monthly variance (n-1)",
-    "             Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is",
+    "             Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:",
     "             ",
     "             o(t,x) = var1{i(t',x), t_1 < t' <= t_n}",
     NULL
@@ -2579,17 +2619,16 @@ static const char *MonpctlHelp[] = {
     "    monpctl - Monthly percentile values",
     "",
     "SYNOPSIS",
-    "    monpctl,p  ifile1 ifile2 ifile3 ofile",
+    "    monpctl,p  infile1 infile2 infile3 outfile",
     "",
     "DESCRIPTION",
-    "    This operator computes percentiles over all timesteps of the same month in ifile1.",
-    "    The algorithm uses histograms with minimum and maximum bounds given in",
-    "    ifile2 and ifile3, respectively. The default number of",
-    "    histogram bins is 101. The default can be overridden by setting the",
-    "    environment variable CDO_PCTL_NBINS to a different value. The files",
-    "    ifile2 and ifile3 should be the result of corresponding",
-    "    monmin and monmax operations, respectively.",
-    "    The time stamp in ofile is from the middle contributing timestep of ifile1.",
+    "    This operator computes percentiles over all timesteps of the same month in infile1.",
+    "    The algorithm uses histograms with minimum and maximum bounds given in infile2 and",
+    "    infile3, respectively. The default number of histogram bins is 101.",
+    "    The default can be overridden by defining the environment variable CDO_PCTL_NBINS.",
+    "    The files infile2 and infile3 should be the result of corresponding monmin",
+    "    and monmax operations, respectively.",
+    "    The time of outfile is determined by the time in the middle of all contributing timesteps of infile1.",
     "    For every adjacent sequence t_1, ...,t_n of timesteps of the same month it is:",
     "    ",
     "    o(t,x) = pth percentile {i(t',x), t_1<t'<=t_n}",
@@ -2608,20 +2647,20 @@ static const char *YearmonstatHelp[] = {
     "    yearmonmean - Yearly mean from monthly data",
     "",
     "SYNOPSIS",
-    "    yearmonmean  ifile ofile",
+    "    yearmonmean  infile outfile",
     "",
     "DESCRIPTION",
     "    This operator computes the yearly mean of a monthly time series.",
     "    Each month is weighted with the number of days per month. ",
-    "    The time stamp in ofile is from the middle contributing timestep of ifile.",
+    "    The time of outfile is determined by the time in the middle of all contributing timesteps of infile.",
     "    ",
-    "    For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is",
+    "    For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:",
     "    ",
     "    o(t,x) = mean{i(t',x), t_1<t'<=t_n}",
     "",
     "ENVIRONMENT",
     "    CDO_TIMESTAT_DATE",
-    "        Sets the date information in ofile to the \"first\", \"middle\" or \"last\" contributing timestep of ifile.",
+    "        Sets the date information in outfile to the \"first\", \"middle\" or \"last\" contributing timestep of infile.",
     NULL
 };
 
@@ -2631,49 +2670,49 @@ static const char *YearstatHelp[] = {
     "    yearvar1 - Yearly statistical values",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile ofile",
+    "    <operator>  infile outfile",
     "",
     "DESCRIPTION",
     "    This module computes statistical values over timesteps of the same year.",
     "    Depending on the chosen operator the minimum, maximum, sum, average, variance",
-    "    or standard deviation of timesteps of the same year is written to ofile.",
-    "    The time stamp in ofile is from the middle contributing timestep of ifile.",
+    "    or standard deviation of timesteps of the same year is written to outfile.",
+    "    The time of outfile is determined by the time in the middle of all contributing timesteps of infile.",
     "",
     "OPERATORS",
     "    yearmin   Yearly minimum",
-    "              For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is",
+    "              For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:",
     "              ",
     "              o(t,x) = min{i(t',x), t_1<t'<=t_n}",
     "    yearmax   Yearly maximum",
-    "              For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is",
+    "              For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:",
     "              ",
     "              o(t,x) = max{i(t',x), t_1<t'<=t_n}",
     "    yearsum   Yearly sum",
-    "              For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is",
+    "              For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:",
     "              ",
     "              o(t,x) = sum{i(t',x), t_1<t'<=t_n}",
     "    yearmean  Yearly mean",
-    "              For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is",
+    "              For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:",
     "              ",
     "              o(t,x) = mean{i(t',x), t_1<t'<=t_n}",
     "    yearavg   Yearly average",
-    "              For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is",
+    "              For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:",
     "              ",
     "              o(t,x) = avg{i(t',x), t_1<t'<=t_n}",
     "    yearstd   Yearly standard deviation",
-    "              Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is",
+    "              Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:",
     "              ",
     "              o(t,x) = std{i(t',x), t_1 < t' <= t_n}",
     "    yearstd1  Yearly standard deviation (n-1)",
-    "              Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is",
+    "              Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:",
     "              ",
     "              o(t,x) = std1{i(t',x), t_1 < t' <= t_n}",
     "    yearvar   Yearly variance",
-    "              Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is",
+    "              Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:",
     "              ",
     "              o(t,x) = var{i(t',x), t_1 < t' <= t_n}",
     "    yearvar1  Yearly variance (n-1)",
-    "              Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is",
+    "              Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:",
     "              ",
     "              o(t,x) = var1{i(t',x), t_1 < t' <= t_n}",
     "",
@@ -2687,18 +2726,16 @@ static const char *YearpctlHelp[] = {
     "    yearpctl - Yearly percentile values",
     "",
     "SYNOPSIS",
-    "    yearpctl,p  ifile1 ifile2 ifile3 ofile",
+    "    yearpctl,p  infile1 infile2 infile3 outfile",
     "",
     "DESCRIPTION",
-    "    This operator computes percentiles over all timesteps of the same year in ifile1.",
-    "    The algorithm uses histograms with minimum and maximum bounds given in",
-    "    ifile2 and ifile3, respectively. The default number of",
-    "    histogram bins is 101. The default can be overridden by setting the",
-    "    environment variable CDO_PCTL_NBINS to a different value. The files",
-    "    ifile2 and ifile3 should be the result of corresponding",
-    "    yearmin and yearmax operations, respectively.",
-    "    The time stamp in ofile is from the middle contributing timestep of ifile1.",
-    "    For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is",
+    "    This operator computes percentiles over all timesteps of the same year in infile1.",
+    "    The algorithm uses histograms with minimum and maximum bounds given in infile2 and",
+    "    infile3, respectively. The default number of histogram bins is 101. The default can be",
+    "    overridden by defining the environment variable CDO_PCTL_NBINS. The files infile2 and",
+    "    infile3 should be the result of corresponding yearmin and yearmax operations, respectively.",
+    "    The time of outfile is determined by the time in the middle of all contributing timesteps of infile1.",
+    "    For every adjacent sequence t_1, ...,t_n of timesteps of the same year it is:",
     "    ",
     "    o(t,x) = pth percentile {i(t',x), t_1<t'<=t_n}",
     "",
@@ -2717,51 +2754,51 @@ static const char *SeasstatHelp[] = {
     "    seasvar1 - Seasonal statistical values",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile ofile",
+    "    <operator>  infile outfile",
     "",
     "DESCRIPTION",
     "    This module computes statistical values over timesteps of the same season.",
     "    Depending on the chosen operator the minimum, maximum, sum, average, variance",
-    "    or standard deviation of timesteps of the same season is written to ofile.",
-    "    The time stamp in ofile is from the middle contributing timestep of ifile.",
+    "    or standard deviation of timesteps of the same season is written to outfile.",
+    "    The time of outfile is determined by the time in the middle of all contributing timesteps of infile.",
     "    Be careful about the first and the last output timestep, they may be incorrect values ",
     "    if the seasons have incomplete timesteps.",
     "",
     "OPERATORS",
     "    seasmin   Seasonal minimum",
-    "              For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is",
+    "              For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:",
     "              ",
     "              o(t,x) = min{i(t',x), t1 < t' <= tn}",
     "    seasmax   Seasonal maximum",
-    "              For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is",
+    "              For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:",
     "              ",
     "              o(t,x) = max{i(t',x), t1 < t' <= tn}",
     "    seassum   Seasonal sum",
-    "              For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is",
+    "              For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:",
     "              ",
     "              o(t,x) = sum{i(t',x), t1 < t' <= tn}",
     "    seasmean  Seasonal mean",
-    "              For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is",
+    "              For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:",
     "              ",
     "              o(t,x) = mean{i(t',x), t1 < t' <= tn}",
     "    seasavg   Seasonal average",
-    "              For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is",
+    "              For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:",
     "              ",
     "              o(t,x) = avg{i(t',x), t1 < t' <= tn}",
     "    seasstd   Seasonal standard deviation",
-    "              Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is",
+    "              Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:",
     "              ",
     "              o(t,x) = std{i(t',x), t1 < t' <= tn}",
     "    seasstd1  Seasonal standard deviation (n-1)",
-    "              Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is",
+    "              Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:",
     "              ",
     "              o(t,x) = std1{i(t',x), t1 < t' <= tn}",
     "    seasvar   Seasonal variance",
-    "              Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is",
+    "              Normalize by n. For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:",
     "              ",
     "              o(t,x) = var{i(t',x), t1 < t' <= tn}",
     "    seasvar1  Seasonal variance (n-1)",
-    "              Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is",
+    "              Normalize by (n-1). For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:",
     "              ",
     "              o(t,x) = var1{i(t',x), t1 < t' <= tn}",
     NULL
@@ -2772,18 +2809,18 @@ static const char *SeaspctlHelp[] = {
     "    seaspctl - Seasonal percentile values",
     "",
     "SYNOPSIS",
-    "    seaspctl,p  ifile1 ifile2 ifile3 ofile",
+    "    seaspctl,p  infile1 infile2 infile3 outfile",
     "",
     "DESCRIPTION",
-    "    This operator computes percentiles over all timesteps in ifile1 of the same season.",
-    "    The algorithm uses histograms with minimum and maximum bounds given in ifile2 and ifile3,",
-    "    respectively. The default number of histogram bins is 101. The default can be overridden by setting ",
-    "    the environment variable CDO_PCTL_NBINS to a different value. The files ifile2 and ",
-    "    ifile3 should be the result of corresponding seasmin and seasmax operations, respectively.",
-    "    The time stamp in ofile is from the middle contributing timestep of ifile1.",
+    "    This operator computes percentiles over all timesteps in infile1 of the same season.",
+    "    The algorithm uses histograms with minimum and maximum bounds given in infile2 and infile3,",
+    "    respectively. The default number of histogram bins is 101. The default can be overridden",
+    "    by defining the environment variable CDO_PCTL_NBINS. The files infile2 and infile3",
+    "    should be the result of corresponding seasmin and seasmax operations, respectively.",
+    "    The time of outfile is determined by the time in the middle of all contributing timesteps of infile1.",
     "    Be careful about the first and the last output timestep, they may be incorrect values ",
     "    if the seasons have incomplete timesteps.",
-    "    For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is",
+    "    For every adjacent sequence t_1, ...,t_n of timesteps of the same season it is:",
     "    ",
     "    o(t,x) = pth percentile {i(t',x), t1 < t' <= tn}",
     "",
@@ -2802,12 +2839,12 @@ static const char *YhourstatHelp[] = {
     "    yhourvar, yhourvar1 - Multi-year hourly statistical values",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile ofile",
+    "    <operator>  infile outfile",
     "",
     "DESCRIPTION",
     "    This module computes statistical values of each hour and day of year.",
     "    Depending on the chosen operator the minimum, maximum, sum, average, variance",
-    "    or standard deviation of each hour and day of year in ifile is written to ofile.",
+    "    or standard deviation of each hour and day of year in infile is written to outfile.",
     "    The date information in an output field is the date of the last contributing input field.",
     "",
     "OPERATORS",
@@ -2864,12 +2901,12 @@ static const char *YdaystatHelp[] = {
     "    ydayvar1 - Multi-year daily statistical values",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile ofile",
+    "    <operator>  infile outfile",
     "",
     "DESCRIPTION",
     "    This module computes statistical values of each day of year.",
     "    Depending on the chosen operator the minimum, maximum, sum, average, variance",
-    "    or standard deviation of each day of year in ifile is written to ofile.",
+    "    or standard deviation of each day of year in infile is written to outfile.",
     "    The date information in an output field is the date of the last contributing input field.",
     "",
     "OPERATORS",
@@ -2925,14 +2962,14 @@ static const char *YdaypctlHelp[] = {
     "    ydaypctl - Multi-year daily percentile values",
     "",
     "SYNOPSIS",
-    "    ydaypctl,p  ifile1 ifile2 ifile3 ofile",
+    "    ydaypctl,p  infile1 infile2 infile3 outfile",
     "",
     "DESCRIPTION",
-    "    This operator writes a certain percentile of each day of year in ifile1 to ofile.",
-    "    The algorithm uses histograms with minimum and maximum bounds given in ifile2 and",
-    "    ifile3, respectively. The default number of histogram bins is 101. The default can be",
+    "    This operator writes a certain percentile of each day of year in infile1 to outfile.",
+    "    The algorithm uses histograms with minimum and maximum bounds given in infile2 and",
+    "    infile3, respectively. The default number of histogram bins is 101. The default can be",
     "    overridden by setting the environment variable CDO_PCTL_NBINS to a different value.",
-    "    The files ifile2 and ifile3 should be the result of corresponding ydaymin and",
+    "    The files infile2 and infile3 should be the result of corresponding ydaymin and",
     "    ydaymax operations, respectively.",
     "    The date information in an output field is the date of the last contributing input field.",
     "    ",
@@ -2955,12 +2992,12 @@ static const char *YmonstatHelp[] = {
     "    ymonvar1 - Multi-year monthly statistical values",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile ofile",
+    "    <operator>  infile outfile",
     "",
     "DESCRIPTION",
     "    This module computes statistical values of each month of year.",
     "    Depending on the chosen operator the minimum, maximum, sum, average, variance",
-    "    or standard deviation of each month of year in ifile is written to ofile.",
+    "    or standard deviation of each month of year in infile is written to outfile.",
     "    The date information in an output field is the date of the last contributing input field.",
     "",
     "OPERATORS",
@@ -3016,15 +3053,15 @@ static const char *YmonpctlHelp[] = {
     "    ymonpctl - Multi-year monthly percentile values",
     "",
     "SYNOPSIS",
-    "    ymonpctl,p  ifile1 ifile2 ifile3 ofile",
+    "    ymonpctl,p  infile1 infile2 infile3 outfile",
     "",
     "DESCRIPTION",
-    "    This operator writes a certain percentile of each month of year in ifile1 to ofile.",
+    "    This operator writes a certain percentile of each month of year in infile1 to outfile.",
     "    The algorithm uses histograms with minimum and maximum bounds given in",
-    "    ifile2 and ifile3, respectively. The default number of",
+    "    infile2 and infile3, respectively. The default number of",
     "    histogram bins is 101. The default can be overridden by setting the",
     "    environment variable CDO_PCTL_NBINS to a different value. The files",
-    "    ifile2 and ifile3 should be the result of corresponding",
+    "    infile2 and infile3 should be the result of corresponding",
     "    ymonmin and ymonmax operations, respectively.",
     "    The date information in an output field is the date of the last",
     "    contributing input field.",
@@ -3048,12 +3085,12 @@ static const char *YseasstatHelp[] = {
     "    yseasvar, yseasvar1 - Multi-year seasonal statistical values",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile ofile",
+    "    <operator>  infile outfile",
     "",
     "DESCRIPTION",
     "    This module computes statistical values of each season.",
     "    Depending on the chosen operator the minimum, maximum, sum, average, variance",
-    "    or standard deviation of each season in ifile is written to ofile.",
+    "    or standard deviation of each season in infile is written to outfile.",
     "    The date information in an output field is the date of the last contributing input field.",
     "",
     "OPERATORS",
@@ -3110,15 +3147,15 @@ static const char *YseaspctlHelp[] = {
     "    yseaspctl - Multi-year seasonal percentile values",
     "",
     "SYNOPSIS",
-    "    yseaspctl,p  ifile1 ifile2 ifile3 ofile",
+    "    yseaspctl,p  infile1 infile2 infile3 outfile",
     "",
     "DESCRIPTION",
-    "    This operator writes a certain percentile of each season in ifile1 to ofile.",
+    "    This operator writes a certain percentile of each season in infile1 to outfile.",
     "    The algorithm uses histograms with minimum and maximum bounds given in",
-    "    ifile2 and ifile3, respectively. The default number of",
+    "    infile2 and infile3, respectively. The default number of",
     "    histogram bins is 101. The default can be overridden by setting the",
     "    environment variable CDO_PCTL_NBINS to a different value. The files",
-    "    ifile2 and ifile3 should be the result of corresponding",
+    "    infile2 and infile3 should be the result of corresponding",
     "    yseasmin and yseasmax operations, respectively.",
     "    The date information in an output field is the date of the last",
     "    contributing input field.",
@@ -3143,10 +3180,10 @@ static const char *YdrunstatHelp[] = {
     "    ydrunvar, ydrunvar1 - Multi-year daily running statistical values",
     "",
     "SYNOPSIS",
-    "    <operator>,nts  ifile ofile",
+    "    <operator>,nts  infile outfile",
     "",
     "DESCRIPTION",
-    "    This module writes running statistical values for each day of year in ifile to ofile.",
+    "    This module writes running statistical values for each day of year in infile to outfile.",
     "    Depending on the chosen operator, the minimum, maximum, sum, average, variance or standard deviation ",
     "    of all timesteps in running windows of which the medium timestep corresponds to a certain day of",
     "    year is computed. The date information in an output field is the date of the timestep in the middle ",
@@ -3214,16 +3251,16 @@ static const char *YdrunpctlHelp[] = {
     "    ydrunpctl - Multi-year daily running percentile values",
     "",
     "SYNOPSIS",
-    "    ydrunpctl,p,nts  ifile1 ifile2 ifile3 ofile",
+    "    ydrunpctl,p,nts  infile1 infile2 infile3 outfile",
     "",
     "DESCRIPTION",
-    "    This operator writes running percentile values for each day of year in ifile1 to ofile. ",
+    "    This operator writes running percentile values for each day of year in infile1 to outfile. ",
     "    A certain percentile is computed for all timesteps in running windows of which the medium ",
     "    timestep corresponds to a certain day of year. ",
-    "    The algorithm uses histograms with minimum and maximum bounds given in ifile2 and ifile3,",
+    "    The algorithm uses histograms with minimum and maximum bounds given in infile2 and infile3,",
     "    respectively. The default number of histogram bins is 101. The default can be overridden",
-    "    by setting the environment variable CDO_PCTL_NBINS to a different value. The files ifile2 ",
-    "    and ifile3 should be the result of corresponding ydrunmin and ydrunmax operations, respectively.",
+    "    by setting the environment variable CDO_PCTL_NBINS to a different value. The files infile2 ",
+    "    and infile3 should be the result of corresponding ydrunmin and ydrunmax operations, respectively.",
     "    The date information in an output field is the date of the timestep in the middle of the last ",
     "    contributing running window.",
     "    Note that the operator have to be applied to a continuous time series of daily measurements ",
@@ -3254,7 +3291,7 @@ static const char *FldcorHelp[] = {
     "    fldcor - Correlation in grid space",
     "",
     "SYNOPSIS",
-    "    fldcor  ifile1 ifile2 ofile",
+    "    fldcor  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
     "    The correlation coefficient is a quantity that gives the quality of a least ",
@@ -3276,7 +3313,7 @@ static const char *TimcorHelp[] = {
     "    timcor - Correlation over time",
     "",
     "SYNOPSIS",
-    "    timcor  ifile1 ifile2 ofile",
+    "    timcor  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
     "    The correlation coefficient is a quantity that gives the quality of a least ",
@@ -3297,7 +3334,7 @@ static const char *FldcovarHelp[] = {
     "    fldcovar - Covariance in grid space",
     "",
     "SYNOPSIS",
-    "    fldcovar  ifile1 ifile2 ofile",
+    "    fldcovar  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
     "    This operator calculates the covariance of two fields over all gridpoints",
@@ -3318,7 +3355,7 @@ static const char *TimcovarHelp[] = {
     "    timcovar - Covariance over time",
     "",
     "SYNOPSIS",
-    "    timcovar  ifile1 ifile2 ofile",
+    "    timcovar  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
     "    This operator calculates the covariance of two fields at each gridpoint",
@@ -3338,10 +3375,10 @@ static const char *RegresHelp[] = {
     "    regres - Regression",
     "",
     "SYNOPSIS",
-    "    regres  ifile ofile",
+    "    regres  infile outfile",
     "",
     "DESCRIPTION",
-    "    The values of the input file ifile are assumed to be distributed as",
+    "    The values of the input file infile are assumed to be distributed as",
     "    N(a+b*t,S^2) with unknown a, b and S^2. This operator estimates the",
     "    parameter b. For every field element x only those timesteps ",
     "    t belong to the sample S(x), which have i(t,x) NE miss.",
@@ -3353,10 +3390,10 @@ static const char *DetrendHelp[] = {
     "    detrend - Detrend time series",
     "",
     "SYNOPSIS",
-    "    detrend  ifile ofile",
+    "    detrend  infile outfile",
     "",
     "DESCRIPTION",
-    "    Every time series in ifile is linearly detrended. For every field element x ",
+    "    Every time series in infile is linearly detrended. For every field element x ",
     "    only those timesteps t belong to the sample S(x), which have i(t,x) NE miss.",
     "",
     "NOTE",
@@ -3370,15 +3407,15 @@ static const char *TrendHelp[] = {
     "    trend - Trend of time series",
     "",
     "SYNOPSIS",
-    "    trend  ifile ofile1 ofile2",
+    "    trend  infile outfile1 outfile2",
     "",
     "DESCRIPTION",
-    "    The values of the input file ifile are assumed to be distributed as",
+    "    The values of the input file infile are assumed to be distributed as",
     "    N(a+b*t,S^2) with unknown a, b and S^2. This operator estimates the",
     "    parameter a and b. For every field element x only those timesteps ",
     "    t belong to the sample S(x), which have i(t,x) NE miss.",
-    "    Thus the estimation for a is stored in ofile1 and that for b is stored ",
-    "    in ofile2. To subtract the trend from the data see operator subtrend.",
+    "    Thus the estimation for a is stored in outfile1 and that for b is stored ",
+    "    in outfile2. To subtract the trend from the data see operator subtrend.",
     NULL
 };
 
@@ -3387,7 +3424,7 @@ static const char *SubtrendHelp[] = {
     "    subtrend - Subtract a trend",
     "",
     "SYNOPSIS",
-    "    subtrend  ifile1 ifile2 ifile3 ofile",
+    "    subtrend  infile1 infile2 infile3 outfile",
     "",
     "DESCRIPTION",
     "    This operator is for subtracting a trend computed by the operator trend.",
@@ -3403,10 +3440,10 @@ static const char *EOFsHelp[] = {
     "    eof, eoftime, eofspatial, eof3d - Empirical Orthogonal Functions",
     "",
     "SYNOPSIS",
-    "    <operator>,neof  ifile ofile1 ofile2",
+    "    <operator>,neof  infile outfile1 outfile2",
     "",
     "DESCRIPTION",
-    "    This module calculates empirical orthogonal functions of the data in ifile ",
+    "    This module calculates empirical orthogonal functions of the data in infile ",
     "    as the eigen values of the scatter matrix (covariance matrix) S of the data",
     "    sample z(t). A more detailed description can be found above.",
     "    ",
@@ -3417,16 +3454,16 @@ static const char *EOFsHelp[] = {
     "    is faster, the module can be forced to perform a computation in time- or gridspace",
     "    by using the operators eoftime or eofspatial, respectively. This can enhance ",
     "    performance, especially for very long time series, where the number of timesteps",
-    "    is larger than the number of grid-points. Data in ifile are assumed to be anomalies.",
+    "    is larger than the number of grid-points. Data in infile are assumed to be anomalies.",
     "    If they are not, the behavior of this module is not well defined. ",
-    "    After execution ofile1 will contain all eigen-values and ofile2 the",
+    "    After execution outfile1 will contain all eigen-values and outfile2 the",
     "    eigenvectors e_j. All EOFs and eigen-values are computed. However, only the first ",
-    "    neof EOFs are written to ofile2. Nonetheless, ofile1 contains all eigen-values. ",
+    "    neof EOFs are written to outfile2. Nonetheless, outfile1 contains all eigen-values. ",
     "    ",
     "    Missing values are not fully supported. Support is only checked for non-changing",
     "    masks of missing values in time. Although there still will be results, they are",
     "    not trustworthy, and a warning will occur. In the latter case we suggest to ",
-    "    replace missing values by 0 in ifile. ",
+    "    replace missing values by 0 in infile. ",
     "",
     "OPERATORS",
     "    eof         Calculate EOFs in spatial or time space",
@@ -3461,19 +3498,19 @@ static const char *EofcoeffHelp[] = {
     "    eofcoeff - Principal coefficients of EOFs",
     "",
     "SYNOPSIS",
-    "    eofcoeff  ifile1 ifile2 obase",
+    "    eofcoeff  infile1 infile2 obase",
     "",
     "DESCRIPTION",
     "    This module calculates the time series of the principal coefficients for given EOF",
-    "    (empirical orthogonal functions) and data. Time steps in ifile1 are assumed to be the EOFs,",
-    "    time steps in ifile2 are assumed to be the time series.",
-    "    Note, that this operator calculates a weighted dot product of the fields in ifile1 and ifile2.",
+    "    (empirical orthogonal functions) and data. Time steps in infile1 are assumed to be the EOFs,",
+    "    time steps in infile2 are assumed to be the time series.",
+    "    Note, that this operator calculates a non weighted dot product of the fields in infile1 and infile2.",
     "    For consistency set the environment variable CDO_WEIGHT_MODE=off when using eof or eof3d.",
     "    ",
     "    There will be a separate file containing a time series of principal coefficients",
-    "    with time information from ifile2 for each EOF in ifile1. Output files will be",
+    "    with time information from infile2 for each EOF in infile1. Output files will be",
     "    numbered as <obase><neof><suffix> where neof+1 is the number of the EOF (timestep)",
-    "    in ifile1 and suffix is the filename extension derived from the file format. ",
+    "    in infile1 and suffix is the filename extension derived from the file format. ",
     "",
     "ENVIRONMENT",
     "    CDO_FILE_SUFFIX",
@@ -3488,7 +3525,7 @@ static const char *RemapbilHelp[] = {
     "    remapbil, genbil - Bilinear interpolation",
     "",
     "SYNOPSIS",
-    "    <operator>,grid  ifile ofile",
+    "    <operator>,grid  infile outfile",
     "",
     "DESCRIPTION",
     "    This module contains operators for a bilinear remapping of fields between grids in spherical coordinates.",
@@ -3519,7 +3556,7 @@ static const char *RemapbicHelp[] = {
     "    remapbic, genbic - Bicubic interpolation",
     "",
     "SYNOPSIS",
-    "    <operator>,grid  ifile ofile",
+    "    <operator>,grid  infile outfile",
     "",
     "DESCRIPTION",
     "    This module contains operators for a bicubic remapping of fields between grids in spherical coordinates.",
@@ -3550,7 +3587,7 @@ static const char *RemapnnHelp[] = {
     "    remapnn, gennn - Nearest neighbor remapping",
     "",
     "SYNOPSIS",
-    "    <operator>,grid  ifile ofile",
+    "    <operator>,grid  infile outfile",
     "",
     "DESCRIPTION",
     "    This module contains operators for a nearest neighbor remapping of fields between grids",
@@ -3581,8 +3618,8 @@ static const char *RemapdisHelp[] = {
     "    remapdis, gendis - Distance-weighted average remapping",
     "",
     "SYNOPSIS",
-    "    remapdis,grid[,neighbors]  ifile ofile",
-    "    gendis,grid  ifile ofile",
+    "    remapdis,grid[,neighbors]  infile outfile",
+    "    gendis,grid  infile outfile",
     "",
     "DESCRIPTION",
     "    This module contains operators for a distance-weighted average remapping of the four",
@@ -3618,7 +3655,7 @@ static const char *RemapyconHelp[] = {
     "    remapycon, genycon - First order conservative remapping",
     "",
     "SYNOPSIS",
-    "    <operator>,grid  ifile ofile",
+    "    <operator>,grid  infile outfile",
     "",
     "DESCRIPTION",
     "    This module contains operators for a first order conservative remapping of fields between grids in spherical coordinates.",
@@ -3657,7 +3694,7 @@ static const char *RemapconHelp[] = {
     "    remapcon, gencon - First order conservative remapping",
     "",
     "SYNOPSIS",
-    "    <operator>,grid  ifile ofile",
+    "    <operator>,grid  infile outfile",
     "",
     "DESCRIPTION",
     "    This module contains operators for a first order conservative remapping of fields between grids in spherical coordinates.",
@@ -3700,7 +3737,7 @@ static const char *Remapcon2Help[] = {
     "    remapcon2, gencon2 - Second order conservative remapping",
     "",
     "SYNOPSIS",
-    "    <operator>,grid  ifile ofile",
+    "    <operator>,grid  infile outfile",
     "",
     "DESCRIPTION",
     "    This module contains operators for a second order conservative remapping of fields between grids in spherical coordinates.",
@@ -3742,7 +3779,7 @@ static const char *RemaplafHelp[] = {
     "    remaplaf, genlaf - Largest area fraction remapping",
     "",
     "SYNOPSIS",
-    "    <operator>,grid  ifile ofile",
+    "    <operator>,grid  infile outfile",
     "",
     "DESCRIPTION",
     "    This module contains operators for a largest area fraction remapping of fields between grids in spherical coordinates.",
@@ -3774,7 +3811,7 @@ static const char *RemapHelp[] = {
     "    remap - Grid remapping",
     "",
     "SYNOPSIS",
-    "    remap,grid,weights  ifile ofile",
+    "    remap,grid,weights  infile outfile",
     "",
     "DESCRIPTION",
     "    Interpolation between different horizontal grids can be a very time-consuming ",
@@ -3816,7 +3853,7 @@ static const char *RemapetaHelp[] = {
     "    remapeta - Remap vertical hybrid level",
     "",
     "SYNOPSIS",
-    "    remapeta,vct[,oro]  ifile ofile",
+    "    remapeta,vct[,oro]  infile outfile",
     "",
     "DESCRIPTION",
     "    This operator interpolates between different vertical hybrid levels. This include the preparation ",
@@ -3826,9 +3863,9 @@ static const char *RemapetaHelp[] = {
     "    few adjustments. The basic tasks are the following one:",
     "    - at first integration of hydrostatic equation",
     "    - extrapolation of surface pressure",
-    "    - Planetary Boundary-Layer (PBL) profile interpolation",
+    "    - Planetary Boundary-Layer (PBL) proutfile interpolation",
     "    - interpolation in free atmosphere",
-    "    - merging of both profiles",
+    "    - merging of both proutfiles",
     "    - final surface pressure correction",
     "    ",
     "    The vertical interpolation corrects the surface pressure. This is simply a cut-off or an addition ",
@@ -3837,7 +3874,7 @@ static const char *RemapetaHelp[] = {
     "    the geopotential height of the 400 hPa level is used. Near the surface the correction can affect ",
     "    the vertical structure of the PBL. Therefore the interpolation is done using the potential temperature. ",
     "    But in the free atmosphere above a certain n (n=0.8 defining the top of the PBL) the interpolation ",
-    "    is done linearly. After the interpolation both profiles are merged. With the resulting ",
+    "    is done linearly. After the interpolation both proutfiles are merged. With the resulting ",
     "    temperature/pressure correction the hydrostatic equation is integrated again and adjusted to the ",
     "    reference level finding the final surface pressure correction. A more detailed description of",
     "    the interpolation can be found in INTERA. This operator requires all variables on the same horizontal grid.",
@@ -3875,13 +3912,13 @@ static const char *VertintmlHelp[] = {
     "    ml2pl, ml2hl - Vertical interpolation",
     "",
     "SYNOPSIS",
-    "    ml2pl,plevels  ifile ofile",
-    "    ml2hl,hlevels  ifile ofile",
+    "    ml2pl,plevels  infile outfile",
+    "    ml2hl,hlevels  infile outfile",
     "",
     "DESCRIPTION",
     "    Interpolate 3D variables on hybrid sigma pressure level to pressure or height levels.",
     "    The input file should contain the log. surface pressure or the surface pressure.",
-    "    To interpolate the temperature, the surface geopotential is also needed.",
+    "    To extrapolate the temperature, the surface geopotential is also needed.",
     "    The pressure, temperature, and surface geopotential are identified by their GRIB1 code number",
     "    or NetCDF CF standard name.",
     "    Supported parameter tables are: WMO standard table number 2 and ECMWF local table number 128.",
@@ -3913,8 +3950,8 @@ static const char *VertintapHelp[] = {
     "    ap2pl, ap2hl - Vertical interpolation",
     "",
     "SYNOPSIS",
-    "    ap2pl,plevels  ifile ofile",
-    "    ap2hl,hlevels  ifile ofile",
+    "    ap2pl,plevels  infile outfile",
+    "    ap2hl,hlevels  infile outfile",
     "",
     "DESCRIPTION",
     "    Interpolate 3D variables on hybrid sigma height coordinates to pressure or height levels.",
@@ -3950,7 +3987,7 @@ static const char *IntlevelHelp[] = {
     "    intlevel - Linear level interpolation",
     "",
     "SYNOPSIS",
-    "    intlevel,levels  ifile ofile",
+    "    intlevel,levels  infile outfile",
     "",
     "DESCRIPTION",
     "    This operator performs a linear vertical interpolation of non hybrid 3D variables.",
@@ -3966,7 +4003,7 @@ static const char *Intlevel3dHelp[] = {
     "    Linear level interpolation from/to 3d vertical coordinates",
     "",
     "SYNOPSIS",
-    "    <operator>,icoordinate  ifile1 ifile2 ofile",
+    "    <operator>,icoordinate  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
     "    This operator performs a linear vertical interpolation of 3D variables fields",
@@ -3978,7 +4015,7 @@ static const char *Intlevel3dHelp[] = {
     "",
     "PARAMETER",
     "    icoordinate  STRING  filename for vertical source coordinates variable",
-    "    ifile2       STRING  target vertical coordinate field (intlevel3d only)",
+    "    infile2      STRING  target vertical coordinate field (intlevel3d only)",
     NULL
 };
 
@@ -3987,8 +4024,8 @@ static const char *InttimeHelp[] = {
     "    inttime, intntime - Time interpolation",
     "",
     "SYNOPSIS",
-    "    inttime,date,time[,inc]  ifile ofile",
-    "    intntime,n  ifile ofile",
+    "    inttime,date,time[,inc]  infile outfile",
+    "    intntime,n  infile outfile",
     "",
     "DESCRIPTION",
     "    This module performs linear interpolation between timesteps.",
@@ -4014,7 +4051,7 @@ static const char *IntyearHelp[] = {
     "    intyear - Year interpolation",
     "",
     "SYNOPSIS",
-    "    intyear,years  ifile1 ifile2 obase",
+    "    intyear,years  infile1 infile2 obase",
     "",
     "DESCRIPTION",
     "    This operator performs linear interpolation between two years, timestep by timestep.",
@@ -4042,8 +4079,8 @@ static const char *SpectralHelp[] = {
     "    sp2gp, sp2gpl, gp2sp, gp2spl, sp2sp - Spectral transformation",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile ofile",
-    "    sp2sp,trunc  ifile ofile",
+    "    <operator>  infile outfile",
+    "    sp2sp,trunc  infile outfile",
     "",
     "DESCRIPTION",
     "    This module transforms fields on Gaussian grids to spectral coefficients and vice versa.",
@@ -4087,7 +4124,7 @@ static const char *WindHelp[] = {
     "    dv2uv, dv2uvl, uv2dv, uv2dvl, dv2ps - Wind transformation",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile ofile",
+    "    <operator>  infile outfile",
     "",
     "DESCRIPTION",
     "    This module converts relative divergence and vorticity to U and V wind and vice versa.",
@@ -4107,7 +4144,7 @@ static const char *WindHelp[] = {
     "    dv2uvl  Divergence and vorticity to U and V wind (linear)",
     "            Calculate U and V wind on a Gaussian grid from spherical harmonic ",
     "            coefficients of relative divergence and vorticity. The divergence and vorticity ",
-    "            need tohave the names sd and svo or code numbers 155 and 138.",
+    "            need to have the names sd and svo or code numbers 155 and 138.",
     "            The number of latitudes of the resulting Gaussian grid is calculated ",
     "            from the triangular truncation by:",
     "            ",
@@ -4140,7 +4177,7 @@ static const char *ImportbinaryHelp[] = {
     "    import_binary - Import binary data sets",
     "",
     "SYNOPSIS",
-    "    import_binary  ifile ofile",
+    "    import_binary  infile outfile",
     "",
     "DESCRIPTION",
     "    This operator imports gridded binary data sets via a GrADS data descriptor file.",
@@ -4168,7 +4205,7 @@ static const char *ImportcmsafHelp[] = {
     "    import_cmsaf - Import CM-SAF HDF5 files",
     "",
     "SYNOPSIS",
-    "    import_cmsaf  ifile ofile",
+    "    import_cmsaf  infile outfile",
     "",
     "DESCRIPTION",
     "    This operator imports gridded CM-SAF (Satellite Application Facility on Climate Monitoring)",
@@ -4217,7 +4254,7 @@ static const char *ImportamsrHelp[] = {
     "    import_amsr - Import AMSR binary files",
     "",
     "SYNOPSIS",
-    "    import_amsr  ifile ofile",
+    "    import_amsr  infile outfile",
     "",
     "DESCRIPTION",
     "    This operator imports gridded binary AMSR (Advanced Microwave Scanning Radiometer) data.",
@@ -4237,9 +4274,9 @@ static const char *InputHelp[] = {
     "    input, inputsrv, inputext - Formatted input",
     "",
     "SYNOPSIS",
-    "    input,grid[,zaxis]  ofile",
-    "    inputsrv  ofile",
-    "    inputext  ofile",
+    "    input,grid[,zaxis]  outfile",
+    "    inputsrv  outfile",
+    "    inputext  outfile",
     "",
     "DESCRIPTION",
     "    This module reads time series of one 2D variable from standard input.",
@@ -4249,16 +4286,16 @@ static const char *InputHelp[] = {
     "OPERATORS",
     "    input     ASCII input",
     "              Reads fields with ASCII numbers from standard input and stores them",
-    "              in ofile. The numbers read are exactly that ones which are written ",
+    "              in outfile. The numbers read are exactly that ones which are written ",
     "              out by the output operator.",
     "    inputsrv  SERVICE ASCII input",
     "              Reads fields with ASCII numbers from standard input and stores them ",
-    "              in ofile. Each field should have a header of 8 integers (SERVICE likely).",
+    "              in outfile. Each field should have a header of 8 integers (SERVICE likely).",
     "              The numbers that are read are exactly that ones which are written out by ",
     "              the outputsrv operator.",
     "    inputext  EXTRA ASCII input",
     "              Read fields with ASCII numbers from standard input and stores them ",
-    "              in ofile. Each field should have header of 4 integers (EXTRA likely).",
+    "              in outfile. Each field should have header of 4 integers (EXTRA likely).",
     "              The numbers read are exactly that ones which are written out by ",
     "              the outputext operator.",
     "",
@@ -4273,11 +4310,11 @@ static const char *OutputHelp[] = {
     "    output, outputf, outputint, outputsrv, outputext - Formatted output",
     "",
     "SYNOPSIS",
-    "    output  ifiles",
-    "    outputf,format[,nelem]  ifiles",
-    "    outputint  ifiles",
-    "    outputsrv  ifiles",
-    "    outputext  ifiles",
+    "    output  infiles",
+    "    outputf,format[,nelem]  infiles",
+    "    outputint  infiles",
+    "    outputsrv  infiles",
+    "    outputext  infiles",
     "",
     "DESCRIPTION",
     "    This module prints all values of all input datasets to standard output.",
@@ -4313,11 +4350,11 @@ static const char *OutputtabHelp[] = {
     "    outputtab - Table output",
     "",
     "SYNOPSIS",
-    "    outputtab,params  ifiles ofile",
+    "    outputtab,params  infiles outfile",
     "",
     "DESCRIPTION",
     "    This operator prints a table of all input datasets to standard output.",
-    "    ifiles is an arbitrary number of input files. All input files need to have ",
+    "    infiles is an arbitrary number of input files. All input files need to have ",
     "    the same structure with the same variables on different timesteps.",
     "    All input fields need to have the same horizontal grid.",
     "    ",
@@ -4353,7 +4390,7 @@ static const char *OutputgmtHelp[] = {
     "    gmtxyz, gmtcells - GMT output",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile",
+    "    <operator>  infile",
     "",
     "DESCRIPTION",
     "    This module prints the first field of the input dataset to standard output.",
@@ -4375,13 +4412,13 @@ static const char *GradsdesHelp[] = {
     "    gradsdes - GrADS data descriptor file",
     "",
     "SYNOPSIS",
-    "    gradsdes[,mapversion]  ifile",
+    "    gradsdes[,mapversion]  infile",
     "",
     "DESCRIPTION",
     "    Creates a GrADS data descriptor file. Supported file formats are GRIB1, NetCDF, SERVICE, ",
     "    EXTRA and IEG. For GRIB1 files the GrADS map file is also generated. For SERVICE and EXTRA",
-    "    files the grid have to be specified with the CDO option '-g <grid>'. This module takes ifile",
-    "    in order to create filenames for the descriptor (ifile.ctl) and the map (ifile.gmp) file.",
+    "    files the grid have to be specified with the CDO option '-g <grid>'. This module takes infile",
+    "    in order to create filenames for the descriptor (infile.ctl) and the map (infile.gmp) file.",
     "",
     "PARAMETER",
     "    mapversion  INTEGER  Format version of the GrADS map file for GRIB1 datasets. Use 1 for a machine",
@@ -4398,7 +4435,7 @@ static const char *AfterburnerHelp[] = {
     "    after - ECHAM standard post processor",
     "",
     "SYNOPSIS",
-    "    after[,vct]  ifiles ofile",
+    "    after[,vct]  infiles outfile",
     "",
     "DESCRIPTION",
     "    The \"afterburner\" is the standard post processor for ECHAM data which provides the following operations:",
@@ -4440,24 +4477,24 @@ static const char *AfterburnerHelp[] = {
     "    CODE selects the variables by the ECHAM GRIB1 code number (1-255). The default value -1 processes all detected codes.",
     "    Derived variables computed by the afterburner:",
     "    ",
-    "    Code  & Name      & Longname                       & Level       & Needed Codes/Computation",
-    "     34   & low_cld   & low cloud                      & single      & 223 on modellevel  ",
-    "     35   & mid_cld   & mid cloud                      & single      & 223 on modellevel  ",
-    "     36   & hih_cld   & high cloud                     & single      & 223 on modellevel  ",
-    "     131  & u         & u-velocity                     & atm (ml+pl) & 138, 155           ",
-    "     132  & v         & v-velocity                     & atm (ml+pl) & 138, 155           ",
-    "     135  & omega     & vertical velocity              & atm (ml+pl) & 138, 152, 155      ",
-    "     148  & stream    & streamfunction                 & atm (ml+pl) & 131, 132           ",
-    "     149  & velopot   & velocity potential             & atm (ml+pl) & 131, 132           ",
-    "     151  & slp       & mean sea level pressure        & surface     & 129, 130, 152       ",
-    "     156  & geopoth   & geopotential height            & atm (ml+pl) & 129, 130, 133, 152 ",
-    "     157  & rhumidity & relative humidity              & atm (ml+pl) & 130, 133, 152      ",
-    "     189  & sclfs     & surface solar cloud forcing    & surface     & 176-185            ",
-    "     190  & tclfs     & surface thermal cloud forcing  & surface     & 177-186            ",
-    "     191  & sclf0     & top solar cloud forcing        & surface     & 178-187             ",
-    "     192  & tclf0     & top thermal cloud forcing      & surface     & 179-188            ",
-    "     259  & windspeed & windspeed                      & atm (ml+pl) & sqrt(u*u+v*v)      ",
-    "     260  & precip    & total precipitation            & surface     & 142+143            ",
+    "    Code  & Name      & Longname                       & Units & Level       & Needed Codes",
+    "     34   & low_cld   & low cloud                      &       & single      & 223 on modellevel  ",
+    "     35   & mid_cld   & mid cloud                      &       & single      & 223 on modellevel  ",
+    "     36   & hih_cld   & high cloud                     &       & single      & 223 on modellevel  ",
+    "     131  & u         & u-velocity                     & m/s   & atm (ml+pl) & 138, 155           ",
+    "     132  & v         & v-velocity                     & m/s   & atm (ml+pl) & 138, 155           ",
+    "     135  & omega     & vertical velocity              & Pa/s  & atm (ml+pl) & 138, 152, 155      ",
+    "     148  & stream    & streamfunction                 & m^2/s & atm (ml+pl) & 131, 132           ",
+    "     149  & velopot   & velocity potential             & m^2/s & atm (ml+pl) & 131, 132           ",
+    "     151  & slp       & mean sea level pressure        & Pa    & surface     & 129, 130, 152       ",
+    "     156  & geopoth   & geopotential height            & m     & atm (ml+pl) & 129, 130, 133, 152 ",
+    "     157  & rhumidity & relative humidity              &       & atm (ml+pl) & 130, 133, 152      ",
+    "     189  & sclfs     & surface solar cloud forcing    &       & surface     & 176-185            ",
+    "     190  & tclfs     & surface thermal cloud forcing  &       & surface     & 177-186            ",
+    "     191  & sclf0     & top solar cloud forcing        &       & surface     & 178-187             ",
+    "     192  & tclf0     & top thermal cloud forcing      &       & surface     & 179-188            ",
+    "     259  & windspeed & windspeed                      & m/s   & atm (ml+pl) & sqrt(u*u+v*v)      ",
+    "     260  & precip    & total precipitation            &       & surface     & 142+143            ",
     "    ",
     "    LEVEL selects the hybrid or pressure levels. The allowed values depends on the parameter TYPE.",
     "    The default value -1 processes all detected levels.",
@@ -4494,29 +4531,29 @@ static const char *FilterHelp[] = {
     "    bandpass, lowpass, highpass - Time series filtering",
     "",
     "SYNOPSIS",
-    "    bandpass,fmin,fmax  ifile ofile",
-    "    lowpass,fmax  ifile ofile",
-    "    highpass,fmin  ifile ofile",
+    "    bandpass,fmin,fmax  infile outfile",
+    "    lowpass,fmax  infile outfile",
+    "    highpass,fmin  infile outfile",
     "",
     "DESCRIPTION",
-    "    This module takes the time series for each gridpoint in ifile and (fast fourier) transforms it ",
+    "    This module takes the time series for each gridpoint in infile and (fast fourier) transforms it ",
     "    into the frequency domain. According to the particular operator and its parameters certain frequencies ",
     "    are filtered (set to zero) in the frequency domain and the spectrum is (inverse fast fourier) transformed ",
     "    back into the time domain.",
-    "    To determine the frequency the time-axis of ifile is used. (Data should have a constant time increment ",
+    "    To determine the frequency the time-axis of infile is used. (Data should have a constant time increment ",
     "    since this assumption applies for transformation. However, the time increment has to be different from zero.)",
     "    All frequencies given as parameter are interpreted per year. This is done by the assumption of a 365-day calendar. ",
     "    Consequently if you want to perform multiyear-filtering accurately you have to delete the 29th of February. ",
-    "    If your ifile has a 360 year calendar the frequency parameters fmin respectively fmax should be ",
+    "    If your infile has a 360 year calendar the frequency parameters fmin respectively fmax should be ",
     "    multiplied with a factor of 360/365 in order to obtain accurate results.  ",
     "    For the set up of a frequency filter the frequency parameters have to be adjusted to a frequency in the data. ",
     "    Here fmin is rounded down and fmax is always rounded up. Consequently it is possible to use bandpass with ",
-    "    fmin=fmax without getting a zero-field for ofile. ",
+    "    fmin=fmax without getting a zero-field for outfile. ",
     "    Hints for efficient usage: ",
     "    - to get reliable results the time-series has to be detrended (cdo detrend)",
-    "    - the lowest frequency greater zero that can be contained in ifile is 1/(N*dT), ",
+    "    - the lowest frequency greater zero that can be contained in infile is 1/(N*dT), ",
     "    - the greatest frequency is 1/(2dT) (Nyquist frequency),",
-    "    with N the number of timesteps and dT the time increment of ifile in years. ",
+    "    with N the number of timesteps and dT the time increment of infile in years. ",
     "",
     "OPERATORS",
     "    bandpass  Bandpass filtering",
@@ -4532,6 +4569,9 @@ static const char *FilterHelp[] = {
     "PARAMETER",
     "    fmin  FLOAT	Minimum frequency per year that passes the filter.",
     "    fmax  FLOAT	Maximum frequency per year that passes the filter.  ",
+    "",
+    "NOTE",
+    "    For better performace of these operators use the CDO configure option --with-fftw3.",
     NULL
 };
 
@@ -4540,7 +4580,7 @@ static const char *GridcellHelp[] = {
     "    gridarea, gridweights - Grid cell quantities",
     "",
     "SYNOPSIS",
-    "    <operator>  ifile ofile",
+    "    <operator>  infile outfile",
     "",
     "DESCRIPTION",
     "    This module reads the grid cell area of the first grid from the input stream.",
@@ -4567,8 +4607,8 @@ static const char *SmoothHelp[] = {
     "    smooth, smooth9 - Smooth grid points",
     "",
     "SYNOPSIS",
-    "    smooth[,options]  ifile ofile",
-    "    smooth9  ifile ofile",
+    "    smooth[,options]  infile outfile",
+    "    smooth9  infile outfile",
     "",
     "DESCRIPTION",
     "    Smooth all grid points of a horizontal grid.",
@@ -4609,9 +4649,9 @@ static const char *ReplacevaluesHelp[] = {
     "    setvals, setrtoc, setrtoc2 - Replace variable values",
     "",
     "SYNOPSIS",
-    "    setvals,oldval,newval[,...]  ifile ofile",
-    "    setrtoc,rmin,rmax,c  ifile ofile",
-    "    setrtoc2,rmin,rmax,c,c2  ifile ofile",
+    "    setvals,oldval,newval[,...]  infile outfile",
+    "    setrtoc,rmin,rmax,c  infile outfile",
+    "    setrtoc2,rmin,rmax,c,c2  infile outfile",
     "",
     "DESCRIPTION",
     "    This module replaces old variable values with new values, depending on the operator.",
@@ -4642,7 +4682,7 @@ static const char *TimsortHelp[] = {
     "    timsort - Timsort",
     "",
     "SYNOPSIS",
-    "    timsort  ifile ofile",
+    "    timsort  infile outfile",
     "",
     "DESCRIPTION",
     "    Sorts the elements in ascending order over all timesteps for every field position.",
@@ -4657,11 +4697,11 @@ static const char *VargenHelp[] = {
     "    const, random, topo, for, stdatm - Generate a field",
     "",
     "SYNOPSIS",
-    "    const,const,grid  ofile",
-    "    random,grid[,seed]  ofile",
-    "    topo[,grid]  ofile",
-    "    for,start,end[,inc]  ofile",
-    "    stdatm,levels  ofile",
+    "    const,const,grid  outfile",
+    "    random,grid[,seed]  outfile",
+    "    topo[,grid]  outfile",
+    "    for,start,end[,inc]  outfile",
+    "    stdatm,levels  outfile",
     "",
     "DESCRIPTION",
     "    Generates a dataset with one or more fields",
@@ -4713,7 +4753,7 @@ static const char *RotuvbHelp[] = {
     "    rotuvb - Rotation",
     "",
     "SYNOPSIS",
-    "    rotuvb,u,v,...  ifile ofile",
+    "    rotuvb,u,v,...  infile outfile",
     "",
     "DESCRIPTION",
     "    This is a special operator for datsets with wind components on a rotated grid, ",
@@ -4730,7 +4770,7 @@ static const char *MastrfuHelp[] = {
     "    mastrfu - Mass stream function",
     "",
     "SYNOPSIS",
-    "    mastrfu  ifile ofile",
+    "    mastrfu  infile outfile",
     "",
     "DESCRIPTION",
     "    This is a special operator for the post processing of the atmospheric general circulation",
@@ -4744,7 +4784,7 @@ static const char *DeriveparHelp[] = {
     "    sealevelpressure - Sea level pressure",
     "",
     "SYNOPSIS",
-    "    sealevelpressure  ifile ofile",
+    "    sealevelpressure  infile outfile",
     "",
     "DESCRIPTION",
     "    This operator computes the sea level pressure (air_pressure_at_sea_level). Required input fields",
@@ -4757,8 +4797,8 @@ static const char *AdisitHelp[] = {
     "    adisit, adipot - Potential temperature to in-situ temperature and vice versa",
     "",
     "SYNOPSIS",
-    "    adisit[,pressure]  ifile ofile",
-    "    adipot  ifile ofile",
+    "    adisit[,pressure]  infile outfile",
+    "    adipot  infile outfile",
     "",
     "DESCRIPTION",
     "",
@@ -4788,7 +4828,7 @@ static const char *RhopotHelp[] = {
     "    rhopot - Calculates potential density",
     "",
     "SYNOPSIS",
-    "    rhopot[,pressure]  ifile ofile",
+    "    rhopot[,pressure]  infile outfile",
     "",
     "DESCRIPTION",
     "    This is a special operator for the post processing of the ocean and sea ice model MPIOM.",
@@ -4806,7 +4846,7 @@ static const char *HistogramHelp[] = {
     "    histcount, histsum, histmean, histfreq - Histogram",
     "",
     "SYNOPSIS",
-    "    <operator>,bounds  ifile ofile",
+    "    <operator>,bounds  infile outfile",
     "",
     "DESCRIPTION",
     "    This module creates bins for a histogram of the input data.",
@@ -4838,7 +4878,7 @@ static const char *SethaloHelp[] = {
     "    sethalo - Set the left and right bounds of a field",
     "",
     "SYNOPSIS",
-    "    sethalo,lhalo,rhalo  ifile ofile",
+    "    sethalo,lhalo,rhalo  infile outfile",
     "",
     "DESCRIPTION",
     "    This operator sets the left and right bounds of the rectangularly understood fields.",
@@ -4858,15 +4898,15 @@ static const char *WctHelp[] = {
     "    wct - Windchill temperature",
     "",
     "SYNOPSIS",
-    "    wct  ifile1 ifile2 ofile",
+    "    wct  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile1 and ifile2 be time series of temperature and wind",
+    "    Let infile1 and infile2 be time series of temperature and wind",
     "    speed records, then a corresponding time series of resulting windchill",
-    "    temperatures is written to ofile. The wind chill temperature",
+    "    temperatures is written to outfile. The wind chill temperature",
     "    calculation is only valid for a temperature of T <= 33 °C and a wind speed",
     "    of v >= 1.39 m/s. Whenever these conditions are not satisfied, a missing",
-    "    value is written to ofile. Note that temperature and wind speed records",
+    "    value is written to outfile. Note that temperature and wind speed records",
     "    have to be given in units of °C and m/s, respectively.",
     NULL
 };
@@ -4876,16 +4916,16 @@ static const char *FdnsHelp[] = {
     "    fdns - Frost days where no snow index per time period",
     "",
     "SYNOPSIS",
-    "    fdns  ifile1 ifile2 ofile",
+    "    fdns  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile1 be a time series of the daily minimum temperature TN",
-    "    and ifile2 be a corresponding series of daily surface snow",
+    "    Let infile1 be a time series of the daily minimum temperature TN",
+    "    and infile2 be a corresponding series of daily surface snow",
     "    amounts. Then the number of days where TN < 0 °C and the surface ",
     "    snow amount is less than 1 cm is counted. The temperature TN",
     "    have to be given in units of Kelvin.",
-    "    The date information of a timestep in ofile is the date of",
-    "    the last contributing timestep in ifile.",
+    "    The date information of a timestep in outfile is the date of",
+    "    the last contributing timestep in infile.",
     NULL
 };
 
@@ -4894,18 +4934,18 @@ static const char *StrwinHelp[] = {
     "    strwin - Strong wind days index per time period",
     "",
     "SYNOPSIS",
-    "    strwin[,v]  ifile ofile",
+    "    strwin[,v]  infile outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile be a time series of the daily maximum horizontal wind speed",
+    "    Let infile be a time series of the daily maximum horizontal wind speed",
     "    VX, then the number of days where VX > v is counted. The horizontal wind",
     "    speed v is an optional parameter with default v = 10.5 m/s. A further",
     "    output variable is the maximum number of consecutive days with maximum wind",
     "    speed greater than or equal to v. Note that both VX and v have to be given in",
     "    units of m/s. Also note that the horizontal wind speed is defined as the",
     "    square root of the sum of squares of the zonal and meridional wind speeds.",
-    "    The date information of a timestep in ofile is the date of",
-    "    the last contributing timestep in ifile.",
+    "    The date information of a timestep in outfile is the date of",
+    "    the last contributing timestep in infile.",
     "",
     "PARAMETER",
     "    v  FLOAT   Horizontal wind speed threshold (m/s, default v = 10.5 m/s)",
@@ -4917,17 +4957,17 @@ static const char *StrbreHelp[] = {
     "    strbre - Strong breeze days index per time period",
     "",
     "SYNOPSIS",
-    "    strbre  ifile ofile",
+    "    strbre  infile outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile be a time series of the daily maximum horizontal wind speed",
+    "    Let infile be a time series of the daily maximum horizontal wind speed",
     "    VX, then the number of days where VX is greater than or equal to 10.5 m/s ",
     "    is counted. A further output variable is the maximum number of consecutive",
     "    days with maximum wind speed greater than or equal to 10.5 m/s. Note that",
     "    VX is defined as the square root of the sum of squares of the zonal and",
     "    meridional wind speeds and have to be given in units of m/s.",
-    "    The date information of a timestep in ofile is the date of",
-    "    the last contributing timestep in ifile.",
+    "    The date information of a timestep in outfile is the date of",
+    "    the last contributing timestep in infile.",
     NULL
 };
 
@@ -4936,17 +4976,17 @@ static const char *StrgalHelp[] = {
     "    strgal - Strong gale days index per time period",
     "",
     "SYNOPSIS",
-    "    strgal  ifile ofile",
+    "    strgal  infile outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile be a time series of the daily maximum horizontal wind speed",
+    "    Let infile be a time series of the daily maximum horizontal wind speed",
     "    VX, then the number of days where VX is greater than or equal to 20.5 m/s ",
     "    is counted. A further output variable is the maximum number of consecutive",
     "    days with maximum wind speed greater than or equal to 20.5 m/s. Note that",
     "    VX is defined as the square root of the sum of square of the zonal and",
     "    meridional wind speeds and have to be given in units of m/s.",
-    "    The date information of a timestep in ofile is the date of",
-    "    the last contributing timestep in ifile.",
+    "    The date information of a timestep in outfile is the date of",
+    "    the last contributing timestep in infile.",
     NULL
 };
 
@@ -4955,17 +4995,66 @@ static const char *HurrHelp[] = {
     "    hurr - Hurricane days index per time period",
     "",
     "SYNOPSIS",
-    "    hurr  ifile ofile",
+    "    hurr  infile outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile be a time series of the daily maximum horizontal wind speed",
+    "    Let infile be a time series of the daily maximum horizontal wind speed",
     "    VX, then the number of days where VX is greater than or equal to 32.5 m/s",
     "    is counted. A further output variable is the maximum number of consecutive",
     "    days with maximum wind speed greater than or equal to 32.5 m/s. Note that",
     "    VX is defined as the square root of the sum of squares of the zonal and",
     "    meridional wind speeds and have to be given in units of m/s.",
-    "    The date information of a timestep in ofile is the date of",
-    "    the last contributing timestep in ifile.",
+    "    The date information of a timestep in outfile is the date of",
+    "    the last contributing timestep in infile.",
+    NULL
+};
+
+static const char *CMORliteHelp[] = {
+    "NAME",
+    "    cmorlite - CMOR lite",
+    "",
+    "SYNOPSIS",
+    "    cmorlite,table[,convert]  infile outfile",
+    "",
+    "DESCRIPTION",
+    "    The CMOR (Climate Model Output Rewriter) library comprises a set of",
+    "    functions, that can be used to produce CF-compliant NetCDF files that ",
+    "    fulfill the requirements of many of the climate community's standard",
+    "    model experiments. These experiments are collectively referred to as",
+    "    MIP's. Much of the metadata written to the output files is defined in",
+    "    MIP-specific tables, typically made available from each MIP's web site.",
+    "    ",
+    "    The CDO operator cmorlite process the header and variable section",
+    "    of such MIP tables and writes the result with the internal IO library CDI.",
+    "    In addition to the CMOR 2 and 3 table format, the CDO parameter table format",
+    "    is also supported. The following parameter table entries are available:",
+    "    ",
+    "     Entry           & Type        & Description      ",
+    "     name            & WORD        & Name of the variable",
+    "     out_name        & WORD        & New name of the variable",
+    "     type            & WORD        & Data type (real or double)",
+    "     standard_name   & WORD        & As defined in the CF standard name table",
+    "     long_name       & STRING      & Describing the variable",
+    "     units           & STRING      & Specifying the units for the variable",
+    "     comment         & STRING      & Information concerning the variable",
+    "     cell_methods    & STRING      & Information concerning calculation of means or climatologies",
+    "     cell_measures   & STRING      & Indicates the names of the variables containing cell areas and volumes",
+    "     missing_value   & FLOAT       & Specifying how missing data will be identified",
+    "     valid_min       & FLOAT       & Minimum valid value",
+    "     valid_max       & FLOAT       & Maximum valid value",
+    "     ok_min_mean_abs & FLOAT       & Minimum absolute mean",
+    "     ok_max_mean_abs & FLOAT       & Maximum absolute mean",
+    "     factor          & FLOAT       & Scale factor",
+    "     delete          & INTEGER     & Set to 1 to delete variable",
+    "     convert         & INTEGER     & Set to 1 to convert the unit if necessary",
+    "    ",
+    "    Most of the above entries are stored as variables attributes, some of them are handled differently.",
+    "    The variable name is used as a search key for the parameter table. valid_min, valid_max,",
+    "    ok_min_mean_abs and ok_max_mean_abs are used to check the range of the data.",
+    "",
+    "PARAMETER",
+    "    table    STRING   Name of the CMOR table as specified from PCMDI",
+    "    convert  STRING   Converts the units if necessary",
     NULL
 };
 
@@ -4974,11 +5063,11 @@ static const char *MagplotHelp[] = {
     "    contour, shaded, grfill - Lat/Lon plot",
     "",
     "SYNOPSIS",
-    "    <operator>,params  ifile obase",
+    "    <operator>,params  infile obase",
     "",
     "DESCRIPTION",
     "    The operators in this module generates 2D Lon/Lat plots.",
-    "    The data for the plot is read from ifile.",
+    "    The data for the plot is read from infile.",
     "    Only data on rectilinear Lon/Lat grids are supported.",
     "    The output file will be named <obase>_<param>.<device> where param is the parameter name and",
     "    device is the device name. The default output file format is postscript,",
@@ -5068,11 +5157,11 @@ static const char *MagvectorHelp[] = {
     "    vector - Lat/Lon vector plot",
     "",
     "SYNOPSIS",
-    "    vector,params  ifile obase",
+    "    vector,params  infile obase",
     "",
     "DESCRIPTION",
     "    This operator generates 2D Lon/Lat vector plots.",
-    "    The data for the plot is read from ifile. The input is expected to contain two velocity",
+    "    The data for the plot is read from infile. The input is expected to contain two velocity",
     "    components. Only data on rectilinear Lon/Lat grids are supported.",
     "    The output file will be named <obase>.<device> where device is the device name. ",
     "    The default output file format is postscript, this can be changed with the device parameter.",
@@ -5098,11 +5187,11 @@ static const char *MaggraphHelp[] = {
     "    graph - Line graph plot",
     "",
     "SYNOPSIS",
-    "    graph,params  ifiles ofile",
+    "    graph,params  infiles outfile",
     "",
     "DESCRIPTION",
     "    This operator generates line graph plots.",
-    "    The data for the plot is read from ifiles. The result is written to ofile.",
+    "    The data for the plot is read from infiles. The result is written to outfile.",
     "    The default output file format is postscript, this can be changed with the device parameter.",
     "    ",
     "    Here is a list of all graph plot parameters:",
@@ -5130,13 +5219,13 @@ static const char *EcaCddHelp[] = {
     "    eca_cdd - Consecutive dry days index per time period",
     "",
     "SYNOPSIS",
-    "    eca_cdd[,R[,N]]  ifile ofile",
+    "    eca_cdd[,R[,N]]  infile outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile be a time series of the daily precipitation amount RR, then the largest number ",
+    "    Let infile be a time series of the daily precipitation amount RR, then the largest number ",
     "    of consecutive days where RR is less than R is counted. R is an optional parameter with ",
     "    default R = 1 mm. A further output variable is the number of dry periods of more than N days.",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile.",
     "    The following variables are created: ",
     "    - consecutive_dry_days_index_per_time_period",
     "    - number_of_cdd_periods_with_more_than_<N>days_per_time_period",
@@ -5152,13 +5241,13 @@ static const char *EcaCfdHelp[] = {
     "    eca_cfd - Consecutive frost days index per time period",
     "",
     "SYNOPSIS",
-    "    eca_cfd[,N]  ifile ofile",
+    "    eca_cfd[,N]  infile outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile be a time series of the daily minimum temperature TN, then the largest number of",
+    "    Let infile be a time series of the daily minimum temperature TN, then the largest number of",
     "    consecutive days where TN < 0 °C is counted. Note that TN have to be given in units of Kelvin.",
     "    A further output variable is the number of frost periods of more than N days.",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile.",
     "    The following variables are created: ",
     "    - consecutive_frost_days_index_per_time_period",
     "    - number_of_cfd_periods_with_more_than_<N>days_per_time_period",
@@ -5173,14 +5262,14 @@ static const char *EcaCsuHelp[] = {
     "    eca_csu - Consecutive summer days index per time period",
     "",
     "SYNOPSIS",
-    "    eca_csu[,T[,N]]  ifile ofile",
+    "    eca_csu[,T[,N]]  infile outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile be a time series of the daily maximum temperature TX, then the largest number of consecutive",
+    "    Let infile be a time series of the daily maximum temperature TX, then the largest number of consecutive",
     "    days where TX > T is counted. The number T is an optional parameter with default T = 25°C.",
     "    Note that TN have to be given in units of Kelvin, whereas T have to be given in degrees Celsius.",
     "    A further output variable is the number of summer periods of more than N days.",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile.",
     "    The following variables are created: ",
     "    - consecutive_summer_days_index_per_time_period",
     "    - number_of_csu_periods_with_more_than_<N>days_per_time_period",
@@ -5196,13 +5285,13 @@ static const char *EcaCwdHelp[] = {
     "    eca_cwd - Consecutive wet days index per time period",
     "",
     "SYNOPSIS",
-    "    eca_cwd[,R[,N]]  ifile ofile",
+    "    eca_cwd[,R[,N]]  infile outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile be a time series of the daily precipitation amount RR, then the largest number ",
+    "    Let infile be a time series of the daily precipitation amount RR, then the largest number ",
     "    of consecutive days where RR is at least R is counted. R is an optional parameter with ",
     "    default R = 1 mm. A further output variable is the number of wet periods of more than N days.",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile.",
     "    The following variables are created: ",
     "    - consecutive_wet_days_index_per_time_period",
     "    - number_of_cwd_periods_with_more_than_<N>days_per_time_period",
@@ -5218,17 +5307,17 @@ static const char *EcaCwdiHelp[] = {
     "    eca_cwdi - Cold wave duration index wrt mean of reference period",
     "",
     "SYNOPSIS",
-    "    eca_cwdi[,nday[,T]]  ifile1 ifile2 ofile",
+    "    eca_cwdi[,nday[,T]]  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile1 be a time series of the daily minimum temperature TN, and let ifile2 be the mean ",
+    "    Let infile1 be a time series of the daily minimum temperature TN, and let infile2 be the mean ",
     "    TNnorm of daily minimum temperatures for any period used as reference. Then counted is the number of days",
     "    where, in intervals of at least nday consecutive days, TN < TNnorm - T.",
     "    The numbers nday and T are optional parameters with default nday = 6 and T = 5°C. ",
     "    A further output variable is the number of cold waves longer than or equal to nday days.",
     "    TNnorm is calculated as the mean of minimum temperatures of a five day window centred on each calendar day ",
     "    of a given climate reference period. Note that both TN and TNnorm have to be given in the same units.",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile1.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile1.",
     "    The following variables are created: ",
     "    - cold_wave_duration_index_wrt_mean_of_reference_period",
     "    - cold_waves_per_time_period",
@@ -5244,18 +5333,18 @@ static const char *EcaCwfiHelp[] = {
     "    eca_cwfi - Cold-spell days index wrt 10th percentile of reference period",
     "",
     "SYNOPSIS",
-    "    eca_cwfi[,nday]  ifile1 ifile2 ofile",
+    "    eca_cwfi[,nday]  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile1 be a time series of the daily mean temperature TG, and ifile2 be the 10th",
+    "    Let infile1 be a time series of the daily mean temperature TG, and infile2 be the 10th",
     "    percentile TGn10 of daily mean temperatures for any period used as reference. ",
     "    Then counted is the number of days where, in intervals of at least nday consecutive days,",
     "    TG < TGn10. The number nday is an optional parameter with default nday = 6.",
     "    A further output variable is the number of cold-spell periods longer than or equal to nday days.",
     "    TGn10 is calculated as the 10th percentile of daily mean temperatures of a five day window ",
     "    centred on each calendar day of a given climate reference period. Note that both TG and TGn10 ",
-    "    have to be given in the same units. The date information of a timestep in ofile is the date of",
-    "    the last contributing timestep in ifile1.",
+    "    have to be given in the same units. The date information of a timestep in outfile is the date of",
+    "    the last contributing timestep in infile1.",
     "    The following variables are created: ",
     "    - cold_spell_days_index_wrt_10th_percentile_of_reference_period",
     "    - cold_spell_periods_per_time_period",
@@ -5270,15 +5359,15 @@ static const char *EcaEtrHelp[] = {
     "    eca_etr - Intra-period extreme temperature range",
     "",
     "SYNOPSIS",
-    "    eca_etr  ifile1 ifile2 ofile",
+    "    eca_etr  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile1 and ifile2 be time series of thr maximum and minimum",
+    "    Let infile1 and infile2 be time series of thr maximum and minimum",
     "    temperature TX and TN, respectively. Then the extreme temperature",
     "    range is the difference of the maximum of TX and the minimum of TN.",
     "    Note that TX and TN have to be given in the same units.",
-    "    The date information of a timestep in ofile is the date of",
-    "    the last contributing timesteps in ifile1 and ifile2.",
+    "    The date information of a timestep in outfile is the date of",
+    "    the last contributing timesteps in infile1 and infile2.",
     "    The following variables are created: ",
     "    - intra_period_extreme_temperature_range",
     NULL
@@ -5289,14 +5378,14 @@ static const char *EcaFdHelp[] = {
     "    eca_fd - Frost days index per time period",
     "",
     "SYNOPSIS",
-    "    eca_fd  ifile ofile",
+    "    eca_fd  infile outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile be a time series of the daily minimum temperature TN,",
+    "    Let infile be a time series of the daily minimum temperature TN,",
     "    then the number of days where TN < 0 °C is counted. Note",
     "    that TN have to be given in units of Kelvin.",
-    "    The date information of a timestep in ofile is the date of",
-    "    the last contributing timestep in ifile.",
+    "    The date information of a timestep in outfile is the date of",
+    "    the last contributing timestep in infile.",
     "    The following variables are created: ",
     "    - frost_days_index_per_time_period",
     NULL
@@ -5307,10 +5396,10 @@ static const char *EcaGslHelp[] = {
     "    eca_gsl - Thermal Growing season length index",
     "",
     "SYNOPSIS",
-    "    eca_gsl[,nday[,T[,fland]]]  ifile1 ifile2 ofile",
+    "    eca_gsl[,nday[,T[,fland]]]  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile1 be a time series of the daily mean temperature TG, and ifile2 be a land-water mask.",
+    "    Let infile1 be a time series of the daily mean temperature TG, and infile2 be a land-water mask.",
     "    Within a period of 12 months, the thermal growing season length is officially defined as the number of days between:",
     "    - first occurrence of at least nday consecutive days with TG > T",
     "    - first occurrence of at least nday consecutive days with TG < T within the last 6 months",
@@ -5325,7 +5414,7 @@ static const char *EcaGslHelp[] = {
     "    is the start day of year of the growing season. Note that TG have to be given in units of Kelvin, whereas T ",
     "    have to be given in degrees Celsius.",
     "    ",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile.",
     "    The following variables are created: ",
     "    - thermal_growing_season_length",
     "    - day_of_year_of_growing_season_start",
@@ -5342,15 +5431,15 @@ static const char *EcaHdHelp[] = {
     "    eca_hd - Heating degree days per time period",
     "",
     "SYNOPSIS",
-    "    eca_hd[,T1[,T2]]  ifile ofile",
+    "    eca_hd[,T1[,T2]]  infile outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile be a time series of the daily mean temperature TG, then the heating degree days ",
+    "    Let infile be a time series of the daily mean temperature TG, then the heating degree days ",
     "    are defined as the sum of T1 - TG, where only values TG < T2 are considered. ",
     "    If T1 and T2 are omitted, a temperature of 17°C is used for both parameters. ",
     "    If only T1 is given, T2 is set to T1. Note that TG have to be given in units ",
     "    of kelvin, whereas T1 and T2 have to be given in degrees Celsius.",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile.",
     "    The following variables are created: ",
     "    - heating_degree_days_per_time_period",
     "",
@@ -5365,17 +5454,17 @@ static const char *EcaHwdiHelp[] = {
     "    eca_hwdi - Heat wave duration index wrt mean of reference period",
     "",
     "SYNOPSIS",
-    "    eca_hwdi[,nday[,T]]  ifile1 ifile2 ofile",
+    "    eca_hwdi[,nday[,T]]  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile1 be a time series of the daily maximum temperature TX, and let ifile2 be the mean ",
+    "    Let infile1 be a time series of the daily maximum temperature TX, and let infile2 be the mean ",
     "    TXnorm of daily maximum temperatures for any period used as reference. Then counted is the number of days",
     "    where, in intervals of at least nday consecutive days, TX > TXnorm + T.",
     "    The numbers nday and T are optional parameters with default nday = 6 and T = 5°C. ",
     "    A further output variable is the number of heat waves longer than or equal to nday days. ",
     "    TXnorm is calculated as the mean of maximum temperatures of a five day window centred on each calendar day",
     "    of a given climate reference period. Note that both TX and TXnorm have to be given in the same units.",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile1.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile1.",
     "    The following variables are created: ",
     "    - heat_wave_duration_index_wrt_mean_of_reference_period",
     "    - heat_waves_per_time_period",
@@ -5391,11 +5480,11 @@ static const char *EcaHwfiHelp[] = {
     "    eca_hwfi - Warm spell days index wrt 90th percentile of reference period",
     "",
     "SYNOPSIS",
-    "    eca_hwfi[,nday]  ifile1 ifile2 ofile",
+    "    eca_hwfi[,nday]  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile1 be a time series of the daily mean temperature TG, and ",
-    "    ifile2 be the 90th percentile TGn90 of daily mean temperatures",
+    "    Let infile1 be a time series of the daily mean temperature TG, and ",
+    "    infile2 be the 90th percentile TGn90 of daily mean temperatures",
     "    for any period used as reference. Then counted is the number of days",
     "    where, in intervals of at least nday consecutive days, TG > TGn90. The",
     "    number nday is an optional parameter with default nday = 6. A further",
@@ -5404,8 +5493,8 @@ static const char *EcaHwfiHelp[] = {
     "    TGn90 is calculated as the 90th percentile of daily mean temperatures of a five ",
     "    day window centred on each calendar day of a given climate reference period.",
     "    Note that both TG and TGn90 have to be given in the same units.",
-    "    The date information of a timestep in ofile is the date of",
-    "    the last contributing timestep in ifile1.",
+    "    The date information of a timestep in outfile is the date of",
+    "    the last contributing timestep in infile1.",
     "    The following variables are created: ",
     "    - warm_spell_days_index_wrt_90th_percentile_of_reference_period",
     "    - warm_spell_periods_per_time_period",
@@ -5420,14 +5509,14 @@ static const char *EcaIdHelp[] = {
     "    eca_id - Ice days index per time period",
     "",
     "SYNOPSIS",
-    "    eca_id  ifile ofile",
+    "    eca_id  infile outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile be a time series of the daily maximum temperature TX,",
+    "    Let infile be a time series of the daily maximum temperature TX,",
     "    then the number of days where TX < 0 °C is counted. Note",
     "    that TX have to be given in units of Kelvin.",
-    "    The date information of a timestep in ofile is the date of",
-    "    the last contributing timestep in ifile.",
+    "    The date information of a timestep in outfile is the date of",
+    "    the last contributing timestep in infile.",
     "    The following variables are created: ",
     "    - ice_days_index_per_time_period",
     NULL
@@ -5438,15 +5527,15 @@ static const char *EcaR75pHelp[] = {
     "    eca_r75p - Moderate wet days wrt 75th percentile of reference period",
     "",
     "SYNOPSIS",
-    "    eca_r75p  ifile1 ifile2 ofile",
+    "    eca_r75p  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)",
-    "    and ifile2 be the 75th percentile RRn75 of the daily precipitation amount at wet days for any period ",
+    "    Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)",
+    "    and infile2 be the 75th percentile RRn75 of the daily precipitation amount at wet days for any period ",
     "    used as reference. Then the percentage of wet days with RR > RRn75 is calculated. ",
     "    RRn75 is calculated as the 75th percentile of all wet days of a given climate reference period.",
-    "    Usually ifile2 is generated by the operator ydaypctl,75.",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile1.",
+    "    Usually infile2 is generated by the operator ydaypctl,75.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile1.",
     "    The following variables are created: ",
     "    - moderate_wet_days_wrt_75th_percentile_of_reference_period",
     NULL
@@ -5457,16 +5546,16 @@ static const char *EcaR75ptotHelp[] = {
     "    eca_r75ptot - Precipitation percent due to R75p days",
     "",
     "SYNOPSIS",
-    "    eca_r75ptot  ifile1 ifile2 ofile",
+    "    eca_r75ptot  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)",
-    "    and ifile2 be the 75th percentile RRn75 of the daily precipitation amount at wet days for any period ",
+    "    Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)",
+    "    and infile2 be the 75th percentile RRn75 of the daily precipitation amount at wet days for any period ",
     "    used as reference. Then the ratio of the precipitation sum at wet days with RR > RRn75 to the total ",
     "    precipitation sum is calculated. ",
     "    RRn75 is calculated as the 75th percentile of all wet days of a given climate reference period.",
-    "    Usually ifile2 is generated by the operator ydaypctl,75.",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile1.",
+    "    Usually infile2 is generated by the operator ydaypctl,75.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile1.",
     "    The following variables are created: ",
     "    - precipitation_percent_due_to_R75p_days",
     NULL
@@ -5477,15 +5566,15 @@ static const char *EcaR90pHelp[] = {
     "    eca_r90p - Wet days wrt 90th percentile of reference period",
     "",
     "SYNOPSIS",
-    "    eca_r90p  ifile1 ifile2 ofile",
+    "    eca_r90p  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)",
-    "    and ifile2 be the 90th percentile RRn90 of the daily precipitation amount at wet days for any period ",
+    "    Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)",
+    "    and infile2 be the 90th percentile RRn90 of the daily precipitation amount at wet days for any period ",
     "    used as reference. Then the percentage of wet days with RR > RRn90 is calculated. ",
     "    RRn90 is calculated as the 90th percentile of all wet days of a given climate reference period.",
-    "    Usually ifile2 is generated by the operator ydaypctl,90.",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile1.",
+    "    Usually infile2 is generated by the operator ydaypctl,90.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile1.",
     "    The following variables are created: ",
     "    - wet_days_wrt_90th_percentile_of_reference_period",
     NULL
@@ -5496,16 +5585,16 @@ static const char *EcaR90ptotHelp[] = {
     "    eca_r90ptot - Precipitation percent due to R90p days",
     "",
     "SYNOPSIS",
-    "    eca_r90ptot  ifile1 ifile2 ofile",
+    "    eca_r90ptot  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)",
-    "    and ifile2 be the 90th percentile RRn90 of the daily precipitation amount at wet days for any period ",
+    "    Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)",
+    "    and infile2 be the 90th percentile RRn90 of the daily precipitation amount at wet days for any period ",
     "    used as reference. Then the ratio of the precipitation sum at wet days with RR > RRn90 to the total ",
     "    precipitation sum is calculated. ",
     "    RRn90 is calculated as the 90th percentile of all wet days of a given climate reference period.",
-    "    Usually ifile2 is generated by the operator ydaypctl,90.",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile1.",
+    "    Usually infile2 is generated by the operator ydaypctl,90.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile1.",
     "    The following variables are created: ",
     "    - precipitation_percent_due_to_R90p_days",
     NULL
@@ -5516,15 +5605,15 @@ static const char *EcaR95pHelp[] = {
     "    eca_r95p - Very wet days wrt 95th percentile of reference period",
     "",
     "SYNOPSIS",
-    "    eca_r95p  ifile1 ifile2 ofile",
+    "    eca_r95p  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)",
-    "    and ifile2 be the 95th percentile RRn95 of the daily precipitation amount at wet days for any period ",
+    "    Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)",
+    "    and infile2 be the 95th percentile RRn95 of the daily precipitation amount at wet days for any period ",
     "    used as reference. Then the percentage of wet days with RR > RRn95 is calculated. ",
     "    RRn95 is calculated as the 95th percentile of all wet days of a given climate reference period.",
-    "    Usually ifile2 is generated by the operator ydaypctl,95.",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile1.",
+    "    Usually infile2 is generated by the operator ydaypctl,95.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile1.",
     "    The following variables are created: ",
     "    - very_wet_days_wrt_95th_percentile_of_reference_period",
     NULL
@@ -5535,16 +5624,16 @@ static const char *EcaR95ptotHelp[] = {
     "    eca_r95ptot - Precipitation percent due to R95p days",
     "",
     "SYNOPSIS",
-    "    eca_r95ptot  ifile1 ifile2 ofile",
+    "    eca_r95ptot  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)",
-    "    and ifile2 be the 95th percentile RRn95 of the daily precipitation amount at wet days for any period ",
+    "    Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)",
+    "    and infile2 be the 95th percentile RRn95 of the daily precipitation amount at wet days for any period ",
     "    used as reference. Then the ratio of the precipitation sum at wet days with RR > RRn95 to the total ",
     "    precipitation sum is calculated. ",
     "    RRn95 is calculated as the 95th percentile of all wet days of a given climate reference period.",
-    "    Usually ifile2 is generated by the operator ydaypctl,95.",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile1.",
+    "    Usually infile2 is generated by the operator ydaypctl,95.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile1.",
     "    The following variables are created: ",
     "    - precipitation_percent_due_to_R95p_days",
     NULL
@@ -5555,15 +5644,15 @@ static const char *EcaR99pHelp[] = {
     "    eca_r99p - Extremely wet days wrt 99th percentile of reference period",
     "",
     "SYNOPSIS",
-    "    eca_r99p  ifile1 ifile2 ofile",
+    "    eca_r99p  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)",
-    "    and ifile2 be the 99th percentile RRn99 of the daily precipitation amount at wet days for any period ",
+    "    Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)",
+    "    and infile2 be the 99th percentile RRn99 of the daily precipitation amount at wet days for any period ",
     "    used as reference. Then the percentage of wet days with RR > RRn99 is calculated. ",
     "    RRn99 is calculated as the 99th percentile of all wet days of a given climate reference period.",
-    "    Usually ifile2 is generated by the operator ydaypctl,99.",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile1.",
+    "    Usually infile2 is generated by the operator ydaypctl,99.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile1.",
     "    The following variables are created: ",
     "    - extremely_wet_days_wrt_99th_percentile_of_reference_period",
     NULL
@@ -5574,16 +5663,16 @@ static const char *EcaR99ptotHelp[] = {
     "    eca_r99ptot - Precipitation percent due to R99p days",
     "",
     "SYNOPSIS",
-    "    eca_r99ptot  ifile1 ifile2 ofile",
+    "    eca_r99ptot  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)",
-    "    and ifile2 be the 99th percentile RRn99 of the daily precipitation amount at wet days for any period ",
+    "    Let infile1 be a time series RR of the daily precipitation amount at wet days (precipitation >= 1 mm)",
+    "    and infile2 be the 99th percentile RRn99 of the daily precipitation amount at wet days for any period ",
     "    used as reference. Then the ratio of the precipitation sum at wet days with RR > RRn99 to the total ",
     "    precipitation sum is calculated. ",
     "    RRn99 is calculated as the 99th percentile of all wet days of a given climate reference period.",
-    "    Usually ifile2 is generated by the operator ydaypctl,99.",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile1.",
+    "    Usually infile2 is generated by the operator ydaypctl,99.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile1.",
     "    The following variables are created: ",
     "    - precipitation_percent_due_to_R99p_days",
     NULL
@@ -5594,15 +5683,15 @@ static const char *EcaPdHelp[] = {
     "    eca_pd, eca_r10mm, eca_r20mm - Precipitation days index per time period",
     "",
     "SYNOPSIS",
-    "    eca_pd,x  ifile ofile",
-    "    eca_r10mm  ifile ofile",
-    "    eca_r20mm  ifile ofile",
+    "    eca_pd,x  infile outfile",
+    "    eca_r10mm  infile outfile",
+    "    eca_r20mm  infile outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile be a time series of the daily precipitation amount RR in [mm] (or alternatively in [kg m-2]),",
+    "    Let infile be a time series of the daily precipitation amount RR in [mm] (or alternatively in [kg m-2]),",
     "    then the number of days where RR is at least x mm is counted. ",
     "    eca_r10mm and eca_r20mm are specific ECA operators with a daily precipitation amount of 10 and 20 mm respectively.",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile.",
     "    The following variables are created: ",
     "    - precipitation_days_index_per_time_period",
     "",
@@ -5628,12 +5717,12 @@ static const char *EcaRr1Help[] = {
     "    eca_rr1 - Wet days index per time period",
     "",
     "SYNOPSIS",
-    "    eca_rr1[,R]  ifile ofile",
+    "    eca_rr1[,R]  infile outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile be a time series of the daily precipitation amount RR in [mm] (or alternatively in [kg m-2]), then",
+    "    Let infile be a time series of the daily precipitation amount RR in [mm] (or alternatively in [kg m-2]), then",
     "    the number of days where RR is at least R is counted. R is an optional parameter with default R = 1 mm. ",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile.",
     "    The following variables are created: ",
     "    - wet_days_index_per_time_period",
     "",
@@ -5647,15 +5736,15 @@ static const char *EcaRx1dayHelp[] = {
     "    eca_rx1day - Highest one day precipitation amount per time period",
     "",
     "SYNOPSIS",
-    "    eca_rx1day[,mode]  ifile ofile",
+    "    eca_rx1day[,mode]  infile outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile be a time series of the daily precipitation amount RR,",
-    "    then the maximum of RR is written to ofile. If the optional",
+    "    Let infile be a time series of the daily precipitation amount RR,",
+    "    then the maximum of RR is written to outfile. If the optional",
     "    parameter mode is set to 'm' the maximum daily precipitation",
     "    amounts are determined for each month. ",
-    "    The date information of a timestep in ofile is the date of",
-    "    the last contributing timestep in ifile.",
+    "    The date information of a timestep in outfile is the date of",
+    "    the last contributing timestep in infile.",
     "    The following variables are created: ",
     "    - highest_one_day_precipitation_amount_per_time_period",
     "",
@@ -5669,13 +5758,13 @@ static const char *EcaRx5dayHelp[] = {
     "    eca_rx5day - Highest five-day precipitation amount per time period",
     "",
     "SYNOPSIS",
-    "    eca_rx5day[,x]  ifile ofile",
+    "    eca_rx5day[,x]  infile outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile be a time series of 5-day precipitation totals RR, then the maximum of RR is written to ofile. ",
+    "    Let infile be a time series of 5-day precipitation totals RR, then the maximum of RR is written to outfile. ",
     "    A further output variable is the number of 5 day period with precipitation totals greater than x mm, where x ",
     "    is an optional parameter with default x = 50 mm.",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile.",
     "    The following variables are created: ",
     "    - highest_five_day_precipitation_amount_per_time_period",
     "    - number_of_5day_heavy_precipitation_periods_per_time_period",
@@ -5690,12 +5779,12 @@ static const char *EcaSdiiHelp[] = {
     "    eca_sdii - Simple daily intensity index per time period",
     "",
     "SYNOPSIS",
-    "    eca_sdii[,R]  ifile ofile",
+    "    eca_sdii[,R]  infile outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile be a time series of the daily precipitation amount RR, then the mean precipitation amount at ",
-    "    wet days (RR > R) is written to ofile. R is an optional parameter with default R = 1 mm.",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile.",
+    "    Let infile be a time series of the daily precipitation amount RR, then the mean precipitation amount at ",
+    "    wet days (RR > R) is written to outfile. R is an optional parameter with default R = 1 mm.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile.",
     "    The following variables are created: ",
     "    - simple_daily_intensity_index_per_time_period",
     "",
@@ -5709,13 +5798,13 @@ static const char *EcaSuHelp[] = {
     "    eca_su - Summer days index per time period",
     "",
     "SYNOPSIS",
-    "    eca_su[,T]  ifile ofile",
+    "    eca_su[,T]  infile outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile be a time series of the daily maximum temperature TX, then the number of days where ",
+    "    Let infile be a time series of the daily maximum temperature TX, then the number of days where ",
     "    TX > T is counted. The number T is an optional parameter with default T = 25°C. ",
     "    Note that TX have to be given in units of Kelvin, whereas T have to be given in degrees Celsius.",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile.",
     "    The following variables are created: ",
     "    - summer_days_index_per_time_period",
     "",
@@ -5729,18 +5818,18 @@ static const char *EcaTg10pHelp[] = {
     "    eca_tg10p - Cold days percent wrt 10th percentile of reference period",
     "",
     "SYNOPSIS",
-    "    eca_tg10p  ifile1 ifile2 ofile",
+    "    eca_tg10p  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile1 be a time series of the daily mean temperature TG, and",
-    "    ifile2 be the 10th percentile TGn10 of daily mean temperatures",
+    "    Let infile1 be a time series of the daily mean temperature TG, and",
+    "    infile2 be the 10th percentile TGn10 of daily mean temperatures",
     "    for any period used as reference. Then the percentage of time where ",
     "    TG < TGn10 is calculated.",
     "    TGn10 is calculated as the 10th percentile of daily mean temperatures of a five ",
     "    day window centred on each calendar day of a given climate reference period.",
     "    Note that both TG and TGn10 have to be given in the same units.",
-    "    The date information of a timestep in ofile is the date of",
-    "    the last contributing timestep in ifile1.",
+    "    The date information of a timestep in outfile is the date of",
+    "    the last contributing timestep in infile1.",
     "    The following variables are created: ",
     "    - cold_days_percent_wrt_10th_percentile_of_reference_period",
     NULL
@@ -5751,18 +5840,18 @@ static const char *EcaTg90pHelp[] = {
     "    eca_tg90p - Warm days percent wrt 90th percentile of reference period",
     "",
     "SYNOPSIS",
-    "    eca_tg90p  ifile1 ifile2 ofile",
+    "    eca_tg90p  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile1 be a time series of the daily mean temperature TG, and",
-    "    ifile2 be the 90th percentile TGn90 of daily mean temperatures",
+    "    Let infile1 be a time series of the daily mean temperature TG, and",
+    "    infile2 be the 90th percentile TGn90 of daily mean temperatures",
     "    for any period used as reference. Then the percentage of time where TG > TGn90 ",
     "    is calculated. ",
     "    TGn90 is calculated as the 90th percentile of daily mean temperatures of a five ",
     "    day window centred on each calendar day of a given climate reference period.",
     "    Note that both TG and TGn90 have to be given in the same units.",
-    "    The date information of a timestep in ofile is the date of",
-    "    the last contributing timestep in ifile1.",
+    "    The date information of a timestep in outfile is the date of",
+    "    the last contributing timestep in infile1.",
     "    The following variables are created: ",
     "    - warm_days_percent_wrt_90th_percentile_of_reference_period",
     NULL
@@ -5773,18 +5862,18 @@ static const char *EcaTn10pHelp[] = {
     "    eca_tn10p - Cold nights percent wrt 10th percentile of reference period",
     "",
     "SYNOPSIS",
-    "    eca_tn10p  ifile1 ifile2 ofile",
+    "    eca_tn10p  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile1 be a time serie of the daily minimum temperature TN, and",
-    "    ifile2 be the 10th percentile TNn10 of daily minimum temperatures",
+    "    Let infile1 be a time serie of the daily minimum temperature TN, and",
+    "    infile2 be the 10th percentile TNn10 of daily minimum temperatures",
     "    for any period used as reference. Then the percentage of time where TN < TNn10 ",
     "    is calculated.",
     "    TNn10 is calculated as the 10th percentile of daily minimum temperatures of a five ",
     "    day window centred on each calendar day of a given climate reference period.",
     "    Note that both TN and TNn10 have to be given in the same units.",
-    "    The date information of a timestep in ofile is the date of",
-    "    the last contributing timestep in ifile1.",
+    "    The date information of a timestep in outfile is the date of",
+    "    the last contributing timestep in infile1.",
     "    The following variables are created: ",
     "    - cold_nights_percent_wrt_10th_percentile_of_reference_period",
     NULL
@@ -5795,15 +5884,15 @@ static const char *EcaTn90pHelp[] = {
     "    eca_tn90p - Warm nights percent wrt 90th percentile of reference period",
     "",
     "SYNOPSIS",
-    "    eca_tn90p  ifile1 ifile2 ofile",
+    "    eca_tn90p  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile1 be a time series of the daily minimum temperature TN, and ifile2 be the ",
+    "    Let infile1 be a time series of the daily minimum temperature TN, and infile2 be the ",
     "    90th percentile TNn90 of daily minimum temperatures for any period used as reference. ",
     "    Then the percentage of time where TN > TNn90 is calculated. TNn90 is calculated as the 90th percentile",
     "    of daily minimum temperatures of a five day window centred on each calendar day of a given climate",
     "    reference period. Note that both TN and TNn90 have to be given in the same units.",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile1.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile1.",
     "    The following variables are created: ",
     "    - warm_nights_percent_wrt_90th_percentile_of_reference_period",
     NULL
@@ -5814,13 +5903,13 @@ static const char *EcaTrHelp[] = {
     "    eca_tr - Tropical nights index per time period",
     "",
     "SYNOPSIS",
-    "    eca_tr[,T]  ifile ofile",
+    "    eca_tr[,T]  infile outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile be a time series of the daily minimum temperature TN, then the number of days where ",
+    "    Let infile be a time series of the daily minimum temperature TN, then the number of days where ",
     "    TN > T is counted. The number T is an optional parameter with default T = 20°C. ",
     "    Note that TN have to be given in units of Kelvin, whereas T have to be given in degrees Celsius.",
-    "    The date information of a timestep in ofile is the date of the last contributing timestep in ifile.",
+    "    The date information of a timestep in outfile is the date of the last contributing timestep in infile.",
     "    The following variables are created: ",
     "    - tropical_nights_index_per_time_period",
     "",
@@ -5834,18 +5923,18 @@ static const char *EcaTx10pHelp[] = {
     "    eca_tx10p - Very cold days percent wrt 10th percentile of reference period",
     "",
     "SYNOPSIS",
-    "    eca_tx10p  ifile1 ifile2 ofile",
+    "    eca_tx10p  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile1 be a time series of the daily maximum temperature TX, and",
-    "    ifile2 be the 10th percentile TXn10 of daily maximum temperatures",
+    "    Let infile1 be a time series of the daily maximum temperature TX, and",
+    "    infile2 be the 10th percentile TXn10 of daily maximum temperatures",
     "    for any period used as reference. Then the percentage of time where TX < TXn10.",
     "    is calculated.",
     "    TXn10 is calculated as the 10th percentile of daily maximum temperatures of a five ",
     "    day window centred on each calendar day of a given climate reference period.",
     "    Note that both TX and TXn10 have to be givenin the same units.",
-    "    The date information of a timestep in ofile is the date of",
-    "    the last contributing timestep in ifile1.",
+    "    The date information of a timestep in outfile is the date of",
+    "    the last contributing timestep in infile1.",
     "    The following variables are created: ",
     "    - very_cold_days_percent_wrt_10th_percentile_of_reference_period",
     NULL
@@ -5856,18 +5945,18 @@ static const char *EcaTx90pHelp[] = {
     "    eca_tx90p - Very warm days percent wrt 90th percentile of reference period",
     "",
     "SYNOPSIS",
-    "    eca_tx90p  ifile1 ifile2 ofile",
+    "    eca_tx90p  infile1 infile2 outfile",
     "",
     "DESCRIPTION",
-    "    Let ifile1 be a time series of the daily maximum temperature TX, and",
-    "    ifile2 be the 90th percentile TXn90 of daily maximum temperatures",
+    "    Let infile1 be a time series of the daily maximum temperature TX, and",
+    "    infile2 be the 90th percentile TXn90 of daily maximum temperatures",
     "    for any period used as reference. Then the percentage of time where TX > TXn90.",
     "    is calculated.",
     "    TXn90 is calculated as the 90th percentile of daily maximum temperatures of a five ",
     "    day window centred on each calendar day of a given climate reference period.",
     "    Note that both TX and TXn90 have to be given in the same units.",
-    "    The date information of a timestep in ofile is the date of",
-    "    the last contributing timestep in ifile1.",
+    "    The date information of a timestep in outfile is the date of",
+    "    the last contributing timestep in infile1.",
     "    The following variables are created: ",
     "    - very_warm_days_percent_wrt_90th_percentile_of_reference_period",
     NULL
diff --git a/src/parse_literal.c b/src/parse_literal.c
new file mode 100644
index 0000000..ef3053f
--- /dev/null
+++ b/src/parse_literal.c
@@ -0,0 +1,136 @@
+#include <errno.h>
+#include <limits.h>
+#include "cdo_int.h"
+#include "cdi.h"
+
+
+int literal_get_datatype(const char *literal)
+{
+  if ( literal && *literal )
+    {
+      char *endptr;
+      errno = 0;
+      long lval = strtol(literal, &endptr, 10);
+      if ( errno == 0 && *endptr == 0 ) return CDI_DATATYPE_INT32;
+      else if ( errno == 0 && *(endptr+1) == 0 && (*endptr == 's' || *endptr == 'b') )
+        {
+          if      ( *endptr == 's' && lval >= SHRT_MIN && lval <= SHRT_MAX )
+            return CDI_DATATYPE_INT16;
+          else if ( *endptr == 'b' && lval >= SCHAR_MIN && lval <= SCHAR_MAX )
+            return CDI_DATATYPE_INT8;
+        }
+      else
+        {
+          errno = 0;
+          double dval = strtod(literal, &endptr);
+          if ( errno == 0 && *endptr == 0 ) return CDI_DATATYPE_FLT64;
+          else if ( errno == 0 && *(endptr+1) == 0 )
+            {
+              if ( *endptr == 'f' && dval >= -FLT_MAX && dval <= FLT_MAX )
+                return CDI_DATATYPE_FLT32;
+            }
+        }
+    }
+
+  return -1;
+}
+
+
+int literals_find_datatype(int n, char **literals)
+{
+  int dtype = -1;
+
+  if ( n )
+    {
+      dtype = literal_get_datatype(literals[0]);
+      if ( dtype != -1 )
+        for ( int i = 1; i < n; ++i )
+          {
+            int xtype = literal_get_datatype(literals[i]);
+            if ( dtype != xtype )
+              {
+                if ( xtype == CDI_DATATYPE_FLT32 || xtype == CDI_DATATYPE_FLT64 )
+                  {
+                    if ( dtype == CDI_DATATYPE_FLT32 || dtype == CDI_DATATYPE_FLT64 )
+                      {
+                        if ( xtype > dtype ) dtype = xtype;
+                      }
+                    else dtype = xtype;
+                  }
+                else
+                  {
+                    if ( !(dtype == CDI_DATATYPE_FLT32 || dtype == CDI_DATATYPE_FLT64) )
+                      {
+                        if ( xtype > dtype ) dtype = xtype;
+                      }
+                    else dtype = xtype;
+                  }
+              }
+          }
+    }
+
+  return dtype;
+}
+
+
+int literal_to_int(const char *literal)
+{
+  int ival = INT_MAX;
+
+  if ( literal && *literal )
+    {
+      char *endptr;
+      ival = strtol(literal, &endptr, 10);
+    }
+
+  return ival;
+}
+
+
+double literal_to_double(const char *literal)
+{
+  double dval = DBL_MAX;
+
+  if ( literal && *literal )
+    {
+      char *endptr;
+      dval = strtod(literal, &endptr);
+    }
+
+  return dval;
+}
+
+
+#ifdef TEST_LITERAL
+
+int main(void)
+{
+  const char *literals[] = {"127b", "-32768s", "-2147483647", "-1.e+36f", "1.e+308", "temperature", "surface pressure", "1000."};
+  int nliterals = sizeof(literals) / sizeof(literals[0]);
+
+  for ( int i = 0; i < nliterals; ++i )
+    {
+      int dtype = literal_get_datatype(literals[i]);
+      printf("%d %s type = %d", i+1, literals[i], dtype);
+      if ( dtype == CDI_DATATYPE_INT8 || dtype == CDI_DATATYPE_INT16 || dtype == CDI_DATATYPE_INT32 )
+        {
+          int ival = literal_to_int(literals[i]);
+          printf("  ival = %d", ival);
+        }
+      else if ( dtype == CDI_DATATYPE_FLT32 || dtype == CDI_DATATYPE_FLT64 )
+        {
+          double dval = literal_to_double(literals[i]);
+          printf("  dval = %g", dval);
+        }
+      else
+        {
+          printf("  sval = '%s'", literals[i]);
+        }
+      
+      printf("\n");
+    }
+  
+  return 0;
+}
+
+#endif
diff --git a/src/percentiles_hist.c b/src/percentiles_hist.c
index 8b83a56..954d4d7 100644
--- a/src/percentiles_hist.c
+++ b/src/percentiles_hist.c
@@ -265,7 +265,7 @@ void hsetDestroy(HISTOGRAM_SET *hset)
 }
 
 
-void hsetDefVarLevelBounds(HISTOGRAM_SET *hset, int varID, int levelID, const field_t *field1, const field_t *field2)
+void hsetDefVarLevelBounds(HISTOGRAM_SET *hset, int varID, int levelID, const field_type *field1, const field_type *field2)
 {
   const double *array1 = field1->ptr;
   const double *array2 = field2->ptr;
@@ -320,7 +320,7 @@ void hsetDefVarLevelBounds(HISTOGRAM_SET *hset, int varID, int levelID, const fi
 }
 
 
-void hsetAddVarLevelValues(HISTOGRAM_SET *hset, int varID, int levelID, const field_t *field)
+void hsetAddVarLevelValues(HISTOGRAM_SET *hset, int varID, int levelID, const field_type *field)
 {
   const double *array = field->ptr;
   int i, grid, nvars, nlevels, nhists, nign = 0;
@@ -373,7 +373,7 @@ void hsetAddVarLevelValues(HISTOGRAM_SET *hset, int varID, int levelID, const fi
 }
 
 
-void hsetGetVarLevelPercentiles(field_t *field, const HISTOGRAM_SET *hset, int varID, int levelID, double p)
+void hsetGetVarLevelPercentiles(field_type *field, const HISTOGRAM_SET *hset, int varID, int levelID, double p)
 {
   double *array = field->ptr;
   int i, nvars, nlevels, nhists, grid;
diff --git a/src/percentiles_hist.h b/src/percentiles_hist.h
index f27c39a..aca924b 100644
--- a/src/percentiles_hist.h
+++ b/src/percentiles_hist.h
@@ -43,8 +43,8 @@ HISTOGRAM_SET *hsetCreate(int nvars);
 void hsetCreateVarLevels(HISTOGRAM_SET *hset, int varID, int nlevels, int nhists);
 void hsetDestroy(HISTOGRAM_SET *hset);
 
-void hsetDefVarLevelBounds(HISTOGRAM_SET *hset, int varID, int levelID, const field_t *min, const field_t *max);
-void hsetAddVarLevelValues(HISTOGRAM_SET *histField, int varID, int levelID, const field_t *field);
-void hsetGetVarLevelPercentiles(field_t *field, const HISTOGRAM_SET *hset, int varID, int levelID, double pn); 
+void hsetDefVarLevelBounds(HISTOGRAM_SET *hset, int varID, int levelID, const field_type *min, const field_type *max);
+void hsetAddVarLevelValues(HISTOGRAM_SET *histField, int varID, int levelID, const field_type *field);
+void hsetGetVarLevelPercentiles(field_type *field, const HISTOGRAM_SET *hset, int varID, int levelID, double pn); 
 
 #endif /* PERCENTILES_HIST_H_ */
diff --git a/src/pipe.c b/src/pipe.c
index 44120cb..af33c4a 100644
--- a/src/pipe.c
+++ b/src/pipe.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -123,13 +123,11 @@ void pipe_init(pipe_t *pipe)
 
 pipe_t *pipeNew()
 {
-  pipe_t *pipe;
-
-  pipe = (pipe_t*) Malloc(sizeof(pipe_t));
+  pipe_t *pipe = (pipe_t*) Malloc(sizeof(pipe_t));
 
   pipe_init(pipe);
 
-  return (pipe);
+  return pipe;
 }
 
 
@@ -211,7 +209,7 @@ int pipeInqVlist(pstream_t *pstreamptr)
   pthread_mutex_unlock(pipe->mutex);
   // UNLOCK
 
-  return (vlistID);
+  return vlistID;
 }
 
 
@@ -267,7 +265,7 @@ int pipeInqTimestep(pstream_t *pstreamptr, int tsID)
 
   pthread_cond_signal(pipe->tsInq);
 
-  return (nrecs);
+  return nrecs;
 }
 
 
diff --git a/src/pipe.h b/src/pipe.h
index 964878f..bdaedff 100644
--- a/src/pipe.h
+++ b/src/pipe.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
diff --git a/src/pmlist.c b/src/pmlist.c
index 892ac4d..d654135 100644
--- a/src/pmlist.c
+++ b/src/pmlist.c
@@ -1,366 +1,289 @@
-#include "cdo_int.h"
-#include "pmlist.h"
-
-static
-void pml_init(pml_t *pml, const char *name)
-{
-  pml->size = 0;
-  pml->name = strdup(name);
-}
-
-
-pml_t *pml_create(const char *name)
-{
-  pml_t *pml = (pml_t*) Malloc(sizeof(pml_t));
-
-  pml_init(pml, name);
-
-  return pml;
-}
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
 
+#include "pmlist.h"
 
-void pml_destroy(pml_t *pml)
+keyValues_t *kvlist_search(list_t *kvlist, const char *key)
 {
-  if ( pml == NULL ) return;
-
-  for ( int i = 0; i < pml->size; ++i )
+  if ( key )
     {
-      if ( pml->entry[i]->txt ) free(pml->entry[i]->txt);
-      if ( pml->entry[i]->name ) free(pml->entry[i]->name);
-      if ( pml->entry[i] ) Free(pml->entry[i]);
+      listNode_t *node = kvlist->head;
+      while ( node )
+        {
+          keyValues_t *kv = *(keyValues_t **)node->data;
+          if ( kv->key && *(kv->key) == *key && strcmp(kv->key, key) == 0 ) return kv;
+          node = node->next;
+        }
     }
 
-  if ( pml->name ) free(pml->name);
-
-  Free(pml);
+  return NULL;
 }
 
 
-void pml_print(pml_t *pml)
+list_t *pmlist_search_kvlist(list_t *pmlist, const char *key, const char *value)
 {
-  if ( pml == NULL ) return;
-
-  fprintf(stdout, "Parameter list: %s\n", pml->name);
-  fprintf(stdout, " Num  Name             Type  Size   Occ  Entries\n");
-
-  for ( int i = 0; i < pml->size; ++i )
+  if ( pmlist && key && value )
     {
-      pml_entry_t *entry = pml->entry[i];
-      fprintf(stdout, "%4d  %-16s %4d  %4d  %4d ",
-	      i+1, pml->entry[i]->name, pml->entry[i]->type, (int)pml->entry[i]->size, pml->entry[i]->occ);
-      int nout = pml->entry[i]->occ;
-      if ( nout > 8 ) nout = 8;
-
-      for ( int j = 0; j < nout; j++ )
+      listNode_t *node = pmlist->head;
+      while ( node )
         {
-          switch (entry->type)
+          if ( node->data )
             {
-            case PML_WORD: fprintf(stdout, " %s", ((char **)entry->ptr)[j]); break;
-            case PML_INT:  fprintf(stdout, " %d", ((int *)entry->ptr)[j]); break;
-            case PML_FLT:  fprintf(stdout, " %g", ((double *)entry->ptr)[j]); break;
+              list_t *kvlist = *(list_t **)node->data;
+              keyValues_t *kv = kvlist_search(kvlist, key);
+              if ( kv && kv->nvalues > 0 && *(kv->values[0]) == *value && strcmp(kv->values[0], value) == 0 ) return kvlist;
             }
+          node = node->next;
         }
-      fprintf(stdout, "\n");
     }
+
+  return NULL;
 }
 
 
-int pml_add(pml_t *pml, const char *txt, const char *name, int type, void *ptr, size_t size)
+bool kvlist_print_iter(void *data)
 {
-  if ( pml->size >= MAX_PML_ENTRY )
-    {
-      fprintf(stderr, "Too many entries in parameter list %s! (Max = %d)\n", pml->name, MAX_PML_ENTRY);
-      return -1;
-    }
-
-  pml_entry_t *pml_entry = (pml_entry_t*) Malloc(sizeof(pml_entry_t));
-
-  pml_entry->txt  = strdup(txt);
-  pml_entry->name = strdup(name);
-  pml_entry->len  = strlen(name);
-  pml_entry->type = type;
-  pml_entry->ptr  = ptr;
-  pml_entry->size = size;
-  pml_entry->occ  = 0;
-
-  int entry = pml->size;
-  pml->entry[pml->size++] = pml_entry;
-
-  return entry;
+  keyValues_t *keyval = *(keyValues_t **)data;
+  char *key = keyval->key;
+  char **values = keyval->values;
+  int nvalues = keyval->nvalues;
+  printf("  %s =", key);
+  for ( int i = 0; i < nvalues; ++i ) printf(" '%s'", values[i]);
+  printf("\n");
+
+  return true;
 }
 
 
-int pml_num_par(pml_t *pml, int pid)
+void kvlist_print(list_t *kvlist)
 {
-  int nocc = 0;
-
-  if ( pml && pid >= 0 && pid < pml->size ) nocc = pml->entry[pid]->occ;
-
-  return nocc;
+  printf("Key/Value list %s:\n", list_name(kvlist));
+  list_for_each(kvlist, kvlist_print_iter);
 }
 
 
-int pml_num(pml_t *pml, const char *name)
+bool pmlist_print_iter(void *data)
 {
-  pml_entry_t *entry;
-  int i, nocc = 0;
-
-  if ( pml == NULL ) return nocc;
-
-  for ( i = 0; i < pml->size; i++ )
-    {
-      entry = pml->entry[i];
-      if ( strcmp(name, entry->name) == 0 )
-	{
-	  nocc = entry->occ;
-	  break;
-	}
-    }
-
-  if ( i == pml->size )
-    fprintf(stderr, "Parameter list entry %s not found in %s\n", name, pml->name);
-
-  return nocc;
+  list_t *kvlist = *(list_t **)data;
+  const char *listname = list_name(kvlist);
+  printf("\nFound %s list with %d key/values: \n", listname?listname:"", list_size(kvlist));
+  list_for_each(kvlist, kvlist_print_iter);
+  return true;
 }
 
-void split_intstring(const char *intstr, int *first, int *last, int *inc);
 
-int pml_add_entry(pml_entry_t *entry, char *arg)
+void free_keyval(void *data)
 {
-  int status = 0;
-
-  if ( entry->type == PML_INT )
-    {
-      int ival, first, last, inc;
-
-      split_intstring(arg, &first, &last, &inc);
-
-      if ( inc >= 0 )
-	{
-	  for ( ival = first; ival <= last; ival += inc )
-	    if ( entry->occ < (int) entry->size )
-	      ((int *) entry->ptr)[entry->occ++] = ival;
-	}
-      else
-	{
-	  for ( ival = first; ival >= last; ival += inc )
-	    if ( entry->occ < (int) entry->size )
-	      ((int *) entry->ptr)[entry->occ++] = ival;
-	}
-    }
-  else if ( entry->type == PML_FLT )
-    {
-      if ( entry->occ < (int) entry->size )
-	((double *) entry->ptr)[entry->occ++] = atof(arg);
-    }
-  else if ( entry->type == PML_WORD )
-    {
-      if ( entry->occ < (int) entry->size )
-	((char **) entry->ptr)[entry->occ++] = strdupx(arg);
-    }
-  else
-    {
-      fprintf(stderr, "Unsupported type!\n");
-    }
-
-  return status;
+  keyValues_t *keyval = *(keyValues_t **)data;
+  if ( keyval->key ) free(keyval->key);
+  int nvalues = keyval->nvalues;
+  for ( int i = 0; i < nvalues; ++i )
+    if ( keyval->values[i] ) free(keyval->values[i]);
+  free(keyval->values);
+  free(keyval);
 }
 
-static
-void pml_process(pml_entry_t *entry, int argc, char **argv)
+
+void free_kvlist(void *data)
 {
-  for ( int i = 0; i < argc; ++i )
-    {
-      char *parg = argv[i];
-      if ( i == 0 )
-	{
-	  char *epos = strchr(parg, '=');
-	  if ( epos == NULL ) fprintf(stderr, "Internal problem, keyword not found!\n");
-	  parg += epos-parg+1;
-	}
-
-      pml_add_entry(entry, parg);
-    }
+  list_t *kvlist = *(list_t **)data;
+  //int n = list_size(kvlist);
+  list_destroy(kvlist);
+  //printf("Successfully freed %d keyvalues...\n", n);
 }
 
 
-int pml_read(pml_t *pml, int argc, char **argv)
+list_t *kvlist_new(const char *name)
 {
-  pml_entry_t *entry = NULL;
-  pml_entry_t *pentry[MAX_PML_ENTRY];
-  int params[MAX_PML_ENTRY];
-  int num_par[MAX_PML_ENTRY];
-  int nparams = 0;
-  int i;
-  char *epos;
-  size_t len;
-  int bufsize = 0;
-  int status = 0;
-
-  if ( argc == 0 ) return 0;
-
-  for ( i = 0; i < argc; ++i )
-    {
-      len = strlen(argv[i]);
-      bufsize += len+1;
-    }
-
-  char *parbuf = (char*) Malloc(bufsize*sizeof(char));
-  memset(parbuf, 0, bufsize*sizeof(char));
-
-  int istart = 0;
-  while ( istart < argc )
-    {
-      epos = strchr(argv[istart], '=');
-      if ( epos == NULL )
-	{
-	  fprintf(stderr, "Parameter >%s< has no keyword!\n", argv[istart]);
-	  status = 1;
-	  goto END_LABEL;
-	}
-
-      len = epos - argv[istart];
-      for ( i = 0; i < pml->size; ++i )
-	{
-	  entry = pml->entry[i];
-	  if ( entry->len == len )
-	    if ( memcmp(entry->name, argv[istart], len) == 0 ) break;
-	}
-
-      if ( i == pml->size )
-	{
-	  fprintf(stderr, "Parameter >%s< has an invalid keyword!\n", argv[istart]);
-	  status = 2;
-	  goto END_LABEL;
-	}
-
-      num_par[nparams] = 0;
-      pentry[nparams]  = entry;
-      params[nparams]  = istart;
-      num_par[nparams] = 1;
-      
-      istart++;
-      for ( i = istart; i < argc; ++i )
-	{
-	  if ( *argv[i] == 0 ) { i++; break;}
-	  epos = strchr(argv[i], '=');
-	  if ( epos != NULL ) break;
-
-	  num_par[nparams]++;
-	}
-
-      istart = i;
-
-      nparams++;
-    }
-
-  for ( i = 0; i < nparams; ++i )
-    {
-      pml_process(pentry[i], num_par[i], &argv[params[i]]);
-    }
-
-
- END_LABEL:
-
-  Free(parbuf);
-
-  return status;
+  return list_new(sizeof(keyValues_t *), free_keyval, name);
 }
 
 
-bool pml_check_int(pml_t *pml, int pid, int *parlist, bool *flaglist, int par)
+void kvlist_destroy(list_t *list)
 {
-  bool found = false;
-  int npar = pml_num_par(pml, pid);
-  for ( int i = 0; i < npar; i++ )
-    if ( par == parlist[i] ) { found = true; flaglist[i] = true;/* break;*/}
-
-  return found;
+  list_destroy(list);
 }
 
 
-bool pml_check_flt(pml_t *pml, int pid, double *parlist, bool *flaglist, double par)
+void kvlist_append(list_t *kvlist, const char *key, const char **values, int nvalues)
 {
-  bool found = false;
-  int npar = pml_num_par(pml, pid);
-  for ( int i = 0; i < npar; i++ )
-    if ( fabs(par - parlist[i]) < 1.e-4 ) { found = true; flaglist[i] = true;/* break;*/}
-
-  return found;
+  keyValues_t *keyval = (keyValues_t *) malloc(sizeof(keyValues_t));
+  keyval->key = strdup(key);
+  keyval->nvalues = nvalues;
+  keyval->values = (char **) malloc(nvalues*sizeof(char*));
+  for ( int i = 0; i < nvalues; ++i ) keyval->values[i] = strdup(values[i]);
+  list_append(kvlist, &keyval);
 }
 
 
-bool pml_check_word(pml_t *pml, int pid, char **parlist, bool *flaglist, const char *par)
+int kvlist_parse_cmdline(list_t *kvlist, int nparams, char **params)
 {
-  bool found = false;
-  int npar = pml_num_par(pml, pid);
-  for ( int i = 0; i < npar; i++ )
-    if ( wildcardmatch(parlist[i], par) == 0 ) { found = true; flaglist[i] = true;/* break;*/}
-
-  return found;
-}
+  /* Assume key = value pairs. That is, if params[i] contains no '='
+   * then treat it as if it belongs to the values of params[i-1]. */
+  char key[256];
+  int i = 0;
+  while ( i < nparams )
+    {
+      char *end = strchr(params[i], '=');
+      if ( end == NULL )
+        {
+          fprintf(stderr, "Missing '=' in key/value string: >%s<\n", params[i]);
+          return -1;
+        }
 
+      snprintf(key, sizeof(key), "%.*s", (int)(end-params[i]), params[i]);
+      key[sizeof(key)-1] = 0;
 
-bool pml_check_date(pml_t *pml, int pid, char **parlist, bool *flaglist, const char *par)
-{
-  bool found = false;
-  int npar = pml_num_par(pml, pid);
-  char wcdate[512];
+      int j = 1;
+      while ( i + j < nparams && strchr(params[i + j], '=') == NULL ) j++;
 
-  if ( *par == ' ' ) ++par;
+      int nvalues = j;
+      const char *values[nvalues];
 
-  for ( int i = 0; i < npar; i++ )
-    {
-      strcpy(wcdate, parlist[i]);
-      strcat(wcdate, "*");
-      if ( wildcardmatch(wcdate, par) == 0 ) { found = true; flaglist[i] = true;/* break;*/}
+      values[0] = end + 1;
+      if ( *values[0] == 0 ) nvalues = 0;
+      for ( j = 1; j < nvalues; ++j ) values[j] = params[i + j];
+      
+      kvlist_append(kvlist, key, values, nvalues);
+      
+      i += j;
     }
 
-  return found;
+  return 0;
 }
 
-void season_to_months(const char *season, int *imonths);
 
-bool pml_check_season(pml_t *pml, int pid, char **parlist, bool *flaglist, int month)
+list_t *pmlist_search_kvlist_ventry(list_t *pmlist, const char *key, const char *value, int nentry, const char **entry)
 {
-  assert(month>=1&&month<=12);
-  bool found = false;
-  int npar = pml_num_par(pml, pid);
-  int imon[13]; /* 1-12 ! */
-
-  for ( int i = 0; i < npar; i++ )
+  if ( pmlist && key && value )
     {
-      for ( int m = 0; m < 13; ++m ) imon[m] = 0;
-      season_to_months(parlist[i], imon);
-      if ( imon[month] ) { found = true; flaglist[i] = true;/* break;*/}
+      listNode_t *node = pmlist->head;
+      while ( node )
+        {
+          if ( node->data )
+            {
+              list_t *kvlist = *(list_t **)node->data;
+              const char *listname = list_name(kvlist);
+              for ( int i = 0; i < nentry; ++i )
+                if ( strcmp(listname, entry[i]) == 0 )
+                  {
+                    keyValues_t *kv = kvlist_search(kvlist, key);
+                    if ( kv && kv->nvalues > 0 && *(kv->values[0]) == *value && strcmp(kv->values[0], value) == 0 ) return kvlist;
+                  }
+            }
+          node = node->next;
+        }
     }
 
-  return found;
+  return NULL;
 }
 
 
-void pml_check_int_flag(pml_t *pml, int pid, int *parlist, bool *flaglist)
+list_t *pmlist_get_kvlist_ventry(list_t *pmlist, int nentry, const char **entry)
 {
-  int npar = pml_num_par(pml, pid);
-  for ( int i = 0; i < npar; ++i )
-    if ( flaglist[i] == false )
-      cdoWarning("%s >%d< not found!", pml->entry[pid]->txt, parlist[i]);
-}
+  if ( pmlist )
+    {
+      listNode_t *node = pmlist->head;
+      while ( node )
+        {
+          if ( node->data )
+            {
+              list_t *kvlist = *(list_t **)node->data;
+              const char *listname = list_name(kvlist);
+              for ( int i = 0; i < nentry; ++i )
+                if ( strcmp(listname, entry[i]) == 0 ) return kvlist;
+            }
+          node = node->next;
+        }
+    }
 
+  return NULL;
+}
 
-void pml_check_flt_flag(pml_t *pml, int pid, double *parlist, bool *flaglist)
+/*
+int main(void)
 {
-  int npar = pml_num_par(pml, pid);
-  for ( int i = 0; i < npar; ++i )
-    if ( flaglist[i] == false )
-      cdoWarning("%s >%g< not found!", pml->entry[pid]->txt, parlist[i]);
-}
+  int numLists = 0;
+  printf("Generating list with lists of keyValues...\n");
+
+  list_t *pmlist = list_new(sizeof(list_t *), free_kvlist, "parameter");
+
+  {
+    const char *k1 = "longname", *k1vals[] = {"surface temperature"};
+    const char *k2 = "name",     *k2vals[] = {"temperature"};
+    const char *k3 = "values",   *k3vals[] = {"273.15", "292.5", "301.4"};
+
+    list_t *kvlist = list_new(sizeof(keyValues_t *), free_keyval, "p1");
+
+    kvlist_append(kvlist, k1, k1vals, sizeof(k1vals)/sizeof(k1vals[0]));
+    kvlist_append(kvlist, k2, k2vals, sizeof(k2vals)/sizeof(k2vals[0]));
+    kvlist_append(kvlist, k3, k3vals, sizeof(k3vals)/sizeof(k3vals[0]));
+
+    list_append(pml, &kvlist);
+    numLists++;
+  }
+  {
+    const char *k1 = "longname", *k1vals[] = {"surface pressure"};
+    const char *k2 = "name",     *k2vals[] = {"pressure"};
+    const char *k3 = "values",   *k3vals[] = {"1000", "850", "500"};
+    const char *k4 = "units",    *k4vals[] = {"hPa"};
+
+    list_t *kvlist = list_new(sizeof(keyValues_t *), free_keyval, "p1");
+
+    kvlist_append(kvlist, k1, k1vals, sizeof(k1vals)/sizeof(k1vals[0]));
+    kvlist_append(kvlist, k2, k2vals, sizeof(k2vals)/sizeof(k2vals[0]));
+    kvlist_append(kvlist, k3, k3vals, sizeof(k3vals)/sizeof(k3vals[0]));
+    kvlist_append(kvlist, k4, k4vals, sizeof(k4vals)/sizeof(k4vals[0]));
+
+    list_append(pmlist, &kvlist);
+    numLists++;
+  }
+  {
+    const char *k1 = "longname", *k1vals[] = {"Air Temperature"};
+    const char *k2 = "name",     *k2vals[] = {"ta"};
+    const char *k3 = "valid_max",*k3vals[] = {"336"};
+    const char *k4 = "units",    *k4vals[] = {"K"};
+
+    list_t *kvlist = list_new(sizeof(keyValues_t *), free_keyval, "p1");
+
+    kvlist_append(kvlist, k1, k1vals, sizeof(k1vals)/sizeof(k1vals[0]));
+    kvlist_append(kvlist, k2, k2vals, sizeof(k2vals)/sizeof(k2vals[0]));
+    kvlist_append(kvlist, k3, k3vals, sizeof(k3vals)/sizeof(k3vals[0]));
+    kvlist_append(kvlist, k4, k4vals, sizeof(k4vals)/sizeof(k4vals[0]));
+
+    list_append(pmlist, &kvlist);
+    numLists++;
+  }
+  
+ 
+  printf("pmlist=%s n=%d:\n", list_name(pmlist), list_size(pmlist));
+  list_for_each(pml, pmlist_print_iter);
+
+  list_t *kvlist = pmlist_search_kvl(pml, "name", "pressure");
+  printf("kvlist of name=pressure:\n");
+  if ( kvlist ) list_for_each(kvlist, kvlist_print_iter);
+
+  printf("\n");
+  int n = list_size(kvlist);
+  for ( int i = 0; i < n; ++i )
+    {
+      keyValues_t *kv = (keyValues_t *) list_entry(kvlist, i);
+      if ( kv ) printf("  %d: key=%s  val0=%s\n", i+1, kv->key, kv->values[0]);
+    }
 
+  printf("\n");
+  int i = 0;
+  for ( listNode_t *node = kvlist->head; node; node = node->next )
+    {
+      keyValues_t *kv = *(keyValues_t **)node->data;
+      if ( kv ) printf("  %d: key=%s  val0=%s\n", i+1, kv->key, kv->values[0]);
+      ++i;
+    }
 
-void pml_check_word_flag(pml_t *pml, int pid, char **parlist, bool *flaglist)
-{
-  int npar = pml_num_par(pml, pid);
-  for ( int i = 0; i < npar; ++i )
-    if ( flaglist[i] == false )
-      cdoWarning("%s >%s< not found!", pml->entry[pid]->txt, parlist[i]);
+  list_destroy(pmlist);
+  printf("Successfully freed %d kvlists...\n", numLists);
+
+  return 0;
 }
+*/
diff --git a/src/pmlist.h b/src/pmlist.h
index ac20b90..c3f2cc8 100644
--- a/src/pmlist.h
+++ b/src/pmlist.h
@@ -1,88 +1,31 @@
-/*
-  This file is part of CDO. CDO is a collection of Operators to
-  manipulate and analyse Climate model Data.
-
-  Copyright (C) 2003-2016 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.
-*/
-
 #ifndef _PMLIST_H
 #define _PMLIST_H
 
-#define  PML_INT         1
-#define  PML_FLT         2
-#define  PML_WORD        3
-#define  PML_DATE        4
-#define  PML_TIME        4
-
-#define  PML_INIT(name, size)                 memset(flag_##name, 0, size * sizeof(bool))
-#define  PML_DEF(name, size)                  bool flag_##name[size]
-#define  PML_DEF_INT(name, size)              int par_##name[size]; int name = 0; PML_DEF(name, size); PML_INIT(name, size)
-#define  PML_DEF_FLT(name, size)              double par_##name[size]; double name = 0; PML_DEF(name, size); PML_INIT(name, size)
-#define  PML_DEF_WORD(name, size)             char *par_##name[size]; const char *name = 0; PML_DEF(name, size); PML_INIT(name, size)
-#define  PML_ADD_INT(pml, name, size, txt)    PML_DEF_INT(name, size);  int pid_##name = pml_add(pml, txt, #name, PML_INT,  par_##name, sizeof(par_##name)/sizeof(int))
-#define  PML_ADD_FLT(pml, name, size, txt)    PML_DEF_FLT(name, size);  int pid_##name = pml_add(pml, txt, #name, PML_FLT,  par_##name, sizeof(par_##name)/sizeof(double))
-#define  PML_ADD_WORD(pml, name, size, txt)   PML_DEF_WORD(name, size); int pid_##name = pml_add(pml, txt, #name, PML_WORD, par_##name, sizeof(par_##name)/sizeof(char *))
-#define  PML_NOCC(pml, name)                  pml_num_par(pml, pid_##name)
-//#define  PML_NUM(pml, name)                   npar_##name = pml_num(pml, #name)
-
-#define  PML_CHECK_INT_FLAG(pml, name)        pml_check_int_flag(pml, pid_##name, par_##name, flag_##name)
-#define  PML_CHECK_FLT_FLAG(pml, name)        pml_check_flt_flag(pml, pid_##name, par_##name, flag_##name)
-#define  PML_CHECK_WORD_FLAG(pml, name)       pml_check_word_flag(pml, pid_##name, par_##name, flag_##name)
-#define  PML_CHECK_INT(pml, name)             pml_check_int(pml, pid_##name, par_##name, flag_##name, name)
-#define  PML_CHECK_FLT(pml, name)             pml_check_flt(pml, pid_##name, par_##name, flag_##name, name)
-#define  PML_CHECK_WORD(pml, name)            pml_check_word(pml, pid_##name, par_##name, flag_##name, name)
-#define  PML_CHECK_DATE(pml, name)            pml_check_date(pml, pid_##name, par_##name, flag_##name, name)
-#define  PML_CHECK_SEASON(pml, name, month)   pml_check_season(pml, pid_##name, par_##name, flag_##name, month)
-
-#define  MAX_PML_ENTRY    256
-
-typedef struct
-{
-  char *txt;
-  char *name;
-  size_t len;
-  void *ptr;
-  int type;
-  int occ;
-  size_t size;
-} pml_entry_t;
+#include "list.h"
 
+typedef struct {
+  int nvalues;
+  char *key;
+  char **values;
+} keyValues_t;
 
-typedef struct
-{
-  int size;
-  char *name;
-  pml_entry_t *entry[MAX_PML_ENTRY];
-} pml_t;
+keyValues_t *kvlist_search(list_t *kvlist, const char *key);
+list_t *pmlist_search_kvl(list_t *pmlist, const char *key, const char *value);
 
+bool kvlist_print_iter(void *data);
+bool pmlist_print_iter(void *data);
 
-pml_t *pml_create(const char *name);
-void pml_destroy(pml_t *pml);
+void kvlist_print(list_t *kvlist);
 
-void pml_print(pml_t *pml);
-int pml_add(pml_t *pml, const char *txt, const char *name, int type, void *ptr, size_t size);
-int pml_num_par(pml_t *pml, int pid);
-int pml_add_entry(pml_entry_t *entry, char *arg);
-int pml_read(pml_t *pml, int argc, char **argv);
+void free_keyval(void *data);
+void free_kvlist(void *data);
 
-bool pml_check_int(pml_t *pml, int pid, int *parlist, bool *flaglist, int par);
-bool pml_check_flt(pml_t *pml, int pid, double *parlist, bool *flaglist, double par);
-bool pml_check_word(pml_t *pml, int pid, char **parlist, bool *flaglist, const char *par);
-bool pml_check_date(pml_t *pml, int pid, char **parlist, bool *flaglist, const char *par);
-bool pml_check_season(pml_t *pml, int pid, char **parlist, bool *flaglist, int month);
+list_t *kvlist_new(const char *name);
+void kvlist_destroy(list_t *list);
+void kvlist_append(list_t *kvlist, const char *key, const char **values, int nvalues);
+int kvlist_parse_cmdline(list_t *kvlist, int nparams, char **params);
 
-void pml_check_int_flag(pml_t *pml, int pid, int *parlist, bool *flaglist);
-void pml_check_flt_flag(pml_t *pml, int pid, double *parlist, bool *flaglist);
-void pml_check_word_flag(pml_t *pml, int pid, char **parlist, bool *flaglist);
+list_t *pmlist_search_kvlist_ventry(list_t *pmlist, const char *key, const char *value, int nentry, const char **entry);
+list_t *pmlist_get_kvlist_ventry(list_t *pmlist, int nentry, const char **entry);
 
-#endif  /* _PMLIST_H */
+#endif
diff --git a/src/printinfo.h b/src/printinfo.h
index a095bb5..bdde1cc 100644
--- a/src/printinfo.h
+++ b/src/printinfo.h
@@ -9,6 +9,14 @@
 #define DATE_FORMAT "%5.4d-%2.2d-%2.2d"
 #define TIME_FORMAT "%2.2d:%2.2d:%2.2d"
 
+void my_reset_text_color(FILE *fp)
+{
+  (void)fp;
+#ifdef CDO
+  reset_text_color(fp);
+#endif
+}
+
 void datetime2str(int date, int time, char *datetimestr, int maxlen)
 {
   int year, month, day;
@@ -50,31 +58,31 @@ void printFiletype(int streamID, int vlistID)
 
   switch ( filetype )
     {
-    case FILETYPE_GRB:
+    case CDI_FILETYPE_GRB:
       printf("GRIB");
       break;
-    case FILETYPE_GRB2:
+    case CDI_FILETYPE_GRB2:
       printf("GRIB2");
       break;
-    case FILETYPE_NC:
+    case CDI_FILETYPE_NC:
       printf("NetCDF");
       break;
-    case FILETYPE_NC2:
+    case CDI_FILETYPE_NC2:
       printf("NetCDF2");
       break;
-    case FILETYPE_NC4:
+    case CDI_FILETYPE_NC4:
       printf("NetCDF4");
       break;
-    case FILETYPE_NC4C:
+    case CDI_FILETYPE_NC4C:
       printf("NetCDF4 classic");
       break;
-    case FILETYPE_SRV:
+    case CDI_FILETYPE_SRV:
       printf("SERVICE");
       break;
-    case FILETYPE_EXT:
+    case CDI_FILETYPE_EXT:
       printf("EXTRA");
       break;
-    case FILETYPE_IEG:
+    case CDI_FILETYPE_IEG:
       printf("IEG");
       break;
     default:
@@ -82,7 +90,7 @@ void printFiletype(int streamID, int vlistID)
       break;
     }
 
-  if ( filetype == FILETYPE_SRV || filetype == FILETYPE_EXT || filetype == FILETYPE_IEG )
+  if ( filetype == CDI_FILETYPE_SRV || filetype == CDI_FILETYPE_EXT || filetype == CDI_FILETYPE_IEG )
     {
       switch ( streamInqByteorder(streamID) )
 	{
@@ -95,40 +103,31 @@ void printFiletype(int streamID, int vlistID)
 	}
     }
 
-  if ( filetype == FILETYPE_GRB || filetype == FILETYPE_NC4 || filetype == FILETYPE_NC4C )
+  if ( filetype == CDI_FILETYPE_GRB || filetype == CDI_FILETYPE_NC4 || filetype == CDI_FILETYPE_NC4C )
     {
-      int nvars, varID;
-      int comptype;
-
-      nvars = vlistNvars(vlistID);
-
-      for ( varID = 0; varID < nvars; varID++ )
+      int nvars = vlistNvars(vlistID);
+      for ( int varID = 0; varID < nvars; varID++ )
 	{
-	  comptype = vlistInqVarCompType(vlistID, varID);
+	  int comptype = vlistInqVarCompType(vlistID, varID);
 	  if ( comptype )
 	    {
-	      if ( comptype == COMPRESS_SZIP )
-		printf(" SZIP");
-	      else if ( comptype == COMPRESS_ZIP )
-		printf(" ZIP");
+	      if      ( comptype == CDI_COMPRESS_SZIP ) printf(" SZIP");
+	      else if ( comptype == CDI_COMPRESS_ZIP  ) printf(" ZIP");
 
 	      break;
 	    }
 	}
     }
 
-  if ( filetype == FILETYPE_GRB2 )
+  if ( filetype == CDI_FILETYPE_GRB2 )
     {
-      int comptype;
       int nvars = vlistNvars(vlistID);
       for ( int varID = 0; varID < nvars; varID++ )
 	{
-	  comptype = vlistInqVarCompType(vlistID, varID);
+	  int comptype = vlistInqVarCompType(vlistID, varID);
 	  if ( comptype )
 	    {
-	      if ( comptype == COMPRESS_JPEG )
-		printf(" JPEG");
-
+	      if ( comptype == CDI_COMPRESS_JPEG ) printf(" JPEG");
 	      break;
 	    }
 	}
@@ -138,251 +137,353 @@ void printFiletype(int streamID, int vlistID)
 }
 
 static
-void printGridInfo(int vlistID)
+void print_xvals(int gridID, int dig)
 {
-  char xname[CDI_MAX_NAME], yname[CDI_MAX_NAME], xunits[CDI_MAX_NAME], yunits[CDI_MAX_NAME];
-  unsigned char uuidOfHGrid[CDI_UUID_SIZE];
+  int xsize = gridInqXsize(gridID);
+  if ( xsize > 0 && gridInqXvals(gridID, NULL) )
+    {
+      char xname[CDI_MAX_NAME], xunits[CDI_MAX_NAME];
+      gridInqXname(gridID, xname);
+      gridInqXunits(gridID, xunits);
 
-  int ngrids = vlistNgrids(vlistID);
-  for ( int index = 0; index < ngrids; index++ )
+      double xfirst = gridInqXval(gridID, 0);
+      double xlast  = gridInqXval(gridID, xsize-1);
+      double xinc   = gridInqXinc(gridID);
+      fprintf(stdout, "%33s : %.*g", xname, dig, xfirst);
+      if ( xsize > 1 )
+        {
+          fprintf(stdout, " to %.*g", dig, xlast);
+          if ( IS_NOT_EQUAL(xinc, 0) )
+            fprintf(stdout, " by %.*g", dig, xinc);
+        }
+      fprintf(stdout, " %s", xunits);
+      if ( gridIsCircular(gridID) ) fprintf(stdout, "  circular");
+      fprintf(stdout, "\n");
+    }
+}
+
+static
+void print_yvals(int gridID, int dig)
+{
+  int ysize = gridInqYsize(gridID);
+  if ( ysize > 0 && gridInqYvals(gridID, NULL) )
     {
-      int gridID   = vlistGrid(vlistID, index);
-      int gridtype = gridInqType(gridID);
-      int trunc    = gridInqTrunc(gridID);
-      int gridsize = gridInqSize(gridID);
-      int xsize    = gridInqXsize(gridID);
-      int ysize    = gridInqYsize(gridID);
-      int xysize   = xsize*ysize;
-      // int prec     = gridInqPrec(gridID);
+      char yname[CDI_MAX_NAME], yunits[CDI_MAX_NAME];
+      gridInqYname(gridID, yname);
+      gridInqYunits(gridID, yunits);
 
-      // int dig = (prec == DATATYPE_FLT64) ? 15 : 7;
-      int dig = 7;
+      double yfirst = gridInqYval(gridID, 0);
+      double ylast  = gridInqYval(gridID, ysize-1);
+      double yinc   = gridInqYinc(gridID);
+      fprintf(stdout, "%33s : %.*g", yname, dig, yfirst);
+      if ( ysize > 1 )
+        {
+          int gridtype = gridInqType(gridID);
+          fprintf(stdout, " to %.*g", dig, ylast);
+          if ( IS_NOT_EQUAL(yinc, 0) && gridtype != GRID_GAUSSIAN && gridtype != GRID_GAUSSIAN_REDUCED )
+            fprintf(stdout, " by %.*g", dig, yinc);
+        }
+      fprintf(stdout, " %s", yunits);
+      fprintf(stdout, "\n");
+    }
+}
 
+static
+void print_xyvals2D(int gridID, int dig)
+{
+  if ( gridInqXvals(gridID, NULL) && gridInqYvals(gridID, NULL) )
+    {
+      char xname[CDI_MAX_NAME], yname[CDI_MAX_NAME], xunits[CDI_MAX_NAME], yunits[CDI_MAX_NAME];
       gridInqXname(gridID, xname);
       gridInqYname(gridID, yname);
       gridInqXunits(gridID, xunits);
       gridInqYunits(gridID, yunits);
 
-      fprintf(stdout, "  %4d : %-24s", index+1, gridNamePtr(gridtype));
+      int gridsize = gridInqSize(gridID);
+      double *xvals2D = (double*) malloc((size_t)gridsize*sizeof(double));
+      double *yvals2D = (double*) malloc((size_t)gridsize*sizeof(double));
 
-      if ( gridtype == GRID_LONLAT   ||
-	   gridtype == GRID_LCC2 ||
-	   gridtype == GRID_LAEA ||
-	   gridtype == GRID_SINUSOIDAL ||
-	   gridtype == GRID_GENERIC ||
-	   gridtype == GRID_GAUSSIAN ||
-	   gridtype == GRID_GAUSSIAN_REDUCED )
-	{
-	  double yfirst = gridInqYval(gridID, 0);
-	  double ylast  = gridInqYval(gridID, ysize-1);
-	  double yinc   = gridInqYinc(gridID);
+      gridInqXvals(gridID, xvals2D);
+      gridInqYvals(gridID, yvals2D);
+
+      double xfirst = xvals2D[0];
+      double xlast  = xvals2D[0];
+      double yfirst = yvals2D[0];
+      double ylast  = yvals2D[0];
+      for ( int i = 1; i < gridsize; i++ )
+        {
+          if ( xvals2D[i] < xfirst ) xfirst = xvals2D[i];
+          if ( xvals2D[i] > xlast  ) xlast  = xvals2D[i];
+          if ( yvals2D[i] < yfirst ) yfirst = yvals2D[i];
+          if ( yvals2D[i] > ylast  ) ylast  = yvals2D[i];
+        }
+
+      double xinc = 0;
+      double yinc = 0;
+      int gridtype = gridInqType(gridID);
+      if ( gridtype == GRID_CURVILINEAR )
+        {
+          int xsize = gridInqXsize(gridID);
+          if ( xsize > 1 )
+            {
+              double *xvals = (double*) malloc(xsize*sizeof(double));
+              for ( int 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++ )
+                if ( fabs(fabs(xvals[i-1] - xvals[i]) - xinc) > 0.01*xinc ) { xinc = 0; break; }
+              free(xvals);
+            }
+          int ysize = gridInqYsize(gridID);
+          if ( ysize > 1 )
+            {
+              double *yvals = (double*) malloc(ysize*sizeof(double));
+              for ( int 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++ )
+                if ( fabs(fabs(yvals[i-1] - yvals[i]) - yinc) > 0.01*yinc ) { yinc = 0; break; }
+              free(yvals);
+            }
+        }
 
-          fprintf(stdout, " : points=%d", gridsize);
-	  if ( gridtype == GRID_GAUSSIAN_REDUCED )
-	    fprintf(stdout, "  nlat=%d", ysize);
-	  else if ( xysize )
-	    fprintf(stdout, " (%dx%d)", xsize, ysize);
+      fprintf(stdout, "%33s : %.*g to %.*g", xname, dig, xfirst, dig, xlast);
+      if ( IS_NOT_EQUAL(xinc, 0) )
+        fprintf(stdout, " by %.*g", dig, xinc);
+      fprintf(stdout, " %s", xunits);
+      if ( gridIsCircular(gridID) ) fprintf(stdout, "  circular");
+      fprintf(stdout, "\n");
+      fprintf(stdout, "%33s : %.*g to %.*g", yname, dig, yfirst, dig, ylast);
+      if ( IS_NOT_EQUAL(yinc, 0) )
+        fprintf(stdout, " by %.*g", dig, yinc);
+      fprintf(stdout, " %s", xunits);
+      fprintf(stdout, "\n");
 
-	  if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
-	    fprintf(stdout, "  np=%d", gridInqNP(gridID));
+      free(xvals2D);
+      free(yvals2D);
+    }
+}
 
-	  fprintf(stdout, "\n");
+static
+void printGridInfoKernel(int gridID, int index, bool lproj)
+{
+  int gridtype = gridInqType(gridID);
 
-          bool lxcoord = true, lycoord = true;
-          if ( gridInqXvals(gridID, NULL) == 0 ) lxcoord = false;
-          if ( gridInqYvals(gridID, NULL) == 0 ) lycoord = false;
+  if ( lproj && gridtype != GRID_PROJECTION )
+    fprintf(stderr, "Internal problem (%s): sub grid not equal GRID_PROJECTION!\n", __func__);
 
-	  if ( xsize > 0 && lxcoord )
-	    {
-              double xfirst = gridInqXval(gridID, 0);
-              double xlast  = gridInqXval(gridID, xsize-1);
-              double xinc   = gridInqXinc(gridID);
-              fprintf(stdout, "%33s : %.*g", xname, dig, xfirst);
-              if ( xsize > 1 )
-                {
-                  fprintf(stdout, " to %.*g", dig, xlast);
-                  if ( IS_NOT_EQUAL(xinc, 0) )
-                    fprintf(stdout, " by %.*g", dig, xinc);
-                }
-              fprintf(stdout, " %s", xunits);
-              if ( gridIsCircular(gridID) ) fprintf(stdout, "  circular");
-              fprintf(stdout, "\n");
-	    }
+  int trunc    = gridInqTrunc(gridID);
+  int gridsize = gridInqSize(gridID);
+  int xsize    = gridInqXsize(gridID);
+  int ysize    = gridInqYsize(gridID);
+  int xysize   = xsize*ysize;
 
-	  if ( ysize > 0 && lycoord )
-	    {
-	      fprintf(stdout, "%33s : %.*g", yname, dig, yfirst);
-	      if ( ysize > 1 )
-                {
-                  fprintf(stdout, " to %.*g", dig, ylast);
-                  if ( IS_NOT_EQUAL(yinc, 0) && gridtype != GRID_GAUSSIAN && gridtype != GRID_GAUSSIAN_REDUCED )
-                    fprintf(stdout, " by %.*g", dig, yinc);
-                }
-              fprintf(stdout, " %s", yunits);
-	      fprintf(stdout, "\n");
-	    }
+  // int prec     = gridInqPrec(gridID);
+  // int dig = (prec == CDI_DATATYPE_FLT64) ? 15 : 7;
+  int dig = 7;
+#ifdef CDO
+  extern int CDO_flt_digits;
+  dig = CDO_flt_digits;
+#endif
 
-	  if ( gridIsRotated(gridID) )
-	    {
-	      double lonpole = gridInqXpole(gridID);
-	      double latpole = gridInqYpole(gridID);
-	      double angle   = gridInqAngle(gridID);
-	      fprintf(stdout, "%33s : lon=%.*g  lat=%.*g", "northpole", dig, lonpole, dig, latpole);
-	      if ( IS_NOT_EQUAL(angle, 0) ) fprintf(stdout, "  angle=%.*g", dig, angle);
-	      fprintf(stdout, "\n");
-	    }
+  if ( !lproj )
+    {
+      fprintf(stdout, "  %4d : ", index+1);
+#ifdef CDO
+      set_text_color(stdout, RESET, BLUE);
+#endif
+      fprintf(stdout, "%-24s", gridNamePtr(gridtype));
+      my_reset_text_color(stdout);
+      fprintf(stdout, " : ");
+    }
 
-	  if ( gridInqXbounds(gridID, NULL) || gridInqYbounds(gridID, NULL) )
-	    {
-	      fprintf(stdout, "%33s :", "available");
-	      if ( gridInqXbounds(gridID, NULL) && gridInqYbounds(gridID, NULL) ) fprintf(stdout, " cellbounds");
-	      if ( gridHasArea(gridID) )          fprintf(stdout, " area");
-	      if ( gridInqMask(gridID, NULL) )    fprintf(stdout, " mask");
-	      fprintf(stdout, "\n");
-	    }
+  if ( gridtype == GRID_LONLAT     ||
+       gridtype == GRID_PROJECTION ||
+       gridtype == GRID_GENERIC    ||
+       gridtype == GRID_GAUSSIAN   ||
+       gridtype == GRID_GAUSSIAN_REDUCED )
+    {
+      if ( !lproj )
+        {
+#ifdef CDO
+          set_text_color(stdout, RESET, GREEN);
+#endif
+          fprintf(stdout, "points=%d", gridsize);
+          if ( gridtype == GRID_GAUSSIAN_REDUCED )
+            fprintf(stdout, "  nlat=%d", ysize);
+          else if ( xysize )
+            fprintf(stdout, " (%dx%d)", xsize, ysize);
 
-	  if ( gridtype == GRID_LAEA )
-	    {
-	      double a, lon_0, lat_0;
-	      gridInqLaea(gridID, &a, &lon_0, &lat_0);
-	      fprintf(stdout, "%33s : a=%g  lon_0=%g  lat_0=%g\n", "projpar", a, lon_0, lat_0);
-	    }
+          if ( gridtype == GRID_GAUSSIAN || gridtype == GRID_GAUSSIAN_REDUCED )
+            fprintf(stdout, "  np=%d", gridInqNP(gridID));
+          my_reset_text_color(stdout);
 
-	  if ( gridtype == GRID_LCC2 )
-	    {
-	      double a, lon_0, lat_0, lat_1, lat_2;
-	      gridInqLcc2(gridID, &a, &lon_0, &lat_0, &lat_1, &lat_2);
-	      fprintf(stdout, "%33s : a=%7.0f  lon_0=%g  lat_0=%g  lat_1=%g  lat_2=%g\n",
-                      "projpar", a, lon_0, lat_0, lat_1, lat_2);
-	    }
-	}
-      else if ( gridtype == GRID_SPECTRAL )
-	{
-	  fprintf(stdout, " : points=%d  nsp=%d  truncation=%d", gridsize, gridsize/2, trunc);
-          if ( gridInqComplexPacking(gridID) ) fprintf(stdout, "  complexPacking");
           fprintf(stdout, "\n");
-	}
-      else if ( gridtype == GRID_FOURIER )
-	{
-	  fprintf(stdout, " : points=%d  nfc=%d  truncation=%d\n", gridsize, gridsize/2, trunc);
-	}
-      else if ( gridtype == GRID_GME )
-	{
-	  int ni = gridInqGMEni(gridID);
-	  int nd = gridInqGMEnd(gridID);
-	  fprintf(stdout, " : points=%d  nd=%d  ni=%d\n", gridsize, nd, ni);
-	}
-      else if ( gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED )
-	{
-	  if ( gridtype == GRID_CURVILINEAR )
-	    fprintf(stdout, " : points=%d (%dx%d)", gridsize, xsize, ysize);
-	  else
-	    fprintf(stdout, " : points=%d", gridsize);
+        }
+
+      char name[CDI_MAX_NAME]; name[0] = 0;
+      cdiGridInqKeyStr(gridID, CDI_KEY_MAPNAME, CDI_MAX_NAME, name);
+      if ( gridtype == GRID_PROJECTION || name[0] )
+        {
+          if ( name[0] == 0 ) strcpy(name, "undefined");
+#ifdef CDO
+          set_text_color(stdout, RESET, BLUE);
+#endif
+          fprintf(stdout, "         %24s", "mapping");
+          my_reset_text_color(stdout);
+          fprintf(stdout, " : ");
+#ifdef CDO
+          set_text_color(stdout, RESET, GREEN);
+#endif
+          fprintf(stdout, "%s\n", name);
+          my_reset_text_color(stdout);
+        }
 
-          if ( gridtype == GRID_UNSTRUCTURED && gridInqNvertex(gridID) > 0 )
-	    fprintf(stdout, "  nvertex=%d", gridInqNvertex(gridID));
+      print_xvals(gridID, dig);
+      print_yvals(gridID, dig);
 
+      if ( gridInqXbounds(gridID, NULL) || gridInqYbounds(gridID, NULL) )
+        {
+          fprintf(stdout, "%33s :", "available");
+          if ( gridInqXbounds(gridID, NULL) && gridInqYbounds(gridID, NULL) ) fprintf(stdout, " cellbounds");
+          if ( gridHasArea(gridID) )          fprintf(stdout, " area");
+          if ( gridInqMask(gridID, NULL) )    fprintf(stdout, " mask");
           fprintf(stdout, "\n");
+        }
+    }
+  else if ( gridtype == GRID_SPECTRAL )
+    {
+#ifdef CDO
+      set_text_color(stdout, RESET, GREEN);
+#endif
+      fprintf(stdout, "points=%d  nsp=%d  truncation=%d", gridsize, gridsize/2, trunc);
+      if ( gridInqComplexPacking(gridID) ) fprintf(stdout, "  complexPacking");
+      my_reset_text_color(stdout);
+      fprintf(stdout, "\n");
+    }
+  else if ( gridtype == GRID_FOURIER )
+    {
+#ifdef CDO
+      set_text_color(stdout, RESET, GREEN);
+#endif
+      fprintf(stdout, "points=%d  nfc=%d  truncation=%d\n", gridsize, gridsize/2, trunc);
+      my_reset_text_color(stdout);
+    }
+  else if ( gridtype == GRID_GME )
+    {
+      int nd, ni, ni2, ni3;
+      gridInqParamGME(gridID, &nd, &ni, &ni2, &ni3);
+#ifdef CDO
+      set_text_color(stdout, RESET, GREEN);
+#endif
+      fprintf(stdout, "points=%d  nd=%d  ni=%d\n", gridsize, nd, ni);
+      my_reset_text_color(stdout);
+    }
+  else if ( gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED )
+    {
+#ifdef CDO
+      set_text_color(stdout, RESET, GREEN);
+#endif
+      if ( gridtype == GRID_CURVILINEAR )
+        fprintf(stdout, "points=%d (%dx%d)", gridsize, xsize, ysize);
+      else
+        fprintf(stdout, "points=%d", gridsize);
 
-          if ( gridtype == GRID_UNSTRUCTURED )
-            {
-              int number   = gridInqNumber(gridID);
-              int position = gridInqPosition(gridID);
+      if ( gridtype == GRID_UNSTRUCTURED && gridInqNvertex(gridID) > 0 )
+        fprintf(stdout, "  nvertex=%d", gridInqNvertex(gridID));
+      my_reset_text_color(stdout);
 
-              if ( number > 0 )
-                {
-                  fprintf(stdout, "%33s : number=%d  position=%d\n", "grid", number, position);
-                }
+      fprintf(stdout, "\n");
 
-              if ( gridInqReference(gridID, NULL) )
-                {
-                  char reference_link[8192];
-                  gridInqReference(gridID, reference_link);
-                  fprintf(stdout, "%33s : %s\n", "uri", reference_link);
-                }
+      if ( gridtype == GRID_UNSTRUCTURED )
+        {
+          int number   = gridInqNumber(gridID);
+          int position = gridInqPosition(gridID);
+          if ( number > 0 )
+            fprintf(stdout, "%33s : number=%d  position=%d\n", "grid", number, position);
+
+          if ( gridInqReference(gridID, NULL) )
+            {
+              char reference_link[8192];
+              gridInqReference(gridID, reference_link);
+              fprintf(stdout, "%33s : %s\n", "uri", reference_link);
             }
+        }
 
-	  if ( gridInqXvals(gridID, NULL) && gridInqYvals(gridID, NULL) )
-	    {
-	      double *xvals = (double*) malloc((size_t)gridsize*sizeof(double));
-	      double *yvals = (double*) malloc((size_t)gridsize*sizeof(double));
-
-	      gridInqXvals(gridID, xvals);
-	      gridInqYvals(gridID, yvals);
-
-	      double xfirst = xvals[0];
-	      double xlast  = xvals[0];
-	      double yfirst = yvals[0];
-	      double ylast  = yvals[0];
-	      for ( int i = 1; i < gridsize; i++ )
-		{
-		  if ( xvals[i] < xfirst ) xfirst = xvals[i];
-		  if ( xvals[i] > xlast  ) xlast  = xvals[i];
-		  if ( yvals[i] < yfirst ) yfirst = yvals[i];
-		  if ( yvals[i] > ylast  ) ylast  = yvals[i];
-		}
-
-	      fprintf(stdout, "%33s : %.*g to %.*g %s", xname, dig, xfirst, dig, xlast, xunits);
-	      if ( gridIsCircular(gridID) ) fprintf(stdout, "  circular");
-	      fprintf(stdout, "\n");
-	      fprintf(stdout, "%33s : %.*g to %.*g %s\n", yname, dig, yfirst, dig, ylast, yunits);
-
-	      free(xvals);
-	      free(yvals);
-	    }
-	}
-      else if ( gridtype == GRID_LCC )
-	{
-	  double originLon, originLat, lonParY, lat1, lat2, xincm, yincm;
-	  int projflag, scanflag;
+      print_xyvals2D(gridID, dig);
+    }
+  else if ( gridtype == GRID_LCC )
+    {
+      double originLon, originLat, lonParY, lat1, lat2, xincm, yincm;
+      int projflag, scanflag;
 
-	  gridInqLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
-		     &projflag, &scanflag);
+      gridInqParamLCC(gridID, &originLon, &originLat, &lonParY, &lat1, &lat2, &xincm, &yincm,
+                 &projflag, &scanflag);
 
-	  fprintf(stdout, " : points=%d (%dx%d)  ", gridsize, xsize, ysize);
-	  if ( (projflag&128) == 0 )
-	    fprintf(stdout, "North Pole\n");
-	  else
-	    fprintf(stdout, "South Pole\n");
+#ifdef CDO
+      set_text_color(stdout, RESET, GREEN);
+#endif
+      fprintf(stdout, "points=%d (%dx%d)  ", gridsize, xsize, ysize);
+      if ( (projflag&128) == 0 )
+        fprintf(stdout, "North Pole\n");
+      else
+        fprintf(stdout, "South Pole\n");
+      my_reset_text_color(stdout);
 
-	  fprintf(stdout, "%33s : originLon=%g  originLat=%g  lonParY=%g\n", " ", originLon, originLat, lonParY);
-	  fprintf(stdout, "%33s : lat1=%g  lat2=%g  xinc=%g m  yinc=%g m\n", " ", lat1, lat2, xincm, yincm);
-	}
-      else /* if ( gridtype == GRID_GENERIC ) */
-	{
-	  if ( ysize == 0 )
-	    fprintf(stdout, " : points=%d\n", gridsize);
-	  else
-            fprintf(stdout, " : points=%d (%dx%d)\n", gridsize, xsize, ysize);
-	}
+      fprintf(stdout, "%33s : originLon=%g  originLat=%g  lonParY=%g\n", " ", originLon, originLat, lonParY);
+      fprintf(stdout, "%33s : lat1=%g  lat2=%g  xinc=%g m  yinc=%g m\n", " ", lat1, lat2, xincm, yincm);
+    }
+  else /* if ( gridtype == GRID_GENERIC ) */
+    {
+#ifdef CDO
+      set_text_color(stdout, RESET, GREEN);
+#endif
+      if ( ysize == 0 )
+        fprintf(stdout, "points=%d\n", gridsize);
+      else
+        fprintf(stdout, "points=%d (%dx%d)\n", gridsize, xsize, ysize);
+      my_reset_text_color(stdout);
+    }
 
-      if ( gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED || gridtype == GRID_LCC )
-	{
-	  if ( gridHasArea(gridID) ||
-	       gridInqXbounds(gridID, NULL) || gridInqYbounds(gridID, NULL) )
-	    {
-	      fprintf(stdout, "%33s :", "available");
-	      if ( gridInqXbounds(gridID, NULL) && gridInqYbounds(gridID, NULL) ) fprintf(stdout, " cellbounds");
-	      if ( gridHasArea(gridID) )          fprintf(stdout, " area");
-	      if ( gridInqMask(gridID, NULL) )    fprintf(stdout, " mask");
-	      fprintf(stdout, "\n");
-	    }
-	}
+  if ( gridtype == GRID_CURVILINEAR || gridtype == GRID_UNSTRUCTURED || gridtype == GRID_LCC )
+    {
+      if ( gridHasArea(gridID) ||
+           gridInqXbounds(gridID, NULL) || gridInqYbounds(gridID, NULL) )
+        {
+          fprintf(stdout, "%33s :", "available");
+          if ( gridInqXbounds(gridID, NULL) && gridInqYbounds(gridID, NULL) ) fprintf(stdout, " cellbounds");
+          if ( gridHasArea(gridID) )          fprintf(stdout, " area");
+          if ( gridInqMask(gridID, NULL) )    fprintf(stdout, " mask");
+          fprintf(stdout, "\n");
+        }
+    }
 
-      gridInqUUID(gridID, uuidOfHGrid);
-      if ( !cdiUUIDIsNull(uuidOfHGrid) )
+  unsigned char uuidOfHGrid[CDI_UUID_SIZE];
+  gridInqUUID(gridID, uuidOfHGrid);
+  if ( !cdiUUIDIsNull(uuidOfHGrid) )
+    {
+      char uuidOfHGridStr[37];
+      cdiUUID2Str(uuidOfHGrid, uuidOfHGridStr);
+      if ( uuidOfHGridStr[0] != 0  && strlen(uuidOfHGridStr) == 36 )
         {
-          char uuidOfHGridStr[37];
-          cdiUUID2Str(uuidOfHGrid, uuidOfHGridStr);
-          if ( uuidOfHGridStr[0] != 0  && strlen(uuidOfHGridStr) == 36 )
-            {
-	      fprintf(stdout, "%33s : %s\n", "uuid", uuidOfHGridStr);
-            }
+          fprintf(stdout, "%33s : %s\n", "uuid", uuidOfHGridStr);
         }
     }
 }
 
 static
+void printGridInfo(int vlistID)
+{
+  int ngrids = vlistNgrids(vlistID);
+  for ( int index = 0; index < ngrids; index++ )
+    {
+      int gridID = vlistGrid(vlistID, index);
+      printGridInfoKernel(gridID, index, false);
+      int projID = gridInqProj(gridID);
+      if ( projID != CDI_UNDEFID )
+        printGridInfoKernel(projID, index, true);
+    }
+}
+
+static
 void printZaxisInfo(int vlistID)
 {
   char zaxisname[CDI_MAX_NAME], zname[CDI_MAX_NAME], zunits[CDI_MAX_NAME];
@@ -395,53 +496,74 @@ void printZaxisInfo(int vlistID)
       int zaxistype = zaxisInqType(zaxisID);
       int ltype     = zaxisInqLtype(zaxisID);
       int levelsize = zaxisInqSize(zaxisID);
-      int prec      = zaxisInqPrec(zaxisID);
-
-      int dig = (prec == DATATYPE_FLT64) ? 15 : 7;
+      // int prec      = zaxisInqPrec(zaxisID);
+      // int dig = (prec == CDI_DATATYPE_FLT64) ? 15 : 7;
+      int dig = 7;
+#ifdef CDO
+      extern int CDO_flt_digits;
+      dig = CDO_flt_digits;
+#endif
 
       zaxisName(zaxistype, zaxisname);
       zaxisInqName(zaxisID, zname);
       zaxisInqUnits(zaxisID, zunits);
       zunits[12] = 0;
 
+      fprintf(stdout, "  %4d : ", vlistZaxisIndex(vlistID, zaxisID)+1);
+#ifdef CDO
+      set_text_color(stdout, RESET, BLUE);
+#endif
       if ( zaxistype == ZAXIS_GENERIC && ltype != 0 )
-        fprintf(stdout, "  %4d : %-12s (ltype=%3d) :", vlistZaxisIndex(vlistID, zaxisID)+1, zaxisname, ltype);
+        fprintf(stdout, "%-12s (ltype=%3d)", zaxisname, ltype);
       else
-        fprintf(stdout, "  %4d : %-24s :", vlistZaxisIndex(vlistID, zaxisID)+1, zaxisname);
+        fprintf(stdout, "%-24s", zaxisname);
+      my_reset_text_color(stdout);
 
+      fprintf(stdout, " :");
+
+#ifdef CDO
+      set_text_color(stdout, RESET, GREEN);
+#endif
       fprintf(stdout, " levels=%d", levelsize);
+      bool zscalar = (levelsize == 1) ? zaxisInqScalar(zaxisID) : false;
+      if ( zscalar ) fprintf(stdout, "  scalar");
+      my_reset_text_color(stdout);
       fprintf(stdout, "\n");
 
-      double *levels = (double*) malloc((size_t)levelsize*sizeof(double));
-      zaxisInqLevels(zaxisID, levels);
-
-      if ( !(zaxistype == ZAXIS_SURFACE && levelsize == 1 && !(fabs(levels[0]) > 0)) )
+      if ( zaxisInqLevels(zaxisID, NULL) )
         {
-          double zfirst = levels[0];
-          double zlast  = levels[levelsize-1];
-          if ( levelsize > 2 )
+          double *levels = (double*) malloc((size_t)levelsize*sizeof(double));
+          zaxisInqLevels(zaxisID, levels);
+
+          if ( !(zaxistype == ZAXIS_SURFACE && levelsize == 1 && !(fabs(levels[0]) > 0)) )
             {
-              int levelID;
-              zinc = (levels[levelsize-1] - levels[0]) / (levelsize-1);
-              for ( levelID = 2; levelID < levelsize; ++levelID )
-                if ( fabs(fabs(levels[levelID] - levels[levelID-1]) - zinc) > 0.001*zinc ) break;
+              double zfirst = levels[0];
+              double zlast  = levels[levelsize-1];
+              if ( levelsize > 2 )
+                {
+                  zinc = (levels[levelsize-1] - levels[0]) / (levelsize-1);
+                  for ( int levelID = 2; levelID < levelsize; ++levelID )
+                    if ( fabs(fabs(levels[levelID] - levels[levelID-1]) - zinc) > 0.001*zinc )
+                      {
+                        zinc = 0;
+                        break;
+                      }
+                }
 
-              if ( levelID < levelsize ) zinc = 0;
+              fprintf(stdout, "%33s : %.*g", zname, dig, zfirst);
+              if ( levelsize > 1 )
+                {
+                  fprintf(stdout, " to %.*g", dig, zlast);
+                  if ( IS_NOT_EQUAL(zinc, 0) )
+                    fprintf(stdout, " by %.*g", dig, zinc);
+                }
+              fprintf(stdout, " %s", zunits);
+              fprintf(stdout, "\n");
             }
 
-          fprintf(stdout, "%33s : %.*g", zname, dig, zfirst);
-          if ( levelsize > 1 )
-            {
-              fprintf(stdout, " to %.*g", dig, zlast);
-              if ( IS_NOT_EQUAL(zinc, 0) )
-                fprintf(stdout, " by %.*g", dig, zinc);
-            }
-          fprintf(stdout, " %s", zunits);
-          fprintf(stdout, "\n");
+          free(levels);
         }
 
-      free(levels);
-
       if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
         {
           double level1, level2;
@@ -464,9 +586,8 @@ void printZaxisInfo(int vlistID)
 
       if ( zaxistype == ZAXIS_HYBRID )
         {
-          char psname[CDI_MAX_NAME];
-          psname[0] = 0;
-          zaxisInqPsName(zaxisID, psname);
+          char psname[CDI_MAX_NAME]; psname[0] = 0;
+          cdiZaxisInqKeyStr(zaxisID, CDI_KEY_PSNAME, CDI_MAX_NAME, psname);
           int vctsize = zaxisInqVctSize(zaxisID);
           if ( vctsize || psname[0] )
             {
@@ -534,7 +655,7 @@ int printDateTime(int ntimeout, int vdate, int vtime)
 
   fprintf(stdout, " %s %s", vdatestr, vtimestr);
 
-  return (++ntimeout);
+  return ++ntimeout;
 }
 
 #define NUM_TIMESTEP 60
diff --git a/src/process.c b/src/process.c
index 422f921..8a9a423 100644
--- a/src/process.c
+++ b/src/process.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -77,7 +77,7 @@ typedef struct {
   short       streamCnt;
   argument_t *streamNames;
   char       *xoperator;
-  char       *operatorName;
+  const char *operatorName;
   char       *operatorArg;
   int         oargc;
   char       *oargv[MAX_OARGC];
@@ -304,7 +304,7 @@ const char *processInqOpername(void)
 }
 
 
-void processDefPrompt(char *opername)
+void processDefPrompt(const char *opername)
 {
   int processID = processSelf();
 
diff --git a/src/process.h b/src/process.h
index e4ff3cb..feadf97 100644
--- a/src/process.h
+++ b/src/process.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
diff --git a/src/pstream.c b/src/pstream.c
index 30ce81c..260ccf7 100644
--- a/src/pstream.c
+++ b/src/pstream.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -291,7 +291,8 @@ void pstreamOpenReadPipe(const argument_t *argument, pstream_t *pstreamptr)
 #if defined(HAVE_LIBPTHREAD)
   int pstreamID = pstreamptr->self;
 
-  char *pipename = (char*) Malloc(16);
+  size_t pnlen = 16;
+  char *pipename = (char*) Malloc(pnlen);
   // struct sched_param param;
   
   argument_t *newargument = (argument_t*) Malloc(sizeof(argument_t));
@@ -300,12 +301,12 @@ void pstreamOpenReadPipe(const argument_t *argument, pstream_t *pstreamptr)
   memcpy(newargument->argv, argument->argv, argument->argc*sizeof(char *));
 
   char *operatorArg  = argument->argv[0];
-  char *operatorName = getOperatorName(operatorArg);
+  const char *operatorName = getOperatorName(operatorArg);
 
   size_t len = strlen(argument->args);
-  char *newarg = (char*) Malloc(len+16);
+  char *newarg = (char*) Malloc(len+pnlen);
   strcpy(newarg, argument->args);
-  sprintf(pipename, "(pipe%d.%d)", processSelf() + 1, processInqChildNum() + 1);
+  snprintf(pipename, pnlen, "(pipe%d.%d)", processSelf() + 1, processInqChildNum() + 1);
   newarg[len] = ' ';
   strcpy(&newarg[len+1], pipename);
 
@@ -647,6 +648,40 @@ int pstreamOpenWritePipe(const argument_t *argument, int filetype)
 }
 
 static
+void set_comp(int fileID, int filetype)
+{
+  if ( cdoCompress )
+    {
+      if      ( filetype == CDI_FILETYPE_GRB )
+        {
+          cdoCompType  = CDI_COMPRESS_SZIP;
+          cdoCompLevel = 0;
+        }
+      else if ( filetype == CDI_FILETYPE_NC4 || filetype == CDI_FILETYPE_NC4C )
+        {
+          cdoCompType  = CDI_COMPRESS_ZIP;
+          cdoCompLevel = 1;
+        }
+    }
+
+  if ( cdoCompType != CDI_COMPRESS_NONE )
+    {
+      streamDefCompType(fileID, cdoCompType);
+      streamDefCompLevel(fileID, cdoCompLevel);
+
+      if ( cdoCompType == CDI_COMPRESS_SZIP &&
+           (filetype != CDI_FILETYPE_GRB && filetype != CDI_FILETYPE_GRB2 && filetype != CDI_FILETYPE_NC4 && filetype != CDI_FILETYPE_NC4C) )
+        cdoWarning("SZIP compression not available for non GRIB/NetCDF4 data!");
+
+      if ( cdoCompType == CDI_COMPRESS_JPEG && filetype != CDI_FILETYPE_GRB2 )
+        cdoWarning("JPEG compression not available for non GRIB2 data!");
+
+      if ( cdoCompType == CDI_COMPRESS_ZIP && (filetype != CDI_FILETYPE_NC4 && filetype != CDI_FILETYPE_NC4C) )
+        cdoWarning("Deflate compression not available for non NetCDF4 data!");
+    }
+}
+
+static
 int pstreamOpenWriteFile(const argument_t *argument, int filetype)
 {
   char *filename = (char*) Malloc(strlen(argument->args)+1);
@@ -658,7 +693,7 @@ int pstreamOpenWriteFile(const argument_t *argument, int filetype)
   
   if ( PSTREAM_Debug ) Message("file %s", argument->args);
 
-  if ( filetype == CDI_UNDEFID ) filetype = FILETYPE_GRB;
+  if ( filetype == CDI_UNDEFID ) filetype = CDI_FILETYPE_GRB;
 
   if ( cdoInteractive )
     {
@@ -695,35 +730,7 @@ int pstreamOpenWriteFile(const argument_t *argument, int filetype)
   if ( cdoDefaultByteorder != CDI_UNDEFID )
     streamDefByteorder(fileID, cdoDefaultByteorder);
 
-  if ( cdoCompress )
-    {
-      if      ( filetype == FILETYPE_GRB )
-        {
-          cdoCompType  = COMPRESS_SZIP;
-          cdoCompLevel = 0;
-        }
-      else if ( filetype == FILETYPE_NC4 || filetype == FILETYPE_NC4C )
-        {
-          cdoCompType  = COMPRESS_ZIP;
-          cdoCompLevel = 1;
-        }
-    }
-
-  if ( cdoCompType != COMPRESS_NONE )
-    {
-      streamDefCompType(fileID, cdoCompType);
-      streamDefCompLevel(fileID, cdoCompLevel);
-
-      if ( cdoCompType == COMPRESS_SZIP &&
-           (filetype != FILETYPE_GRB && filetype != FILETYPE_GRB2 && filetype != FILETYPE_NC4 && filetype != FILETYPE_NC4C) )
-        cdoWarning("SZIP compression not available for non GRIB/NetCDF4 data!");
-
-      if ( cdoCompType == COMPRESS_JPEG && filetype != FILETYPE_GRB2 )
-        cdoWarning("JPEG compression not available for non GRIB2 data!");
-
-      if ( cdoCompType == COMPRESS_ZIP && (filetype != FILETYPE_NC4 && filetype != FILETYPE_NC4C) )
-        cdoWarning("Deflate compression not available for non NetCDF4 data!");
-    }
+  set_comp(fileID, filetype);
   /*
     if ( cdoDefaultInstID != CDI_UNDEFID )
     streamDefInstID(fileID, cdoDefaultInstID);
@@ -789,19 +796,25 @@ int pstreamOpenAppend(const argument_t *argument)
       else
 	pthread_mutex_lock(&streamOpenReadMutex);
 #endif
+      
       int fileID = streamOpenAppend(argument->args);
+      
 #if defined(HAVE_LIBPTHREAD)
       if ( cdoLockIO )
 	pthread_mutex_unlock(&streamMutex);
       else
 	pthread_mutex_unlock(&streamOpenReadMutex);
 #endif
+      
       if ( processNums() == 1 && ompNumThreads == 1 ) timer_stop(timer_write);
       if ( fileID < 0 ) cdiOpenError(fileID, "Open failed on >%s<", argument->args);
       /*
       cdoInqHistory(fileID);
       cdoDefHistory(fileID, commandLine());
       */
+      int filetype = streamInqFiletype(fileID);
+      set_comp(fileID, filetype);
+      
       strcpy(filename, argument->args);
 
       pstreamptr->mode   = 'a';
@@ -1015,26 +1028,26 @@ void pstreamDefVarlist(pstream_t *pstreamptr, int vlistID)
 
       int datatype = varlist[varID].datatype;
 
-      if ( filetype == FILETYPE_NC || filetype == FILETYPE_NC2 || filetype == FILETYPE_NC4 || filetype == FILETYPE_NC4C )
+      if ( filetype == CDI_FILETYPE_NC || filetype == CDI_FILETYPE_NC2 || filetype == CDI_FILETYPE_NC4 || filetype == CDI_FILETYPE_NC4C )
 	{
-	  if ( datatype == DATATYPE_UINT8 && (filetype == FILETYPE_NC || filetype == FILETYPE_NC2) )
+	  if ( datatype == CDI_DATATYPE_UINT8 && (filetype == CDI_FILETYPE_NC || filetype == CDI_FILETYPE_NC2) )
 	    {
-	      datatype = DATATYPE_INT16;
+	      datatype = CDI_DATATYPE_INT16;
 	      varlist[varID].datatype = datatype;
 	    }
 
-	  if ( datatype == DATATYPE_UINT16 && (filetype == FILETYPE_NC || filetype == FILETYPE_NC2) )
+	  if ( datatype == CDI_DATATYPE_UINT16 && (filetype == CDI_FILETYPE_NC || filetype == CDI_FILETYPE_NC2) )
 	    {
-	      datatype = DATATYPE_INT32;
+	      datatype = CDI_DATATYPE_INT32;
 	      varlist[varID].datatype = datatype;
 	    }
 
 	  if ( laddoffset || lscalefactor )
 	    {
-	      if ( datatype == DATATYPE_INT8   ||
-		   datatype == DATATYPE_UINT8  ||
-		   datatype == DATATYPE_INT16  ||
-		   datatype == DATATYPE_UINT16 )
+	      if ( datatype == CDI_DATATYPE_INT8   ||
+		   datatype == CDI_DATATYPE_UINT8  ||
+		   datatype == CDI_DATATYPE_INT16  ||
+		   datatype == CDI_DATATYPE_UINT16 )
 		varlist[varID].check_datarange = TRUE;
 	    }
 	  else if ( cdoCheckDatarange )
@@ -1070,7 +1083,7 @@ void pstreamDefVlist(int pstreamID, int vlistID)
 	  for ( varID = 0; varID < nvars; ++varID )
 	    vlistDefVarDatatype(vlistID, varID, cdoDefaultDataType);
 
-	  if ( cdoDefaultDataType == DATATYPE_FLT64 || cdoDefaultDataType == DATATYPE_FLT32 )
+	  if ( cdoDefaultDataType == CDI_DATATYPE_FLT64 || cdoDefaultDataType == CDI_DATATYPE_FLT32 )
 	    {
 	      for ( varID = 0; varID < nvars; varID++ )
 		{
@@ -1095,11 +1108,11 @@ void pstreamDefVlist(int pstreamID, int vlistID)
         }
 
       if ( CDO_Version_Info )
-        vlistDefAttTxt(vlistID, CDI_GLOBAL, "CDO", (int)strlen(cdoComment())+1, cdoComment());
+        cdiDefAttTxt(vlistID, CDI_GLOBAL, "CDO", (int)strlen(cdoComment()), cdoComment());
 
 #if defined(_OPENMP)
       if ( ompNumThreads > 1 )
-	vlistDefAttInt(vlistID, CDI_GLOBAL, "cdo_openmp_thread_number", DATATYPE_INT32, 1, &ompNumThreads);
+	cdiDefAttInt(vlistID, CDI_GLOBAL, "cdo_openmp_thread_number", CDI_DATATYPE_INT32, 1, &ompNumThreads);
 #endif
       pstreamDefVarlist(pstreamptr, vlistID);
 
@@ -1264,8 +1277,8 @@ void pstreamCheckDatarange(pstream_t *pstreamptr, int varID, double *array, int
       double smin = (arrmin - addoffset)/scalefactor;
       double smax = (arrmax - addoffset)/scalefactor;
 
-      if ( datatype == DATATYPE_INT8  || datatype == DATATYPE_UINT8 ||
-	   datatype == DATATYPE_INT16 || datatype == DATATYPE_UINT16 )
+      if ( datatype == CDI_DATATYPE_INT8  || datatype == CDI_DATATYPE_UINT8 ||
+	   datatype == CDI_DATATYPE_INT16 || datatype == CDI_DATATYPE_UINT16 )
 	{
 	  smin = (int)lround(smin);
 	  smax = (int)lround(smax);
@@ -1273,20 +1286,20 @@ void pstreamCheckDatarange(pstream_t *pstreamptr, int varID, double *array, int
 
       double vmin = 0, vmax = 0;
 
-      if      ( datatype == DATATYPE_INT8   ) { vmin =        -128.; vmax =        127.; }
-      else if ( datatype == DATATYPE_UINT8  ) { vmin =           0.; vmax =        255.; }
-      else if ( datatype == DATATYPE_INT16  ) { vmin =      -32768.; vmax =      32767.; }
-      else if ( datatype == DATATYPE_UINT16 ) { vmin =           0.; vmax =      65535.; }
-      else if ( datatype == DATATYPE_INT32  ) { vmin = -2147483648.; vmax = 2147483647.; }
-      else if ( datatype == DATATYPE_UINT32 ) { vmin =           0.; vmax = 4294967295.; }
-      else if ( datatype == DATATYPE_FLT32  ) { vmin = -3.40282e+38; vmax = 3.40282e+38; }
+      if      ( datatype == CDI_DATATYPE_INT8   ) { vmin =        -128.; vmax =        127.; }
+      else if ( datatype == CDI_DATATYPE_UINT8  ) { vmin =           0.; vmax =        255.; }
+      else if ( datatype == CDI_DATATYPE_INT16  ) { vmin =      -32768.; vmax =      32767.; }
+      else if ( datatype == CDI_DATATYPE_UINT16 ) { vmin =           0.; vmax =      65535.; }
+      else if ( datatype == CDI_DATATYPE_INT32  ) { vmin = -2147483648.; vmax = 2147483647.; }
+      else if ( datatype == CDI_DATATYPE_UINT32 ) { vmin =           0.; vmax = 4294967295.; }
+      else if ( datatype == CDI_DATATYPE_FLT32  ) { vmin = -3.40282e+38; vmax = 3.40282e+38; }
       else                                    { vmin =     -1.e+300; vmax =     1.e+300; }
 
       if ( smin < vmin || smax > vmax )
 	cdoWarning("Some data values (min=%g max=%g) are outside the\n"
 		   "    valid range (%g - %g) of the used output precision!\n"
 		   "    Use the CDO option%s -b 64 to increase the output precision.",
-		   smin, smax, vmin, vmax, (datatype == DATATYPE_FLT32) ? "" : " -b 32 or");
+		   smin, smax, vmin, vmax, (datatype == CDI_DATATYPE_FLT32) ? "" : " -b 32 or");
     }
 }
 
@@ -1665,7 +1678,7 @@ void cdoFinish(void)
 	}
 
       if ( memmax )
-	sprintf(memstring, " %ld%c ", memmax, mu[muindex]);
+	snprintf(memstring, sizeof(memstring), " %ld%c ", memmax, mu[muindex]);
 
       processEndTime(&p_usertime, &p_systime);
       p_cputime  = p_usertime + p_systime;
diff --git a/src/pstream.h b/src/pstream.h
index 59b5c06..b76b346 100644
--- a/src/pstream.h
+++ b/src/pstream.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
diff --git a/src/pstream_int.h b/src/pstream_int.h
index 72e5501..f708ed3 100644
--- a/src/pstream_int.h
+++ b/src/pstream_int.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
diff --git a/src/pstream_write.h b/src/pstream_write.h
index fb1a595..1fefa0c 100644
--- a/src/pstream_write.h
+++ b/src/pstream_write.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
diff --git a/src/readline.c b/src/readline.c
index 41cdd5d..168ad22 100644
--- a/src/readline.c
+++ b/src/readline.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
diff --git a/src/remap.h b/src/remap.h
index ff8bb84..ce89747 100644
--- a/src/remap.h
+++ b/src/remap.h
@@ -117,19 +117,20 @@ typedef struct {
 remapgrid_t;
 
 typedef struct {
-  int      option;
+  bool     option;
   int      max_links;
   int      num_blks;
-  int*     num_links;
-  int**    src_add;
-  int**    dst_add;
-  int**    w_index;
+  int     *num_links;
+  int    **src_add;
+  int    **dst_add;
+  int    **w_index;
 }
 remaplink_t;
 
 typedef struct {
-  int      sort_add;
-  int      pinit;            /* TRUE if the pointers are initialized     */
+  int      links_per_value;
+  bool     sort_add;
+  bool     pinit;            /* true: if the pointers are initialized    */
   long     max_links;        /* current size of link arrays              */
   long     num_links;        /* actual number of links for remapping     */
   long     num_wts;          /* num of weights used in remapping         */
@@ -137,10 +138,10 @@ typedef struct {
   int      norm_opt;         /* option for normalization (conserv only)  */
   int      resize_increment; /* default amount to increase array size    */
 
-  int*     src_cell_add;     /* source grid address for each link        */
-  int*     tgt_cell_add;     /* target grid address for each link        */
+  int     *src_cell_add;     /* source grid address for each link        */
+  int     *tgt_cell_add;     /* target grid address for each link        */
 
-  double*  wts;              /* map weights for each link [max_links*num_wts] */
+  double  *wts;              /* map weights for each link [max_links*num_wts] */
 
   remaplink_t links;
 }
@@ -176,7 +177,7 @@ void remapGridFree(remapgrid_t *grid);
 void remap(double *restrict dst_array, double missval, long dst_size, long num_links, double *restrict map_wts, 
 	   long num_wts, const int *restrict dst_add, const int *restrict src_add, const double *restrict src_array, 
 	   const double *restrict src_grad1, const double *restrict src_grad2, const double *restrict src_grad3,
-	   remaplink_t links);
+	   remaplink_t links, long links_per_value);
 
 void remap_laf(double *restrict dst_array, double missval, long dst_size, long num_links, double *restrict map_wts,
 	       long num_wts, const int *restrict dst_add, const int *restrict src_add, const double *restrict src_array);
diff --git a/src/remap_conserv.c b/src/remap_conserv.c
index 113f804..4c6586f 100644
--- a/src/remap_conserv.c
+++ b/src/remap_conserv.c
@@ -301,20 +301,17 @@ static
 void boundbox_from_corners1r(long ic, long nc, const double *restrict corner_lon,
 			     const double *restrict corner_lat, restr_t *restrict bound_box)
 {
-  long inc, j;
-  restr_t clon, clat;
-
-  inc = ic*nc;
+  long inc = ic*nc;
 
-  clat = RESTR_SCALE(corner_lat[inc]);
-  clon = RESTR_SCALE(corner_lon[inc]);
+  restr_t clat = RESTR_SCALE(corner_lat[inc]);
+  restr_t clon = RESTR_SCALE(corner_lon[inc]);
 
   bound_box[0] = clat;
   bound_box[1] = clat;
   bound_box[2] = clon;
   bound_box[3] = clon;
 
-  for ( j = 1; j < nc; ++j )
+  for ( long j = 1; j < nc; ++j )
     {
       clat = RESTR_SCALE(corner_lat[inc+j]);
       clon = RESTR_SCALE(corner_lon[inc+j]);
diff --git a/src/remap_scrip_io.c b/src/remap_scrip_io.c
index fcea19c..8c7c093 100644
--- a/src/remap_scrip_io.c
+++ b/src/remap_scrip_io.c
@@ -81,7 +81,7 @@ void write_remap_scrip(const char *interp_file, int map_type, int submap_type, i
   char tgt_grid_name[64] = "dest grid";
   const char *src_grid_units = "radians";
   const char *tgt_grid_units = "radians";
-  int lgridarea = FALSE;
+  bool lgridarea = false;
   int writemode = NC_CLOBBER;
 
   switch ( rv.norm_opt )
@@ -100,7 +100,7 @@ void write_remap_scrip(const char *interp_file, int map_type, int submap_type, i
   switch ( map_type )
     {
     case MAP_TYPE_CONSERV:
-      lgridarea = TRUE;
+      lgridarea = true;
       if ( submap_type == SUBMAP_TYPE_LAF )
 	{
 	  strcpy(map_method, "Largest area fraction");
@@ -112,7 +112,7 @@ void write_remap_scrip(const char *interp_file, int map_type, int submap_type, i
 	  break;
 	}
     case MAP_TYPE_CONSERV_YAC:
-      lgridarea = TRUE;
+      lgridarea = true;
       /*
       if ( submap_type == SUBMAP_TYPE_LAF )
 	{
@@ -144,24 +144,43 @@ void write_remap_scrip(const char *interp_file, int map_type, int submap_type, i
     cdoAbort("Number of remap links is 0, no remap weights found!");
   */
   {
+    size_t nlinks = rv.num_links;
     size_t nele1 = 4*8 + 4;
     size_t nele2 = 4*8 + 4;
     if ( src_grid.lneed_cell_corners ) nele1 += src_grid.num_cell_corners*2*8;
     if ( tgt_grid.lneed_cell_corners ) nele2 += tgt_grid.num_cell_corners*2*8;
     size_t filesize = src_grid.size*(nele1) +
                       tgt_grid.size*(nele2) +
-                      rv.num_links*(4 + 4 + rv.num_wts*8);
+                      nlinks*(4 + 4 + rv.num_wts*8);
 
     if ( cdoVerbose )
-      cdoPrint("Filesize for remap weights: ~%lu", (unsigned long) filesize);
-    
+      {
+        cdoPrint("Number of remap links:       %zu", nlinks);
+        cdoPrint("Filesize for remap weights: ~%zu", filesize);
+      }
+
     if ( filesize > 0x7FFFFC00 ) // 2**31 - 1024 (<2GB)
       {
-#if defined(NC_64BIT_OFFSET)
-	writemode = NC_CLOBBER | NC_64BIT_OFFSET;
+        size_t maxlinks = 0x3FFFFFFF; // 1GB
+        if ( nlinks > maxlinks || filesize > 8*maxlinks )
+          {
+#if defined (HAVE_NETCDF4)
+            writemode |= NC_NETCDF4 | NC_CLASSIC_MODEL;
+            if ( cdoVerbose ) cdoPrint("Store weights and links to NetCDF4!");
+#else
+            cdoPrint("Number of remap links %lz exceeds maximum of %lz and NetCDF 4 not available!",
+                     nlinks, maxlinks);
+#endif
+          }
+        else
+          {
+#if defined (NC_64BIT_OFFSET)
+            writemode |= NC_64BIT_OFFSET;
+            if ( cdoVerbose ) cdoPrint("Store weights and links to NetCDF2!");
 #else
-	cdoAbort("Filesize for remap weights maybe too large!");
+            cdoPrint("Filesize for remap weights maybe too large!");
 #endif
+          }
       }
   }
 
@@ -394,7 +413,7 @@ void read_remap_scrip(const char *interp_file, int gridID1, int gridID2, int *ma
 
   // Local variables
 
-  int lgridarea = FALSE;
+  bool lgridarea = false;
   int status;
   int nc_file_id;           /* id for NetCDF file                       */
   int nc_srcgrdsize_id;     /* id for source grid size                  */
@@ -459,7 +478,8 @@ void read_remap_scrip(const char *interp_file, int gridID1, int gridID2, int *ma
   nce(nc_inq_attlen(nc_file_id, NC_GLOBAL, "normalization", &attlen));
   normalize_opt[attlen] = 0;
 
-  rv->sort_add = FALSE;
+  rv->links_per_value = -1;
+  rv->sort_add = false;
 
   if ( strcmp(normalize_opt, "none") == 0 )
     rv->norm_opt = NORM_OPT_NONE;
@@ -521,7 +541,7 @@ void read_remap_scrip(const char *interp_file, int gridID1, int gridID2, int *ma
   if ( cdoVerbose )
     cdoPrint("map_type = %s", map_method);
 
-  if ( rv->map_type == MAP_TYPE_CONSERV ) lgridarea = TRUE;
+  if ( rv->map_type == MAP_TYPE_CONSERV ) lgridarea = true;
 
   *map_type = rv->map_type;
 
@@ -625,7 +645,7 @@ void read_remap_scrip(const char *interp_file, int gridID1, int gridID2, int *ma
 
   if ( gridInqType(gridID1) == GRID_GME ) gridInqMaskGME(gridID1_gme_c, src_grid->vgpm);    
 
-  rv->pinit = TRUE;
+  rv->pinit = true;
   rv->wts = NULL;
 
   rv->max_links = rv->num_links;
@@ -769,7 +789,7 @@ void read_remap_scrip(const char *interp_file, int gridID1, int gridID2, int *ma
   cdoAbort("NetCDF support not compiled in!");
 #endif
 
-  rv->links.option    = FALSE;
+  rv->links.option    = false;
   rv->links.max_links = 0;
   rv->links.num_blks  = 0;
   rv->links.num_links = NULL;
diff --git a/src/remap_search_latbins.c b/src/remap_search_latbins.c
index 3cc896a..c1bb18c 100644
--- a/src/remap_search_latbins.c
+++ b/src/remap_search_latbins.c
@@ -241,7 +241,7 @@ long get_srch_cells(long tgt_cell_add, long nbins, int *bin_addr1, int *bin_addr
 	}
     }
 
-  return (num_srch_cells);
+  return num_srch_cells;
 }
 
 static
diff --git a/src/remaplib.c b/src/remaplib.c
index 10da6fb..084438f 100644
--- a/src/remaplib.c
+++ b/src/remaplib.c
@@ -60,12 +60,12 @@
 #include "remap_store_link_cnsrv.h"
 
 
-#define IS_REG2D_GRID(gridID)  (!gridIsRotated(gridID) && (gridInqType(gridID) == GRID_LONLAT || gridInqType(gridID) == GRID_GAUSSIAN))
+#define IS_REG2D_GRID(gridID)  (gridInqType(gridID) == GRID_LONLAT || gridInqType(gridID) == GRID_GAUSSIAN)
 
 
 
-static int  remap_gen_weights     = TRUE;
-static int  remap_write_remap     = FALSE;
+static bool remap_gen_weights     = true;
+static bool remap_write_remap     = false;
 static int  remap_num_srch_bins   = 180;
 #define  DEFAULT_MAX_ITER  100
 long remap_max_iter        = DEFAULT_MAX_ITER;  /* Max iteration count for i, j iteration */
@@ -73,10 +73,10 @@ long remap_max_iter        = DEFAULT_MAX_ITER;  /* Max iteration count for i, j
 void remap_set_int(int remapvar, int value)
 {
   if      ( remapvar == REMAP_STORE_LINK_FAST ) remap_store_link_fast = value;
-  else if ( remapvar == REMAP_WRITE_REMAP     ) remap_write_remap     = value;
+  else if ( remapvar == REMAP_WRITE_REMAP     ) remap_write_remap     = value > 0;
   else if ( remapvar == REMAP_MAX_ITER        ) remap_max_iter        = value;
   else if ( remapvar == REMAP_NUM_SRCH_BINS   ) remap_num_srch_bins   = value;
-  else if ( remapvar == REMAP_GENWEIGHTS      ) remap_gen_weights     = value;
+  else if ( remapvar == REMAP_GENWEIGHTS      ) remap_gen_weights     = value > 0;
   else      cdoAbort("Unsupported remap variable (%d)!", remapvar);
 }
 
@@ -111,26 +111,24 @@ void remapGridFree(remapgrid_t *grid)
 
 void remapVarsFree(remapvars_t *rv)
 {
-  long i, num_blks;
-
-  if ( rv->pinit == TRUE )
+  if ( rv->pinit )
     {
-      rv->pinit    = FALSE;
-      rv->sort_add = FALSE;
+      rv->pinit    = false;
+      rv->sort_add = false;
 
       if ( rv->src_cell_add ) Free(rv->src_cell_add);
       if ( rv->tgt_cell_add ) Free(rv->tgt_cell_add);
       if ( rv->wts ) Free(rv->wts);
 
-      if ( rv->links.option == TRUE )
+      if ( rv->links.option )
 	{
-	  rv->links.option = FALSE;
+	  rv->links.option = false;
 
 	  if ( rv->links.num_blks )
 	    {
 	      Free(rv->links.num_links);
-	      num_blks = rv->links.num_blks;
-	      for ( i = 0; i < num_blks; ++i )
+	      long num_blks = rv->links.num_blks;
+	      for ( long i = 0; i < num_blks; ++i )
 		{
 		  Free(rv->links.src_add[i]);
 		  Free(rv->links.dst_add[i]);
@@ -186,14 +184,12 @@ void remapgrid_init(remapgrid_t *grid)
 
 void remapgrid_alloc(int map_type, remapgrid_t *grid)
 {
-  long nalloc;
-
   if ( grid->nvgp )
     grid->vgpm   = (int*) Malloc(grid->nvgp*sizeof(int));
 
   grid->mask     = (int*) Malloc(grid->size*sizeof(int));
 
-  if ( remap_write_remap == TRUE || grid->remap_grid_type != REMAP_GRID_TYPE_REG2D )
+  if ( remap_write_remap || grid->remap_grid_type != REMAP_GRID_TYPE_REG2D )
     {
       grid->cell_center_lon = (double*) Malloc(grid->size*sizeof(double));
       grid->cell_center_lat = (double*) Malloc(grid->size*sizeof(double));
@@ -216,7 +212,7 @@ void remapgrid_alloc(int map_type, remapgrid_t *grid)
 	}
       else
 	{
-	  nalloc = grid->num_cell_corners*grid->size;
+	  long nalloc = grid->num_cell_corners*grid->size;
 
 	  grid->cell_corner_lon = (double*) Malloc(nalloc*sizeof(double));
 	  memset(grid->cell_corner_lon, 0, nalloc*sizeof(double));
@@ -331,43 +327,6 @@ void boundbox_from_center(bool lonIsCyclic, long size, long nx, long ny, const d
     }
 }
 
-static
-void check_lon_range2(long nc, long nlons, double *corners, double *centers)
-{
-  long n, k;
-
-  assert(corners != NULL);
-  /*
-#if defined(_OPENMP)
-#pragma omp parallel for default(none) shared(nlons, lons)
-#endif
-  */
-  for ( n = 0; n < nlons; ++n )
-    {
-      bool lneg = false, lpos = false;
-
-      for ( k = 0; k < nc; ++k )
-	{
- 	  if      ( !lneg && corners[n*nc+k] > -PI && corners[n*nc+k] < 0. ) lneg = true;
-	  else if ( !lpos && corners[n*nc+k] <  PI && corners[n*nc+k] > 0. ) lpos = true;
-	}
-
-      if ( lneg && lpos )
-	{
-	  if ( centers[n] > PI )
-	    for ( k = 0; k < nc; ++k ) corners[n*nc+k] += PI2;
-	}
-      else
-	{
-	  for ( k = 0; k < nc; ++k )
-	    {
-	      if ( corners[n*nc+k] > PI2  ) corners[n*nc+k] -= PI2;
-	      if ( corners[n*nc+k] < ZERO ) corners[n*nc+k] += PI2;
-	    }
-	}
-    }
-}
-
 
 void remapgrid_get_lonlat(remapgrid_t *grid, unsigned cell_add, double *plon, double *plat)
 {
@@ -387,7 +346,7 @@ void remapgrid_get_lonlat(remapgrid_t *grid, unsigned cell_add, double *plon, do
     }
 }
 
-static
+
 void check_lon_range(long nlons, double *lons)
 {
   assert(lons != NULL);
@@ -406,7 +365,7 @@ void check_lon_range(long nlons, double *lons)
     }
 }
 
-static
+
 void check_lat_range(long nlats, double *lats)
 {
   assert(lats != NULL);
@@ -463,8 +422,6 @@ void check_lat_boundbox_range(long nlats, restr_t *restrict bound_box, double *r
 static
 int expand_lonlat_grid(int gridID)
 {
-  char units[CDI_MAX_NAME];
-
   long nx = gridInqXsize(gridID);
   long ny = gridInqYsize(gridID);
   long nxp4 = nx+4;
@@ -475,14 +432,12 @@ int expand_lonlat_grid(int gridID)
   gridInqXvals(gridID, xvals+2);
   gridInqYvals(gridID, yvals+2);
 
-  int gridIDnew = gridCreate(GRID_LONLAT, nxp4*nyp4);
+  int gridtype = gridInqType(gridID);
+  int gridIDnew = gridCreate(gridtype, nxp4*nyp4);
   gridDefXsize(gridIDnew, nxp4);
   gridDefYsize(gridIDnew, nyp4);
-	      
-  gridInqXunits(gridID,    units);
-  gridDefXunits(gridIDnew, units);
-  gridInqYunits(gridID,    units);
-  gridDefYunits(gridIDnew, units);
+
+  grid_copy_attributes(gridID, gridIDnew);
 
   xvals[0] = xvals[2] - 2*gridInqXinc(gridID);
   xvals[1] = xvals[2] - gridInqXinc(gridID);
@@ -500,11 +455,11 @@ int expand_lonlat_grid(int gridID)
   Free(xvals);
   Free(yvals);
 
-  if ( gridIsRotated(gridID) )
+  if ( gridtype == GRID_PROJECTION && gridInqProjType(gridID) == CDI_PROJ_RLL )
     {
-      gridDefXpole(gridIDnew, gridInqXpole(gridID));
-      gridDefYpole(gridIDnew, gridInqYpole(gridID));
-      gridDefAngle(gridIDnew, gridInqAngle(gridID));
+      double xpole, ypole, angle;
+      gridInqParamRLL(gridID, &xpole, &ypole, &angle);
+      gridDefParamRLL(gridIDnew, xpole, ypole, angle);
     }
 
   return gridIDnew;
@@ -513,7 +468,6 @@ int expand_lonlat_grid(int gridID)
 static
 int expand_curvilinear_grid(int gridID)
 {
-  char units[CDI_MAX_NAME];
   long i, j;
 
   long gridsize = gridInqSize(gridID);
@@ -532,10 +486,7 @@ int expand_curvilinear_grid(int gridID)
   gridDefXsize(gridIDnew, nxp4);
   gridDefYsize(gridIDnew, nyp4);
 
-  gridInqXunits(gridID,   units);
-  gridDefXunits(gridIDnew, units);
-  gridInqYunits(gridID,   units);
-  gridDefYunits(gridIDnew, units);
+  grid_copy_attributes(gridID, gridIDnew);
 
   for ( j = ny-1; j >= 0; j-- )
     for ( i = nx-1; i >= 0; i-- )
@@ -610,8 +561,6 @@ void grid_check_lat_borders_rad(int n, double *ybounds)
 static
 void remap_define_reg2d(int gridID, remapgrid_t *grid)
 {
-  char unitstr[CDI_MAX_NAME];
-
   long nx = grid->dims[0];
   long ny = grid->dims[1];
 
@@ -633,10 +582,11 @@ void remap_define_reg2d(int gridID, remapgrid_t *grid)
 
   /* Convert lat/lon units if required */
 
-  gridInqYunits(gridID, unitstr);
+  char yunits[CDI_MAX_NAME]; yunits[0] = 0;
+  cdiGridInqKeyStr(gridID, CDI_KEY_YUNITS, CDI_MAX_NAME, yunits);
 
-  grid_to_radian(unitstr, nx, grid->reg2d_center_lon, "grid reg2d center lon"); 
-  grid_to_radian(unitstr, ny, grid->reg2d_center_lat, "grid reg2d center lat"); 
+  grid_to_radian(yunits, nx, grid->reg2d_center_lon, "grid reg2d center lon"); 
+  grid_to_radian(yunits, ny, grid->reg2d_center_lat, "grid reg2d center lat"); 
 
   if ( grid->is_cyclic ) grid->reg2d_center_lon[nx] = grid->reg2d_center_lon[0] + PI2;
 
@@ -655,12 +605,8 @@ void remap_define_reg2d(int gridID, remapgrid_t *grid)
 static
 void remap_define_grid(int map_type, int gridID, remapgrid_t *grid, const char *txt)
 {
-  char xunitstr[CDI_MAX_NAME];
-  char yunitstr[CDI_MAX_NAME];
-  long gridsize;
-  long i;
-  int lgrid_destroy = FALSE;
-  int lgrid_gen_bounds = FALSE;
+  bool lgrid_destroy = false;
+  bool lgrid_gen_bounds = false;
   int gridID_gme = -1;
 
   if ( gridInqType(grid->gridID) != GRID_UNSTRUCTURED && gridInqType(grid->gridID) != GRID_CURVILINEAR )
@@ -673,15 +619,15 @@ void remap_define_grid(int map_type, int gridID, remapgrid_t *grid, const char *
 	  gridCompress(gridID);
 	  grid->luse_cell_corners = true;
 	}
-      else if ( remap_write_remap == TRUE || grid->remap_grid_type != REMAP_GRID_TYPE_REG2D )
+      else if ( remap_write_remap || grid->remap_grid_type != REMAP_GRID_TYPE_REG2D )
 	{
-	  lgrid_destroy = TRUE;
+	  lgrid_destroy = true;
 	  gridID = gridToCurvilinear(grid->gridID, 1);
-	  lgrid_gen_bounds = TRUE;
+	  lgrid_gen_bounds = true;
 	}
     }
 
-  gridsize = grid->size = gridInqSize(gridID);
+  long gridsize = grid->size = gridInqSize(gridID);
 
   grid->dims[0] = gridInqXsize(gridID);
   grid->dims[1] = gridInqYsize(gridID);
@@ -691,37 +637,31 @@ void remap_define_grid(int map_type, int gridID, remapgrid_t *grid, const char *
       if ( grid->dims[1] == 0 ) cdoAbort("%s grid without latitude coordinates!", gridNamePtr(gridInqType(grid->gridID)));
     }
 
-  grid->is_cyclic = gridIsCircular(gridID) ? true : false;
+  grid->is_cyclic = (gridIsCircular(gridID) > 0);
 
-  if ( gridInqType(gridID) == GRID_UNSTRUCTURED )
-    grid->rank = 1;
-  else
-    grid->rank = 2;
+  grid->rank = (gridInqType(gridID) == GRID_UNSTRUCTURED) ? 1 : 2;
 
-  if ( gridInqType(gridID) == GRID_UNSTRUCTURED )
-    grid->num_cell_corners = gridInqNvertex(gridID);
-  else
-    grid->num_cell_corners = 4;
+  grid->num_cell_corners = (gridInqType(gridID) == GRID_UNSTRUCTURED) ? gridInqNvertex(gridID) : 4;
 
- remapgrid_alloc(map_type, grid);
+  remapgrid_alloc(map_type, grid);
 
   /* Initialize logical mask */
 
 #if defined(_OPENMP)
 #pragma omp parallel for default(none) shared(gridsize, grid)
 #endif
-  for ( i = 0; i < gridsize; ++i ) grid->mask[i] = TRUE;
+  for ( long i = 0; i < gridsize; ++i ) grid->mask[i] = TRUE;
 
   if ( gridInqMask(gridID, NULL) )
     {
       int *mask = (int*) Malloc(gridsize*sizeof(int));
       gridInqMask(gridID, mask);
-      for ( i = 0; i < gridsize; ++i )
+      for ( long i = 0; i < gridsize; ++i )
 	if ( mask[i] == 0 ) grid->mask[i] = FALSE;
       Free(mask);
     }
 
-  if ( remap_write_remap == FALSE && grid->remap_grid_type == REMAP_GRID_TYPE_REG2D ) return;
+  if ( !remap_write_remap && grid->remap_grid_type == REMAP_GRID_TYPE_REG2D ) return;
 
   if ( !(gridInqXvals(gridID, NULL) && gridInqYvals(gridID, NULL)) )
     cdoAbort("%s grid cell center coordinates missing!", txt);
@@ -729,9 +669,10 @@ void remap_define_grid(int map_type, int gridID, remapgrid_t *grid, const char *
   gridInqXvals(gridID, grid->cell_center_lon);
   gridInqYvals(gridID, grid->cell_center_lat);
 
-  gridInqXunits(gridID, xunitstr);
-  gridInqYunits(gridID, yunitstr);
-
+  char xunits[CDI_MAX_NAME]; xunits[0] = 0;
+  char yunits[CDI_MAX_NAME]; yunits[0] = 0;
+  cdiGridInqKeyStr(gridID, CDI_KEY_XUNITS, CDI_MAX_NAME, xunits);
+  cdiGridInqKeyStr(gridID, CDI_KEY_YUNITS, CDI_MAX_NAME, yunits);
 
   if ( grid->lneed_cell_corners )
     {
@@ -742,8 +683,8 @@ void remap_define_grid(int map_type, int gridID, remapgrid_t *grid, const char *
 	}
       else if ( lgrid_gen_bounds )
 	{
-	  grid_cell_center_to_bounds_X2D(xunitstr, grid->dims[0], grid->dims[1], grid->cell_center_lon, grid->cell_corner_lon, 0);
-	  grid_cell_center_to_bounds_Y2D(yunitstr, grid->dims[0], grid->dims[1], grid->cell_center_lat, grid->cell_corner_lat);
+	  grid_cell_center_to_bounds_X2D(xunits, grid->dims[0], grid->dims[1], grid->cell_center_lon, grid->cell_corner_lon, 0);
+	  grid_cell_center_to_bounds_Y2D(yunits, grid->dims[0], grid->dims[1], grid->cell_center_lat, grid->cell_corner_lat);
 	}
       else
 	{
@@ -756,13 +697,13 @@ void remap_define_grid(int map_type, int gridID, remapgrid_t *grid, const char *
 
   /* Convert lat/lon units if required */
 
-  grid_to_radian(xunitstr, grid->size, grid->cell_center_lon, "grid center lon"); 
-  grid_to_radian(yunitstr, grid->size, grid->cell_center_lat, "grid center lat"); 
+  grid_to_radian(xunits, grid->size, grid->cell_center_lon, "grid center lon"); 
+  grid_to_radian(yunits, grid->size, grid->cell_center_lat, "grid center lat"); 
   /* Note: using units from cell center instead from bounds */
   if ( grid->num_cell_corners && grid->lneed_cell_corners )
     {
-      grid_to_radian(xunitstr, grid->num_cell_corners*grid->size, grid->cell_corner_lon, "grid corner lon"); 
-      grid_to_radian(yunitstr, grid->num_cell_corners*grid->size, grid->cell_corner_lat, "grid corner lat"); 
+      grid_to_radian(xunits, grid->num_cell_corners*grid->size, grid->cell_corner_lon, "grid corner lon"); 
+      grid_to_radian(yunits, grid->num_cell_corners*grid->size, grid->cell_corner_lat, "grid corner lat"); 
     }
 
   if ( lgrid_destroy ) gridDestroy(gridID);
@@ -772,10 +713,8 @@ void remap_define_grid(int map_type, int gridID, remapgrid_t *grid, const char *
   check_lon_range(grid->size, grid->cell_center_lon);
 
   if ( grid->num_cell_corners && grid->lneed_cell_corners )
-    {
-      //check_lon_range2(grid->num_cell_corners, grid->size, grid->cell_corner_lon, grid->cell_center_lon);
-	check_lon_range(grid->num_cell_corners*grid->size, grid->cell_corner_lon);
-    }
+    check_lon_range(grid->num_cell_corners*grid->size, grid->cell_corner_lon);
+
   /*  Make sure input latitude range is within the machine values for +/- pi/2 */
 
   check_lat_range(grid->size, grid->cell_center_lat);
@@ -821,12 +760,10 @@ void cell_bounding_boxes(remapgrid_t *grid, int remap_grid_basis)
     }
   else if ( remap_grid_basis == REMAP_GRID_BASIS_SRC )
     {
-      long nx, ny;
-
       if ( grid->rank != 2 ) cdoAbort("Internal problem, grid rank = %d!", grid->rank);
 
-      nx = grid->dims[0];
-      ny = grid->dims[1];
+      long nx = grid->dims[0];
+      long ny = grid->dims[1];
 
       if ( cdoVerbose ) cdoPrint("Grid: boundbox_from_center");
 
@@ -846,7 +783,6 @@ void cell_bounding_boxes(remapgrid_t *grid, int remap_grid_basis)
 
 void remap_grids_init(int map_type, bool lextrapolate, int gridID1, remapgrid_t *src_grid, int gridID2, remapgrid_t *tgt_grid)
 {
-  int lbounds = TRUE;
   int reg2d_src_gridID = gridID1;
   int reg2d_tgt_gridID = gridID2;
 
@@ -867,7 +803,7 @@ void remap_grids_init(int map_type, bool lextrapolate, int gridID1, remapgrid_t
       // else src_grid->remap_grid_type = -1;
     }
 
-  if ( remap_gen_weights == FALSE && IS_REG2D_GRID(gridID2) && tgt_grid->remap_grid_type != REMAP_GRID_TYPE_REG2D )
+  if ( !remap_gen_weights && IS_REG2D_GRID(gridID2) && tgt_grid->remap_grid_type != REMAP_GRID_TYPE_REG2D )
     {
       if ( map_type == MAP_TYPE_DISTWGT ) tgt_grid->remap_grid_type = REMAP_GRID_TYPE_REG2D;
       if ( map_type == MAP_TYPE_BILINEAR && src_grid->remap_grid_type == REMAP_GRID_TYPE_REG2D ) tgt_grid->remap_grid_type = REMAP_GRID_TYPE_REG2D;
@@ -898,7 +834,7 @@ void remap_grids_init(int map_type, bool lextrapolate, int gridID1, remapgrid_t
 
   if ( !src_grid->lextrapolate && gridInqSize(src_grid->gridID) > 1 &&
        map_type == MAP_TYPE_DISTWGT &&
-       ((gridInqType(gridID1) == GRID_LONLAT && gridIsRotated(gridID1)) ||
+       ((gridInqType(gridID1) == GRID_PROJECTION && gridInqProjType(gridID1) == CDI_PROJ_RLL) ||
 	(gridInqType(gridID1) == GRID_LONLAT && src_grid->non_global)) )
     {
       src_grid->gridID = gridID1 = expand_lonlat_grid(gridID1);
@@ -929,11 +865,13 @@ void remap_grids_init(int map_type, bool lextrapolate, int gridID1, remapgrid_t
 	}
     }
 
-  if ( gridInqSize(src_grid->gridID) > 1 && 
-       (gridInqType(src_grid->gridID) == GRID_LCC || 
-	gridInqType(src_grid->gridID) == GRID_LAEA || 
-	gridInqType(src_grid->gridID) == GRID_SINUSOIDAL) )
+  int sgridID = src_grid->gridID;
+  if ( gridInqSize(sgridID) > 1 && 
+       (gridInqType(sgridID) == GRID_LCC || 
+	(gridInqType(sgridID) == GRID_PROJECTION && gridInqProjType(sgridID) == CDI_PROJ_LAEA) || 
+	(gridInqType(sgridID) == GRID_PROJECTION && gridInqProjType(sgridID) == CDI_PROJ_SINU)) )
     {
+      int lbounds = TRUE;
       src_grid->gridID = gridID1 = gridToCurvilinear(src_grid->gridID, lbounds);
     }
 
@@ -983,9 +921,9 @@ void remap_grids_init(int map_type, bool lextrapolate, int gridID1, remapgrid_t
 void remap_vars_init(int map_type, long src_grid_size, long tgt_grid_size, remapvars_t *rv)
 {
   /* Initialize all pointer */
-  if ( rv->pinit == FALSE )
+  if ( rv->pinit == false )
     {
-      rv->pinit = TRUE;
+      rv->pinit = true;
 
       rv->src_cell_add = NULL;
       rv->tgt_cell_add = NULL;
@@ -997,21 +935,21 @@ void remap_vars_init(int map_type, long src_grid_size, long tgt_grid_size, remap
 #if defined(_OPENMP)
   if ( ompNumThreads > 1 )
     {
-      if      ( map_type == MAP_TYPE_CONSERV     ) rv->sort_add = TRUE;
-      else if ( map_type == MAP_TYPE_CONSERV_YAC ) rv->sort_add = FALSE;
-      else if ( map_type == MAP_TYPE_BILINEAR    ) rv->sort_add = FALSE;
-      else if ( map_type == MAP_TYPE_BICUBIC     ) rv->sort_add = FALSE;
-      else if ( map_type == MAP_TYPE_DISTWGT     ) rv->sort_add = FALSE;
+      if      ( map_type == MAP_TYPE_CONSERV     ) rv->sort_add = true;
+      else if ( map_type == MAP_TYPE_CONSERV_YAC ) rv->sort_add = false;
+      else if ( map_type == MAP_TYPE_BILINEAR    ) rv->sort_add = false;
+      else if ( map_type == MAP_TYPE_BICUBIC     ) rv->sort_add = false;
+      else if ( map_type == MAP_TYPE_DISTWGT     ) rv->sort_add = false;
       else cdoAbort("Unknown mapping method!");
     }
   else
 #endif
     {
-      if      ( map_type == MAP_TYPE_CONSERV     ) rv->sort_add = TRUE;
-      else if ( map_type == MAP_TYPE_CONSERV_YAC ) rv->sort_add = FALSE;
-      else if ( map_type == MAP_TYPE_BILINEAR    ) rv->sort_add = FALSE;
-      else if ( map_type == MAP_TYPE_BICUBIC     ) rv->sort_add = FALSE;
-      else if ( map_type == MAP_TYPE_DISTWGT     ) rv->sort_add = FALSE;
+      if      ( map_type == MAP_TYPE_CONSERV     ) rv->sort_add = true;
+      else if ( map_type == MAP_TYPE_CONSERV_YAC ) rv->sort_add = false;
+      else if ( map_type == MAP_TYPE_BILINEAR    ) rv->sort_add = false;
+      else if ( map_type == MAP_TYPE_BICUBIC     ) rv->sort_add = false;
+      else if ( map_type == MAP_TYPE_DISTWGT     ) rv->sort_add = false;
       else cdoAbort("Unknown mapping method!");
     }
 
@@ -1022,6 +960,8 @@ void remap_vars_init(int map_type, long src_grid_size, long tgt_grid_size, remap
   else if ( map_type == MAP_TYPE_DISTWGT     ) rv->num_wts = 1;
   else cdoAbort("Unknown mapping method!");
 
+  rv->links_per_value = -1;
+
    /*
     Initialize num_links and set max_links to four times the largest 
     of the destination grid sizes initially (can be changed later).
@@ -1042,7 +982,7 @@ void remap_vars_init(int map_type, long src_grid_size, long tgt_grid_size, remap
       rv->wts = (double*) Malloc(rv->num_wts*rv->max_links*sizeof(double));
     }
 
-  rv->links.option    = FALSE;
+  rv->links.option    = false;
   rv->links.max_links = 0;
   rv->links.num_blks  = 0;
   rv->links.num_links = NULL;
@@ -1088,7 +1028,7 @@ void resize_remap_vars(remapvars_t *rv, int increment)
 void remap(double *restrict dst_array, double missval, long dst_size, long num_links, double *restrict map_wts, 
 	   long num_wts, const int *restrict dst_add, const int *restrict src_add, const double *restrict src_array, 
 	   const double *restrict src_grad1, const double *restrict src_grad2, const double *restrict src_grad3,
-	   remaplink_t links)
+	   remaplink_t links, long links_per_value)
 {
   /*
     Input arrays:
@@ -1113,59 +1053,100 @@ void remap(double *restrict dst_array, double missval, long dst_size, long num_l
     double *dst_array    ! array for remapped field on destination grid
   */
 
-  /* Local variables */
-  long n;
-  int iorder;
   extern int timer_remap;
 
-  /* Check the order of the interpolation */
+  // Check the order of the interpolation
 
-  if ( src_grad1 )
-    iorder = 2;
-  else
-    iorder = 1;
+  int iorder = (src_grad1 == NULL) ? 1 : 2;
 
-  for ( n = 0; n < dst_size; ++n ) dst_array[n] = missval;
+  for ( long n = 0; n < dst_size; ++n ) dst_array[n] = missval;
 
   if ( cdoTimer ) timer_start(timer_remap);
 
+  if ( iorder == 1 )   // First order remapping
+    {
+      if ( links.option )
+	{
 #ifdef SX
 #pragma cdir nodep
 #endif
-  for ( n = 0; n < num_links; ++n ) dst_array[dst_add[n]] = 0.;
+          for ( long n = 0; n < num_links; ++n ) dst_array[dst_add[n]] = 0.;
 
-  if ( iorder == 1 )   /* First order remapping */
-    {
-      if ( links.option == TRUE )
-	{
-	  long j;
-	  for ( j = 0; j < links.num_blks; ++j )
+	  for ( long j = 0; j < links.num_blks; ++j )
 	    {
-#ifdef SX
-#pragma cdir nodep
+              const int *restrict dst_addx = links.dst_add[j];
+              const int *restrict src_addx = links.src_add[j];
+              const int *restrict windex = links.w_index[j];
+
+#if defined(HAVE_OPENMP4)
+#pragma omp simd
 #endif
-	      for ( n = 0; n < links.num_links[j]; ++n )
+	      for ( long n = 0; n < links.num_links[j]; ++n )
 		{
-		  dst_array[links.dst_add[j][n]] += src_array[links.src_add[j][n]]*map_wts[num_wts*links.w_index[j][n]];
+		  dst_array[dst_addx[n]] += src_array[src_addx[n]]*map_wts[num_wts*windex[n]];
 		}
 	    }
 	}
       else
 	{
-	  for ( n = 0; n < num_links; ++n )
-	    {
-	      /*
-		printf("%5d %5d %5d %g # dst_add src_add n\n", dst_add[n], src_add[n], n, map_wts[num_wts*n]);
-	      */
-	      dst_array[dst_add[n]] += src_array[src_add[n]]*map_wts[num_wts*n];
-	    }
+          long lpv = links_per_value;
+          if ( lpv > 0 )
+            {
+              long nlinks = num_links/lpv;
+
+              if ( lpv == 4 )
+                {
+#if defined(_OPENMP)
+#pragma omp parallel for default(none)  shared(dst_array, src_array, dst_add, src_add, map_wts, num_wts, nlinks, lpv)
+#endif
+                  for ( long n = 0; n < nlinks; ++n )
+                    {
+                      long noff = n*lpv;
+                      dst_array[dst_add[noff]] = src_array[src_add[noff]]*map_wts[num_wts*(noff)] +
+                                                 src_array[src_add[noff+1]]*map_wts[num_wts*(noff+1)] +
+                                                 src_array[src_add[noff+2]]*map_wts[num_wts*(noff+2)] +
+                                                 src_array[src_add[noff+3]]*map_wts[num_wts*(noff+3)];
+                    }
+                }
+              else
+                {
+#if defined(_OPENMP)
+#pragma omp parallel for default(none)  shared(dst_array, src_array, dst_add, src_add, map_wts, num_wts, nlinks, lpv)
+#endif
+                  for ( long n = 0; n < nlinks; ++n )
+                    {
+                      long noff = n*lpv;
+                      dst_array[dst_add[noff]] = src_array[src_add[noff]]*map_wts[num_wts*noff];
+                      for ( long k = 1; k < lpv; ++k )
+                        dst_array[dst_add[noff]] += src_array[src_add[noff+k]]*map_wts[num_wts*(noff+k)];
+                    }
+                }
+            }
+          else
+            {
+#ifdef SX
+#pragma cdir nodep
+#endif
+              for ( long n = 0; n < num_links; ++n ) dst_array[dst_add[n]] = 0.;
+
+              for ( long n = 0; n < num_links; ++n )
+                {
+                  // printf("%5d %5d %5ld %g # dst_add src_add n\n", dst_add[n], src_add[n], n, map_wts[num_wts*n]);
+                  dst_array[dst_add[n]] += src_array[src_add[n]]*map_wts[num_wts*n];
+                }
+            }
 	}
     }
-  else                 /* Second order remapping */
+  else                 // Second order remapping
     {
+#ifdef SX
+#pragma cdir nodep
+#endif
+      for ( long n = 0; n < num_links; ++n ) dst_array[dst_add[n]] = 0.;
+
       if ( num_wts == 3 )
 	{
-	  for ( n = 0; n < num_links; ++n )
+	  for ( long n = 0; n < num_links; ++n )
 	    {
 	      dst_array[dst_add[n]] += src_array[src_add[n]]*map_wts[3*n] +
                                        src_grad1[src_add[n]]*map_wts[3*n+1] +
@@ -1174,7 +1155,7 @@ void remap(double *restrict dst_array, double missval, long dst_size, long num_l
 	}
       else if ( num_wts == 4 )
 	{
-      	  for ( n = 0; n < num_links; ++n )
+      	  for ( long n = 0; n < num_links; ++n )
 	    {
               dst_array[dst_add[n]] += src_array[src_add[n]]*map_wts[4*n] +
                                        src_grad1[src_add[n]]*map_wts[4*n+1] +
@@ -1190,17 +1171,13 @@ void remap(double *restrict dst_array, double missval, long dst_size, long num_l
 static
 long get_max_add(long num_links, long size, const int *restrict add)
 {
-  long n, i;
-  long max_add;
-  int *isum;
-
-  isum = (int*) Malloc(size*sizeof(int));
+  int *isum = (int*) Malloc(size*sizeof(int));
   memset(isum, 0, size*sizeof(int));
 
-  for ( n = 0; n < num_links; ++n ) isum[add[n]]++;
+  for ( long n = 0; n < num_links; ++n ) isum[add[n]]++;
 
-  max_add = 0;
-  for ( i = 0; i < size; ++i ) if ( isum[i] > max_add ) max_add = isum[i];
+  long max_add = 0;
+  for ( long i = 0; i < size; ++i ) if ( isum[i] > max_add ) max_add = isum[i];
   Free(isum);
 
   return (max_add);
@@ -1256,50 +1233,43 @@ void remap_laf(double *restrict dst_array, double missval, long dst_size, long n
   */
 
   /* Local variables */
-  long i, n, k, ncls, imax;
-  long max_cls;
-  double wts;
-  double *src_cls;
-  double *src_wts;
-#if defined(_OPENMP)
-  double **src_cls2;
-  double **src_wts2;
-#endif
+  long n, k;
 
-  for ( i = 0; i < dst_size; ++i ) dst_array[i] = missval;
+  for ( long i = 0; i < dst_size; ++i ) dst_array[i] = missval;
 
   if ( num_links == 0 ) return;
 
-  max_cls = get_max_add(num_links, dst_size, dst_add);
+  long max_cls = get_max_add(num_links, dst_size, dst_add);
 
 #if defined(_OPENMP)
-  src_cls2 = (double **) Malloc(ompNumThreads*sizeof(double *));
-  src_wts2 = (double **) Malloc(ompNumThreads*sizeof(double *));
-  for ( i = 0; i < ompNumThreads; ++i )
+  double **src_cls2 = (double **) Malloc(ompNumThreads*sizeof(double *));
+  double **src_wts2 = (double **) Malloc(ompNumThreads*sizeof(double *));
+  for ( long i = 0; i < ompNumThreads; ++i )
     {
       src_cls2[i] = (double*) Malloc(max_cls*sizeof(double));
       src_wts2[i] = (double*) Malloc(max_cls*sizeof(double));
     }
 #else
-  src_cls = (double*) Malloc(max_cls*sizeof(double));
-  src_wts = (double*) Malloc(max_cls*sizeof(double));
+  double *src_cls = (double*) Malloc(max_cls*sizeof(double));
+  double *src_wts = (double*) Malloc(max_cls*sizeof(double));
 #endif
 
-  for ( n = 0; n < num_links; ++n )
+  for ( long n = 0; n < num_links; ++n )
     if ( DBL_IS_EQUAL(dst_array[dst_add[n]], missval) ) dst_array[dst_add[n]] = ZERO;
 
 #if defined(_OPENMP)
 #pragma omp parallel for default(none) \
-  shared(dst_size, src_cls2, src_wts2, num_links, dst_add, src_add, src_array, map_wts, num_wts, dst_array, max_cls)					\
-  private(n, k, src_cls, src_wts, ncls, imax, wts) \
+  shared(dst_size, src_cls2, src_wts2, num_links, dst_add, src_add, src_array, map_wts, num_wts, dst_array, max_cls)  \
+  private(n, k) \
   schedule(dynamic,1)
 #endif
-  for ( i = 0; i < dst_size; ++i )
+  for ( long i = 0; i < dst_size; ++i )
     {
+      long ncls;
 #if defined(_OPENMP)
       int ompthID = cdo_omp_get_thread_num();
-      src_cls = src_cls2[ompthID];
-      src_wts = src_wts2[ompthID];
+      double *src_cls = src_cls2[ompthID];
+      double *src_wts = src_wts2[ompthID];
 #endif
       memset(src_cls, 0, max_cls*sizeof(double));
       memset(src_wts, 0, max_cls*sizeof(double));
@@ -1361,8 +1331,8 @@ void remap_laf(double *restrict dst_array, double missval, long dst_size, long n
       
       if ( ncls )
 	{
-	  imax = 0;
-	  wts = src_wts[0];
+	  long imax = 0;
+	  double wts = src_wts[0];
 	  for ( k = 1; k < ncls; ++k )
 	    {
 	      if ( src_wts[k] > wts )
@@ -1377,7 +1347,7 @@ void remap_laf(double *restrict dst_array, double missval, long dst_size, long n
     }
 
 #if defined(_OPENMP)
-  for ( i = 0; i < ompNumThreads; ++i )
+  for ( long i = 0; i < ompNumThreads; ++i )
     {
       Free(src_cls2[i]);
       Free(src_wts2[i]);
@@ -1410,25 +1380,22 @@ void remap_sum(double *restrict dst_array, double missval, long dst_size, long n
     int num_wts          ! num of weights used in remapping
 
     double *map_wts      ! remapping weights for each link
-
     double *src_array    ! array with source field to be remapped
 
     output variables:
 
     double *dst_array    ! array for remapped field on destination grid
   */
-  /* Local variables */
-  long n;
 
-  for ( n = 0; n < dst_size; ++n ) dst_array[n] = missval;
+  for ( long n = 0; n < dst_size; ++n ) dst_array[n] = missval;
 
 #ifdef SX
 #pragma cdir nodep
 #endif
-  for ( n = 0; n < num_links; ++n )
+  for ( long n = 0; n < num_links; ++n )
     if ( DBL_IS_EQUAL(dst_array[dst_add[n]], missval) ) dst_array[dst_add[n]] = ZERO;
 
-  for ( n = 0; n < num_links; ++n )
+  for ( long n = 0; n < num_links; ++n )
     {
       /*
 	printf("%5d %5d %5d %g # dst_add src_add n\n", dst_add[n], src_add[n], n, map_wts[num_wts*n]);
@@ -1444,22 +1411,18 @@ void remap_sum(double *restrict dst_array, double missval, long dst_size, long n
 
 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)
-{
-  long n, ns, i;
-  long idiff, imax, imin, icount;
-  int *tgt_count;
-	  
+{	  
   if ( remap_order == 2 )
     cdoPrint("Second order mapping from grid1 to grid2:");
   else
     cdoPrint("First order mapping from grid1 to grid2:");
   cdoPrint("----------------------------------------");
 
-  ns = 0;
+  long ns = 0;
   double sum = 0;
   double minval =  DBL_MAX;
   double maxval = -DBL_MAX;
-  for ( n = 0; n < src_grid.size; ++n )
+  for ( long n = 0; n < src_grid.size; ++n )
     {
       if ( !DBL_IS_EQUAL(array1[n], missval) )
 	{
@@ -1476,7 +1439,7 @@ void remap_stat(int remap_order, remapgrid_t src_grid, remapgrid_t tgt_grid, rem
   sum = 0;
   minval =  DBL_MAX;
   maxval = -DBL_MAX;
-  for ( n = 0; n < tgt_grid.size; ++n )
+  for ( long n = 0; n < tgt_grid.size; ++n )
     {
       if ( !DBL_IS_EQUAL(array2[n], missval) )
 	{
@@ -1495,13 +1458,13 @@ void remap_stat(int remap_order, remapgrid_t src_grid, remapgrid_t tgt_grid, rem
     {
       cdoPrint("Conservation:");
       sum = 0;
-      for ( n = 0; n < src_grid.size; ++n )
+      for ( long n = 0; n < src_grid.size; ++n )
 	if ( !DBL_IS_EQUAL(array1[n], missval) )
 	  sum += array1[n]*src_grid.cell_area[n]*src_grid.cell_frac[n];
       cdoPrint("Grid1 Integral = %g", sum);
 
       sum = 0;
-      for ( n = 0; n < tgt_grid.size; ++n )
+      for ( long n = 0; n < tgt_grid.size; ++n )
 	if ( !DBL_IS_EQUAL(array2[n], missval) )
 	  sum += array2[n]*tgt_grid.cell_area[n]*tgt_grid.cell_frac[n];
       cdoPrint("Grid2 Integral = %g", sum);
@@ -1513,48 +1476,51 @@ void remap_stat(int remap_order, remapgrid_t src_grid, remapgrid_t tgt_grid, rem
       */
     }
 
-  cdoPrint("number of sparse matrix entries %d", rv.num_links);
-  cdoPrint("total number of dest cells %d", tgt_grid.size);
+  cdoPrint("Number of weights %d", rv.num_wts);
+  cdoPrint("Number of sparse matrix entries %d", rv.num_links);
+  cdoPrint("Total number of dest cells %d", tgt_grid.size);
 
-  tgt_count = (int*) Malloc(tgt_grid.size*sizeof(int));
+  int *tgt_count = (int*) Malloc(tgt_grid.size*sizeof(int));
 
-  for ( n = 0; n < tgt_grid.size; ++n ) tgt_count[n] = 0;
+  for ( long n = 0; n < tgt_grid.size; ++n ) tgt_count[n] = 0;
 
 #if defined(SX)
 #pragma vdir nodep
 #endif
-  for ( n = 0; n < rv.num_links; ++n ) tgt_count[rv.tgt_cell_add[n]]++;
+  for ( long n = 0; n < rv.num_links; ++n ) tgt_count[rv.tgt_cell_add[n]]++;
 
-  imin = INT_MAX;
-  imax = INT_MIN;
-  for ( n = 0; n < tgt_grid.size; ++n )
+  long imin = INT_MAX;
+  long imax = INT_MIN;
+  for ( long n = 0; n < tgt_grid.size; ++n )
     {
       if ( tgt_count[n] > 0 )
-	if ( tgt_count[n] < imin ) imin = tgt_count[n];
-      if ( tgt_count[n] > imax ) imax = tgt_count[n];
+        {
+          if ( tgt_count[n] < imin ) imin = tgt_count[n];
+          if ( tgt_count[n] > imax ) imax = tgt_count[n];
+        }
     }
 
-  idiff =  (imax - imin)/10 + 1;
-  icount = 0;
-  for ( i = 0; i < tgt_grid.size; ++i )
+  long idiff =  (imax - imin)/10 + 1;
+  long icount = 0;
+  for ( long i = 0; i < tgt_grid.size; ++i )
     if ( tgt_count[i] > 0 ) icount++;
 
-  cdoPrint("number of cells participating in remap %d", icount);
+  cdoPrint("Number of cells participating in remap %d", icount);
 
   if ( icount )
     {
-      cdoPrint("min no of entries/row = %d", imin);
-      cdoPrint("max no of entries/row = %d", imax);
+      cdoPrint("Min no of entries/row = %d", imin);
+      cdoPrint("Max no of entries/row = %d", imax);
 
       imax = imin + idiff;
-      for ( n = 0; n < 10; ++n )
+      for ( long n = 0; n < 10; ++n )
 	{
 	  icount = 0;
-	  for ( i = 0; i < tgt_grid.size; ++i )
+	  for ( long i = 0; i < tgt_grid.size; ++i )
 	    if ( tgt_count[i] >= imin && tgt_count[i] < imax ) icount++;
 
 	  if ( icount )
-	    cdoPrint("num of rows with entries between %d - %d  %d", imin, imax-1, icount);
+	    cdoPrint("Num of rows with entries between %d - %d  %d", imin, imax-1, icount);
 
 	  imin = imin + idiff;
 	  imax = imax + idiff;
@@ -1563,8 +1529,7 @@ void remap_stat(int remap_order, remapgrid_t src_grid, remapgrid_t tgt_grid, rem
 
   Free(tgt_count);
 
-  if ( rv.sort_add )
-    cdoPrint("Sparse matrix entries are explicitly sorted.");
+  if ( rv.sort_add ) cdoPrint("Sparse matrix entries are explicitly sorted.");
 
 } /* remap_stat */
 
@@ -1573,7 +1538,6 @@ void remap_stat(int remap_order, remapgrid_t src_grid, remapgrid_t tgt_grid, rem
 void remap_gradients(remapgrid_t grid, const double *restrict array, double *restrict grad_lat,
 		     double *restrict grad_lon, double *restrict grad_latlon)
 {
-  long nx, ny, grid_size;
   long i, j, ip1, im1, jp1, jm1, in, is, ie, iw, ine, inw, ise, isw;
   double delew, delns;
   double grad_lat_zero, grad_lon_zero;
@@ -1581,9 +1545,9 @@ void remap_gradients(remapgrid_t grid, const double *restrict array, double *res
   if ( grid.rank != 2 )
     cdoAbort("Internal problem (remap_gradients), grid rank = %d!", grid.rank);
 
-  grid_size = grid.size;
-  nx = grid.dims[0];
-  ny = grid.dims[1];
+  long grid_size = grid.size;
+  long nx = grid.dims[0];
+  long ny = grid.dims[1];
 
 #if defined(_OPENMP)
 #pragma omp parallel for default(none)        \
@@ -1776,19 +1740,16 @@ void remap_gradients(remapgrid_t grid, const double *restrict array, double *res
 void reorder_links(remapvars_t *rv)
 {
   long j, nval = 0, num_blks = 0;
-  long lastval;
-  long nlinks;
-  long max_links = 0;
   long n;
-  long num_links;
 
-  num_links = rv->num_links;
+  long num_links = rv->num_links;
 
   printf("reorder_links\n");
   printf("  num_links %ld\n", num_links);
-  rv->links.option = TRUE;
+  rv->links.option = true;
 
-  lastval = -1;
+  long lastval = -1;
+  long max_links = 0;
   for ( n = 0; n < num_links; n++ )
     {
       if ( rv->tgt_cell_add[n] == lastval ) nval++;
@@ -1825,7 +1786,7 @@ void reorder_links(remapvars_t *rv)
     {
       nval = 0;
       lastval = -1;
-      nlinks = 0;
+      long nlinks = 0;
 
       for ( n = 0; n < num_links; n++ )
 	{
diff --git a/src/sellist.c b/src/sellist.c
new file mode 100644
index 0000000..b582faa
--- /dev/null
+++ b/src/sellist.c
@@ -0,0 +1,361 @@
+#include <cdo_int.h>
+#include "sellist.h"
+
+//#define SELDEBUG 1
+
+sellist_t *sellist_create(list_t *kvlist)
+{
+  sellist_t *sellist = (sellist_t *) Malloc(sizeof(sellist_t));
+  sellist->size = list_size(kvlist);
+  sellist->entry = (selentry_t *) Malloc(sellist->size*sizeof(selentry_t));
+
+  int i = 0;
+  for ( listNode_t *kvnode = kvlist->head; kvnode; kvnode = kvnode->next )
+    {
+      keyValues_t *kv = *(keyValues_t **)kvnode->data;
+      selentry_t *e = &(sellist->entry[i]);
+      e->key = kv->key;
+      e->values = kv->values;
+      e->nvalues = kv->nvalues;
+#ifdef SELDEBUG
+      printf("%s =", e->key);
+      for ( int ii = 0; ii < e->nvalues; ++ii ) printf(" '%s'", e->values[ii]);
+      printf("\n");
+#endif
+      ++i;
+    }
+
+  for ( int i = 0; i < sellist->size; ++i )
+    {
+      selentry_t *e = &(sellist->entry[i]);
+      e->flag = NULL;
+      e->cvalues = NULL;
+#ifdef SELDEBUG
+      printf("%s =", e->key);
+      for ( int ii = 0; ii < e->nvalues; ++ii ) printf(" '%s'", e->values[ii]);
+      printf("\n");
+#endif
+    }
+
+  return sellist;
+}
+
+
+void sellist_destroy(sellist_t *sellist)
+{
+  if ( sellist )
+    {
+      for ( int i = 0; i < sellist->size; ++i )
+        {
+          selentry_t *e = &(sellist->entry[i]);
+          if ( e->txt ) Free(e->txt);
+          if ( e->flag ) Free(e->flag);
+          if ( e->cvalues ) Free(e->cvalues);
+        }
+
+      Free(sellist);
+    }
+}
+
+
+void sellist_verify(sellist_t *sellist)
+{
+  if ( sellist )
+    {
+      for ( int i = 0; i < sellist->size; ++i )
+        {
+          selentry_t *e = &(sellist->entry[i]);
+          if ( e->type == 0 ) cdoAbort("Unsupported selection keyword: '%s'!", e->key);
+        }
+    }
+}
+
+void split_intstring(const char *intstr, int *first, int *last, int *inc);
+
+int sellist_add(sellist_t *sellist, const char *txt, const char *name, int type)
+{
+  int idx = -1;
+
+  if ( sellist )
+    {
+      for ( int i = 0; i < sellist->size; ++i )
+        {
+          const char *key = sellist->entry[i].key;
+          if ( strcmp(key, name) == 0 )
+            {
+              idx = i;
+              break;
+            }
+        }
+
+      if ( idx >= 0 && idx < sellist->size )
+        {
+          selentry_t *e = &(sellist->entry[idx]);
+          e->type = type;
+          e->txt = strdup(txt);
+          if ( e->nvalues && e->cvalues == NULL )
+            {
+              switch (type)
+                {
+                case SELLIST_INT:  e->cvalues = Malloc(e->nvalues*sizeof(int)); break;
+                case SELLIST_FLT:  e->cvalues = Malloc(e->nvalues*sizeof(double)); break;
+                case SELLIST_WORD: e->cvalues = Malloc(e->nvalues*sizeof(char*)); break;
+                }
+            }
+
+          int j = 0;
+          int nvalues = e->nvalues;
+          for ( int i = 0; i < nvalues; ++i )
+            switch (type)
+              {
+              case SELLIST_INT:
+                {
+                  int first, last, inc;
+                  split_intstring(e->values[i], &first, &last, &inc);
+
+                  if ( first == last )
+                    {
+                      ((int*)e->cvalues)[j++] = parameter2int(e->values[i]);
+                    }
+                  else
+                    {
+                      int k = 0;
+                      if ( inc >= 0 )
+                        for ( int ival = first; ival <= last; ival += inc ) k++;
+                      else
+                        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 )
+                        {
+                          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;
+                        }
+                    }
+
+                  break;
+                }
+              case SELLIST_FLT:  ((double*)e->cvalues)[i] = parameter2double(e->values[i]); break;
+              case SELLIST_WORD: ((const char**)e->cvalues)[i] = parameter2word(e->values[i]); break;
+              }
+
+          if ( e->nvalues ) e->flag = (bool*) Calloc(e->nvalues, sizeof(bool));      
+#ifdef SELDEBUG          
+          printf("%s =", e->key);
+          for ( int i = 0; i < e->nvalues; ++i )
+            switch (type)
+              {
+              case SELLIST_INT:  printf(" %d", ((int*)e->cvalues)[i]); break;
+              case SELLIST_FLT:  printf(" %g", ((double*)e->cvalues)[i]); break;
+              case SELLIST_WORD: printf(" %s", ((char**)e->cvalues)[i]); break;
+              }
+          printf("\n");
+#endif
+        }
+    }
+
+  return idx;
+}
+
+
+int sellist_nvalues(sellist_t *sellist, int idx)
+{
+  int nvalues = 0;
+
+  if ( sellist && idx >= 0 && idx < sellist->size ) nvalues = sellist->entry[idx].nvalues;
+
+  return nvalues;
+}
+
+
+void sellist_check_flag(sellist_t *sellist, int idx)
+{
+  if ( idx < 0 || idx >= sellist->size ) return;
+
+  int nvalues = sellist_nvalues(sellist, idx);
+
+  if ( nvalues )
+    {
+      selentry_t *e = &(sellist->entry[idx]);
+      for ( int i = 0; i < nvalues; ++i )
+        if ( e->flag[i] == false )
+          switch (e->type)
+            {
+            case SELLIST_INT:  cdoWarning("%s >%d< not found!", e->txt, ((int*)e->cvalues)[i]); break;
+            case SELLIST_FLT:  cdoWarning("%s >%g< not found!", e->txt, ((double*)e->cvalues)[i]); break;
+            case SELLIST_WORD: cdoWarning("%s >%s< not found!", e->txt, ((char**)e->cvalues)[i]); break;
+            }
+    }
+}
+
+
+bool sellist_check(sellist_t *sellist, int idx, void *par)
+{
+  bool found = false;
+
+  if ( idx < 0 || idx >= sellist->size ) return found;
+
+  int nvalues = sellist_nvalues(sellist, idx);
+
+  if ( nvalues )
+    {
+      selentry_t *e = &(sellist->entry[idx]);
+      for ( int i = 0; i < nvalues; ++i )
+        {
+          switch (e->type)
+            {
+            case SELLIST_INT:  if ( *(int*)par == ((int*)e->cvalues)[i] )                       { found = true; e->flag[i] = true; } break;
+            case SELLIST_FLT:  if ( fabs(*(double*)par - ((double*)e->cvalues)[i]) < 1.e-4 )    { found = true; e->flag[i] = true; } break;
+            case SELLIST_WORD: if ( wildcardmatch(((char**)e->cvalues)[i], *(char**)par) == 0 ) { found = true; e->flag[i] = true; } break;
+            }
+        }
+    }
+
+  return found;
+}
+
+
+bool sellist_check_date(sellist_t *sellist, int idx, const char *par)
+{
+  bool found = false;
+
+  if ( idx < 0 || idx >= sellist->size ) return found;
+
+  int nvalues = sellist_nvalues(sellist, idx);
+
+  if ( nvalues )
+    {
+      char wcdate[512];
+      selentry_t *e = &(sellist->entry[idx]);
+
+      if ( *par == ' ' ) ++par;
+
+      for ( int i = 0; i < nvalues; ++i )
+        {
+          strcpy(wcdate, e->values[i]);
+          strcat(wcdate, "*");
+          if ( wildcardmatch(wcdate, par) == 0 ) { found = true; e->flag[i] = true; }
+        }
+    }
+
+  return found;
+}
+
+void season_to_months(const char *season, int *imonths);
+
+bool sellist_check_season(sellist_t *sellist, int idx, int month)
+{
+  assert(month>=1&&month<=12);
+  bool found = false;
+
+  if ( idx < 0 || idx >= sellist->size ) return found;
+
+  int nvalues = sellist_nvalues(sellist, idx);
+
+  if ( nvalues )
+    {
+      int imon[13]; /* 1-12 ! */
+      selentry_t *e = &(sellist->entry[idx]);
+
+      for ( int i = 0; i < nvalues; ++i )
+        {
+          for ( int m = 0; m < 13; ++m ) imon[m] = 0;
+          season_to_months(e->values[i], imon);
+          if ( imon[month] ) { found = true; e->flag[i] = true; }
+        }
+    }
+
+  return found;
+}
+
+
+void sellist_def_flag(sellist_t *sellist, int idx, int vindex, bool flag)
+{
+  if ( idx < 0 || idx >= sellist->size ) return;
+
+  int nvalues = sellist_nvalues(sellist, idx);
+
+  if ( nvalues )
+    {
+      selentry_t *e = &(sellist->entry[idx]);
+      if ( vindex >= 0 && vindex < nvalues ) e->flag[vindex] = flag;
+    }  
+}
+
+
+void sellist_get_val(sellist_t *sellist, int idx, int vindex, void *val)
+{
+  if ( idx < 0 || idx >= sellist->size ) return;
+
+  int nvalues = sellist_nvalues(sellist, idx);
+
+  if ( nvalues )
+    {
+      selentry_t *e = &(sellist->entry[idx]);
+      if ( vindex >= 0 && vindex < nvalues )
+        {
+          switch (e->type)
+            {
+            case SELLIST_INT:  *(int*)val = ((int*)e->cvalues)[vindex]; break;
+            case SELLIST_FLT:  *(double*)val = ((double*)e->cvalues)[vindex]; break;
+            case SELLIST_WORD: *(const char**)val = ((const char**)e->cvalues)[vindex]; break;
+            }
+        }
+    }
+}
+
+
+void sellist_def_val(sellist_t *sellist, int idx, int vindex, void *val)
+{
+  if ( idx < 0 || idx >= sellist->size ) return;
+
+  int nvalues = sellist_nvalues(sellist, idx);
+
+  if ( nvalues )
+    {
+      selentry_t *e = &(sellist->entry[idx]);
+      if ( vindex >= 0 && vindex < nvalues )
+        {
+          switch (e->type)
+            {
+            case SELLIST_INT:  ((int*)e->cvalues)[vindex] = *(int*)val; break;
+            case SELLIST_FLT:  ((double*)e->cvalues)[vindex] = *(double*)val; break;
+            case SELLIST_WORD: ((const char**)e->cvalues)[vindex] = *(const char**)val; break;
+            }
+        }
+    }
+}
+
+
+void sellist_print(sellist_t *sellist)
+{
+  if ( sellist )
+    {
+      // printf("Parameter list: %s\n", sellist->
+      printf("Num  Name             Type  Size  Entries\n");
+      for ( int idx = 0; idx < sellist->size; ++idx )
+        {
+          selentry_t *e = &(sellist->entry[idx]);
+          printf("%3d  %-16s %4d  %4d ", idx+1, e->key, e->type, e->nvalues);
+          int nvalues = e->nvalues;
+          if ( nvalues > 12 ) nvalues = 12;
+          for ( int i = 0; i < nvalues; ++i )
+            switch (e->type)
+              {
+              case SELLIST_INT:  printf(" %d", ((int*)e->cvalues)[i]); break;
+              case SELLIST_FLT:  printf(" %g", ((double*)e->cvalues)[i]); break;
+              case SELLIST_WORD: printf(" %s", ((char**)e->cvalues)[i]); break;
+              }
+          if ( nvalues < e->nvalues ) printf(" ...");
+          printf("\n");
+        }
+    }
+}
+
diff --git a/src/sellist.h b/src/sellist.h
new file mode 100644
index 0000000..97e9788
--- /dev/null
+++ b/src/sellist.h
@@ -0,0 +1,63 @@
+#ifndef _SELLIST_H
+#define _SELLIST_H
+
+#include "pmlist.h"
+
+typedef union {
+  int ival;
+  double dval;
+  const char *cval;
+} cvalues_t;
+
+typedef struct {
+  int nvalues;
+  char *key;
+  char **values;
+  bool *flag;
+  int type;
+  char *txt;
+  void *cvalues;
+} selentry_t;
+
+
+typedef struct {
+  int size;
+  selentry_t *entry;
+} sellist_t;
+
+
+#define  SELLIST_INT         1
+#define  SELLIST_FLT         2
+#define  SELLIST_WORD        3
+
+#define  SELLIST_DEF_INT(name)                  int name = 0
+#define  SELLIST_DEF_FLT(name)                  double name = 0
+#define  SELLIST_DEF_WORD(name)                 const char *name = 0
+#define  SELLIST_ADD_INT(name, txt)             SELLIST_DEF_INT(name);  int idx_##name = sellist_add(sellist, txt, #name, SELLIST_INT)
+#define  SELLIST_ADD_FLT(name, txt)             SELLIST_DEF_FLT(name);  int idx_##name = sellist_add(sellist, txt, #name, SELLIST_FLT)
+#define  SELLIST_ADD_WORD(name, txt)            SELLIST_DEF_WORD(name); int idx_##name = sellist_add(sellist, txt, #name, SELLIST_WORD)
+#define  SELLIST_NVAL(name)                     sellist_nvalues(sellist, idx_##name)
+#define  SELLIST_CHECK_FLAG(name)               sellist_check_flag(sellist, idx_##name)
+#define  SELLIST_CHECK(name)                    sellist_check(sellist, idx_##name, &name)
+#define  SELLIST_CHECK_DATE(name)               sellist_check_date(sellist, idx_##name, name)
+#define  SELLIST_CHECK_SEASON(name, month)      sellist_check_season(sellist, idx_##name, month)
+#define  SELLIST_DEF_FLAG(name, vindex, flag)   sellist_def_flag(sellist, idx_##name, vindex, flag)
+#define  SELLIST_GET_VAL(name, vindex, val)     sellist_get_val(sellist, idx_##name, vindex, val)
+#define  SELLIST_DEF_VAL(name, vindex, val)     sellist_def_val(sellist, idx_##name, vindex, val)
+
+
+sellist_t *sellist_create(list_t *kvlist);
+void sellist_destroy(sellist_t *sellist);
+void sellist_verify(sellist_t *sellist);
+int sellist_add(sellist_t *sellist, const char *txt, const char *name, int type);
+int sellist_nvalues(sellist_t *sellist, int idx);
+void sellist_check_flag(sellist_t *sellist, int idx);
+bool sellist_check(sellist_t *sellist, int idx, void *par);
+bool sellist_check_date(sellist_t *sellist, int idx, const char *par);
+bool sellist_check_season(sellist_t *sellist, int idx, int month);
+void sellist_def_flag(sellist_t *sellist, int idx, int vindex, bool flag);
+void sellist_get_val(sellist_t *sellist, int idx, int vindex, void *val);
+void sellist_def_val(sellist_t *sellist, int idx, int vindex, void *val);
+void sellist_print(sellist_t *sellist);
+
+#endif
diff --git a/src/specspace.c b/src/specspace.c
index cd9e866..fa35b3c 100644
--- a/src/specspace.c
+++ b/src/specspace.c
@@ -60,6 +60,7 @@ void spec2grid(SPTRANS *sptrans, int gridIDin, double *arrayIn, int gridIDout, d
 
 void four2spec(SPTRANS *sptrans, int gridIDin, double *arrayIn, int gridIDout, double *arrayOut)
 {
+  (void)gridIDin;
   int nlev  = 1;
   int ntr   = gridInqTrunc(gridIDout);
   int nlat  = sptrans->nlat;
@@ -75,7 +76,7 @@ void spec2four(SPTRANS *sptrans, int gridIDin, double *arrayIn, int gridIDout, d
   int nlev  = 1;
   int ntr   = gridInqTrunc(gridIDin);
   int nfc   = gridInqSize(gridIDout);
-  int nlat  = nfc2nlat(nfc, ntr);
+  int nlat  = nfc_to_nlat(nfc, ntr);
   int waves = ntr + 1;
   nfc   = waves * 2;
 
@@ -166,7 +167,7 @@ SPTRANS *sptrans_new(int nlon, int nlat, int ntr, int flag)
   for ( int jgl = 0; jgl < nlat; ++jgl )
     sptrans->rcoslat[jgl] = 1.0 / sptrans->coslat[jgl];
 
-  return (sptrans);
+  return sptrans;
 }
 
 
@@ -201,7 +202,7 @@ DVTRANS *dvtrans_new(int ntr)
 
   geninx(ntr, dvtrans->f1, dvtrans->f2);
 
-  return (dvtrans);
+  return dvtrans;
 }
 
 
@@ -283,4 +284,3 @@ void trans_dv2uv(SPTRANS *sptrans, DVTRANS *dvtrans, int nlev,
 
   Free(fpwork);
 }
-
diff --git a/src/stdnametable.c b/src/stdnametable.c
index cabcb73..489c776 100644
--- a/src/stdnametable.c
+++ b/src/stdnametable.c
@@ -39,28 +39,28 @@ static int stdnametable_idx(int varid)
 
   assert( idx < num_entries );
 
-  return (idx);
+  return idx;
 }
 
 
 int var_echamcode(int varid)
 {
-  return (stdnametable[stdnametable_idx(varid)].echamcode);
+  return stdnametable[stdnametable_idx(varid)].echamcode;
 }
 
 const char* var_name(int varid)
 {
-  return (stdnametable[stdnametable_idx(varid)].name);
+  return stdnametable[stdnametable_idx(varid)].name;
 }
 
 const char* var_stdname(int varid)
 {
-  return (stdnametable[stdnametable_idx(varid)].stdname);
+  return stdnametable[stdnametable_idx(varid)].stdname;
 }
 
 const char* var_units(int varid)
 {
-  return (stdnametable[stdnametable_idx(varid)].units);
+  return stdnametable[stdnametable_idx(varid)].units;
 }
 
 int echamcode_from_stdname(const char* stdname)
@@ -75,7 +75,7 @@ int echamcode_from_stdname(const char* stdname)
   else if ( strcmp(stdname, var_stdname(air_pressure_at_sea_level)) == 0 ) code = 151;
   else if ( strcmp(stdname, var_stdname(geopotential_height))       == 0 ) code = 156;
 
-  return (code);
+  return code;
 }
 
 
diff --git a/src/table.c b/src/table.c
index 0b92d76..d1fcf7d 100644
--- a/src/table.c
+++ b/src/table.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -28,10 +28,9 @@
 
 int defineTable(const char *tablearg)
 {
-  int tableID = CDI_UNDEFID;
   const char *tablename = tablearg;
 
-  if ( fileExists(tablename) ) tableID = tableRead(tablename);
+  int tableID = fileExists(tablename) ? tableRead(tablename) : CDI_UNDEFID;
 
   if ( tableID == CDI_UNDEFID )
     {
@@ -47,11 +46,9 @@ int defineTable(const char *tablearg)
 	}
     }
 
-  if ( tableID == CDI_UNDEFID )
-    tableID = tableInq(-1, 0, tablename);
+  if ( tableID == CDI_UNDEFID ) tableID = tableInq(-1, 0, tablename);
 
-  if ( tableID == CDI_UNDEFID )
-    Error("table <%s> not found", tablename);
+  if ( tableID == CDI_UNDEFID ) Error("table <%s> not found", tablename);
 
   return tableID;
 }
diff --git a/src/timer.c b/src/timer.c
index f1d32bd..713911c 100644
--- a/src/timer.c
+++ b/src/timer.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -123,7 +123,7 @@ double get_time_val(void *mark0)
 
   dt -= tm_shift;
 
-  return (dt);
+  return dt;
 }
 
 int ntests = 100; /* tests need about n microsecs on pwr4 */
@@ -131,40 +131,36 @@ int ntests = 100; /* tests need about n microsecs on pwr4 */
 static
 double m1(void)
 {
-  double dt, dt0;
-  int i;
   char mark[32];
 
-  dt0 = 1.0;
-  for ( i = 0; i < ntests; i++ )
+  double dt0 = 1.0;
+  for ( int i = 0; i < ntests; i++ )
     {
       set_time_mark(mark);
-      dt = get_time_val(mark);
+      double dt = get_time_val(mark);
       if ( dt < dt0 ) dt0 = dt;
     }
 
-  return (dt0);
+  return dt0;
 }
 
 static
 double m2(void)
 {
   char mark1[32], mark2[32];
-  double dt1, dt2, dt0;
-  int i;
 
-  dt0 = 1.0;
-  for ( i = 0; i < ntests; i++ )
+  double dt0 = 1.0;
+  for ( int i = 0; i < ntests; i++ )
     {
       set_time_mark(mark2);
       set_time_mark(mark1);
-      dt1 = get_time_val(mark1);
-      dt2 = get_time_val(mark2);
+      double dt1 = get_time_val(mark1);
+      double dt2 = get_time_val(mark2);
       if ( dt2 < dt0 ) dt0 = dt2;
       if ( dt2 < dt1 ) fprintf(rt_unit, "estimate_overhead: internal error\n");
     }
 
-  return (dt0);
+  return dt0;
 }
 
 static
@@ -210,7 +206,7 @@ int timer_new(const char *text)
 
   if ( text ) strcpy(rt[it].text, text);
 
-  return (it);
+  return it;
 }
 
 static
@@ -223,19 +219,17 @@ void timer_check(int it)
 
 double timer_val(int it)
 {
-  double val, dt;
-
   timer_check(it);
 
-  val = rt[it].tot;
+  double val = rt[it].tot;
 
   if ( rt[it].stat == rt_stat_on )
     {
-      dt = get_time_val(rt[it].mark1);
+      double dt = get_time_val(rt[it].mark1);
       val += dt;
     }
 
-  return (val);
+  return val;
 }
 
 static
@@ -249,23 +243,19 @@ void timer_header(void)
 
 void timer_report(void)
 {
-  int it;
-  double total, avg;
-
   timer_header();
 
-  for ( it = 0; it < top_timer; it++ )
+  for ( int it = 0; it < top_timer; it++ )
     {
-      total = timer_val(it);
+      double total = timer_val(it);
 
-      avg = rt[it].tot;
+      double avg = rt[it].tot;
       if ( rt[it].calls > 0 ) avg /= rt[it].calls;
 
       if ( rt[it].stat != rt_stat_undef )
 	fprintf(rt_unit, "%4d %7d %12.4g %12.4g %12.4g %12.4g  %s\n",
 		it, rt[it].calls, rt[it].min, avg, rt[it].max, total, rt[it].text);
     }
-
 }
 
 
@@ -284,8 +274,6 @@ void timer_start(int it)
 
 void timer_stop(int it)
 {
-  double dt;
-
   timer_check(it);
 
   if ( rt[it].stat != rt_stat_on )
@@ -296,7 +284,7 @@ void timer_stop(int it)
         fprintf(rt_unit, "timer_stop: undefined timer >%s<\n", rt[it].text);
     }
 
-  dt = get_time_val(rt[it].mark1);
+  double dt = get_time_val(rt[it].mark1);
 
   rt[it].last  = dt;
   rt[it].tot  += dt;
@@ -336,5 +324,5 @@ void counter_stop(counter_t *counter)
 
 double counter_cputime(counter_t counter)
 {
-  return (counter.cputime);
+  return counter.cputime;
 }
diff --git a/src/util.c b/src/util.c
index 97aacc0..ad3c1eb 100644
--- a/src/util.c
+++ b/src/util.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -78,6 +78,9 @@ int cdoDefaultTimeType   = CDI_UNDEFID;
 int cdoLockIO            = FALSE;
 int cdoCheckDatarange    = FALSE;
 
+int CDO_flt_digits       = 7;
+int CDO_dbl_digits       = 15;
+
 int CDO_Color            = FALSE;
 int CDO_Use_FFTW         = TRUE;
 int CDO_Version_Info     = TRUE;
@@ -92,7 +95,7 @@ int CDO_Reduce_Dim       = FALSE;
 int CDO_Append_History   = TRUE;
 int CDO_Reset_History    = FALSE;
 
-int cdoCompType          = COMPRESS_NONE;  // compression type
+int cdoCompType          = CDI_COMPRESS_NONE;  // compression type
 int cdoCompLevel         = 0;              // compression level
 int cdoDebug             = 0;
 int cdoChunkType         = CDI_UNDEFID;
@@ -122,14 +125,13 @@ int timer_read, timer_write;
 const char *cdoComment(void)
 {
   static char comment[256];
-  static int init = 0;
+  static bool init = false;
 
   if ( ! init )
     {
-      init = 1;
+      init = true;
 
       int size = strlen(CDO_Version);
-
       strncat(comment, CDO_Version, size);
       comment[size] = 0;
     }
@@ -182,13 +184,11 @@ int cdo_omp_get_thread_num(void)
 
 char *getProgname(char *string)
 {
-  char *progname;
-
 #if defined(_WIN32)
   /*  progname = strrchr(string, '\\'); */
-  progname = " cdo";
+  char *progname = " cdo";
 #else
-  progname = strrchr(string, '/');
+  char *progname = strrchr(string, '/');
 #endif
 
   if ( progname == NULL ) progname = string;
@@ -213,24 +213,18 @@ char *getOperator(const char *argument)
   return operatorArg;
 }
 
-char *operatorAlias(char *operatorName);
+const char *operatorAlias(const char *operatorName);
 
-char *getOperatorName(const char *operatorArg)
+const char *getOperatorName(const char *operatorArg)
 {
-  char *commapos;
   char *operatorName = NULL;
-  size_t len;
 
   if ( operatorArg )
     {
       if ( operatorArg[0] == '-' ) operatorArg++;
 
-      commapos = (char *)strchr(operatorArg, ',');
-
-      if ( commapos )
-        len = commapos - operatorArg;
-      else
-        len = strlen(operatorArg);
+      char *commapos = (char *)strchr(operatorArg, ',');
+      size_t len = (commapos != NULL) ? (size_t)(commapos - operatorArg) : strlen(operatorArg);
 
       operatorName = (char*) Malloc(len+1);
 
@@ -239,8 +233,7 @@ char *getOperatorName(const char *operatorArg)
     }
 
   /*  return operatorName; */
-  char * alias = operatorAlias(operatorName);
-  return alias;
+  return operatorAlias(operatorName);
 }
 
 
@@ -322,11 +315,9 @@ void argument_free(argument_t *argument)
 
 void argument_fill(argument_t *argument, int argc, char *argv[])
 {
-  int iarg;
-
   assert(argument->argc == argc);
 
-  for ( iarg = 0; iarg < argc; ++iarg )
+  for ( int iarg = 0; iarg < argc; ++iarg )
     argument->argv[iarg] = strdup(argv[iarg]);
 }
 
@@ -334,18 +325,15 @@ void argument_fill(argument_t *argument, int argc, char *argv[])
 char *getFileArg(char *argument)
 {
   char *fileArg = NULL;
-  char *parg;
-  char *blankpos;
-  size_t len;
 
   if ( argument )
     {
-      blankpos = strchr(argument, ' ');
+      char *blankpos = strchr(argument, ' ');
 
       if ( blankpos )
         {
-          parg = blankpos + 1;
-          len = strlen(parg);
+          char *parg = blankpos + 1;
+          size_t len = strlen(parg);
           fileArg = (char*) Malloc(len+1);
           strcpy(fileArg, parg);
         }
@@ -354,6 +342,33 @@ char *getFileArg(char *argument)
   return fileArg;
 }
 
+static
+void trim_flt(char *ss)
+{
+  char *cp = ss;
+  if ( *cp == '-' ) cp++;
+  while ( isdigit((int)*cp ) || *cp == '.' ) cp++;
+  if ( *--cp == '.' ) return;
+
+  char *ep = cp+1;
+  while ( *cp == '0' ) cp--;
+  cp++;
+  if ( cp == ep ) return;
+  while ( *ep ) *cp++ = *ep++;
+  *cp = '\0';
+
+  return;
+}
+
+
+char *double_to_attstr(int digits, char *str, size_t len, double value)
+{
+  int ret = snprintf(str, len, "%#.*g", digits, value);
+  assert(ret != -1 && ret < (int)len);
+  trim_flt(str);
+  return str;
+}
+
 
 void input_int(char *arg, int intarr[], int maxint, int *nintfound)
 {
@@ -370,23 +385,51 @@ void input_int(char *arg, int intarr[], int maxint, int *nintfound)
 
 void strtolower(char *str)
 {
-  int i, len;
-
   if ( str )
+    for ( size_t i = 0; str[i]; ++i )
+      str[i] = (char)tolower((int)str[i]);
+}
+
+
+const char *parameter2word(const char *string)
+{
+  size_t len = strlen(string);
+
+  for ( size_t i = 0; i < len; ++i )
     {
-      len = (int) strlen(str);
-      for ( i = 0; i < len; i++ )
-        str[i] = tolower((int) str[i]);
+      int c = string[i];
+      if ( iscntrl(c) || isblank(c) )
+        cdoAbort("Word parameter >%s< contains invalid character at position %d!", string, i+1);
     }
+
+  if ( len == 0 ) cdoAbort("Word parameter >%s< is empty!", string);
+
+  return string;
+}
+
+
+bool parameter2bool(const char *str)
+{
+  size_t len = strlen(str);
+
+  if ( len == 1 )
+    {
+      if ( *str == 't' || *str == 'T' || *str == '1' ) return true;
+      if ( *str == 'f' || *str == 'F' || *str == '0' ) return false;
+    }
+  else if ( len == 4 && (STR_IS_EQ(str, "true")  || STR_IS_EQ(str, "TRUE")  || STR_IS_EQ(str, "True"))  ) return true;
+  else if ( len == 5 && (STR_IS_EQ(str, "false") || STR_IS_EQ(str, "FALSE") || STR_IS_EQ(str, "False")) ) return false;
+
+  cdoAbort("Boolean parameter >%s< contains invalid characters!", str);
+
+  return false;
 }
 
 
 double parameter2double(const char *string)
 {
   char *endptr = NULL;
-
   double fval = strtod(string, &endptr);
-
   if ( *endptr != 0 )
     cdoAbort("Float parameter >%s< contains invalid character at position %d!",
 	     string, (int)(endptr-string+1));
@@ -398,9 +441,7 @@ double parameter2double(const char *string)
 int parameter2int(const char *string)
 {
   char *endptr = NULL;
-
   int ival = (int) strtol(string, &endptr, 10);
-
   if ( *endptr != 0 )
     cdoAbort("Integer parameter >%s< contains invalid character at position %d!",
 	     string, (int)(endptr-string+1));
@@ -412,9 +453,7 @@ int parameter2int(const char *string)
 int parameter2intlist(const char *string)
 {
   char *endptr = NULL;
-
   int ival = (int) strtol(string, &endptr, 10);
-
   if ( *endptr != 0 && *endptr != '/' && (endptr - string) == 0 )
     cdoAbort("Integer parameter >%s< contains invalid character at position %d!",
 	     string, (int)(endptr-string+1));
@@ -458,12 +497,10 @@ int get_season_start(void)
 
 void get_season_name(const char *seas_name[])
 {
-  long i;
-
   if ( get_season_start() == START_DEC )
-    for ( i = 0; i < 4; ++i ) seas_name[i] = seas_name_dec[i];
+    for ( int i = 0; i < 4; ++i ) seas_name[i] = seas_name_dec[i];
   else
-    for ( i = 0; i < 4; ++i ) seas_name[i] = seas_name_jan[i];
+    for ( int i = 0; i < 4; ++i ) seas_name[i] = seas_name_jan[i];
 }
 
 
@@ -498,23 +535,23 @@ int month_to_season(int month)
 #include <sys/stat.h>
 //#include <unistd.h>
 
-int fileExists(const char *restrict filename)
+bool fileExists(const char *restrict filename)
 {
-  int status = 0;
+  bool status = false;
   struct stat buf;
 
   if ( stat(filename, &buf) == 0 )
     {
-      if ( S_ISREG(buf.st_mode) && buf.st_size > 0 ) status = 1;
+      if ( S_ISREG(buf.st_mode) && buf.st_size > 0 ) status = true;
     }
 
   return status;
 }
 
 
-int userFileOverwrite(const char *restrict filename)
+bool userFileOverwrite(const char *restrict filename)
 {
-  int status = 0;
+  bool status = false;
 
   if ( !cdoSilentMode && stdin_is_tty && stderr_is_tty )
     {
@@ -527,13 +564,13 @@ int userFileOverwrite(const char *restrict filename)
       if ( len == 3 )
         {
           if ( pline[0] == 'y' && pline[1] == 'e' && pline[2] == 's' )
-            status = 1;
+            status = true;
           else if ( pline[0] == 'Y' && pline[1] == 'E' && pline[2] == 'S' )
-            status = 1;
+            status = true;
         }
       else if ( len == 1 )
         {
-          if ( pline[0] == 'y' || pline[0] == 'Y' ) status = 1;
+          if ( pline[0] == 'y' || pline[0] == 'Y' ) status = true;
         }
     }
 
@@ -555,8 +592,6 @@ void progressInit(void)
 
 void progressStatus(double offset, double refval, double curval)
 {
-  int ival;
-
   if ( cdoSilentMode ) return;
   if ( !stdout_is_tty ) return;
 
@@ -567,7 +602,7 @@ void progressStatus(double offset, double refval, double curval)
   curval = curval < 0 ? 0: curval;
   curval = curval > 1 ? 1: curval;
 
-  ival = (offset + refval*curval)*100;
+  int ival = (offset + refval*curval)*100;
 
   if ( ps_cval == -1 )
     {
@@ -596,18 +631,18 @@ int datatype2str(int datatype, char *datatypestr)
 {
   int status = 0;
 
-  if      ( datatype == DATATYPE_PACK   ) strcpy(datatypestr, "P0");
-  else if ( datatype > 0 && datatype <= 32  ) sprintf(datatypestr, "P%d", datatype);
-  else if ( datatype == DATATYPE_CPX32  ) strcpy(datatypestr, "C32");
-  else if ( datatype == DATATYPE_CPX64  ) strcpy(datatypestr, "C64");
-  else if ( datatype == DATATYPE_FLT32  ) strcpy(datatypestr, "F32");
-  else if ( datatype == DATATYPE_FLT64  ) strcpy(datatypestr, "F64");
-  else if ( datatype == DATATYPE_INT8   ) strcpy(datatypestr, "I8");
-  else if ( datatype == DATATYPE_INT16  ) strcpy(datatypestr, "I16");
-  else if ( datatype == DATATYPE_INT32  ) strcpy(datatypestr, "I32");
-  else if ( datatype == DATATYPE_UINT8  ) strcpy(datatypestr, "U8");
-  else if ( datatype == DATATYPE_UINT16 ) strcpy(datatypestr, "U16");
-  else if ( datatype == DATATYPE_UINT32 ) strcpy(datatypestr, "U32");
+  if      ( datatype == CDI_DATATYPE_PACK   ) strcpy(datatypestr, "P0");
+  else if ( datatype > 0 && datatype <= 32  ) snprintf(datatypestr, 4, "P%d", datatype);
+  else if ( datatype == CDI_DATATYPE_CPX32  ) strcpy(datatypestr, "C32");
+  else if ( datatype == CDI_DATATYPE_CPX64  ) strcpy(datatypestr, "C64");
+  else if ( datatype == CDI_DATATYPE_FLT32  ) strcpy(datatypestr, "F32");
+  else if ( datatype == CDI_DATATYPE_FLT64  ) strcpy(datatypestr, "F64");
+  else if ( datatype == CDI_DATATYPE_INT8   ) strcpy(datatypestr, "I8");
+  else if ( datatype == CDI_DATATYPE_INT16  ) strcpy(datatypestr, "I16");
+  else if ( datatype == CDI_DATATYPE_INT32  ) strcpy(datatypestr, "I32");
+  else if ( datatype == CDI_DATATYPE_UINT8  ) strcpy(datatypestr, "U8");
+  else if ( datatype == CDI_DATATYPE_UINT16 ) strcpy(datatypestr, "U16");
+  else if ( datatype == CDI_DATATYPE_UINT32 ) strcpy(datatypestr, "U32");
   else                                  { strcpy(datatypestr, "-1"); status = -1;}
 
   return status;
@@ -617,28 +652,26 @@ int datatype2str(int datatype, char *datatypestr)
 int str2datatype(const char *datatypestr)
 {
   int datatype = -1;
-  size_t len;
-
-  len = strlen(datatypestr);
+  size_t len = strlen(datatypestr);
 
   if ( len > 1 )
     {
       int ilen = atoi(datatypestr+1);
-      if      ( strncmp(datatypestr, "P0",  len) == 0 ) datatype = DATATYPE_PACK;
+      if      ( strncmp(datatypestr, "P0",  len) == 0 ) datatype = CDI_DATATYPE_PACK;
       else if ( strncmp(datatypestr, "P",     1) == 0 &&
-                ilen > 0 && ilen <= 32 )               datatype = atoi(datatypestr+1);
-      else if ( strncmp(datatypestr, "C32", len) == 0 ) datatype = DATATYPE_CPX32;
-      else if ( strncmp(datatypestr, "C64", len) == 0 ) datatype = DATATYPE_CPX64;
-      else if ( strncmp(datatypestr, "F32", len) == 0 ) datatype = DATATYPE_FLT32;
-      else if ( strncmp(datatypestr, "F64", len) == 0 ) datatype = DATATYPE_FLT64;
-      else if ( strncmp(datatypestr, "I8",  len) == 0 ) datatype = DATATYPE_INT8;
-      else if ( strncmp(datatypestr, "I16", len) == 0 ) datatype = DATATYPE_INT16;
-      else if ( strncmp(datatypestr, "I32", len) == 0 ) datatype = DATATYPE_INT32;
-      else if ( strncmp(datatypestr, "U8",  len) == 0 ) datatype = DATATYPE_UINT8;
-      else if ( strncmp(datatypestr, "U16", len) == 0 ) datatype = DATATYPE_UINT16;
-      else if ( strncmp(datatypestr, "U32", len) == 0 ) datatype = DATATYPE_UINT32;
-      else if ( strncmp(datatypestr, "real",   len) == 0 ) datatype = DATATYPE_FLT32;
-      else if ( strncmp(datatypestr, "double", len) == 0 ) datatype = DATATYPE_FLT64;
+                ilen > 0 && ilen <= 32 )                datatype = atoi(datatypestr+1);
+      else if ( strncmp(datatypestr, "C32", len) == 0 ) datatype = CDI_DATATYPE_CPX32;
+      else if ( strncmp(datatypestr, "C64", len) == 0 ) datatype = CDI_DATATYPE_CPX64;
+      else if ( strncmp(datatypestr, "F32", len) == 0 ) datatype = CDI_DATATYPE_FLT32;
+      else if ( strncmp(datatypestr, "F64", len) == 0 ) datatype = CDI_DATATYPE_FLT64;
+      else if ( strncmp(datatypestr, "I8",  len) == 0 ) datatype = CDI_DATATYPE_INT8;
+      else if ( strncmp(datatypestr, "I16", len) == 0 ) datatype = CDI_DATATYPE_INT16;
+      else if ( strncmp(datatypestr, "I32", len) == 0 ) datatype = CDI_DATATYPE_INT32;
+      else if ( strncmp(datatypestr, "U8",  len) == 0 ) datatype = CDI_DATATYPE_UINT8;
+      else if ( strncmp(datatypestr, "U16", len) == 0 ) datatype = CDI_DATATYPE_UINT16;
+      else if ( strncmp(datatypestr, "U32", len) == 0 ) datatype = CDI_DATATYPE_UINT32;
+      else if ( strncmp(datatypestr, "real",   len) == 0 ) datatype = CDI_DATATYPE_FLT32;
+      else if ( strncmp(datatypestr, "double", len) == 0 ) datatype = CDI_DATATYPE_FLT64;
     }
 
   return datatype;
@@ -663,24 +696,23 @@ off_t fileSize(const char *restrict filename)
 
 
 /* 
- * Return the filetype extension (const char)
- * for a given filetype (int)
+ * Return the filetype extension (const char) for a given filetype (int)
  * TODO: handle lists of extensions i.e. grb and grb2 for GRIB2-format
  */
 const char *filetypeext(int filetype)
 {
   switch ( filetype )
     {
-    case FILETYPE_GRB:
-    case FILETYPE_GRB2: return ".grb";   break;
-    case FILETYPE_NC:
-    case FILETYPE_NC2:
-    case FILETYPE_NC4:
-    case FILETYPE_NC4C: return ".nc";    break;
-    case FILETYPE_SRV:  return ".srv";   break;
-    case FILETYPE_EXT:  return ".ext";   break;
-    case FILETYPE_IEG:  return ".ieg";   break;
-    default:            return "";
+    case CDI_FILETYPE_GRB:
+    case CDI_FILETYPE_GRB2: return ".grb";   break;
+    case CDI_FILETYPE_NC:
+    case CDI_FILETYPE_NC2:
+    case CDI_FILETYPE_NC4:
+    case CDI_FILETYPE_NC4C: return ".nc";    break;
+    case CDI_FILETYPE_SRV:  return ".srv";   break;
+    case CDI_FILETYPE_EXT:  return ".ext";   break;
+    case CDI_FILETYPE_IEG:  return ".ieg";   break;
+    default:                return "";
     }
 }
 
@@ -748,20 +780,20 @@ void cdoGenFileSuffix(char *filesuffix, size_t maxlen, int filetype, int vlistID
                       switch (firstchar)
                         {
                         case 'g':
-                          if ( cdoDefaultFileType == FILETYPE_GRB || cdoDefaultFileType == FILETYPE_GRB2 ) lready = true;
+                          if ( cdoDefaultFileType == CDI_FILETYPE_GRB || cdoDefaultFileType == CDI_FILETYPE_GRB2 ) lready = true;
                           break;
                         case 'n':
-                          if ( cdoDefaultFileType == FILETYPE_NC || cdoDefaultFileType == FILETYPE_NC2 ||
-                               cdoDefaultFileType == FILETYPE_NC4 || cdoDefaultFileType == FILETYPE_NC4C ) lready = true;
+                          if ( cdoDefaultFileType == CDI_FILETYPE_NC || cdoDefaultFileType == CDI_FILETYPE_NC2 ||
+                               cdoDefaultFileType == CDI_FILETYPE_NC4 || cdoDefaultFileType == CDI_FILETYPE_NC4C ) lready = true;
                           break;
                         case 's':
-                          if ( cdoDefaultFileType == FILETYPE_SRV ) lready = true;
+                          if ( cdoDefaultFileType == CDI_FILETYPE_SRV ) lready = true;
                           break;
                         case 'e':
-                          if ( cdoDefaultFileType == FILETYPE_EXT ) lready = true;
+                          if ( cdoDefaultFileType == CDI_FILETYPE_EXT ) lready = true;
                           break;
                         case 'i':
-                          if ( cdoDefaultFileType == FILETYPE_IEG ) lready = true;
+                          if ( cdoDefaultFileType == CDI_FILETYPE_IEG ) lready = true;
                           break;
                         }
                     }
@@ -782,10 +814,10 @@ void cdoGenFileSuffix(char *filesuffix, size_t maxlen, int filetype, int vlistID
           if ( !lready )
             {
               strncat(filesuffix, streamFilesuffix(cdoDefaultFileType), maxlen-1);
-              if ( cdoDefaultFileType == FILETYPE_GRB && vlistIsSzipped(vlistID) ) lcompsz = true;
+              if ( cdoDefaultFileType == CDI_FILETYPE_GRB && vlistIsSzipped(vlistID) ) lcompsz = true;
             }
 
-          if ( cdoDefaultFileType == FILETYPE_GRB && cdoCompType == COMPRESS_SZIP ) lcompsz = true;
+          if ( cdoDefaultFileType == CDI_FILETYPE_GRB && cdoCompType == CDI_COMPRESS_SZIP ) lcompsz = true;
           if ( lcompsz ) strncat(filesuffix, ".sz", maxlen-1);
         }
     }
@@ -796,7 +828,7 @@ int cdoFiletype(void)
 {
   if ( cdoDefaultFileType == CDI_UNDEFID )
     {
-      cdoDefaultFileType = FILETYPE_GRB;
+      cdoDefaultFileType = CDI_FILETYPE_GRB;
       if ( ! cdoSilentMode )
         cdoPrint("Set default filetype to GRIB");
     }
@@ -819,13 +851,12 @@ void cdoSetNAN(double missval, size_t gridsize, double *array)
 
 void minmaxval(long nvals, double *array, int *imiss, double *minval, double *maxval)
 {
-  long i;
   double xmin =  DBL_MAX;
   double xmax = -DBL_MAX;
 
   if ( imiss )
     {
-      for ( i = 0; i < nvals; ++i )
+      for ( long i = 0; i < nvals; ++i )
 	{
 	  if ( ! imiss[i] )
 	    {
@@ -838,7 +869,7 @@ void minmaxval(long nvals, double *array, int *imiss, double *minval, double *ma
     {
       xmin = array[0];
       xmax = array[0];
-      for ( i = 1; i < nvals; ++i )
+      for ( long i = 1; i < nvals; ++i )
 	{
 	  if      ( array[i] > xmax ) xmax = array[i];
 	  else if ( array[i] < xmin ) xmin = array[i];
diff --git a/src/util.h b/src/util.h
index 3a9ff91..ed0364d 100644
--- a/src/util.h
+++ b/src/util.h
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -19,6 +19,7 @@
 #define _UTIL_H
 
 #include <stdio.h>
+#include <stdbool.h>
 #include "percentiles.h"
 
 /* dummy use of unused parameters to silence compiler warnings */
@@ -51,9 +52,13 @@ extern int CDO_Append_History;
 extern int CDO_Reset_History;
 extern int timer_read, timer_write; // refactor: both pstream.c and CDIread.c CDIwrite.c defined in cdo.c
 
-extern int   CDO_optind;
+extern int CDO_optind;
 extern const char *CDO_optarg;
 extern int CDO_opterr;
+
+extern int CDO_flt_digits;
+extern int CDO_dbl_digits;
+
 extern int remap_genweights;
 
 extern const char *cdoExpName;
@@ -120,7 +125,7 @@ void        argument_fill(argument_t *argument, int argc, char *argv[]);
 
 char *getProgname(char *string);
 char *getOperator(const char *argument);
-char *getOperatorName(const char *xoperator);
+const char *getOperatorName(const char *xoperator);
 const char *cdoComment(void);
 
 argument_t makeArgument(int argc, char *argv[]);
@@ -133,11 +138,13 @@ int month_to_season(int month);
 
 void init_is_tty(void);
 
+char *double_to_attstr(int digits, char *str, size_t len, double value);
+
 void progressInit(void);
 void progressStatus(double offset, double refval, double curval);
 
-int fileExists(const char *filename);
-int userFileOverwrite(const char *filename);
+bool fileExists(const char *filename);
+bool userFileOverwrite(const char *filename);
 
 /* convert a CDI datatype to string */
 int datatype2str(int datatype, char *datatypestr);
@@ -207,7 +214,7 @@ void cdoGenFileSuffix(char *filesuffix, size_t maxlen, int filetype, int vlistID
 void writeNCgrid(const char *gridfile, int gridID, int *imask);
 void defineZaxis(const char *zaxisarg);
 
-int gridFromName(const char *gridname);
+int grid_from_name(const char *gridname);
 int zaxisFromName(const char *zaxisname);
 
 /* refactor: moved here from cdo.h */
diff --git a/src/zaxis.c b/src/zaxis.c
index 644d186..6674e13 100644
--- a/src/zaxis.c
+++ b/src/zaxis.c
@@ -2,7 +2,7 @@
   This file is part of CDO. CDO is a collection of Operators to
   manipulate and analyse Climate model Data.
 
-  Copyright (C) 2003-2016 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
+  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
@@ -38,6 +38,7 @@ typedef struct {
   int     vctsize;
   int     type;
   int     size;
+  bool    scalar;
   char    name[CDI_MAX_NAME];
   char    longname[CDI_MAX_NAME];
   char    units[CDI_MAX_NAME];
@@ -54,39 +55,31 @@ void zaxisInit(zaxis_t *zaxis)
   zaxis->type        = UNDEFID;
   zaxis->vctsize     = 0;
   zaxis->size        = 0;
+  zaxis->scalar      = false;
   zaxis->name[0]     = 0;
   zaxis->longname[0] = 0;
   zaxis->units[0]    = 0;
 }
 
-
-static int getoptname(char *optname, const char *optstring, int nopt)
+static
+int getoptname(char *optname, const char *optstring, int nopt)
 {
-  int i, nerr = 0;
-  size_t namelen;
-  const char *pname;
-  const char *pend;
+  int nerr = 0;
 
-  pname = optstring;
-  pend  = optstring;
+  const char *pname = optstring;
+  const char *pend  = optstring;
 
-  for ( i = 0; i < nopt; i++ )
+  for ( int i = 0; i < nopt; i++ )
     {
       pend = strchr(pname, ',');
-      if ( pend == NULL )
-	break;
-      else
-	pname = pend + 1;
+      if ( pend == NULL ) break;
+      pname = pend + 1;
     }
 
   if ( pend )
     {
       pend = strchr(pname, ',');
-      if ( pend == NULL )
-	namelen = strlen(pname);
-      else
-	namelen = pend - pname;
-
+      size_t namelen = (pend == NULL) ? strlen(pname) : (size_t)(pend-pname);
       memcpy(optname, pname, namelen);
       optname[namelen] = '\0';
     }
@@ -99,13 +92,12 @@ static int getoptname(char *optname, const char *optstring, int nopt)
 
 int zaxisDefine(zaxis_t zaxis)
 {
-  int zaxisID = UNDEFID;
-
   if ( zaxis.type == -1 ) Error("zaxistype undefined!");
+  if ( zaxis.size ==  0 ) Error("zaxis size undefined!");
 
-  if ( zaxis.size == 0 ) Error("zaxis size undefined!");
+  int zaxisID = zaxisCreate(zaxis.type, zaxis.size);
 
-  zaxisID = zaxisCreate(zaxis.type, zaxis.size);
+  if ( zaxis.size == 1 && zaxis.scalar ) zaxisDefScalar(zaxisID);
 
   if ( zaxis.vals )
     {
@@ -139,249 +131,225 @@ int zaxisDefine(zaxis_t zaxis)
 }
 
 
-static char *skipSeparator(char *pline)
+typedef struct {
+  keyValues_t *kv;
+  bool isValid;
+} kvmap_t;
+
+static
+void zaxis_read_data(size_t nkv, kvmap_t *kvmap, zaxis_t *zaxis, size_t *iatt, const char *dname)
 {
-  while ( isspace((int) *pline) ) pline++;
-  if ( *pline == '=' || *pline == ':' ) pline++;
-  while ( isspace((int) *pline) ) pline++;
+  // char uuidStr[256];
 
-  return pline;
+  for ( size_t ik = 0; ik < nkv; ++ik )
+    {
+      if ( !kvmap[ik].isValid ) continue;
+
+      keyValues_t *kv = kvmap[ik].kv;
+      const char *key = kv->key;
+      // size_t nvalues = kv->nvalues;
+      const char *value = (kv->nvalues > 0) ? kv->values[0] : NULL;
+      // bool lv1 = (kv->nvalues == 1);
+
+      // printf("%s = ", key); if ( value  ) printf("%s", kv->value); printf("\n");
+
+      if ( STR_IS_EQ(key, "zaxistype") )
+        {
+          const char *zaxistype = parameter2word(value);
+
+          if      ( STR_IS_EQ(zaxistype, "pressure") )          zaxis->type = ZAXIS_PRESSURE;
+          else if ( STR_IS_EQ(zaxistype, "hybrid_half") )       zaxis->type = ZAXIS_HYBRID_HALF;
+          else if ( STR_IS_EQ(zaxistype, "hybrid") )            zaxis->type = ZAXIS_HYBRID;
+          else if ( STR_IS_EQ(zaxistype, "height") )            zaxis->type = ZAXIS_HEIGHT;
+          else if ( STR_IS_EQ(zaxistype, "depth_below_sea") )   zaxis->type = ZAXIS_DEPTH_BELOW_SEA;
+          else if ( STR_IS_EQ(zaxistype, "depth_below_land") )  zaxis->type = ZAXIS_DEPTH_BELOW_LAND;
+          else if ( STR_IS_EQ(zaxistype, "isentropic") )        zaxis->type = ZAXIS_ISENTROPIC;
+          else if ( STR_IS_EQ(zaxistype, "surface") )           zaxis->type = ZAXIS_SURFACE;
+          else if ( STR_IS_EQ(zaxistype, "generic") )           zaxis->type = ZAXIS_GENERIC;
+	  else cdoAbort("Invalid zaxisname : %s (zaxis description file: %s)", zaxistype, dname);
+        }
+      else if ( STR_IS_EQ(key, "size") ) zaxis->size = parameter2int(value);
+      else if ( STR_IS_EQ(key, "scalar") ) zaxis->scalar = parameter2bool(value);
+      else if ( STR_IS_EQ(key, "vctsize") ) zaxis->vctsize = parameter2int(value);
+      else if ( STR_IS_EQ(key, "name") ) strcpy(zaxis->name, parameter2word(value));
+      else if ( STR_IS_EQ(key, "units") ) strcpy(zaxis->units, parameter2word(value));
+      else if ( STR_IS_EQ(key, "longname") ) strcpy(zaxis->longname, value);
+      else if ( STR_IS_EQ(key, "levels") )
+        {
+          if ( zaxis->size == 0 ) cdoAbort("size undefined (zaxis description file: %s)!", dname);
+          zaxis->vals = (double*) Malloc(zaxis->size*sizeof(double));
+          for ( size_t i = 0; i < (size_t) zaxis->size; ++i ) zaxis->vals[i] = parameter2double(kv->values[i]);
+        }
+      else if ( STR_IS_EQ(key, "lbounds") )
+        {
+          if ( zaxis->size == 0 ) cdoAbort("size undefined (zaxis description file: %s)!", dname);
+          zaxis->lbounds = (double*) Malloc(zaxis->size*sizeof(double));
+          for ( size_t i = 0; i < (size_t) zaxis->size; ++i ) zaxis->lbounds[i] = parameter2double(kv->values[i]);
+        }
+      else if ( STR_IS_EQ(key, "ubounds") )
+        {
+          if ( zaxis->size == 0 ) cdoAbort("size undefined (zaxis description file: %s)!", dname);
+          zaxis->ubounds = (double*) Malloc(zaxis->size*sizeof(double));
+          for ( size_t i = 0; i < (size_t) zaxis->size; ++i ) zaxis->ubounds[i] = parameter2double(kv->values[i]);
+        }
+      else if ( STR_IS_EQ(key, "vct") )
+        {
+          if ( zaxis->vctsize == 0 ) cdoAbort("vctsize undefined (zaxis description file: %s)!", dname);
+          zaxis->vct = (double*) Malloc(zaxis->vctsize*sizeof(double));
+          for ( size_t i = 0; i < (size_t) zaxis->vctsize; ++i ) zaxis->vct[i] = parameter2double(kv->values[i]);
+        }
+      else
+        {
+          *iatt = ik; break;
+        }
+    }
+}
+
+static
+void zaxis_read_attributes(size_t iatt, size_t nkv, kvmap_t *kvmap, int zaxisID)
+{
+  for ( size_t ik = iatt; ik < nkv; ++ik )
+    {
+      if ( !kvmap[ik].isValid ) continue;
+
+      keyValues_t *kv = kvmap[ik].kv;
+      const char *key = kv->key;
+      size_t nvalues = kv->nvalues;
+      const char *value = (kv->nvalues > 0) ? kv->values[0] : NULL;
+      
+      int dtype = literals_find_datatype(nvalues, kv->values);
+
+      if ( dtype == CDI_DATATYPE_INT8 || dtype == CDI_DATATYPE_INT16 || dtype == CDI_DATATYPE_INT32 )
+        {
+          int *ivals = (int*) Malloc(nvalues*sizeof(int));
+          for ( size_t i = 0; i < nvalues; ++i ) ivals[i] = literal_to_int(kv->values[i]);
+          cdiDefAttInt(zaxisID, CDI_GLOBAL, key, dtype, nvalues, ivals);
+          Free(ivals);
+        }
+      else if ( dtype == CDI_DATATYPE_FLT32 || dtype == CDI_DATATYPE_FLT64 )
+        {
+          double *dvals = (double*) Malloc(nvalues*sizeof(double));
+          for ( size_t i = 0; i < nvalues; ++i ) dvals[i] = literal_to_double(kv->values[i]);
+          cdiDefAttFlt(zaxisID, CDI_GLOBAL, key, dtype, nvalues, dvals);
+          Free(dvals);
+        }
+      else
+        {
+          int len = (value && *value) ? (int) strlen(value) : 0;
+          cdiDefAttTxt(zaxisID, CDI_GLOBAL, key, len, value);
+        }
+    }
 }
 
 
 int zaxisFromFile(FILE *gfp, const char *dname)
 {
-  char line[MAX_LINE_LEN], *pline;
-  int zaxisID;
-  size_t i, len;
-  zaxis_t zaxis;
+  list_t *pmlist = namelist_to_pmlist(gfp, dname);
+  if ( pmlist == NULL ) return -1;
+  list_t *kvlist = *(list_t **)pmlist->head->data;
+  if ( kvlist == NULL ) return -1;
+
+  size_t nkv = list_size(kvlist);
+  if ( nkv == 0 ) return -1;
+  kvmap_t *kvmap = (kvmap_t*) Malloc(nkv*sizeof(kvmap_t));
+  for ( size_t i = 0; i < nkv; ++i ) kvmap[i].isValid = false;
+
+  size_t ik = 0;
+  for ( listNode_t *kvnode = kvlist->head; kvnode; kvnode = kvnode->next )
+    {
+      keyValues_t *kv = *(keyValues_t **)kvnode->data;
+      if ( ik == 0 && !STR_IS_EQ(kv->key, "zaxistype") )
+        cdoAbort("First zaxis description parameter must be >zaxistype< (found: %s)!", kv->key);
+
+      if ( kv->nvalues == 0 )
+        {
+          cdoWarning("Z-axis description parameter %s has no values, skipped!", kv->key);
+        }
+      else
+        {
+          kvmap[ik].isValid = true;
+          kvmap[ik].kv = kv;
+        }
+      ik++;
+    }
 
+  zaxis_t zaxis;
   zaxisInit(&zaxis);
 
-  while ( readline(gfp, line, MAX_LINE_LEN) )
+  size_t iatt = 0;
+  zaxis_read_data(nkv, kvmap, &zaxis, &iatt, dname);
+
+  int zaxisID = (zaxis.type == CDI_UNDEFID) ? CDI_UNDEFID : zaxisDefine(zaxis);
+
+  if ( zaxisID != CDI_UNDEFID && iatt > 0 )
     {
-      if ( line[0] == '#' ) continue;
-      if ( line[0] == '\0' ) continue;
-      len = strlen(line);
-
-      bool lerror = false;
-      for ( i = 0; i < len; ++i )
-	if ( !(line[i] == 9 || (line[i] > 31 && line[i] < 127)) )
-	  {
-	    lerror = true;
-	    line[i] = '#';
-	  }
-      if ( lerror ) cdoAbort("Zaxis description file >%s< contains illegal characters (line: %s)!", dname, line);
-
-      pline = line;
-      while ( isspace((int) *pline) ) pline++;
-      if ( pline[0] == '\0' ) continue;
-      if ( cmpstrlen(pline, "zaxistype", len) == 0 || 
-	   cmpstrlen(pline, "type", len) == 0 )
-	{
-	  if ( *pline == 'z' )
-	    pline = skipSeparator(pline + 9);
-	  else
-	    pline = skipSeparator(pline + 4);
-
-	  if ( cmpstrlen(pline, "pressure", len) == 0 )
-	    zaxis.type = ZAXIS_PRESSURE;
-	  else if ( cmpstrlen(pline, "hybrid_half", len)  == 0 )
-	    zaxis.type = ZAXIS_HYBRID_HALF;
-	  else if ( cmpstrlen(pline, "hybrid", len)  == 0 )
-	    zaxis.type = ZAXIS_HYBRID;
-	  else if ( cmpstrlen(pline, "height", len) == 0 )
-	    zaxis.type = ZAXIS_HEIGHT;
-	  else if ( cmpstrlen(pline, "depth below sea", len) == 0 ||
-		    cmpstrlen(pline, "depth_below_sea", len) == 0 )
-	    zaxis.type = ZAXIS_DEPTH_BELOW_SEA;
-	  else if ( cmpstrlen(pline, "depth below land", len) == 0 ||
-		    cmpstrlen(pline, "depth_below_land", len) == 0 )
-	    zaxis.type = ZAXIS_DEPTH_BELOW_LAND;
-	  else if ( cmpstrlen(pline, "isentropic", len)  == 0 )
-	    zaxis.type = ZAXIS_ISENTROPIC;
-	  else if ( cmpstrlen(pline, "surface", len)  == 0 )
-	    zaxis.type = ZAXIS_SURFACE;
-	  else if ( cmpstrlen(pline, "generic", len)  == 0 )
-	    zaxis.type = ZAXIS_GENERIC;
-	  else
-	    cdoAbort("Invalid zaxisname : %s (zaxis description file: %s)", pline, dname);
-	}
-      else if ( cmpstrlen(pline, "size", len)  == 0 )
-	{
-	  zaxis.size = atol(skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "vctsize", len)  == 0 )
-	{
-	  zaxis.vctsize = atol(skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "name", len)  == 0 )
-	{
-	  strcpy(zaxis.name, skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "longname", len)  == 0 )
-	{
-	  strcpy(zaxis.longname, skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "units", len)  == 0 )
-	{
-	  strcpy(zaxis.units, skipSeparator(pline + len));
-	}
-      else if ( cmpstrlen(pline, "levels", len)  == 0 )
-	{
-	  int i;
-	  double flev;
-
-	  if ( zaxis.size > 0 )
-	    {
-	      pline = skipSeparator(pline + len);
-	  
-	      zaxis.vals = (double*) Malloc(zaxis.size*sizeof(double));
-	      for ( i = 0; i < zaxis.size; i++ )
-		{
-		  pline = skipSeparator(pline);
-		  if ( strlen(pline) == 0 )
-		    {
-		      if ( ! readline(gfp, line, MAX_LINE_LEN) )
-			cdoAbort("Incomplete command: >levels< (zaxis description file: %s)", dname);
-
-		      pline = line;
-		      pline = skipSeparator(pline);
-		    }
-		  flev = 0;
-		  sscanf(pline, "%lg", &flev);
-		  zaxis.vals[i] = flev;
-		  while ( isalnum((int) *pline) ||
-			  isdigit((int) *pline) ||
-			  ispunct((int) *pline) ) pline++;
-		}
-	    }
-	  else
-	    {
-	      cdoAbort("size undefined (zaxis description file: %s)!", dname);
-	    }
-	}
-      else if ( cmpstrlen(pline, "vct", len)  == 0 )
-	{
-	  int i;
-	  double flev;
-
-	  if ( zaxis.vctsize > 0 )
-	    {
-	      pline = skipSeparator(pline + len);
-	  
-	      zaxis.vct = (double*) Malloc(zaxis.vctsize*sizeof(double));
-	      for ( i = 0; i < zaxis.vctsize; i++ )
-		{
-		  pline = skipSeparator(pline);
-		  if ( strlen(pline) == 0 )
-		    {
-		      if ( ! readline(gfp, line, MAX_LINE_LEN) )
-			cdoAbort("Incomplete command: >vct< (zaxis description file: %s)", dname);
-
-		      pline = line;
-		      pline = skipSeparator(pline);
-		    }
-		  flev = 0;
-		  sscanf(pline, "%lg", &flev);
-		  zaxis.vct[i] = flev;
-		  while ( isalnum((int) *pline) ||
-			  isdigit((int) *pline) ||
-			  ispunct((int) *pline) ) pline++;
-		}
-	    }
-	  else
-	    {
-	      cdoAbort("vctsize undefined (zaxis description file: %s)!", dname);
-	    }
-	}
-      else if ( cmpstrlen(pline, "lbounds", len)  == 0 )
-	{
-	  int i;
-	  double flev;
-
-	  if ( zaxis.size > 0 )
-	    {
-	      pline = skipSeparator(pline + len);
-	  
-	      zaxis.lbounds = (double*) Malloc(zaxis.size*sizeof(double));
-	      for ( i = 0; i < zaxis.size; i++ )
-		{
-		  pline = skipSeparator(pline);
-		  if ( strlen(pline) == 0 )
-		    {
-		      if ( ! readline(gfp, line, MAX_LINE_LEN) )
-			cdoAbort("Incomplete command: >lbounds< (zaxis description file: %s)", dname);
-
-		      pline = line;
-		      pline = skipSeparator(pline);
-		    }
-		  flev = 0;
-		  sscanf(pline, "%lg", &flev);
-		  zaxis.lbounds[i] = flev;
-		  while ( isalnum((int) *pline) ||
-			  isdigit((int) *pline) ||
-			  ispunct((int) *pline) ) pline++;
-		}
-	    }
-	  else
-	    {
-	      cdoAbort("size undefined (zaxis description file: %s)!", dname);
-	    }
-	}
-      else if ( cmpstrlen(pline, "ubounds", len)  == 0 )
-	{
-	  int i;
-	  double flev;
-
-	  if ( zaxis.size > 0 )
-	    {
-	      pline = skipSeparator(pline + len);
-	  
-	      zaxis.ubounds = (double*) Malloc(zaxis.size*sizeof(double));
-	      for ( i = 0; i < zaxis.size; i++ )
-		{
-		  pline = skipSeparator(pline);
-		  if ( strlen(pline) == 0 )
-		    {
-		      if ( ! readline(gfp, line, MAX_LINE_LEN) )
-			cdoAbort("Incomplete command: >ubounds< (zaxis description file: %s)", dname);
-
-		      pline = line;
-		      pline = skipSeparator(pline);
-		    }
-		  flev = 0;
-		  sscanf(pline, "%lg", &flev);
-		  zaxis.ubounds[i] = flev;
-		  while ( isalnum((int) *pline) ||
-			  isdigit((int) *pline) ||
-			  ispunct((int) *pline) ) pline++;
-		}
-	    }
-	  else
-	    {
-	      cdoAbort("size undefined (zaxis description file: %s)!", dname);
-	    }
-	}
-      else
-	cdoAbort("Invalid zaxis command : >%s< (zaxis description file: %s)", pline, dname);
+      zaxis_read_attributes(iatt, nkv, kvmap, zaxisID);
     }
 
-  zaxisID = zaxisDefine(zaxis);
+  list_destroy(pmlist);
+
+  Free(kvmap);
 
   return zaxisID;
 }
 
+static
+void gen_zaxis_height(zaxis_t *zaxis, const char *pline)
+{
+  int zaxistype = ZAXIS_HEIGHT;
+
+  if ( CDO_CMOR_Mode ) zaxis->scalar = true;
+
+  if ( *pline != 0 )
+    {
+      if ( *pline == '_' ) pline++;
+      else return;
+
+      if ( *pline == 0 ) return;
+
+      if ( ! isdigit((int) *pline) && !ispunct((int) *pline) ) return;
+
+      char *endptr = (char *) pline;
+      double value = strtod(pline, &endptr);
+      if ( *endptr != 0 )
+        {
+          pline = endptr;
+          if ( *pline == '_' ) pline++;
+          
+          if ( *pline == 0 ) return;
+          const char *units = pline;
+
+          zaxis->type = zaxistype;
+          zaxis->size = 1;
+          // zaxis->scalar = true;
+          double *levels = (double*) Malloc(sizeof(double));
+          *levels = value;
+          zaxis->vals = levels;
+          strcpy(zaxis->units, units);
+
+          size_t len = strlen(units);
+          if ( len > 2 && units[len-2] == '_' && units[len-1] == 's' )
+            {
+              zaxis->units[len-2] = 0;
+              zaxis->scalar = true;
+            }
+        }
+    }
+}
+
 
-int zaxisFromName(const char *zaxisname)
+int zaxisFromName(const char *zaxisnameptr)
 {
-  const char *pline;
   int zaxisID = UNDEFID;
-  zaxis_t zaxis;
+  size_t len;
+
+  char *zaxisname = strdup(zaxisnameptr);
+  strtolower(zaxisname);
 
+  zaxis_t zaxis;
   zaxisInit(&zaxis);
 
-  pline = zaxisname;
+  const char *pline = zaxisname;
   if ( cmpstr(pline, "surface") == 0 ) /* surface */
     {
       zaxis.type = ZAXIS_SURFACE;
@@ -389,19 +357,25 @@ int zaxisFromName(const char *zaxisname)
       zaxis.vals = (double*) Malloc(zaxis.size*sizeof(double));
       zaxis.vals[0] = 0;
     }
+  else if ( cmpstrlen(zaxisname, "height", len) == 0 )
+    {
+      pline = &zaxisname[len];
+      gen_zaxis_height(&zaxis, pline);
+    }
 
   if ( zaxis.type != -1 ) zaxisID = zaxisDefine(zaxis);
 
+  free(zaxisname);
+
   return zaxisID;
 }
 
 
 int cdoDefineZaxis(const char *zaxisfile)
 {
-  FILE *zfp;
   int zaxisID = -1;
 
-  zfp = fopen(zaxisfile, "r");
+  FILE *zfp = fopen(zaxisfile, "r");
   if ( zfp == NULL )
     {
       zaxisID = zaxisFromName(zaxisfile);
@@ -453,12 +427,8 @@ int ztype2ltype(int zaxistype)
 
 int zaxis2ltype(int zaxisID)
 {
-  int ltype;
-  int zaxistype;
-
-  zaxistype = zaxisInqType(zaxisID);
-
-  ltype = zaxisInqLtype(zaxisID);
+  int zaxistype = zaxisInqType(zaxisID);
+  int ltype = zaxisInqLtype(zaxisID);
 
   if ( ltype <= 0 ) ltype = ztype2ltype(zaxistype);
 
diff --git a/src/zaxis_print.c b/src/zaxis_print.c
new file mode 100644
index 0000000..7fb029e
--- /dev/null
+++ b/src/zaxis_print.c
@@ -0,0 +1,107 @@
+#include <cdi.h>
+#include "cdi_uuid.h"
+#include "cdo_int.h"
+
+void cdo_print_attributes(FILE *fp, int cdiID, int varID, int nblanks);
+
+static
+void printDblsPrefixAutoBrk(FILE *fp, int dig, const char prefix[], int nbyte0, size_t n, const double vals[], size_t extbreak)
+{
+  fputs(prefix, fp);
+  int nbyte = nbyte0;
+  for ( size_t i = 0; i < n; i++ )
+    {
+      if ( nbyte > 80  || (i && i == extbreak) )
+        {
+          fprintf(fp, "\n%*s", nbyte0, "");
+          nbyte = nbyte0;
+        }
+      nbyte += fprintf(fp, "%.*g ", dig, vals[i]);
+    }
+  fputs("\n", fp);
+}
+
+static
+void zaxis_print_kernel(int zaxisID, FILE *fp)
+{
+  char attstr[CDI_MAX_NAME];
+  int type    = zaxisInqType(zaxisID);
+  int nlevels = zaxisInqSize(zaxisID);
+  int prec    = zaxisInqPrec(zaxisID);
+  size_t nvals = (size_t) zaxisInqLevels(zaxisID, NULL);
+
+  int dig = (prec == CDI_DATATYPE_FLT64) ? CDO_dbl_digits : CDO_flt_digits;
+
+  fprintf(fp, "zaxistype = %s\n", zaxisNamePtr(type));
+  fprintf(fp, "size      = %d\n", nlevels);
+
+  if ( nlevels == 1 && zaxisInqScalar(zaxisID) ) fprintf(fp, "scalar    = true\n");
+
+  attstr[0] = 0; cdiZaxisInqKeyStr(zaxisID, CDI_KEY_NAME, CDI_MAX_NAME, attstr);
+  if ( attstr[0] )  fprintf(fp, "name      = %s\n", attstr);
+  attstr[0] = 0; cdiZaxisInqKeyStr(zaxisID, CDI_KEY_LONGNAME, CDI_MAX_NAME, attstr);
+  if ( attstr[0] )  fprintf(fp, "longname  = \"%s\"\n", attstr);
+  attstr[0] = 0; cdiZaxisInqKeyStr(zaxisID, CDI_KEY_UNITS, CDI_MAX_NAME, attstr);
+  if ( attstr[0] )  fprintf(fp, "units     = \"%s\"\n", attstr);
+
+  double *vals = (double*) Malloc(nvals*sizeof(double));
+
+  if ( nvals )
+    {                
+      zaxisInqLevels(zaxisID, vals);
+      static const char prefix[] = "levels    = ";
+      printDblsPrefixAutoBrk(fp, dig, prefix, (int)sizeof(prefix)-1, nvals, vals, 0);
+    }
+
+  if ( zaxisInqLbounds(zaxisID, NULL) && zaxisInqUbounds(zaxisID, NULL) )
+    {
+      {
+        zaxisInqLbounds(zaxisID, vals);
+        static const char prefix[] = "lbounds   = ";
+        printDblsPrefixAutoBrk(fp, dig, prefix, (int)sizeof(prefix)-1, nvals, vals, 0);
+      }
+
+      {
+        zaxisInqUbounds(zaxisID, vals);
+        static const char prefix[] = "ubounds   = ";
+        printDblsPrefixAutoBrk(fp, dig, prefix, (int)sizeof(prefix)-1, nvals, vals, 0);
+      }
+    }
+
+  Free(vals);
+
+  if ( type == ZAXIS_HYBRID || type == ZAXIS_HYBRID_HALF )
+    {
+      int vctsize = zaxisInqVctSize(zaxisID);
+      if ( vctsize )
+        {
+          fprintf(fp, "vctsize   = %d\n", vctsize);
+          double *vct = (double*) Malloc(vctsize*sizeof(double));
+          zaxisInqVct(zaxisID, vct);
+          static const char prefix[] = "vct       = ";
+          printDblsPrefixAutoBrk(fp, dig, prefix, (int)sizeof(prefix)-1, vctsize, vct, vctsize/2);
+          Free(vct);
+        }
+    }
+
+  if ( type == ZAXIS_REFERENCE )
+    {
+      unsigned char uuid[CDI_UUID_SIZE];
+      zaxisInqUUID(zaxisID, uuid);
+      if ( !cdiUUIDIsNull(uuid) )
+        {
+          char uuidStr[37];
+          cdiUUID2Str(uuid, uuidStr);
+          if ( uuidStr[0] != 0 && strlen(uuidStr) == 36 )
+            fprintf(fp, "uuid      = %s\n", uuidStr);
+        }
+    }
+
+  cdo_print_attributes(fp, zaxisID, CDI_GLOBAL, 0);
+}
+
+
+void cdo_print_zaxis(int zaxisID)
+{
+  zaxis_print_kernel(zaxisID, stdout);
+}
diff --git a/test/Arithc.test.in b/test/Arithc.test.in
index 3b2eb88..04f5f54 100644
--- a/test/Arithc.test.in
+++ b/test/Arithc.test.in
@@ -53,7 +53,7 @@ for STAT in $STATS; do
     if [ "$STAT" = sub ] ; then OP='-' ; fi
     if [ "$STAT" = mul ] ; then OP='*' ; fi
     if [ "$STAT" = div ] ; then OP='/' ; fi
-    OFILE3=expr${STAT}_res
+    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"
diff --git a/test/Fldstat.test.in b/test/Comp.test.in
similarity index 59%
copy from test/Fldstat.test.in
copy to test/Comp.test.in
index 5bbccab..df3acce 100644
--- a/test/Fldstat.test.in
+++ b/test/Comp.test.in
@@ -1,5 +1,5 @@
 #! @SHELL@
-echo 1..9 # Number of tests to be executed.
+echo 1..6 # Number of tests to be executed.
 #
 test -n "$CDO"      || CDO=cdo
 test -n "$DATAPATH" || DATAPATH=./data
@@ -7,22 +7,23 @@ test -n "$DATAPATH" || DATAPATH=./data
 CDOOUT=cout$$
 CDOERR=cerr$$
 FORMAT="-f srv -b 32"
+STATS="eq ne le lt ge gt"
+CONST=300
 #
-STATS="min max sum avg mean std std1 var var1"
-#
-IFILE=$DATAPATH/t21_geosp_tsurf.grb
-#
+IFILE=$DATAPATH/comptest.srv
 NTEST=1
+CFILE=constdata
+$CDO $FORMAT const,${CONST},${IFILE} $CFILE
 #
 for STAT in $STATS; do
   RSTAT=0
-  RFILE=$DATAPATH/fld${STAT}_ref
-  OFILE=fld${STAT}_res
+  RFILE=$DATAPATH/comp_${STAT}c_ref
+  OFILE=comp_${STAT}_res
 
-  CDOTEST="fld$STAT"
-  CDOCOMMAND="$CDO $FORMAT fld${STAT} $IFILE $OFILE"
+  CDOTEST="$STAT"
+  CDOCOMMAND="$CDO $FORMAT ${STAT} $IFILE $CFILE $OFILE"
 
-  echo "Running test: $NTEST"
+  echo "Running test: $NTEST - $CDOTEST"
   echo "$CDOCOMMAND"
 
   $CDOCOMMAND
@@ -40,6 +41,6 @@ for STAT in $STATS; do
   rm -f $OFILE
 done
 #
-rm -f $CDOOUT $CDOERR
+rm -f $CDOOUT $CDOERR $CFILE
 #
 exit 0
diff --git a/test/Fldstat.test.in b/test/Compc.test.in
similarity index 65%
copy from test/Fldstat.test.in
copy to test/Compc.test.in
index 5bbccab..5abae87 100644
--- a/test/Fldstat.test.in
+++ b/test/Compc.test.in
@@ -1,5 +1,5 @@
 #! @SHELL@
-echo 1..9 # Number of tests to be executed.
+echo 1..6 # Number of tests to be executed.
 #
 test -n "$CDO"      || CDO=cdo
 test -n "$DATAPATH" || DATAPATH=./data
@@ -7,22 +7,21 @@ test -n "$DATAPATH" || DATAPATH=./data
 CDOOUT=cout$$
 CDOERR=cerr$$
 FORMAT="-f srv -b 32"
+STATS="eqc nec lec ltc gec gtc"
+CONST=300
 #
-STATS="min max sum avg mean std std1 var var1"
-#
-IFILE=$DATAPATH/t21_geosp_tsurf.grb
-#
+IFILE=$DATAPATH/comptest.srv
 NTEST=1
 #
 for STAT in $STATS; do
   RSTAT=0
-  RFILE=$DATAPATH/fld${STAT}_ref
-  OFILE=fld${STAT}_res
+  RFILE=$DATAPATH/comp_${STAT}_ref
+  OFILE=comp_${STAT}_res
 
-  CDOTEST="fld$STAT"
-  CDOCOMMAND="$CDO $FORMAT fld${STAT} $IFILE $OFILE"
+  CDOTEST="$STAT"
+  CDOCOMMAND="$CDO $FORMAT ${STAT},${CONST} $IFILE $OFILE"
 
-  echo "Running test: $NTEST"
+  echo "Running test: $NTEST - $CDOTEST"
   echo "$CDOCOMMAND"
 
   $CDOCOMMAND
diff --git a/test/EOF.test.in b/test/EOF.test.in
new file mode 100644
index 0000000..4e2a6e6
--- /dev/null
+++ b/test/EOF.test.in
@@ -0,0 +1,64 @@
+#! @SHELL@
+#
+echo 1..2 # Number of tests to be executed.
+#
+test -n "$CDO"      || CDO=cdo
+test -n "$DATAPATH" || DATAPATH=./data
+#
+export CDO_FILE_SUFFIX=NULL
+export CDO_WEIGHT_MODE=off
+#export CDO_SVD_MODE=danielson_lanczos
+#
+CDOOUT=cout$$
+CDOERR=cerr$$
+FORMAT="-f srv -b 32"
+NTEST=1
+######################################################
+IFILE=$DATAPATH/psl_DJF_anom.grb
+RFILE1=$DATAPATH/eval_ref
+RFILE2=$DATAPATH/eof_ref
+RFILE3=$DATAPATH/pcoeff00000
+OFILE1=eval_res
+OFILE2=eof_res
+OFILE3=res_pcoeff
+#
+for MODE in jacobi danielson_lanczos; do
+  export CDO_SVD_MODE=$MODE
+  RSTAT=0
+  CDOTEST="eof/eofcoeff - $MODE"
+  CDOCOMMAND="$CDO $FORMAT eof,1 $IFILE $OFILE1 $OFILE2"
+  echo "$CDOCOMMAND"
+
+  $CDOCOMMAND
+  test $? -eq 0 || let RSTAT+=1
+#
+  $CDO diff,1e-8 $OFILE1 $RFILE1 > $CDOOUT 2> $CDOERR
+  test $? -eq 0 || let RSTAT+=1
+  test -s $CDOOUT && let RSTAT+=1
+#
+  $CDO diff,1e-7 -abs $OFILE2 -abs $RFILE2 > $CDOOUT 2> $CDOERR
+  test $? -eq 0 || let RSTAT+=1
+  test -s $CDOOUT && let RSTAT+=1
+
+  CDOCOMMAND="$CDO $FORMAT eofcoeff $OFILE2 $IFILE $OFILE3"
+  echo "$CDOCOMMAND"
+
+  $CDOCOMMAND
+  test $? -eq 0 || let RSTAT+=1
+#
+  $CDO diff,0.02 -abs ${OFILE3}00000 -abs $RFILE3 > $CDOOUT 2> $CDOERR
+  test $? -eq 0 || let RSTAT+=1
+  test -s $CDOOUT && let RSTAT+=1
+
+  cat $CDOOUT $CDOERR
+#
+  test $RSTAT -eq 0 && echo "ok $NTEST - $CDOTEST"
+  test $RSTAT -eq 0 || echo "not ok $NTEST - $CDOTEST"
+#
+  let NTEST+=1
+  rm -f $OFILE1 $OFILE2 ${OFILE3}00000
+done
+#
+rm -f $CDOOUT $CDOERR
+#
+exit 0
diff --git a/test/Fldstat.test.in b/test/Fldstat.test.in
index 5bbccab..69a3665 100644
--- a/test/Fldstat.test.in
+++ b/test/Fldstat.test.in
@@ -8,6 +8,7 @@ CDOOUT=cout$$
 CDOERR=cerr$$
 FORMAT="-f srv -b 32"
 #
+TYPE=fld
 STATS="min max sum avg mean std std1 var var1"
 #
 IFILE=$DATAPATH/t21_geosp_tsurf.grb
@@ -16,11 +17,11 @@ NTEST=1
 #
 for STAT in $STATS; do
   RSTAT=0
-  RFILE=$DATAPATH/fld${STAT}_ref
-  OFILE=fld${STAT}_res
+  RFILE=$DATAPATH/${TYPE}${STAT}_ref
+  OFILE=${TYPE}${STAT}_res
 
-  CDOTEST="fld$STAT"
-  CDOCOMMAND="$CDO $FORMAT fld${STAT} $IFILE $OFILE"
+  CDOTEST="${TYPE}$STAT"
+  CDOCOMMAND="$CDO $FORMAT ${TYPE}${STAT} $IFILE $OFILE"
 
   echo "Running test: $NTEST"
   echo "$CDOCOMMAND"
diff --git a/test/Fldstat.test.in b/test/Gridboxstat.test.in
similarity index 85%
copy from test/Fldstat.test.in
copy to test/Gridboxstat.test.in
index 5bbccab..7038ae7 100644
--- a/test/Fldstat.test.in
+++ b/test/Gridboxstat.test.in
@@ -8,6 +8,7 @@ CDOOUT=cout$$
 CDOERR=cerr$$
 FORMAT="-f srv -b 32"
 #
+TYPE=gridbox
 STATS="min max sum avg mean std std1 var var1"
 #
 IFILE=$DATAPATH/t21_geosp_tsurf.grb
@@ -17,10 +18,10 @@ NTEST=1
 for STAT in $STATS; do
   RSTAT=0
   RFILE=$DATAPATH/fld${STAT}_ref
-  OFILE=fld${STAT}_res
+  OFILE=${TYPE}${STAT}_res
 
-  CDOTEST="fld$STAT"
-  CDOCOMMAND="$CDO $FORMAT fld${STAT} $IFILE $OFILE"
+  CDOTEST="${TYPE}$STAT"
+  CDOCOMMAND="$CDO $FORMAT ${TYPE}${STAT},64,32 $IFILE $OFILE"
 
   echo "Running test: $NTEST"
   echo "$CDOCOMMAND"
diff --git a/test/Makefile.am b/test/Makefile.am
index 564e053..8297062 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -11,9 +11,15 @@ TEST_LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \
                   $(top_srcdir)/config/tap-driver.sh
 
 # tests which should pass
-TESTS = threads.test tsformat.test wildcard.test File.test Read_grib.test Read_netcdf.test Copy_netcdf.test Cat.test Gridarea.test  \
-        Detrend.test Genweights.test Remap.test Select.test Spectral.test Ymonstat.test Timstat.test Ensstat.test \
-        Enspctl.test Fldstat.test Fldpctl.test Vertint.test Afterburner.test Arithc.test Arith.test Expr.test \
+TESTS = threads.test tsformat.test wildcard.test File.test Comp.test Compc.test \
+        Read_grib.test Read_netcdf.test Copy_netcdf.test Cat.test Gridarea.test  \
+        Detrend.test Genweights.test Remap.test Select.test Spectral.test \
+        Ensstat.test Enspctl.test Gridboxstat.test \
+        Vertstat.test Fldstat.test Fldpctl.test Merstat.test Zonstat.test \
+        Timstat.test Timselstat.test Seasstat.test \
+        Runstat.test Multiyearstat.test \
+        EOF.test \
+        Vertint.test Afterburner.test Arithc.test Arith.test Expr.test \
         Gradsdes.test Collgrid.test MapReduce.test Ninfo.test
 
 # tests which should fail
diff --git a/test/Makefile.in b/test/Makefile.in
index dafd17f..4444989 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -82,13 +82,18 @@ 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)/Cat.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)/Select.test.in \
-	$(srcdir)/Spectral.test.in $(srcdir)/Timstat.test.in \
-	$(srcdir)/Vertint.test.in $(srcdir)/Ymonstat.test.in \
+	$(srcdir)/Remap.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)/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)/Afterburner.test.in $(srcdir)/Detrend.test.in \
 	$(srcdir)/Arithc.test.in $(srcdir)/Arith.test.in \
 	$(srcdir)/Expr.test.in $(srcdir)/Gradsdes.test.in \
@@ -106,12 +111,15 @@ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
 mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
 CONFIG_HEADER = $(top_builddir)/src/config.h
 CONFIG_CLEAN_FILES = File.test Read_grib.test Read_netcdf.test \
-	Copy_netcdf.test Cat.test Gridarea.test Genweights.test \
-	Remap.test Select.test Spectral.test Timstat.test Vertint.test \
-	Ymonstat.test Fldstat.test Fldpctl.test Ensstat.test \
-	Enspctl.test Afterburner.test Detrend.test Arithc.test \
-	Arith.test Expr.test Gradsdes.test Collgrid.test threads.test \
-	tsformat.test wildcard.test MapReduce.test Ninfo.test
+	Copy_netcdf.test Comp.test Compc.test Cat.test Gridarea.test \
+	Genweights.test Remap.test EOF.test Select.test Spectral.test \
+	Vertint.test Timstat.test Timselstat.test Seasstat.test \
+	Runstat.test Multiyearstat.test Gridboxstat.test Vertstat.test \
+	Fldstat.test Fldpctl.test Ensstat.test Enspctl.test \
+	Merstat.test Zonstat.test Afterburner.test Detrend.test \
+	Arithc.test Arith.test Expr.test Gradsdes.test Collgrid.test \
+	threads.test tsformat.test wildcard.test MapReduce.test \
+	Ninfo.test
 CONFIG_CLEAN_VPATH_FILES =
 AM_V_P = $(am__v_P_ at AM_V@)
 am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
@@ -520,9 +528,15 @@ TEST_LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \
 
 
 # tests which should pass
-TESTS = threads.test tsformat.test wildcard.test File.test Read_grib.test Read_netcdf.test Copy_netcdf.test Cat.test Gridarea.test  \
-        Detrend.test Genweights.test Remap.test Select.test Spectral.test Ymonstat.test Timstat.test Ensstat.test \
-        Enspctl.test Fldstat.test Fldpctl.test Vertint.test Afterburner.test Arithc.test Arith.test Expr.test \
+TESTS = threads.test tsformat.test wildcard.test File.test Comp.test Compc.test \
+        Read_grib.test Read_netcdf.test Copy_netcdf.test Cat.test Gridarea.test  \
+        Detrend.test Genweights.test Remap.test Select.test Spectral.test \
+        Ensstat.test Enspctl.test Gridboxstat.test \
+        Vertstat.test Fldstat.test Fldpctl.test Merstat.test Zonstat.test \
+        Timstat.test Timselstat.test Seasstat.test \
+        Runstat.test Multiyearstat.test \
+        EOF.test \
+        Vertint.test Afterburner.test Arithc.test Arith.test Expr.test \
         Gradsdes.test Collgrid.test MapReduce.test Ninfo.test
 
 
@@ -580,6 +594,10 @@ Read_netcdf.test: $(top_builddir)/config.status $(srcdir)/Read_netcdf.test.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 Copy_netcdf.test: $(top_builddir)/config.status $(srcdir)/Copy_netcdf.test.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+Comp.test: $(top_builddir)/config.status $(srcdir)/Comp.test.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+Compc.test: $(top_builddir)/config.status $(srcdir)/Compc.test.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 Cat.test: $(top_builddir)/config.status $(srcdir)/Cat.test.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 Gridarea.test: $(top_builddir)/config.status $(srcdir)/Gridarea.test.in
@@ -588,15 +606,27 @@ Genweights.test: $(top_builddir)/config.status $(srcdir)/Genweights.test.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 Remap.test: $(top_builddir)/config.status $(srcdir)/Remap.test.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+EOF.test: $(top_builddir)/config.status $(srcdir)/EOF.test.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 Select.test: $(top_builddir)/config.status $(srcdir)/Select.test.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 Spectral.test: $(top_builddir)/config.status $(srcdir)/Spectral.test.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+Vertint.test: $(top_builddir)/config.status $(srcdir)/Vertint.test.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 Timstat.test: $(top_builddir)/config.status $(srcdir)/Timstat.test.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
-Vertint.test: $(top_builddir)/config.status $(srcdir)/Vertint.test.in
+Timselstat.test: $(top_builddir)/config.status $(srcdir)/Timselstat.test.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
-Ymonstat.test: $(top_builddir)/config.status $(srcdir)/Ymonstat.test.in
+Seasstat.test: $(top_builddir)/config.status $(srcdir)/Seasstat.test.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+Runstat.test: $(top_builddir)/config.status $(srcdir)/Runstat.test.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+Multiyearstat.test: $(top_builddir)/config.status $(srcdir)/Multiyearstat.test.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+Gridboxstat.test: $(top_builddir)/config.status $(srcdir)/Gridboxstat.test.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+Vertstat.test: $(top_builddir)/config.status $(srcdir)/Vertstat.test.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 Fldstat.test: $(top_builddir)/config.status $(srcdir)/Fldstat.test.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
@@ -606,6 +636,10 @@ Ensstat.test: $(top_builddir)/config.status $(srcdir)/Ensstat.test.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 Enspctl.test: $(top_builddir)/config.status $(srcdir)/Enspctl.test.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+Merstat.test: $(top_builddir)/config.status $(srcdir)/Merstat.test.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+Zonstat.test: $(top_builddir)/config.status $(srcdir)/Zonstat.test.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 Afterburner.test: $(top_builddir)/config.status $(srcdir)/Afterburner.test.in
 	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
 Detrend.test: $(top_builddir)/config.status $(srcdir)/Detrend.test.in
diff --git a/test/MapReduce.test.in b/test/MapReduce.test.in
index 22e3669..3d75b3f 100644
--- a/test/MapReduce.test.in
+++ b/test/MapReduce.test.in
@@ -27,8 +27,9 @@ for OPERATOR in reducegrid; do
       $CDOCOMMAND
       test $? -eq 0 || let RSTAT+=1
 
-      $CDO griddes reduced_${grid}.nc > griddes.${grid}
-      cmp griddes.${grid} $REF
+#      $CDO griddes reduced_${grid}.nc > griddes.${grid}
+      $CDO griddes reduced_${grid}.nc | sed -e s-\"--g > griddes.${grid}
+      diff griddes.${grid} $REF
       test $? -eq 0 || let RSTAT+=1
 
       rm reduced_${grid}.nc
diff --git a/test/Fldstat.test.in b/test/Merstat.test.in
similarity index 82%
copy from test/Fldstat.test.in
copy to test/Merstat.test.in
index 5bbccab..7ae2556 100644
--- a/test/Fldstat.test.in
+++ b/test/Merstat.test.in
@@ -8,6 +8,7 @@ CDOOUT=cout$$
 CDOERR=cerr$$
 FORMAT="-f srv -b 32"
 #
+TYPE=mer
 STATS="min max sum avg mean std std1 var var1"
 #
 IFILE=$DATAPATH/t21_geosp_tsurf.grb
@@ -16,11 +17,11 @@ NTEST=1
 #
 for STAT in $STATS; do
   RSTAT=0
-  RFILE=$DATAPATH/fld${STAT}_ref
-  OFILE=fld${STAT}_res
+  RFILE=$DATAPATH/${TYPE}${STAT}_ref
+  OFILE=${TYPE}${STAT}_res
 
-  CDOTEST="fld$STAT"
-  CDOCOMMAND="$CDO $FORMAT fld${STAT} $IFILE $OFILE"
+  CDOTEST="${TYPE}$STAT"
+  CDOCOMMAND="$CDO $FORMAT ${TYPE}${STAT} $IFILE $OFILE"
 
   echo "Running test: $NTEST"
   echo "$CDOCOMMAND"
diff --git a/test/Multiyearstat.test.in b/test/Multiyearstat.test.in
new file mode 100644
index 0000000..110df7b
--- /dev/null
+++ b/test/Multiyearstat.test.in
@@ -0,0 +1,49 @@
+#! @SHELL@
+echo 1..36 # Number of tests to be executed.
+#
+test -n "$CDO"      || CDO=cdo
+test -n "$DATAPATH" || DATAPATH=./data
+#
+CDOOUT=cout$$
+CDOERR=cerr$$
+TYPES="ymon yday yhour yseas"
+STATS="min max sum avg mean std std1 var var1"
+#
+IFILE=$DATAPATH/ts_mm_5years
+NTEST=1
+#
+for TYPE in $TYPES; do
+  for STAT in $STATS; do
+    RSTAT=0
+    if [ $TYPE = yday -o $TYPE = yhour ] ; then
+      RFILE=$DATAPATH/ymon${STAT}_ref
+    else
+      RFILE=$DATAPATH/${TYPE}${STAT}_ref
+    fi
+    OFILE=${TYPE}${STAT}_res
+
+    CDOTEST="${TYPE}$STAT"
+    CDOCOMMAND="$CDO ${TYPE}${STAT} $IFILE $OFILE"
+
+    echo "Running test: $NTEST"
+    echo "$CDOCOMMAND"
+
+    $CDOCOMMAND
+    test $? -eq 0 || let RSTAT+=1
+
+    $CDO diff $OFILE $RFILE > $CDOOUT 2> $CDOERR
+    test $? -eq 0 || let RSTAT+=1
+    test -s $CDOOUT && let RSTAT+=1
+    cat $CDOOUT $CDOERR
+
+    test $RSTAT -eq 0 && echo "ok $NTEST - $CDOTEST"
+    test $RSTAT -eq 0 || echo "not ok $NTEST - $CDOTEST"
+
+    let NTEST+=1
+    rm -f $OFILE
+  done
+done
+#
+rm -f $CDOOUT $CDOERR
+#
+exit 0
diff --git a/test/Ninfo.test.in b/test/Ninfo.test.in
index bf74c0a..5d6a046 100644
--- a/test/Ninfo.test.in
+++ b/test/Ninfo.test.in
@@ -52,10 +52,12 @@ if [ "@ENABLE_NETCDF@" = yes ] ; then
   $CDO -O -f nc -temp,r18x9 temp.small
   $CDO -O -f nc -temp,global_10 temp.global
   $CDO -O -f nc -merge temp.small temp.global temp.2grids
-  if test 2 -eq $($CDOCOMMAND temp.2grids) ; then  echo "ok $NTEST - $CDOCOMMAND temp.2grids"; else echo "not ok $NTEST - $CDOCOMMAND temp.2grids"; fi; let NTEST+=1
-  else
-    test $RSTAT -eq 0 && echo "ok $NTEST - $CDOTEST # SKIP netCDF not enabled"
-  fi
-
+  if test 2 -eq $($CDOCOMMAND temp.2grids) ; then  echo "ok $NTEST - $CDOCOMMAND temp.2grids";
+  else echo "not ok $NTEST - $CDOCOMMAND temp.2grids"; fi
+  let NTEST+=1
+  rm -f temp.small temp.global temp.2grids
+else
+  test $RSTAT -eq 0 && echo "ok $NTEST - $CDOTEST # SKIP netCDF not enabled"
+fi
 #
 exit 0
diff --git a/test/Timstat.test.in b/test/Runstat.test.in
similarity index 82%
copy from test/Timstat.test.in
copy to test/Runstat.test.in
index b410cf9..0d8cba3 100644
--- a/test/Timstat.test.in
+++ b/test/Runstat.test.in
@@ -6,18 +6,19 @@ test -n "$DATAPATH" || DATAPATH=./data
 #
 CDOOUT=cout$$
 CDOERR=cerr$$
+TYPE=run
 STATS="min max sum avg mean std std1 var var1"
+NTEST=1
 #
 IFILE=$DATAPATH/ts_mm_5years
-NTEST=1
 #
 for STAT in $STATS; do
   RSTAT=0
-  RFILE=$DATAPATH/tim${STAT}_ref
-  OFILE=tim${STAT}_res
+  RFILE=$DATAPATH/${TYPE}${STAT}_ref
+  OFILE=${TYPE}${STAT}_res
 
-  CDOTEST="tim$STAT"
-  CDOCOMMAND="$CDO tim${STAT} $IFILE $OFILE"
+  CDOTEST="${TYPE}$STAT"
+  CDOCOMMAND="$CDO ${TYPE}${STAT},12 $IFILE $OFILE"
 
   echo "Running test: $NTEST"
   echo "$CDOCOMMAND"
diff --git a/test/Ymonstat.test.in b/test/Seasstat.test.in
similarity index 82%
rename from test/Ymonstat.test.in
rename to test/Seasstat.test.in
index c81f81f..8a6f9d3 100644
--- a/test/Ymonstat.test.in
+++ b/test/Seasstat.test.in
@@ -6,18 +6,19 @@ test -n "$DATAPATH" || DATAPATH=./data
 #
 CDOOUT=cout$$
 CDOERR=cerr$$
+TYPE=seas
 STATS="min max sum avg mean std std1 var var1"
+NTEST=1
 #
 IFILE=$DATAPATH/ts_mm_5years
-NTEST=1
 #
 for STAT in $STATS; do
   RSTAT=0
-  RFILE=$DATAPATH/ymon${STAT}_ref
-  OFILE=ymon${STAT}_res
+  RFILE=$DATAPATH/${TYPE}${STAT}_ref
+  OFILE=${TYPE}${STAT}_res
 
-  CDOTEST="ymon$STAT"
-  CDOCOMMAND="$CDO ymon${STAT} $IFILE $OFILE"
+  CDOTEST="${TYPE}$STAT"
+  CDOCOMMAND="$CDO ${TYPE}${STAT} $IFILE $OFILE"
 
   echo "Running test: $NTEST"
   echo "$CDOCOMMAND"
diff --git a/test/Timstat.test.in b/test/Timselstat.test.in
similarity index 82%
copy from test/Timstat.test.in
copy to test/Timselstat.test.in
index b410cf9..5f840db 100644
--- a/test/Timstat.test.in
+++ b/test/Timselstat.test.in
@@ -6,18 +6,19 @@ test -n "$DATAPATH" || DATAPATH=./data
 #
 CDOOUT=cout$$
 CDOERR=cerr$$
+TYPE=timsel
 STATS="min max sum avg mean std std1 var var1"
+NTEST=1
 #
 IFILE=$DATAPATH/ts_mm_5years
-NTEST=1
 #
 for STAT in $STATS; do
   RSTAT=0
-  RFILE=$DATAPATH/tim${STAT}_ref
-  OFILE=tim${STAT}_res
+  RFILE=$DATAPATH/year${STAT}_ref
+  OFILE=${TYPE}${STAT}_res
 
-  CDOTEST="tim$STAT"
-  CDOCOMMAND="$CDO tim${STAT} $IFILE $OFILE"
+  CDOTEST="${TYPE}$STAT"
+  CDOCOMMAND="$CDO ${TYPE}${STAT},12 $IFILE $OFILE"
 
   echo "Running test: $NTEST"
   echo "$CDOCOMMAND"
diff --git a/test/Timstat.test.in b/test/Timstat.test.in
index b410cf9..3b5c61a 100644
--- a/test/Timstat.test.in
+++ b/test/Timstat.test.in
@@ -1,40 +1,49 @@
 #! @SHELL@
-echo 1..9 # Number of tests to be executed.
+echo 1..36 # Number of tests to be executed.
 #
 test -n "$CDO"      || CDO=cdo
 test -n "$DATAPATH" || DATAPATH=./data
 #
 CDOOUT=cout$$
 CDOERR=cerr$$
+TYPES="tim year mon day"
 STATS="min max sum avg mean std std1 var var1"
-#
-IFILE=$DATAPATH/ts_mm_5years
 NTEST=1
 #
-for STAT in $STATS; do
-  RSTAT=0
-  RFILE=$DATAPATH/tim${STAT}_ref
-  OFILE=tim${STAT}_res
+for TYPE in $TYPES; do
+  if [ $TYPE = day ] ; then
+    IFILE=$DATAPATH/ts_6h_1mon
+  elif [ $TYPE = mon ] ; then
+    IFILE=$DATAPATH/ts_1d_1year
+  else
+    IFILE=$DATAPATH/ts_mm_5years
+  fi
+#
+  for STAT in $STATS; do
+    RSTAT=0
+    RFILE=$DATAPATH/${TYPE}${STAT}_ref
+    OFILE=${TYPE}${STAT}_res
 
-  CDOTEST="tim$STAT"
-  CDOCOMMAND="$CDO tim${STAT} $IFILE $OFILE"
+    CDOTEST="${TYPE}$STAT"
+    CDOCOMMAND="$CDO ${TYPE}${STAT} $IFILE $OFILE"
 
-  echo "Running test: $NTEST"
-  echo "$CDOCOMMAND"
+    echo "Running test: $NTEST"
+    echo "$CDOCOMMAND"
 
-  $CDOCOMMAND
-  test $? -eq 0 || let RSTAT+=1
+    $CDOCOMMAND
+    test $? -eq 0 || let RSTAT+=1
 
-  $CDO diff $OFILE $RFILE > $CDOOUT 2> $CDOERR
-  test $? -eq 0 || let RSTAT+=1
-  test -s $CDOOUT && let RSTAT+=1
-  cat $CDOOUT $CDOERR
+    $CDO diff $OFILE $RFILE > $CDOOUT 2> $CDOERR
+    test $? -eq 0 || let RSTAT+=1
+    test -s $CDOOUT && let RSTAT+=1
+    cat $CDOOUT $CDOERR
 
-  test $RSTAT -eq 0 && echo "ok $NTEST - $CDOTEST"
-  test $RSTAT -eq 0 || echo "not ok $NTEST - $CDOTEST"
+    test $RSTAT -eq 0 && echo "ok $NTEST - $CDOTEST"
+    test $RSTAT -eq 0 || echo "not ok $NTEST - $CDOTEST"
 
-  let NTEST+=1
-  rm -f $OFILE
+    let NTEST+=1
+    rm -f $OFILE
+  done
 done
 #
 rm -f $CDOOUT $CDOERR
diff --git a/test/Fldstat.test.in b/test/Vertstat.test.in
similarity index 68%
copy from test/Fldstat.test.in
copy to test/Vertstat.test.in
index 5bbccab..0cb8826 100644
--- a/test/Fldstat.test.in
+++ b/test/Vertstat.test.in
@@ -1,5 +1,5 @@
 #! @SHELL@
-echo 1..9 # Number of tests to be executed.
+echo 1..10 # Number of tests to be executed.
 #
 test -n "$CDO"      || CDO=cdo
 test -n "$DATAPATH" || DATAPATH=./data
@@ -8,19 +8,20 @@ CDOOUT=cout$$
 CDOERR=cerr$$
 FORMAT="-f srv -b 32"
 #
-STATS="min max sum avg mean std std1 var var1"
+TYPE=vert
+STATS="min max sum avg mean std std1 var var1 int"
 #
-IFILE=$DATAPATH/t21_geosp_tsurf.grb
+IFILE=$DATAPATH/pl_data.grb
 #
 NTEST=1
 #
 for STAT in $STATS; do
   RSTAT=0
-  RFILE=$DATAPATH/fld${STAT}_ref
-  OFILE=fld${STAT}_res
+  RFILE=$DATAPATH/${TYPE}${STAT}_ref
+  OFILE=${TYPE}${STAT}_res
 
-  CDOTEST="fld$STAT"
-  CDOCOMMAND="$CDO $FORMAT fld${STAT} $IFILE $OFILE"
+  CDOTEST="${TYPE}$STAT"
+  CDOCOMMAND="$CDO $FORMAT ${TYPE}${STAT} $IFILE $OFILE"
 
   echo "Running test: $NTEST"
   echo "$CDOCOMMAND"
diff --git a/test/Fldstat.test.in b/test/Zonstat.test.in
similarity index 82%
copy from test/Fldstat.test.in
copy to test/Zonstat.test.in
index 5bbccab..8cc50b9 100644
--- a/test/Fldstat.test.in
+++ b/test/Zonstat.test.in
@@ -8,6 +8,7 @@ CDOOUT=cout$$
 CDOERR=cerr$$
 FORMAT="-f srv -b 32"
 #
+TYPE=zon
 STATS="min max sum avg mean std std1 var var1"
 #
 IFILE=$DATAPATH/t21_geosp_tsurf.grb
@@ -16,11 +17,11 @@ NTEST=1
 #
 for STAT in $STATS; do
   RSTAT=0
-  RFILE=$DATAPATH/fld${STAT}_ref
-  OFILE=fld${STAT}_res
+  RFILE=$DATAPATH/${TYPE}${STAT}_ref
+  OFILE=${TYPE}${STAT}_res
 
-  CDOTEST="fld$STAT"
-  CDOCOMMAND="$CDO $FORMAT fld${STAT} $IFILE $OFILE"
+  CDOTEST="${TYPE}$STAT"
+  CDOCOMMAND="$CDO $FORMAT ${TYPE}${STAT} $IFILE $OFILE"
 
   echo "Running test: $NTEST"
   echo "$CDOCOMMAND"
diff --git a/test/data/Makefile.am b/test/data/Makefile.am
index fb636f3..0cfacfa 100644
--- a/test/data/Makefile.am
+++ b/test/data/Makefile.am
@@ -1,14 +1,25 @@
-INPUTDATA = ts_mm_5years hl_l19.grb t21_geosp_tsurf.grb bathy4.grb pl_data pl_data.grb detrend_data \
+INPUTDATA = ts_mm_5years ts_6h_1mon ts_1d_1year hl_l19.grb t21_geosp_tsurf.grb bathy4.grb pl_data pl_data.grb detrend_data \
             grib_testfile01.grb grib_testfile02.grb grib_testfile03.grb netcdf_testfile01.nc netcdf_testfile02.nc testfile01c.nc \
-            datar.nc datac.nc datau.nc datag.nc arith1.srv expr1.srv arithmask.srv
+            datar.nc datac.nc datau.nc datag.nc arith1.srv expr1.srv arithmask.srv psl_DJF_anom.grb
 
 FILE_REF     = file_F32_srv_ref
 GRIB_REF     = grib_testfile01_sinfo_ref grib_testfile01_info_ref grib_testfile02_sinfo_ref grib_testfile02_info_ref grib_testfile03_sinfo_ref grib_testfile03_info_ref
 NETCDF_REF   = netcdf_testfile01_sinfon_ref netcdf_testfile01_infon_ref netcdf_testfile02_sinfon_ref netcdf_testfile02_infon_ref
+COMP_REF     = comp_eqc_ref comp_gec_ref comp_gtc_ref comp_lec_ref comp_ltc_ref comp_nec_ref comptest.srv
+EOF_REF      = eval_ref eof_ref pcoeff00000
 YMONSTAT_REF = ymonmin_ref ymonmax_ref ymonsum_ref ymonavg_ref ymonmean_ref ymonstd_ref ymonstd1_ref ymonvar_ref ymonvar1_ref
+YSEASSTAT_REF = yseasmin_ref yseasmax_ref yseassum_ref yseasavg_ref yseasmean_ref yseasstd_ref yseasstd1_ref yseasvar_ref yseasvar1_ref
+SEASSTAT_REF = seasmin_ref seasmax_ref seassum_ref seasavg_ref seasmean_ref seasstd_ref seasstd1_ref seasvar_ref seasvar1_ref
+RUNSTAT_REF  = runmin_ref runmax_ref runsum_ref runavg_ref runmean_ref runstd_ref runstd1_ref runvar_ref runvar1_ref
 TIMSTAT_REF  = timmin_ref timmax_ref timsum_ref timavg_ref timmean_ref timstd_ref timstd1_ref timvar_ref timvar1_ref
+YEARSTAT_REF = yearmin_ref yearmax_ref yearsum_ref yearavg_ref yearmean_ref yearstd_ref yearstd1_ref yearvar_ref yearvar1_ref
+MONSTAT_REF  = monmin_ref monmax_ref monsum_ref monavg_ref monmean_ref monstd_ref monstd1_ref monvar_ref monvar1_ref
+DAYSTAT_REF  = daymin_ref daymax_ref daysum_ref dayavg_ref daymean_ref daystd_ref daystd1_ref dayvar_ref dayvar1_ref
+VERTSTAT_REF = vertmin_ref vertmax_ref vertsum_ref vertavg_ref vertmean_ref vertstd_ref vertstd1_ref vertvar_ref vertvar1_ref vertint_ref
 FLDSTAT_REF  = fldmin_ref fldmax_ref fldsum_ref fldavg_ref fldmean_ref fldstd_ref fldstd1_ref fldvar_ref fldvar1_ref
 FLDPSTAT_REF = fldpctl1_ref fldpctl20_ref fldpctl25_ref fldpctl33_ref fldpctl50_ref fldpctl66_ref fldpctl75_ref fldpctl80_ref fldpctl99_ref fldpctl100_ref
+MERSTAT_REF  = mermin_ref mermax_ref mersum_ref meravg_ref mermean_ref merstd_ref merstd1_ref mervar_ref mervar1_ref
+ZONSTAT_REF  = zonmin_ref zonmax_ref zonsum_ref zonavg_ref zonmean_ref zonstd_ref zonstd1_ref zonvar_ref zonvar1_ref
 ENSPSTAT_REF = enspctl1_ref enspctl20_ref enspctl25_ref enspctl33_ref enspctl50_ref enspctl66_ref enspctl75_ref enspctl80_ref enspctl99_ref enspctl100_ref
 SPECTRAL_REF = sp2gp_ref sp2gpl_ref gp2sp_ref gp2spl_ref
 VERTINT_REF  = ml2pl_ref
@@ -22,4 +33,4 @@ GRADSDES_REF = pl_data.ctl pl_data.gmp
 ARITH_REF    = arithadd_ref arithsub_ref arithmul_ref arithdiv_ref
 MAPREDUCE    = r18x9_grid icon_cell_grid griddes.r18x9 griddes.icon_cell
 
-EXTRA_DIST = $(INPUTDATA) $(FILE_REF) $(GRIB_REF) $(NETCDF_REF) $(YMONSTAT_REF) $(TIMSTAT_REF) $(FLDSTAT_REF) $(FLDPSTAT_REF) $(ENSPSTAT_REF) $(SPECTRAL_REF) $(VERTINT_REF) $(REMAP_REF) $(SELECT_REF) $(DETREND_REF) $(THREAD_REF) $(EXPR_REF) $(GRADSDES_REF) $(ARITH_REF) $(MAPREDUCE)
+EXTRA_DIST = $(INPUTDATA) $(FILE_REF) $(GRIB_REF) $(NETCDF_REF) $(EOF_REF) $(COMP_REF) $(YMONSTAT_REF) $(YSEASSTAT_REF) $(SEASSTAT_REF) $(RUNSTAT_REF) $(TIMSTAT_REF) $(YEARSTAT_REF) $(MONSTAT_REF) $(DAYSTAT_REF) $(VERTSTAT_REF) $(FLDSTAT_REF) $(FLDPSTAT_REF) $(MERSTAT_REF) $(ZONSTAT_REF) $(ENSPSTAT_REF) $(SPECTRAL_REF) $(VERTINT_REF) $(REMAP_REF) $(SELECT_REF) $(DETREND_REF) $(THREAD_REF) $(EXPR_REF) $(GRADSDES_REF) $(ARITH_REF) $(MAPREDUCE)
diff --git a/test/data/Makefile.in b/test/data/Makefile.in
index e974fb9..7d57124 100644
--- a/test/data/Makefile.in
+++ b/test/data/Makefile.in
@@ -285,17 +285,28 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-INPUTDATA = ts_mm_5years hl_l19.grb t21_geosp_tsurf.grb bathy4.grb pl_data pl_data.grb detrend_data \
+INPUTDATA = ts_mm_5years ts_6h_1mon ts_1d_1year hl_l19.grb t21_geosp_tsurf.grb bathy4.grb pl_data pl_data.grb detrend_data \
             grib_testfile01.grb grib_testfile02.grb grib_testfile03.grb netcdf_testfile01.nc netcdf_testfile02.nc testfile01c.nc \
-            datar.nc datac.nc datau.nc datag.nc arith1.srv expr1.srv arithmask.srv
+            datar.nc datac.nc datau.nc datag.nc arith1.srv expr1.srv arithmask.srv psl_DJF_anom.grb
 
 FILE_REF = file_F32_srv_ref
 GRIB_REF = grib_testfile01_sinfo_ref grib_testfile01_info_ref grib_testfile02_sinfo_ref grib_testfile02_info_ref grib_testfile03_sinfo_ref grib_testfile03_info_ref
 NETCDF_REF = netcdf_testfile01_sinfon_ref netcdf_testfile01_infon_ref netcdf_testfile02_sinfon_ref netcdf_testfile02_infon_ref
+COMP_REF = comp_eqc_ref comp_gec_ref comp_gtc_ref comp_lec_ref comp_ltc_ref comp_nec_ref comptest.srv
+EOF_REF = eval_ref eof_ref pcoeff00000
 YMONSTAT_REF = ymonmin_ref ymonmax_ref ymonsum_ref ymonavg_ref ymonmean_ref ymonstd_ref ymonstd1_ref ymonvar_ref ymonvar1_ref
+YSEASSTAT_REF = yseasmin_ref yseasmax_ref yseassum_ref yseasavg_ref yseasmean_ref yseasstd_ref yseasstd1_ref yseasvar_ref yseasvar1_ref
+SEASSTAT_REF = seasmin_ref seasmax_ref seassum_ref seasavg_ref seasmean_ref seasstd_ref seasstd1_ref seasvar_ref seasvar1_ref
+RUNSTAT_REF = runmin_ref runmax_ref runsum_ref runavg_ref runmean_ref runstd_ref runstd1_ref runvar_ref runvar1_ref
 TIMSTAT_REF = timmin_ref timmax_ref timsum_ref timavg_ref timmean_ref timstd_ref timstd1_ref timvar_ref timvar1_ref
+YEARSTAT_REF = yearmin_ref yearmax_ref yearsum_ref yearavg_ref yearmean_ref yearstd_ref yearstd1_ref yearvar_ref yearvar1_ref
+MONSTAT_REF = monmin_ref monmax_ref monsum_ref monavg_ref monmean_ref monstd_ref monstd1_ref monvar_ref monvar1_ref
+DAYSTAT_REF = daymin_ref daymax_ref daysum_ref dayavg_ref daymean_ref daystd_ref daystd1_ref dayvar_ref dayvar1_ref
+VERTSTAT_REF = vertmin_ref vertmax_ref vertsum_ref vertavg_ref vertmean_ref vertstd_ref vertstd1_ref vertvar_ref vertvar1_ref vertint_ref
 FLDSTAT_REF = fldmin_ref fldmax_ref fldsum_ref fldavg_ref fldmean_ref fldstd_ref fldstd1_ref fldvar_ref fldvar1_ref
 FLDPSTAT_REF = fldpctl1_ref fldpctl20_ref fldpctl25_ref fldpctl33_ref fldpctl50_ref fldpctl66_ref fldpctl75_ref fldpctl80_ref fldpctl99_ref fldpctl100_ref
+MERSTAT_REF = mermin_ref mermax_ref mersum_ref meravg_ref mermean_ref merstd_ref merstd1_ref mervar_ref mervar1_ref
+ZONSTAT_REF = zonmin_ref zonmax_ref zonsum_ref zonavg_ref zonmean_ref zonstd_ref zonstd1_ref zonvar_ref zonvar1_ref
 ENSPSTAT_REF = enspctl1_ref enspctl20_ref enspctl25_ref enspctl33_ref enspctl50_ref enspctl66_ref enspctl75_ref enspctl80_ref enspctl99_ref enspctl100_ref
 SPECTRAL_REF = sp2gp_ref sp2gpl_ref gp2sp_ref gp2spl_ref
 VERTINT_REF = ml2pl_ref
@@ -309,7 +320,7 @@ THREAD_REF = thread1_ref tsformat1_ref
 GRADSDES_REF = pl_data.ctl pl_data.gmp
 ARITH_REF = arithadd_ref arithsub_ref arithmul_ref arithdiv_ref
 MAPREDUCE = r18x9_grid icon_cell_grid griddes.r18x9 griddes.icon_cell
-EXTRA_DIST = $(INPUTDATA) $(FILE_REF) $(GRIB_REF) $(NETCDF_REF) $(YMONSTAT_REF) $(TIMSTAT_REF) $(FLDSTAT_REF) $(FLDPSTAT_REF) $(ENSPSTAT_REF) $(SPECTRAL_REF) $(VERTINT_REF) $(REMAP_REF) $(SELECT_REF) $(DETREND_REF) $(THREAD_REF) $(EXPR_REF) $(GRADSDES_REF) $(ARITH_REF) $(MAPREDUCE)
+EXTRA_DIST = $(INPUTDATA) $(FILE_REF) $(GRIB_REF) $(NETCDF_REF) $(EOF_REF) $(COMP_REF) $(YMONSTAT_REF) $(YSEASSTAT_REF) $(SEASSTAT_REF) $(RUNSTAT_REF) $(TIMSTAT_REF) $(YEARSTAT_REF) $(MONSTAT_REF) $(DAYSTAT_REF) $(VERTSTAT_REF) $(FLDSTAT_REF) $(FLDPSTAT_REF) $(MERSTAT_REF) $(ZONSTAT_REF) $(ENSPSTAT_REF) $(SPECTRAL_REF) $(VERTINT_REF) $(REMAP_REF) $(SELECT_REF) $(DETREND_REF) $(THREAD_REF) $(EXPR_REF) $(GRADSDES_REF) $(ARITH_REF) $(MAPREDUCE)
 all: all-am
 
 .SUFFIXES:
diff --git a/test/data/comp_eqc_ref b/test/data/comp_eqc_ref
new file mode 100644
index 0000000..7f3dcc9
Binary files /dev/null and b/test/data/comp_eqc_ref differ
diff --git a/test/data/comp_gec_ref b/test/data/comp_gec_ref
new file mode 100644
index 0000000..a82ad94
Binary files /dev/null and b/test/data/comp_gec_ref differ
diff --git a/test/data/comp_gtc_ref b/test/data/comp_gtc_ref
new file mode 100644
index 0000000..a82ad94
Binary files /dev/null and b/test/data/comp_gtc_ref differ
diff --git a/test/data/comp_lec_ref b/test/data/comp_lec_ref
new file mode 100644
index 0000000..9e4e1a5
Binary files /dev/null and b/test/data/comp_lec_ref differ
diff --git a/test/data/comp_ltc_ref b/test/data/comp_ltc_ref
new file mode 100644
index 0000000..9e4e1a5
Binary files /dev/null and b/test/data/comp_ltc_ref differ
diff --git a/test/data/comp_nec_ref b/test/data/comp_nec_ref
new file mode 100644
index 0000000..db9852c
Binary files /dev/null and b/test/data/comp_nec_ref differ
diff --git a/test/data/comptest.srv b/test/data/comptest.srv
new file mode 100644
index 0000000..7822f84
Binary files /dev/null and b/test/data/comptest.srv differ
diff --git a/test/data/dayavg_ref b/test/data/dayavg_ref
new file mode 100644
index 0000000..24bc425
Binary files /dev/null and b/test/data/dayavg_ref differ
diff --git a/test/data/daymax_ref b/test/data/daymax_ref
new file mode 100644
index 0000000..aff5b44
Binary files /dev/null and b/test/data/daymax_ref differ
diff --git a/test/data/daymean_ref b/test/data/daymean_ref
new file mode 100644
index 0000000..24bc425
Binary files /dev/null and b/test/data/daymean_ref differ
diff --git a/test/data/daymin_ref b/test/data/daymin_ref
new file mode 100644
index 0000000..7c0364e
Binary files /dev/null and b/test/data/daymin_ref differ
diff --git a/test/data/daystd1_ref b/test/data/daystd1_ref
new file mode 100644
index 0000000..89c665e
Binary files /dev/null and b/test/data/daystd1_ref differ
diff --git a/test/data/daystd_ref b/test/data/daystd_ref
new file mode 100644
index 0000000..faf84ae
Binary files /dev/null and b/test/data/daystd_ref differ
diff --git a/test/data/daysum_ref b/test/data/daysum_ref
new file mode 100644
index 0000000..869056e
Binary files /dev/null and b/test/data/daysum_ref differ
diff --git a/test/data/dayvar1_ref b/test/data/dayvar1_ref
new file mode 100644
index 0000000..749642e
Binary files /dev/null and b/test/data/dayvar1_ref differ
diff --git a/test/data/dayvar_ref b/test/data/dayvar_ref
new file mode 100644
index 0000000..b17478c
Binary files /dev/null and b/test/data/dayvar_ref differ
diff --git a/test/data/eof_ref b/test/data/eof_ref
new file mode 100644
index 0000000..fc41bea
Binary files /dev/null and b/test/data/eof_ref differ
diff --git a/test/data/eval_ref b/test/data/eval_ref
new file mode 100644
index 0000000..fbec1b3
Binary files /dev/null and b/test/data/eval_ref differ
diff --git a/test/data/griddes.icon_cell b/test/data/griddes.icon_cell
index 64f2069..a12762d 100644
--- a/test/data/griddes.icon_cell
+++ b/test/data/griddes.icon_cell
@@ -4,171 +4,161 @@
 gridtype  = unstructured
 gridsize  = 65
 xname     = clon
+xdimname  = ncells
 xlongname = center longitude
 xunits    = radian
 yname     = clat
+ydimname  = ncells
 ylongname = center latitude
 yunits    = radian
+vdimname  = vertices
 nvertex   = 3
-xvals     = 0.993894662193839 0.628318530717959 0.262742399242078 3.14159265358979 
-            -2.77601652211391 2.77601652211391 -2.25053172362976 -0.628318530717959 
-            -0.262742399242078 -0.993894662193839 0.628318530717959 0.340374571222605 
-            0.628318530717958 0.916262490213313 1.88495559215388 1.59701163265852 
-            1.88495559215388 2.17289955164923 3.14159265358979 2.85364869409444 3.14159265358979 
-            -2.85364869409444 -1.88495559215388 -2.17289955164923 -1.88495559215388 
-            -1.59701163265852 -0.628318530717959 -0.916262490213313 -0.628318530717958 
-            -0.340374571222605 1.25663706143592 1.54458102093127 1.25663706143592 
-            0.968693101940563 2.51327412287183 2.80121808236719 2.51327412287183 
-            2.22533016337648 -2.51327412287183 -2.22533016337648 -2.51327412287183 
-            -2.80121808236719 -1.25663706143592 -0.968693101940563 -1.25663706143592 
-            -1.54458102093127 0 0.287943959495354 0 -0.287943959495354 1.25663706143592 
-            0.891060929960037 1.6222131929118 2.51327412287183 2.14769799139595 2.87885025434771 
-            -2.51327412287183 -2.87885025434772 -2.14769799139595 -1.25663706143592 
-            -1.6222131929118 -0.891060929960037 0 -0.36557613147588 0.36557613147588 
-xbounds   = 0.628318530717959 1.25663706143592 1.25663706143592 
-            1.25663706143592 0.628318530717959 0 
-            0 0 0.628318530717959 
-            3.14159265358979 -2.51327412287183 2.51327412287183 
-            3.14159265358979 -2.51327412287183 -2.51327412287183 
-            2.51327412287183 2.51327412287183 3.14159265358979 
-            -2.51327412287183 -2.51327412287183 -1.88495559215388 
-            -0.628318530717959 0 -1.25663706143592 
-            -0.628318530717959 0 0 
-            -1.25663706143592 -1.25663706143592 -0.628318530717959 
-            0.628318530717959 0.314159265358979 0.942477796076938 
-            0.628318530717959 0 0.314159265358979 
-            0.314159265358979 0.628318530717959 0.942477796076938 
-            0.942477796076938 1.25663706143592 0.628318530717959 
-            1.88495559215388 1.5707963267949 2.19911485751286 
-            1.88495559215388 1.25663706143592 1.5707963267949 
-            1.5707963267949 1.88495559215388 2.19911485751286 
-            2.19911485751286 2.51327412287183 1.88495559215388 
-            3.14159265358979 2.82743338823081 -2.82743338823081 
-            3.14159265358979 2.51327412287183 2.82743338823081 
-            2.82743338823081 3.14159265358979 -2.82743338823081 
-            -2.82743338823081 -2.51327412287183 3.14159265358979 
-            -1.88495559215388 -2.19911485751286 -1.5707963267949 
-            -1.88495559215388 -2.51327412287183 -2.19911485751286 
-            -2.19911485751286 -1.88495559215388 -1.5707963267949 
-            -1.5707963267949 -1.25663706143592 -1.88495559215388 
-            -0.628318530717959 -0.942477796076938 -0.314159265358979 
-            -0.628318530717959 -1.25663706143592 -0.942477796076938 
-            -0.942477796076938 -0.628318530717959 -0.314159265358979 
-            -0.314159265358979 0 -0.628318530717959 
-            1.25663706143592 1.5707963267949 0.942477796076938 
-            1.25663706143592 1.88495559215388 1.5707963267949 
-            1.5707963267949 1.25663706143592 0.942477796076938 
-            0.942477796076938 0.628318530717959 1.25663706143592 
-            2.51327412287183 2.82743338823081 2.19911485751286 
-            2.51327412287183 3.14159265358979 2.82743338823081 
-            2.82743338823081 2.51327412287183 2.19911485751286 
-            2.19911485751286 1.88495559215388 2.51327412287183 
-            -2.51327412287183 -2.19911485751286 -2.82743338823081 
-            -2.51327412287183 -1.88495559215388 -2.19911485751286 
-            -2.19911485751286 -2.51327412287183 -2.82743338823081 
-            -2.82743338823081 3.14159265358979 -2.51327412287183 
-            -1.25663706143592 -0.942477796076938 -1.5707963267949 
-            -1.25663706143592 -0.628318530717959 -0.942477796076938 
-            -0.942477796076938 -1.25663706143592 -1.5707963267949 
-            -1.5707963267949 -1.88495559215388 -1.25663706143592 
-            0 0.314159265358979 -0.314159265358979 
-            0 0.628318530717959 0.314159265358979 
-            0.314159265358979 0 -0.314159265358979 
-            -0.314159265358979 -0.628318530717959 0 
-            1.25663706143592 0.628318530717959 1.88495559215388 
-            1.25663706143592 0.628318530717959 0.628318530717959 
-            1.88495559215388 1.88495559215388 1.25663706143592 
-            2.51327412287183 1.88495559215388 3.14159265358979 
-            2.51327412287183 1.88495559215388 1.88495559215388 
-            3.14159265358979 3.14159265358979 2.51327412287183 
-            -2.51327412287183 3.14159265358979 -1.88495559215388 
-            -2.51327412287183 3.14159265358979 3.14159265358979 
-            -1.88495559215388 -1.88495559215388 -2.51327412287183 
-            -1.25663706143592 -1.88495559215388 -0.628318530717959 
-            -1.25663706143592 -1.88495559215388 -1.88495559215388 
-            -0.628318530717959 -0.628318530717959 -1.25663706143592 
-            0 -0.628318530717959 0.628318530717959 
-            0 -0.628318530717959 -0.628318530717959 
-            0.628318530717959 0.628318530717959 0 
-yvals     = 0.723075379408535 1.2331053800287 0.723075379408535 0.918438187010528 
-            0.723075379408535 0.723075379408535 0.723075379408535 0.918438187010528 
-            0.723075379408535 0.723075379408535 0.188710530783562 0.336710713671639 
-            -0.125956662234605 0.336710713671639 0.188710530783562 0.336710713671639 
-            -0.125956662234605 0.336710713671639 0.188710530783562 0.336710713671639 
-            -0.125956662234605 0.336710713671639 0.188710530783562 0.336710713671639 
-            -0.125956662234605 0.336710713671639 0.188710530783562 0.336710713671639 
-            -0.125956662234605 0.336710713671639 -0.188710530783562 -0.336710713671639 
-            0.125956662234605 -0.336710713671639 -0.188710530783562 -0.336710713671639 
-            0.125956662234605 -0.336710713671639 -0.188710530783562 -0.336710713671639 
-            0.125956662234605 -0.336710713671639 -0.188710530783562 -0.336710713671639 
-            0.125956662234605 -0.336710713671639 -0.188710530783562 -0.336710713671639 
-            0.125956662234605 -0.336710713671639 -0.918438187010528 -0.723075379408535 
-            -0.723075379408535 -0.918438187010528 -0.723075379408535 -0.723075379408535 
-            -0.918438187010528 -0.723075379408535 -0.723075379408535 -0.918438187010528 
-            -0.723075379408535 -0.723075379408535 -0.918438187010528 -0.723075379408535 
-            -0.723075379408535 
-ybounds   = 0.553574358897045 0.463647609000806 1.01722196789785 
-            1.01722196789785 1.5707963267949 1.01722196789785 
-            1.01722196789785 0.463647609000806 0.553574358897045 
-            0.553574358897045 1.01722196789785 1.01722196789785 
-            0.553574358897045 0.463647609000806 1.01722196789785 
-            1.01722196789785 0.463647609000806 0.553574358897045 
-            1.01722196789785 0.463647609000806 0.553574358897045 
-            0.553574358897045 1.01722196789785 1.01722196789785 
-            0.553574358897045 0.463647609000806 1.01722196789785 
-            1.01722196789785 0.463647609000806 0.553574358897045 
-            0.553574358897045 0 0 
-            0.553574358897045 0.463647609000806 0 
-            0 -0.463647609000806 0 
-            0 0.463647609000806 0.553574358897045 
-            0.553574358897045 0 0 
-            0.553574358897045 0.463647609000806 0 
-            0 -0.463647609000806 0 
-            0 0.463647609000806 0.553574358897045 
-            0.553574358897045 0 0 
-            0.553574358897045 0.463647609000806 0 
-            0 -0.463647609000806 0 
-            0 0.463647609000806 0.553574358897045 
-            0.553574358897045 0 0 
-            0.553574358897045 0.463647609000806 0 
-            0 -0.463647609000806 0 
-            0 0.463647609000806 0.553574358897045 
-            0.553574358897045 0 0 
-            0.553574358897045 0.463647609000806 0 
-            0 -0.463647609000806 0 
-            0 0.463647609000806 0.553574358897045 
-            -0.553574358897045 0 0 
-            -0.553574358897045 -0.463647609000806 0 
-            0 0.463647609000806 0 
-            0 -0.463647609000806 -0.553574358897045 
-            -0.553574358897045 0 0 
-            -0.553574358897045 -0.463647609000806 0 
-            0 0.463647609000806 0 
-            0 -0.463647609000806 -0.553574358897045 
-            -0.553574358897045 0 0 
-            -0.553574358897045 -0.463647609000806 0 
-            0 0.463647609000806 0 
-            0 -0.463647609000806 -0.553574358897045 
-            -0.553574358897045 0 0 
-            -0.553574358897045 -0.463647609000806 0 
-            0 0.463647609000806 0 
-            0 -0.463647609000806 -0.553574358897045 
-            -0.553574358897045 0 0 
-            -0.553574358897045 -0.463647609000806 0 
-            0 0.463647609000806 0 
-            0 -0.463647609000806 -0.553574358897045 
-            -0.553574358897045 -1.01722196789785 -1.01722196789785 
-            -0.553574358897045 -0.463647609000806 -1.01722196789785 
-            -1.01722196789785 -0.463647609000806 -0.553574358897045 
-            -0.553574358897045 -1.01722196789785 -1.01722196789785 
-            -0.553574358897045 -0.463647609000806 -1.01722196789785 
-            -1.01722196789785 -0.463647609000806 -0.553574358897045 
-            -0.553574358897045 -1.01722196789785 -1.01722196789785 
-            -0.553574358897045 -0.463647609000806 -1.01722196789785 
-            -1.01722196789785 -0.463647609000806 -0.553574358897045 
-            -0.553574358897045 -1.01722196789785 -1.01722196789785 
-            -0.553574358897045 -0.463647609000806 -1.01722196789785 
-            -1.01722196789785 -0.463647609000806 -0.553574358897045 
-            -0.553574358897045 -1.01722196789785 -1.01722196789785 
-            -0.553574358897045 -0.463647609000806 -1.01722196789785 
-            -1.01722196789785 -0.463647609000806 -0.553574358897045 
+xvals     = 0.9938946 0.6283185 0.2627424 3.141593 -2.776016 2.776016 -2.250532 -0.6283185 
+            -0.2627424 -0.9938946 0.6283185 0.3403746 0.6283185 0.9162625 1.884956 
+            1.597012 1.884956 2.172899 3.141593 2.853649 3.141593 -2.853649 -1.884956 
+            -2.172899 -1.884956 -1.597012 -0.6283185 -0.9162625 -0.6283185 -0.3403746 
+            1.256637 1.544581 1.256637 0.9686931 2.513274 2.801218 2.513274 2.22533 
+            -2.513274 -2.22533 -2.513274 -2.801218 -1.256637 -0.9686931 -1.256637 
+            -1.544581 0 0.287944 0 -0.287944 1.256637 0.8910609 1.622213 2.513274 
+            2.147698 2.87885 -2.513274 -2.87885 -2.147698 -1.256637 -1.622213 -0.8910609 
+            0 -0.3655761 0.3655761 
+xbounds   = 0.6283185 1.256637 1.256637 
+            1.256637 0.6283185 0 
+            0 0 0.6283185 
+            3.141593 -2.513274 2.513274 
+            3.141593 -2.513274 -2.513274 
+            2.513274 2.513274 3.141593 
+            -2.513274 -2.513274 -1.884956 
+            -0.6283185 0 -1.256637 
+            -0.6283185 0 0 
+            -1.256637 -1.256637 -0.6283185 
+            0.6283185 0.3141593 0.9424778 
+            0.6283185 0 0.3141593 
+            0.3141593 0.6283185 0.9424778 
+            0.9424778 1.256637 0.6283185 
+            1.884956 1.570796 2.199115 
+            1.884956 1.256637 1.570796 
+            1.570796 1.884956 2.199115 
+            2.199115 2.513274 1.884956 
+            3.141593 2.827433 -2.827433 
+            3.141593 2.513274 2.827433 
+            2.827433 3.141593 -2.827433 
+            -2.827433 -2.513274 3.141593 
+            -1.884956 -2.199115 -1.570796 
+            -1.884956 -2.513274 -2.199115 
+            -2.199115 -1.884956 -1.570796 
+            -1.570796 -1.256637 -1.884956 
+            -0.6283185 -0.9424778 -0.3141593 
+            -0.6283185 -1.256637 -0.9424778 
+            -0.9424778 -0.6283185 -0.3141593 
+            -0.3141593 0 -0.6283185 
+            1.256637 1.570796 0.9424778 
+            1.256637 1.884956 1.570796 
+            1.570796 1.256637 0.9424778 
+            0.9424778 0.6283185 1.256637 
+            2.513274 2.827433 2.199115 
+            2.513274 3.141593 2.827433 
+            2.827433 2.513274 2.199115 
+            2.199115 1.884956 2.513274 
+            -2.513274 -2.199115 -2.827433 
+            -2.513274 -1.884956 -2.199115 
+            -2.199115 -2.513274 -2.827433 
+            -2.827433 3.141593 -2.513274 
+            -1.256637 -0.9424778 -1.570796 
+            -1.256637 -0.6283185 -0.9424778 
+            -0.9424778 -1.256637 -1.570796 
+            -1.570796 -1.884956 -1.256637 
+            0 0.3141593 -0.3141593 
+            0 0.6283185 0.3141593 
+            0.3141593 0 -0.3141593 
+            -0.3141593 -0.6283185 0 
+            1.256637 0.6283185 1.884956 
+            1.256637 0.6283185 0.6283185 
+            1.884956 1.884956 1.256637 
+            2.513274 1.884956 3.141593 
+            2.513274 1.884956 1.884956 
+            3.141593 3.141593 2.513274 
+            -2.513274 3.141593 -1.884956 
+            -2.513274 3.141593 3.141593 
+            -1.884956 -1.884956 -2.513274 
+            -1.256637 -1.884956 -0.6283185 
+            -1.256637 -1.884956 -1.884956 
+            -0.6283185 -0.6283185 -1.256637 
+            0 -0.6283185 0.6283185 
+            0 -0.6283185 -0.6283185 
+            0.6283185 0.6283185 0 
+yvals     = 0.7230754 1.233105 0.7230754 0.9184382 0.7230754 0.7230754 0.7230754 
+            0.9184382 0.7230754 0.7230754 0.1887105 0.3367107 -0.1259567 0.3367107 
+            0.1887105 0.3367107 -0.1259567 0.3367107 0.1887105 0.3367107 -0.1259567 
+            0.3367107 0.1887105 0.3367107 -0.1259567 0.3367107 0.1887105 0.3367107 
+            -0.1259567 0.3367107 -0.1887105 -0.3367107 0.1259567 -0.3367107 -0.1887105 
+            -0.3367107 0.1259567 -0.3367107 -0.1887105 -0.3367107 0.1259567 -0.3367107 
+            -0.1887105 -0.3367107 0.1259567 -0.3367107 -0.1887105 -0.3367107 0.1259567 
+            -0.3367107 -0.9184382 -0.7230754 -0.7230754 -0.9184382 -0.7230754 -0.7230754 
+            -0.9184382 -0.7230754 -0.7230754 -0.9184382 -0.7230754 -0.7230754 -0.9184382 
+            -0.7230754 -0.7230754 
+ybounds   = 0.5535744 0.4636476 1.017222 
+            1.017222 1.570796 1.017222 
+            1.017222 0.4636476 0.5535744 
+            0.5535744 1.017222 1.017222 
+            0.5535744 0.4636476 1.017222 
+            1.017222 0.4636476 0.5535744 
+            1.017222 0.4636476 0.5535744 
+            0.5535744 1.017222 1.017222 
+            0.5535744 0.4636476 1.017222 
+            1.017222 0.4636476 0.5535744 
+            0.5535744 0 0 
+            0.5535744 0.4636476 0 
+            0 -0.4636476 0 
+            0 0.4636476 0.5535744 
+            0.5535744 0 0 
+            0.5535744 0.4636476 0 
+            0 -0.4636476 0 
+            0 0.4636476 0.5535744 
+            0.5535744 0 0 
+            0.5535744 0.4636476 0 
+            0 -0.4636476 0 
+            0 0.4636476 0.5535744 
+            0.5535744 0 0 
+            0.5535744 0.4636476 0 
+            0 -0.4636476 0 
+            0 0.4636476 0.5535744 
+            0.5535744 0 0 
+            0.5535744 0.4636476 0 
+            0 -0.4636476 0 
+            0 0.4636476 0.5535744 
+            -0.5535744 0 0 
+            -0.5535744 -0.4636476 0 
+            0 0.4636476 0 
+            0 -0.4636476 -0.5535744 
+            -0.5535744 0 0 
+            -0.5535744 -0.4636476 0 
+            0 0.4636476 0 
+            0 -0.4636476 -0.5535744 
+            -0.5535744 0 0 
+            -0.5535744 -0.4636476 0 
+            0 0.4636476 0 
+            0 -0.4636476 -0.5535744 
+            -0.5535744 0 0 
+            -0.5535744 -0.4636476 0 
+            0 0.4636476 0 
+            0 -0.4636476 -0.5535744 
+            -0.5535744 0 0 
+            -0.5535744 -0.4636476 0 
+            0 0.4636476 0 
+            0 -0.4636476 -0.5535744 
+            -0.5535744 -1.017222 -1.017222 
+            -0.5535744 -0.4636476 -1.017222 
+            -1.017222 -0.4636476 -0.5535744 
+            -0.5535744 -1.017222 -1.017222 
+            -0.5535744 -0.4636476 -1.017222 
+            -1.017222 -0.4636476 -0.5535744 
+            -0.5535744 -1.017222 -1.017222 
+            -0.5535744 -0.4636476 -1.017222 
+            -1.017222 -0.4636476 -0.5535744 
+            -0.5535744 -1.017222 -1.017222 
+            -0.5535744 -0.4636476 -1.017222 
+            -1.017222 -0.4636476 -0.5535744 
+            -0.5535744 -1.017222 -1.017222 
+            -0.5535744 -0.4636476 -1.017222 
+            -1.017222 -0.4636476 -0.5535744 
diff --git a/test/data/griddes.r18x9 b/test/data/griddes.r18x9
index e6f0fcc..dbdc28e 100644
--- a/test/data/griddes.r18x9
+++ b/test/data/griddes.r18x9
@@ -4,11 +4,14 @@
 gridtype  = unstructured
 gridsize  = 88
 xname     = lon
+xdimname  = ncells
 xlongname = longitude
 xunits    = degrees_east
 yname     = lat
+ydimname  = ncells
 ylongname = latitude
 yunits    = degrees_north
+vdimname  = vertices
 nvertex   = 4
 xvals     = 180 200 260 280 0 20 40 60 80 100 120 140 160 180 200 220 240 260 280 
             300 320 340 0 20 40 60 80 100 120 140 160 180 200 220 240 260 280 300 
diff --git a/test/data/meravg_ref b/test/data/meravg_ref
new file mode 100644
index 0000000..30b89b3
Binary files /dev/null and b/test/data/meravg_ref differ
diff --git a/test/data/mermax_ref b/test/data/mermax_ref
new file mode 100644
index 0000000..2e752a2
Binary files /dev/null and b/test/data/mermax_ref differ
diff --git a/test/data/mermean_ref b/test/data/mermean_ref
new file mode 100644
index 0000000..30b89b3
Binary files /dev/null and b/test/data/mermean_ref differ
diff --git a/test/data/mermin_ref b/test/data/mermin_ref
new file mode 100644
index 0000000..da7c814
Binary files /dev/null and b/test/data/mermin_ref differ
diff --git a/test/data/merstd1_ref b/test/data/merstd1_ref
new file mode 100644
index 0000000..5ec7468
Binary files /dev/null and b/test/data/merstd1_ref differ
diff --git a/test/data/merstd_ref b/test/data/merstd_ref
new file mode 100644
index 0000000..f99832e
Binary files /dev/null and b/test/data/merstd_ref differ
diff --git a/test/data/mersum_ref b/test/data/mersum_ref
new file mode 100644
index 0000000..0b6b99d
Binary files /dev/null and b/test/data/mersum_ref differ
diff --git a/test/data/mervar1_ref b/test/data/mervar1_ref
new file mode 100644
index 0000000..38a850b
Binary files /dev/null and b/test/data/mervar1_ref differ
diff --git a/test/data/mervar_ref b/test/data/mervar_ref
new file mode 100644
index 0000000..61b3cd8
Binary files /dev/null and b/test/data/mervar_ref differ
diff --git a/test/data/monavg_ref b/test/data/monavg_ref
new file mode 100644
index 0000000..e229c79
Binary files /dev/null and b/test/data/monavg_ref differ
diff --git a/test/data/monmax_ref b/test/data/monmax_ref
new file mode 100644
index 0000000..5d5f056
Binary files /dev/null and b/test/data/monmax_ref differ
diff --git a/test/data/monmean_ref b/test/data/monmean_ref
new file mode 100644
index 0000000..e229c79
Binary files /dev/null and b/test/data/monmean_ref differ
diff --git a/test/data/monmin_ref b/test/data/monmin_ref
new file mode 100644
index 0000000..b519c82
Binary files /dev/null and b/test/data/monmin_ref differ
diff --git a/test/data/monstd1_ref b/test/data/monstd1_ref
new file mode 100644
index 0000000..fe64f57
Binary files /dev/null and b/test/data/monstd1_ref differ
diff --git a/test/data/monstd_ref b/test/data/monstd_ref
new file mode 100644
index 0000000..676f481
Binary files /dev/null and b/test/data/monstd_ref differ
diff --git a/test/data/monsum_ref b/test/data/monsum_ref
new file mode 100644
index 0000000..d2df917
Binary files /dev/null and b/test/data/monsum_ref differ
diff --git a/test/data/monvar1_ref b/test/data/monvar1_ref
new file mode 100644
index 0000000..973d72c
Binary files /dev/null and b/test/data/monvar1_ref differ
diff --git a/test/data/monvar_ref b/test/data/monvar_ref
new file mode 100644
index 0000000..ab5a646
Binary files /dev/null and b/test/data/monvar_ref differ
diff --git a/test/data/pcoeff00000 b/test/data/pcoeff00000
new file mode 100644
index 0000000..1b0bcf3
Binary files /dev/null and b/test/data/pcoeff00000 differ
diff --git a/test/data/psl_DJF_anom.grb b/test/data/psl_DJF_anom.grb
new file mode 100644
index 0000000..9ddfb18
Binary files /dev/null and b/test/data/psl_DJF_anom.grb differ
diff --git a/test/data/runavg_ref b/test/data/runavg_ref
new file mode 100644
index 0000000..c2c11ca
Binary files /dev/null and b/test/data/runavg_ref differ
diff --git a/test/data/runmax_ref b/test/data/runmax_ref
new file mode 100644
index 0000000..1bd1c63
Binary files /dev/null and b/test/data/runmax_ref differ
diff --git a/test/data/runmean_ref b/test/data/runmean_ref
new file mode 100644
index 0000000..c2c11ca
Binary files /dev/null and b/test/data/runmean_ref differ
diff --git a/test/data/runmin_ref b/test/data/runmin_ref
new file mode 100644
index 0000000..a693695
Binary files /dev/null and b/test/data/runmin_ref differ
diff --git a/test/data/runstd1_ref b/test/data/runstd1_ref
new file mode 100644
index 0000000..3c7b3da
Binary files /dev/null and b/test/data/runstd1_ref differ
diff --git a/test/data/runstd_ref b/test/data/runstd_ref
new file mode 100644
index 0000000..32d9dd7
Binary files /dev/null and b/test/data/runstd_ref differ
diff --git a/test/data/runsum_ref b/test/data/runsum_ref
new file mode 100644
index 0000000..dcd4bd0
Binary files /dev/null and b/test/data/runsum_ref differ
diff --git a/test/data/runvar1_ref b/test/data/runvar1_ref
new file mode 100644
index 0000000..02ed060
Binary files /dev/null and b/test/data/runvar1_ref differ
diff --git a/test/data/runvar_ref b/test/data/runvar_ref
new file mode 100644
index 0000000..2a94b02
Binary files /dev/null and b/test/data/runvar_ref differ
diff --git a/test/data/seasavg_ref b/test/data/seasavg_ref
new file mode 100644
index 0000000..68f6f13
Binary files /dev/null and b/test/data/seasavg_ref differ
diff --git a/test/data/seasmax_ref b/test/data/seasmax_ref
new file mode 100644
index 0000000..2306e18
Binary files /dev/null and b/test/data/seasmax_ref differ
diff --git a/test/data/seasmean_ref b/test/data/seasmean_ref
new file mode 100644
index 0000000..68f6f13
Binary files /dev/null and b/test/data/seasmean_ref differ
diff --git a/test/data/seasmin_ref b/test/data/seasmin_ref
new file mode 100644
index 0000000..8a07466
Binary files /dev/null and b/test/data/seasmin_ref differ
diff --git a/test/data/seasstd1_ref b/test/data/seasstd1_ref
new file mode 100644
index 0000000..9f072e2
Binary files /dev/null and b/test/data/seasstd1_ref differ
diff --git a/test/data/seasstd_ref b/test/data/seasstd_ref
new file mode 100644
index 0000000..676d216
Binary files /dev/null and b/test/data/seasstd_ref differ
diff --git a/test/data/seassum_ref b/test/data/seassum_ref
new file mode 100644
index 0000000..a5733fc
Binary files /dev/null and b/test/data/seassum_ref differ
diff --git a/test/data/seasvar1_ref b/test/data/seasvar1_ref
new file mode 100644
index 0000000..95da46b
Binary files /dev/null and b/test/data/seasvar1_ref differ
diff --git a/test/data/seasvar_ref b/test/data/seasvar_ref
new file mode 100644
index 0000000..6b239a5
Binary files /dev/null and b/test/data/seasvar_ref differ
diff --git a/test/data/timavg_ref b/test/data/timavg_ref
index 943bd5b..61e9261 100644
Binary files a/test/data/timavg_ref and b/test/data/timavg_ref differ
diff --git a/test/data/timmax_ref b/test/data/timmax_ref
index 8f37f19..93a4390 100644
Binary files a/test/data/timmax_ref and b/test/data/timmax_ref differ
diff --git a/test/data/timmean_ref b/test/data/timmean_ref
index 943bd5b..61e9261 100644
Binary files a/test/data/timmean_ref and b/test/data/timmean_ref differ
diff --git a/test/data/timmin_ref b/test/data/timmin_ref
index ac70eba..0fe7519 100644
Binary files a/test/data/timmin_ref and b/test/data/timmin_ref differ
diff --git a/test/data/timstd1_ref b/test/data/timstd1_ref
index 2731aa8..c42a446 100644
Binary files a/test/data/timstd1_ref and b/test/data/timstd1_ref differ
diff --git a/test/data/timstd_ref b/test/data/timstd_ref
index 90f4540..409a0d0 100644
Binary files a/test/data/timstd_ref and b/test/data/timstd_ref differ
diff --git a/test/data/timsum_ref b/test/data/timsum_ref
index 3e40bdb..ee45933 100644
Binary files a/test/data/timsum_ref and b/test/data/timsum_ref differ
diff --git a/test/data/timvar1_ref b/test/data/timvar1_ref
index 9374806..1481d0b 100644
Binary files a/test/data/timvar1_ref and b/test/data/timvar1_ref differ
diff --git a/test/data/timvar_ref b/test/data/timvar_ref
index cefe9a5..a0a1c52 100644
Binary files a/test/data/timvar_ref and b/test/data/timvar_ref differ
diff --git a/test/data/ts_1d_1year b/test/data/ts_1d_1year
new file mode 100644
index 0000000..a11f805
Binary files /dev/null and b/test/data/ts_1d_1year differ
diff --git a/test/data/ts_6h_1mon b/test/data/ts_6h_1mon
new file mode 100644
index 0000000..0ae27cc
Binary files /dev/null and b/test/data/ts_6h_1mon differ
diff --git a/test/data/ts_mm_5years b/test/data/ts_mm_5years
index ca4f161..a6a420f 100644
Binary files a/test/data/ts_mm_5years and b/test/data/ts_mm_5years differ
diff --git a/test/data/vertavg_ref b/test/data/vertavg_ref
new file mode 100644
index 0000000..a83cef6
Binary files /dev/null and b/test/data/vertavg_ref differ
diff --git a/test/data/vertint_ref b/test/data/vertint_ref
new file mode 100644
index 0000000..580e152
Binary files /dev/null and b/test/data/vertint_ref differ
diff --git a/test/data/vertmax_ref b/test/data/vertmax_ref
new file mode 100644
index 0000000..c928fa0
Binary files /dev/null and b/test/data/vertmax_ref differ
diff --git a/test/data/vertmean_ref b/test/data/vertmean_ref
new file mode 100644
index 0000000..5ecb049
Binary files /dev/null and b/test/data/vertmean_ref differ
diff --git a/test/data/vertmin_ref b/test/data/vertmin_ref
new file mode 100644
index 0000000..d79233c
Binary files /dev/null and b/test/data/vertmin_ref differ
diff --git a/test/data/vertstd1_ref b/test/data/vertstd1_ref
new file mode 100644
index 0000000..56ff381
Binary files /dev/null and b/test/data/vertstd1_ref differ
diff --git a/test/data/vertstd_ref b/test/data/vertstd_ref
new file mode 100644
index 0000000..e89c371
Binary files /dev/null and b/test/data/vertstd_ref differ
diff --git a/test/data/vertsum_ref b/test/data/vertsum_ref
new file mode 100644
index 0000000..580e152
Binary files /dev/null and b/test/data/vertsum_ref differ
diff --git a/test/data/vertvar1_ref b/test/data/vertvar1_ref
new file mode 100644
index 0000000..22de4bd
Binary files /dev/null and b/test/data/vertvar1_ref differ
diff --git a/test/data/vertvar_ref b/test/data/vertvar_ref
new file mode 100644
index 0000000..cfafe0b
Binary files /dev/null and b/test/data/vertvar_ref differ
diff --git a/test/data/yearavg_ref b/test/data/yearavg_ref
new file mode 100644
index 0000000..9f3ac66
Binary files /dev/null and b/test/data/yearavg_ref differ
diff --git a/test/data/yearmax_ref b/test/data/yearmax_ref
new file mode 100644
index 0000000..18af696
Binary files /dev/null and b/test/data/yearmax_ref differ
diff --git a/test/data/yearmean_ref b/test/data/yearmean_ref
new file mode 100644
index 0000000..9f3ac66
Binary files /dev/null and b/test/data/yearmean_ref differ
diff --git a/test/data/yearmin_ref b/test/data/yearmin_ref
new file mode 100644
index 0000000..d2c235f
Binary files /dev/null and b/test/data/yearmin_ref differ
diff --git a/test/data/yearstd1_ref b/test/data/yearstd1_ref
new file mode 100644
index 0000000..a518a55
Binary files /dev/null and b/test/data/yearstd1_ref differ
diff --git a/test/data/yearstd_ref b/test/data/yearstd_ref
new file mode 100644
index 0000000..acff270
Binary files /dev/null and b/test/data/yearstd_ref differ
diff --git a/test/data/yearsum_ref b/test/data/yearsum_ref
new file mode 100644
index 0000000..9bbc5c9
Binary files /dev/null and b/test/data/yearsum_ref differ
diff --git a/test/data/yearvar1_ref b/test/data/yearvar1_ref
new file mode 100644
index 0000000..c76f599
Binary files /dev/null and b/test/data/yearvar1_ref differ
diff --git a/test/data/yearvar_ref b/test/data/yearvar_ref
new file mode 100644
index 0000000..184a736
Binary files /dev/null and b/test/data/yearvar_ref differ
diff --git a/test/data/ymonavg_ref b/test/data/ymonavg_ref
index f5da236..b9610c1 100644
Binary files a/test/data/ymonavg_ref and b/test/data/ymonavg_ref differ
diff --git a/test/data/ymonmax_ref b/test/data/ymonmax_ref
index f69c7fe..623fdf4 100644
Binary files a/test/data/ymonmax_ref and b/test/data/ymonmax_ref differ
diff --git a/test/data/ymonmean_ref b/test/data/ymonmean_ref
index f5da236..b9610c1 100644
Binary files a/test/data/ymonmean_ref and b/test/data/ymonmean_ref differ
diff --git a/test/data/ymonmin_ref b/test/data/ymonmin_ref
index fc7e017..e549267 100644
Binary files a/test/data/ymonmin_ref and b/test/data/ymonmin_ref differ
diff --git a/test/data/ymonstd1_ref b/test/data/ymonstd1_ref
index 1d9fd7c..f35971a 100644
Binary files a/test/data/ymonstd1_ref and b/test/data/ymonstd1_ref differ
diff --git a/test/data/ymonstd_ref b/test/data/ymonstd_ref
index 75913de..a4be676 100644
Binary files a/test/data/ymonstd_ref and b/test/data/ymonstd_ref differ
diff --git a/test/data/ymonsum_ref b/test/data/ymonsum_ref
index caf5a86..64334b7 100644
Binary files a/test/data/ymonsum_ref and b/test/data/ymonsum_ref differ
diff --git a/test/data/ymonvar1_ref b/test/data/ymonvar1_ref
index 4887e39..05cdebb 100644
Binary files a/test/data/ymonvar1_ref and b/test/data/ymonvar1_ref differ
diff --git a/test/data/ymonvar_ref b/test/data/ymonvar_ref
index 291bcca..82f47e9 100644
Binary files a/test/data/ymonvar_ref and b/test/data/ymonvar_ref differ
diff --git a/test/data/yseasavg_ref b/test/data/yseasavg_ref
new file mode 100644
index 0000000..96503e6
Binary files /dev/null and b/test/data/yseasavg_ref differ
diff --git a/test/data/yseasmax_ref b/test/data/yseasmax_ref
new file mode 100644
index 0000000..ba43317
Binary files /dev/null and b/test/data/yseasmax_ref differ
diff --git a/test/data/yseasmean_ref b/test/data/yseasmean_ref
new file mode 100644
index 0000000..96503e6
Binary files /dev/null and b/test/data/yseasmean_ref differ
diff --git a/test/data/yseasmin_ref b/test/data/yseasmin_ref
new file mode 100644
index 0000000..be91e2f
Binary files /dev/null and b/test/data/yseasmin_ref differ
diff --git a/test/data/yseasstd1_ref b/test/data/yseasstd1_ref
new file mode 100644
index 0000000..5724235
Binary files /dev/null and b/test/data/yseasstd1_ref differ
diff --git a/test/data/yseasstd_ref b/test/data/yseasstd_ref
new file mode 100644
index 0000000..401e063
Binary files /dev/null and b/test/data/yseasstd_ref differ
diff --git a/test/data/yseassum_ref b/test/data/yseassum_ref
new file mode 100644
index 0000000..5987baa
Binary files /dev/null and b/test/data/yseassum_ref differ
diff --git a/test/data/yseasvar1_ref b/test/data/yseasvar1_ref
new file mode 100644
index 0000000..73f29df
Binary files /dev/null and b/test/data/yseasvar1_ref differ
diff --git a/test/data/yseasvar_ref b/test/data/yseasvar_ref
new file mode 100644
index 0000000..5e78e9a
Binary files /dev/null and b/test/data/yseasvar_ref differ
diff --git a/test/data/zonavg_ref b/test/data/zonavg_ref
new file mode 100644
index 0000000..e55bf6f
Binary files /dev/null and b/test/data/zonavg_ref differ
diff --git a/test/data/zonmax_ref b/test/data/zonmax_ref
new file mode 100644
index 0000000..23e2603
Binary files /dev/null and b/test/data/zonmax_ref differ
diff --git a/test/data/zonmean_ref b/test/data/zonmean_ref
new file mode 100644
index 0000000..e55bf6f
Binary files /dev/null and b/test/data/zonmean_ref differ
diff --git a/test/data/zonmin_ref b/test/data/zonmin_ref
new file mode 100644
index 0000000..1285fc9
Binary files /dev/null and b/test/data/zonmin_ref differ
diff --git a/test/data/zonstd1_ref b/test/data/zonstd1_ref
new file mode 100644
index 0000000..e44a1c6
Binary files /dev/null and b/test/data/zonstd1_ref differ
diff --git a/test/data/zonstd_ref b/test/data/zonstd_ref
new file mode 100644
index 0000000..a70fff4
Binary files /dev/null and b/test/data/zonstd_ref differ
diff --git a/test/data/zonsum_ref b/test/data/zonsum_ref
new file mode 100644
index 0000000..fea7de8
Binary files /dev/null and b/test/data/zonsum_ref differ
diff --git a/test/data/zonvar1_ref b/test/data/zonvar1_ref
new file mode 100644
index 0000000..7aa9c8e
Binary files /dev/null and b/test/data/zonvar1_ref differ
diff --git a/test/data/zonvar_ref b/test/data/zonvar_ref
new file mode 100644
index 0000000..1c37331
Binary files /dev/null and b/test/data/zonvar_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