[netcdf-fortran] 01/09: Imported Upstream version 4.4.1

Bas Couwenberg sebastic at xs4all.nl
Fri Jan 16 23:38:45 UTC 2015


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

sebastic-guest pushed a commit to branch master
in repository netcdf-fortran.

commit b78b7bd465c090074d7025d71eab8815f01e8074
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Fri Jan 16 22:06:50 2015 +0100

    Imported Upstream version 4.4.1
---
 .gitignore                                 |    5 +
 Doxyfile.general                           | 2315 +++++++
 docs/DoxygenLayout.xml                     |  184 +
 docs/defines.texi                          |  112 +
 docs/footer.html                           |   13 +
 docs/netcdf-f77.md                         | 8779 +++++++++++++++++++++++++
 docs/netcdf-f90.texi                       | 7105 +++++++++++++++++++++
 docs/old/netcdf-f77.texi                   | 9560 ++++++++++++++++++++++++++++
 fortran/EightByteIntTest-2.f90             |   16 +
 fortran/EightByteIntTest.f90               |   11 +
 fortran/NOTES                              |   37 +
 fortran/example_good.cdl                   |   51 +
 fortran/f90aux.m4                          |   50 +
 fortran/gen.m4                             |  145 +
 fortran/netcdf.inc                         | 1740 -----
 libsrc/nfconfig.inc => fortran/nfconfig.in |   30 +-
 fortran/nvea.m4                            |   33 +
 fortran/nveaget48.m4                       |   35 +
 fortran/nveaput48.m4                       |   33 +
 fortran/nves.m4                            |   15 +
 fortran/nvesget48.m4                       |   17 +
 fortran/nvesput48.m4                       |   15 +
 fortran/testEightByteGet.f90               |   49 +
 libsrc/cfortran.doc                        | 2049 ++++++
 libsrc/makevms.com                         |   20 +
 libsrc/netcdf_f77.3                        | 1370 ----
 m4/dummy.txt                               |    2 +
 nf03_test/README_NF03_TESTS                |    4 +
 nf_test/README_NF03_TESTS                  |    4 +
 nf_test/f03test.F                          | 1458 +++++
 nf_test/f03tst_groups.F                    |  152 +
 nf_test/f03tst_parallel.F                  |  135 +
 nf_test/f03tst_path.f90                    |   87 +
 nf_test/f03tst_types.F                     |  178 +
 nf_test/f03tst_types2.F                    |   98 +
 nf_test/f03tst_types3.F                    |  121 +
 nf_test/f03tst_v2.F                        |   94 +
 nf_test/f03tst_vars.F                      |  172 +
 nf_test/f03tst_vars2.F                     |  137 +
 nf_test/f03tst_vars3.F                     |  189 +
 nf_test/f03tst_vars4.F                     |  120 +
 nf_test/f03tst_vars5.F                     |  117 +
 nf_test/f03tst_vars6.F                     |  204 +
 nf_test/f90tst_parallel_fill.f90           |  199 +
 nf_test/lib.F                              |   60 +
 nf_test/module_tests.F90                   |  255 +
 nf_test/nf03_error.F                       |   75 +
 nf_test/nf03_test.F                        |  388 ++
 nf_test/test03_get.F                       | 5601 ++++++++++++++++
 nf_test/test03_put.F                       | 6647 +++++++++++++++++++
 nf_test/test03_read.F                      | 1069 ++++
 nf_test/test03_write.F                     | 1436 +++++
 nf_test/tst03_f77_v2.F                     |   73 +
 nf_test/util03.F                           | 1496 +++++
 54 files changed, 51232 insertions(+), 3128 deletions(-)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5343c2c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+CTestConfig.cmake
+build
+\#.\#
+*.*~
+html
diff --git a/Doxyfile.general b/Doxyfile.general
new file mode 100644
index 0000000..069dcc9
--- /dev/null
+++ b/Doxyfile.general
@@ -0,0 +1,2315 @@
+# Doxyfile 1.8.7
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = netcdf-fortran
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         = 4.4.1-rc1
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO           = docs/netcdf-50x50.png
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       =
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = YES
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = YES
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = YES
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = YES
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = YES
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. Do not use file names with spaces, bibtex cannot handle them. See
+# also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = .
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS          = *.c \
+                         *.h \
+                         *.f \
+                         *.F90 \
+                         *.f90 \
+                         *.md
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE = README.md
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = YES
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
+# defined cascading style sheet that is included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet file to the output directory. For an example
+# see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
+# replace them by respectively the title of the page, the current date and time,
+# only the current date, the version number of doxygen, the project name (see
+# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font n the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = YES
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = YES
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = YES
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = YES
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/docs/DoxygenLayout.xml b/docs/DoxygenLayout.xml
new file mode 100644
index 0000000..fa8d07d
--- /dev/null
+++ b/docs/DoxygenLayout.xml
@@ -0,0 +1,184 @@
+<doxygenlayout version="1.0">
+  <!-- Navigation index tabs for HTML output -->
+  <navindex>
+    <tab type="mainpage" visible="yes" title=""/>
+    <tab type="pages" visible="yes" title="" intro=""/>
+    <tab type="modules" visible="yes" title="Functions" intro="Functions are organized according to the netCDF data model."/>
+    <tab type="namespaces" visible="no" title="">
+      <tab type="namespaces" visible="yes" title="" intro=""/>
+      <tab type="namespacemembers" visible="yes" title="" intro=""/>
+    </tab>
+    <tab type="classes" visible="no" title="">
+      <tab type="classes" visible="yes" title="" intro=""/>
+      <tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/> 
+      <tab type="hierarchy" visible="yes" title="" intro=""/>
+      <tab type="classmembers" visible="yes" title="" intro=""/>
+    </tab>
+    <tab type="files" visible="yes" title="">
+      <tab type="files" visible="yes" title="" intro=""/>
+      <tab type="globals" visible="yes" title="" intro=""/>
+    </tab>
+    <tab type="examples" visible="yes" title="" intro=""/>  
+  </navindex>
+
+  <!-- Layout definition for a class page -->
+  <class>
+    <briefdescription visible="yes"/>
+    <includes visible="$SHOW_INCLUDE_FILES"/>
+    <inheritancegraph visible="$CLASS_GRAPH"/>
+    <collaborationgraph visible="$COLLABORATION_GRAPH"/>
+    <allmemberslink visible="yes"/>
+    <memberdecl>
+      <nestedclasses visible="yes" title=""/>
+      <publictypes title=""/>
+      <publicslots title=""/>
+      <signals title=""/>
+      <publicmethods title=""/>
+      <publicstaticmethods title=""/>
+      <publicattributes title=""/>
+      <publicstaticattributes title=""/>
+      <protectedtypes title=""/>
+      <protectedslots title=""/>
+      <protectedmethods title=""/>
+      <protectedstaticmethods title=""/>
+      <protectedattributes title=""/>
+      <protectedstaticattributes title=""/>
+      <packagetypes title=""/>
+      <packagemethods title=""/>
+      <packagestaticmethods title=""/>
+      <packageattributes title=""/>
+      <packagestaticattributes title=""/>
+      <properties title=""/>
+      <events title=""/>
+      <privatetypes title=""/>
+      <privateslots title=""/>
+      <privatemethods title=""/>
+      <privatestaticmethods title=""/>
+      <privateattributes title=""/>
+      <privatestaticattributes title=""/>
+      <friends title=""/>
+      <related title="" subtitle=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+    <memberdef>
+      <typedefs title=""/>
+      <enums title=""/>
+      <constructors title=""/>
+      <functions title=""/>
+      <related title=""/>
+      <variables title=""/>
+      <properties title=""/>
+      <events title=""/>
+    </memberdef>
+    <usedfiles visible="$SHOW_USED_FILES"/>
+    <authorsection visible="yes"/>
+  </class>
+
+  <!-- Layout definition for a namespace page -->
+  <namespace>
+    <briefdescription visible="yes"/>
+    <memberdecl>
+      <nestednamespaces visible="yes" title=""/>
+      <classes visible="yes" title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+    <memberdef>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+    </memberdef>
+    <authorsection visible="yes"/>
+  </namespace>
+
+  <!-- Layout definition for a file page -->
+  <file>
+    <briefdescription visible="yes"/>
+    <includes visible="$SHOW_INCLUDE_FILES"/>
+    <includegraph visible="$INCLUDE_GRAPH"/>
+    <includedbygraph visible="$INCLUDED_BY_GRAPH"/>
+    <sourcelink visible="yes"/>
+    <memberdecl>
+      <classes visible="yes" title=""/>
+      <namespaces visible="yes" title=""/>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+    <memberdef>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+    </memberdef>
+    <authorsection/>
+  </file>
+
+  <!-- Layout definition for a group page -->
+  <group>
+    <briefdescription visible="yes"/>
+    <groupgraph visible="$GROUP_GRAPHS"/>
+    <memberdecl>
+      <classes visible="yes" title=""/>
+      <namespaces visible="yes" title=""/>
+      <dirs visible="yes" title=""/>
+      <nestedgroups visible="yes" title=""/>
+      <files visible="yes" title=""/>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <enumvalues title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <signals title=""/>
+      <publicslots title=""/>
+      <protectedslots title=""/>
+      <privateslots title=""/>
+      <events title=""/>
+      <properties title=""/>
+      <friends title=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+    <memberdef>
+      <pagedocs/>
+      <inlineclasses title=""/>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <enumvalues title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <signals title=""/>
+      <publicslots title=""/>
+      <protectedslots title=""/>
+      <privateslots title=""/>
+      <events title=""/>
+      <properties title=""/>
+      <friends title=""/>
+    </memberdef>
+    <authorsection visible="yes"/>
+  </group>
+
+  <!-- Layout definition for a directory page -->
+  <directory>
+    <briefdescription visible="yes"/>
+    <directorygraph visible="yes"/>
+    <memberdecl>
+      <dirs visible="yes"/>
+      <files visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+  </directory>
+</doxygenlayout>
diff --git a/docs/defines.texi b/docs/defines.texi
new file mode 100644
index 0000000..79ef123
--- /dev/null
+++ b/docs/defines.texi
@@ -0,0 +1,112 @@
+ at c This is part of the netCDF documentation. See COPYRIGHT file
+ at c for terms of use.
+
+ at c This file is included by the manual texi files, and contains
+ at c common definitions.
+
+ at c $Id: defines.texi,v 1.16 2009/12/08 18:34:47 ed Exp $
+
+ at c The canonical name for each manual.
+ at set n-man The NetCDF Users Guide
+ at set c-man The NetCDF C Interface Guide
+ at set cxx-man The NetCDF C++ Interface Guide
+ at set cxx4-man The NetCDF-4 C++ Interface Guide
+ at set f77-man The NetCDF Fortran 77 Interface Guide
+ at set f90-man The NetCDF Fortran 90 Interface Guide
+ at set i-man The NetCDF Installation and Porting Guide
+ at set tut-man The NetCDF Tutorial
+ at set j-man The NetCDF Java User Manual
+
+ at c Support email.
+ at set netcdf-support-email support-netcdf@@unidata.ucar.edu
+ at set hdf5-support-email help@@hdfgroup.org
+
+ at c Home pages for internal stuff like netcdf, netcdf-4, netcdf java,
+ at c Unidata, etc.
+ at set unidata-url http://www.unidata.ucar.edu
+ at set netcdf-url @value{unidata-url}/netcdf
+ at set netcdf-4-url @value{netcdf-url}/netcdf-4
+ at set netcdf-java-url @value{unidata-url}/software/netcdf-java
+ at set ucar-url http://www.ucar.edu
+ at set uop-url http://www.uop.ucar.edu
+
+ at c External web pages.
+ at set hdf5-url http://hdfgroup.org/HDF5/
+ at set hdf5-tutorial-url @value{hdf5-url}/HDF5/Tutor
+ at set hdf5-download-url @value{hdf5-url}/HDF5/release/beta/obtain518.html
+ at set hdf5-szip-license-url http://hdf.ncsa.uiuc.edu/doc_resource/SZIP/Commercial_szip.html
+ at set hdf5-chunking-advice-url http://hdfeos.org/workshops/ws13/presentations/day1/HDF5-EOSXIII-Advanced-Chunking.ppt
+ at set cygwin-url http://www.cygwin.com
+ at set mingw-url http://www.mingw.org
+ at set mingw-faq @value{mingw-url}/mingwfaq.shtml
+ at set woe32-url http://www.haible.de/bruno/woe32dll.html
+ at set red-hat-w32-url http://www.redhat.com/docs/manuals/enterprise/RHEL-4-Manual/gnu-linker/win32.html
+ at set cf-url http://cf-pcmdi.llnl.gov
+ at set zlib-url http://www.zlib.net
+ at set curl-url http://curl.haxx.se
+ at set xml2-url http://xmlsoft.org
+ at set opendap-url http://opendap.org
+ at set pnetcdf-url http://www.mcs.anl.gov/parallel-netcdf
+
+ at c urls for netcdf documents
+ at set docs-url @value{netcdf-url}/docs
+ at set docs4-url @value{netcdf-url}/netcdf-4/newdocs
+ at set old-docs-url @value{netcdf-url}/old_docs
+ at set v2-docs-url @value{netcdf-url}/old_docs/really_old/guide_toc.html
+ at set pre360-install-url @value{old-docs-url}/INSTALL_pre_360.html
+ at set 360-install-url @value{old-docs-url}/docs_3_6_0/netcdf-install
+ at set 361-install-url @value{old-docs-url}/docs_3_6_1/netcdf-install
+ at set install-url @value{docs-url}/netcdf-install
+ at set netcdf-install-url @value{docs-url}/netcdf-install
+ at set netcdf-faq-url @value{netcdf-url}/faq.html
+ at set netcdf-shared-faq-url @value{netcdf-faq-url}#using_shared
+ at set netcdf-builds @value{netcdf-url}/builds
+ at set netcdf-other-builds @value{netcdf-url}/other-builds.html
+ at set netcdf-software-url @value{netcdf-url}/software.html
+ at set known-problems-url @value{docs-url}/known_problems.html
+ at set netcdf-java-man-url @value{netcdf-java-url}/v2.1/NetcdfJavaUserManual.htm
+
+ at c urls to search on-line stuff
+ at set netcdf-support-search-url /search.jsp?support&netcdf
+ at set netcdf-list-search-url /search.jsp?netcdfgroup
+
+ at c places to get downloads
+ at set ftp-site ftp://ftp.unidata.ucar.edu/pub/netcdf
+ at set netcdf4-ftp-site @value{ftp-site}/netcdf-4
+ at set netcdf-binaries-url @value{unidata-url}/downloads/netcdf/index.jsp 
+ at set windows-ftp-site @value{ftp-site}/contrib/win32
+
+ at c Tools mentioned in the netCDF tutorial.
+ at set idv-url http://www.unidata.ucar.edu/software/idv
+ at set udunits-url http://www.unidata.ucar.edu/software/udunits
+ at set ncl-url http://www.ncl.ucar.edu
+ at set nco-url http://nco.sourceforge.net
+ at set grads-url http://grads.iges.org/grads/grads.html
+
+ at setchapternewpage odd
+ at finalout
+ at copying 
+Copyright @copyright{} 2005-2009 University Corporation for
+Atmospheric Research
+
+ at sp 2
+Permission is granted to make and distribute verbatim copies of this
+manual provided that the copyright notice and these paragraphs are
+preserved on all copies.  The software and any accompanying written 
+materials are provided ``as is'' without warranty of any kind.  UCAR 
+expressly disclaims all warranties of any kind, either expressed or 
+implied, including but not limited to the implied warranties of 
+merchantability and fitness for a particular purpose.  
+
+The Unidata Program Center is managed by the University 
+Corporation for Atmospheric Research and sponsored by the National 
+Science Foundation.  Any opinions, findings, conclusions, or 
+recommendations expressed in this publication are those of the 
+author(s) and do not necessarily reflect the views of the National 
+Science Foundation.
+
+Mention of any commercial company or product in this document 
+does not constitute an endorsement by the Unidata Program Center.  
+Unidata does not authorize any use of information from this 
+publication for advertising or publicity purposes.
+ at end copying
diff --git a/docs/footer.html b/docs/footer.html
new file mode 100644
index 0000000..0423b99
--- /dev/null
+++ b/docs/footer.html
@@ -0,0 +1,13 @@
+
+
+
+<hr size="2"/>
+<address style="text-align: center;">
+<a href="http://www.unidata.ucar.edu/software/netcdf/">Return to the Main Unidata NetCDF page.</a><br>
+<img src="http://www.unidata.ucar.edu/img/v3/logos/uniLogo.png">
+
+<address style="text-align: right;"><small>
+Generated on $datetime for $projectname. NetCDF is
+a <a href="http://www.unidata.ucar.edu/">Unidata</a> library.</small></address>
+</body>
+</html>
diff --git a/docs/netcdf-f77.md b/docs/netcdf-f77.md
new file mode 100644
index 0000000..27d6b64
--- /dev/null
+++ b/docs/netcdf-f77.md
@@ -0,0 +1,8779 @@
+The NetCDF Fortran 77 Interface Guide {#nc_f77_interface_guide}
+=====================================
+
+[TOC]
+
+This document describes the FORTRAN-77 interface to the netCDF library.
+
+1 Use of the NetCDF Library {#Use_of_the_NetCDF_Library}
+=============================
+
+You can use the netCDF library without knowing about all of the netCDF
+interface. If you are creating a netCDF dataset, only a handful of
+routines are required to define the necessary dimensions, variables, and
+attributes, and to write the data to the netCDF dataset. (Even less are
+needed if you use the ncgen utility to create the dataset before running
+a program using netCDF library calls to write data. See
+section ‘ncgen’ in The NetCDF Users
+Guide.) Similarly, if you are writing software to access data stored in
+a particular netCDF object, only a smallbset of the netCDF library is
+required to open the netCDF dataset and access the data. Authors of
+generic applications that access arbitrary netCDF datasets need to be
+familiar with more of the netCDF library.
+
+In this we provide templates of common sequences of netCDF calls
+needed for common uses. For clarity we present only the names of
+routines; omit declarations and error checking; omit the type-specific
+suffixes of routine names for variables and attributes; indent
+statements that are typically invoked multiple times; and use ... to
+represent arbitrary sequences of other statements. Full parameter lists
+are described in laters.
+
+
+
+1.1 Creating a NetCDF Dataset {#Creating_a_NetCDF_Dataset}
+-----------------------------
+
+Here is a typical sequence of netCDF calls used to create a new netCDF
+dataset:
+
+ 
+
+
+    NF_CREATE           ! create netCDF dataset: enter define mode
+         ... 
+       NF_DEF_DIM       ! define dimensions: from name and length
+         ... 
+       NF_DEF_VAR       ! define variables: from name, type, dims
+         ... 
+       NF_PUT_ATT       ! assign attribute values
+         ... 
+    NF_ENDDEF           ! end definitions: leave define mode
+         ... 
+       NF_PUT_VAR       ! provide values for variable
+         ... 
+    NF_CLOSE            ! close: save new netCDF dataset
+
+
+Only one call is needed to create a netCDF dataset, at which point you
+will be in the first of two netCDF modes. When accessing an open netCDF
+dataset, it is either in define mode or data mode. In define mode, you
+can create dimensions, variables, and new attributes, but you cannot
+read or write variable data. In data mode, you can access data and
+change existing attributes, but you are not permitted to create new
+dimensions, variables, or attributes.
+
+One call to NF\_DEF\_DIM is needed for each dimension created.
+Similarly, one call to NF\_DEF\_VAR is needed for each variable
+creation, and one call to a member of the NF\_PUT\_ATT family is needed
+for each attribute defined and assigned a value. To leave define mode
+and enter data mode, call NF\_ENDDEF.
+
+Once in data mode, you can add new data to variables, change old values,
+and change values of existing attributes (so long as the attribute
+changes do not require more storage space). Single values may be written
+to a netCDF variable with one of the members of the NF\_PUT\_VAR1
+family, depending on what type of data you have to write. All the values
+of a variable may be written at once with one of the members of the
+NF\_PUT\_VAR family. Arrays or array crosss of a variable may be
+written using members of the NF\_PUT\_VARA family. Subsampled array
+sections may be written using members of the NF\_PUT\_VARS family.
+Mapped arrays may be written using members of the NF\_PUT\_VARM
+family. (Subsampled and mapped access are general forms of data access
+that are explained later.)
+
+Finally, you should explicitly close all netCDF datasets that have been
+opened for writing by calling NF\_CLOSE. By default, access to the file
+system is buffered by the netCDF library. If a program terminates
+abnormally with netCDF datasets open for writing, your most recent
+modifications may be lost. This default buffering of data is disabled by
+setting the NF\_SHARE flag when opening the dataset. But even if this
+flag is set, changes to attribute values or changes made in define mode
+are not written out until NF\_SYNC or NF\_CLOSE is called.
+
+1.2 Reading a NetCDF Dataset with Known Names {#Reading_a_NetCDF_Dataset_with_Known_Names} 
+---------------------------------------------
+
+Here we consider the case where you know the names of not only the
+netCDF datasets, but also the names of their dimensions, variables, and
+attributes. (Otherwise you would have to do "inquire" calls.) The order
+of typical C calls to read data from those variables in a netCDF dataset
+is:
+
+ 
+
+
+    NF_OPEN               ! open existing netCDF dataset
+         ... 
+       NF_INQ_DIMID       ! get dimension IDs
+         ... 
+       NF_INQ_VARID       ! get variable IDs
+         ... 
+       NF_GET_ATT         ! get attribute values
+         ... 
+       NF_GET_VAR         ! get values of variables
+         ... 
+    NF_CLOSE              ! close netCDF dataset
+
+
+First, a single call opens the netCDF dataset, given the dataset name,
+and returns a netCDF ID that is used to refer to the open netCDF dataset
+in allbsequent calls.
+
+Next, a call to NF\_INQ\_DIMID for each dimension of interest gets the
+dimension ID from the dimension name. Similarly, each required variable
+ID is determined from its name by a call to NF\_INQ\_VARID.Once variable
+IDs are known, variable attribute values can be retrieved using the
+netCDF ID, the variable ID, and the desired attribute name as input to a
+member of the NF\_GET\_ATT family (typically NF\_GET\_ATT\_TEXT or
+NF\_GET\_ATT\_DOUBLE) for each desired attribute. Variable data values
+can be directly accessed from the netCDF dataset with calls to members
+of the NF\_GET\_VAR1 family for single values, the NF\_GET\_VAR family
+for entire variables, or various other members of the NF\_GET\_VARA,
+NF\_GET\_VARS, or NF\_GET\_VARM families for array,bsampled or mapped
+access.
+
+Finally, the netCDF dataset is closed with NF\_CLOSE. There is no need
+to close a dataset open only for reading.
+
+
+1.3 Reading a netCDF Dataset with Unknown Names {#Reading_a_netCDF_Dataset_with_Unknown_Names}
+-----------------------------------------------
+
+It is possible to write programs (e.g., generic software) which doch
+things as processing every variable, without needing to know in advance
+the names of these variables. Similarly, the names of dimensions and
+attributes may be unknown.
+
+Names and other information about netCDF objects may be obtained from
+netCDF datasets by calling inquire functions. These return information
+about a whole netCDF dataset, a dimension, a variable, or an attribute.
+The following template illustrates how they are used:
+
+ 
+
+
+    NF_OPEN                   ! open existing netCDF dataset
+      ... 
+    NF_INQ                    ! find out what is in it
+         ... 
+       NF_INQ_DIM             ! get dimension names, lengths
+         ... 
+       NF_INQ_VAR             ! get variable names, types, shapes
+            ... 
+          NF_INQ_ATTNAME      ! get attribute names
+            ... 
+          NF_INQ_ATT          ! get attribute values
+            ... 
+          NF_GET_ATT          ! get attribute values
+            ... 
+       NF_GET_VAR             ! get values of variables
+         ... 
+    NF_CLOSE                  ! close netCDF dataset
+
+
+As in the previous example, a single call opens the existing netCDF
+dataset, returning a netCDF ID. This netCDF ID is given to the NF\_INQ
+routine, which returns the number of dimensions, the number of
+variables, the number of global attributes, and the ID of the unlimited
+dimension, if there is one.
+
+All the inquire functions are inexpensive to use and require no I/O,
+since the information they provide is stored in memory when a netCDF
+dataset is first opened.
+
+Dimension IDs use consecutive integers, beginning at 1. Also dimensions,
+once created, cannot be deleted. Therefore, knowing the number of
+dimension IDs in a netCDF dataset means knowing all the dimension IDs:
+they are the integers 1, 2, 3, ... up to the number of dimensions. For
+each dimension ID, a call to the inquire function NF\_INQ\_DIM returns
+the dimension name and length.
+
+Variable IDs are also assigned from consecutive integers 1, 2, 3, ... up
+to the number of variables. These can be used in NF\_INQ\_VAR calls to
+find out the names, types, shapes, and the number of attributes assigned
+to each variable.
+
+Once the number of attributes for a variable is known,ccessive calls
+to NF\_INQ\_ATTNAME return the name for each attribute given the netCDF
+ID, variable ID, and attribute number. Armed with the attribute name, a
+call to NF\_INQ\_ATT returns its type and length. Given the type and
+length, you can allocate enough space to hold the attribute values. Then
+a call to a member of the NF\_GET\_ATT family returns the attribute
+values.
+
+Once the IDs and shapes of netCDF variables are known, data values can
+be accessed by calling a member of the NF\_GET\_VAR1 family for single
+values, or members of the NF\_GET\_VAR, NF\_GET\_VARA, NF\_GET\_VARS, or
+NF\_GET\_VARM for various kinds of array access.
+
+1.4 Adding New Dimensions, Variables, Attributes {#Adding_New_Dimensions__Variables__Attributes}
+------------------------------------------------
+
+An existing netCDF dataset can be extensively altered. New dimensions,
+variables, and attributes can be added or existing ones renamed, and
+existing attributes can be deleted. Existing dimensions, variables, and
+attributes can be renamed. The following code template lists a typical
+sequence of calls to add new netCDF components to an existing dataset:
+
+ 
+
+
+    NF_OPEN             ! open existing netCDF dataset
+      ... 
+    NF_REDEF            ! put it into define mode
+        ... 
+      NF_DEF_DIM        ! define additional dimensions (if any)
+        ... 
+      NF_DEF_VAR        ! define additional variables (if any)
+        ... 
+      NF_PUT_ATT        ! define other attributes (if any)
+        ... 
+    NF_ENDDEF           ! check definitions, leave define mode
+        ... 
+      NF_PUT_VAR        ! provide new variable values
+        ... 
+    NF_CLOSE            ! close netCDF dataset
+
+
+A netCDF dataset is first opened by the NF\_OPEN call. This call puts
+the open dataset in data mode, which means existing data values can be
+accessed and changed, existing attributes can be changed (so long as
+they do not grow), but nothing can be added. To add new netCDF
+dimensions, variables, or attributes you must enter define mode, by
+calling NF\_REDEF.In define mode, call NF\_DEF\_DIM to define new
+dimensions, NF\_DEF\_VAR to define new variables, and a member of the
+NF\_PUT\_ATT family to assign new attributes to variables or enlarge old
+attributes.
+
+You can leave define mode and reenter data mode, checking all the new
+definitions for consistency and committing the changes to disk, by
+calling NF\_ENDDEF. If you do not wish to reenter data mode, just call
+NF\_CLOSE, which will have the effect of first calling NF\_ENDDEF.
+
+Until the NF\_ENDDEF call, you may back out of all the redefinitions
+made in define mode and restore the previous state of the netCDF dataset
+by calling NF\_ABORT. You may also use the NF\_ABORT call to restore the
+netCDF dataset to a consistent state if the call to NF\_ENDDEF fails. If
+you have called NF\_CLOSE from definition mode and the implied call to
+NF\_ENDDEF fails, NF\_ABORT will automatically be called to close the
+netCDF dataset and leave it in its previous consistent state (before you
+entered define mode).
+
+At most one process should have a netCDF dataset open for writing at one
+time. The library is designed to provide limitedpport for multiple
+concurrent readers with one writer, via disciplined use of the NF\_SYNC
+function and the NF\_SHARE flag. If a writer makes changes in define
+mode,ch as the addition of new variables, dimensions, or attributes,
+some means external to the library is necessary to prevent readers from
+making concurrent accesses and to inform readers to call NF\_SYNC before
+the next access.
+
+1.5 Error Handling {#Error_Handling_1_5} 
+------------------
+
+The netCDF library provides the facilities needed to handle errors in a
+flexible way. Each netCDF function returns an integer status value. If
+the returned status value indicates an error, you may handle it in any
+way desired, from printing an associated error message and exiting to
+ignoring the error indication and proceeding (not recommended!). For
+simplicity, the examples in this guide check the error status and call a
+separate function to handle any errors.
+
+The NF\_STRERROR function is available to convert a returned integer
+error status into an error message string.
+
+Occasionally, low-level I/O errors may occur in a layer below the netCDF
+library. For example, if a write operation causes you to exceed disk
+quotas or to attempt to write to a device that is no longer available,
+you may get an error from a layer below the netCDF library, but the
+rlting write error will still be reflected in the returned status
+value.
+
+1.6 Compiling and Linking with the NetCDF Library {#Compiling_and_Linking_with_the_NetCDF_Library}
+-------------------------------------------------
+
+Details of how to compile and link a program that uses the netCDF C or
+FORTRAN interfaces differ, depending on the operating system, the
+available compilers, and where the netCDF library and include files are
+installed. Nevertheless, we provide here examples of how to compile and
+link a program that uses the netCDF library on a Unix platform, so that
+you can adjust these examples to fit your installation.
+
+Every FORTRAN file that references netCDF functions or constants must
+contain an appropriate INCLUDE statement before the first
+reference:
+
+	INCLUDE 'netcdf.inc'
+
+
+Unless the netcdf.inc file is installed in a standard directory where
+the FORTRAN compiler always looks, you must use the -I option when
+invoking the compiler, to specify a directory where netcdf.inc is
+installed, for example:
+
+	f77 -c -I/usr/local/include myprogram.f
+
+
+Unless the netCDF library is installed in a standard directory where the
+linker always looks, you must use the -L and -l options to link an
+object file that uses the netCDF library. Since version 4.1.3, the
+netCDF Fortran library (named ‘libnetcdff’) is distinct from the netCDF
+C library (named ‘libnetcdf’), but depends on it. If it is installed as
+a shared library, you need only use ‘-lnetcdff’ to specify the Fortran
+library for linking.
+
+For example, if installed as a shared library, use something like:
+
+
+	f77 -o myprogram myprogram.o -L/usr/local/lib -lnetcdff
+
+
+If installed as a static library, you will at least need to mention the
+netCDF C library and perhaps other libraries,ch as hdf5 or curl,
+depending on how the C library was built. For example:
+
+ 
+
+
+	f77 -o myprogram myprogram.o -L/usr/local/lib -lnetcdff -lnetcdf
+
+
+Use of the nf-config utility program, installed as part of the
+netcdf-fortran software, provides an easier way to compile and link,
+without needing to know the details of where the library has been
+installed, or whether it is installed as a shared or static library.
+
+To see all the options for ‘nf-config’, invoke it with the ‘–help’
+argument.
+
+Here’s an example of how you could use ‘nf-config’ to compile and link a
+Fortran program in one step:
+
+ 
+
+
+	f77 myprogram.f -o myprogram `nf-config --fflags --flibs`
+
+
+If it is installed on your system, you could also use the ‘pkg-config’
+utility to compile and link Fortran programs with the netCDF libraries.
+This is especially useful in Makefiles, to ilate them from changes to
+library versions and dependencies. Here is an example of how you could
+compile and link a Fortran program with netCDF libraries using
+pkg-config:
+
+ 
+
+
+	export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
+	f77 myprogram.f -o myprogram `pkg-config --cflags --libs netcdf-fortran`
+
+
+where here ‘–cflags’ means compiler flags and ‘libs’ requests that the
+approriate libraries be linked in.
+
+
+
+2. Datasets  {#Datasets_}
+===========
+
+2.1 Datasets Introduction {#Datasets_Introduction} 
+-------------------------
+
+This presents the interfaces of the netCDF functions that deal
+with a netCDF dataset or the whole netCDF library.
+
+A netCDF dataset that has not yet been opened can only be referred to by
+its dataset name. Once a netCDF dataset is opened, it is referred to by
+a netCDF ID, which is a small nonnegative integer returned when you
+create or open the dataset. A netCDF ID is much like a file descriptor
+in C or a logical unit number in FORTRAN. In any single program, the
+netCDF IDs of distinct open netCDF datasets are distinct. A single
+netCDF dataset may be opened multiple times and will then have multiple
+distinct netCDF IDs; however at most one of the open instances of a
+single netCDF dataset should permit writing. When an open netCDF dataset
+is closed, the ID is no longer associated with a netCDF dataset.
+
+Functions that deal with the netCDF library include:
+
+-   Get version of library.
+-   Get error message corresponding to a returned error code.
+
+The operationspported on a netCDF dataset as a single object are:
+
+-   Create, given dataset name and whether to overwrite or not.
+-   Open for access, given dataset name and read or write intent.
+-   Put into define mode, to add dimensions, variables, or attributes.
+-   Take out of define mode, checking consistency of additions.
+-   Close, writing to disk if required.
+-   Inquire about the number of dimensions, number of variables, number
+    of global attributes, and ID of the unlimited dimension, if any.
+-   Synchronize to disk to makere it is current.
+-   Set and unset nofill mode for optimized sequential writes.
+-   After ammary of conventions used in describing the netCDF
+    interfaces, the rest of this presents a detailed description
+    of the interfaces for these operations.
+
+2.2 NetCDF Library Interface Descriptions {#NetCDF_Library_Interface_Descriptions} 
+-----------------------------------------
+
+Each interface description for a particular netCDF function in this and
+laters contains:
+
+-   a description of the purpose of the function;
+-   a FORTRAN function prototype that presents the type and order of the
+    formal parameters to the function;
+-   a description of each formal parameter in the C interface;
+-   a list of possible error conditions; and
+-   an example of a FORTRAN program fragment calling the netCDF function
+    (and perhaps other netCDF functions).
+
+The examples follow a simple convention for error handling, always
+checking the error status returned from each netCDF function call and
+calling a handle\_error function in case an error was detected. For an
+example ofch a function, see Section 5.2 "Get error message
+corresponding to error status: nf\_strerror".
+
+2.3 NF_STRERROR {#NF_STRERROR} 
+----------------
+
+The function NF\_STRERROR returns a static reference to an error message
+string corresponding to an integer netCDF error status or to a system
+error number, prmably returned by a previous call to some other
+netCDF function. The list of netCDF error status codes is available in
+the appropriate include file for each language binding.
+
+### Usage 
+
+~~~
+CHARACTER*80 FUNCTION NF_STRERROR(INTEGER NCERR)
+~~~
+
+ `NCERR`
+:   An error status that might have been returned from a previous call
+    to some netCDF function.
+
+
+### Errors 
+
+If you provide an invalid integer error status that does not correspond
+to any netCDF error message or or to any system error message (as
+understood by the system strerror function), NF\_STRERROR returns a
+string indicating that there is noch error status.
+
+### Example 
+
+Here is an example of a simple error handling function that uses
+NF\_STRERROR to print the error message corresponding to the netCDF
+error status returned from any netCDF function call and then exit:
+
+ 
+
+~~~
+INCLUDE 'netcdf.inc'
+   ... 
+SUBROUTINE HANDLE_ERR(STATUS)
+INTEGER STATUS
+IF (STATUS .NE. NF_NOERR) THEN
+  PRINT *, NF_STRERROR(STATUS)
+  STOP 'Stopped'
+ENDIF
+END
+~~~
+
+
+2.4 Get netCDF library version: NF_INQ_LIBVERS {#Get_netCDF_library_version_NF_INQ_LIBVERS} 
+------------------------------------------------
+
+The function NF\_INQ\_LIBVERS returns a string identifying the version
+of the netCDF library, and when it was built.
+
+### Usage 
+
+~~~
+CHARACTER*80 FUNCTION NF_INQ_LIBVERS()
+~~~
+
+### Errors 
+
+This function takes no arguments, and thus no errors are possible in its
+invocation.
+
+### Example 
+
+Here is an example using nf\_inq\_libvers to print the version of the
+netCDF library with which the program is linked:
+
+
+~~~
+INCLUDE 'netcdf.inc'
+   ... 
+PRINT *, NF_INQ_LIBVERS()
+~~~
+
+2.5 NF_CREATE {#NF_CREATE} 
+--------------
+
+This function creates a new netCDF dataset, returning a netCDF ID that
+can sequently be used to refer to the netCDF dataset in other netCDF
+function calls. The new netCDF dataset opened for write access and
+placed in define mode, ready for you to add dimensions, variables, and
+attributes.
+
+A creation mode flag specifies whether to overwrite any existing dataset
+with the same name and whether access to the dataset is shared.
+
+### Usage 
+ 
+~~~
+INTEGER FUNCTION NF_CREATE (CHARACTER*(*) PATH, INTEGER CMODE, 
+                            INTEGER ncid)
+~~~
+
+ `PATH`:   The file name of the new netCDF dataset.
+
+ `CMODE`:   The creation mode flag. The following flags are available:
+    NF\_NOCLOBBER, NF\_SHARE, NF\_64BIT\_OFFSET, NF\_NETCDF4 and
+    NF\_CLASSIC\_MODEL. You can combine the affect of multiple flags in
+    a single argument by using the bitwise OR operator. For example, to
+    specify both NF\_NOCLOBBER and NF\_SHARE, you could provide the
+    argument OR(NF\_NOCLOBBER, NF\_SHARE).
+
+
+A zero value (defined for convenience as NF_CLOBBER) specifies the
+default behavior: overwrite any existing dataset with the same file
+name and buffer and cache accesses for efficiency. The dataset will
+be in netCDF classic format. See  'NetCDF Classic Format Limitations' 
+in The NetCDF Users Guide.
+
+Setting NF\_NOCLOBBER means you do not want to clobber (overwrite)
+an existing dataset; an error (NF_EEXIST) is returned if the
+specified dataset already exists.
+
+The NF\_SHARE flag is appropriate when one process may be writing
+the dataset and one or more other processes reading the dataset
+concurrently; it means that dataset accesses are not buffered and
+caching is limited. Since the buffering scheme is optimized for
+sequential access, programs that do not access data sequentially may
+see some performance improvement by setting the NF\_SHARE flag. This
+only applied to classic and 64-bit offset format files.
+
+Setting NF\_64BIT\_OFFSET causes netCDF to create a 64-bit offset
+format file, instead of a netCDF classic format file. The 64-bit
+offset format imposes far fewer restrictions on very large (i.e.
+over 2 GB) data files. See [(netcdf)Large File
+Support](netcdf.html#Large-File-Support) ‘Large File
+Support’ in The NetCDF Users Guide.
+
+Setting NF\_NETCDF4 causes netCDF to create a netCDF-4/HDF5 format
+file. Oring NF\_CLASSIC\_MODEL with NF\_NETCDF4 causes the netCDF
+library to create a netCDF-4/HDF5 data file, with the netCDF classic
+model enforced - none of the new features of the netCDF-4 data model
+may be usedinch a file, for example groups and user-defined
+types.
+
+ `ncid`
+:   Returned netCDF ID.
+
+### Errors 
+
+NF\_CREATE returns the value NF\_NOERR if no errors occurred. Possible
+causes of errors include:
+
+-   Passing a dataset name that includes a directory that does not
+    exist.
+-   Specifying a dataset name of a file that exists and also specifying
+    NF\_NOCLOBBER.
+-   Specifying a meaningless value for the creation mode.
+-   Attempting to create a netCDF dataset in a directory where you don’t
+    have permission to create files.
+
+### Example 
+
+In this example we create a netCDF dataset named foo.nc; we want the
+dataset to be created in the current directory only if a dataset with
+that name does not already exist:
+
+ 
+
+~~~
+INCLUDE 'netcdf.inc'
+  ... 
+INTEGER NCID, STATUS
+... 
+STATUS = NF_CREATE('foo.nc', NF_NOCLOBBER, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+~~~
+
+2.6 NF__CREATE {#NF__CREATE}
+----------------
+
+This function is a variant of NF\_CREATE, NF\_\_CREATE (note the double
+underscore) allows users to specify two tuning parameters for the file
+that it is creating. These tuning parameters are not written to the data
+file, they are only used for so long as the file remains open after an
+NF\_\_CREATE.
+
+This function creates a new netCDF dataset, returning a netCDF ID that
+canbsequently be used to refer to the netCDF dataset in other netCDF
+function calls. The new netCDF dataset opened for write access and
+placed in define mode, ready for you to add dimensions, variables, and
+attributes.
+
+A creation mode flag specifies whether to overwrite any existing dataset
+with the same name and whether access to the dataset is shared.
+
+### Usage 
+
+~~~
+INTEGER FUNCTION NF__CREATE (CHARACTER*(*) PATH, INTEGER CMODE, INTEGER INITIALSZ, 
+                            INTEGER BUFRSIZEHINT, INTEGER ncid)
+
+~~~
+ `PATH`
+:   The file name of the new netCDF dataset.
+
+ `CMODE`
+:   The creation mode flag. The following flags are available:
+    NF\_NOCLOBBER, NF\_SHARE, NF\_64BIT\_OFFSET, NF\_NETCDF4, and
+    NF\_CLASSIC\_MODEL.
+
+    Setting NF\_NOCLOBBER means you do not want to clobber (overwrite)
+    an existing dataset; an error (NF\_EEXIST) is returned if the
+    specified dataset already exists.
+
+    The NF\_SHARE flag is appropriate when one process may be writing
+    the dataset and one or more other processes reading the dataset
+    concurrently; it means that dataset accesses are not buffered and
+    caching is limited. Since the buffering scheme is optimized for
+    sequential access, programs that do not access data sequentially may
+    see some performance improvement by setting the NF\_SHARE flag. This
+    flag has no effect with netCDF-4/HDF5 files.
+
+    Setting NF\_64BIT\_OFFSET causes netCDF to create a 64-bit offset
+    format file, instead of a netCDF classic format file. The 64-bit
+    offset format imposes far fewer restrictions on very large (i.e.
+    over 2 GB) data files. See [(netcdf)Large File
+    Support](netcdf.html#Large-File-Support) ‘Large File
+    Support’ in The NetCDF Users Guide.
+
+    Setting NF\_CLASSIC\_MODEL causes netCDF to enforce the classic data
+    model in this file. (This only has effect for netCDF-4/HDF5 files,
+    as classic and 64-bit offset files always use the classic model.)
+    When used with NF\_NETCDF4, this flag eres that the rlting
+    netCDF-4/HDF5 file may never contain any new constructs from the
+    enhanced data model. That is, it cannot contain groups, user defined
+    types, multiple unlimited dimensions, or new atomic types. The
+    advantage of this restriction is thatch files are guarenteed to
+    work with existing netCDF software.
+
+    A zero value (defined for convenience as NF\_CLOBBER) specifies the
+    default behavior: overwrite any existing dataset with the same file
+    name and buffer and cache accesses for efficiency. The dataset will
+    be in netCDF classic format. See [(netcdf)NetCDF Classic Format
+    Limitations](netcdf.html#NetCDF-Classic-Format-Limitations)
+    ‘NetCDF Classic Format Limitations’ in The NetCDF Users Guide.
+
+ `INITIALSZ`
+:   This parameter sets the initial size of the file at creation time.
+
+ `BUFRSIZEHINT`
+:   The argument referenced by BUFRSIZEHINT controls a space ves time
+    tradeoff, memory allocated in the netcdf library ves number of
+    system calls.
+
+    Because of internal requirements, the value may not be set to
+    exactly the value requested. The actual value chosen is returned by
+    reference.
+
+    Using the value NF\_SIZEHINT\_DEFAULT causes the library to choose a
+    default. How the system chooses the default depends on the system.
+    On many systems, the "preferred I/O block size" is available from
+    the stat() system call, struct stat member st\_blksize. If this is
+    available it is used. Lacking that, twice the system pagesize is
+    used.
+
+    Lacking a call to discover the system pagesize, we just set default
+    bufrsize to 8192.
+
+    The BUFRSIZE is a property of a given open netcdf descriptor ncid,
+    it is not a persistent property of the netcdf dataset.
+
+ `ncid`
+:   Returned netCDF ID.
+
+### Errors 
+
+NF\_\_CREATE returns the value NF\_NOERR if no errors occurred. Possible
+causes of errors include:
+
+-   Passing a dataset name that includes a directory that does not
+    exist.
+-   Specifying a dataset name of a file that exists and also specifying
+    NF\_NOCLOBBER.
+-   Specifying a meaningless value for the creation mode.
+-   Attempting to create a netCDF dataset in a directory where you don’t
+    have permission to create files.
+
+### Example 
+
+In this example we create a netCDF dataset named foo.nc; we want the
+dataset to be created in the current directory only if a dataset with
+that name does not already exist:
+
+ 
+
+~~~
+INCLUDE 'netcdf.inc'
+  ... 
+INTEGER NCID, STATUS, INITIALSZ, BUFRSIZEHINT
+... 
+INITIALSZ = 2048
+BUFRSIZEHINT = 1024
+STATUS = NF__CREATE('foo.nc', NF_NOCLOBBER, INITIALSZ, BUFRSIZEHINT, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+~~~
+
+2.7 NF_CREATE_PAR {#NF_CREATE_PAR} 
+-------------------
+
+This function is a variant of nf\_create, nf\_create\_par allows users
+to open a file on a MPI/IO or MPI/Posix parallel file system.
+
+The parallel parameters are not written to the data file, they are only
+used for so long as the file remains open after an nf\_create\_par.
+
+This function is only available if the netCDF library was built with
+parallel I/O.
+
+This function creates a new netCDF dataset, returning a netCDF ID that
+canbsequently be used to refer to the netCDF dataset in other netCDF
+function calls. The new netCDF dataset opened for write access and
+placed in define mode, ready for you to add dimensions, variables, and
+attributes.
+
+When a netCDF-4 file is created for parallel access, independent
+operations are the default. To use collective access on a variable, See
+section [Change between Collective and Independent Parallel Access:
+NF\_VAR\_PAR\_ACCESS](#NF_005fVAR_005fPAR_005fACCESS).
+
+### Usage 
+
+~~~
+INTEGER FUNCTION NF_CREATE_PAR(CHARACTER*(*) PATH, INTEGER CMODE, 
+                               INTEGER MPI_COMM, INTEGER MPI_INFO, 
+                               INTEGER ncid)
+~~~
+
+ `PATH`
+:   The file name of the new netCDF dataset.
+
+ `CMODE`
+:   The creation mode flag. The following flags are available:
+    NF\_NOCLOBBER, NF\_NETCDF4 and NF\_CLASSIC\_MODEL. You can combine
+    the affect of multiple flags in a single argument by using the
+    bitwise OR operator. For example, to specify both NF\_NOCLOBBER and
+    NF\_NETCDF4, you could provide the argument OR(NF\_NOCLOBBER,
+    NF\_NETCDF4).
+
+    Setting NF\_NETCDF4 causes netCDF to create a netCDF-4/HDF5 format
+    file. Oring NF\_CLASSIC\_MODEL with NF\_NETCDF4 causes the netCDF
+    library to create a netCDF-4/HDF5 data file, with the netCDF classic
+    model enforced - none of the new features of the netCDF-4 data model
+    may be usedinch a file, for example groups and user-defined
+    types.
+
+    Only netCDF-4/HDF5 files may be used with parallel I/O.
+
+ `MPI_COMM`
+:   The MPI communicator.
+
+ `MPI_INFO`
+:   The MPI info.
+
+ `ncid`
+:   Returned netCDF ID.
+
+### Errors 
+
+
+NF\_CREATE returns the value NF\_NOERR if no errors occurred. Possible
+causes of errors include:
+
+-   Passing a dataset name that includes a directory that does not
+    exist.
+-   Specifying a dataset name of a file that exists and also specifying
+    NF\_NOCLOBBER.
+-   Specifying a meaningless value for the creation mode.
+-   Attempting to create a netCDF dataset in a directory where you don’t
+    have permission to create files.
+
+### Example 
+
+
+This example is from test program nf\_test/ftst\_parallel.F.
+
+ 
+
+~~~
+!     Create the netCDF file. 
+      mode_flag = IOR(nf_netcdf4, nf_classic_model) 
+      retval = nf_create_par(FILE_NAME, mode_flag, MPI_COMM_WORLD, 
+     $     MPI_INFO_NULL, ncid)
+      if (retval .ne. nf_noerr) stop 2
+~~~
+
+
+2.8 NF_OPEN  {#NF_OPEN_}
+------------
+
+The function NF\_OPEN opens an existing netCDF dataset for access.
+
+### Usage 
+
+~~~
+INTEGER FUNCTION NF_OPEN(CHARACTER*(*) PATH, INTEGER OMODE, INTEGER ncid)
+~~~
+
+ `PATH`
+:   File name for netCDF dataset to be opened. This may be an OPeNDAP
+    URL if DAPpport is enabled.
+
+ `OMODE`
+:   A zero value (or NF\_NOWRITE) specifies: open the dataset with
+    read-only access, buffering and caching accesses for efficiency.
+
+    Otherwise, the creation mode is NF\_WRITE, NF\_SHARE, or
+    OR(NF\_WRITE, NF\_SHARE). Setting the NF\_WRITE flag opens the
+    dataset with read-write access. ("Writing" means any kind of change
+    to the dataset, including appending or changing data, adding or
+    renaming dimensions, variables, and attributes, or deleting
+    attributes.) The NF\_SHARE flag is appropriate when one process may
+    be writing the dataset and one or more other processes reading the
+    dataset concurrently; it means that dataset accesses are not
+    buffered and caching is limited. Since the buffering scheme is
+    optimized for sequential access, programs that do not access data
+    sequentially may see some performance improvement by setting the
+    NF\_SHARE flag.
+
+ `ncid`
+:   Returned netCDF ID.
+
+### Errors 
+
+
+NF\_OPEN returns the value NF\_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+
+-   The specified netCDF dataset does not exist.
+-   A meaningless mode was specified.
+
+### Example 
+
+Here is an example using NF\_OPEN to open an existing netCDF dataset
+named foo.nc for read-only, non-shared access:
+
+~~~
+INCLUDE 'netcdf.inc'
+ ... 
+INTEGER NCID, STATUS
+... 
+STATUS = NF_OPEN('foo.nc', 0, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+~~~
+
+2.9 NF__OPEN  {#NF__OPEN_}
+--------------
+
+The function NF\_OPEN opens an existing netCDF dataset for access, with
+a performance tuning parameter.
+
+### Usage 
+
+~~~
+INTEGER FUNCTION NF_OPEN(CHARACTER*(*) PATH, INTEGER OMODE, INTEGER
+BUFRSIZEHINT, INTEGER ncid)
+~~~
+
+ `PATH`
+:   File name for netCDF dataset to be opened.
+
+ `OMODE`
+:   A zero value (or NF\_NOWRITE) specifies: open the dataset with
+    read-only access, buffering and caching accesses for efficiency
+
+    Otherwise, the creation mode is NF\_WRITE, NF\_SHARE, or
+    OR(NF\_WRITE,NF\_SHARE). Setting the NF\_WRITE flag opens the
+    dataset with read-write access. ("Writing" means any kind of change
+    to the dataset, including appending or changing data, adding or
+    renaming dimensions, variables, and attributes, or deleting
+    attributes.) The NF\_SHARE flag is appropriate when one process may
+    be writing the dataset and one or more other processes reading the
+    dataset concurrently; it means that dataset accesses are not
+    buffered and caching is limited. Since the buffering scheme is
+    optimized for sequential access, programs that do not access data
+    sequentially may see some performance improvement by setting the
+    NF\_SHARE flag.
+
+ `BUFRSIZEHINT`
+:   This argument controls a space ves time tradeoff, memory
+    allocated in the netcdf library ves number of system calls.
+
+    Because of internal requirements, the value may not be set to
+    exactly the value requested. The actual value chosen is returned by
+    reference.
+
+    Using the value NF\_SIZEHINT\_DEFAULT causes the library to choose a
+    default. How the system chooses the default depends on the system.
+    On many systems, the "preferred I/O block size" is available from
+    the stat() system call, struct stat member st\_blksize. If this is
+    available it is used. Lacking that, twice the system pagesize is
+    used.
+
+    Lacking a call to discover the system pagesize, we just set default
+    bufrsize to 8192.
+
+    The bufrsize is a property of a given open netcdf descriptor ncid,
+    it is not a persistent property of the netcdf dataset.
+
+ `ncid`
+:   Returned netCDF ID.
+
+### Errors 
+
+
+NF\_\_OPEN returns the value NF\_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+
+-   The specified netCDF dataset does not exist.
+-   A meaningless mode was specified.
+
+### Example 
+
+Here is an example using NF\_\_OPEN to open an existing netCDF dataset
+named foo.nc for read-only, non-shared access:
+
+
+~~~
+INCLUDE 'netcdf.inc'
+ ... 
+INTEGER NCID, STATUS, BUFRSIZEHINT
+... 
+BUFRSIZEHINT = 1024
+STATUS = NF_OPEN('foo.nc', 0, BUFRSIZEHINT, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+~~~
+
+2.10 NF\_OPEN\_PAR  {#NF_OPEN_PAR}
+------------------
+
+This function opens a netCDF-4 dataset for parallel access.
+
+This function is only available if the netCDF library was built with a
+HDF5 library for which –enable-parallel was used, and which was linked
+(like HDF5) to MPI libraries.
+
+This opens the file using either MPI-IO or MPI-POSIX. The file must be a
+netCDF-4 file. (That is, it must have been created using NF\_NETCDF4 in
+the creation mode).
+
+This function is only available if netCDF-4 was build with a version of
+the HDF5 library which was built with –enable-parallel.
+
+Before either HDF5 or netCDF-4 can be installed withpport for
+parallel programming, and MPI layer must also be installed on the
+machine, and ally a parallel file system.
+
+NetCDF-4 exposes the parallel access functionality of HDF5. For more
+information about what is required to install and use the parallel
+access functions, see the HDF5 web site.
+
+When a netCDF-4 file is opened for parallel access, collective
+operations are the default. To use independent access on a variable, See
+section [Change between Collective and Independent Parallel Access:
+NF\_VAR\_PAR\_ACCESS](#NF_005fVAR_005fPAR_005fACCESS).
+
+Usage 
+-----
+
+~~~
+INTEGER FUNCTION NF_OPEN_PAR(CHARACTER*(*) PATH, INTEGER OMODE, 
+                             INTEGER MPI_COMM, INTEGER MPI_INFO, 
+                             INTEGER ncid)
+~~~
+
+ `PATH`
+:   File name for netCDF dataset to be opened.
+
+ `OMODE`
+:   A zero value (or NF\_NOWRITE) specifies: open the dataset with
+    read-only access.
+
+    Otherwise, the mode may be NF\_WRITE. Setting the NF\_WRITE flag
+    opens the dataset with read-write access. ("Writing" means any kind
+    of change to the dataset, including appending or changing data,
+    adding or renaming dimensions, variables, and attributes, or
+    deleting attributes.)
+
+    Setting NF\_NETCDF4 is not necessary (or allowed). The file type is
+    detected automatically.
+
+ `MPI_COMM`
+:   The MPI communicator.
+
+ `MPI_INFO`
+:   The MPI info.
+
+ `ncid`
+:   Returned netCDF ID.
+
+Errors 
+------
+
+NF\_OPEN returns the value NF\_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+
+-   The specified netCDF dataset does not exist.
+-   A meaningless mode was specified.
+-   Not a netCDF-4 file.
+
+Example 
+-------
+
+This example is from the test program nf\_test/ftst\_parallel.F.
+
+ 
+
+
+!     Reopen the file.
+      retval = nf_open_par(FILE_NAME, nf_nowrite, MPI_COMM_WORLD, 
+     $     MPI_INFO_NULL, ncid)
+      if (retval .ne. nf_noerr) stop 2
+
+
+2.11 NF\_REDEF 
+--------------
+
+The function NF\_REDEF puts an open netCDF dataset into define mode, so
+dimensions, variables, and attributes can be added or renamed and
+attributes can be deleted.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_REDEF(INTEGER NCID)
+
+
+ `NCID`
+:   netCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+Errors 
+------
+
+NF\_REDEF returns the value NF\_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+
+-   The specified netCDF dataset is already in define mode.
+-   The specified netCDF dataset was opened for read-only.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+Here is an example using NF\_REDEF to open an existing netCDF dataset
+named foo.nc and put it into define mode:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER NCID, STATUS
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_WRITE, NCID)   ! open dataset
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_REDEF(NCID)                      ! put in define mode
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+2.12 NF\_ENDDEF 
+---------------
+
+The function NF\_ENDDEF takes an open netCDF dataset out of define mode.
+The changes made to the netCDF dataset while it was in define mode are
+checked and committed to disk if no problems occurred. Non-record
+variables may be initialized to a "fill value" as well (see
+[NF\_SET\_FILL](#NF_005fSET_005fFILL)). The netCDF dataset is then
+placed in data mode, so variable data can be read or written.
+
+This call may involve copying data under some circumstances. See
+[(netcdf)File Structure and
+Performance](netcdf.html#File-Structure-and-Performance) ‘File
+Structure and Performance’ in NetCDF Users’ Guide.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_ENDDEF(INTEGER NCID)
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+Errors 
+------
+
+NF\_ENDDEF returns the value NF\_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+
+-   The specified netCDF dataset is not in define mode.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+    The size of one or more variables exceed the size constraints for
+    whichever variant of the file format is in use). See [(netcdf)Large
+    File Support](netcdf.html#Large-File-Support) ‘Large File
+    Support’ in The NetCDF Users Guide.
+
+Example 
+-------
+
+Here is an example using NF\_ENDDEF to finish the definitions of a new
+netCDF dataset named foo.nc and put it into data mode:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER NCID, STATUS
+   ... 
+STATUS = NF_CREATE('foo.nc', NF_NOCLOBBER, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+   ...   ! create dimensions, variables, attributes
+
+STATUS = NF_ENDDEF(NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+2.13 NF\_\_ENDDEF 
+-----------------
+
+The function NF\_\_ENDDEF takes an open netCDF dataset out of define
+mode. The changes made to the netCDF dataset while it was in define mode
+are checked and committed to disk if no problems occurred. Non-record
+variables may be initialized to a "fill value" as well (see
+[NF\_SET\_FILL](#NF_005fSET_005fFILL)). The netCDF dataset is then
+placed in data mode, so variable data can be read or written.
+
+This call may involve copying data under some circumstances. See
+[(netcdf)File Structure and
+Performance](netcdf.html#File-Structure-and-Performance) ‘File
+Structure and Performance’ in NetCDF Users’ Guide.
+
+This function ames specific characteristics of the netcdf version 1
+and version 2 file formats. Users should use nf\_enddef in most
+circumstances. Although this function will be available in future netCDF
+implementations, it may not continue to have any effect on performance.
+
+The current netcdf file format has threes, the "header",
+the data for fixed size variables, and the data for
+variables which have an unlimited dimension (record variables).
+
+The header begins at the beginning of the file. The index (offset) of
+the beginning of the other twos is contained in the header.
+Typically, there is no space between thes. This causes copying
+overhead to accrue if one wishes to change the size of thes, as
+may happen when changing names of things, text attribute values, adding
+attributes or adding variables. Also, for buffered i/o, there may be
+advantages to alignings in certain ways.
+
+The minfree parameters allow one to control costs of future calls to
+nf\_redef, nf\_enddef by requesting that minfree bytes be available at
+the end of the.
+
+The align parameters allow one to set the alignment of the beginning of
+the correspondings. The beginning of the is rounded up
+to an index which is a multiple of the align parameter. The flag value
+ALIGN\_CHUNK tells the library to use the bufrsize (see above) as the
+align parameter.
+
+The file format requires mod 4 alignment, so the align parameters are
+silently rounded up to multiples of 4. The al call,
+
+ 
+
+
+nf_enddef(ncid);
+
+
+is equivalent to
+
+
+nf_enddef(ncid, 0, 4, 0, 4);
+
+
+The file format does not contain a "record size" value, this is
+calculated from the sizes of the record variables. This unfortunate fact
+prevents us from providing minfree and alignment control of the
+"records" in a netcdf file. If you add a variable which has an unlimited
+dimension, the third will always be copied with the new variable
+added.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_ENDDEF(INTEGER NCID, INTEGER H_MINFREE, INTEGER V_ALIGN,
+               INTEGER V_MINFREE, INTEGER R_ALIGN)
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `H_MINFREE`
+:   Sets the pad at the end of the "header".
+
+ `V_ALIGN`
+:   Controls the alignment of the beginning of the data for
+    fixed size variables.
+
+ `V_MINFREE`
+:   Sets the pad at the end of the data for fixed size
+    variables.
+
+ `R_ALIGN`
+:   Controls the alignment of the beginning of the data for
+    variables which have an unlimited dimension (record variables).
+
+Errors 
+------
+
+NF\_\_ENDDEF returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The specified netCDF dataset is not in define mode.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+-   The size of one or more variables exceed the size constraints for
+    whichever variant of the file format is in use). See [(netcdf)Large
+    File Support](netcdf.html#Large-File-Support) ‘Large File
+    Support’ in The NetCDF Users Guide.
+
+Example 
+-------
+
+Here is an example using NF\_\_ENDDEF to finish the definitions of a new
+netCDF dataset named foo.nc and put it into data mode:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER NCID, STATUS, H_MINFREE, V_ALIGN, V_MINFREE, R_ALIGN
+   ... 
+STATUS = NF_CREATE('foo.nc', NF_NOCLOBBER, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+   ...   ! create dimensions, variables, attributes
+
+H_MINFREE = 512
+V_ALIGN = 512
+V_MINFREE = 512
+R_ALIGN = 512
+STATUS = NF_ENDDEF(NCID, H_MINFREE, V_ALIGN, V_MINFREE, R_ALIGN)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+2.14 NF\_CLOSE 
+--------------
+
+The function NF\_CLOSE closes an open netCDF dataset. If the dataset is
+in define mode, NF\_ENDDEF will be called before closing. (In this case,
+if NF\_ENDDEF returns an error, NF\_ABORT will automatically be called
+to restore the dataset to the consistent state before define mode was
+last entered.) After an open netCDF dataset is closed, its netCDF ID may
+be reassigned to the next netCDF dataset that is opened or created.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_CLOSE(INTEGER NCID)
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+Errors 
+------
+
+NF\_CLOSE returns the value NF\_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+
+-   Define mode was entered and the automatic call made to NF\_ENDDEF
+    failed.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+Here is an example using NF\_CLOSE to finish the definitions of a new
+netCDF dataset named foo.nc and release its netCDF ID:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER NCID, STATUS
+   ... 
+STATUS = NF_CREATE('foo.nc', NF_NOCLOBBER, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+   ...   ! create dimensions, variables, attributes
+
+STATUS = NF_CLOSE(NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+2.15 NF\_INQ Family 
+-------------------
+
+Members of the NF\_INQ family of functions return information about an
+open netCDF dataset, given its netCDF ID. Dataset inquire functions may
+be called from either define mode or data mode. The first function,
+NF\_INQ, returns values for the number of dimensions, the number of
+variables, the number of global attributes, and the dimension ID of the
+dimension defined with unlimited length, if any. The other functions in
+the family each return just one of these items of information.
+
+For FORTRAN, these functions include NF\_INQ, NF\_INQ\_NDIMS,
+NF\_INQ\_NVARS, NF\_INQ\_NATTS, and NF\_INQ\_UNLIMDIM. An additional
+function, NF\_INQ\_FORMAT, returns the (rarely needed) format version.
+
+No I/O is performed when these functions are called, since the required
+information is available in memory for each open netCDF dataset.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ          (INTEGER NCID, INTEGER ndims,
+                                  INTEGER nvars,INTEGER ngatts,
+                                  INTEGER unlimdimid)
+INTEGER FUNCTION NF_INQ_NDIMS    (INTEGER NCID, INTEGER ndims)
+INTEGER FUNCTION NF_INQ_NVARS    (INTEGER NCID, INTEGER nvars)
+INTEGER FUNCTION NF_INQ_NATTS    (INTEGER NCID, INTEGER ngatts)
+INTEGER FUNCTION NF_INQ_UNLIMDIM (INTEGER NCID, INTEGER unlimdimid)
+INTEGER FUNCTION NF_INQ_FORMAT   (INTEGER NCID, INTEGER format)
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `ndims`
+:   Returned number of dimensions defined for this netCDF dataset.
+
+ `nvars`
+:   Returned number of variables defined for this netCDF dataset.
+
+ `ngatts`
+:   Returned number of global attributes defined for this netCDF
+    dataset.
+
+ `unlimdimid`
+:   Returned ID of the unlimited dimension, if there is one for this
+    netCDF dataset. If no unlimited length dimension has been defined,
+    -1 is returned.
+
+ `format`
+:   Returned format version, one of NF\_FORMAT\_CLASSIC,
+    NF\_FORMAT\_64BIT, NF\_FORMAT\_NETCDF4,
+    NF\_FORMAT\_NETCDF4\_CLASSIC.
+
+Errors 
+------
+
+All members of the NF\_INQ family return the value NF\_NOERR if no
+errors occurred. Otherwise, the returned status indicates an error.
+Possible causes of errors include:
+
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+Here is an example using NF\_INQ to find out about a netCDF dataset
+named foo.nc:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS, NCID, NDIMS, NVARS, NGATTS, UNLIMDIMID
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ(NCID, NDIMS, NVARS, NGATTS, UNLIMDIMID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+2.16 NF\_SYNC 
+-------------
+
+The function NF\_SYNC offers a way to synchronize the disk copy of a
+netCDF dataset with in-memory buffers. There are two reasons you might
+want to synchronize after writes:
+
+-   To minimize data loss in case of abnormal termination, or
+-   To make data available to other processes for reading immediately
+    after it is written. But note that a process that already had the
+    dataset open for reading would not see the number of records
+    increase when the writing process calls NF\_SYNC; to accomplish
+    this, the reading process must call NF\_SYNC.
+
+This function is backward-compatible with previous versions of the
+netCDF library. The intent was to allow sharing of a netCDF dataset
+among multiple readers and one writer, by having the writer call
+NF\_SYNC after writing and the readers call NF\_SYNC before each read.
+For a writer, this flushes buffers to disk. For a reader, it makesre
+that the next read will be from disk rather than from previously cached
+buffers, so that the reader will see changes made by the writing process
+(e.g., the number of records written) without having to close and reopen
+the dataset. If you are only accessing a small amount of data, it can be
+expensive in computer resources to always synchronize to disk after
+every write, since you are giving up the benefits of buffering.
+
+An easier way to accomplish sharing (and what is now recommended) is to
+have the writer and readers open the dataset with the NF\_SHARE flag,
+and then it will not be necessary to call NF\_SYNC at all. However, the
+NF\_SYNC function still provides finer granularity than the NF\_SHARE
+flag, if only a few netCDF accesses need to be synchronized among
+processes.
+
+It is important to note that changes to the ancillary data,ch as
+attribute values, are not propagated automatically by use of the
+NF\_SHARE flag. Use of the NF\_SYNC function is still required for this
+purpose.
+
+Sharing datasets when the writer enters define mode to change the data
+schema requires extra care. In previous releases, after the writer left
+define mode, the readers were left looking at an old copy of the
+dataset, since the changes were made to a new copy. The only way readers
+could see the changes was by closing and reopening the dataset. Now the
+changes are made in place, but readers have no knowledge that their
+internal tables are now inconsistent with the new dataset schema. If
+netCDF datasets are shared across redefinition, some mechanism external
+to the netCDF library must be provided that prevents access by readers
+during redefinition and causes the readers to call NF\_SYNC before any
+subsequent access.
+
+When calling NF\_SYNC, the netCDF dataset must be in data mode. A netCDF
+dataset in define mode is synchronized to disk only when NF\_ENDDEF is
+called. A process that is reading a netCDF dataset that another process
+is writing may call NF\_SYNC to get updated with the changes made to the
+data by the writing process (e.g., the number of records written),
+without having to close and reopen the dataset.
+
+Data is automatically synchronized to disk when a netCDF dataset is
+closed, or whenever you leave define mode.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_SYNC(INTEGER NCID)
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+Errors 
+------
+
+NF\_SYNC returns the value NF\_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+
+-   The netCDF dataset is in define mode.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+Here is an example using NF\_SYNC to synchronize the disk writes of a
+netCDF dataset named foo.nc:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS, NCID
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+! write data or change attributes
+   ... 
+STATUS = NF_SYNC(NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+2.17 NF\_ABORT 
+--------------
+
+You no longer need to call this function, since it is called
+automatically by NF\_CLOSE in case the dataset is in define mode and
+something goes wrong with committing the changes. The function NF\_ABORT
+just closes the netCDF dataset, if not in define mode. If the dataset is
+being created and is still in define mode, the dataset is deleted. If
+define mode was entered by a call to NF\_REDEF, the netCDF dataset is
+restored to its state before definition mode was entered and the dataset
+is closed.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_ABORT(INTEGER NCID)
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+Errors 
+------
+
+NF\_ABORT returns the value NF\_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+
+-   When called from define mode while creating a netCDF dataset,
+    deletion of the dataset failed.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+Here is an example using NF\_ABORT to back out of redefinitions of a
+dataset named foo.nc:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS, NCID, LATID
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_REDEF(NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_DEF_DIM(NCID, 'LAT', 18, LATID)
+IF (STATUS .NE. NF_NOERR) THEN  ! dimension definition failed
+   CALL HANDLE_ERR(STATUS)
+   STATUS = NF_ABORT(NCID)  ! abort redefinitions
+   IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ENDIF
+...
+
+
+2.18 NF\_SET\_FILL 
+------------------
+
+This function is intended for advanced usage, to optimize writes under
+some circumstances described below. The function NF\_SET\_FILL sets the
+fill mode for a netCDF dataset open for writing and returns the current
+fill mode in a return parameter. The fill mode can be specified as
+either NF\_FILL or NF\_NOFILL. The default behavior corresponding to
+NF\_FILL is that data is pre-filled with fill values, that is fill
+values are written when you create non-record variables or when you
+write a value beyond data that has not yet been written. This makes it
+possible to detect attempts to read data before it was written. See
+section [Fill Values](#Fill-Values), for more information on the use of
+fill values. See [(netcdf)Attribute
+Conventions](netcdf.html#Attribute-Conventions) ‘Attribute
+Conventions’ in The NetCDF Users Guide, for information about how to
+define your own fill values.
+
+The behavior corresponding to NF\_NOFILL overrides the default behavior
+of prefilling data with fill values. This can be used to enhance
+performance, because it avoids the duplicate writes that occur when the
+netCDF library writes fill values that are later overwritten with data.
+
+A value indicating which mode the netCDF dataset was already in is
+returned. You can use this value to temporarily change the fill mode of
+an open netCDF dataset and then restore it to the previous mode.
+
+After you turn on NF\_NOFILL mode for an open netCDF dataset, you must
+be certain to write valid data in all the positions that will later be
+read. Note that nofill mode is only a transient property of a netCDF
+dataset open for writing: if you close and reopen the dataset, it will
+revert to the default behavior. You can also revert to the default
+behavior by calling NF\_SET\_FILL again to explicitly set the fill mode
+to NF\_FILL.
+
+There are three situations where it is advantageous to set nofill mode:
+
+1.  Creating and initializing a netCDF dataset. In this case, you should
+    set nofill mode before calling NF\_ENDDEF and then write completely
+    all non-record variables and the initial records of all the record
+    variables you want to initialize.
+2.  Extending an existing record-oriented netCDF dataset. Set nofill
+    mode after opening the dataset for writing, then append the
+    additional records to the dataset completely, leaving no intervening
+    unwritten records.
+3.  Adding new variables that you are going to initialize to an existing
+    netCDF dataset. Set nofill mode before calling NF\_ENDDEF then write
+    all the new variables completely.
+
+If the netCDF dataset has an unlimited dimension and the last record was
+written while in nofill mode, then the dataset may be shorter than if
+nofill mode was not set, but this will be completely transparent if you
+access the data only through the netCDF interfaces.
+
+The use of this feature may not be available (or even needed) in future
+releases. Programmers are cautioned against heavy reliance upon this
+feature.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_SET_FILL(INTEGER NCID, INTEGER FILLMODE,
+                             INTEGER old_mode)
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `FILLMODE`
+:   Desired fill mode for the dataset, either NF\_NOFILL or NF\_FILL.
+
+ `old_mode`
+:   Returned current fill mode of the dataset before this call, either
+    NF\_NOFILL or NF\_FILL.
+
+Errors 
+------
+
+NF\_SET\_FILL returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+-   The specified netCDF ID refers to a dataset open for read-only
+    access.
+-   The fill mode argument is neither NF\_NOFILL nor NF\_FILL..
+
+Example 
+-------
+
+Here is an example using NF\_SET\_FILL to set nofill mode forbsequent
+writes of a netCDF dataset named foo.nc:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER NCID, STATUS, OMODE
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+! write data with default prefilling behavior
+   ... 
+STATUS = NF_SET_FILL(NCID, NF_NOFILL, OMODE)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+! write data with no prefilling
+   ... 
+
+
+2.19 NF\_SET\_DEFAULT\_FORMAT 
+-----------------------------
+
+This function is intended for advanced users.
+
+In version 3.6, netCDF introduced a new data format, the first change in
+the underlying binary data format since the netCDF interface was
+released. The new format, 64-bit offset format, was introduced to
+greatly relax the limitations on creating very large files.
+
+In version 4.0, another new binary format was introduced: netCDF-4/HDF5.
+
+Users are warned that creating files in the 64-bit offset format makes
+them unreadable by the netCDF library prior to version 3.6.0, and
+creating files in netcdf-4/HDF5 format makes them unreadable by the
+netCDF library prior to version 4.0. For reasons of compatibility, users
+should continue to create files in netCDF classic format.
+
+Users who do want to use 64-bit offset or netCDF-4/HDF5 format files can
+create them directory from NF\_CREATE, using the proper cmode flag. (see
+section [NF\_CREATE](#NF_005fCREATE)).
+
+The function NF\_SET\_DEFAULT\_FORMAT allows the user to change the
+format of the netCDF file to be created by future calls to NF\_CREATE
+without changing the cmode flag.
+
+This allows the user to convert a program to use the new formats without
+changing all calls the NF\_CREATE.
+
+Once the default format is set, all future created files will be in the
+desired format.
+
+Constants are provided in the netcdf.inc file to be used with this
+function: nf\_format\_classic, nf\_format\_64bit, nf\_format\_netcdf4
+and nf\_format\_netcdf4\_classic.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_SET_DEFAULT_FORMAT(INTEGER FORMAT, INTEGER OLD_FORMT)
+
+
+ `FORMAT`
+:   Either nf\_format\_classic, nf\_format\_64bit, nf\_format\_netcdf4
+    or nf\_format\_netcdf4\_classic.
+
+ `OLD_FORMAT`
+:   The default format at the time the function is called is returned
+    here.
+
+Errors 
+------
+
+The following error codes may be returned by this function:
+
+-   An NF\_EINVAL error is returned if an invalid default format is
+    specified.
+
+Example 
+-------
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS, OLD_FORMAT
+   ... 
+STATUS = NF_SET_DEFAULT_FORMAT(nf_format_64bit, OLD_FORMAT)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+
+
+2.20 Set HDF5 Chunk Cache for Future File Opens/Creates: NF\_SET\_CHUNK\_CACHE 
+------------------------------------------------------------------------------
+
+This function changes the chunk cache settings in the HDF5 library. The
+settings apply forbsequent file opens/creates. This function does not
+change the chunk cache settings of already open files.
+
+This affects the per-file chunk cache which the HDF5 layer maintains.
+The chunk cache size can be tuned for better performance.
+
+For more information, see the documentation for the H5Pset\_cache()
+function in the HDF5 library at the HDF5 website:
+[http://hdfgroup.org/HDF5/](http://hdfgroup.org/HDF5/).
+
+Usage 
+-----
+
+ 
+
+
+INTEGER NF_SET_CHUNK_CACHE(INTEGER SIZE, INTEGER NELEMS, INTEGER PREEMPTION);
+
+
+ `SIZE`
+:   The total size of the raw data chunk cache in MegaBytes.
+
+ `NELEMS`
+:   The number slots in the per-variable chunk cache (should be a prime
+    number larger than the number of chunks in the cache).
+
+ `PREEMPTION`
+:   The preemtion value must be between 0 and 100 inclusive and
+    indicates how much chunks that have been fully read are favored for
+    preemption. A value of zero means fully read chunks are treated no
+    differently than other chunks (the preemption is strictly LRU) while
+    a value of 100 means fully read chunks are always preempted before
+    other chunks.
+
+Return Codes 
+------------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EINVAL`
+:   Parameters size and nelems must be non-zero positive integers, and
+    preemption must be between zero and 100 (inclusive). An NF\_EINVAL
+    will be returned otherwise.
+
+
+
+2.21 Get the HDF5 Chunk Cache Settings for Future File Opens/Creates: NF\_GET\_CHUNK\_CACHE 
+-------------------------------------------------------------------------------------------
+
+This function gets the chunk cache settings for the HDF5 library. The
+settings apply forbsequent file opens/creates.
+
+This affects the per-file chunk cache which the HDF5 layer maintains.
+The chunk cache size can be tuned for better performance.
+
+For more information, see the documentation for the H5Pget\_cache()
+function in the HDF5 library at the HDF5 website:
+[http://hdfgroup.org/HDF5/](http://hdfgroup.org/HDF5/).
+
+Usage 
+-----
+
+ 
+
+
+INTEGER NC_GET_CHUNK_CACHE(INTEGER SIZE, INTEGER NELEMS, INTEGER PREEMPTION);
+
+
+ `SIZE`
+:   The total size of the raw data chunk cache will be put here.
+
+ `NELEMS`
+:   The number of chunk slots in the raw data chunk cache hash table
+    will be put here.
+
+ `PREEMPTION`
+:   The preemption will be put here. The preemtion value is between 0
+    and 100 inclusive and indicates how much chunks that have been fully
+    read are favored for preemption. A value of zero means fully read
+    chunks are treated no differently than other chunks (the preemption
+    is strictly LRU) while a value of 100 means fully read chunks are
+    always preempted before other chunks.
+
+Return Codes 
+------------
+
+ `NC_NOERR`
+:   No error.
+
+3. Groups 
+=========
+
+NetCDF-4 addedpport for hierarchical groups within netCDF datasets.
+
+Groups are identified with a ncid, which identifies both the open file,
+and the group within that file. When a file is opened with NF\_OPEN or
+NF\_CREATE, the ncid for the root group of that file is provided. Using
+that as a starting point, users can add new groups, or list and navigate
+existing groups.
+
+All netCDF calls take a ncid which determines where the call will take
+its action. For example, the NF\_DEF\_VAR function takes a ncid as its
+first parameter. It will create a variable in whichever group its ncid
+refers to. Use the root ncid provided by NF\_CREATE or NF\_OPEN to
+create a variable in the root group. Or use NF\_DEF\_GRP to create a
+group and use its ncid to define a variable in the new group.
+
+Variable are only visible in the group in which they are defined. The
+same applies to attributes. “Global” attributes are defined in whichever
+group is refered to by the ncid.
+
+Dimensions are visible in their groups, and all child groups.
+
+Group operations are only permitted on netCDF-4 files - that is, files
+created with the HDF5 flag in nf\_create. (see
+[NF\_CREATE](#NF_005fCREATE)). Groups are not compatible with the netCDF
+classic data model, so files created with the NF\_CLASSIC\_MODEL file
+cannot contain groups (except the root group).
+
+3.1 Find a Group ID: NF\_INQ\_NCID 
+----------------------------------
+
+Given an ncid and group name (NULL or "" gets root group), return ncid
+of the named group.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_NCID(INTEGER NCID, CHARACTER*(*) NAME, INTEGER GRPID)
+
+
+ `NCID`
+:   The group id for this operation.
+
+ `NAME`
+:   A character array that holds the name of the desired group. Must be
+    less then NF\_MAX\_NAME.
+
+ `GRPID`
+:   The ID of the group will go here.
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADID`
+:   Bad group id.
+
+ `NF_ENOTNC4`
+:   Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+    operations can only be performed on files defined with a create mode
+    which includes flag HDF5. (see [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_ESTRICTNC3`
+:   This file was created with the strict netcdf-3 flag, therefore
+    netcdf-4 operations are not allowed. (see
+    [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_groups.F.
+
+ 
+
+
+C     Check getting the group by name
+      retval = nf_inq_ncid(ncid, group_name, grpid_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+3.2 Get a List of Groups in a Group: NF\_INQ\_GRPS 
+--------------------------------------------------
+
+Given a location id, return the number of groups it contains, and an
+array of their ncids.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_GRPS(INTEGER NCID, INTEGER NUMGRPS, INTEGER NCIDS)
+
+
+ `NCID`
+:   The group id for this operation.
+
+ `NUMGRPS`
+:   An integer which will get number of groups in this group.
+
+ `NCIDS`
+:   An array of ints which will receive the IDs of all the groups in
+    this group.
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADID`
+:   Bad group id.
+
+ `NF_ENOTNC4`
+:   Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+    operations can only be performed on files defined with a create mode
+    which includes flag HDF5. (see [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_ESTRICTNC3`
+:   This file was created with the strict netcdf-3 flag, therefore
+    netcdf-4 operations are not allowed. (see
+    [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_groups.F.
+
+ 
+
+
+C     What groups are there from the root group?
+      retval = nf_inq_grps(ncid, ngroups_in, grpids)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+3.3 Find all the Variables in a Group: NF\_INQ\_VARIDS 
+------------------------------------------------------
+
+Find all varids for a location.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_VARIDS(INTEGER NCID, INTEGERS VARIDS)
+
+
+ `NCID`
+:   The group id for this operation.
+
+ `VARIDS`
+:   An already allocated array to store the list of varids. Use
+    nf\_inq\_nvars to find out how many variables there are. (see
+    [NF\_INQ Family](#NF_005fINQ-Family)).
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADID`
+:   Bad group id.
+
+ `NF_ENOTNC4`
+:   Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+    operations can only be performed on files defined with a create mode
+    which includes flag HDF5. (see [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_ESTRICTNC3`
+:   This file was created with the strict netcdf-3 flag, therefore
+    netcdf-4 operations are not allowed. (see
+    [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_groups.F.
+
+ 
+
+
+C     Check varids inbgroup.
+      retval = nf_inq_varidsbgrp_in, nvars, varids_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+3.4 Find all Dimensions Visible in a Group: NF\_INQ\_DIMIDS 
+-----------------------------------------------------------
+
+Find all dimids for a location. This finds all dimensions in a group, or
+any of its parents.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_DIMIDS(INTEGER NCID, INTEGER NDIMS, INTEGER DIMIDS, INTEGER INCLUDE_PARENTS)
+
+
+ `NCID`
+:   The group id for this operation.
+
+ `NDIMS`
+:   Returned number of dimensions for this location. If INCLUDE\_PARENTS
+    is non-zero, number of dimensions visible from this group, which
+    includes dimensions in parent groups.
+
+ `DIMIDS`
+:   An array of ints when the dimids of the visible dimensions will be
+    stashed. Use nf\_inq\_ndims to find out how many dims are visible
+    from this group. (see [NF\_INQ Family](#NF_005fINQ-Family)).
+
+ `INCLUDE_PARENTS`
+:   If zero, only the group specified by NCID will be searched for
+    dimensions. Otherwise parent groups will be searched too.
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADID`
+:   Bad group id.
+
+ `NF_ENOTNC4`
+:   Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+    operations can only be performed on files defined with a create mode
+    which includes flag HDF5. (see [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_ESTRICTNC3`
+:   This file was created with the strict netcdf-3 flag, therefore
+    netcdf-4 operations are not allowed. (see
+    [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_groups.F.
+
+ 
+
+
+C     Check dimids inbgroup.
+      retval = nf_inq_dimidsbgrp_in, ndims, dimids_in, 0)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (ndims .ne. 2 .or. dimids_in(1) .ne. dimids(1) .or.
+     &     dimids_in(2) .ne. dimids(2)) stop 2
+
+
+3.5 Find the Length of a Group’s Name: NF\_INQ\_GRPNAME\_LEN 
+------------------------------------------------------------
+
+Given ncid, find length of the full name. (Root group is named "/", with
+length 1.)
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_GRPNAME_LEN(INTEGER NCID, INTEGER LEN)
+
+
+ `NCID`
+:   The group id for this operation.
+
+ `LEN`
+:   An integer where the length will be placed.
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADID`
+:   Bad group id.
+
+ `NF_ENOTNC4`
+:   Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+    operations can only be performed on files defined with a create mode
+    which includes flag HDF5. (see [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_ESTRICTNC3`
+:   This file was created with the strict netcdf-3 flag, therefore
+    netcdf-4 operations are not allowed. (see
+    [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_groups.F.
+
+ 
+
+
+C     Check the length of the full name.
+      retval = nf_inq_grpname_len(grpids(1), full_name_len)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+3.6 Find a Group’s Name: NF\_INQ\_GRPNAME 
+-----------------------------------------
+
+Given ncid, find relative name of group. (Root group is named "/").
+
+The name provided by this function is relative to the parent group. For
+a full path name for the group is, with all parent groups included,
+separated with a forward slash (as in Unix directory names) See
+[Find a Group’s Full Name:
+NF\_INQ\_GRPNAME\_FULL](#NF_005fINQ_005fGRPNAME_005fFULL).
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_GRPNAME(INTEGER NCID, CHARACTER*(*) NAME)
+
+
+`NCID`
+
+The group id for this operation.
+
+`NAME`
+
+The name of the group will be copied to this character array. The name
+will be less than NF\_MAX\_NAME in length.
+
+``
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADID`
+:   Bad group id.
+
+ `NF_ENOTNC4`
+:   Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+    operations can only be performed on files defined with a create mode
+    which includes flag HDF5. (see [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_ESTRICTNC3`
+:   This file was created with the strict netcdf-3 flag, therefore
+    netcdf-4 operations are not allowed. (see
+    [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_groups.F.
+
+ 
+
+
+C     Check the name of the root group.
+      retval = nf_inq_grpname(ncid, name_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:1) .ne. '/') stop 2
+
+
+
+3.7 Find a Group’s Full Name: NF\_INQ\_GRPNAME\_FULL 
+----------------------------------------------------
+
+Given ncid, find complete name of group. (Root group is named "/").
+
+The name provided by this function is a full path name for the group is,
+with all parent groups included, separated with a forward slash (as in
+Unix directory names). For a name relative to the parent group See
+section [Find a Group’s Name:
+NF\_INQ\_GRPNAME](#NF_005fINQ_005fGRPNAME).
+
+To find the length of the full name See [Find the Length of a
+Group’s Name: NF\_INQ\_GRPNAME\_LEN](#NF_005fINQ_005fGRPNAME_005fLEN).
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_GRPNAME_FULL(INTEGER NCID, INTEGER LEN, CHARACTER*(*) NAME)
+
+
+ `NCID`
+:   The group id for this operation.
+
+ `LEN`
+:   The length of the full group name will go here.
+
+ `NAME`
+:   The name of the group will be copied to this character array.
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADID`
+:   Bad group id.
+
+ `NF_ENOTNC4`
+:   Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+    operations can only be performed on files defined with a create mode
+    which includes flag HDF5. (see [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_ESTRICTNC3`
+:   This file was created with the strict netcdf-3 flag, therefore
+    netcdf-4 operations are not allowed. (see
+    [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_groups.F.
+
+ 
+
+
+C     Check the full name.
+      retval = nf_inq_grpname_full(grpids(1), full_name_len, name_in2)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+3.8 Find a Group’s Parent: NF\_INQ\_GRP\_PARENT 
+-----------------------------------------------
+
+Given ncid, find the ncid of the parent group.
+
+When used with the root group, this function returns the NF\_ENOGRP
+error (since the root group has no parent.)
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_GRP_PARENT(INTEGER NCID, INTEGER PARENT_NCID)
+
+
+ `NCID`
+:   The group id.
+
+ `PARENT_NCID`
+:   The ncid of the parent group will be copied here.
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADID`
+:   Bad group id.
+
+ `NF_ENOGRP`
+:   No parent group found (i.e. this is the root group).
+
+ `NF_ENOTNC4`
+:   Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+    operations can only be performed on files defined with a create mode
+    which includes flag HDF5. (see [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_ESTRICTNC3`
+:   This file was created with the strict netcdf-3 flag, therefore
+    netcdf-4 operations are not allowed. (see
+    [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_groups.F.
+
+ 
+
+
+C     Check the parent ncid.
+      retval = nf_inq_grp_parent(grpids(1), grpid_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+3.9 Find a Group by Name: NF\_INQ\_GRP\_NCID 
+--------------------------------------------
+
+Given a group name an an ncid, find the ncid of the group id.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_GRP_NCID(INTEGER NCID, CHARACTER GRP_NAME, INTEGER GRP_NCID)
+
+
+ `NCID`
+:   The group id to look in.
+
+ `GRP_NAME`
+:   The name of the group that should be found.
+
+ `GRP_NCID`
+:   This will get the group id, if it is found.
+
+Return Codes 
+------------
+
+The following return codes may be returned by this function.
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADID`
+:   Bad group id.
+
+ `NF_EINVAL`
+:   No name provided or name longer than NF\_MAX\_NAME.
+
+ `NF_ENOGRP`
+:   Named group not found.
+
+ `NF_ENOTNC4`
+:   Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+    operations can only be performed on files defined with a create mode
+    which includes flag HDF5. (see [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_ESTRICTNC3`
+:   This file was created with the strict netcdf-3 flag, therefore
+    netcdf-4 operations are not allowed. (see
+    [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_types3.F.
+
+ 
+
+
+C     Go to a child group and find the id of our type.
+      retval = nf_inq_grp_ncid(ncid, group_name,b_grpid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+3.10 Find a Group by its Fully-qualified Name: NF\_INQ\_GRP\_FULL\_NCID 
+-----------------------------------------------------------------------
+
+Given a fully qualified group name an an ncid, find the ncid of the
+group id.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_GRP_FULL_NCID(INTEGER NCID, CHARACTER FULL_NAME, INTEGER GRP_NCID)
+
+
+ `NCID`
+:   The group id to look in.
+
+ `FULL_NAME`
+:   The fully-qualified group name.
+
+ `GRP_NCID`
+:   This will get the group id, if it is found.
+
+Return Codes 
+------------
+
+The following return codes may be returned by this function.
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADID`
+:   Bad group id.
+
+ `NF_EINVAL`
+:   No name provided or name longer than NF\_MAX\_NAME.
+
+ `NF_ENOGRP`
+:   Named group not found.
+
+ `NF_ENOTNC4`
+:   Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+    operations can only be performed on files defined with a create mode
+    which includes flag HDF5. (see [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_ESTRICTNC3`
+:   This file was created with the strict netcdf-3 flag, therefore
+    netcdf-4 operations are not allowed. (see
+    [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_groups.F.
+
+ 
+
+
+C     Check the full name of the root group (also "/").
+      retval = nf_inq_grpname_full(ncid, full_name_len, name_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+3.11 Create a New Group: NF\_DEF\_GRP 
+-------------------------------------
+
+Create a group. Its location id is returned in new\_ncid.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_DEF_GRP(INTEGER PARENT_NCID, CHARACTER*(*) NAME,
+        INTEGER NEW_NCID)
+
+
+ `PARENT_NCID`
+:   The group id of the parent group.
+
+ `NAME`
+:   The name of the new group, which must be different from the name of
+    any variable within the same parent group.
+
+ `NEW_NCID`
+:   The ncid of the new group will be placed there.
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADID`
+:   Bad group id.
+
+ `NF_ENAMEINUSE`
+:   That name is in use. Group names must be unique within a group.
+
+ `NF_EMAXNAME`
+:   Name exceed max length NF\_MAX\_NAME.
+
+ `NF_EBADNAME`
+:   Name contains illegal characters.
+
+ `NF_ENOTNC4`
+:   Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+    operations can only be performed on files defined with a create mode
+    which includes flag HDF5. (see [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_ESTRICTNC3`
+:   This file was created with the strict netcdf-3 flag, therefore
+    netcdf-4 operations are not allowed. (see
+    [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+ `NF_EPERM`
+:   Attempt to write to a read-only file.
+
+ `NF_ENOTINDEFINE`
+:   Not in define mode.
+
+Example 
+-------
+
+In this exampe rom nf\_test/ftst\_groups.F, a groups is reated, and then
+ab-group is created in that group.
+
+ 
+
+
+C     Create the netCDF file.
+      retval = nf_create(file_name, NF_NETCDF4, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Create a group and abgroup.
+      retval = nf_def_grp(ncid, group_name, grpid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_def_grp(grpid,b_group_name,b_grpid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+4. Dimensions 
+=============
+
+4.1 Dimensions Introduction 
+---------------------------
+
+Dimensions for a netCDF dataset are defined when it is created, while
+the netCDF dataset is in define mode. Additional dimensions may be added
+later by reentering define mode. A netCDF dimension has a name and a
+length. At most one dimension in a netCDF dataset can have the unlimited
+length, which means variables using this dimension can grow along this
+dimension.
+
+There is aggested limit (100) to the number of dimensions that can be
+defined in a single netCDF dataset. The limit is the value of the
+predefined macro NF\_MAX\_DIMS. The purpose of the limit is to make
+writing generic applications simpler. They need only provide an array of
+NF\_MAX\_DIMS dimensions to handle any netCDF dataset. The
+implementation of the netCDF library does not enforce this advisory
+maximum, so it is possible to use more dimensions, if necessary, but
+netCDF utilities that ame the advisory maximums may not be able to
+handle the rlting netCDF datasets.
+
+Ordinarily, the name and length of a dimension are fixed when the
+dimension is first defined. The name may be changed later, but the
+length of a dimension (other than the unlimited dimension) cannot be
+changed without copying all the data to a new netCDF dataset with a
+redefined dimension length.
+
+A netCDF dimension in an open netCDF dataset is referred to by a small
+integer called a dimension ID. In the FORTRAN interface, dimension IDs
+are 1, 2, 3, ..., in the order in which the dimensions were defined.
+
+Operationspported on dimensions are:
+
+-   Create a dimension, given its name and length.
+-   Get a dimension ID from its name.
+-   Get a dimension’s name and length from its ID.
+-   Rename a dimension.
+
+4.2 NF\_DEF\_DIM 
+----------------
+
+The function NF\_DEF\_DIM adds a new dimension to an open netCDF dataset
+in define mode. It returns (as an argument) a dimension ID, given the
+netCDF ID, the dimension name, and the dimension length. At most one
+unlimited length dimension, called the record dimension, may be defined
+for each netCDF dataset.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_DEF_DIM (INTEGER NCID, CHARACTER*(*) NAME,
+                          INTEGER LEN, INTEGER dimid)
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `NAME`
+:   Dimension name.
+
+ `LEN`
+:   Length of dimension; that is, number of values for this dimension as
+    an index to variables that use it. This should be either a positive
+    integer or the predefined constant NF\_UNLIMITED.
+
+ `dimid`
+:   Returned dimension ID.
+
+Errors 
+------
+
+NF\_DEF\_DIM returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The netCDF dataset is not in definition mode.
+-   The specified dimension name is the name of another existing
+    dimension.
+-   The specified length is not greater than zero.
+-   The specified length is unlimited, but there is already an unlimited
+    length dimension defined for this netCDF dataset.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+Here is an example using NF\_DEF\_DIM to create a dimension named lat of
+length 18 and a unlimited dimension named rec in a new netCDF dataset
+named foo.nc:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS, NCID, LATID, RECID
+   ... 
+STATUS = NF_CREATE('foo.nc', NF_NOCLOBBER, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_DEF_DIM(NCID, 'lat', 18, LATID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_DEF_DIM(NCID, 'rec', NF_UNLIMITED, RECID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+4.3 NF\_INQ\_DIMID 
+------------------
+
+The function NF\_INQ\_DIMID returns (as an argument) the ID of a netCDF
+dimension, given the name of the dimension. If ndims is the number of
+dimensions defined for a netCDF dataset, each dimension has an ID
+between 1 and ndims.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_DIMID (INTEGER NCID, CHARACTER*(*) NAME,
+                               INTEGER dimid)
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `NAME`
+:   Dimension name.
+
+ `dimid`
+:   Returned dimension ID.
+
+Errors 
+------
+
+NF\_INQ\_DIMID returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The name that was specified is not the name of a dimension in the
+    netCDF dataset.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+Here is an example using NF\_INQ\_DIMID to determine the dimension ID of
+a dimension named lat, amed to have been defined previously in an
+existing netCDF dataset named foo.nc:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS, NCID, LATID
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_DIMID(NCID, 'lat', LATID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+4.4 NF\_INQ\_DIM Family 
+-----------------------
+
+This family of functions returns information about a netCDF dimension.
+Information about a dimension includes its name and its length. The
+length for the unlimited dimension, if any, is the number of records
+written so far.
+
+The functions in this family include NF\_INQ\_DIM, NF\_INQ\_DIMNAME, and
+NF\_INQ\_DIMLEN. The function NF\_INQ\_DIM returns all the information
+about a dimension; the other functions each return just one item of
+information.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_DIM     (INTEGER NCID, INTEGER DIMID,
+                                 CHARACTER*(*) name, INTEGER len)
+INTEGER FUNCTION NF_INQ_DIMNAME (INTEGER NCID, INTEGER DIMID,
+                                 CHARACTER*(*) name)
+INTEGER FUNCTION NF_INQ_DIMLEN  (INTEGER NCID, INTEGER DIMID,
+                                 INTEGER len)
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `DIMID`
+:   Dimension ID, from a previous call to NF\_INQ\_DIMID or
+    NF\_DEF\_DIM.
+
+ `NAME`
+:   Returned dimension name. The caller must allocate space for the
+    returned name. The maximum possible length, in characters, of a
+    dimension name is given by the predefined constant NF\_MAX\_NAME.
+
+ `len`
+:   Returned length of dimension. For the unlimited dimension, this is
+    the current maximum value used for writing any variables with this
+    dimension, that is the maximum record number.
+
+Errors 
+------
+
+These functions return the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The dimension ID is invalid for the specified netCDF dataset.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+Here is an example using NF\_INQ\_DIM to determine the length of a
+dimension named lat, and the name and current maximum length of the
+unlimited dimension for an existing netCDF dataset named foo.nc:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS, NCID, LATID, LATLEN, RECID, NRECS
+CHARACTER*(NF_MAX_NAME) LATNAM, RECNAM
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+! get ID of unlimited dimension
+STATUS = NF_INQ_UNLIMDIM(NCID, RECID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_DIMID(NCID, 'lat', LATID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+! get lat length
+STATUS = NF_INQ_DIMLEN(NCID, LATID, LATLEN)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+! get unlimited dimension name and current length
+STATUS = NF_INQ_DIM(NCID, RECID, RECNAME, NRECS)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+4.5 NF\_RENAME\_DIM 
+-------------------
+
+The function NF\_RENAME\_DIM renames an existing dimension in a netCDF
+dataset open for writing. If the new name is longer than the old name,
+the netCDF dataset must be in define mode. You cannot rename a dimension
+to have the same name as another dimension.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_RENAME_DIM (INTEGER NCID, INTEGER DIMID,
+                                CHARACTER*(*) NAME)
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `DIMID`
+:   Dimension ID, from a previous call to NF\_INQ\_DIMID or
+    NF\_DEF\_DIM.
+
+ `NAME`
+:   New dimension name.
+
+Errors 
+------
+
+NF\_RENAME\_DIM returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The new name is the name of another dimension.
+-   The dimension ID is invalid for the specified netCDF dataset.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+-   The new name is longer than the old name and the netCDF dataset is
+    not in define mode.
+
+Example 
+-------
+
+Here is an example using NF\_RENAME\_DIM to rename the dimension lat to
+latitude in an existing netCDF dataset named foo.nc:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS, NCID, LATID
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+! put in define mode to rename dimension
+STATUS = NF_REDEF(NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_INQ_DIMID(NCID, 'lat', LATID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_RENAME_DIM(NCID, LATID, 'latitude')
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+! leave define mode
+STATUS = NF_ENDDEF(NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+5. User Defined Data Types 
+==========================
+
+5.1 User Defined Types Introduction 
+-----------------------------------
+
+NetCDF-4 has addedpport for four different user defined data types.
+
+ `compound type`
+:   Like a C struct, a compound type is a collection of types, including
+    other user defined types, in one package.
+
+ `variable length array type`
+:   The variable length array may be used to store ragged arrays.
+
+ `opaque type`
+:   This type has only a size per element, and no other type
+    information.
+
+ `enum type`
+:   Like an enumeration in C, this type lets you assign text values to
+    integer values, and store the integer values.
+
+Users may construct user defined type with the various NF\_DEF\_\*
+functions described in this. They may learn about user defined
+types by using the NF\_INQ\_ functions defined in this.
+
+Once types are constructed, define variables of the new type with
+NF\_DEF\_VAR (see [Create a Variable:
+`NF_DEF_VAR`](#NF_005fDEF_005fVAR)). Write to them with NF\_PUT\_VAR1,
+NF\_PUT\_VAR, NF\_PUT\_VARA, or NF\_PUT\_VARS (see
+[Variables](#Variables)). Read data of user-defined type with
+NF\_GET\_VAR1, NF\_GET\_VAR, NF\_GET\_VARA, or NF\_GET\_VARS (see
+section [Variables](#Variables)).
+
+Create attributes of the new type with NF\_PUT\_ATT (see
+[NF\_PUT\_ATT\_ type](#NF_005fPUT_005fATT_005f-type)). Read attributes
+of the new type with NF\_GET\_ATT (see [NF\_GET\_ATT\_
+type](#NF_005fGET_005fATT_005f-type)).
+
+5.2 Learn the IDs of All Types in Group: NF\_INQ\_TYPEIDS 
+---------------------------------------------------------
+
+Learn the number of types defined in a group, and their IDs.
+
+Usage 
+-----
+
+
+
+INTEGER FUNCTION NF_INQ_TYPEIDS(INTEGER NCID, INTEGER NTYPES, 
+        INTEGER TYPEIDS)
+
+
+ `NCID`
+:   The group id.
+
+ `NTYPES`
+:   A pointer to int which will get the number of types defined in the
+    group. If NULL, ignored.
+
+ `TYPEIDS`
+:   A pointer to an int array which will get the typeids. If NULL,
+    ignored.
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_BADID`
+:   Bad ncid.
+
+Example 
+-------
+
+The following example is from the test program nf\_test/ftst\_vars3.F.
+
+ 
+
+
+      retval = nf_inq_typeids(ncid, num_types, typeids)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+
+5.3 Find a Typeid from Group and Name: NF\_INQ\_TYPEID 
+------------------------------------------------------
+
+Given a group ID and a type name, find the ID of the type. If the type
+is not found in the group, then the parents are searched. If still not
+found, the entire file is searched.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_TYPEID(INTEGER NCID, CHARACTER NAME, NF_TYPE TYPEIDP)
+
+
+ `NCID`
+:   The group id.
+
+ `NAME`
+:   The name of a type.
+
+ `TYPEIDP`
+:   The typeid of the named type (if found).
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADID`
+:   Bad ncid.
+
+ `NF_EBADTYPE`
+:   Can’t find type.
+
+Example 
+-------
+
+The following example is from nf\_test/ftst\_types3.F:
+
+ 
+
+
+C     Go to a child group and find the id of our type.
+      retval = nf_inq_grp_ncid(ncid, group_name,b_grpid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_inq_typeidb_grpid, type_name, typeid_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+5.4 Learn About a User Defined Type: NF\_INQ\_TYPE 
+--------------------------------------------------
+
+Given an ncid and a typeid, get the information about a type. This
+function will work on any type, including atomic and any user defined
+type, whether compound, opaque, enumeration, or variable length array.
+
+For even more information about a user defined type [Learn About a User
+Defined Type: NF\_INQ\_USER\_TYPE](#NF_005fINQ_005fUSER_005fTYPE).
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_TYPE(INTEGER NCID, INTEGER XTYPE, 
+        CHARACTER*(*) NAME, INTEGER SIZE)
+
+
+ `NCID`
+:   The ncid for the group containing the type (ignored for atomic
+    types).
+
+ `XTYPE`
+:   The typeid for this type, as returned by NF\_DEF\_COMPOUND,
+    NF\_DEF\_OPAQUE, NF\_DEF\_ENUM, NF\_DEF\_VLEN, or NF\_INQ\_VAR, or
+    as found in netcdf.inc in the list of atomic types (NF\_CHAR,
+    NF\_INT, etc.).
+
+ `NAME`
+:   The name of the user defined type will be copied here. It will be
+    NF\_MAX\_NAME bytes or less. For atomic types, the type name from
+    CDL will be given.
+
+ `SIZEP`
+:   The (in-memory) size of the type (in bytes) will be copied here.
+    VLEN type size is the size of one vlen sturture (i.e. the sice of
+    nc\_vlen\_t). String size is returned as the size of one C character
+    pointer.
+
+Return Codes 
+------------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADTYPEID`
+:   Bad typeid.
+
+ `NF_ENOTNC4`
+:   Seeking a user-defined type in a netCDF-3 file.
+
+ `NF_ESTRICTNC3`
+:   Seeking a user-defined type in a netCDF-4 file for which classic
+    model has been turned on.
+
+ `NF_EBADGRPID`
+:   Bad group ID in ncid.
+
+ `NF_EBADID`
+:   Type ID not found.
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+Example 
+-------
+
+This example is from the test program nf\_test/ftst\_vars3.F, and it
+uses all the possible inquiry functions on an enum type.
+
+ 
+
+
+C     Check the enum type.
+      retval = NF_INQ_TYPEIDS(ncid, num_types, typeids)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (num_types .ne. MAX_TYPES) stop 2
+      retval = nf_inq_enum(ncid, typeids(1), type_name, base_type, 
+     &     base_size, num_members)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (base_type .ne. NF_INT .or. num_members .ne. 2) stop 2
+      retval = nf_inq_enum_member(ncid, typeids(1), 1, member_name, 
+     &     member_value)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (member_name(1:len(one_name)) .ne. one_name) stop 2
+
+
+5.5 Learn About a User Defined Type: NF\_INQ\_USER\_TYPE 
+--------------------------------------------------------
+
+Given an ncid and a typeid, get the information about a user defined
+type. This function will work on any user defined type, whether
+compound, opaque, enumeration, or variable length array.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_USER_TYPE(INTEGER NCID, INTEGER XTYPE,
+        CHARACTER*(*) NAME, INTEGER SIZE, INTEGER BASE_NF_TYPE, 
+        INTEGER NFIELDS, INTEGER CLASS)
+
+
+ `NCID`
+:   The ncid for the group containing the user defined type.
+
+ `XTYPE`
+:   The typeid for this type, as returned by NF\_DEF\_COMPOUND,
+    NF\_DEF\_OPAQUE, NF\_DEF\_ENUM, NF\_DEF\_VLEN, or NF\_INQ\_VAR.
+
+ `NAME`
+:   The name of the user defined type will be copied here. It will be
+    NF\_MAX\_NAME bytes or less.
+
+ `SIZE`
+:   The (in-memory) size of the user defined type will be copied here.
+
+ `BASE_NF_TYPE`
+:   The base typeid will be copied here for vlen and enum types.
+
+ `NFIELDS`
+:   The number of fields will be copied here for enum and compound
+    types.
+
+ `CLASS`
+:   The class of the user defined type, NF\_VLEN, NF\_OPAQUE, NF\_ENUM,
+    or NF\_COMPOUND, will be copied here.
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADTYPEID`
+:   Bad typeid.
+
+ `NF_EBADFIELDID`
+:   Bad fieldid.
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_types2.F.
+
+ 
+
+
+C     Check the type.
+      retval = nf_inq_user_type(ncid, typeids(1), name_in, size_in, 
+     &     base_type_in, nfields_in, class_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+5.6 Compound Types Introduction 
+-------------------------------
+
+NetCDF-4 addedpport for compound types, which allow users to
+construct a new type - a combination of other types, like a C struct.
+
+Compound types are notpported in classic or 64-bit offset format
+files.
+
+To write data in a compound type, first use nf\_def\_compound to create
+the type, multiple calls to nf\_insert\_compound to add to the compound
+type, and then write data with the appropriate nf\_put\_var1,
+nf\_put\_vara, nf\_put\_vars, or nf\_put\_varm call.
+
+To read data written in a compound type, you must know its structure.
+Use the NF\_INQ\_COMPOUND functions to learn about the compound type.
+
+In Fortran a character buffer must be used for the compound data. The
+user must read the data from within that buffer in the same way that the
+C compiler which compiled netCDF would store the structure.
+
+The use of compound types introduces challenges and portability ies
+for Fortran users.
+
+### 5.6.1 Creating a Compound Type: NF\_DEF\_COMPOUND 
+
+Create a compound type. Provide an ncid, a name, and a total size (in
+bytes) of one element of the completed compound type.
+
+After calling this function, fill out the type with repeated calls to
+NF\_INSERT\_COMPOUND (see [Inserting a Field into a Compound
+Type: NF\_INSERT\_COMPOUND](#NF_005fINSERT_005fCOMPOUND)). Call
+NF\_INSERT\_COMPOUND once for each field you wish to insert into the
+compound type.
+
+Note that there does not seem to be a way to readch types into
+structures in Fortran 90 (and there are no structures in Fortran 77).
+
+Fortran users may use character buffers to read and write compound
+types.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_DEF_COMPOUND(INTEGER NCID, INTEGER SIZE,
+        CHARACTER*(*) NAME, INTEGER TYPEIDP)
+
+
+ `NCID`
+:   The groupid where this compound type will be created.
+
+ `SIZE`
+:   The size, in bytes, of the compound type.
+
+ `NAME`
+:   The name of the new compound type.
+
+ `TYPEIDP`
+:   The typeid of the new type will be placed here.
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADID`
+:   Bad group id.
+
+ `NF_ENAMEINUSE`
+:   That name is in use. Compound type names must be unique in the data
+    file.
+
+ `NF_EMAXNAME`
+:   Name exceeds max length NF\_MAX\_NAME.
+
+ `NF_EBADNAME`
+:   Name contains illegal characters.
+
+ `NF_ENOTNC4`
+:   Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+    operations can only be performed on files defined with a create mode
+    which includes flag NF\_NETCDF4. (see
+    [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_ESTRICTNC3`
+:   This file was created with the strict netcdf-3 flag, therefore
+    netcdf-4 operations are not allowed. (see
+    [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+ `NF_EPERM`
+:   Attempt to write to a read-only file.
+
+ `NF_ENOTINDEFINE`
+:   Not in define mode.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_types2.F.
+
+ 
+
+
+C     Define a compound type.
+      retval = nf_def_compound(ncid, cmp_size, type_name, 
+     &     cmp_typeid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+### 5.6.2 Inserting a Field into a Compound Type: NF\_INSERT\_COMPOUND 
+
+Insert a named field into a compound type.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNTION NF_INSERT_COMPOUND(INTEGER TYPEID, CHARACTER*(*) NAME, INTEGER OFFSET, 
+        INTEGER FIELD_TYPEID)
+
+
+ `TYPEID`
+:   The typeid for this compound type, as returned by NF\_DEF\_COMPOUND,
+    or NF\_INQ\_VAR.
+
+ `NAME`
+:   The name of the new field.
+
+ `OFFSET`
+:   Offset in byte from the beginning of the compound type for this
+    field.
+
+ `FIELD_TYPEID`
+:   The type of the field to be inserted.
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADID`
+:   Bad group id.
+
+ `NF_ENAMEINUSE`
+:   That name is in use. Field names must be unique within a compound
+    type.
+
+ `NF_EMAXNAME`
+:   Name exceed max length NF\_MAX\_NAME.
+
+ `NF_EBADNAME`
+:   Name contains illegal characters.
+
+ `NF_ENOTNC4`
+:   Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+    operations can only be performed on files defined with a create mode
+    which includes flag NF\_NETCDF4. (see
+    [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_ESTRICTNC3`
+:   This file was created with the strict netcdf-3 flag, therefore
+    netcdf-4 operations are not allowed. (see
+    [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+ `NF_ENOTINDEFINE`
+:   Not in define mode.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_types.F.
+
+ 
+
+
+C     Define a compound type.
+      retval = nf_def_compound(ncid, WIND_T_SIZE, type_name, 
+     &     wind_typeid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_insert_compound(ncid, wind_typeid, u_name, 0, NF_INT)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_insert_compound(ncid, wind_typeid, v_name, 4, NF_INT)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+
+### 5.6.3 Inserting an Array Field into a Compound Type: NF\_INSERT\_ARRAY\_COMPOUND 
+
+Insert a named array field into a compound type.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INSERT_ARRAY_COMPOUND(INTEGER NCID, INTEGER XTYPE,
+        CHARACTER*(*) NAME, INTEGER OFFSET, INTEGER FIELD_TYPEID,
+        INTEGER NDIMS, INTEGER DIM_SIZES) 
+
+
+ `NCID`
+:   The ID of the file that contains the array type and the compound
+    type.
+
+ `XTYPE`
+:   The typeid for this compound type, as returned by nf\_def\_compound,
+    or nf\_inq\_var.
+
+ `NAME`
+:   The name of the new field.
+
+ `OFFSET`
+:   Offset in byte from the beginning of the compound type for this
+    field.
+
+ `FIELD_TYPEID`
+:   The base type of the array to be inserted.
+
+ `NDIMS`
+:   The number of dimensions for the array to be inserted.
+
+ `DIM_SIZES`
+:   An array containing the sizes of each dimension.
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADID`
+:   Bad group id.
+
+ `NF_ENAMEINUSE`
+:   That name is in use. Field names must be unique within a compound
+    type.
+
+ `NF_EMAXNAME`
+:   Name exceed max length NF\_MAX\_NAME.
+
+ `NF_EBADNAME`
+:   Name contains illegal characters.
+
+ `NF_ENOTNC4`
+:   Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+    operations can only be performed on files defined with a create mode
+    which includes flag NF\_NETCDF4. (see
+    [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_ESTRICTNC3`
+:   This file was created with the strict netcdf-3 flag, therefore
+    netcdf-4 operations are not allowed. (see
+    [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+ `NF_ENOTINDEFINE`
+:   Not in define mode.
+
+ `NF_ETYPEDEFINED`
+:   Attempt to change type that has already been committed. The first
+    time the file leaves define mode, all defined types are committed,
+    and can’t be changed. If you wish to add an array to a compound
+    type, you must do so before the compound type is committed.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_types2.F.
+
+ 
+
+
+C     Define a compound type.
+      retval = nf_def_compound(ncid, cmp_size, type_name, 
+     &     cmp_typeid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Include an array.
+      dim_sizes(1) = NX
+      dim_sizes(2) = NY
+      retval = nf_insert_array_compound(ncid, cmp_typeid, ary_name, 0, 
+     &     NF_INT, NDIMS, dim_sizes)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+### 5.6.4 Learn About a Compound Type: NF\_INQ\_COMPOUND 
+
+Get the number of fields, length in bytes, and name of a compound type.
+
+In addtion to the NF\_INQ\_COMPOUND function, three additional functions
+are provided which get only the name, size, and number of fields.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_COMPOUND(INTEGER NCID, INTEGER XTYPE,
+        CHARACTER*(*) NAME, INTEGER SIZEP, INTEGER NFIELDSP)
+
+INTEGER FUNCTION NF_INQ_COMPOUND_NAME(INTEGER NCID, INTEGER XTYPE, 
+        CHARACTER*(*) NAME)
+
+INTEGER FUNCTION NF_INQ_COMPOUND_SIZE(INTEGER NCID, INTEGER XTYPE, 
+        INTEGER SIZEP)
+
+INTEGER FUNCTION NF_INQ_COMPOUND_NFIELDS(INTEGER NCID, INTEGER XTYPE, 
+        INTEGER NFIELDSP)
+
+
+ `NCID`
+:   The ID of any group in the file that contains the compound type.
+
+ `XTYPE`
+:   The typeid for this compound type, as returned by NF\_DEF\_COMPOUND,
+    or NF\_INQ\_VAR.
+
+ `NAME`
+:   Character array which will get the name of the compound type. It
+    will have a maximum length of NF\_MAX\_NAME.
+
+ `SIZEP`
+:   The size of the compound type in bytes will be put here.
+
+ `NFIELDSP`
+:   The number of fields in the compound type will be placed here.
+
+Return Codes 
+------------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADID`
+:   Couldn’t find this ncid.
+
+ `NF_ENOTNC4`
+:   Not a netCDF-4/HDF5 file.
+
+ `NF_ESTRICTNC3`
+:   A netCDF-4/HDF5 file, but with CLASSIC\_MODEL. No user defined types
+    are allowed in the classic model.
+
+ `NF_EBADTYPE`
+:   This type not a compound type.
+
+ `NF_EBADTYPEID`
+:   Bad type id.
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_types.F.
+
+ 
+
+
+C     Check it differently.
+      retval = nf_inq_compound(ncid, typeids(1), name_in, size_in, 
+     &     nfields_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:len(type_name)) .ne. type_name .or. 
+     &     size_in .ne. WIND_T_SIZE .or. nfields_in .ne. 2) stop 2
+
+C     Check it one piece at a time.
+      retval = nf_inq_compound_nfields(ncid, typeids(1), nfields_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (nfields_in .ne. 2) stop 2
+      retval = nf_inq_compound_size(ncid, typeids(1), size_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (size_in .ne. WIND_T_SIZE) stop 2
+      retval = nf_inq_compound_name(ncid, typeids(1), name_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:len(type_name)) .ne. type_name) stop 2
+
+
+### 5.6.5 Learn About a Field of a Compound Type: NF\_INQ\_COMPOUND\_FIELD 
+
+Get information about one of the fields of a compound type.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_COMPOUND_FIELD(INTEGER NCID, INTEGER XTYPE,
+        INTEGER FIELDID, CHARACTER*(*) NAME, INTEGER OFFSETP, 
+        INTEGER FIELD_TYPEIDP, INTEGER NDIMSP, INTEGER DIM_SIZESP)
+
+INTEGER FUNCTION NF_INQ_COMPOUND_FIELDNAME(INTEGER TYPEID, 
+        INTEGER FIELDID, CHARACTER*(*) NAME)
+
+INTEGER FUNCTION NF_INQ_COMPOUND_FIELDINDEX(INTEGER TYPEID,    
+        CHARACTER*(*) NAME, INTEGER FIELDIDP)
+
+INTEGER FUNCTION NF_INQ_COMPOUND_FIELDOFFSET(INTEGER TYPEID, 
+        INTEGER FIELDID, INTEGER OFFSETP)
+
+INTEGER FUNCTION NF_INQ_COMPOUND_FIELDTYPE(INTEGER TYPEID, 
+        INTEGER FIELDID, INTEGER FIELD_TYPEIDP)
+
+INTEGER FUNCTION NF_INQ_COMPOUND_FIELDNDIMS(INTEGER NCID, 
+        INTEGER XTYPE, INTEGER FIELDID, INTEGER NDIMSP)
+
+INTEGER FUNCTION NF_INQ_COMPOUND_FIELDDIM_SIZES(INTEGER NCID, 
+        INTEGER XTYPE, INTEGER FIELDID, INTEGER DIM_SIZES)
+
+
+ `NCID`
+:   The groupid where this compound type exists.
+
+ `XTYPE`
+:   The typeid for this compound type, as returned by NF\_DEF\_COMPOUND,
+    or NF\_INQ\_VAR.
+
+ `FIELDID`
+:   A one-based index number specifying a field in the compound type.
+
+ `NAME`
+:   A character array which will get the name of the field. The name
+    will be NF\_MAX\_NAME characters, at most.
+
+ `OFFSETP`
+:   An integer which will get the offset of the field.
+
+ `FIELD_TYPEID`
+:   An integer which will get the typeid of the field.
+
+ `NDIMSP`
+:   An integer which will get the number of dimensions of the field.
+
+ `DIM_SIZESP`
+:   An integer array which will get the dimension sizes of the field.
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADTYPEID`
+:   Bad type id.
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+Example 
+-------
+
+This example is from nf\_test/fst\_types.F.
+
+ 
+
+
+C     Check the first field of the compound type.
+      retval = nf_inq_compound_field(ncid, typeids(1), 1, name_in, 
+     &     offset_in, field_typeid_in, ndims_in, dim_sizes_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:len(u_name)) .ne. u_name .or. offset_in .ne. 0 .or.
+     &     field_typeid_in .ne. NF_INT .or. ndims_in .ne. 0) stop 2
+      retval = nf_inq_compound_fieldname(ncid, typeids(1), 1, name_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:len(u_name)) .ne. u_name) stop 2
+      retval = nf_inq_compound_fieldoffset(ncid, typeids(1), 1, 
+     &     offset_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (offset_in .ne. 0) stop 2
+      retval = nf_inq_compound_fieldtype(ncid, typeids(1), 1, 
+     &     field_typeid_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (field_typeid_in .ne. NF_INT) stop 2
+      retval = nf_inq_compound_fieldndims(ncid, typeids(1), 1, 
+     &     ndims_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (ndims_in .ne. 0) stop 2
+
+
+5.7 Variable Length Array Introduction 
+--------------------------------------
+
+NetCDF-4 addedpport for a variable length array type. This is not
+supported in classic or 64-bit offset files, or in netCDF-4 files which
+were created with the NF\_CLASSIC\_MODEL flag.
+
+A variable length array is represented in C as a structure from HDF5,
+the nf\_vlen\_t structure. It contains a len member, which contains the
+length of that array, and a pointer to the array.
+
+So an array of VLEN in C is an array of nc\_vlen\_t structures. The only
+way to handle this in Fortran is with a character buffer sized correctly
+for the platform.
+
+The extra access functions NF\_GET\_VLEN\_ELEMENT and
+NF\_PUT\_VLEN\_ELEMENT to get and put one VLEN element. (That is, one
+array of variable length.) When calling the put, the data are not copied
+from the source. When calling the get the data are copied from VLEN
+allocated memory, which must still be freed (see below).
+
+VLEN arrays are handled differently with respect to allocation of
+memory. Generally, when reading data, it is up to the user to malloc
+(andbsequently free) the memory needed to hold the data. It is up to
+the user to ere that enough memory is allocated.
+
+With VLENs, this is impossible. The user cannot know the size of an
+array of VLEN until after reading the array. Therefore when reading VLEN
+arrays, the netCDF library will allocate the memory for the data within
+each VLEN.
+
+It is up to the user, however, to eventually free this memory. This is
+not just a matter of one call to free, with the pointer to the array of
+VLENs; each VLEN contains a pointer which must be freed.
+
+Compression is permitted but may not be effective for VLEN data, because
+the compression is applied to the nc\_vlen\_t structures, rather than
+the actual data.
+
+### 5.7.1 Define a Variable Length Array (VLEN): NF\_DEF\_VLEN 
+
+Use this function to define a variable length array type.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_DEF_VLEN(INTEGER NCID, CHARACTER*(*) NAME, 
+        INTEGER BASE_TYPEID, INTEGER XTYPEP)
+
+
+ `NCID`
+:   The ncid of the file to create the VLEN type in.
+
+ `NAME` 
+:   A name for the VLEN type.
+
+ `BASE_TYPEID`
+:   The typeid of the base type of the VLEN. For example, for a VLEN of
+    shorts, the base type is NF\_SHORT. This can be a user defined type.
+
+ `XTYPEP`
+:   The typeid of the new VLEN type will be set here.
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EMAXNAME`
+:   NF\_MAX\_NAME exceeded.
+
+ `NF_ENAMEINUSE`
+:   Name is already in use.
+
+ `NF_EBADNAME`
+:   Attribute or variable name contains illegal characters.
+
+ `NF_EBADID`
+:   ncid invalid.
+
+ `NF_EBADGRPID`
+:   Group ID part of ncid was invalid.
+
+ `NF_EINVAL`
+:   Size is invalid.
+
+ `NF_ENOMEM`
+:   Out of memory.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_vars4.F.
+
+ 
+
+
+C     Create the vlen type.
+      retval = nf_def_vlen(ncid, vlen_type_name, nf_int, vlen_typeid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+### 5.7.2 Learning about a Variable Length Array (VLEN) Type: NF\_INQ\_VLEN 
+
+Use this type to learn about a vlen.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_VLEN(INTEGER NCID, INTEGER XTYPE,
+        CHARACTER*(*) NAME, INTEGER DATUM_SIZEP, INTEGER  
+        BASE_NF_TYPEP)
+
+
+ `NCID`
+:   The ncid of the file that contains the VLEN type.
+
+ `XTYPE`
+:   The type of the VLEN to inquire about.
+
+ `NAME`
+:   The name of the VLEN type. The name will be NF\_MAX\_NAME characters
+    or less.
+
+ `DATUM_SIZEP`
+:   A pointer to a size\_t, this will get the size of one element of
+    this vlen.
+
+ `BASE_NF_TYPEP`
+:   An integer that will get the type of the VLEN base type. (In other
+    words, what type is this a VLEN of?)
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADTYPE`
+:   Can’t find the typeid.
+
+ `NF_EBADID`
+:   ncid invalid.
+
+ `NF_EBADGRPID`
+:   Group ID part of ncid was invalid.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_vars4.F.
+
+ 
+
+
+C     Use nf_inq_vlen and makere we get the same answers as we did
+C     with nf_inq_user_type.
+      retval = nf_inq_vlen(ncid, typeids(1), type_name, base_size, 
+     &     base_type)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+### 5.7.3 Releasing Memory for a Variable Length Array (VLEN) Type: NF\_FREE\_VLEN 
+
+When a VLEN is read into user memory from the file, the HDF5 library
+performs memory allocations for each of the variable length arrays
+contained within the VLEN structure. This memory must be freed by the
+user to avoid memory leaks.
+
+This violates the normal netCDF expectation that the user is responsible
+for all memory allocation. But, with VLEN arrays, the underlying HDF5
+library allocates the memory for the user, and the user is responsible
+for deallocating that memory.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_FREE_VLEN(CHARACTER VL);
+
+
+ `VL`
+:   The variable length array structure which is to be freed.
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADTYPE`
+:   Can’t find the typeid.
+
+Example 
+-------
+
+### 5.7.4 Set a Variable Length Array with NF\_PUT\_VLEN\_ELEMENT 
+
+Use this to set the element of the (potentially) n-dimensional array of
+VLEN. That is, this sets the data in one variable length array.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_PUT_VLEN_ELEMENT(INTEGER NCID, INTEGER XTYPE,
+        CHARACTER*(*) VLEN_ELEMENT, INTEGER LEN, DATA)
+
+
+ `NCID`
+:   The ncid of the file that contains the VLEN type.
+
+ `XTYPE`
+:   The type of the VLEN.
+
+ `VLEN_ELEMENT`
+:   The VLEN element to be set.
+
+ `LEN`
+:   The number of entries in this array.
+
+ `DATA`
+:   The data to be stored. Must match the base type of this VLEN.
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADTYPE`
+:   Can’t find the typeid.
+
+ `NF_EBADID`
+:   ncid invalid.
+
+ `NF_EBADGRPID`
+:   Group ID part of ncid was invalid.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_vars4.F.
+
+ 
+
+
+C     Set up the vlen with this helper function, since F77 can't deal
+C     with pointers.
+      retval = nf_put_vlen_element(ncid, vlen_typeid, vlen, 
+     &     vlen_len, data1)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+### 5.7.5 Set a Variable Length Array with NF\_GET\_VLEN\_ELEMENT 
+
+Use this to set the element of the (potentially) n-dimensional array of
+VLEN. That is, this sets the data in one variable length array.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_GET_VLEN_ELEMENT(INTEGER NCID, INTEGER XTYPE,
+        CHARACTER*(*) VLEN_ELEMENT, INTEGER LEN, DATA)
+
+
+ `NCID`
+:   The ncid of the file that contains the VLEN type.
+
+ `XTYPE`
+:   The type of the VLEN.
+
+ `VLEN_ELEMENT`
+:   The VLEN element to be set.
+
+ `LEN`
+:   This will be set to the number of entries in this array.
+
+ `DATA`
+:   The data will be copied here. Sufficient storage must be available
+    or bad things will happen to you.
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADTYPE`
+:   Can’t find the typeid.
+
+ `NF_EBADID`
+:   ncid invalid.
+
+ `NF_EBADGRPID`
+:   Group ID part of ncid was invalid.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_vars4.F.
+
+ 
+
+
+C     Read the vlen attribute.
+      retval = nf_get_att(ncid, NF_GLOBAL, 'att1', vlen_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Get the data from the vlen we just read.
+      retval = nf_get_vlen_element(ncid, vlen_typeid, vlen_in, 
+     &     vlen_len_in, data1_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+5.8 Opaque Type Introduction 
+----------------------------
+
+NetCDF-4 addedpport for the opaque type. This is notpported in
+classic or 64-bit offset files.
+
+The opaque type is a type which is a collection of objects of a known
+size. (And each object is the same size). Nothing is known to netCDF
+about the contents of these blobs of data, except their size in bytes,
+and the name of the type.
+
+To use an opaque type, first define it with [Creating Opaque Types:
+NF\_DEF\_OPAQUE](#NF_005fDEF_005fOPAQUE). If encountering an enum type
+in a new data file, use [Learn About an Opaque Type:
+NF\_INQ\_OPAQUE](#NF_005fINQ_005fOPAQUE) to learn its name and size.
+
+### 5.8.1 Creating Opaque Types: NF\_DEF\_OPAQUE 
+
+Create an opaque type. Provide a size and a name.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_DEF_OPAQUE(INTEGER NCID, INTEGER SIZE, 
+        CHARACTER*(*) NAME, INTEGER TYPEIDP)
+
+
+ `NCID`
+:   The groupid where the type will be created. The type may be used
+    anywhere in the file, no matter what group it is in.
+
+ `SIZE`
+:   The size of each opaque object.
+
+ `NAME`
+:   The name for this type. Must be shorter than NF\_MAX\_NAME.
+
+ `TYPEIDP`
+:   Pointer where the new typeid for this type is returned. Use this
+    typeid when defining variables of this type with [Create a Variable:
+    `NF_DEF_VAR`](#NF_005fDEF_005fVAR).
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADTYPEID`
+:   Bad typeid.
+
+ `NF_EBADFIELDID`
+:   Bad fieldid.
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_vars3.F.
+
+ 
+
+
+C     Create the opaque type.
+      retval = nf_def_opaque(ncid, opaque_size, opaque_type_name, 
+     &     opaque_typeid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+### 5.8.2 Learn About an Opaque Type: NF\_INQ\_OPAQUE 
+
+Given a typeid, get the information about an opaque type.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_OPAQUE(INTEGER NCID, INTEGER XTYPE,
+        CHARACTER*(*) NAME, INTEGER SIZEP)
+
+
+ `NCID`
+:   The ncid for the group containing the opaque type.
+
+ `XTYPE`
+:   The typeid for this opaque type, as returned by NF\_DEF\_COMPOUND,
+    or NF\_INQ\_VAR.
+
+ `NAME`
+:   The name of the opaque type will be copied here. It will be
+    NF\_MAX\_NAME bytes or less.
+
+ `SIZEP`
+:   The size of the opaque type will be copied here.
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADTYPEID`
+:   Bad typeid.
+
+ `NF_EBADFIELDID`
+:   Bad fieldid.
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_vars3.F.
+
+ 
+
+
+C     Use nf_inq_opaque and makere we get the same answers as we did
+C     with nf_inq_user_type.
+      retval = nf_inq_opaque(ncid, typeids(2), type_name, base_size)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+5.9 Enum Type Introduction 
+--------------------------
+
+NetCDF-4 addedpport for the enum type. This is notpported in
+classic or 64-bit offset files.
+
+### 5.9.1 Creating a Enum Type: NF\_DEF\_ENUM 
+
+Create an enum type. Provide an ncid, a name, and a base integer type.
+
+After calling this function, fill out the type with repeated calls to
+NF\_INSERT\_ENUM (see [Inserting a Field into a Enum Type:
+NF\_INSERT\_ENUM](#NF_005fINSERT_005fENUM)). Call NF\_INSERT\_ENUM once
+for each value you wish to make part of the enumeration.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_DEF_ENUM(INTEGER NCID, INTEGER BASE_TYPEID, 
+        CHARACTER*(*) NAME, INTEGER TYPEIDP)
+
+
+ `NCID`
+:   The groupid where this compound type will be created.
+
+ `BASE_TYPEID`
+:   The base integer type for this enum. Must be one of: NF\_BYTE,
+    NF\_UBYTE, NF\_SHORT, NF\_USHORT, NF\_INT, NF\_UINT, NF\_INT64,
+    NF\_UINT64.
+
+ `NAME`
+:   The name of the new enum type.
+
+ `TYPEIDP`
+:   The typeid of the new type will be placed here.
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADID`
+:   Bad group id.
+
+ `NF_ENAMEINUSE`
+:   That name is in use. Compound type names must be unique in the data
+    file.
+
+ `NF_EMAXNAME`
+:   Name exceeds max length NF\_MAX\_NAME.
+
+ `NF_EBADNAME`
+:   Name contains illegal characters.
+
+ `NF_ENOTNC4`
+:   Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+    operations can only be performed on files defined with a create mode
+    which includes flag NF\_NETCDF4. (see
+    [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_ESTRICTNC3`
+:   This file was created with the strict netcdf-3 flag, therefore
+    netcdf-4 operations are not allowed. (see
+    [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+ `NF_EPERM`
+:   Attempt to write to a read-only file.
+
+ `NF_ENOTINDEFINE`
+:   Not in define mode.
+
+This example is from nf\_test/ftst\_vars3.F.
+
+ 
+
+
+C     Create the enum type.
+      retval = nf_def_enum(ncid, NF_INT, enum_type_name, enum_typeid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+### 5.9.2 Inserting a Field into a Enum Type: NF\_INSERT\_ENUM 
+
+Insert a named member into a enum type.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INSERT_ENUM(INTEGER NCID, INTEGER XTYPE, 
+        CHARACTER IDENTIFIER, INTEGER VALUE)
+
+
+ `NCID`
+:   The ncid of the group which contains the type.
+
+ `TYPEID`
+:   The typeid for this enum type, as returned by nf\_def\_enum, or
+    nf\_inq\_var.
+
+ `IDENTIFIER`
+:   The identifier of the new member.
+
+ `VALUE`
+:   The value that is to be associated with this member.
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADID`
+:   Bad group id.
+
+ `NF_ENAMEINUSE`
+:   That name is in use. Field names must be unique within a enum type.
+
+ `NF_EMAXNAME`
+:   Name exceed max length NF\_MAX\_NAME.
+
+ `NF_EBADNAME`
+:   Name contains illegal characters.
+
+ `NF_ENOTNC4`
+:   Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+    operations can only be performed on files defined with a create mode
+    which includes flag NF\_NETCDF4. (see
+    [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_ESTRICTNC3`
+:   This file was created with the strict netcdf-3 flag, therefore
+    netcdf-4 operations are not allowed. (see
+    [NF\_OPEN](#NF_005fOPEN)).
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+ `NF_ENOTINDEFINE`
+:   Not in define mode.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_vars3.F.
+
+ 
+
+
+      one = 1
+      zero = 0
+      retval = nf_insert_enum(ncid, enum_typeid, zero_name, zero)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_insert_enum(ncid, enum_typeid, one_name, one)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+### 5.9.3 Learn About a Enum Type: NF\_INQ\_ENUM 
+
+Get information about a user-defined enumeration type.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_ENUM(INTEGER NCID, INTEGER XTYPE,
+        CHARACTER*(*) NAME, INTEGER BASE_NF_TYPE, INTEGER BASE_SIZE, 
+        INTEGER NUM_MEMBERS)
+
+
+ `NCID`
+:   The group ID of the group which holds the enum type.
+
+ `XTYPE`
+:   The typeid for this enum type, as returned by NF\_DEF\_ENUM, or
+    NF\_INQ\_VAR.
+
+ `NAME`
+:   Character array which will get the name. It will have a maximum
+    length of NF\_MAX\_NAME.
+
+ `BASE_NF_TYPE`
+:   An integer which will get the base integer type of this enum.
+
+ `BASE_SIZE`
+:   An integer which will get the size (in bytes) of the base integer
+    type of this enum.
+
+ `NUM_MEMBERS`
+:   An integer which will get the number of members defined for this
+    enumeration type.
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADTYPEID`
+:   Bad type id.
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+Example 
+-------
+
+In this example from nf\_test/ftst\_vars3.F, an enum type is created and
+then examined:
+
+ 
+
+
+      retval = nf_inq_enum(ncid, typeids(1), type_name, base_type, 
+     &     base_size, num_members)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (base_type .ne. NF_INT .or. num_members .ne. 2) stop 2
+
+
+### 5.9.4 Learn the Name of a Enum Type: nf\_inq\_enum\_member 
+
+Get information about a member of an enum type.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_ENUM_MEMBER(INTEGER NCID, INTEGER XTYPE, 
+        INTEGER IDX, CHARACTER*(*) NAME, INTEGER VALUE)
+
+
+ `NCID`
+:   The groupid where this enum type exists.
+
+ `XTYPE`
+:   The typeid for this enum type.
+
+ `IDX`
+:   The one-based index number for the member of interest.
+
+ `NAME`
+:   A character array which will get the name of the member. It will
+    have a maximum length of NF\_MAX\_NAME.
+
+ `VALUE`
+:   An integer that will get the value associated with this member.
+
+Errors 
+------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADTYPEID`
+:   Bad type id.
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_vars3.F:
+
+ 
+
+
+C     Check the members of the enum type.
+      retval = nf_inq_enum_member(ncid, typeids(1), 1, member_name, 
+     &     member_value)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (member_name(1:len(zero_name)) .ne. zero_name .or.
+     &     member_value .ne. 0) stop 2
+      retval = nf_inq_enum_member(ncid, typeids(1), 2, member_name, 
+     &     member_value)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (member_name(1:len(one_name)) .ne. one_name .or.
+     &     member_value .ne. 1) stop 2
+
+
+### 5.9.5 Learn the Name of a Enum Type: NF\_INQ\_ENUM\_IDENT 
+
+Get the name which is associated with an enum member value.
+
+This is similar to NF\_INQ\_ENUM\_MEMBER, but instead of using the index
+of the member, you use the value of the member.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_ENUM_IDENT(INTEGER NCID, INTEGER XTYPE,
+        INTEGER VALUE, CHARACTER*(*) IDENTIFIER)
+
+
+ `NCID`
+:   The groupid where this enum type exists.
+
+ `XTYPE`
+:   The typeid for this enum type.
+
+ `VALUE`
+:   The value for which an identifier is sought.
+
+ `IDENTIFIER`
+:   A character array that will get the identifier. It will have a
+    maximum length of NF\_MAX\_NAME.
+
+Return Code 
+-----------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EBADTYPEID`
+:   Bad type id, or not an enum type.
+
+ `NF_EHDFERR`
+:   An error was reported by the HDF5 layer.
+
+ `NF_EINVAL`
+:   The value was not found in the enum.
+
+Example 
+-------
+
+In this example from nf\_test/ftst\_vars3.F, the values for 0 and 1 are
+checked in an enum.
+
+ 
+
+
+      retval = nf_inq_enum_ident(ncid, typeids(1), 0, member_name)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (member_name(1:len(zero_name)) .ne. zero_name) stop 2
+      retval = nf_inq_enum_ident(ncid, typeids(1), 1, member_name)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (member_name(1:len(one_name)) .ne. one_name) stop 2
+
+
+6. Variables 
+============
+
+6.1 Variables Introduction 
+--------------------------
+
+Variables for a netCDF dataset are defined when the dataset is created,
+while the netCDF dataset is in define mode. Other variables may be added
+later by reentering define mode. A netCDF variable has a name, a type,
+and a shape, which are specified when it is defined. A variable may also
+have values, which are established later in data mode.
+
+Ordinarily, the name, type, and shape are fixed when the variable is
+first defined. The name may be changed, but the type and shape of a
+variable cannot be changed. However, a variable defined in terms of the
+unlimited dimension can grow without bound in that dimension.
+
+A netCDF variable in an open netCDF dataset is referred to by a small
+integer called a variable ID.
+
+Variable IDs reflect the order in which variables were defined within a
+netCDF dataset. Variable IDs are 1, 2, 3,..., in the order in which the
+variables were defined. A function is available for getting the variable
+ID from the variable name and vice-versa.
+
+Attributes (see [Attributes](#Attributes)) may be associated with a
+variable to specifych properties as units.
+
+Operationspported on variables are:
+
+-   Create a variable, given its name, data type, and shape.
+-   Get a variable ID from its name.
+-   Get a variable’s name, data type, shape, and number of attributes
+    from its ID.
+-   Put a data value into a variable, given variable ID, indices, and
+    value.
+-   Put an array of values into a variable, given variable ID, corner
+    indices, edge lengths, and a block of values.
+-   Put absampled or mapped array of values into a variable,
+    given variable ID, corner indices, edge lengths, stride vector,
+    index mapping vector, and a block of values.
+-   Get a data value from a variable, given variable ID and indices.
+-   Get an array of values from a variable, given variable ID, corner
+    indices, and edge lengths.
+-   Get absampled or mapped array of values from a variable,
+    given variable ID, corner indices, edge lengths, stride vector, and
+    index mapping vector.
+-   Rename a variable.
+
+
+6.2 Language Types Corresponding to netCDF external data types 
+--------------------------------------------------------------
+
+The following table gives the netCDF external data types and the
+corresponding type constants for defining variables in the FORTRAN
+interface:
+
+  -------- ---------------------- ------
+  Type     FORTRAN API Mnemonic   Bits
+  byte     NF\_BYTE               8
+  char     NF\_CHAR               8
+  short    NF\_SHORT              16
+  int      NF\_INT                32
+  float    NF\_FLOAT              32
+  double   NF\_DOUBLE             64
+  -------- ---------------------- ------
+
+The first column gives the netCDF external data type, which is the same
+as the CDL data type. The next column gives the corresponding FORTRAN
+parameter for use in netCDF functions (the parameters are defined in the
+netCDF FORTRAN include-file netcdf.inc). The last column gives the
+number of bits used in the external representation of values of the
+corresponding type.
+
+Note that there are no netCDF types corresponding to 64-bit integers or
+to characters wider than 8 bits in the current version of the netCDF
+library.
+
+6.3 Create a Variable: `NF_DEF_VAR` 
+-----------------------------------
+
+The function NF\_DEF\_VAR adds a new variable to an open netCDF dataset
+in define mode. It returns (as an argument) a variable ID, given the
+netCDF ID, the variable name, the variable type, the number of
+dimensions, and a list of the dimension IDs.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_DEF_VAR(INTEGER NCID, CHARACTER*(*) NAME,
+                            INTEGER XTYPE, INTEGER NVDIMS,
+                            INTEGER VDIMS(*), INTEGER varid)
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `NAME`
+:   Variable name.
+
+ `XTYPE`
+:   One of the set of predefined netCDF external data types. The type of
+    this parameter, NF\_TYPE, is defined in the netCDF header file. The
+    valid netCDF external data types are NF\_BYTE, NF\_CHAR, NF\_SHORT,
+    NF\_INT, NF\_FLOAT, and NF\_DOUBLE. If the file is a NetCDF-4/HDF5
+    file, the additional types NF\_UBYTE, NF\_USHORT, NF\_UINT,
+    NF\_INT64, NF\_UINT64, and NF\_STRING may be used, as well as a user
+    defined type ID.
+
+ `NVDIMS`
+:   Number of dimensions for the variable. For example, 2 specifies a
+    matrix, 1 specifies a vector, and 0 means the variable is a scalar
+    with no dimensions. Must not be negative or greater than the
+    predefined constant NF\_MAX\_VAR\_DIMS.
+
+ `VDIMS`
+:   Vector of ndims dimension IDs corresponding to the variable
+    dimensions. If the ID of the unlimited dimension is included, it
+    must be first. This argument is ignored if ndims is 0. For expanded
+    model netCDF4/HDF5 files, there may be any number of unlimited
+    dimensions, and they may be used in any element of the dimids array.
+
+ `varid`
+:   Returned variable ID.
+
+Errors 
+------
+
+NF\_DEF\_VAR returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The netCDF dataset is not in define mode.
+-   The specified variable name is the name of another existing
+    variable.
+-   The specified type is not a valid netCDF type.
+-   The specified number of dimensions is negative or more than the
+    constant NF\_MAX\_VAR\_DIMS, the maximum number of dimensions
+    permitted for a netCDF variable.
+-   One or more of the dimension IDs in the list of dimensions is not a
+    valid dimension ID for the netCDF dataset.
+-   The number of variables would exceed the constant NF\_MAX\_VARS, the
+    maximum number of variables permitted in a netCDF dataset.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+Here is an example using NF\_DEF\_VAR to create a variable named rh of
+type double with three dimensions, time, lat, and lon in a new netCDF
+dataset named foo.nc:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER  STATUS, NCID
+INTEGER  LATDIM, LONDIM, TIMDIM  ! dimension IDs
+INTEGER  RHID                    ! variable ID
+INTEGER  RHDIMS(3)               ! variable shape
+   ... 
+STATUS = NF_CREATE ('foo.nc', NF_NOCLOBBER, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+                                 ! define dimensions
+STATUS = NF_DEF_DIM(NCID, 'lat', 5, LATDIM)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_DEF_DIM(NCID, 'lon', 10, LONDIM)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_DEF_DIM(NCID, 'time', NF_UNLIMITED, TIMDIM)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+         ... 
+                                 ! define variable
+RHDIMS(1) = LONDIM
+RHDIMS(2) = LATDIM
+RHDIMS(3) = TIMDIM
+STATUS = NF_DEF_VAR (NCID, 'rh', NF_DOUBLE, 3, RHDIMS, RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+6.4 Define Chunking Parameters for a Variable: `NF_DEF_VAR_CHUNKING` 
+--------------------------------------------------------------------
+
+The function NF\_DEF\_VAR\_CHUNKING sets the storage parameters for a
+variable in a netCDF-4 file. It can set the chunk sizes to get chunked
+storage, or it can set the contiguous flag to get contiguous storage.
+
+Variables that make use of one or more unlimited dimensions,
+compression, or checms must use chunking. Such variables are created
+with default chunk sizes of 1 for each unlimited dimension and the
+dimension length for other dimensions, except that if the rlting
+chunks are too large, the default chunk sizes for non-record dimensions
+are reduced.
+
+The total size of a chunk must be less than 4 GiB. That is, the product
+of all chunksizes and the size of the data (or the size of nc\_vlen\_t
+for VLEN types) must be less than 4 GiB.
+
+This function may only be called after the variable is defined, but
+before nc\_enddef is called. Once the chunking parameters are set for a
+variable, they cannot be changed. This function can be used to change
+the default chunking for record, compressed, or checmmed variables
+before nc\_enddef is called.
+
+Note that you cannot set chunking for scalar variables. Only non-scalar
+variables can have chunking.
+
+Usage 
+-----
+
+ 
+
+
+NF_DEF_VAR_CHUNKING(INTEGER NCID, INTEGER VARID, INTEGER STORAGE, INTEGER CHUNKSIZES)
+
+
+ `ncid`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `varid`
+:   Variable ID.
+
+ `storage`
+:   If NF\_CONTIGUOUS, then contiguous storage is used for this
+    variable. Variables with compression, shuffle filter, checms, or
+    one or more unlimited dimensions cannot use contiguous storage. If
+    contiguous storage is turned on, the chunksizes parameter is
+    ignored.
+
+    If NF\_CHUNKED, then chunked storage is used for this variable.
+    Chunk sizes may be specified with the chunksizes parameter. Default
+    sizes will be used if chunking is required and this function is not
+    called.
+
+    By default contiguous storage is used for fix-sized variables when
+    conpression, chunking, checms, or endianness control are not
+    used.
+
+ `chunksizes`
+:   An array of chunk sizes. The array must have the one chunksize for
+    each dimension in the variable. If contiguous storage is used, then
+    the chunksizes parameter is ignored.
+
+Errors 
+------
+
+NF\_DEF\_VAR\_CHUNKING returns the value NF\_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error.
+
+Possible return codes include:
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_BADID`
+:   Bad ncid.
+
+ `NF_EINVAL`
+:   Invalid input. This can occur when the user attempts to set
+    contiguous storage for a variable with compression or checms, or
+    one or more unlimited dimensions.
+
+ `NF_ENOTNC4`
+:   Not a netCDF-4 file.
+
+ `NF_ENOTVAR`
+:   Can’t find this variable.
+
+ `NF_ELATEDEF`
+:   This variable has already been thebject of a NF\_ENDDEF call. In
+    netCDF-4 files NF\_ENDDEF will be called automatically for any data
+    read or write. Once enddef has been called, it is impossible to set
+    the chunking for a variable.
+
+ `NF_ENOTINDEFINE`
+:   Not in define mode. This is returned for netCDF classic or 64-bit
+    offset files, or for netCDF-4 files, when they were been created
+    with NF\_STRICT\_NC3 flag. (see
+    [NF\_CREATE](#NF_005fCREATE)).
+
+ `NF_ESTRICTNC3`
+:   Trying to create a var some place other than the root group in a
+    netCDF file with NF\_STRICT\_NC3 turned on.
+
+Example 
+-------
+
+In this example from nf\_test/ftst\_vars.F, a file is created, two
+dimensions and a variable are defined, and the chunksizes of the data
+are set to the size of the data (that is, data will be written in one
+chunk).
+
+ 
+
+
+C     Create the netCDF file.
+      retval = nf_create(FILE_NAME, NF_NETCDF4, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define the dimensions.
+      retval = nf_def_dim(ncid, "x", NX, x_dimid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_def_dim(ncid, "y", NY, y_dimid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define the variable. 
+      dimids(1) = y_dimid
+      dimids(2) = x_dimid
+      retval = NF_DEF_VAR(ncid, "data", NF_INT, NDIMS, dimids, varid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Turn on chunking.
+      chunks(1) = NY
+      chunks(2) = NX
+      retval = NF_DEF_VAR_chunking(ncid, varid, NF_CHUNKED, chunks)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+6.5 Learn About Chunking Parameters for a Variable: `NF_INQ_VAR_CHUNKING` 
+-------------------------------------------------------------------------
+
+The function NF\_INQ\_VAR\_CHUNKING returns the chunking settings for a
+variable in a netCDF-4 file.
+
+Usage 
+-----
+
+ 
+
+
+NF_INQ_VAR_CHUNKING(INTEGER NCID, INTEGER VARID, INTEGER STORAGE, INTEGER CHUNKSIZES);
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID.
+
+ `STORAGE`
+:   On return, set to NF\_CONTIGUOUS if this variable uses contiguous
+    storage, NF\_CHUNKED if it uses chunked storage.
+
+ `CHUNKSIZES`
+:   An array of chunk sizes. The length of CHUNKSIZES must be the same
+    as the number of dimensions of the variable.
+
+Errors 
+------
+
+NF\_INQ\_VAR\_CHUNKING returns the value NF\_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error.
+
+Possible return codes include:
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_BADID`
+:   Bad ncid.
+
+ `NF_ENOTNC4`
+:   Not a netCDF-4 file.
+
+ `NF_ENOTVAR`
+:   Can’t find this variable.
+
+Example 
+-------
+
+In this example from nf\_test/ftst\_vars.F, a variable with chunked
+storage is checked to ere that the chunksizes are set to expected
+values.
+
+ 
+
+
+C     Is everything set that ispposed to be?
+      retval = nf_inq_var_chunking(ncid, varid, storage, chunks_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (storage .ne. NF_CHUNKED) stop 2
+      if (chunks(1) .ne. chunks_in(1)) stop 2
+      if (chunks(2) .ne. chunks_in(2)) stop 2
+
+
+6.6 Set HDF5 Chunk Cache for a Variable: NF\_SET\_VAR\_CHUNK\_CACHE 
+-------------------------------------------------------------------
+
+This function changes the chunk cache settings for a variable. The
+change in cache size happens immediately. This is a property of the open
+file - it does not persist the next time you open the file.
+
+For more information, see the documentation for the H5Pset\_cache()
+function in the HDF5 library at the HDF5 website:
+[http://hdfgroup.org/HDF5/](http://hdfgroup.org/HDF5/).
+
+Usage 
+-----
+
+ 
+
+
+NF_SET_VAR_CHUNK_CACHE(INTEGER NCID, INTEGER VARID, INTEGER SIZE, INTEGER NELEMS, 
+               INTEGER PREEMPTION);
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to nc\_open or nc\_create.
+
+ `VARID`
+:   Variable ID.
+
+ `SIZE`
+:   The total size of the raw data chunk cache, in megabytes. This
+    should be big enough to hold multiple chunks of data. (Note that the
+    C API uses bytes, but the Fortran APIs uses megabytes to avoid
+    numbers that can’t fit in 4-byte integers.)
+
+ `NELEMS`
+:   The number of chunk slots in the raw data chunk cache hash table.
+    This should be a prime number larger than the number of chunks that
+    will be in the cache.
+
+ `PREEMPTION`
+:   The preemption value must be between 0 and 100 inclusive and
+    indicates the degreee to which chunks that have been fully read are
+    favored for kicking out of the chunk cache, when needed. A value of
+    zero means fully read chunks are treated no differently than other
+    chunks (the preemption is strictly Least Recently Used) while a
+    value of 100 means fully read chunks are always preempted before
+    other chunks. (The C API uses a float between 0 and 1 for this
+    value).
+
+Return Codes 
+------------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_EINVAL`
+:   Preemption must be between zero and 100 (inclusive).
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_vars2.F:
+
+ 
+
+
+      include 'netcdf.inc'
+ ...
+C     These will be used to set the per-variable chunk cache.
+      integer CACHE_SIZE, CACHE_NELEMS, CACHE_PREEMPTION
+      parameter (CACHE_SIZE = 8, CACHE_NELEMS = 571)
+      parameter (CACHE_PREEMPTION = 42)
+...
+C        Set variable caches.
+         retval = nf_set_var_chunk_cache(ncid, varid(i), CACHE_SIZE, 
+     &        CACHE_NELEMS, CACHE_PREEMPTION)
+         if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+6.7 Get the HDF5 Chunk Cache Settings for a variable: NF\_GET\_VAR\_CHUNK\_CACHE 
+--------------------------------------------------------------------------------
+
+This function gets the current chunk cache settings for a variable in a
+netCDF-4/HDF5 file.
+
+For more information, see the documentation for the H5Pget\_cache()
+function in the HDF5 library at the HDF5 website:
+[http://hdfgroup.org/HDF5/](http://hdfgroup.org/HDF5/).
+
+Usage 
+-----
+
+ 
+
+
+INTEGER NF_GET_VAR_CHUNK_CACHE(INTEGER NCID, INTEGER VARID, INTEGER SIZE, INTEGER NELEMS, 
+                               INTEGER PREEMPTION);
+
+
+ `ncid`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `varid`
+:   Variable ID.
+
+ `sizep`
+:   The total size of the raw data chunk cache, in megabytes, will be
+    put here.
+
+ `nelemsp`
+:   The number of chunk slots in the raw data chunk cache hash table
+    will be put here.
+
+ `preemptionp`
+:   The preemption will be put here. The preemtion value is between 0
+    and 100 inclusive and indicates how much chunks that have been fully
+    read are favored for preemption. A value of zero means fully read
+    chunks are treated no differently than other chunks (the preemption
+    is strictly LRU) while a value of 100 means fully read chunks are
+    always preempted before other chunks.
+
+Return Codes 
+------------
+
+ `NC_NOERR`
+:   No error.
+
+Example 
+-------
+
+This example is from nf\_test/ftst\_vars2.c:
+
+ 
+
+
+      include 'netcdf.inc'
+...
+C     These will be used to set the per-variable chunk cache.
+      integer CACHE_SIZE, CACHE_NELEMS, CACHE_PREEMPTION
+      parameter (CACHE_SIZE = 8, CACHE_NELEMS = 571)
+      parameter (CACHE_PREEMPTION = 42)
+
+C     These will be used to check the setting of the per-variable chunk
+C     cache.
+      integer cache_size_in, cache_nelems_in, cache_preemption_in
+
+...
+         retval = nf_get_var_chunk_cache(ncid, varid(i), cache_size_in, 
+     &        cache_nelems_in, cache_preemption_in)
+         if (retval .ne. nf_noerr) call handle_err(retval)
+         if (cache_size_in .ne. CACHE_SIZE .or. cache_nelems_in .ne. 
+     &        CACHE_NELEMS .or. cache_preemption .ne. CACHE_PREEMPTION)
+     &        stop 8
+
+
+6.8 Define Fill Parameters for a Variable: `nf_def_var_fill` 
+------------------------------------------------------------
+
+The function NF\_DEF\_VAR\_FILL sets the fill parameters for a variable
+in a netCDF-4 file.
+
+This function must be called after the variable is defined, but before
+NF\_ENDDEF is called.
+
+Usage 
+-----
+
+ 
+
+
+NF_DEF_VAR_FILL(INTEGER NCID, INTEGER VARID, INTEGER NO_FILL, FILL_VALUE);
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID.
+
+ `NO_FILL`
+:   Set to non-zero value to set no\_fill mode on a variable. When this
+    mode is on, fill values will not be written for the variable. This
+    is helpful in high performance applications. For netCDF-4/HDF5 files
+    (whether classic model or not), this may only be changed after the
+    variable is defined, but before it is committed to disk (i.e. before
+    the first NF\_ENDDEF after the NF\_DEF\_VAR.) For classic and 64-bit
+    offset file, the no\_fill mode may be turned on and off at any time.
+
+ `FILL_VALUE`
+:   A value which will be used as the fill value for the variable. Must
+    be the same type as the variable. This will be written to a
+    \_FillValue attribute, created for this purpose. If NULL, this
+    argument will be ignored.
+
+Return Codes 
+------------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_BADID`
+:   Bad ncid.
+
+ `NF_ENOTNC4`
+:   Not a netCDF-4 file.
+
+ `NF_ENOTVAR`
+:   Can’t find this variable.
+
+ `NF_ELATEDEF`
+:   This variable has already been thebject of a NF\_ENDDEF call. In
+    netCDF-4 files NF\_ENDDEF will be called automatically for any data
+    read or write. Once enddef has been called, it is impossible to set
+    the fill for a variable.
+
+ `NF_ENOTINDEFINE`
+:   Not in define mode. This is returned for netCDF classic or 64-bit
+    offset files, or for netCDF-4 files, when they were been created
+    with NF\_STRICT\_NC3 flag. (see
+    [NF\_CREATE](#NF_005fCREATE)).
+
+ `NF_EPERM`
+:   Attempt to create object in read-only file.
+
+Example 
+-------
+
+6.9 Learn About Fill Parameters for a Variable: `NF_INQ_VAR_FILL` 
+-----------------------------------------------------------------
+
+The function NF\_INQ\_VAR\_FILL returns the fill settings for a variable
+in a netCDF-4 file.
+
+Usage 
+-----
+
+ 
+
+
+NF_INQ_VAR_FILL(INTEGER NCID, INTEGER VARID, INTEGER NO_FILL, FILL_VALUE)
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID.
+
+ `NO_FILL`
+:   An integer which will get a 1 if no\_fill mode is set for this
+    variable, and a zero if it is not set
+
+ `FILL_VALUE`
+:   This will get the fill value for this variable. This parameter will
+    be ignored if it is NULL.
+
+Return Codes 
+------------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_BADID`
+:   Bad ncid.
+
+ `NF_ENOTNC4`
+:   Not a netCDF-4 file.
+
+ `NF_ENOTVAR`
+:   Can’t find this variable.
+
+Example 
+-------
+
+6.10 Define Compression Parameters for a Variable: `NF_DEF_VAR_DEFLATE` 
+-----------------------------------------------------------------------
+
+The function NF\_DEF\_VAR\_DEFLATE sets the deflate parameters for a
+variable in a netCDF-4 file.
+
+When using parallel I/O for writing data, deflate cannot be used. This
+is because the compression makes it impossible for the HDF5 library to
+exactly map the data to disk location.
+
+(Deflated data can be read with parallel I/O).
+
+NF\_DEF\_VAR\_DEFLATE must be called after the variable is defined, but
+before NF\_ENDDEF is called.
+
+Usage 
+-----
+
+ 
+
+
+NF_DEF_VAR_DEFLATE(INTEGER NCID, INTEGER VARID, INTEGER SHUFFLE, INTEGER DEFLATE, 
+                   INTEGER DEFLATE_LEVEL);
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID.
+
+ `SHUFFLE`
+:   If non-zero, turn on the shuffle filter.
+
+ `DEFLATE`
+:   If non-zero, turn on the deflate filter at the level specified by
+    the deflate\_level parameter.
+
+ `DEFLATE_LEVEL`
+:   Must be between 0 (no deflate, the default) and 9 (slowest, but
+    “best” deflate).
+
+    If set to zero, no deflation takes place and the def\_var\_deflate
+    call is ignored. This is slightly different from HDF5 handing of 0
+    deflate, which turns on the filter but makes only trivial changes to
+    the data.
+
+    Informal testing at NetCDF World Headquartersggests that there is
+    little to be gained (with the limited set of test data used here),
+    in setting the deflate level above 2 or 3.
+
+Errors 
+------
+
+NF\_DEF\_VAR\_DEFLATE returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error.
+
+Possible return codes include:
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_BADID`
+:   Bad ncid.
+
+ `NF_ENOTNC4`
+:   Not a netCDF-4 file.
+
+ `NF_ENOTVAR`
+:   Can’t find this variable.
+
+ `NF_ELATEDEF`
+:   This variable has already been thebject of a NF\_ENDDEF call. In
+    netCDF-4 files NF\_ENDDEF will be called automatically for any data
+    read or write. Once enddef has been called, it is impossible to set
+    the deflate for a variable.
+
+ `NF_ENOTINDEFINE`
+:   Not in define mode. This is returned for netCDF classic or 64-bit
+    offset files, or for netCDF-4 files, when they were been created
+    with NF\_STRICT\_NC3 flag. (see
+    [NF\_CREATE](#NF_005fCREATE)).
+
+ `NF_EPERM`
+:   Attempt to create object in read-only file.
+
+ `NF_EINVAL`
+:   Invalid deflate\_level. The deflate level must be between 0 and 9,
+    inclusive.
+
+Example 
+-------
+
+In this example from nf\_test/ftst\_vars.F, a file is created with two
+dimensions and one variable. Chunking, deflate, and the fletcher32
+filter are turned on. The deflate level is set to 4 below.
+
+ 
+
+
+C     Create the netCDF file.
+      retval = nf_create(FILE_NAME, NF_NETCDF4, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define the dimensions.
+      retval = nf_def_dim(ncid, "x", NX, x_dimid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_def_dim(ncid, "y", NY, y_dimid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define the variable. 
+      dimids(1) = y_dimid
+      dimids(2) = x_dimid
+      retval = NF_DEF_VAR(ncid, "data", NF_INT, NDIMS, dimids, varid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Turn on chunking.
+      chunks(1) = NY
+      chunks(2) = NX
+      retval = NF_DEF_VAR_CHUNKING(ncid, varid, NF_CHUNKED, chunks)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Turn on deflate compression, fletcher32 checm.
+      retval = NF_DEF_VAR_deflate(ncid, varid, 0, 1, 4)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = NF_DEF_VAR_FLETCHER32(ncid, varid, NF_FLETCHER32)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+6.11 Learn About Deflate Parameters for a Variable: `NF_INQ_VAR_DEFLATE` 
+------------------------------------------------------------------------
+
+The function NF\_INQ\_VAR\_DEFLATE returns the deflate settings for a
+variable in a netCDF-4 file.
+
+It is not necessary to know the deflate settings to read the variable.
+(Deflate is completely transparent to readers of the data).
+
+Usage 
+-----
+
+ 
+
+
+NF_INQ_VAR_DEFLATE(INTEGER NCID, INTEGER VARID, INTEGER SHUFFLE, 
+                   INTEGER DEFLATE, INTEGER DEFLATE_LEVEL);
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID.
+
+ `SHUFFLE`
+:   NF\_INQ\_VAR\_DEFLATE will set this to a 1 if the shuffle filter is
+    turned on for this variable, and a 0 otherwise.
+
+ `DEFLATE`
+:   NF\_INQ\_VAR\_DEFLATE will set this to a 1 if the deflate filter is
+    turned on for this variable, and a 0 otherwise.
+
+ `DEFLATE_LEVEL`
+:   NF\_INQ\_VAR\_DEFLATE function will write the deflate\_level here,
+    if deflate is in use.
+
+Errors 
+------
+
+NF\_INQ\_VAR\_DEFLATE returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error.
+
+Possible return codes include:
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_BADID`
+:   Bad ncid.
+
+ `NF_ENOTNC4`
+:   Not a netCDF-4 file.
+
+ `NF_ENOTVAR`
+:   Can’t find this variable.
+
+Example 
+-------
+
+In this example code from nf\_test/ftst\_vars.F, a file with a variable
+using deflate is opened, and the deflate level checked.
+
+ 
+
+
+C     Is everything set that ispposed to be?
+      retval = nf_inq_var_deflate(ncid, varid, shuffle, deflate, 
+     +     deflate_level)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (shuffle .ne. 0 .or. deflate .ne. 1 .or. 
+     +     deflate_level .ne. 4) stop 2
+
+
+6.12 Learn About Szip Parameters for a Variable: `NF_INQ_VAR_SZIP` 
+------------------------------------------------------------------
+
+The function NF\_INQ\_VAR\_SZIP returns the szip settings for a variable
+in a netCDF-4 file.
+
+It is not necessary to know the szip settings to read the variable.
+(Szip is completely transparent to readers of the data).
+
+Usage 
+-----
+
+ 
+
+
+NF_INQ_VAR_SZIP(INTEGER NCID, INTEGER VARID, INTEGER OPTION_MASK, 
+                        PIXELS_PER_BLOCK);
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID.
+
+ `OPTION_MASK`
+:   This will be set to the option\_mask value.
+
+ `PIXELS_PER_BLOCK`
+:   The number of bits per pixel will be put here.
+
+Errors 
+------
+
+NF\_INQ\_VAR\_SZIP returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error.
+
+Possible return codes include:
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_BADID`
+:   Bad ncid.
+
+ `NF_ENOTNC4`
+:   Not a netCDF-4 file.
+
+ `NF_ENOTVAR`
+:   Can’t find this variable.
+
+
+6.13 Define Checm Parameters for a Variable: `NF_DEF_VAR_FLETCHER32` 
+-----------------------------------------------------------------------
+
+The function NF\_DEF\_VAR\_FLETCHER32 sets the checm property for a
+variable in a netCDF-4 file.
+
+This function may only be called after the variable is defined, but
+before NF\_ENDDEF is called.
+
+Usage 
+-----
+
+ 
+
+
+NF_DEF_VAR_FLETCHER32(INTEGER NCID, INTEGER VARID, INTEGER CHECKSUM);
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID.
+
+ `CHECKSUM`
+:   If this is NF\_FLETCHER32, fletcher32 checms will be turned on
+    for this variable.
+
+Errors 
+------
+
+NF\_DEF\_VAR\_FLETCHER32 returns the value NF\_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error.
+
+Possible return codes include:
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_BADID`
+:   Bad ncid.
+
+ `NF_ENOTNC4`
+:   Not a netCDF-4 file.
+
+ `NF_ENOTVAR`
+:   Can’t find this variable.
+
+ `NF_ELATEDEF`
+:   This variable has already been thebject of a NF\_ENDDEF call. In
+    netCDF-4 files NF\_ENDDEF will be called automatically for any data
+    read or write. Once enddef has been called, it is impossible to set
+    the checm property for a variable.
+
+ `NF_ENOTINDEFINE`
+:   Not in define mode. This is returned for netCDF classic or 64-bit
+    offset files, or for netCDF-4 files, when they were been created
+    with NF\_STRICT\_NC3 flag. (see
+    [NF\_CREATE](#NF_005fCREATE)).
+
+ `NF_EPERM`
+:   Attempt to create object in read-only file.
+
+Example 
+-------
+
+In this example from nf\_test/ftst\_vars.F, the variable in a file has
+the Fletcher32 checm filter turned on.
+
+ 
+
+
+C     Create the netCDF file.
+      retval = nf_create(FILE_NAME, NF_NETCDF4, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define the dimensions.
+      retval = nf_def_dim(ncid, "x", NX, x_dimid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_def_dim(ncid, "y", NY, y_dimid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define the variable. 
+      dimids(1) = y_dimid
+      dimids(2) = x_dimid
+      retval = NF_DEF_VAR(ncid, "data", NF_INT, NDIMS, dimids, varid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Turn on chunking.
+      chunks(1) = NY
+      chunks(2) = NX
+      retval = NF_DEF_VAR_CHUNKING(ncid, varid, NF_CHUNKED, chunks)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Turn on deflate compression, fletcher32 checms.
+      retval = NF_DEF_VAR_DEFLATE(ncid, varid, 0, 1, 4)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = NF_DEF_VAR_FLETCHER32(ncid, varid, NF_FLETCHER32)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+
+6.14 Learn About Checm Parameters for a Variable: `NF_INQ_VAR_FLETCHER32` 
+----------------------------------------------------------------------------
+
+The function NF\_INQ\_VAR\_FLETCHER32 returns the checm settings for
+a variable in a netCDF-4 file.
+
+Usage 
+-----
+
+ 
+
+
+NF_INQ_VAR_FLETCHER32(INTEGER NCID, INTEGER VARID, INTEGER CHECKSUM);
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID.
+
+ `CHECKSUM`
+:   NF\_INQ\_VAR\_FLETCHER32 will set this to NF\_FLETCHER32 if the
+    fletcher32 filter is turned on for this variable, and NF\_NOCHECKSUM
+    if it is not.
+
+Errors 
+------
+
+NF\_INQ\_VAR\_FLETCHER32 returns the value NF\_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error.
+
+Possible return codes include:
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_BADID`
+:   Bad ncid.
+
+ `NF_ENOTNC4`
+:   Not a netCDF-4 file.
+
+ `NF_ENOTVAR`
+:   Can’t find this variable.
+
+Example 
+-------
+
+In this example from nf\_test/ftst\_vars.F the checm filter is
+checked for a file. Since it was turned on for this variable, the
+checm variable is set to NF\_FLETCHER32.
+
+ 
+
+
+      retval = nf_inq_var_fletcher32(ncid, varid, checm)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (checm .ne. NF_FLETCHER32) stop 2
+
+
+6.15 Define Endianness of a Variable: `NF_DEF_VAR_ENDIAN` 
+---------------------------------------------------------
+
+The function NF\_DEF\_VAR\_ENDIAN sets the endianness for a variable in
+a netCDF-4 file.
+
+This function must be called after the variable is defined, but before
+NF\_ENDDEF is called.
+
+By default, netCDF-4 variables are in native endianness. That is, they
+are big-endian on a big-endian machine, and little-endian on a little
+endian machine.
+
+In some cases a user might wish to change from native endianness to
+either big or little-endianness. This function allows them to do that.
+
+Usage 
+-----
+
+ 
+
+
+NF_DEF_VAR_ENDIAN(INTEGER NCID, INTEGER VARID, INTEGER ENDIAN)
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID.
+
+ `ENDIAN`
+:   Set to NF\_ENDIAN\_NATIVE for native endianness. (This is the
+    default). Set to NF\_ENDIAN\_LITTLE for little endian, or
+    NF\_ENDIAN\_BIG for big endian.
+
+Errors 
+------
+
+NF\_DEF\_VAR\_ENDIAN returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error.
+
+Possible return codes include:
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_BADID`
+:   Bad ncid.
+
+ `NF_ENOTNC4`
+:   Not a netCDF-4 file.
+
+ `NF_ENOTVAR`
+:   Can’t find this variable.
+
+ `NF_ELATEDEF`
+:   This variable has already been thebject of a NF\_ENDDEF call. In
+    netCDF-4 files NF\_ENDDEF will be called automatically for any data
+    read or write. Once enddef has been called, it is impossible to set
+    the endianness of a variable.
+
+ `NF_ENOTINDEFINE`
+:   Not in define mode. This is returned for netCDF classic or 64-bit
+    offset files, or for netCDF-4 files, when they were been created
+    with NF\_STRICT\_NC3 flag, and the file is not in define mode. (see
+    [NF\_CREATE](#NF_005fCREATE)).
+
+ `NF_EPERM`
+:   Attempt to create object in read-only file.
+
+Example 
+-------
+
+In this example from nf\_test/ftst\_vars.c, a file is created with one
+variable, and its endianness is set to NF\_ENDIAN\_BIG.
+
+ 
+
+
+C     Create the netCDF file.
+      retval = nf_create(FILE_NAME, NF_NETCDF4, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define the dimensions.
+      retval = nf_def_dim(ncid, "x", NX, x_dimid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_def_dim(ncid, "y", NY, y_dimid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define the variable. 
+      dimids(1) = y_dimid
+      dimids(2) = x_dimid
+      retval = NF_DEF_VAR(ncid, "data", NF_INT, NDIMS, dimids, varid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Turn on chunking.
+      chunks(1) = NY
+      chunks(2) = NX
+      retval = NF_DEF_VAR_chunking(ncid, varid, 0, chunks)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Set variable to big-endian (default is whatever is native to
+C     writing machine).
+      retval = NF_DEF_VAR_endian(ncid, varid, NF_ENDIAN_BIG)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+
+6.16 Learn About Endian Parameters for a Variable: `NF_INQ_VAR_ENDIAN` 
+----------------------------------------------------------------------
+
+The function NF\_INQ\_VAR\_ENDIAN returns the endianness settings for a
+variable in a netCDF-4 file.
+
+Usage 
+-----
+
+ 
+
+
+NF_INQ_VAR_ENDIAN(INTEGER NCID, INTEGER VARID, INTEGER ENDIAN)
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID.
+
+ `ENDIAN`
+:   NF\_INQ\_VAR\_ENDIAN will set this to NF\_ENDIAN\_LITTLE if this
+    variable is stored in little-endian format, NF\_ENDIAN\_BIG if it is
+    stored in big-endian format, and NF\_ENDIAN\_NATIVE if the
+    endianness is not set, and the variable is not created yet.
+
+Errors 
+------
+
+NF\_INQ\_VAR\_ENDIAN returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error.
+
+Possible return codes include:
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_BADID`
+:   Bad ncid.
+
+ `NF_ENOTNC4`
+:   Not a netCDF-4 file.
+
+ `NF_ENOTVAR`
+:   Can’t find this variable.
+
+Example 
+-------
+
+In this example from nf\_test/ftst\_vars.F, the endianness of a variable
+is checked to makere it is NF\_ENDIAN\_BIG.
+
+ 
+
+
+      retval = nf_inq_var_endian(ncid, varid, endianness)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (endianness .ne. NF_ENDIAN_BIG) stop 2
+
+
+
+6.17 Get a Variable ID from Its Name: NF\_INQ\_VARID 
+----------------------------------------------------
+
+The function NF\_INQ\_VARID returns the ID of a netCDF variable, given
+its name.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_VARID(INTEGER NCID, CHARACTER*(*) NAME, 
+                              INTEGER varid)
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `NAME`
+:   Variable name for which ID is desired.
+
+ `varid`
+:   Returned variable ID.
+
+Errors 
+------
+
+NF\_INQ\_VARID returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The specified variable name is not a valid name for a variable in
+    the specified netCDF dataset.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+Here is an example using NF\_INQ\_VARID to find out the ID of a variable
+named rh in an existing netCDF dataset named foo.nc:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER  STATUS, NCID, RHID
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+
+6.18 Get Information about a Variable from Its ID: NF\_INQ\_VAR family 
+----------------------------------------------------------------------
+
+A family of functions that returns information about a netCDF variable,
+given its ID. Information about a variable includes its name, type,
+number of dimensions, a list of dimension IDs describing the shape of
+the variable, and the number of variable attributes that have been
+assigned to the variable.
+
+The function NF\_INQ\_VAR returns all the information about a netCDF
+variable, given its ID. The other functions each return just one item of
+information about a variable.
+
+These other functions include NF\_INQ\_VARNAME, NF\_INQ\_VARTYPE,
+NF\_INQ\_VARNDIMS, NF\_INQ\_VARDIMID, and NF\_INQ\_VARNATTS.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_VAR      (INTEGER NCID, INTEGER VARID,
+                                  CHARACTER*(*) name, INTEGER xtype,
+                                  INTEGER ndims, INTEGER dimids(*),
+                                  INTEGER natts)
+INTEGER FUNCTION NF_INQ_VARNAME  (INTEGER NCID, INTEGER VARID, 
+                                  CHARACTER*(*) name)
+INTEGER FUNCTION NF_INQ_VARTYPE  (INTEGER NCID, INTEGER VARID, 
+                                  INTEGER xtype)
+INTEGER FUNCTION NF_INQ_VARNDIMS (INTEGER NCID, INTEGER VARID, 
+                                  INTEGER ndims)
+INTEGER FUNCTION NF_INQ_VARDIMID (INTEGER NCID, INTEGER VARID, 
+                                  INTEGER dimids(*))
+INTEGER FUNCTION NF_INQ_VARNATTS (INTEGER NCID, INTEGER VARID, 
+                                  INTEGER natts)
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID.
+
+ `NAME`
+:   Returned variable name. The caller must allocate space for the
+    returned name. The maximum possible length, in characters, of a
+    variable name is given by the predefined constant NF\_MAX\_NAME.
+
+ `xtype`
+:   Returned variable type, one of the set of predefined netCDF external
+    data types. The type of this parameter, NF\_TYPE, is defined in the
+    netCDF header file. The valid netCDF external data types are
+    NF\_BYTE, NF\_CHAR, NF\_SHORT, NF\_INT, NF\_FLOAT, AND NF\_DOUBLE.
+
+ `ndims`
+:   Returned number of dimensions the variable was defined as using. For
+    example, 2 indicates a matrix, 1 indicates a vector, and 0 means the
+    variable is a scalar with no dimensions.
+
+ `dimids`
+:   Returned vector of \*ndimsp dimension IDs corresponding to the
+    variable dimensions. The caller must allocate enough space for a
+    vector of at least \*ndimsp integers to be returned. The maximum
+    possible number of dimensions for a variable is given by the
+    predefined constant NF\_MAX\_VAR\_DIMS.
+
+ `natts`
+:   Returned number of variable attributes assigned to this variable.
+
+These functions return the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The variable ID is invalid for the specified netCDF dataset.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+Here is an example using NF\_INQ\_VAR to find out about a variable named
+rh in an existing netCDF dataset named foo.nc:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER  STATUS, NCID
+INTEGER  RHID               ! variable ID
+CHARACTER*31 RHNAME         ! variable name
+INTEGER  RHTYPE             ! variable type
+INTEGER  RHN                ! number of dimensions
+INTEGER  RHDIMS(NF_MAX_VAR_DIMS)   ! variable shape
+INTEGER  RHNATT                    ! number of attributes
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)  ! get ID
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_INQ_VAR (NCID, RHID, RHNAME, RHTYPE, RHN, RHDIMS, RHNATT)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+6.19 Write a Single Data Value: NF\_PUT\_VAR1\_ type 
+----------------------------------------------------
+
+The functions NF\_PUT\_VAR1\_type (for various types) put a single data
+value of the specified type into a variable of an open netCDF dataset
+that is in data mode. Inputs are the netCDF ID, the variable ID, an
+index that specifies which value to add or alter, and the data value.
+The value is converted to the external data type of the variable, if
+necessary.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION  NF_PUT_VAR1_TEXT(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), CHARACTER CHVAL)
+INTEGER FUNCTION  NF_PUT_VAR1_INT1(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), INTEGER*1 I1VAL)
+INTEGER FUNCTION  NF_PUT_VAR1_INT2(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), INTEGER*2 I2VAL)
+INTEGER FUNCTION  NF_PUT_VAR1_INT (INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), INTEGER   IVAL)
+INTEGER FUNCTION  NF_PUT_VAR1_REAL(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), REAL      RVAL)
+INTEGER FUNCTION  NF_PUT_VAR1_DOUBLE(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), DOUBLE    DVAL) 
+INTEGER FUNCTION  NF_PUT_VAR1(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), *) 
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID.
+
+ `INDEX`
+:   The index of the data value to be written. The indices are relative
+    to 1, so for example, the first data value of a two-dimensional
+    variable would have index (1,1). The elements of index must
+    correspond to the variable’s dimensions. Hence, if the variable uses
+    the unlimited dimension, the last index would correspond to the
+    record number.
+
+ `CHVAL`\
+ `I1VAL`\
+ `I2VAL`\
+ `IVAL`\
+ `RVAL`\
+ `DVAL`
+:   Pointer to the data value to be written. If the type of data values
+    differs from the netCDF variable type, type conversion will occur.
+    See [(netcdf)Type Conversion](netcdf.html#Type-Conversion)
+    ‘Type Conversion’ in The NetCDF Users Guide.
+
+Errors 
+------
+
+NF\_PUT\_VAR1\_ type returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The variable ID is invalid for the specified netCDF dataset.
+-   The specified indices were out of range for the rank of the
+    specified variable. For example, a negative index or an index that
+    is larger than the corresponding dimension length will cause an
+    error.
+-   The specified value is out of the range of values representable by
+    the external data type of the variable.
+-   The specified netCDF is in define mode rather than data mode.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+Here is an example using NF\_PUT\_VAR1\_DOUBLE to set the (4,3,2)
+element of the variable named rh to 0.5 in an existing netCDF dataset
+named foo.nc. For simplicity in this example, we ame that we know
+that rh is dimensioned with lon, lat, and time, so we want to set the
+value of rh that corresponds to the fourth lon value, the third lat
+value, and the second time value:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER  STATUS             ! error status
+INTEGER  NCID
+INTEGER  RHID               ! variable ID
+INTEGER  RHINDX(3)          ! where to put value
+DATA RHINDX /4, 3, 2/
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)  ! get ID
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_PUT_VAR1_DOUBLE (NCID, RHID, RHINDX, 0.5)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+6.20 Write an Entire Variable: NF\_PUT\_VAR\_ type 
+--------------------------------------------------
+
+The NF\_PUT\_VAR\_ type family of functions write all the values of a
+variable into a netCDF variable of an open netCDF dataset. This is the
+simplest interface to use for writing a value in a scalar variable or
+whenever all the values of a multidimensional variable can all be
+written at once. The values to be written are associated with the netCDF
+variable by aming that the last dimension of the netCDF variable
+varies fastest in the C interface. The values are converted to the
+external data type of the variable, if necessary.
+
+Take care when using the simplest forms of this interface with record
+variables (variables that use the NF\_UNLIMITED dimension) when you
+don’t specify how many records are to be written. If you try to write
+all the values of a record variable into a netCDF file that has no
+record data yet (hence has 0 records), nothing will be written.
+Similarly, if you try to write all the values of a record variable from
+an array but there are more records in the file than you ame, more
+in-memory data will be accessed than you expect, which may cause a
+segmentation violation. To avoidch problems, it is better to use the
+NF\_PUT\_VARA\_type interfaces for variables that use the NF\_UNLIMITED
+dimension. See [Write an Array of Values: NF\_PUT\_VARA\_
+type](#NF_005fPUT_005fVARA_005f-type).
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_PUT_VAR_TEXT  (INTEGER NCID, INTEGER VARID,
+                                   CHARACTER*(*) TEXT)
+INTEGER FUNCTION NF_PUT_VAR_INT1  (INTEGER NCID, INTEGER VARID,
+                                   INTEGER*1 I1VALS(*))
+INTEGER FUNCTION NF_PUT_VAR_INT2  (INTEGER NCID, INTEGER VARID,
+                                   INTEGER*2 I2VALS(*))
+INTEGER FUNCTION NF_PUT_VAR_INT   (INTEGER NCID, INTEGER VARID,
+                                   INTEGER IVALS(*))
+INTEGER FUNCTION NF_PUT_VAR_REAL  (INTEGER NCID, INTEGER VARID,
+                                   REAL RVALS(*))
+INTEGER FUNCTION NF_PUT_VAR_DOUBLE(INTEGER NCID, INTEGER VARID,
+                                   DOUBLE DVALS(*))
+INTEGER FUNCTION NF_PUT_VAR       (INTEGER NCID, INTEGER VARID,
+                                   VALS(*))
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID.
+
+ `TEXT`\
+ `I1VALS`\
+ `I2VALS`\
+ `IVALS`\
+ `RVALS`\
+ `DVALS`\
+ `VALS`
+:   The block of data values to be written. The data should be of the
+    type appropriate for the function called. You cannot put CHARACTER
+    data into a numeric variable or numeric data into a text variable.
+    For numeric data, if the type of data differs from the netCDF
+    variable type, type conversion will occur (see [(netcdf)Type
+    Conversion](netcdf.html#Type-Conversion) ‘Type Conversion’
+    in The NetCDF Users Guide). The order in which the data will be
+    written into the specified variable is with the first dimension
+    varying fastest (like the ordinary FORTRAN convention).
+
+Errors 
+------
+
+Members of the NF\_PUT\_VAR\_ type family return the value NF\_NOERR if
+no errors occurred. Otherwise, the returned status indicates an error.
+Possible causes of errors include:
+
+-   The variable ID is invalid for the specified netCDF dataset.
+-   One or more of the specified values are out of the range of values
+    representable by the external data type of the variable.
+-   One or more of the specified values are out of the range of values
+    representable by the external data type of the variable.
+-   The specified netCDF dataset is in define mode rather than data
+    mode.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+Here is an example using NF\_PUT\_VAR\_DOUBLE to add or change all the
+values of the variable named rh to 0.5 in an existing netCDF dataset
+named foo.nc. For simplicity in this example, we ame that we know
+that rh is dimensioned with lon and lat, and that there are ten lon
+values and five lat values.
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+PARAMETER (LATS=5, LONS=10) ! dimension lengths
+INTEGER  STATUS, NCID
+INTEGER  RHID                        ! variable ID
+DOUBLE RHVALS(LONS, LATS)
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+DO 10 ILON = 1, LONS
+   DO 10 ILAT = 1, LATS
+         RHVALS(ILON, ILAT) = 0.5
+10 CONTINUE
+STATUS = NF_PUT_var_DOUBLE (NCID, RHID, RHVALS)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+
+6.21 Write an Array of Values: NF\_PUT\_VARA\_ type 
+---------------------------------------------------
+
+The function NF\_PUT\_VARA\_ type writes values into a netCDF variable
+of an open netCDF dataset. The part of the netCDF variable to write is
+specified by giving a corner and a vector of edge lengths that refer to
+an array of the netCDF variable. The values to be written are
+associated with the netCDF variable by aming that the first dimension
+of the netCDF variable varies fastest in the FORTRAN interface. The
+netCDF dataset must be in data mode.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_PUT_VARA_TEXT(INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  CHARACTER*(*) TEXT)
+INTEGER FUNCTION NF_PUT_VARA_INT1(INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  INTEGER*1 I1VALS(*))
+INTEGER FUNCTION NF_PUT_VARA_INT2(INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  INTEGER*2 I2VALS(*))
+INTEGER FUNCTION NF_PUT_VARA_INT (INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  INTEGER IVALS(*))
+INTEGER FUNCTION NF_PUT_VARA_REAL(INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  REAL RVALS(*))
+INTEGER FUNCTION NF_PUT_VARA_DOUBLE(INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  DOUBLE DVALS(*)) 
+INTEGER FUNCTION NF_PUT_VARA     (INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  VALS(*)) 
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID.
+
+ `START`
+:   A vector of integers specifying the index in the variable where the
+    first of the data values will be written. The indices are relative
+    to 1, so for example, the first data value of a variable would have
+    index (1, 1, ..., 1). The length of START must be the same as the
+    number of dimensions of the specified variable. The elements of
+    START must correspond to the variable’s dimensions in order. Hence,
+    if the variable is a record variable, the last index would
+    correspond to the starting record number for writing the data
+    values.
+
+ `COUNT`
+:   A vector of integers specifying the edge lengths along each
+    dimension of the block of data values to written. To write a single
+    value, for example, specify COUNT as (1, 1, ..., 1). The length of
+    COUNT is the number of dimensions of the specified variable. The
+    elements of COUNT correspond to the variable’s dimensions. Hence, if
+    the variable is a record variable, the last element of COUNT
+    corresponds to a count of the number of records to write.
+
+    Note: setting any element of the count array to zero causes the
+    function to exit without error, and without doing anything.
+
+ `TEXT`\
+ `I1VALS`\
+ `I2VALS`\
+ `IVALS`\
+ `RVALS`\
+ `DVALS`\
+ `VALS`
+:   The block of data values to be written. The data should be of the
+    type appropriate for the function called. You cannot put CHARACTER
+    data into a numeric variable or numeric data into a text variable.
+    For numeric data, if the type of data differs from the netCDF
+    variable type, type conversion will occur (see [(netcdf)Type
+    Conversion](netcdf.html#Type-Conversion) ‘Type Conversion’
+    in The NetCDF Users Guide).
+
+Errors 
+------
+
+NF\_PUT\_VARA\_ type returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The variable ID is invalid for the specified netCDF dataset.
+-   The specified corner indices were out of range for the rank of the
+    specified variable. For example, a negative index, or an index that
+    is larger than the corresponding dimension length will cause an
+    error.
+-   The specified edge lengths added to the specified corner would have
+    referenced data out of range for the rank of the specified variable.
+    For example, an edge length that is larger than the corresponding
+    dimension length minus the corner index will cause an error.
+-   One or more of the specified values are out of the range of values
+    representable by the external data type of the variable.
+-   The specified netCDF dataset is in define mode rather than data
+    mode.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+Here is an example using NF\_PUT\_VARA\_DOUBLE to add or change all the
+values of the variable named rh to 0.5 in an existing netCDF dataset
+named foo.nc. For simplicity in this example, we ame that we know
+that rh is dimensioned with time, lat, and lon, and that there are three
+time values, five lat values, and ten lon values.
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+PARAMETER (NDIMS=3)         ! number of dimensions
+PARAMETER (TIMES=3, LATS=5, LONS=10) ! dimension lengths
+INTEGER  STATUS, NCID, TIMES
+INTEGER  RHID               ! variable ID
+INTEGER  START(NDIMS), COUNT(NDIMS)
+DOUBLE RHVALS(LONS, LATS, TIMES)
+DATA START /1, 1, 1/        ! start at first value
+DATA COUNT /LONS, LATS, TIMES/
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+DO 10 ILON = 1, LONS
+   DO 10 ILAT = 1, LATS
+      DO 10 ITIME = 1, TIMES
+         RHVALS(ILON, ILAT, ITIME) = 0.5
+10 CONTINUE
+STATUS = NF_PUT_VARA_DOUBLE (NCID, RHID, START, COUNT, RHVALS)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+
+6.22 NF\_PUT\_VARS\_ type 
+-------------------------
+
+Each member of the family of functions NF\_PUT\_VARS\_ type writes a
+subsampled (strided) array of values into a netCDF variable of
+an open netCDF dataset. Thebsampled array is specified by
+giving a corner, a vector of counts, and a stride vector. The netCDF
+dataset must be in data mode.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_PUT_VARS_TEXT  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*),CHARACTER*(*) TEXT)
+INTEGER FUNCTION NF_PUT_VARS_INT1  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*),INTEGER*1 I1VALS(*))
+INTEGER FUNCTION NF_PUT_VARS_INT2  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*),INTEGER*2 I2VALS(*))
+INTEGER FUNCTION NF_PUT_VARS_INT   (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IVALS(*))
+INTEGER FUNCTION NF_PUT_VARS_REAL  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*),  REAL RVALS(*))
+INTEGER FUNCTION NF_PUT_VARS_DOUBLE(INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*),  DOUBLE DVALS(*))
+INTEGER FUNCTION NF_PUT_VARS       (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), VALS(*))
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID.
+
+ `START`
+:   A vector of integers specifying the index in the variable where the
+    first of the data values will be written. The indices are relative
+    to 1, so for example, the first data value of a variable would have
+    index (1, 1, ..., 1). The elements of START correspond, in order, to
+    the variable’s dimensions. Hence, if the variable is a record
+    variable, the last index would correspond to the starting record
+    number for writing the data values.
+
+ `COUNT`
+:   A vector of integers specifying the number of indices selected along
+    each dimension. To write a single value, for example, specify COUNT
+    as (1, 1, ..., 1). The elements of COUNT correspond, in order, to
+    the variable’s dimensions. Hence, if the variable is a record
+    variable, the last element of COUNT corresponds to a count of the
+    number of records to write.
+
+    Note: setting any element of the count array to zero causes the
+    function to exit without error, and without doing anything.
+
+ `STRIDE`
+:   A vector of integers that specifies the sampling interval along each
+    dimension of the netCDF variable. The elements of the stride vector
+    correspond, in order, to the netCDF variable’s dimensions (STRIDE(1)
+    gives the sampling interval along the most rapidly varying dimension
+    of the netCDF variable). Sampling intervals are specified in
+    type-independent units of elements (a value of 1 selects consecutive
+    elements of the netCDF variable along the corresponding dimension, a
+    value of 2 selects every other element, etc.).
+
+ `TEXT`\
+ `I1VALS`\
+ `I2VALS`\
+ `IVALS`\
+ `RVALS`\
+ `DVALS`\
+ `VALS`
+:   The block of data values to be written. The data should be of the
+    type appropriate for the function called. You cannot put CHARACTER
+    data into a numeric variable or numeric data into a text variable.
+    For numeric data, if the type of data differs from the netCDF
+    variable type, type conversion will occur (see [(netcdf)Type
+    Conversion](netcdf.html#Type-Conversion) ‘Type Conversion’
+    in The NetCDF Users Guide).
+
+Errors 
+------
+
+NF\_PUT\_VARS\_ type returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The variable ID is invalid for the specified netCDF dataset.
+-   The specified start, count and stride generate an index which is out
+    of range.
+-   One or more of the specified values are out of the range of values
+    representable by the external data type of the variable.
+-   The specified netCDF is in define mode rather than data mode.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+Here is an example of using NF\_PUT\_VARS\_REAL to write – from an
+internal array – every other point of a netCDF variable named rh which
+is described by the FORTRAN declaration REAL RH(6,4) (note the size of
+the dimensions):
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+PARAMETER (NDIM=2)   ! rank of netCDF variable
+INTEGER NCID         ! netCDF dataset ID
+INTEGER STATUS       ! return code
+INTEGER RHID         ! variable ID
+INTEGER START(NDIM)  ! netCDF variable start point
+INTEGER COUNT(NDIM)  ! size of internal array
+INTEGER STRIDE(NDIM) ! netCDF variablebsampling intervals
+REAL RH(3,2)         ! notebsampled sizes for netCDF variable
+                     ! dimensions
+DATA START   /1, 1/  ! start at first netCDF variable value
+DATA COUNT   /3, 2/  ! size of internal array: entire bsampled)
+                     ! netCDF variable
+DATA STRIDE /2, 2/   ! access every other netCDF element
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID(NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_PUT_VARS_REAL(NCID, RHID, START, COUNT, STRIDE, RH)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+6.23 NF\_PUT\_VARM\_ type 
+-------------------------
+
+The NF\_PUT\_VARM\_ type family of functions writes a mapped array
+section of values into a netCDF variable of an open netCDF dataset. The
+mapped array is specified by giving a corner, a vector of
+counts, a stride vector, and an index mapping vector. The index mapping
+vector is a vector of integers that specifies the mapping between the
+dimensions of a netCDF variable and the in-memory structure of the
+internal data array. No amptions are made about the ordering or
+length of the dimensions of the data array. The netCDF dataset must be
+in data mode.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_PUT_VARM_TEXT  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            CHARACTER*(*) TEXT)
+INTEGER FUNCTION NF_PUT_VARM_INT1  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            INTEGER*1 I1VALS(*))
+INTEGER FUNCTION NF_PUT_VARM_INT2  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            INTEGER*2 I2VALS(*))
+INTEGER FUNCTION NF_PUT_VARM_INT   (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            INTEGER IVALS(*))
+INTEGER FUNCTION NF_PUT_VARM_REAL  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            REAL RVALS(*))
+INTEGER FUNCTION NF_PUT_VARM_DOUBLE(INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            DOUBLE DVALS(*))
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID.
+
+ `START`
+:   A vector of integers specifying the index in the variable where the
+    first of the data values will be written. The indices are relative
+    to 1, so for example, the first data value of a variable would have
+    index (1, 1, ..., 1). The elements of START correspond, in order, to
+    the variable’s dimensions. Hence, if the variable is a record
+    variable, the last index would correspond to the starting record
+    number for writing the data values.
+
+ `COUNT`
+:   A vector of integers specifying the number of indices selected along
+    each dimension. To write a single value, for example, specify COUNT
+    as (1, 1, ..., 1). The elements of COUNT correspond, in order, to
+    the variable’s dimensions. Hence, if the variable is a record
+    variable, the last element of COUNT corresponds to a count of the
+    number of records to write.
+
+    Note: setting any element of the count array to zero causes the
+    function to exit without error, and without doing anything.
+
+ `STRIDE`
+:   A vector of integers that specifies the sampling interval along each
+    dimension of the netCDF variable. The elements of the stride vector
+    correspond, in order, to the netCDF variable’s dimensions (STRIDE(1)
+    gives the sampling interval along the most rapidly varying dimension
+    of the netCDF variable). Sampling intervals are specified in
+    type-independent units of elements (a value of 1 selects consecutive
+    elements of the netCDF variable along the corresponding dimension, a
+    value of 2 selects every other element, etc.).
+
+ `IMAP`
+:   A vector of integers that specifies the mapping between the
+    dimensions of a netCDF variable and the in-memory structure of the
+    internal data array. The elements of the index mapping vector
+    correspond, in order, to the netCDF variable’s dimensions (IMAP(1)
+    gives the distance between elements of the internal array
+    corresponding to the most rapidly varying dimension of the netCDF
+    variable). Distances between elements are specified in units of
+    elements (the distance between internal elements that occupy
+    adjacent memory locations is 1 and not the element’s byte-length as
+    in netCDF 2).
+
+ `TEXT`\
+ `I1VALS`\
+ `I2VALS`\
+ `IVALS`\
+ `RVALS`\
+ `DVALS`
+:   The data values to be written. The data should be of the type
+    appropriate for the function called. You cannot put CHARACTER data
+    into a numeric variable or numeric data into a text variable. For
+    numeric data, if the type of data differs from the netCDF variable
+    type, type conversion will occur (see [(netcdf)Type
+    Conversion](netcdf.html#Type-Conversion) ‘Type Conversion’
+    in The NetCDF Users Guide).
+
+Errors 
+------
+
+NF\_PUT\_VARM\_ type returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The variable ID is invalid for the specified netCDF dataset.
+-   The specified START, COUNT, and STRIDE generate an index which is
+    out of range. Note that no error checking is possible on the imap
+    vector.
+-   One or more of the specified values are out of the range of values
+    representable by the external data type of the variable.
+-   The specified netCDF is in define mode rather than data mode.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+The following IMAP vector maps in the trivial way a 2x3x4 netCDF
+variable and an internal array of the same shape:
+
+ 
+
+
+REAL A(2,3,4)       ! same shape as netCDF variable
+INTEGER IMAP(3)
+DATA IMAP /1, 2, 6/ ! netCDF dimension       inter-element distance
+                    ! ----------------       ----------------------
+                    ! most rapidly varying       1
+                    ! intermediate               2 (=IMAP(1)*2)
+                    ! most slowly varying        6 (=IMAP(2)*3)
+
+
+Using the IMAP vector above with NF\_PUT\_VARM\_REAL obtains the same
+rlt as simply using NF\_PUT\_VAR\_REAL.
+
+Here is an example of using NF\_PUT\_VARM\_REAL to write – from a
+transposed, internal array – a netCDF variable named rh which is
+described by the FORTRAN declaration REAL RH(4,6) (note the size and
+order of the dimensions):
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+PARAMETER (NDIM=2)   ! rank of netCDF variable
+INTEGER NCID         ! netCDF ID
+INTEGER STATUS       ! return code
+INTEGER RHID         ! variable ID
+INTEGER START(NDIM)  ! netCDF variable start point
+INTEGER COUNT(NDIM)  ! size of internal array
+INTEGER STRIDE(NDIM) ! netCDF variablebsampling intervals
+INTEGER IMAP(NDIM)   ! internal array inter-element distances
+REAL RH(6,4)         ! note transposition of netCDF variable dimensions
+DATA START   /1, 1/  ! start at first netCDF variable element
+DATA COUNT   /4, 6/  ! entire netCDF variable; order corresponds
+                     ! to netCDF variable -- not internal array
+DATA STRIDE /1, 1/   ! sample every netCDF element
+DATA IMAP   /6, 1/   ! would be /1, 4/ if not transposing
+
+STATUS = NF_OPEN('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID(NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_PUT_VARM_REAL(NCID, RHID, START, COUNT, STRIDE, IMAP, RH)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+Here is another example of using NF\_PUT\_VARM\_REAL to write – from a
+transposed, internal array – absample of the same netCDF variable, by
+writing every other point of the netCDF variable:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+PARAMETER (NDIM=2)   ! rank of netCDF variable
+INTEGER NCID         ! netCDF dataset ID
+INTEGER STATUS       ! return code
+INTEGER RHID         ! variable ID
+INTEGER START(NDIM)  ! netCDF variable start point
+INTEGER COUNT(NDIM)  ! size of internal array
+INTEGER STRIDE(NDIM) ! netCDF variablebsampling intervals
+INTEGER IMAP(NDIM)   ! internal array inter-element distances
+REAL RH(3,2)         ! note transposition of bsampled) dimensions
+DATA START   /1, 1/  ! start at first netCDF variable value
+DATA COUNT   /2, 3/  ! order of bsampled) dimensions corresponds
+                     ! to netCDF variable -- not internal array
+DATA STRIDE /2, 2/   ! sample every other netCDF element
+DATA IMAP   /3, 1/   ! would be `1, 2' if not transposing
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID(NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_PUT_VARM_REAL(NCID, RHID, START, COUNT, STRIDE, IMAP, RH)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+6.24 NF\_GET\_VAR1\_ type 
+-------------------------
+
+The functions NF\_GET\_VAR1\_ type get a single data value from a
+variable of an open netCDF dataset that is in data mode. Inputs are the
+netCDF ID, the variable ID, a multidimensional index that specifies
+which value to get, and the address of a location into which the data
+value will be read. The value is converted from the external data type
+of the variable, if necessary.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION  NF_GET_VAR1_TEXT(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), CHARACTER CHVAL)
+INTEGER FUNCTION  NF_GET_VAR1_INT1(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), INTEGER*1 I1VAL)
+INTEGER FUNCTION  NF_GET_VAR1_INT2(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), INTEGER*2 I2VAL)
+INTEGER FUNCTION  NF_GET_VAR1_INT (INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), INTEGER   IVAL)
+INTEGER FUNCTION  NF_GET_VAR1_REAL(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), REAL      RVAL)
+INTEGER FUNCTION  NF_GET_VAR1_DOUBLE(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), DOUBLE    DVAL) 
+INTEGER FUNCTION  NF_GET_VAR1(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), VAL) 
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID.
+
+ `INDEX`
+:   The index of the data value to be read. The indices are relative to
+    1, so for example, the first data value of a two-dimensional
+    variable has index (1,1). The elements of index correspond to the
+    variable’s dimensions. Hence, if the variable is a record variable,
+    the last index is the record number.
+
+ `CHVAL`\
+ `I1VAL`\
+ `I2VAL`\
+ `IVAL`\
+ `RVAL`\
+ `DVAL`\
+ `VAL`
+:   The location into which the data value will be read. You cannot get
+    CHARACTER data from a numeric variable or numeric data from a
+    character variable. For numeric data, if the type of data differs
+    from the netCDF variable type, type conversion will occur. (see
+    [(netcdf)Type Conversion](netcdf.html#Type-Conversion) ‘Type
+    Conversion’ in The NetCDF Users Guide).
+
+Errors 
+------
+
+NF\_GET\_VAR1\_ type returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The variable ID is invalid for the specified netCDF dataset.
+-   The specified indices were out of range for the rank of the
+    specified variable. For example, a negative index or an index that
+    is larger than the corresponding dimension length will cause an
+    error.
+-   The value is out of the range of values representable by the desired
+    data type.
+-   The specified netCDF is in define mode rather than data mode.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+Here is an example using NF\_GET\_VAR1\_DOUBLE to get the (4,3,2)
+element of the variable named rh in an existing netCDF dataset named
+foo.nc. For simplicity in this example, we ame that we know that rh
+is dimensioned with lon, lat, and time, so we want to get the value of
+rh that corresponds to the fourth lon value, the third lat value, and
+the second time value:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS, NCID
+INTEGER RHID           ! variable ID
+INTEGER RHINDX(3)      ! where to get value
+DOUBLE PRECISION RHVAL ! put it here
+DATA RHINDX /4, 3, 2/
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_GET_VAR1_DOUBLE (NCID, RHID, RHINDX, RHVAL)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+6.25 NF\_GET\_VAR\_ type 
+------------------------
+
+The members of the NF\_GET\_VAR\_ type family of functions read all the
+values from a netCDF variable of an open netCDF dataset. This is the
+simplest interface to use for reading the value of a scalar variable or
+when all the values of a multidimensional variable can be read at once.
+The values are read into consecutive locations with the first dimension
+varying fastest. The netCDF dataset must be in data mode.
+
+Take care when using the simplest forms of this interface with record
+variables (variables that use the NF\_UNLIMITED dimension) when you
+don’t specify how many records are to be read. If you try to read all
+the values of a record variable into an array but there are more records
+in the file than you ame, more data will be read than you expect,
+which may cause a segmentation violation. To avoidch problems, it is
+better to use the NF\_GET\_VARA\_type interfaces for variables that use
+the NF\_UNLIMITED dimension. See [NF\_GET\_VARA\_
+type](#NF_005fGET_005fVARA_005f-type).
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_GET_VAR_TEXT  (INTEGER NCID, INTEGER VARID,
+                                   CHARACTER*(*) text)
+INTEGER FUNCTION NF_GET_VAR_INT1  (INTEGER NCID, INTEGER VARID,
+                                   INTEGER*1 i1vals(*))
+INTEGER FUNCTION NF_GET_VAR_INT2  (INTEGER NCID, INTEGER VARID,
+                                   INTEGER*2 i2vals(*))
+INTEGER FUNCTION NF_GET_VAR_INT   (INTEGER NCID, INTEGER VARID,
+                                   INTEGER ivals(*))
+INTEGER FUNCTION NF_GET_VAR_REAL  (INTEGER NCID, INTEGER VARID,
+                                   REAL rvals(*))
+INTEGER FUNCTION NF_GET_VAR_DOUBLE(INTEGER NCID, INTEGER VARID,
+                                   DOUBLE dvals(*))
+INTEGER FUNCTION NF_GET_VAR       (INTEGER NCID, INTEGER VARID,
+                                   vals(*))
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID.
+
+ `TEXT`\
+ `I1VALS`\
+ `I2VALS`\
+ `IVALS`\
+ `RVALS`\
+ `DVALS`\
+ `VALS`
+:   The block of data values to be read. The data should be of the type
+    appropriate for the function called. You cannot read CHARACTER data
+    from a numeric variable or numeric data from a text variable. For
+    numeric data, if the type of data differs from the netCDF variable
+    type, type conversion will occur (see [(netcdf)Type
+    Conversion](netcdf.html#Type-Conversion) ‘Type Conversion’
+    in The NetCDF Users Guide).
+
+Errors 
+------
+
+NF\_GET\_VAR\_ type returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The variable ID is invalid for the specified netCDF dataset.
+-   One or more of the values are out of the range of values
+    representable by the desired type.
+-   The specified netCDF is in define mode rather than data mode.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+Here is an example using NF\_GET\_VAR\_DOUBLE to read all the values of
+the variable named rh from an existing netCDF dataset named foo.nc. For
+simplicity in this example, we ame that we know that rh is
+dimensioned with lon and lat, and that there are ten lon values and five
+lat values.
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+PARAMETER (LATS=5, LONS=10) ! dimension lengths
+INTEGER STATUS, NCID
+INTEGER RHID                         ! variable ID
+DOUBLE RHVALS(LONS, LATS)
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_GET_VAR_DOUBLE (NCID, RHID, RHVALS)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+6.26 NF\_GET\_VARA\_ type 
+-------------------------
+
+The members of the NF\_GET\_VARA\_ type family of functions read an
+array of values from a netCDF variable of an open netCDF dataset. The
+array is specified by giving a corner and a vector of edge lengths. The
+values are read into consecutive locations with the first dimension
+varying fastest. The netCDF dataset must be in data mode.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_GET_VARA_TEXT(INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  CHARACTER*(*) text)
+INTEGER FUNCTION NF_GET_VARA_INT1(INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  INTEGER*1 i1vals(*))
+INTEGER FUNCTION NF_GET_VARA_INT2(INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  INTEGER*2 i2vals(*))
+INTEGER FUNCTION NF_GET_VARA_INT (INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  INTEGER ivals(*))
+INTEGER FUNCTION NF_GET_VARA_REAL(INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  REAL rvals(*))
+INTEGER FUNCTION NF_GET_VARA_DOUBLE(INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  DOUBLE dvals(*))
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID.
+
+ `START`
+:   A vector of integers specifying the index in the variable where the
+    first of the data values will be read. The indices are relative to
+    1, so for example, the first data value of a variable would have
+    index (1, 1, ..., 1). The length of START must be the same as the
+    number of dimensions of the specified variable. The elements of
+    START correspond, in order, to the variable’s dimensions. Hence, if
+    the variable is a record variable, the last index would correspond
+    to the starting record number for reading the data values.
+
+ `COUNT`
+:   A vector of integers specifying the edge lengths along each
+    dimension of the block of data values to be read. To read a single
+    value, for example, specify COUNT as (1, 1, ..., 1). The length of
+    COUNT is the number of dimensions of the specified variable. The
+    elements of COUNT correspond, in order, to the variable’s
+    dimensions. Hence, if the variable is a record variable, the last
+    element of COUNT corresponds to a count of the number of records to
+    read.
+
+    Note: setting any element of the count array to zero causes the
+    function to exit without error, and without doing anything.
+
+ `text`\
+ `i1vals`\
+ `i2vals`\
+ `ivals`\
+ `rvals`\
+ `dvals`
+:   The block of data values to be read. The data should be of the type
+    appropriate for the function called. You cannot read CHARACTER data
+    from a numeric variable or numeric data from a text variable. For
+    numeric data, if the type of data differs from the netCDF variable
+    type, type conversion will occur (see [(netcdf)Type
+    Conversion](netcdf.html#Type-Conversion) ‘Type Conversion’
+    in The NetCDF Users Guide).
+
+Errors 
+------
+
+NF\_GET\_VARA\_ type returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The variable ID is invalid for the specified netCDF dataset.
+-   The specified corner indices were out of range for the rank of the
+    specified variable. For example, a negative index or an index that
+    is larger than the corresponding dimension length will cause an
+    error.
+-   The specified edge lengths added to the specified corner would have
+    referenced data out of range for the rank of the specified variable.
+    For example, an edge length that is larger than the corresponding
+    dimension length minus the corner index will cause an error.
+-   One or more of the values are out of the range of values
+    representable by the desired type.
+-   The specified netCDF is in define mode rather than data mode.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+Here is an example using NF\_GET\_VARA\_DOUBLE to read all the values of
+the variable named rh from an existing netCDF dataset named foo.nc. For
+simplicity in this example, we ame that we know that rh is
+dimensioned with lon, lat, and time, and that there are ten lon values,
+five lat values, and three time values.
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+PARAMETER (NDIMS=3)                  ! number of dimensions
+PARAMETER (TIMES=3, LATS=5, LONS=10) ! dimension lengths
+INTEGER STATUS, NCID
+INTEGER RHID                         ! variable ID
+INTEGER START(NDIMS), COUNT(NDIMS)
+DOUBLE RHVALS(LONS, LATS, TIMES)
+DATA START /1, 1, 1/                 ! start at first value
+DATA COUNT /LONS, LATS, TIMES/       ! get all the values
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_GET_VARA_DOUBLE (NCID, RHID, START, COUNT, RHVALS)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+6.27 NF\_GET\_VARS\_ type 
+-------------------------
+
+The NF\_GET\_VARS\_ type family of functions read absampled (strided)
+array of values from a netCDF variable of an open netCDF
+dataset. Thebsampled array is specified by giving a corner, a
+vector of edge lengths, and a stride vector. The values are read with
+the first dimension of the netCDF variable varying fastest. The netCDF
+dataset must be in data mode.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_GET_VARS_TEXT  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*),CHARACTER*(*) text)
+INTEGER FUNCTION NF_GET_VARS_INT1  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*),INTEGER*1 i1vals(*))
+INTEGER FUNCTION NF_GET_VARS_INT2  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*),INTEGER*2 i2vals(*))
+INTEGER FUNCTION NF_GET_VARS_INT   (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER ivals(*))
+INTEGER FUNCTION NF_GET_VARS_REAL  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), REAL rvals(*))
+INTEGER FUNCTION NF_GET_VARS_DOUBLE(INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), DOUBLE dvals(*))
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID.
+
+ `START`
+:   A vector of integers specifying the index in the variable from which
+    the first of the data values will be read. The indices are relative
+    to 1, so for example, the first data value of a variable would have
+    index (1, 1, ..., 1). The elements of START correspond, in order, to
+    the variable’s dimensions. Hence, if the variable is a record
+    variable, the last index would correspond to the starting record
+    number for reading the data values.
+
+ `COUNT`
+:   A vector of integers specifying the number of indices selected along
+    each dimension. To read a single value, for example, specify COUNT
+    as (1, 1, ..., 1). The elements of COUNT correspond, in order, to
+    the variable’s dimensions. Hence, if the variable is a record
+    variable, the last element of COUNT corresponds to a count of the
+    number of records to read.
+
+    Note: setting any element of the count array to zero causes the
+    function to exit without error, and without doing anything.
+
+ `STRIDE`
+:   A vector of integers specifying, for each dimension, the interval
+    between selected indices or the value 0. The elements of the vector
+    correspond, in order, to the variable’s dimensions. A value of 1
+    accesses adjacent values of the netCDF variable in the corresponding
+    dimension; a value of 2 accesses every other value of the netCDF
+    variable in the corresponding dimension; and so on. A 0 argument is
+    treated as (1, 1, ..., 1).
+
+ `text`\
+ `i1vals`\
+ `i2vals`\
+ `ivals`\
+ `rvals`\
+ `dvals`
+:   The block of data values to be read. The data should be of the type
+    appropriate for the function called. You cannot read CHARACTER data
+    from a numeric variable or numeric data from a text variable. For
+    numeric data, if the type of data differs from the netCDF variable
+    type, type conversion will occur (see [(netcdf)Type
+    Conversion](netcdf.html#Type-Conversion) ‘Type Conversion’
+    in The NetCDF Users Guide).
+
+Errors 
+------
+
+NF\_GET\_VARS\_ type returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The variable ID is invalid for the specified netCDF dataset.
+-   The specified start, count and stride generate an index which is out
+    of range.
+-   One or more of the values are out of the range of values
+    representable by the desired type.
+-   The specified netCDF is in define mode rather than data mode.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+Here is an example using NF\_GET\_VARS\_DOUBLE to read every other value
+in each dimension of the variable named rh from an existing netCDF
+dataset named foo.nc. Values are assigned, using the same dimensional
+strides, to a 2-parameter array. For simplicity in this example, we
+ame that we know that rh is dimensioned with lon, lat, and time, and
+that there are ten lon values, five lat values, and three time values.
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+PARAMETER (NDIMS=3)                  ! number of dimensions
+PARAMETER (TIMES=3, LATS=5, LONS=10) ! dimension lengths
+INTEGER STATUS, NCID
+INTEGER RHID ! variable ID
+INTEGER START(NDIMS), COUNT(NDIMS), STRIDE(NDIMS)
+DOUBLE DATA(LONS, LATS, TIMES)
+DATA START /1, 1, 1/                 ! start at first value
+DATA COUNT /LONS, LATS, TIMES/
+DATA STRIDE /2, 2, 2/
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_GET_VARS_DOUBLE(NCID,RHID,START,COUNT,STRIDE,DATA(1,1,1))
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+6.28 NF\_GET\_VARM\_ type 
+-------------------------
+
+The NF\_GET\_VARM\_ type family of functions reads a mapped array
+section of values from a netCDF variable of an open netCDF dataset. The
+mapped array is specified by giving a corner, a vector of edge
+lengths, a stride vector, and an index mapping vector. The index mapping
+vector is a vector of integers that specifies the mapping between the
+dimensions of a netCDF variable and the in-memory structure of the
+internal data array. No amptions are made about the ordering or
+length of the dimensions of the data array. The netCDF dataset must be
+in data mode.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_GET_VARM_TEXT  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            CHARACTER*(*) text)
+INTEGER FUNCTION NF_GET_VARM_INT1  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            INTEGER*1 i1vals(*))
+INTEGER FUNCTION NF_GET_VARM_INT2  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            INTEGER*2 i2vals(*))
+INTEGER FUNCTION NF_GET_VARM_INT   (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            INTEGER ivals(*))
+INTEGER FUNCTION NF_GET_VARM_REAL  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            REAL rvals(*))
+INTEGER FUNCTION NF_GET_VARM_DOUBLE(INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            DOUBLE dvals(*))
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID.
+
+ `START`
+:   A vector of integers specifying the index in the variable from which
+    the first of the data values will be read. The indices are relative
+    to 1, so for example, the first data value of a variable would have
+    index (1, 1, ..., 1). The elements of START correspond, in order, to
+    the variable’s dimensions. Hence, if the variable is a record
+    variable, the last index would correspond to the starting record
+    number for reading the data values.
+
+ `COUNT`
+:   A vector of integers specifying the number of indices selected along
+    each dimension. To read a single value, for example, specify COUNT
+    as (1, 1, ..., 1). The elements of COUNT correspond, in order, to
+    the variable’s dimensions. Hence, if the variable is a record
+    variable, the last element of COUNT corresponds to a count of the
+    number of records to read.
+
+    Note: setting any element of the count array to zero causes the
+    function to exit without error, and without doing anything.
+
+ `STRIDE`
+:   A vector of integers specifying, for each dimension, the interval
+    between selected indices or the value 0. The elements of the vector
+    correspond, in order, to the variable’s dimensions. A value of 1
+    accesses adjacent values of the netCDF variable in the corresponding
+    dimension; a value of 2 accesses every other value of the netCDF
+    variable in the corresponding dimension; and so on. A 0 argument is
+    treated as (1, 1, ..., 1).
+
+ `IMAP`
+:   A vector of integers that specifies the mapping between the
+    dimensions of a netCDF variable and the in-memory structure of the
+    internal data array. IMAP(1) gives the distance between elements of
+    the internal array corresponding to the most rapidly varying
+    dimension of the netCDF variable. IMAP(N) (where N is the rank of
+    the netCDF variable) gives the distance between elements of the
+    internal array corresponding to the most slowly varying dimension of
+    the netCDF variable. Intervening IMAP elements correspond to other
+    dimensions of the netCDF variable in the obvious way. Distances
+    between elements are specified in units of elements (the distance
+    between internal elements that occupy adjacent memory locations is 1
+    and not the element’s byte-length as in netCDF 2).
+
+ `text`\
+ `i1vals`\
+ `i2vals`\
+ `ivals`\
+ `rvals`\
+ `dvals`
+:   The block of data values to be read. The data should be of the type
+    appropriate for the function called. You cannot read CHARACTER data
+    from a numeric variable or numeric data from a text variable. For
+    numeric data, if the type of data differs from the netCDF variable
+    type, type conversion will occur (see [(netcdf)Type
+    Conversion](netcdf.html#Type-Conversion) ‘Type Conversion’
+    in The NetCDF Users Guide).
+
+Errors 
+------
+
+NF\_GET\_VARM\_ type returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The variable ID is invalid for the specified netCDF dataset.
+-   The specified START, COUNT, and STRIDE generate an index which is
+    out of range. Note that no error checking is possible on the imap
+    vector.
+-   One or more of the values are out of the range of values
+    representable by the desired type.
+-   The specified netCDF is in define mode rather than data mode.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+The following IMAP vector maps in the trivial way a 2x3x4 netCDF
+variable and an internal array of the same shape:
+
+ 
+
+
+REAL A(2,3,4)       ! same shape as netCDF variable
+INTEGER IMAP(3)
+DATA IMAP /1, 2, 6/ ! netCDF dimension       inter-element distance
+                    ! ----------------       ----------------------
+                    ! most rapidly varying       1
+                    ! intermediate               2 (=IMAP(1)*2)
+                    ! most slowly varying        6 (=IMAP(2)*3)
+
+
+Using the IMAP vector above with NF\_GET\_VARM\_REAL obtains the same
+rlt as simply using NF\_GET\_VAR\_REAL.
+
+Here is an example of using NF\_GET\_VARM\_REAL to transpose a netCDF
+variable named rh which is described by the FORTRAN declaration REAL
+RH(4,6) (note the size and order of the dimensions):
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+PARAMETER (NDIM=2)   ! rank of netCDF variable
+INTEGER NCID         ! netCDF dataset ID
+INTEGER STATUS       ! return code
+INTEGER RHID         ! variable ID
+INTEGER START(NDIM)  ! netCDF variable start point
+INTEGER COUNT(NDIM)  ! size of internal array
+INTEGER STRIDE(NDIM) ! netCDF variablebsampling intervals
+INTEGER IMAP(NDIM)   ! internal array inter-element distances
+REAL    RH(6,4)      ! note transposition of netCDF variable dimensions
+DATA START   /1, 1/  ! start at first netCDF variable element
+DATA COUNT   /4, 6/  ! entire netCDF variable; order corresponds
+                     ! to netCDF variable -- not internal array
+DATA STRIDE /1, 1/   ! sample every netCDF element
+DATA IMAP   /6, 1/   ! would be /1, 4/ if not transposing
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID(NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_GET_VARM_REAL(NCID, RHID, START, COUNT, STRIDE, IMAP, RH)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+Here is another example of using NF\_GET\_VARM\_REAL to simultaneously
+transpose andbsample the same netCDF variable, by accessing every
+other point of the netCDF variable:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+PARAMETER (NDIM=2)   ! rank of netCDF variable
+INTEGER NCID         ! netCDF dataset ID
+INTEGER STATUS       ! return code
+INTEGER RHID         ! variable ID
+INTEGER START(NDIM)  ! netCDF variable start point
+INTEGER COUNT(NDIM)  ! size of internal array
+INTEGER STRIDE(NDIM) ! netCDF variablebsampling intervals
+INTEGER IMAP(NDIM)   ! internal array inter-element distances
+REAL    RH(3,2)      ! note transposition of bsampled) dimensions
+DATA START   /1, 1/  ! start at first netCDF variable value
+DATA COUNT   /2, 3/  ! order of bsampled) dimensions corresponds
+                     ! to netCDF variable -- not internal array
+DATA STRIDE /2, 2/   ! sample every other netCDF element
+DATA IMAP   /3, 1/   ! would be `1, 2' if not transposing
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID(NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_GET_VARM_REAL(NCID, RHID, START, COUNT, STRIDE, IMAP, RH)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+6.29 Reading and Writing Character String Values 
+------------------------------------------------
+
+Character strings are not a primitive netCDF external data type, in part
+because FORTRAN does notpport the abstraction of variable-length
+character strings (the FORTRAN LEN function returns the static length of
+a character string, not its dynamic length). As a rlt, a character
+string cannot be written or read as a single object in the netCDF
+interface. Instead, a character string must be treated as an array of
+characters, and array access must be used to read and write character
+strings as variable data in netCDF datasets. Furthermore,
+variable-length strings are notpported by the netCDF interface except
+by convention; for example, you may treat a zero byte as terminating a
+character string, but you must explicitly specify the length of strings
+to be read from and written to netCDF variables.
+
+Character strings as attribute values are easier to use, since the
+strings are treated as a single unit for access. However, the value of a
+character-string attribute is still an array of characters with an
+explicit length that must be specified when the attribute is defined.
+
+When you define a variable that will have character-string values, use a
+character-position dimension as the most quickly varying dimension for
+the variable (the first dimension for the variable in FORTRAN). The
+length of the character-position dimension will be the maximum string
+length of any value to be stored in the character-string variable. Space
+for maximum-length strings will be allocated in the disk representation
+of character-string variables whether you use the space or not. If two
+or more variables have the same maximum length, the same
+character-position dimension may be used in defining the variable
+shapes.
+
+To write a character-string value into a character-string variable, use
+either entire variable access or array access. The latter requires that
+you specify both a corner and a vector of edge lengths. The
+character-position dimension at the corner should be one for FORTRAN. If
+the length of the string to be written is n, then the vector of edge
+lengths will specify n in the character-position dimension, and one for
+all the other dimensions:(n, 1, 1, ..., 1).
+
+In FORTRAN, fixed-length strings may be written to a netCDF dataset
+without a terminating character, to save space. Variable-length strings
+should follow the C convention of writing strings with a terminating
+zero byte so that the intended length of the string can be determined
+when it is later read by either C or FORTRAN programs.
+
+The FORTRAN interface for reading and writing strings requires the use
+of different functions for accessing string values and numeric values,
+because standard FORTRAN does not permit the same formal parameter to be
+used for both character values and numeric values. An additional
+argument, specifying the declared length of the character string passed
+as a value, is required for NF\_PUT\_VARA\_TEXT and NF\_GET\_VARA\_TEXT.
+The actual length of the string is specified as the value of the
+edge-length vector corresponding to the character-position dimension.
+
+Here is an example that defines a record variable, tx, for character
+strings and stores a character-string value into the third record using
+NF\_PUT\_VARA\_TEXT. In this example, we ame the string variable and
+data are to be added to an existing netCDF dataset named foo.nc that
+already has an unlimited record dimension time.
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER   TDIMS, TXLEN
+PARAMETER (TDIMS=2)    ! number of TX dimensions
+PARAMETER (TXLEN = 15) ! length of example string
+INTEGER  NCID
+INTEGER  CHID          ! char position dimension id
+INTEGER  TIMEID        ! record dimension id
+INTEGER  TXID          ! variable ID
+INTEGER  TXDIMS(TDIMS) ! variable shape
+INTEGER  TSTART(TDIMS), TCOUNT(TDIMS)
+CHARACTER*40 TXVAL     ! max length 40
+DATA TXVAL /'example string'/
+   ... 
+TXVAL(TXLEN:TXLEN) = CHAR(0)   ! null terminate
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_REDEF(NCID)        ! enter define mode
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+! define character-position dimension for strings of max length 40
+STATUS = NF_DEF_DIM(NCID, "chid", 40, CHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+! define a character-string variable
+TXDIMS(1) = CHID   ! character-position dimension first
+TXDIMS(2) = TIMEID
+STATUS = NF_DEF_VAR(NCID, "tx", NF_CHAR, TDIMS, TXDIMS, TXID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_ENDDEF(NCID) ! leave define mode
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+! write txval into tx netCDF variable in record 3
+TSTART(1) = 1      ! start at beginning of variable
+TSTART(2) = 3      ! record number to write
+TCOUNT(1) = TXLEN  ! number of chars to write
+TCOUNT(2) = 1      ! only write one record
+STATUS = NF_PUT_VARA_TEXT (NCID, TXID, TSTART, TCOUNT, TXVAL)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+6.30 Fill Values 
+----------------
+
+What happens when you try to read a value that was never written in an
+open netCDF dataset? You might expect that this should always be an
+error, and that you should get an error message or an error status
+returned. You do get an error if you try to read data from a netCDF
+dataset that is not open for reading, if the variable ID is invalid for
+the specified netCDF dataset, or if the specified indices are not
+properly within the range defined by the dimension lengths of the
+specified variable. Otherwise, reading a value that was not written
+returns a special fill value used to fill in any undefined values when a
+netCDF variable is first written.
+
+You may ignore fill values and use the entire range of a netCDF external
+data type, but in this case you should makere you write all data
+values before reading them. If you know you will be writing all the data
+before reading it, you can specify that no prefilling of variables with
+fill values will occur by calling NF\_SET\_FILL before writing. This may
+provide a significant performance gain for netCDF writes.
+
+The variable attribute \_FillValue may be used to specify the fill value
+for a variable. Their are default fill values for each type, defined in
+the include file netcdf.inc: NF\_FILL\_CHAR, NF\_FILL\_INT1 (same as
+NF\_FILL\_BYTE), NF\_FILL\_INT2 (same as NF\_FILL\_SHORT),
+NF\_FILL\_INT, NF\_FILL\_REAL (same as NF\_FILL\_FLOAT), and
+NF\_FILL\_DOUBLE.
+
+The netCDF byte and character types have different default fill values.
+The default fill value for characters is the zero byte, a useful value
+for detecting the end of variable-length C character strings. If you
+need a fill value for a byte variable, it is recommended that you
+explicitly define an appropriate \_FillValue attribute, as generic
+utilitiesch as ncdump will not ame a default fill value for byte
+variables.
+
+Type conversion for fill values is identical to type conversion for
+other values: attempting to convert a value from one type to another
+type that can’t represent the value rlts in a range error. Such
+errors may occur on writing or reading values from a larger type ch
+as double) to a smaller type ch as float), if the fill value for the
+larger type cannot be represented in the smaller type.
+
+6.31 NF\_RENAME\_VAR 
+--------------------
+
+The function NF\_RENAME\_VAR changes the name of a netCDF variable in an
+open netCDF dataset. If the new name is longer than the old name, the
+netCDF dataset must be in define mode. You cannot rename a variable to
+have the name of any existing variable.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_RENAME_VAR (INTEGER NCID, INTEGER VARID,
+                                CHARACTER*(*) NEWNAM)
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID.
+
+ `NAME`
+:   New name for the specified variable.
+
+Errors 
+------
+
+NF\_RENAME\_VAR returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The new name is in use as the name of another variable.
+-   The variable ID is invalid for the specified netCDF dataset.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+Here is an example using NF\_RENAME\_VAR to rename the variable rh to
+rel\_hum in an existing netCDF dataset named foo.nc:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER  STATUS, NCID
+INTEGER  RHID             ! variable ID
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_REDEF (NCID)  ! enter definition mode
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_RENAME_VAR (NCID, RHID, 'rel_hum')
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_ENDDEF (NCID) ! leave definition mode
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+
+6.32 Change between Collective and Independent Parallel Access: NF\_VAR\_PAR\_ACCESS 
+------------------------------------------------------------------------------------
+
+The function NF\_VAR\_PAR\_ACCESS changes whether read/write operations
+on a parallel file system are performed collectively or independently
+(the default) on the variable. This function can only be called if the
+file was created with NF\_CREATE\_PAR (see
+[NF\_CREATE\_PAR](#NF_005fCREATE_005fPAR)) or opened with NF\_OPEN\_PAR
+(see [NF\_OPEN\_PAR](#NF_005fOPEN_005fPAR)).
+
+This function is only available if the netCDF library was built with a
+HDF5 library for which –enable-parallel was used, and which was linked
+(like HDF5) to MPI libraries.
+
+Calling this function affects only the open file - information about
+whether a variable is to be accessed collectively or independently is
+not written to the data file. Every time you open a file on a parallel
+file system, all variables default to independent operations. The change
+a variable to collective lasts only as long as that file is open.
+
+The variable can be changed from collective to independent, and back, as
+often as desired.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER NF_VAR_PAR_ACCESS(INTEGER NCID, INTEGER VARID, INTEGER ACCESS);
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN\_PAR (see
+    [NF\_OPEN\_PAR](#NF_005fOPEN_005fPAR)) or NF\_CREATE\_PAR (see
+    [NF\_CREATE\_PAR](#NF_005fCREATE_005fPAR)).
+
+ `varid`
+:   Variable ID.
+
+ `access`
+:   NF\_INDEPENDENT to set this variable to independent operations.
+    NF\_COLLECTIVE to set it to collective operations.
+
+Return Values 
+-------------
+
+ `NF_NOERR`
+:   No error.
+
+ `NF_ENOTVAR`
+:   No variable found.
+
+ `NF_ENOTNC4`
+:   Not a netCDF-4 file.
+
+ `NF_NOPAR`
+:   File not opened for parallel access.
+
+Example 
+-------
+
+This example comes from test program nf\_test/ftst\_parallel.F. For this
+test to be run, netCDF must have been built with a parallel-enabled
+HDF5, and –enable-parallel-tests must have been used when configuring
+netcdf.
+
+ 
+
+
+      retval = nf_var_par_access(ncid, varid, nf_collective)
+      if (retval .ne. nf_noerr) stop 2
+
+
+
+7. Attributes 
+=============
+
+7.1 Attributes Introduction 
+---------------------------
+
+Attributes may be associated with each netCDF variable to specifych
+properties as units, special values, maximum and minimum valid values,
+scaling factors, and offsets. Attributes for a netCDF dataset are
+defined when the dataset is first created, while the netCDF dataset is
+in define mode. Additional attributes may be added later by reentering
+define mode. A netCDF attribute has a netCDF variable to which it is
+assigned, a name, a type, a length, and a sequence of one or more
+values. An attribute is designated by its variable ID and name. When an
+attribute name is not known, it may be designated by its variable ID and
+number in order to determine its name, using the function
+NF\_INQ\_ATTNAME.
+
+The attributes associated with a variable are typically defined
+immediately after the variable is created, while still in define mode.
+The data type, length, and value of an attribute may be changed even
+when in data mode, as long as the changed attribute requires no more
+space than the attribute as originally defined.
+
+It is also possible to have attributes that are not associated with any
+variable. These are called global attributes and are identified by using
+NF\_GLOBAL as a variable pseudo-ID. Global attributes are ally
+related to the netCDF dataset as a whole and may be used for purposes
+such as providing a title or processing history for a netCDF dataset.
+
+Attributes are much more useful when they follow established community
+conventions. See [(netcdf)Attribute
+Conventions](netcdf.html#Attribute-Conventions) ‘Attribute
+Conventions’ in The NetCDF Users Guide.
+
+Operationspported on attributes are:
+
+-   Create an attribute, given its variable ID, name, data type, length,
+    and value.
+-   Get attribute’s data type and length from its variable ID and name.
+-   Get attribute’s value from its variable ID and name.
+-   Copy attribute from one netCDF variable to another.
+-   Get name of attribute from its number.
+-   Rename an attribute.
+-   Delete an attribute.
+
+7.2 NF\_PUT\_ATT\_ type 
+-----------------------
+
+The function NF\_PUT\_ATT\_ type adds or changes a variable attribute or
+global attribute of an open netCDF dataset. If this attribute is new, or
+if the space required to store the attribute is greater than before, the
+netCDF dataset must be in define mode.
+
+Usage 
+-----
+
+Although it’s possible to create attributes of all types, text and
+double attributes are adequate for most purposes.
+
+ 
+
+
+INTEGER FUNCTION  NF_PUT_ATT_TEXT  (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME, INTEGER LEN,
+                                    CHARACTER*(*) TEXT)
+INTEGER FUNCTION  NF_PUT_ATT_INT1  (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME, INTEGER XTYPE,
+                                    LEN, INTEGER*1 I1VALS(*))
+INTEGER FUNCTION  NF_PUT_ATT_INT2  (INTEGER NCID, INTEGER VARID,
+                                     CHARACTER*(*) NAME, INTEGER XTYPE,
+                                    LEN, INTEGER*2 I2VALS(*))
+INTEGER FUNCTION  NF_PUT_ATT_INT   (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME, INTEGER XTYPE,
+                                    LEN, INTEGER IVALS(*))
+INTEGER FUNCTION  NF_PUT_ATT_REAL  (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME, INTEGER XTYPE,
+                                    LEN, REAL RVALS(*))
+INTEGER FUNCTION  NF_PUT_ATT_DOUBLE(INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME, INTEGER XTYPE,
+                                    LEN, DOUBLE DVALS(*))
+INTEGER FUNCTION  NF_PUT_ATT       (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME, INTEGER XTYPE,
+                                    LEN, * VALS(*))
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID of the variable to which the attribute will be assigned
+    or NF\_GLOBAL for a global attribute.
+
+ `NAME`
+:   Attribute name. Attribute name conventions are amed by some
+    netCDF generic applications, e.g., ‘units’ as the name for a string
+    attribute that gives the units for a netCDF variable. See
+    [(netcdf)Attribute Conventions](netcdf.html#Attribute-Conventions)
+    ‘Attribute Conventions’ in The NetCDF Users Guide.
+
+ `XTYPE`
+:   One of the set of predefined netCDF external data types. The type of
+    this parameter, NF\_TYPE, is defined in the netCDF header file. The
+    valid netCDF external data types are NF\_BYTE, NF\_CHAR, NF\_SHORT,
+    NF\_INT, NF\_FLOAT, and NF\_DOUBLE. Although it’s possible to create
+    attributes of all types, NF\_CHAR and NF\_DOUBLE attributes are
+    adequate for most purposes.
+
+ `LEN`
+:   Number of values provided for the attribute.
+
+ `TEXT`\
+ `I1VALS`\
+ `I2VALS`\
+ `IVALS`\
+ `RVALS`\
+ `DVALS`\
+ `VALS`
+:   An array of LEN attribute values. The data should be of a type
+    appropriate for the function called. You cannot write CHARACTER data
+    into a numeric attribute or numeric data into a text attribute. For
+    numeric data, if the type of data differs from the attribute type,
+    type conversion will occur See [(netcdf)Type
+    Conversion](netcdf.html#Type-Conversion) ‘Type Conversion’
+    in The NetCDF Users Guide.
+
+Errors 
+------
+
+NF\_PUT\_ATT\_ type returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The variable ID is invalid for the specified netCDF dataset.
+-   The specified netCDF type is invalid.
+-   The specified length is negative.
+-   The specified open netCDF dataset is in data mode and the specified
+    attribute would expand.
+-   The specified open netCDF dataset is in data mode and the specified
+    attribute does not already exist.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+-   The number of attributes for this variable exceeds NF\_MAX\_ATTRS.
+
+Example 
+-------
+
+Here is an example using NF\_PUT\_ATT\_DOUBLE to add a variable
+attribute named valid\_range for a netCDF variable named rh and a global
+attribute named title to an existing netCDF dataset named foo.nc:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS, NCID
+INTEGER RHID                 ! variable ID
+DOUBLE RHRNGE(2)
+DATA RHRNGE /0.0D0, 100.0D0/
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_REDEF (NCID)     ! enter define mode
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_PUT_ATT_DOUBLE (NCID, RHID, 'valid_range', NF_DOUBLE, &
+                            2, RHRNGE)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_PUT_ATT_TEXT (NCID, NF_GLOBAL, 'title', 19, 
+                          'example netCDF dataset')
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_ENDDEF (NCID)    ! leave define mode
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+7.3 NF\_INQ\_ATT Family 
+-----------------------
+
+This family of functions returns information about a netCDF attribute.
+All but one of these functions require the variable ID and attribute
+name; the exception is NF\_INQ\_ATTNAME. Information about an attribute
+includes its type, length, name, and number. See the NF\_GET\_ATT family
+for getting attribute values.
+
+The function NF\_INQ\_ATTNAME gets the name of an attribute, given its
+variable ID and number. This function is useful in generic applications
+that need to get the names of all the attributes associated with a
+variable, since attributes are accessed by name rather than number in
+all other attribute functions. The number of an attribute is more
+volatile than the name, since it can change when other attributes of the
+same variable are deleted. This is why an attribute number is not called
+an attribute ID.
+
+The function NF\_INQ\_ATT returns the attribute’s type and length. The
+other functions each return just one item of information about an
+attribute.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_INQ_ATT    (INTEGER NCID, INTEGER VARID,
+                                CHARACTER*(*) NAME, INTEGER xtype,
+                                INTEGER len)
+INTEGER FUNCTION NF_INQ_ATTTYPE(INTEGER NCID, INTEGER VARID,
+                                CHARACTER*(*) NAME, INTEGER xtype)
+INTEGER FUNCTION NF_INQ_ATTLEN (INTEGER NCID, INTEGER VARID,
+                                CHARACTER*(*) NAME, INTEGER len)
+INTEGER FUNCTION NF_INQ_ATTNAME(INTEGER NCID, INTEGER VARID,
+                                INTEGER ATTNUM, CHARACTER*(*) name)
+INTEGER FUNCTION NF_INQ_ATTID  (INTEGER NCID, INTEGER VARID,
+                                CHARACTER*(*) NAME, INTEGER attnum)
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID of the attribute’s variable, or NF\_GLOBAL for a global
+    attribute.
+
+ `NAME`
+:   Attribute name. For NF\_INQ\_ATTNAME, this is a pointer to the
+    location for the returned attribute name.
+
+ `xtype`
+:   Returned attribute type, one of the set of predefined netCDF
+    external data types. The valid netCDF external data types are
+    NF\_BYTE, NF\_CHAR, NF\_SHORT, NF\_INT, NF\_FLOAT, and NF\_DOUBLE.
+
+ `len`
+:   Returned number of values currently stored in the attribute. For a
+    string-valued attribute, this is the number of characters in the
+    string.
+
+ `attnum`
+:   For NF\_INQ\_ATTNAME, the input attribute number; for
+    NF\_INQ\_ATTID, the returned attribute number. The attributes for
+    each variable are numbered from 1 (the first attribute) to NATTS,
+    where NATTS is the number of attributes for the variable, as
+    returned from a call to NF\_INQ\_VARNATTS.
+
+    (If you already know an attribute name, knowing its number is not
+    very useful, because accessing information about an attribute
+    requires its name.)
+
+Errors 
+------
+
+Each function returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The variable ID is invalid for the specified netCDF dataset.
+-   The specified attribute does not exist.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+-   For NF\_INQ\_ATTNAME, the specified attribute number is negative or
+    more than the number of attributes defined for the specified
+    variable.
+
+Example 
+-------
+
+Here is an example using NF\_INQ\_ATT to find out the type and length of
+a variable attribute named valid\_range for a netCDF variable named rh
+and a global attribute named title in an existing netCDF dataset named
+foo.nc:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS, NCID
+INTEGER RHID               ! variable ID
+INTEGER VRLEN, TLEN        ! attribute lengths
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_ATTLEN (NCID, RHID, 'valid_range', VRLEN)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_INQ_ATTLEN (NCID, NF_GLOBAL, 'title', TLEN)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+7.4 NF\_GET\_ATT\_ type 
+-----------------------
+
+Members of the NF\_GET\_ATT\_ type family of functions get the value(s)
+of a netCDF attribute, given its variable ID and name.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_GET_ATT_TEXT   (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME,
+                                    CHARACTER*(*) text)
+INTEGER FUNCTION NF_GET_ATT_INT1   (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME,
+                                    INTEGER*1 i1vals(*))
+INTEGER FUNCTION NF_GET_ATT_INT2   (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME,
+                                    INTEGER*2 i2vals(*))
+INTEGER FUNCTION NF_GET_ATT_INT    (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME,
+                                    INTEGER ivals(*))
+INTEGER FUNCTION NF_GET_ATT_REAL   (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME,
+                                    REAL rvals(*))
+INTEGER FUNCTION NF_GET_ATT_DOUBLE (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME,
+                                    DOUBLE dvals(*))
+INTEGER FUNCTION NF_GET_ATT        (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME, * vals(*))
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   Variable ID of the attribute’s variable, or NF\_GLOBAL for a global
+    attribute.
+
+ `NAME`
+:   Attribute name.
+
+ `TEXT`\
+ `I1VALS`\
+ `I2VALS`\
+ `IVALS`\
+ `RVALS`\
+ `DVALS`\
+ `VALS`
+:   Returned attribute values. All elements of the vector of attribute
+    values are returned, so you must provide enough space to hold them.
+    If you don’t know how much space to reserve, call NF\_INQ\_ATTLEN
+    first to find out the length of the attribute. You cannot read
+    character data from a numeric variable or numeric data from a text
+    variable. For numeric data, if the type of data differs from the
+    netCDF variable type, type conversion will occur. See [(netcdf)Type
+    Conversion](netcdf.html#Type-Conversion) ‘Type Conversion’
+    in The The NetCDF Users Guide.
+
+Errors 
+------
+
+NF\_GET\_ATT\_ type returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The variable ID is invalid for the specified netCDF dataset.
+-   The specified attribute does not exist.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+-   One or more of the attribute values are out of the range of values
+    representable by the desired type.
+
+Example 
+-------
+
+Here is an example using NF\_GET\_ATT\_DOUBLE to determine the values of
+a variable attribute named valid\_range for a netCDF variable named rh
+and a global attribute named title in an existing netCDF dataset named
+foo.nc. In this example, it is amed that we don’t know how many
+values will be returned, but that we do know the types of the
+attributes. Hence, to allocate enough space to store them, we must first
+inquire about the length of the attributes.
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+PARAMETER (MVRLEN=3)           ! max number of "valid_range" values
+PARAMETER (MTLEN=80)           ! max length of "title" attribute
+INTEGER STATUS, NCID
+INTEGER RHID                   ! variable ID
+INTEGER VRLEN, TLEN            ! attribute lengths
+DOUBLE PRECISION VRVAL(MVRLEN) ! vr attribute values
+CHARACTER*80 TITLE             ! title attribute values
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+! find out attribute lengths, to makere we have enough space
+STATUS = NF_INQ_ATTLEN (NCID, RHID, 'valid_range', VRLEN)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_INQ_ATTLEN (NCID, NF_GLOBAL, 'title', TLEN)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+! get attribute values, if not too big
+IF (VRLEN .GT. MVRLEN) THEN
+    WRITE (*,*) 'valid_range attribute too big!'
+    CALL EXIT
+ELSE
+    STATUS = NF_GET_ATT_DOUBLE (NCID, RHID, 'valid_range', VRVAL)
+    IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ENDIF
+IF (TLEN .GT. MTLEN) THEN
+    WRITE (*,*) 'title attribute too big!'
+    CALL EXIT
+ELSE
+    STATUS = NF_GET_ATT_TEXT (NCID, NF_GLOBAL, 'title', TITLE)
+    IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ENDIF
+
+
+7.5 NF\_COPY\_ATT 
+-----------------
+
+The function NF\_COPY\_ATT copies an attribute from one open netCDF
+dataset to another. It can also be used to copy an attribute from one
+variable to another within the same netCDF.
+
+If used to copy an attribute of user-defined type, then that
+user-defined type must already be defined in the target file. In the
+case of user-defined attributes, enddef/redef is called for ncid\_in and
+ncid\_out if they are in define mode. (This is the ere that all
+user-defined types are committed to the file(s) before the copy is
+attempted.)
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_COPY_ATT (INTEGER NCID_IN, INTEGER VARID_IN,
+                              CHARACTER*(*) NAME, INTEGER NCID_OUT,
+                              INTEGER VARID_OUT)
+
+
+ `NCID_IN`
+:   The netCDF ID of an input netCDF dataset from which the attribute
+    will be copied, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID_IN`
+:   ID of the variable in the input netCDF dataset from which the
+    attribute will be copied, or NF\_GLOBAL for a global attribute.
+
+ `NAME`
+:   Name of the attribute in the input netCDF dataset to be copied.
+
+ `NCID_OUT`
+:   The netCDF ID of the output netCDF dataset to which the attribute
+    will be copied, from a previous call to NF\_OPEN or NF\_CREATE. It
+    is permissible for the input and output netCDF IDs to be the same.
+    The output netCDF dataset should be in define mode if the attribute
+    to be copied does not already exist for the target variable, or if
+    it would cause an existing target attribute to grow.
+
+ `VARID_OUT`
+:   ID of the variable in the output netCDF dataset to which the
+    attribute will be copied, or NF\_GLOBAL to copy to a global
+    attribute.
+
+Errors 
+------
+
+NF\_COPY\_ATT returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The input or output variable ID is invalid for the specified netCDF
+    dataset.
+-   The specified attribute does not exist.
+-   The output netCDF is not in define mode and the attribute is new for
+    the output dataset is larger than the existing attribute.
+-   The input or output netCDF ID does not refer to an open netCDF
+    dataset.
+
+Example 
+-------
+
+Here is an example using NF\_COPY\_ATT to copy the variable attribute
+units from the variable rh in an existing netCDF dataset named foo.nc to
+the variable avgrh in another existing netCDF dataset named bar.nc,
+aming that the variable avgrh already exists, but does not yet have a
+units attribute:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS             ! error status
+INTEGER NCID1, NCID2       ! netCDF IDs
+INTEGER RHID, AVRHID       ! variable IDs
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_NOWRITE, NCID1)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_OPEN ('bar.nc', NF_WRITE, NCID2)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID1, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_INQ_VARID (NCID2, 'avgrh', AVRHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_REDEF (NCID2)  ! enter define mode
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+! copy variable attribute from "rh" to "avgrh"
+STATUS = NF_COPY_ATT (NCID1, RHID, 'units', NCID2, AVRHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_ENDDEF (NCID2) ! leave define mode
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+7.6 NF\_RENAME\_ATT 
+-------------------
+
+The function NF\_RENAME\_ATT changes the name of an attribute. If the
+new name is longer than the original name, the netCDF dataset must be in
+define mode. You cannot rename an attribute to have the same name as
+another attribute of the same variable.
+
+Usage 
+-----
+
+ 
+
+
+INTEGER FUNCTION NF_RENAME_ATT (INTEGER NCID, INTEGER VARID,
+                                CHARACTER*(*) NAME,
+                                CHARACTER*(*) NEWNAME)
+
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE
+
+ `VARID`
+:   ID of the attribute’s variable, or NF\_GLOBAL for a global attribute
+
+ `NAME`
+:   The current attribute name.
+
+ `NEWNAME`
+:   The new name to be assigned to the specified attribute. If the new
+    name is longer than the current name, the netCDF dataset must be in
+    define mode.
+
+Errors 
+------
+
+NF\_RENAME\_ATT returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The specified variable ID is not valid.
+-   The new attribute name is already in use for another attribute of
+    the specified variable.
+-   The specified netCDF dataset is in data mode and the new name is
+    longer than the old name.
+-   The specified attribute does not exist.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+Here is an example using NF\_RENAME\_ATT to rename the variable
+attribute units to Units for a variable rh in an existing netCDF dataset
+named foo.nc:
+
+ 
+
+
+INCLUDE "netcdf.inc"
+   ... 
+INTEGER STATUS   ! error status
+INTEGER NCID     ! netCDF ID
+INTEGER RHID     ! variable ID
+   ... 
+STATUS = NF_OPEN ("foo.nc", NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, "rh", RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+! rename attribute
+STATUS = NF_RENAME_ATT (NCID, RHID, "units", "Units")
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+7.7 NF\_DEL\_ATT 
+----------------
+
+The function NF\_DEL\_ATT deletes a netCDF attribute from an open netCDF
+dataset. The netCDF dataset must be in define mode.
+
+Usage 
+-----
+
+INTEGER FUNCTION NF\_DEL\_ATT (INTEGER NCID, INTEGER VARID,
+CHARACTER\*(\*) NAME)
+
+ `NCID`
+:   NetCDF ID, from a previous call to NF\_OPEN or NF\_CREATE.
+
+ `VARID`
+:   ID of the attribute’s variable, or NF\_GLOBAL for a global
+    attribute.
+
+ `NAME`
+:   The name of the attribute to be deleted.
+
+Errors 
+------
+
+NF\_DEL\_ATT returns the value NF\_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. Possible causes of
+errors include:
+
+-   The specified variable ID is not valid.
+-   The specified netCDF dataset is in data mode.
+-   The specified attribute does not exist.
+-   The specified netCDF ID does not refer to an open netCDF dataset.
+
+Example 
+-------
+
+Here is an example using NF\_DEL\_ATT to delete the variable attribute
+Units for a variable rh in an existing netCDF dataset named foo.nc:
+
+ 
+
+
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS            ! error status
+INTEGER NCID              ! netCDF ID
+INTEGER RHID              ! variable ID
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+! delete attribute
+STATUS = NF_REDEF (NCID)  ! enter define mode
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_DEL_ATT (NCID, RHID, 'Units')
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_ENDDEF (NCID) ! leave define mode
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+A. NetCDF 2 to NetCDF 3 Fortran 77 Transition Guide {.appendix}
+===================================================
+
+A.1 Overview of FORTRAN interface changes 
+-----------------------------------------
+
+NetCDF version 3 includes a complete rewrite of the netCDF library. It
+is about twice as fast as the previous version. The netCDF file format
+is unchanged, so files written with version 3 can be read with version 2
+code and vice versa.
+
+The core library is now written in ANSI C. You must have an ANSI C
+compiler to compile this version. The FORTRAN interface is layered on
+top of the C interface using a different technique than was used in
+netCDF-2.
+
+Rewriting the library offered an opportunity to implement improved C and
+FORTRAN interfaces that provide some significant benefits:
+
+-   type safety, by eliminating the need to use type punning in
+    arguments;
+-   automatic type conversions, by eliminating the undesirable coupling
+    between the language-independent external netCDF types (NF\_BYTE,
+    ..., NF\_DOUBLE) and language-dependent internal data types (INT\*1,
+    ..., DOUBLE PRECISION);
+-  pport for future enhancements, by eliminating obstacles to the
+    clean addition ofpport for packed data and multithreading;
+-   more standard error behavior, by uniformly communicating an error
+    status back to the calling program in the return value of each
+    function.
+
+It is not necessary to rewrite programs that use the version 2 FORTRAN
+interface, because the netCDF-3 library includes a backward
+compatibility interface thatpports all the old functions, globals,
+and behavior. We are hoping that the benefits of the new interface will
+be an incentive to use it in new netCDF applications. It is possible to
+convert old applications to the new interface incrementally, replacing
+netCDF-2 calls with the corresponding netCDF-3 calls one at a time.
+
+Other changes in the implementation of netCDF rlt in improved
+portability, maintainability, and performance on most platforms. A clean
+separation between I/O and type layers facilitates platform-specific
+optimizations. The new library no longer uses a vendor-provided XDR
+library, which simplifies linking programs that use netCDF and speeds up
+data access significantly in most cases.
+
+A.2 The New FORTRAN Interface 
+-----------------------------
+
+First, here’s an example of FORTRAN code that uses the netCDF-2
+interface:
+
+ 
+
+
+! Use a buffer big enough for values of any type
+DOUBLE PRECISION DBUF(NDATA)
+REAL RBUF(NDATA)
+...
+EQUIVALENCE (RBUF, DBUF), ...
+INT XTYPE     ! to hold the actual type of the data
+INT STATUS    ! for error status
+! Get the actual data type
+CALL NCVINQ(NCID, VARID, ...,XTYPE, ...)
+...
+! Get the data
+CALL NCVGT(NCID, VARID, START, COUNT, DBUF, STATUS)
+IF(STATUS .NE. NCNOERR) THEN
+   PRINT *, 'Cannot get data, error code =', STATUS
+   ! Deal with error
+   ...
+ENDIF
+IF (XTYPE .EQ. NCDOUBLE) THEN
+   CALL DANALYZE(DBUF)
+ELSEIF (XTYPE .EQ. NCFLOAT) THEN
+   CALL RANALYZE(RBUF)
+...
+ENDIF
+
+
+Here’s how you might handle this with the new netCDF-3 FORTRAN
+interface:
+
+ 
+
+
+! I want to use doubles for my analysis
+DOUBLE PRECISION DBUF(NDATA)
+INT STATUS
+! So I use a function that gets the data as doubles.
+STATUS = NF_GET_VARA_DOUBLE(NCID, VARID, START, COUNT, DBUF)
+IF(STATUS .NE. NF_NOERR) THEN
+   PRINT *, 'Cannot get data, ', NF_STRERROR(STATUS)
+   ! Deal with error
+   ...
+ENDIF
+CALL DANALYZE(DBUF)
+
+
+The example above illustrates changes in function names, data type
+conversion, and error handling, discussed in detail in thes
+below.
+
+A.3 Function Naming Conventions 
+-------------------------------
+
+The netCDF-3 Fortran 77 library employs a naming convention intended to
+make netCDF programs more readable. For example, the name of the
+function to rename a variable is now NF\_RENAME\_VAR instead of the
+previous NCVREN.
+
+All netCDF-3 FORTRAN function names begin with the NF\_ prefix. The
+second part of the name is a verb, like GET, PUT, INQ (for inquire), or
+OPEN. The third part of the name is typically the object of the verb:
+for example DIM, VAR, or ATT for functions dealing with dimensions,
+variables, or attributes. To distinguish the various I/O operations for
+variables, a single character modifier is appended to VAR:
+
+-   VAR entire variable access
+-   VAR1 single value access
+-   VARA array or array access
+-   VARS strided access to absample of values
+-   VARM mapped access to values not contiguous in memory
+
+At the end of the name for variable and attribute functions, there is a
+component indicating the type of the final argument: TEXT, INT1, INT2,
+INT, REAL, or DOUBLE. This part of the function name indicates the type
+of the data container you are using in your program: character string,
+1-byte integer, and so on.
+
+Also, all PARAMETER names in the public FORTRAN interface begin with the
+prefix NF\_. For example, the PARAMETER which was formerly MAXNCNAM is
+now NF\_MAX\_NAME, and the former FILFLOAT is now NF\_FILL\_FLOAT.
+
+As previously mentioned, all the old names are stillpported for
+backward compatibility.
+
+A.4 Type Conversion 
+-------------------
+
+With the new interface, users need not be aware of the external type of
+numeric variables, since automatic conversion to or from any desired
+numeric type is now available. You can use this feature to simplify
+code, by making it independent of external types. The elimination of
+type punning prevents some kinds of type errors that could occur with
+the previous interface. Programs may be made more robust with the new
+interface, because they need not be changed to accommodate a change to
+the external type of a variable.
+
+If conversion to or from an external numeric type is necessary, it is
+handled by the library. This automatic conversion and separation of
+external data representation from internal data types will become even
+more important in netCDF version 4, when new external types will be
+added for packed data for which there is no natural corresponding
+internal type, for example, arrays of 11-bit values.
+
+Converting from one numeric type to another may rlt in an error if
+the target type is not capable of representing the converted value. (In
+netCDF-2,ch overflows can only happen in the XDR layer.) For example,
+a REAL may not be able to hold data stored externally as an NF\_DOUBLE
+(an IEEE floating-point number). When accessing an array of values, an
+NF\_ERANGE error is returned if one or more values are out of the range
+of representable values, but other values are converted properly.
+
+Note that mere loss of precision in type conversion does not return an
+error. Thus, if you read double precision values into an INTEGER, for
+example, no error rlts unless the magnitude of the double precision
+value exceeds the representable range of INTEGERs on your platform.
+Similarly, if you read a large integer into a REAL incapable of
+representing all the bits of the integer in its mantissa, this loss
+There are two new functions in netCDF-3 that don’t correspond to any
+netCDF-2 functions: NF\_INQ\_LIBVERS and NF\_STRERROR. The version ation
+The previous implementation returned an error when the same dimension
+was used more than once in specifying the shape of a variable in
+ncvardef. This restriction is relaxed in the netCDF-3 implementation,
+because an autocorrelation matrix is a good example where using the same
+dimension twice makes sense.
+
+In the new interface, units for the IMAP argument to the NF\_PUT\_VARM
+and NF\_GET\_VARM families of functions are now in terms of the number
+of data elements of the desired internal type, not in terms of bytes as
+in the netCDF version-2 mapped access interfaces.
+
+Following is a table of netCDF-2 function names and names of the
+corresponding netCDF-3 functions. For parameter lists of netCDF-2
+functions, see the netCDF-2 User’s Guide.
+
+ `NCABOR`
+:   NF\_ABORT
+
+ `NCACPY`
+:   NF\_COPY\_ATT
+
+ `NCADEL`
+:   NF\_DEL\_ATT
+
+ `NCAGT`
+:   NF\_GET\_ATT\_DOUBLE, NF\_GET\_ATT\_REAL, NF\_GET\_ATT\_INT,
+    NF\_GET\_ATT\_INT1, NF\_GET\_ATT\_INT2
+
+ `NCAGTC`
+:   NF\_GET\_ATT\_TEXT
+
+ `NCAINQ`
+:   NF\_INQ\_ATT, NF\_INQ\_ATTID, NF\_INQ\_ATTLEN, NF\_INQ\_ATTTYPE
+
+ `NCANAM`
+:   NF\_INQ\_ATTNAME
+
+ `NCAPT`
+:   NF\_PUT\_ATT\_DOUBLE, NF\_PUT\_ATT\_REAL, NF\_PUT\_ATT\_INT,
+    NF\_PUT\_ATT\_INT1NF\_PUT
+
+B. Summary of FORTRAN 77 Interface {.appendix}
+==================================
+
+Input parameters are in upper case, output parameters are in lower case.
+The FORTRAN types of all the parameters are listed alphabetically by
+parameter name below the function declarations.
+
+ 
+
+
+CHARACTER*80 FUNCTION  NF_INQ_LIBVERS()
+CHARACTER*80 FUNCTION  NF_STRERROR  (NCERR)
+INTEGER FUNCTION  NF_CREATE         (PATH, CMODE, ncid)
+INTEGER FUNCTION  NF_OPEN           (PATH, MODE, ncid)
+INTEGER FUNCTION  NF_SET_FILL       (NCID, FILLMODE, old_mode)
+INTEGER FUNCTION  NF_REDEF          (NCID)
+INTEGER FUNCTION  NF_ENDDEF         (NCID)
+INTEGER FUNCTION  NF_SYNC           (NCID)
+INTEGER FUNCTION  NF_ABORT          (NCID)
+INTEGER FUNCTION  NF_CLOSE          (NCID)
+INTEGER FUNCTION  NF_INQ            (NCID, ndims, nvars, ngatts,
+                                     unlimdimid)
+INTEGER FUNCTION  NF_INQ_NDIMS      (NCID, ndims)
+INTEGER FUNCTION  NF_INQ_NVARS      (NCID, nvars)
+INTEGER FUNCTION  NF_INQ_NATTS      (NCID, ngatts)
+INTEGER FUNCTION  NF_INQ_UNLIMDIM   (NCID, unlimdimid)
+INTEGER FUNCTION  NF_DEF_DIM        (NCID, NAME, LEN, dimid)
+INTEGER FUNCTION  NF_INQ_DIMID      (NCID, NAME, dimid)
+INTEGER FUNCTION  NF_INQ_DIM        (NCID, DIMID, name, len)
+INTEGER FUNCTION  NF_INQ_DIMNAME    (NCID, DIMID, name)
+INTEGER FUNCTION  NF_INQ_DIMLEN     (NCID, DIMID, len)
+INTEGER FUNCTION  NF_RENAME_DIM     (NCID, DIMID, NAME)
+
+INTEGER FUNCTION  NF_DEF_VAR        (NCID, NAME, XTYPE, NDIMS, DIMIDS, 
+                                     varid)
+INTEGER FUNCTION  NF_INQ_VAR        (NCID, VARID, name, xtype, ndims, 
+                                     dimids, natts)
+INTEGER FUNCTION  NF_INQ_VARID      (NCID, NAME, varid)
+INTEGER FUNCTION  NF_INQ_VARNAME    (NCID, VARID, name)
+INTEGER FUNCTION  NF_INQ_VARTYPE    (NCID, VARID, xtype)
+INTEGER FUNCTION  NF_INQ_VARNDIMS   (NCID, VARID, ndims)
+INTEGER FUNCTION  NF_INQ_VARDIMID   (NCID, VARID, DIMIDS)
+INTEGER FUNCTION  NF_INQ_VARNATTS   (NCID, VARID, natts)
+INTEGER FUNCTION  NF_RENAME_VAR     (NCID, VARID, NAME)
+INTEGER FUNCTION  NF_PUT_VAR_TEXT   (NCID, VARID, TEXT)
+INTEGER FUNCTION  NF_GET_VAR_TEXT   (NCID, VARID, text)
+INTEGER FUNCTION  NF_PUT_VAR_INT1   (NCID, VARID, I1VAL)
+INTEGER FUNCTION  NF_GET_VAR_INT1   (NCID, VARID, i1val)
+INTEGER FUNCTION  NF_PUT_VAR_INT2   (NCID, VARID, I2VAL)
+INTEGER FUNCTION  NF_GET_VAR_INT2   (NCID, VARID, i2val)
+INTEGER FUNCTION  NF_PUT_VAR_INT    (NCID, VARID, IVAL)
+INTEGER FUNCTION  NF_GET_VAR_INT    (NCID, VARID, ival)
+INTEGER FUNCTION  NF_PUT_VAR_REAL   (NCID, VARID, RVAL)
+INTEGER FUNCTION  NF_GET_VAR_REAL   (NCID, VARID, rval)
+INTEGER FUNCTION  NF_PUT_VAR_DOUBLE (NCID, VARID, DVAL)
+INTEGER FUNCTION  NF_GET_VAR_DOUBLE (NCID, VARID, dval)
+INTEGER FUNCTION  NF_PUT_VAR1_TEXT  (NCID, VARID, INDEX, TEXT)
+INTEGER FUNCTION  NF_GET_VAR1_TEXT  (NCID, VARID, INDEX, text)
+INTEGER FUNCTION  NF_PUT_VAR1_INT1  (NCID, VARID, INDEX, I1VAL)
+INTEGER FUNCTION  NF_GET_VAR1_INT1  (NCID, VARID, INDEX, i1val)
+INTEGER FUNCTION  NF_PUT_VAR1_INT2  (NCID, VARID, INDEX, I2VAL)
+INTEGER FUNCTION  NF_GET_VAR1_INT2  (NCID, VARID, INDEX, i2val)
+INTEGER FUNCTION  NF_PUT_VAR1_INT   (NCID, VARID, INDEX, IVAL)
+INTEGER FUNCTION  NF_GET_VAR1_INT   (NCID, VARID, INDEX, ival)
+INTEGER FUNCTION  NF_PUT_VAR1_REAL  (NCID, VARID, INDEX, RVAL)
+INTEGER FUNCTION  NF_GET_VAR1_REAL  (NCID, VARID, INDEX, rval)
+INTEGER FUNCTION  NF_PUT_VAR1_DOUBLE(NCID, VARID, INDEX, DVAL)
+INTEGER FUNCTION  NF_GET_VAR1_DOUBLE(NCID, VARID, INDEX, dval)
+INTEGER FUNCTION  NF_PUT_VARA_TEXT  (NCID, VARID, START, COUNT, TEXT)
+INTEGER FUNCTION  NF_GET_VARA_TEXT  (NCID, VARID, START, COUNT, text)
+INTEGER FUNCTION  NF_PUT_VARA_INT1  (NCID, VARID, START, COUNT, I1VALS)
+INTEGER FUNCTION  NF_GET_VARA_INT1  (NCID, VARID, START, COUNT, i1vals)
+INTEGER FUNCTION  NF_PUT_VARA_INT2  (NCID, VARID, START, COUNT, I2VALS)
+INTEGER FUNCTION  NF_GET_VARA_INT2  (NCID, VARID, START, COUNT, i2vals)
+INTEGER FUNCTION  NF_PUT_VARA_INT   (NCID, VARID, START, COUNT, IVALS)
+INTEGER FUNCTION  NF_GET_VARA_INT   (NCID, VARID, START, COUNT, ivals)
+INTEGER FUNCTION  NF_PUT_VARA_REAL  (NCID, VARID, START, COUNT, RVALS)
+INTEGER FUNCTION  NF_GET_VARA_REAL  (NCID, VARID, START, COUNT, rvals)
+INTEGER FUNCTION  NF_PUT_VARA_DOUBLE(NCID, VARID, START, COUNT, DVALS)
+INTEGER FUNCTION  NF_GET_VARA_DOUBLE(NCID, VARID, START, COUNT, dvals)
+INTEGER FUNCTION  NF_PUT_VARS_TEXT  (NCID, VARID, START, COUNT, STRIDE,
+                                     TEXT)
+INTEGER FUNCTION  NF_GET_VARS_TEXT  (NCID, VARID, START, COUNT, STRIDE,
+                                     text)
+INTEGER FUNCTION  NF_PUT_VARS_INT1  (NCID, VARID, START, COUNT, STRIDE,
+                                     I1VALS)
+INTEGER FUNCTION  NF_GET_VARS_INT1  (NCID, VARID, START, COUNT, STRIDE,
+                                     i1vals)
+INTEGER FUNCTION  NF_PUT_VARS_INT2  (NCID, VARID, START, COUNT, STRIDE,
+                                     I2VALS)
+INTEGER FUNCTION  NF_GET_VARS_INT2  (NCID, VARID, START, COUNT, STRIDE,
+                                     i2vals)
+INTEGER FUNCTION  NF_PUT_VARS_INT   (NCID, VARID, START, COUNT, STRIDE,
+                                     IVALS)
+INTEGER FUNCTION  NF_GET_VARS_INT   (NCID, VARID, START, COUNT, STRIDE,
+                                     ivals)
+INTEGER FUNCTION  NF_PUT_VARS_REAL  (NCID, VARID, START, COUNT, STRIDE,
+                                     RVALS)
+INTEGER FUNCTION  NF_GET_VARS_REAL  (NCID, VARID, START, COUNT, STRIDE,
+                                     rvals)
+INTEGER FUNCTION  NF_PUT_VARS_DOUBLE(NCID, VARID, START, COUNT, STRIDE,
+                                     DVALS)
+INTEGER FUNCTION  NF_GET_VARS_DOUBLE(NCID, VARID, START, COUNT, STRIDE,
+                                     dvals)
+INTEGER FUNCTION  NF_PUT_VARM_TEXT  (NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, TEXT)
+INTEGER FUNCTION  NF_GET_VARM_TEXT  (NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, text)
+INTEGER FUNCTION  NF_PUT_VARM_INT1  (NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, I1VALS)
+INTEGER FUNCTION  NF_GET_VARM_INT1  (NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, i1vals)
+INTEGER FUNCTION  NF_PUT_VARM_INT2  (NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, I2VALS)
+INTEGER FUNCTION  NF_GET_VARM_INT2  (NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, i2vals)
+INTEGER FUNCTION  NF_PUT_VARM_INT   (NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, IVALS)
+INTEGER FUNCTION  NF_GET_VARM_INT   (NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, ivals)
+INTEGER FUNCTION  NF_PUT_VARM_REAL  (NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, RVALS)
+INTEGER FUNCTION  NF_GET_VARM_REAL  (NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, rvals)
+INTEGER FUNCTION  NF_PUT_VARM_DOUBLE(NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, DVALS)
+INTEGER FUNCTION  NF_GET_VARM_DOUBLE(NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, dvals)
+
+INTEGER FUNCTION  NF_INQ_ATT        (NCID, VARID, NAME, xtype, len)
+INTEGER FUNCTION  NF_INQ_ATTID      (NCID, VARID, NAME, attnum)
+INTEGER FUNCTION  NF_INQ_ATTTYPE    (NCID, VARID, NAME, xtype)
+INTEGER FUNCTION  NF_INQ_ATTLEN     (NCID, VARID, NAME, len)
+INTEGER FUNCTION  NF_INQ_ATTNAME    (NCID, VARID, ATTNUM, name)
+INTEGER FUNCTION  NF_COPY_ATT       (NCID_IN, VARID_IN, NAME,
+                                     NCID_OUT, VARID_OUT)
+INTEGER FUNCTION  NF_RENAME_ATT     (NCID, VARID, CURNAME, NEWNAME)
+INTEGER FUNCTION  NF_DEL_ATT        (NCID, VARID, NAME)
+INTEGER FUNCTION  NF_PUT_ATT_TEXT   (NCID, VARID, NAME, LEN, TEXT)
+INTEGER FUNCTION  NF_GET_ATT_TEXT   (NCID, VARID, NAME, text)
+INTEGER FUNCTION  NF_PUT_ATT_INT1   (NCID, VARID, NAME, XTYPE, LEN,
+                                     I1VALS)
+INTEGER FUNCTION  NF_GET_ATT_INT1   (NCID, VARID, NAME, i1vals)
+INTEGER FUNCTION  NF_PUT_ATT_INT2   (NCID, VARID, NAME, XTYPE, LEN,
+                                     I2VALS)
+INTEGER FUNCTION  NF_GET_ATT_INT2   (NCID, VARID, NAME, i2vals)
+INTEGER FUNCTION  NF_PUT_ATT_INT    (NCID, VARID, NAME, XTYPE, LEN,
+                                     IVALS)
+INTEGER FUNCTION  NF_GET_ATT_INT    (NCID, VARID, NAME, ivals)
+INTEGER FUNCTION  NF_PUT_ATT_REAL   (NCID, VARID, NAME, XTYPE, LEN,
+                                     RVALS)
+INTEGER FUNCTION  NF_GET_ATT_REAL   (NCID, VARID, NAME, rvals)
+INTEGER FUNCTION  NF_PUT_ATT_DOUBLE (NCID, VARID, NAME, XTYPE, LEN,
+                                     DVALS)
+INTEGER FUNCTION  NF_GET_ATT_DOUBLE (NCID, VARID, NAME, dvals)
+
+INTEGER       ATTNUM       ! attribute number
+INTEGER       attnum       ! returned attribute number
+INTEGER       CMODE        ! NF_NOCLOBBER, NF_SHARE flags expression
+INTEGER       COUNT        ! array of edge lengths of block of values
+CHARACTER(*)  CURNAME      ! current name (before renaming)
+INTEGER       DIMID        ! dimension ID
+INTEGER       dimid        ! returned dimension ID
+INTEGER       DIMIDS       ! list of dimension IDs
+INTEGER       dimids       ! list of returned dimension IDs
+DOUBLEPRECISION  DVAL      ! single data value
+DOUBLEPRECISION  dval      ! returned single data value
+DOUBLEPRECISION  DVALS     ! array of data values
+DOUBLEPRECISION  dvals     ! array of returned data values
+INTEGER       FILLMODE     ! NF_NOFILL or NF_FILL, for setting fill mode
+INTEGER*1     I1VAL        ! single data value
+INTEGER*1     I1val        ! returned single data value
+INTEGER*1     I1VALS       ! array of data values
+INTEGER*1     i1vals       ! array of returned data values
+INTEGER*2     I2VAL        ! single data value
+INTEGER*2     i2val        ! returned single data value
+INTEGER*2     I2VALS       ! array of data values
+INTEGER*2     i2vals       ! array of returned data values
+INTEGER       IMAP         ! index mapping vector
+INTEGER       INDEX        ! variable array index vector
+INTEGER       IVAL         ! single data value
+INTEGER       ival         ! returned single data value
+INTEGER       IVALS        ! array of data values
+INTEGER       ivals        ! array of returned data values
+INTEGER       LEN          ! dimension or attribute length
+INTEGER       len          ! returned dimension or attribute length
+INTEGER       MODE         ! open mode, one of NF_WRITE or NF_NOWRITE
+CHARACTER(*)  NAME         ! dimension, variable, or attribute name
+CHARACTER(*)  name         ! returned dim, var, or att name
+INTEGER       natts        ! returned number of attributes
+INTEGER       NCERR        ! error returned from NF_xxx function call
+INTEGER       NCID         ! netCDF ID of an open netCDF dataset
+INTEGER       ncid         ! returned netCDF ID
+INTEGER       NCID_IN      ! netCDF ID of open source netCDF dataset
+INTEGER       NCID_OUT     ! netCDF ID of open destination netCDF dataset
+INTEGER       NDIMS        ! number of dimensions
+INTEGER       ndims        ! returned number of dimensions
+CHARACTER(*)  NEWNAME      ! new name for dim, var, or att
+INTEGER       ngatts       ! returned number of global attributes
+INTEGER       nvars        ! returned number of variables
+INTEGER       old_mode     ! previous fill mode, NF_NOFILL or NF_FILL,
+CHARACTER(*)  PATH         ! name of netCDF dataset
+REAL          RVAL         ! single data value
+REAL          rval         ! returned single data value
+REAL          RVALS        ! array of data values
+REAL          rvals        ! array of returned data values
+INTEGER       START        ! variable array indices of first value
+INTEGER       STRIDE       ! variable array dimensional strides
+CHARACTER(*)  TEXT         ! input text value
+CHARACTER(*)  text         ! returned text value
+INTEGER       unlimdimid   ! returned ID of unlimited dimension
+INTEGER       VARID        ! variable ID
+INTEGER       varid        ! returned variable ID
+INTEGER       VARID_IN     ! variable ID
+INTEGER       VARID_OUT    ! variable ID
+INTEGER       XTYPE        ! external type: NF_BYTE, NF_CHAR, ... , 
+INTEGER       xtype        ! returned external type
+
diff --git a/docs/netcdf-f90.texi b/docs/netcdf-f90.texi
new file mode 100755
index 0000000..150e2a6
--- /dev/null
+++ b/docs/netcdf-f90.texi
@@ -0,0 +1,7105 @@
+\input texinfo @c -*-texinfo-*-
+ at comment This is part of the netCDF documentation. See COPYRIGHT file
+ at c $Id: netcdf-f90.texi,v 1.61 2010/03/25 15:26:06 ed Exp $
+ at c %**start of header
+ at setfilename netcdf-f90.info
+ at settitle NetCDF Fortran 90 Interface Guide
+ at setcontentsaftertitlepage
+ at c Combine the variable, concept, and function indices.
+ at synindex vr cp
+ at synindex fn cp
+ at c %**end of header
+
+ at c version.texi is automatically generated by automake and contains
+ at c defined variables VERSION, UPDATED, UPDATED-MONTH.
+ at include version-f90.texi
+ at include defines.texi
+
+ at ifinfo
+ at dircategory netCDF scientific data format
+ at direntry
+* netcdf-f90: (netcdf-f90).         @value{f90-man}
+ at end direntry
+ at end ifinfo
+
+ at titlepage
+ at title @value{f90-man}
+ at subtitle NetCDF Version @value{VERSION}
+ at subtitle @value{UPDATED}
+ at author Robert Pincus
+ at author Russ Rew
+ at page
+ at vskip 0pt plus 1filll
+ at insertcopying
+ at end titlepage
+
+ at ifnottex
+ at node Top, Use of the NetCDF Library, (dir), (dir)
+ at top @value{f90-man}
+
+This document describes the Fortran 90 interface to the netCDF
+library. It applies to netCDF version @value{VERSION}. This document
+was last updated in @value{UPDATED}.
+
+For a complete description of the netCDF format and utilities see 
+ at ref{Top, @value{n-man},, netcdf, @value{n-man}}.
+
+ at end ifnottex
+
+ at menu
+* Use of the NetCDF Library::   
+* Datasets::                    
+* Groups::                      
+* Dimensions::                  
+* User Defined Data Types::     
+* Variables::                   
+* Attributes::                  
+* Summary of Fortran 90 Interface::  
+* FORTRAN 77 to Fortran 90 Transition Guide::  
+* Combined Index::              
+
+ at detailmenu
+ --- The Detailed Node Listing ---
+
+Use of the NetCDF Library
+
+* Creating a NetCDF Dataset::   
+* Reading a NetCDF Dataset with Known Names::  
+* Reading a netCDF Dataset with Unknown Names::  
+* Writing Data in an Existing NetCDF Dataset::  
+* Adding New Dimensions::       
+* Error Handling::              
+* Compiling and Linking with the NetCDF Library::  
+
+Datasets
+
+* Datasets Introduction::       
+* NetCDF Library Interface Descriptions::  
+* NF90_STRERROR::               
+* NF90_INQ_LIBVERS::            
+* NF90_CREATE::                 
+* NF90_OPEN::                   
+* NF90_REDEF::                  
+* NF90_ENDDEF::                 
+* NF90_CLOSE::                  
+* NF90_INQUIRE Family::         
+* NF90_SYNC::                   
+* NF90_ABORT::                  
+* NF90_SET_FILL::               
+
+Groups
+
+* NF90_INQ_NCID::               
+* NF90_INQ_GRPS::               
+* NF90_INQ_VARIDS::             
+* NF90_INQ_DIMIDS::             
+* NF90_INQ_GRPNAME_LEN::        
+* NF90_INQ_GRPNAME::            
+* NF90_INQ_GRPNAME_FULL::       
+* NF90_INQ_GRP_PARENT::         
+* NF90_INQ_GRP_NCID::           
+* NF90_INQ_GRP_FULL_NCID::      
+* NF90_DEF_GRP::                
+
+Dimensions
+
+* Dimensions Introduction::     
+* NF90_DEF_DIM::                
+* NF90_INQ_DIMID::              
+* NF90_INQUIRE_DIMENSION::      
+* NF90_RENAME_DIM::             
+
+User Defined Data Types
+
+* User Defined Types::          
+* NF90_INQ_TYPEIDS::            
+* nf90_inq_typeid::             
+* NF90_INQ_TYPE::               
+* NF90_INQ_USER_TYPE::          
+* Compound Types::              
+* Variable Length Array::       
+* Opaque Type::                 
+* Enum Type::                   
+
+Example
+
+* NF90_PUT_VLEN_ELEMENT::       
+* NF90_GET_VLEN_ELEMENT::       
+
+Compound Types Introduction
+
+* NF90_DEF_COMPOUND::           
+* NF90_INSERT_COMPOUND::        
+* NF90_INSERT_ARRAY_COMPOUND::  
+* NF90_INQ_COMPOUND::           
+* NF90_INQ_COMPOUND_FIELD::     
+
+Variable Length Array Introduction
+
+* NF90_DEF_VLEN::               
+* NF90_INQ_VLEN::               
+* NF90_FREE_VLEN::              
+
+Opaque Type Introduction
+
+* NF90_DEF_OPAQUE::             
+* NF90_INQ_OPAQUE::             
+
+Example
+
+* NF90_INQ_OPAQUE::               
+
+Enum Type Introduction
+
+* NF90_DEF_ENUM::               
+* NF90_INSERT_ENUM::            
+* NF90_INQ_ENUM::               
+* NF90_INQ_ENUM_MEMBER::        
+* NF90_INQ_ENUM_IDENT::         
+
+Variables
+
+* Variables Introduction::      
+* Language-Types::              
+* NF90_DEF_VAR::                Create a Variable
+* NF90_DEF_VAR_FILL::           
+* NF90_INQ_VAR_FILL::           
+* NF90_INQUIRE_VARIABLE::       Get Var Metadata
+* NF90_INQ_VARID::              
+* NF90_PUT_VAR::                Write data
+* NF90_GET_VAR::                Read data
+* Reading and Writing Character String Values::  
+* Fill Values::                 What's Written Where there's No Data?
+* NF90_RENAME_VAR::             
+* NF90_VAR_PAR_ACCESS::         
+
+Attributes
+
+* Attributes Introduction::     
+* NF90_PUT_ATT::                
+* NF90_INQUIRE_ATTRIBUTE::      
+* NF90_GET_ATT::                
+* NF90_COPY_ATT::               
+* NF90_RENAME_ATT::             
+* NF90_DEL_ATT::                
+
+ at end detailmenu
+ at end menu
+
+ at node Use of the NetCDF Library, Datasets, Top, Top
+ at chapter Use of the NetCDF Library
+ at cindex users' guide, netcdf
+ at cindex common netcdf commands
+
+You can use the netCDF library without knowing about all of the netCDF
+interface. If you are creating a netCDF dataset, only a handful of
+routines are required to define the necessary dimensions, variables,
+and attributes, and to write the data to the netCDF dataset. (Even
+less are needed if you use the ncgen utility to create the dataset
+before running a program using netCDF library calls to write
+data. @xref{ncgen,,,netcdf, NetCDF Users Guide}.)
+Similarly, if you are writing software to access data stored in a
+particular netCDF object, only a small subset of the netCDF library is
+required to open the netCDF dataset and access the data. Authors of
+generic applications that access arbitrary netCDF datasets need to be
+familiar with more of the netCDF library.
+
+In this chapter we provide templates of common sequences of netCDF
+calls needed for common uses. For clarity we present only the names of
+routines; omit declarations and error checking; omit the type-specific
+suffixes of routine names for variables and attributes; indent
+statements that are typically invoked multiple times; and use ... to
+represent arbitrary sequences of other statements. Full parameter
+lists are described in later chapters.
+
+
+ at menu
+* Creating a NetCDF Dataset::   
+* Reading a NetCDF Dataset with Known Names::  
+* Reading a netCDF Dataset with Unknown Names::  
+* Writing Data in an Existing NetCDF Dataset::  
+* Adding New Dimensions::       
+* Error Handling::              
+* Compiling and Linking with the NetCDF Library::  
+ at end menu
+
+ at node Creating a NetCDF Dataset, Reading a NetCDF Dataset with Known Names, Use of the NetCDF Library, Use of the NetCDF Library
+ at section Creating a NetCDF Dataset
+ at cindex dataset, creating
+ at findex NF90_CREATE, typical use
+ at findex NF90_DEF_DIM, typical use
+ at findex NF90_DEF_VAR, typical use
+ at findex NF90_PUT_ATT, typical use
+ at findex NF90_ENDDEF, typical use
+ at findex NF90_PUT_VAR, typical use
+ at findex NF90_CLOSE, typical use
+
+Here is a typical sequence of netCDF calls used to create a new netCDF
+dataset: 
+
+ at example
+     NF90_CREATE           ! create netCDF dataset: enter define mode
+          ... 
+        NF90_DEF_DIM       ! define dimensions: from name and length
+          ... 
+        NF90_DEF_VAR       ! define variables: from name, type, dims
+          ... 
+        NF90_PUT_ATT       ! assign attribute values
+          ... 
+     NF90_ENDDEF           ! end definitions: leave define mode
+          ... 
+        NF90_PUT_VAR       ! provide values for variable
+          ... 
+     NF90_CLOSE            ! close: save new netCDF dataset
+ at end example
+
+Only one call is needed to create a netCDF dataset, at which point you
+will be in the first of two netCDF modes. When accessing an open
+netCDF dataset, it is either in define mode or data mode. In define
+mode, you can create dimensions, variables, and new attributes, but
+you cannot read or write variable data. In data mode, you can access
+data and change existing attributes, but you are not permitted to
+create new dimensions, variables, or attributes.
+
+One call to NF90_DEF_DIM is needed for each dimension
+created. Similarly, one call to NF90_DEF_VAR is needed for each
+variable creation, and one call to a member of the NF90_PUT_ATT family
+is needed for each attribute defined and assigned a value. To leave
+define mode and enter data mode, call NF90_ENDDEF.
+
+Once in data mode, you can add new data to variables, change old
+values, and change values of existing attributes (so long as the
+attribute changes do not require more storage space). Data of all
+types is written to a netCDF variable using the NF90_PUT_VAR
+subroutine. Single values, arrays, or array sections may be supplied
+to NF90_PUT_VAR; optional arguments allow the writing of subsampled or
+mapped portions of the variable. (Subsampled and mapped access are
+general forms of data access that are explained later.)
+
+Finally, you should explicitly close all netCDF datasets that have
+been opened for writing by calling NF90_CLOSE. By default, access to
+the file system is buffered by the netCDF library. If a program
+terminates abnormally with netCDF datasets open for writing, your most
+recent modifications may be lost. This default buffering of data is
+disabled by setting the NF90_SHARE flag when opening the dataset. But
+even if this flag is set, changes to attribute values or changes made
+in define mode are not written out until NF90_SYNC or NF90_CLOSE is
+called.
+
+
+ at node Reading a NetCDF Dataset with Known Names, Reading a netCDF Dataset with Unknown Names, Creating a NetCDF Dataset, Use of the NetCDF Library
+ at section Reading a NetCDF Dataset with Known Names
+ at findex NF90_OPEN, typical use
+ at findex NF90_INQ_DIMID, typical use
+ at findex NF90_INQ_VARID, typical use
+ at findex NF90_GET_ATT, typical use
+ at findex NF90_GET_VAR, typical use
+
+Here we consider the case where you know the names of not only the
+netCDF datasets, but also the names of their dimensions, variables,
+and attributes. (Otherwise you would have to do "inquire" calls.) The
+order of typical C calls to read data from those variables in a netCDF
+dataset is:
+
+ at example
+     NF90_OPEN               ! open existing netCDF dataset
+          ... 
+        NF90_INQ_DIMID       ! get dimension IDs
+          ... 
+        NF90_INQ_VARID       ! get variable IDs
+          ... 
+        NF90_GET_ATT         ! get attribute values
+          ... 
+        NF90_GET_VAR         ! get values of variables
+          ... 
+     NF90_CLOSE              ! close netCDF dataset
+ at end example
+
+First, a single call opens the netCDF dataset, given the dataset name,
+and returns a netCDF ID that is used to refer to the open netCDF
+dataset in all subsequent calls.
+
+Next, a call to NF90_INQ_DIMID for each dimension of interest gets the
+dimension ID from the dimension name. Similarly, each required
+variable ID is determined from its name by a call to
+NF90_INQ_VARID. Once variable IDs are known, variable attribute values
+can be retrieved using the netCDF ID, the variable ID, and the desired
+attribute name as input to NF90_GET_ATT for each desired
+attribute. Variable data values can be directly accessed from the
+netCDF dataset with calls to NF90_GET_VAR.
+
+Finally, the netCDF dataset is closed with NF90_CLOSE. There is no
+need to close a dataset open only for reading.
+
+ at node Reading a netCDF Dataset with Unknown Names, Writing Data in an Existing NetCDF Dataset, Reading a NetCDF Dataset with Known Names, Use of the NetCDF Library
+ at section Reading a netCDF Dataset with Unknown Names
+ at cindex reading dataset with unknown names
+ at findex NF90_INQUIRE, typical use
+ at findex NF90_INQUIRE_DIMENSION, typical use
+ at findex NF90_INQUIRE_VARIABLE, typical use
+ at findex NF90_INQUIRE_ATTRIBUTE, typical use
+ at findex NF90_INQ_ATTNAME, typical use
+ at findex NF90_GET_ATT, typical use
+
+It is possible to write programs (e.g., generic software) which do
+such things as processing every variable, without needing to know in
+advance the names of these variables. Similarly, the names of
+dimensions and attributes may be unknown.
+
+Names and other information about netCDF objects may be obtained from
+netCDF datasets by calling inquire functions. These return information
+about a whole netCDF dataset, a dimension, a variable, or an
+attribute. The following template illustrates how they are used:
+
+ at example
+     NF90_OPEN                 ! open existing netCDF dataset
+       ... 
+     NF90_INQUIRE              ! find out what is in it
+          ... 
+        NF90_INQUIRE_DIMENSION ! get dimension names, lengths
+          ... 
+        NF90_INQUIRE_VARIABLE  ! get variable names, types, shapes
+             ... 
+           NF90_INQ_ATTNAME    ! get attribute names
+             ... 
+           NF90_INQUIRE_ATTRIBUTE ! get other attribute information
+             ... 
+           NF90_GET_ATT        ! get attribute values
+             ... 
+        NF90_GET_VAR           ! get values of variables
+          ... 
+     NF90_CLOSE                ! close netCDF dataset
+ at end example
+
+As in the previous example, a single call opens the existing netCDF
+dataset, returning a netCDF ID. This netCDF ID is given to the
+NF90_INQUIRE routine, which returns the number of dimensions, the
+number of variables, the number of global attributes, and the ID of
+the unlimited dimension, if there is one.
+
+All the inquire functions are inexpensive to use and require no I/O,
+since the information they provide is stored in memory when a netCDF
+dataset is first opened.
+
+Dimension IDs use consecutive integers, beginning at 1. Also
+dimensions, once created, cannot be deleted. Therefore, knowing the
+number of dimension IDs in a netCDF dataset means knowing all the
+dimension IDs: they are the integers 1, 2, 3, ...up to the number of
+dimensions. For each dimension ID, a call to the inquire function
+NF90_INQUIRE_DIMENSION returns the dimension name and length.
+
+Variable IDs are also assigned from consecutive integers 1, 2, 3,
+... up to the number of variables. These can be used in
+NF90_INQUIRE_VARIABLE calls to find out the names, types, shapes, and
+the number of attributes assigned to each variable.
+
+Once the number of attributes for a variable is known, successive
+calls to NF90_INQ_ATTNAME return the name for each attribute given the
+netCDF ID, variable ID, and attribute number. Armed with the attribute
+name, a call to NF90_INQUIRE_ATTRIBUTE returns its type and
+length. Given the type and length, you can allocate enough space to
+hold the attribute values. Then a call to NF90_GET_ATT returns the
+attribute values.
+
+Once the IDs and shapes of netCDF variables are known, data values can
+be accessed by calling NF90_GET_VAR.
+
+ at node Writing Data in an Existing NetCDF Dataset, Adding New Dimensions, Reading a netCDF Dataset with Unknown Names, Use of the NetCDF Library
+ at section Writing Data in an Existing NetCDF Dataset 
+ at findex NF90_INQ_VARID, typical use
+ at findex NF90_PUT_VAR, typical use
+ at findex NF90_PUT_ATT, typical use
+ at cindex writing to existing dataset
+
+With write access to an existing netCDF dataset, you can overwrite
+data values in existing variables or append more data to record
+variables along the unlimited (record) dimension. To append more data
+to non-record variables requires changing the shape of such variables,
+which means creating a new netCDF dataset, defining new variables with
+the desired shape, and copying data. The netCDF data model was not
+designed to make such "schema changes" efficient or easy, so it is
+best to specify the shapes of variables correctly when you create a
+netCDF dataset, and to anticipate which variables will later grow by
+using the unlimited dimension in their definition.
+
+The following code template lists a typical sequence of calls to
+overwrite some existing values and add some new records to record
+variables in an existing netCDF dataset with known variable names:
+
+ at example
+     NF90_OPEN             ! open existing netCDF dataset
+       ... 
+       NF90_INQ_VARID      ! get variable IDs
+       ... 
+       NF90_PUT_VAR        ! provide new values for variables, if any
+       ... 
+       NF90_PUT_ATT        ! provide new values for attributes, if any
+         ... 
+     NF90_CLOSE            ! close netCDF dataset
+ at end example
+
+A netCDF dataset is first opened by the NF90_OPEN call. This call puts
+the open dataset in data mode, which means existing data values can be
+accessed and changed, existing attributes can be changed, but no new
+dimensions, variables, or attributes can be added.
+
+Next, calls to NF90_INQ_VARID get the variable ID from the name, for
+each variable you want to write. Then each call to NF90_PUT_VAR writes
+data into a specified variable, either a single value at a time, or a
+whole set of values at a time, depending on which variant of the
+interface is used. The calls used to overwrite values of non-record
+variables are the same as are used to overwrite values of record
+variables or append new data to record variables. The difference is
+that, with record variables, the record dimension is extended by
+writing values that don't yet exist in the dataset. This extends all
+record variables at once, writing "fill values" for record variables
+for which the data has not yet been written (but @pxref{Fill Values}
+to specify different behavior).
+
+Calls to NF90_PUT_ATT may be used to change the values of existing
+attributes, although data that changes after a file is created is
+typically stored in variables rather than attributes.
+
+Finally, you should explicitly close any netCDF datasets into which
+data has been written by calling NF90_CLOSE before program
+termination. Otherwise, modifications to the dataset may be lost.
+
+ at node Adding New Dimensions, Error Handling, Writing Data in an Existing NetCDF Dataset, Use of the NetCDF Library
+ at section Adding New Dimensions, Variables, Attributes
+ at cindex dimensions, adding
+ at cindex variables, adding
+ at cindex attributes, adding
+ at findex NF90_REDEF, typical use
+
+An existing netCDF dataset can be extensively altered. New dimensions,
+variables, and attributes can be added or existing ones renamed, and
+existing attributes can be deleted. Existing dimensions, variables,
+and attributes can be renamed. The following code template lists a
+typical sequence of calls to add new netCDF components to an existing
+dataset:
+
+ at example
+     NF90_OPEN             ! open existing netCDF dataset
+       ... 
+     NF90_REDEF            ! put it into define mode
+         ... 
+       NF90_DEF_DIM        ! define additional dimensions (if any)
+         ... 
+       NF90_DEF_VAR        ! define additional variables (if any)
+         ... 
+       NF90_PUT_ATT        ! define other attributes (if any)
+         ... 
+     NF90_ENDDEF           ! check definitions, leave define mode
+         ... 
+       NF90_PUT_VAR        ! provide new variable values
+         ... 
+     NF90_CLOSE            ! close netCDF dataset
+ at end example
+
+A netCDF dataset is first opened by the NF90_OPEN call. This call puts
+the open dataset in data mode, which means existing data values can be
+accessed and changed, existing attributes can be changed (so long as
+they do not grow), but nothing can be added. To add new netCDF
+dimensions, variables, or attributes you must enter define mode, by
+calling NF90_REDEF. In define mode, call NF90_DEF_DIM to define new
+dimensions, NF90_DEF_VAR to define new variables, and NF90_PUT_ATT to
+assign new attributes to variables or enlarge old attributes.
+
+You can leave define mode and reenter data mode, checking all the new
+definitions for consistency and committing the changes to disk, by
+calling NF90_ENDDEF. If you do not wish to reenter data mode, just
+call NF90_CLOSE, which will have the effect of first calling
+NF90_ENDDEF.
+
+Until the NF90_ENDDEF call, you may back out of all the redefinitions
+made in define mode and restore the previous state of the netCDF
+dataset by calling NF90_ABORT. You may also use the NF90_ABORT call to
+restore the netCDF dataset to a consistent state if the call to
+NF90_ENDDEF fails. If you have called NF90_CLOSE from definition mode
+and the implied call to NF90_ENDDEF fails, NF90_ABORT will
+automatically be called to close the netCDF dataset and leave it in
+its previous consistent state (before you entered define mode).
+
+At most one process should have a netCDF dataset open for writing at
+one time. The library is designed to provide limited support for
+multiple concurrent readers with one writer, via disciplined use of
+the NF90_SYNC function and the NF90_SHARE flag. If a writer makes
+changes in define mode, such as the addition of new variables,
+dimensions, or attributes, some means external to the library is
+necessary to prevent readers from making concurrent accesses and to
+inform readers to call NF90_SYNC before the next access.
+
+ at node Error Handling, Compiling and Linking with the NetCDF Library, Adding New Dimensions, Use of the NetCDF Library
+ at section Error Handling
+ at cindex error handling
+ at findex NF90_STRERROR, introduction
+
+The netCDF library provides the facilities needed to handle errors in
+a flexible way. Each netCDF function returns an integer status
+value. If the returned status value indicates an error, you may handle
+it in any way desired, from printing an associated error message and
+exiting to ignoring the error indication and proceeding (not
+recommended!). For simplicity, the examples in this guide check the
+error status and call a separate function to handle any errors.
+
+The NF90_STRERROR function is available to convert a returned integer
+error status into an error message string.
+
+Occasionally, low-level I/O errors may occur in a layer below the
+netCDF library. For example, if a write operation causes you to exceed
+disk quotas or to attempt to write to a device that is no longer
+available, you may get an error from a layer below the netCDF library,
+but the resulting write error will still be reflected in the returned
+status value.
+
+ at node Compiling and Linking with the NetCDF Library,  , Error Handling, Use of the NetCDF Library
+ at section Compiling and Linking with the NetCDF Library
+ at cindex linking to netCDF library
+ at cindex compiling with netCDF library
+ at cindex nf-config
+
+Details of how to compile and link a program that uses the netCDF C or
+Fortran interfaces differ, depending on the operating system, the
+available compilers, and where the netCDF library and include files
+are installed. Nevertheless, we provide here examples of how to
+compile and link a program that uses the netCDF library on a Unix
+platform, so that you can adjust these examples to fit your
+installation.
+
+Every Fortran 90 procedure or module which references netCDF constants
+or procedures must have access to the module information created when
+the netCDF module was compiled. The suffix for this file is ``MOD''
+(or sometimes ``mod''). 
+
+Most F90 compilers allow the user to specify the location of .MOD
+files, usually with the -I flag.
+
+ at example
+f90 -c -I/usr/local/include mymodule.f90
+ at end example
+
+Starting with version 3.6.2, another method of building the netCDF
+fortran libraries became available. With the --enable-separate-fortran
+option to configure, the user can specify that the C library should
+not contain the fortran functions. In these cases an additional
+library, libnetcdff.a (note the extra ``f'') will be built. This
+library contains the Fortran functions.  Since verion 4.1.3, the
+netCDF Fortran software and library is always distinct from the netCDF
+C library, but depends on it.  If it is installed as a shared library,
+you need only use `-lnetcdff' to specify the Fortran library for
+linking.
+
+For more information about configure options, @xref{Specifying the
+Environment for Building,,, netcdf-install, @value{i-man}}.
+
+If installed as a shared library, link, using something like:
+
+ at example
+f90 -o myprogram myprogram.o -L/usr/local/lib -lnetcdff
+ at end example
+
+If installed as a static library, you will at least need to mention
+the netCDF C library and perhaps other libraries, such as hdf5 or
+curl, depending on how the C library was built.  For example:
+
+ at example
+f90 -o myprogram myprogram.o -L/usr/local/lib -lnetcdff -lnetcdf
+ at end example
+
+Use of the nf-config utility program, installed as part of the
+netcdf-fortran software, provides an easier way to compile and link,
+without needing to know the details of where the library has been
+installed, or whether it is installed as a shared or static library.
+
+To see all the options for `nf-config', invoke it with the `--help'
+argument. 
+
+Here's an example of how you could use `nf-config' to compile and link
+a Fortran program in one step:
+
+ at example
+f90 myprogram.f90 -o myprogram `nf-config --fflags --flibs`
+ at end example
+
+If it is installed on your system, you could also use the `pkg-config'
+utility to compile and link Fortran programs with the netCDF
+libraries.  This is especially useful in Makefiles, to insulate them
+from changes to library versions and dependencies.  Here is an example
+of how you could compile and link a Fortran program with netCDF
+libraries using pkg-config:
+
+ at example
+export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
+f90 myprogram.f90 -o myprogram `pkg-config --cflags --libs netcdf-fortran`
+ at end example
+
+where here `--cflags' means compiler flags and `libs' requests that
+the approriate libraries be linked in.
+
+ at node Datasets, Groups, Use of the NetCDF Library, Top
+ at chapter Datasets
+
+ at menu
+* Datasets Introduction::       
+* NetCDF Library Interface Descriptions::  
+* NF90_STRERROR::               
+* NF90_INQ_LIBVERS::            
+* NF90_CREATE::                 
+* NF90_OPEN::                   
+* NF90_REDEF::                  
+* NF90_ENDDEF::                 
+* NF90_CLOSE::                  
+* NF90_INQUIRE Family::         
+* NF90_SYNC::                   
+* NF90_ABORT::                  
+* NF90_SET_FILL::               
+ at end menu
+
+ at node Datasets Introduction, NetCDF Library Interface Descriptions, Datasets, Datasets
+ at section Datasets Introduction
+ at cindex datasets, overview
+
+This chapter presents the interfaces of the netCDF functions that deal
+with a netCDF dataset or the whole netCDF library.
+
+A netCDF dataset that has not yet been opened can only be referred to
+by its dataset name. Once a netCDF dataset is opened, it is referred
+to by a netCDF ID, which is a small nonnegative integer returned when
+you create or open the dataset. A netCDF ID is much like a file
+descriptor in C or a logical unit number in FORTRAN. In any single
+program, the netCDF IDs of distinct open netCDF datasets are
+distinct. A single netCDF dataset may be opened multiple times and
+will then have multiple distinct netCDF IDs; however at most one of
+the open instances of a single netCDF dataset should permit
+writing. When an open netCDF dataset is closed, the ID is no longer
+associated with a netCDF dataset.
+
+Functions that deal with the netCDF library include:
+ at itemize
+
+ at item
+Get version of library. 
+
+ at item
+Get error message corresponding to a returned error code. 
+ at end itemize
+
+The operations supported on a netCDF dataset as a single object are:
+ at itemize
+
+ at item
+Create, given dataset name and whether to overwrite or not. 
+
+ at item
+Open for access, given dataset name and read or write intent. 
+
+ at item
+Put into define mode, to add dimensions, variables, or attributes.
+
+ at item
+Take out of define mode, checking consistency of additions. 
+
+ at item
+Close, writing to disk if required. 
+
+ at item
+Inquire about the number of dimensions, number of variables, number of
+global attributes, and ID of the unlimited dimension, if any.
+
+ at item
+Synchronize to disk to make sure it is current. 
+
+ at item
+Set and unset nofill mode for optimized sequential writes. 
+
+ at item
+After a summary of conventions used in describing the netCDF
+interfaces, the rest of this chapter presents a detailed description
+of the interfaces for these operations.
+ at end itemize
+
+ at node NetCDF Library Interface Descriptions, NF90_STRERROR, Datasets Introduction, Datasets
+ at section NetCDF Library Interface Descriptions
+ at cindex interface descriptions
+
+Each interface description for a particular netCDF function in this
+and later chapters contains:
+
+ at itemize
+
+ at item
+a description of the purpose of the function; 
+
+ at item
+a Fortran 90 interface block that presents the type and order of the
+formal parameters to the function;
+
+ at item
+a description of each formal parameter in the C interface; 
+
+ at item
+a list of possible error conditions; and 
+
+ at item
+an example of a Fortran 90 program fragment calling the netCDF
+function (and perhaps other netCDF functions).
+ at end itemize
+
+The examples follow a simple convention for error handling, always
+checking the error status returned from each netCDF function call and
+calling a handle_error function in case an error was detected. For an
+example of such a function, see Section 5.2 "Get error message
+corresponding to error status: nf90_strerror".
+
+ at node NF90_STRERROR, NF90_INQ_LIBVERS, NetCDF Library Interface Descriptions, Datasets
+ at section NF90_STRERROR
+ at findex NF90_STRERROR
+ at cindex NF90_STRERROR, example
+
+The function NF90_STRERROR returns a static reference to an error
+message string corresponding to an integer netCDF error status or to a
+system error number, presumably returned by a previous call to some
+other netCDF function. The list of netCDF error status codes is
+available in the appropriate include file for each language binding.
+
+ at heading Usage
+ at example
+ function nf90_strerror(ncerr)
+   integer, intent( in) :: ncerr
+   character(len = 80)  :: nf90_strerror
+ at end example
+
+ at table @code
+ at item NCERR
+An error status that might have been returned from a previous call to
+some netCDF function.
+ at end table
+
+ at heading Errors 
+
+If you provide an invalid integer error status that does not
+correspond to any netCDF error message or or to any system error
+message (as understood by the system strerror function), NF90_STRERROR
+returns a string indicating that there is no such error status.
+
+ at heading Example 
+
+Here is an example of a simple error handling function that uses
+NF90_STRERROR to print the error message corresponding to the netCDF
+error status returned from any netCDF function call and then exit:
+
+ at example
+ subroutine handle_err(status)
+   integer, intent ( in) :: status
+   
+   if(status /= nf90_noerr) then
+     print *, trim(nf90_strerror(status))
+     stop "Stopped"
+   end if
+ end subroutine handle_err
+ at end example
+
+ at node NF90_INQ_LIBVERS, NF90_CREATE, NF90_STRERROR, Datasets
+ at section Get netCDF library version: NF90_INQ_LIBVERS
+ at findex NF90_INQ_LIBVERS
+ at cindex NF90_INQ_LIBVERS, example
+
+The function NF90_INQ_LIBVERS returns a string identifying the version
+of the netCDF library, and when it was built.
+
+ at heading Usage 
+ at example
+ function nf90_inq_libvers()
+   character(len = 80) :: nf90_inq_libvers
+ at end example
+
+ at heading Errors 
+
+This function takes no arguments, and returns no error status. 
+
+ at heading Example 
+
+Here is an example using nf90_inq_libvers to print the version of the
+netCDF library with which the program is linked:
+
+ at example
+ print *, trim(nf90_inq_libvers())
+ at end example
+
+ at node NF90_CREATE, NF90_OPEN, NF90_INQ_LIBVERS, Datasets
+ at section NF90_CREATE 
+ at findex NF90_CREATE 
+ at cindex NF90_CREATE , example
+
+This function creates a new netCDF dataset, returning a netCDF ID that
+can subsequently be used to refer to the netCDF dataset in other
+netCDF function calls. The new netCDF dataset opened for write access
+and placed in define mode, ready for you to add dimensions, variables,
+and attributes.
+
+A creation mode flag specifies whether to overwrite any existing
+dataset with the same name and whether access to the dataset is
+shared.
+
+ at heading Usage 
+
+ at example
+  function nf90_create(path, cmode, ncid, initialsize, bufrsize, cache_size, &
+       cache_nelems, cache_preemption, comm, info)
+    implicit none
+    character (len = *), intent(in) :: path
+    integer, intent(in) :: cmode
+    integer, intent(out) :: ncid
+    integer, optional, intent(in) :: initialsize
+    integer, optional, intent(inout) :: bufrsize
+    integer, optional, intent(in) :: cache_size, cache_nelems
+    real, optional, intent(in) :: cache_preemption
+    integer, optional, intent(in) :: comm, info
+    integer :: nf90_create
+ at end example
+
+ at table @code
+ at item path
+The file name of the new netCDF dataset.
+ 
+ at item cmode
+The creation mode flag. The following flags are available:
+NF90_CLOBBER, NF90_NOCLOBBER, NF90_SHARE, NF90_64BIT_OFFSET, NF90_NETCDF4, and
+NF90_CLASSIC_MODEL.  (NF90_HDF5 is deprecated, use NF90_NETCDF4 instead).
+
+A zero value (defined for convenience as NF90_CLOBBER) specifies: overwrite any existing dataset with the same file
+name, and buffer and cache accesses for efficiency. The dataset will be
+in netCDF classic format. @xref{NetCDF Classic Format Limitations,,,
+netcdf, NetCDF Users' Guide}.
+
+Setting NF90_NOCLOBBER means you do not want to clobber (overwrite) an
+existing dataset; an error (NF90_EEXIST) is returned if the specified
+dataset already exists.
+
+The NF90_SHARE flag is appropriate when one process may be writing the
+dataset and one or more other processes reading the dataset
+concurrently; it means that dataset accesses are not buffered and
+caching is limited. Since the buffering scheme is optimized for
+sequential access, programs that do not access data sequentially may
+see some performance improvement by setting the NF90_SHARE flag. (This
+only applies to netCDF-3 classic or 64-bit offset files.)
+
+Setting NF90_64BIT_OFFSET causes netCDF to create a 64-bit offset format
+file, instead of a netCDF classic format file. The 64-bit offset
+format imposes far fewer restrictions on very large (i.e. over 2 GB)
+data files. @xref{Large File Support,,, netcdf, NetCDF Users' Guide}.
+
+Setting the NF90_NETCDF4 flag causes netCDF to create a netCDF-4/HDF5
+format output file.
+
+Oring the NF90_CLASSIC_MODEL flag with the NF90_NETCDF4 flag causes the
+resulting netCDF-4/HDF5 file to restrict itself to the classic model -
+none of the new netCDF-4 data model features, such as groups or
+user-defined types, are allowed in such a file.
+
+ at item ncid
+Returned netCDF ID.
+ at end table
+
+The following optional arguments allow additional performance tuning.
+
+ at table @code
+
+ at item initialsize
+The initial size of the file (in bytes) at creation time. A value of 0
+causes the file size to be computed when nf90_enddef is called. This
+is ignored for NetCDF-4/HDF5 files.
+
+ at item bufrsize
+Controls a space versus time trade-off, memory allocated in the netcdf
+library versus number of system calls. Because of internal
+requirements, the value may not be set to exactly the value
+requested. The actual value chosen is returned.
+
+The library chooses a system-dependent default value if
+NF90_SIZEHINT_DEFAULT is supplied as input. If the "preferred I/O
+block size" is available from the stat() system call as member
+st_blksize this value is used. Lacking that, twice the system pagesize
+is used. Lacking a call to discover the system pagesize, the default
+bufrsize is set to 8192 bytes.
+
+The bufrsize is a property of a given open netcdf descriptor ncid, it
+is not a persistent property of the netcdf dataset. 
+
+This is ignored for NetCDF-4/HDF5 files.
+
+ at item cache_size
+If the cache_size is provided when creating a netCDF-4/HDF5 file, it
+will be used instead of the default (32000000) as the size, in bytes,
+of the HDF5 chunk cache.
+
+ at item cache_nelems
+If cache_nelems is provided when creating a netCDF-4/HDF5 file, it
+will be used instead of the default (1000) as the maximum number of
+elements in the HDF5 chunk cache.
+
+ at item cache_premtion
+If cache_preemption is provided when creating a netCDF-4/HDF5 file, it
+will be used instead of the default (0.75) as the preemption value for
+the HDF5 chunk cache.
+
+ at item comm
+If the comm and info parameters are provided the file is created and
+opened for parallel I/O. Set the comm parameter to the MPI
+communicator (of type MPI_Comm). If this parameter is provided the
+info parameter must also be provided.
+
+ at item info
+If the comm and info parameters are provided the file is created and
+opened for parallel I/O. Set the comm parameter to the MPI information
+value (of type MPI_Info). If this parameter is provided the comm
+parameter must also be provided.
+
+ at end table
+
+ at heading Errors 
+NF90_CREATE returns the value NF90_NOERR if no errors occurred. Possible
+causes of errors include:
+ at itemize
+
+ at item
+Passing a dataset name that includes a directory that does not exist.
+ at item
+Specifying a dataset name of a file that exists and also specifying
+NF90_NOCLOBBER.
+ at item
+Specifying a meaningless value for the creation mode.
+ at item
+Attempting to create a netCDF dataset in a directory where you don't
+have permission to create files.
+ at end itemize
+
+ at heading Example 
+
+In this example we create a netCDF dataset named foo.nc; we want the
+dataset to be created in the current directory only if a dataset with
+that name does not already exist:
+
+ at example
+ use netcdf
+ implicit none
+ integer :: ncid, status
+ ...
+ status = nf90_create(path = "foo.nc", cmode = nf90_noclobber, ncid = ncid)
+ if (status /= nf90_noerr) call handle_err(status)
+ at end example
+
+ at node NF90_OPEN, NF90_REDEF, NF90_CREATE, Datasets
+ at section NF90_OPEN 
+ at findex NF90_OPEN 
+ at cindex NF90_OPEN , example
+
+The function NF90_OPEN opens an existing netCDF dataset for access.
+
+ at heading Usage 
+
+ at example
+  function nf90_open(path, mode, ncid, bufrsize, cache_size, cache_nelems, &
+                     cache_preemption, comm, info)
+    implicit none
+    character (len = *), intent(in) :: path
+    integer, intent(in) :: mode
+    integer, intent(out) :: ncid
+    integer, optional, intent(inout) :: bufrsize
+    integer, optional, intent(in) :: cache_size, cache_nelems
+    real, optional, intent(in) :: cache_preemption
+    integer, optional, intent(in) :: comm, info
+    integer :: nf90_open
+ at end example
+
+ at table @code
+
+ at item path
+File name for netCDF dataset to be opened.
+This may be an OPeNDAP URL if DAP support is enabled.
+ 
+ at item mode
+A zero value (or NF90_NOWRITE) specifies: open the
+dataset with read-only access, buffering and caching accesses for
+efficiency
+
+Otherwise, the open mode is NF90_WRITE, NF90_SHARE, or
+NF90_WRITE|NF90_SHARE. Setting the NF90_WRITE flag opens the dataset
+with read-write access. ("Writing" means any kind of change to the
+dataset, including appending or changing data, adding or renaming
+dimensions, variables, and attributes, or deleting attributes.) The
+NF90_SHARE flag is appropriate when one process may be writing the
+dataset and one or more other processes reading the dataset
+concurrently (note that this is not the same as parallel I/O); it
+means that dataset accesses are not buffered and caching is
+limited. Since the buffering scheme is optimized for sequential
+access, programs that do not access data sequentially may see some
+performance improvement by setting the NF90_SHARE flag.
+ 
+ at item ncid
+Returned netCDF ID.
+ at end table
+
+The following optional argument allows additional performance tuning.
+
+ at table @code
+
+ at item bufrsize
+This parameter applies only when opening classic format or 64-bit
+offset files. It is ignored for netCDF-4/HDF5 files. 
+
+It Controls a space versus time trade-off, memory allocated in the netcdf
+library versus number of system calls. Because of internal
+requirements, the value may not be set to exactly the value
+requested. The actual value chosen is returned.
+
+The library chooses a system-dependent default value if
+NF90_SIZEHINT_DEFAULT is supplied as input. If the "preferred I/O
+block size" is available from the stat() system call as member
+st_blksize this value is used. Lacking that, twice the system pagesize
+is used. Lacking a call to discover the system pagesize, the default
+bufrsize is set to 8192 bytes.
+
+The bufrsize is a property of a given open netcdf descriptor ncid, it
+is not a persistent property of the netcdf dataset.
+
+ at item cache_size
+If the cache_size is provided when opening a netCDF-4/HDF5 file, it
+will be used instead of the default (32000000) as the size, in bytes,
+of the HDF5 chunk cache.
+
+ at item cache_nelems
+If cache_nelems is provided when opening a netCDF-4/HDF5 file, it
+will be used instead of the default (1000) as the maximum number of
+elements in the HDF5 chunk cache.
+
+ at item cache_premtion
+If cache_preemption is provided when opening a netCDF-4/HDF5 file, it
+will be used instead of the default (0.75) as the preemption value
+for the HDF5 chunk cache.
+
+ at item comm
+If the comm and info parameters are provided the file is opened for
+parallel I/O. Set the comm parameter to the MPI communicator (of type
+MPI_Comm). If this parameter is provided the info parameter must also
+be provided.
+
+ at item info
+If the comm and info parameters are provided the file is opened for
+parallel I/O. Set the comm parameter to the MPI information value (of
+type MPI_Info). If this parameter is provided the comm parameter must
+also be provided.
+
+ at end table
+
+ at heading Errors 
+
+NF90_OPEN returns the value NF90_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+ at itemize
+
+ at item
+The specified netCDF dataset does not exist. 
+ at item
+A meaningless mode was specified. 
+ at end itemize
+
+ at heading Example 
+Here is an example using NF90_OPEN to open an existing netCDF dataset
+named foo.nc for read-only, non-shared access:
+
+ at example
+ use netcdf
+ implicit none
+ integer :: ncid, status
+ ...
+ status = nf90_open(path = "foo.nc", mode = nf90_nowrite, ncid = ncid)
+ if (status /= nf90_noerr) call handle_err(status)
+ at end example
+
+ at heading Example 
+Here is an example using NF90_OPEN to open an existing netCDF dataset
+for parallel I/O access. (Note the use of the comm and info
+parameters). This example is from test program
+nf_test/f90tst_parallel.f90.
+
+ at example
+ use netcdf
+ implicit none
+ integer :: ncid, status
+ ...
+  ! Reopen the file.
+  call handle_err(nf90_open(FILE_NAME, nf90_nowrite, ncid, comm = MPI_COMM_WORLD, &
+       info = MPI_INFO_NULL))
+ at end example
+
+ at node NF90_REDEF, NF90_ENDDEF, NF90_OPEN, Datasets
+ at section NF90_REDEF 
+ at findex NF90_REDEF 
+ at cindex NF90_REDEF , example
+
+The function NF90_REDEF puts an open netCDF dataset into define mode, so
+dimensions, variables, and attributes can be added or renamed and
+attributes can be deleted.
+
+ at heading Usage 
+
+ at example
+ function nf90_redef(ncid)
+   integer, intent( in) :: ncid
+   integer              :: nf90_redef
+ at end example
+
+ at table @code
+ at item ncid
+netCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
+ at end table
+
+ at heading Errors 
+NF90_REDEF returns the value NF90_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+ at itemize
+
+ at item
+The specified netCDF dataset is already in define mode. 
+
+ at item
+The specified netCDF dataset was opened for read-only. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+ at end itemize
+
+ at heading Example 
+Here is an example using NF90_REDEF to open an existing netCDF dataset
+named foo.nc and put it into define mode:
+
+ at example
+ use netcdf
+ implicit none
+ integer :: ncid, status
+ ...
+ status = nf90_open("foo.nc", nf90_write, ncid) ! Open dataset
+ if (status /= nf90_noerr) call handle_err(status)
+ ...
+ status = nf90_redef(ncid)                       ! Put the file in define mode
+ if (status /= nf90_noerr) call handle_err(status)
+ at end example
+
+ at node NF90_ENDDEF, NF90_CLOSE, NF90_REDEF, Datasets
+ at section NF90_ENDDEF 
+ at findex NF90_ENDDEF 
+ at cindex NF90_ENDDEF , example
+
+The function NF90_ENDDEF takes an open netCDF dataset out of define
+mode. The changes made to the netCDF dataset while it was in define
+mode are checked and committed to disk if no problems
+occurred. Non-record variables may be initialized to a "fill value" as
+well (@pxref{NF90_SET_FILL}). The netCDF dataset is then placed in
+data mode, so variable data can be read or written.
+
+This call may involve copying data under some circumstances. For a
+more extensive discussion @xref{File Structure and
+Performance,,,netcdf, NetCDF Users Guide}.
+
+ at heading Usage 
+
+ at example
+ function nf90_enddef(ncid, h_minfree, v_align, v_minfree, r_align)
+   integer,           intent( in) :: ncid
+   integer, optional, intent( in) :: h_minfree, v_align, v_minfree, r_align
+   integer                        :: nf90_enddef
+ at end example
+
+ at table @code
+ at item ncid
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
+ at end table
+
+The following arguments allow additional performance tuning. Note:
+these arguments expose internals of the netcdf version 1 file format,
+and may not be available in future netcdf implementations.
+
+The current netcdf file format has three sections: the "header"
+section, the data section for fixed size variables, and the data
+section for variables which have an unlimited dimension (record
+variables). The header begins at the beginning of the file. The index
+(offset) of the beginning of the other two sections is contained in
+the header. Typically, there is no space between the sections. This
+causes copying overhead to accrue if one wishes to change the size of
+the sections, as may happen when changing the names of things, text
+attribute values, adding attributes or adding variables. Also, for
+buffered i/o, there may be advantages to aligning sections in certain
+ways.
+
+The minfree parameters allow one to control costs of future calls to
+nf90_redef or nf90_enddef by requesting that some space be available
+at the end of the section. The default value for both h_minfree and
+v_minfree is 0.
+
+The align parameters allow one to set the alignment of the beginning
+of the corresponding sections. The beginning of the section is rounded
+up to an index which is a multiple of the align parameter. The flag
+value NF90_ALIGN_CHUNK tells the library to use the bufrsize (see
+above) as the align parameter. The default value for both v_align and
+r_align is 4 bytes.
+
+ at table @code
+
+ at item h_minfree
+Size of the pad (in bytes) at the end of the "header" section.
+
+ at item v_minfree
+Size of the pad (in bytes) at the end of the data section for fixed
+size variables.
+
+ at item v_align
+The alignment of the beginning of the data section for fixed size
+variables.
+
+ at item r_align
+The alignment of the beginning of the data section for variables which
+have an unlimited dimension (record variables). 
+
+ at end table
+
+ at heading Errors 
+
+NF90_ENDDEF returns the value NF90_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+ at itemize
+
+ at item
+The specified netCDF dataset is not in define mode. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset.
+
+ at item
+The size of one or more variables exceed the size constraints for
+whichever variant of the file format is in use).
+ at xref{Large File Support,,, netcdf, @value{n-man}}.
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF90_ENDDEF to finish the definitions of a new
+netCDF dataset named foo.nc and put it into data mode:
+
+ at example
+ use netcdf
+ implicit none
+ integer :: ncid, status
+ ...
+ status = nf90_create("foo.nc", nf90_noclobber, ncid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ ...  !  create dimensions, variables, attributes
+ status = nf90_enddef(ncid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ at end example
+
+ at node NF90_CLOSE, NF90_INQUIRE Family, NF90_ENDDEF, Datasets
+ at section NF90_CLOSE 
+ at findex NF90_CLOSE 
+ at cindex NF90_CLOSE , example
+
+The function NF90_CLOSE closes an open netCDF dataset. If the dataset is
+in define mode, NF90_ENDDEF will be called before closing. (In this
+case, if NF90_ENDDEF returns an error, NF90_ABORT will automatically be
+called to restore the dataset to the consistent state before define
+mode was last entered.) After an open netCDF dataset is closed, its
+netCDF ID may be reassigned to the next netCDF dataset that is opened
+or created.
+
+ at heading Usage 
+ at example
+ function nf90_close(ncid)
+   integer, intent( in) :: ncid
+   integer              :: nf90_close
+ at end example
+
+ at table @code
+ at item ncid
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
+ at end table
+
+ at heading Errors 
+
+NF90_CLOSE returns the value NF90_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+ at itemize
+
+ at item
+Define mode was entered and the automatic call made to NF90_ENDDEF
+failed.
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset.
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF90_CLOSE to finish the definitions of a new
+netCDF dataset named foo.nc and release its netCDF ID:
+
+ at example
+ use netcdf
+ implicit none
+ integer :: ncid, status
+ ...
+ status = nf90_create("foo.nc", nf90_noclobber, ncid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ ...  !  create dimensions, variables, attributes
+ status = nf90_close(ncid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ at end example
+
+ at node NF90_INQUIRE Family, NF90_SYNC, NF90_CLOSE, Datasets
+ at section NF90_INQUIRE Family
+
+The NF90_INQUIRE subroutine returns information about an open netCDF
+dataset, given its netCDF ID. The subroutine can be called from either
+define mode or data mode, and returns values for any or all of the
+following: the number of dimensions, the number of variables, the
+number of global attributes, and the dimension ID of the dimension
+defined with unlimited length, if any.    An additional function,
+NF90_INQ_FORMAT, returns the (rarely needed) format version.
+
+No I/O is performed when NF90_INQUIRE is called, since the required
+information is available in memory for each open netCDF dataset.
+
+ at heading Usage 
+ at example
+ function nf90_inquire(ncid, nDimensions, nVariables, nAttributes, &
+                       unlimitedDimId, formatNum)
+   integer,           intent( in) :: ncid
+   integer, optional, intent(out) :: nDimensions, nVariables, &
+                                     nAttributes, unlimitedDimId, &
+                                     formatNum
+   integer                        :: nf90_inquire
+ at end example
+
+ at table @code
+ at item ncid
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
+ 
+ at item nDimensions
+Returned number of dimensions defined for this netCDF dataset.
+ 
+ at item nVariables
+Returned number of variables defined for this netCDF dataset.
+ 
+ at item nAttributes
+Returned number of global attributes defined for this netCDF dataset.
+ 
+ at item unlimitedDimID
+Returned ID of the unlimited dimension, if there is one for this
+netCDF dataset. If no unlimited length dimension has been defined, -1
+is returned.
+
+ at item format
+Returned integer indicating format version for this dataset, one of
+nf90_format_classic,
+nf90_format_64bit,
+nf90_format_netcdf4, or
+nf90_format_netcdf4_classic.  These are rarely needed by users or
+applications, since thhe library recognizes the format of a file it is
+accessing and handles it accordingly.
+ at end table
+
+ at heading Errors 
+
+Function NF90_INQUIRE returns the value NF90_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF90_INQUIRE to find out about a netCDF dataset
+named foo.nc:
+
+ at example
+ use netcdf
+ implicit none
+ integer :: ncid, status, nDims, nVars, nGlobalAtts, unlimDimID
+ ...
+ status = nf90_open("foo.nc", nf90_nowrite, ncid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ ...  
+ status = nf90_inquire(ncid, nDims, nVars, nGlobalAtts, unlimdimid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ status = nf90_inquire(ncid, nDimensions = nDims, &
+                       unlimitedDimID = unlimdimid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ at end example
+
+ at node NF90_SYNC, NF90_ABORT, NF90_INQUIRE Family, Datasets
+ at section NF90_SYNC 
+ at findex NF90_SYNC 
+ at cindex NF90_SYNC , example
+
+The function NF90_SYNC offers a way to synchronize the disk copy of a
+netCDF dataset with in-memory buffers. There are two reasons you might
+want to synchronize after writes:
+ at itemize
+
+ at item
+To minimize data loss in case of abnormal termination, or 
+
+ at item
+To make data available to other processes for reading immediately
+after it is written. But note that a process that already had the
+dataset open for reading would not see the number of records increase
+when the writing process calls NF90_SYNC; to accomplish this, the
+reading process must call NF90_SYNC.
+ at end itemize
+
+This function is backward-compatible with previous versions of the
+netCDF library. The intent was to allow sharing of a netCDF dataset
+among multiple readers and one writer, by having the writer call
+NF90_SYNC after writing and the readers call NF90_SYNC before each
+read. For a writer, this flushes buffers to disk. For a reader, it
+makes sure that the next read will be from disk rather than from
+previously cached buffers, so that the reader will see changes made by
+the writing process (e.g., the number of records written) without
+having to close and reopen the dataset. If you are only accessing a
+small amount of data, it can be expensive in computer resources to
+always synchronize to disk after every write, since you are giving up
+the benefits of buffering.
+
+An easier way to accomplish sharing (and what is now recommended) is
+to have the writer and readers open the dataset with the NF90_SHARE
+flag, and then it will not be necessary to call NF90_SYNC at
+all. However, the NF90_SYNC function still provides finer granularity
+than the NF90_SHARE flag, if only a few netCDF accesses need to be
+synchronized among processes.
+
+It is important to note that changes to the ancillary data, such as
+attribute values, are not propagated automatically by use of the
+NF90_SHARE flag. Use of the NF90_SYNC function is still required for
+this purpose.
+
+Sharing datasets when the writer enters define mode to change the data
+schema requires extra care. In previous releases, after the writer
+left define mode, the readers were left looking at an old copy of the
+dataset, since the changes were made to a new copy. The only way
+readers could see the changes was by closing and reopening the
+dataset. Now the changes are made in place, but readers have no
+knowledge that their internal tables are now inconsistent with the new
+dataset schema. If netCDF datasets are shared across redefinition,
+some mechanism external to the netCDF library must be provided that
+prevents access by readers during redefinition and causes the readers
+to call NF90_SYNC before any subsequent access.
+
+When calling NF90_SYNC, the netCDF dataset must be in data mode. A
+netCDF dataset in define mode is synchronized to disk only when
+NF90_ENDDEF is called. A process that is reading a netCDF dataset that
+another process is writing may call NF90_SYNC to get updated with the
+changes made to the data by the writing process (e.g., the number of
+records written), without having to close and reopen the dataset.
+
+Data is automatically synchronized to disk when a netCDF dataset is
+closed, or whenever you leave define mode.
+
+ at heading Usage 
+ at example
+ function nf90_sync(ncid)
+   integer, intent( in) :: ncid
+   integer              :: nf90_sync
+ at end example
+
+ at table @code
+ at item ncid
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
+ at end table
+
+ at heading Errors 
+
+NF90_SYNC returns the value NF90_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+ at itemize
+
+ at item
+The netCDF dataset is in define mode. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF90_SYNC to synchronize the disk writes of a
+netCDF dataset named foo.nc:
+
+ at example
+ use netcdf
+ implicit none
+ integer :: ncid, status
+ ...
+ status = nf90_open("foo.nc", nf90_write, ncid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ ...  
+ ! write data or change attributes
+ ...  
+ status = NF90_SYNC(ncid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ at end example
+
+ at node NF90_ABORT, NF90_SET_FILL, NF90_SYNC, Datasets
+ at section NF90_ABORT 
+ at findex NF90_ABORT 
+ at cindex NF90_ABORT , example
+
+You no longer need to call this function, since it is called
+automatically by NF90_CLOSE in case the dataset is in define mode and
+something goes wrong with committing the changes. The function
+NF90_ABORT just closes the netCDF dataset, if not in define mode. If the
+dataset is being created and is still in define mode, the dataset is
+deleted. If define mode was entered by a call to NF90_REDEF, the netCDF
+dataset is restored to its state before definition mode was entered
+and the dataset is closed.
+
+ at heading Usage 
+ at example
+ function nf90_abort(ncid)
+   integer, intent( in) :: ncid
+   integer              :: nf90_abort
+ at end example
+
+ at table @code
+ at item ncid
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
+ at end table
+
+ at heading Errors 
+
+NF90_ABORT returns the value NF90_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+ at itemize
+
+ at item
+When called from define mode while creating a netCDF dataset, deletion
+of the dataset failed.
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF90_ABORT to back out of redefinitions of a
+dataset named foo.nc:
+
+ at example
+ use netcdf
+ implicit none
+ integer :: ncid, status, LatDimID
+ ...
+ status = nf90_open("foo.nc", nf90_write, ncid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ ...  
+ status = nf90_redef(ncid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ ...  
+ status = nf90_def_dim(ncid, "Lat", 18, LatDimID) 
+ if (status /= nf90_noerr) then ! Dimension definition failed
+   call handle_err(status)
+   status = nf90_abort(ncid) ! Abort redefinitions
+   if (status /= nf90_noerr) call handle_err(status)
+ end if
+...
+ at end example
+
+ at node NF90_SET_FILL,  , NF90_ABORT, Datasets
+ at section NF90_SET_FILL 
+ at findex NF90_SET_FILL 
+ at cindex NF90_SET_FILL , example
+
+This function is intended for advanced usage, to optimize writes under
+some circumstances described below. The function NF90_SET_FILL sets
+the fill mode for a netCDF dataset open for writing and returns the
+current fill mode in a return parameter. The fill mode can be
+specified as either NF90_FILL or NF90_NOFILL. The default behavior
+corresponding to NF90_FILL is that data is pre-filled with fill
+values, that is fill values are written when you create non-record
+variables or when you write a value beyond data that has not yet been
+written. This makes it possible to detect attempts to read data before
+it was written. @xref{Fill Values}, for more information on the use of
+fill values. @xref{Attribute Conventions,,,netcdf, @value{n-man}}, for
+information about how to define your own fill values.
+
+The behavior corresponding to NF90_NOFILL overrides the default behavior
+of prefilling data with fill values. This can be used to enhance
+performance, because it avoids the duplicate writes that occur when
+the netCDF library writes fill values that are later overwritten with
+data.
+
+A value indicating which mode the netCDF dataset was already in is
+returned. You can use this value to temporarily change the fill mode
+of an open netCDF dataset and then restore it to the previous mode.
+
+After you turn on NF90_NOFILL mode for an open netCDF dataset, you must
+be certain to write valid data in all the positions that will later be
+read. Note that nofill mode is only a transient property of a netCDF
+dataset open for writing: if you close and reopen the dataset, it will
+revert to the default behavior. You can also revert to the default
+behavior by calling NF90_SET_FILL again to explicitly set the fill mode
+to NF90_FILL.
+
+There are three situations where it is advantageous to set nofill
+mode:
+ at enumerate
+ at item
+Creating and initializing a netCDF dataset. In this case, you should
+set nofill mode before calling NF90_ENDDEF and then write completely all
+non-record variables and the initial records of all the record
+variables you want to initialize.
+ at item
+Extending an existing record-oriented netCDF dataset. Set nofill mode
+after opening the dataset for writing, then append the additional
+records to the dataset completely, leaving no intervening unwritten
+records.
+ at item
+Adding new variables that you are going to initialize to an existing
+netCDF dataset. Set nofill mode before calling NF90_ENDDEF then write
+all the new variables completely.
+ at end enumerate
+
+If the netCDF dataset has an unlimited dimension and the last record
+was written while in nofill mode, then the dataset may be shorter than
+if nofill mode was not set, but this will be completely transparent if
+you access the data only through the netCDF interfaces.
+
+The use of this feature may not be available (or even needed) in
+future releases. Programmers are cautioned against heavy reliance upon
+this feature.
+
+ at heading Usage 
+ at example
+ function nf90_set_fill(ncid, fillmode, old_mode)
+   integer, intent( in) :: ncid, fillmode 
+   integer, intent(out) :: old_mode
+   integer              :: nf90_set_fill
+ at end example
+
+ at table @code
+ at item ncid
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
+ 
+ at item fillmode
+Desired fill mode for the dataset, either NF90_NOFILL or NF90_FILL.
+ 
+ at item old_mode
+Returned current fill mode of the dataset before this call, either
+NF90_NOFILL or NF90_FILL.
+ at end table
+
+ at heading Errors 
+
+NF90_SET_FILL returns the value NF90_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+ at itemize
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+
+ at item
+The specified netCDF ID refers to a dataset open for read-only access. 
+
+ at item
+The fill mode argument is neither NF90_NOFILL nor NF90_FILL.. 
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF90_SET_FILL to set nofill mode for subsequent
+writes of a netCDF dataset named foo.nc:
+
+ at example
+ use netcdf
+ implicit none
+ integer :: ncid, status, oldMode
+ ...
+ status = nf90_open("foo.nc", nf90_write, ncid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ ...  
+ ! Write data with prefilling behavior
+ ...  
+ status = nf90_set_fill(ncid, nf90_nofill, oldMode) 
+ if (status /= nf90_noerr) call handle_err(status)
+ ...
+ !  Write data with no prefilling
+ ...
+ at end example
+
+ at node Groups, Dimensions, Datasets, Top
+ at chapter Groups
+ at cindex groups, overview
+
+NetCDF-4 added support for hierarchical groups within netCDF
+datasets. 
+
+Groups are identified with a ncid, which identifies both the open
+file, and the group within that file. When a file is opened with
+NF90_OPEN or NF90_CREATE, the ncid for the root group of that file is
+provided. Using that as a starting point, users can add new groups, or
+list and navigate existing groups.
+
+All netCDF calls take a ncid which determines where the call will
+take its action. For example, the NF90_DEF_VAR function takes a ncid as
+its first parameter. It will create a variable in whichever group
+its ncid refers to. Use the root ncid provided by NF90_CREATE or
+NF90_OPEN to create a variable in the root group. Or use NF90_DEF_GRP to
+create a group and use its ncid to define a variable in the new
+group.
+
+Variable are only visible in the group in which they are defined. The
+same applies to attributes. ``Global'' attributes are defined in
+whichever group is refered to by the ncid. 
+
+Dimensions are visible in their groups, and all child groups.
+
+Group operations are only permitted on netCDF-4 files - that is, files
+created with the HDF5 flag in nf90_create. (@pxref{NF90_CREATE}). Groups
+are not compatible with the netCDF classic data model, so files
+created with the NF90_CLASSIC_MODEL file cannot contain groups (except
+the root group).
+
+ at menu
+* NF90_INQ_NCID::               
+* NF90_INQ_GRPS::               
+* NF90_INQ_VARIDS::             
+* NF90_INQ_DIMIDS::             
+* NF90_INQ_GRPNAME_LEN::        
+* NF90_INQ_GRPNAME::            
+* NF90_INQ_GRPNAME_FULL::       
+* NF90_INQ_GRP_PARENT::         
+* NF90_INQ_GRP_NCID::           
+* NF90_INQ_GRP_FULL_NCID::      
+* NF90_DEF_GRP::                
+ at end menu
+
+ at node NF90_INQ_NCID, NF90_INQ_GRPS, Groups, Groups
+ at section Find a Group ID: NF90_INQ_NCID
+ at findex NF90_INQ_NCID
+
+Given an ncid and group name (NULL or "" gets root group), return
+ncid of the named group.
+
+ at heading Usage 
+
+ at example
+  function nf90_inq_ncid(ncid, name, grp_ncid)
+    integer, intent(in) :: ncid
+    character (len = *), intent(in) :: name
+    integer, intent(out) :: grp_ncid
+    integer :: nf90_inq_ncid
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id for this operation.
+
+ at item NAME
+A character array that holds the name of the desired group. Must be
+less then NF90_MAX_NAME.
+
+ at item GRPID
+The ID of the group will go here.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADID
+Bad group id. 
+
+ at item NF90_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag HDF5. (@pxref{NF90_OPEN}).
+
+ at item NF90_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF90_OPEN}).
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+This example is from nf90_test/ftst_groups.F.
+
+ at example
+ at end example
+
+ at node NF90_INQ_GRPS, NF90_INQ_VARIDS, NF90_INQ_NCID, Groups
+ at section Get a List of Groups in a Group: NF90_INQ_GRPS
+ at findex NF90_INQ_GRPS
+
+Given a location id, return the number of groups it contains, and an
+array of their ncids.
+
+ at heading Usage 
+
+ at example
+  function nf90_inq_grps(ncid, numgrps, ncids)
+    integer, intent(in) :: ncid
+    integer, intent(out) :: numgrps
+    integer, intent(out) :: ncids
+    integer :: nf90_inq_grps
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id for this operation.
+
+ at item NUMGRPS
+An integer which will get number of groups in this group. 
+
+ at item NCIDS
+An array of ints which will receive the IDs of all the groups in this
+group.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADID
+Bad group id. 
+
+ at item NF90_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag HDF5. (@pxref{NF90_OPEN}).
+
+ at item NF90_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF90_OPEN}).
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+
+ at example
+ at end example
+
+ at node NF90_INQ_VARIDS, NF90_INQ_DIMIDS, NF90_INQ_GRPS, Groups
+ at section Find all the Variables in a Group: NF90_INQ_VARIDS
+ at findex NF90_INQ_VARIDS
+
+Find all varids for a location.
+
+ at heading Usage 
+
+ at example
+  function nf90_inq_varids(ncid, nvars, varids)
+    integer, intent(in) :: ncid
+    integer, intent(out) :: nvars
+    integer, intent(out) :: varids
+    integer :: nf90_inq_varids
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id for this operation.
+
+ at item VARIDS
+An already allocated array to store the list of varids. Use
+nf90_inq_nvars to find out how many variables there
+are. (@pxref{NF90_INQUIRE_VARIABLE}).
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADID
+Bad group id. 
+
+ at item NF90_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag HDF5. (@pxref{NF90_OPEN}).
+
+ at item NF90_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF90_OPEN}).
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+
+ at example
+ at end example
+
+ at node NF90_INQ_DIMIDS, NF90_INQ_GRPNAME_LEN, NF90_INQ_VARIDS, Groups
+ at section Find all Dimensions Visible in a Group: NF90_INQ_DIMIDS
+ at findex NF90_INQ_DIMIDS
+
+Find all dimids for a location. This finds all dimensions in a group,
+or any of its parents.
+
+ at heading Usage 
+
+ at example
+  function nf90_inq_dimids(ncid, ndims, dimids, include_parents)
+    integer, intent(in) :: ncid
+    integer, intent(out) :: ndims
+    integer, intent(out) :: dimids
+    integer, intent(out) :: include_parents
+    integer :: nf90_inq_dimids
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id for this operation.
+
+ at item NDIMS
+Returned number of dimensions for this location.  If include_parents
+is non-zero, number of dimensions visible from this group, which
+includes dimensions in parent groups.
+
+ at item DIMIDS
+An array of ints when the dimids of the visible dimensions will be
+stashed. Use nf90_inq_ndims to find out how many dims are visible from
+this group. (@pxref{NF90_INQUIRE_VARIABLE}).
+
+ at item INCLUDE_PARENTS
+If zero, only the group specified by NCID will be searched for
+dimensions. Otherwise parent groups will be searched too.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADID
+Bad group id. 
+
+ at item NF90_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag HDF5. (@pxref{NF90_OPEN}).
+
+ at item NF90_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF90_OPEN}).
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+
+ at example
+ at end example
+
+ at node NF90_INQ_GRPNAME_LEN, NF90_INQ_GRPNAME, NF90_INQ_DIMIDS, Groups
+ at section Find the Length of a Group's Full Name: NF90_INQ_GRPNAME_LEN
+ at findex NF90_INQ_GRPNAME_LEN
+
+Given ncid, find length of the full name. (Root group is named "/",
+with length 1.)
+
+ at heading Usage 
+
+ at example
+  function nf90_inq_grpname_len(ncid, len)
+    integer, intent(in) :: ncid
+    integer, intent(out) :: len
+    integer :: nf90_inq_grpname_len
+  end function nf90_inq_grpname_len
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id for this operation.
+
+ at item LEN
+An integer where the length will be placed.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADID
+Bad group id. 
+
+ at item NF90_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag HDF5. (@pxref{NF90_OPEN}).
+
+ at item NF90_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF90_OPEN}).
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node NF90_INQ_GRPNAME, NF90_INQ_GRPNAME_FULL, NF90_INQ_GRPNAME_LEN, Groups
+ at section Find a Group's Name: NF90_INQ_GRPNAME
+ at findex NF90_INQ_GRPNAME
+
+Given ncid, find relative name of group. (Root group is named "/").
+
+The name provided by this function is relative to the parent
+group. For a full path name for the group is, with all parent groups
+included, separated with a forward slash (as in Unix directory names) @xref{NF90_INQ_GRPNAME_FULL}.
+
+ at heading Usage 
+
+ at example
+  function nf90_inq_grpname(ncid, name)
+    integer, intent(in) :: ncid
+    character (len = *), intent(out) :: name
+    integer :: nf90_inq_grpname
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id for this operation.
+
+ at item NAME
+The name of the
+group will be copied to this character array. The name will be less
+than NF90_MAX_NAME in length.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADID
+Bad group id. 
+
+ at item NF90_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag HDF5. (@pxref{NF90_OPEN}).
+
+ at item NF90_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF90_OPEN}).
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+
+ at example
+ at end example
+
+ at node NF90_INQ_GRPNAME_FULL, NF90_INQ_GRP_PARENT, NF90_INQ_GRPNAME, Groups
+ at section Find a Group's Full Name: NF90_INQ_GRPNAME_FULL
+ at findex NF90_INQ_GRPNAME_FULL
+
+Given ncid, find complete name of group. (Root group is named "/").
+
+The name provided by this function is a full path name for the group
+is, with all parent groups included, separated with a forward slash
+(as in Unix directory names). For a name relative to the parent group
+ at xref{NF90_INQ_GRPNAME}.
+
+To find the length of the full name @xref{NF90_INQ_GRPNAME_LEN}.
+
+ at heading Usage 
+
+ at example
+  function nf90_inq_grpname_full(ncid, len, name)
+    integer, intent(in) :: ncid
+    integer, intent(out) :: len
+    character (len = *), intent(out) :: name
+    integer :: nf90_inq_grpname_full
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id for this operation.
+
+ at item LEN
+The length of the full group name will go here.      
+
+ at item NAME
+The name of the group will be copied to this character array. 
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADID
+Bad group id. 
+
+ at item NF90_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag HDF5. (@pxref{NF90_OPEN}).
+
+ at item NF90_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF90_OPEN}).
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+This example is from test program nf_test/f90tst_grps.f90.         
+
+ at example
+  call check(nf90_inq_grpname_full(grpid1, len, name_in))
+  if (name_in .ne. grp1_full_name) stop 62
+ at end example
+
+ at node NF90_INQ_GRP_PARENT, NF90_INQ_GRP_NCID, NF90_INQ_GRPNAME_FULL, Groups
+ at section Find a Group's Parent: NF90_INQ_GRP_PARENT
+ at findex NF90_INQ_GRP_PARENT
+
+Given ncid, find the ncid of the parent group. 
+
+When used with the root group, this function returns the NF90_ENOGRP
+error (since the root group has no parent.)
+
+ at heading Usage 
+
+ at example
+  function nf90_inq_grp_parent(ncid, parent_ncid)
+    integer, intent(in) :: ncid
+    integer, intent(out) :: parent_ncid
+    integer :: nf90_inq_grp_parent
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id.
+
+ at item PARENT_NCID
+The ncid of the parent group will be copied here.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADID
+Bad group id. 
+
+ at item NF90_ENOGRP
+No parent group found (i.e. this is the root group).
+
+ at item NF90_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag HDF5. (@pxref{NF90_OPEN}).
+
+ at item NF90_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF90_OPEN}).
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node NF90_INQ_GRP_NCID, NF90_INQ_GRP_FULL_NCID, NF90_INQ_GRP_PARENT, Groups
+ at section Find a Group by Name: NF90_INQ_GRP_NCID
+ at findex NF90_INQ_GRP_PARENT
+
+Given a group name an an ncid, find the ncid of the group id. 
+
+ at heading Usage 
+
+ at example
+  function nf90_inq_grp_ncid(ncid, name, grpid)
+    integer, intent(in) :: ncid
+    character (len = *), intent(in) :: name
+    integer, intent(out) :: grpid
+    integer :: nf90_inq_grp_ncid
+  
+    nf90_inq_grp_ncid = nf_inq_grp_ncid(ncid, name, grpid)
+  end function nf90_inq_grp_ncid
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id to look in.
+
+ at item GRP_NAME
+The name of the group that should be found.
+
+ at item GRP_NCID
+This will get the group id, if it is found.
+
+ at end table
+
+ at heading Return Codes
+
+The following return codes may be returned by this function.
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADID
+Bad group id. 
+
+ at item NF90_EINVAL
+No name provided or name longer than NF90_MAX_NAME.
+
+ at item NF90_ENOGRP
+Named group not found.
+
+ at item NF90_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag HDF5. (@pxref{NF90_OPEN}).
+
+ at item NF90_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF90_OPEN}).
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+This example is from test program nf_test/f90tst_grps.f90.         
+
+ at example
+  ! Get the group ids for the newly reopened file.
+  call check(nf90_inq_grp_ncid(ncid, GRP1_NAME, grpid1))
+  call check(nf90_inq_grp_ncid(grpid1, GRP2_NAME, grpid2))
+  call check(nf90_inq_grp_ncid(grpid2, GRP3_NAME, grpid3))
+  call check(nf90_inq_grp_ncid(grpid3, GRP4_NAME, grpid4))
+ at end example
+
+ at node NF90_INQ_GRP_FULL_NCID, NF90_DEF_GRP, NF90_INQ_GRP_NCID, Groups
+ at section Find a Group by its Fully-qualified Name: NF90_INQ_GRP_FULL_NCID
+ at findex NF90_INQ_GRP_PARENT
+
+Given a fully qualified group name an an ncid, find the ncid of the
+group id.
+
+ at heading Usage 
+
+ at example
+  function nf90_inq_grpname_full(ncid, len, name)
+    integer, intent(in) :: ncid
+    integer, intent(out) :: len
+    character (len = *), intent(out) :: name
+    integer :: nf90_inq_grpname_full
+  
+    nf90_inq_grpname_full = nf_inq_grpname_full(ncid, len, name)
+  end function nf90_inq_grpname_full
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id to look in.
+
+ at item FULL_NAME
+The fully-qualified group name.
+
+ at item GRP_NCID
+This will get the group id, if it is found.
+
+ at end table
+
+ at heading Return Codes
+
+The following return codes may be returned by this function.
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADID
+Bad group id. 
+
+ at item NF90_EINVAL
+No name provided or name longer than NF90_MAX_NAME.
+
+ at item NF90_ENOGRP
+Named group not found.
+
+ at item NF90_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag HDF5. (@pxref{NF90_OPEN}).
+
+ at item NF90_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF90_OPEN}).
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+This example is from test program nf_test/tstf90_grps.f90.
+
+ at example
+  ! Check for the groups with full group names. 
+  write(grp1_full_name, '(AA)') '/', GRP1_NAME
+  call check(nf90_inq_grp_full_ncid(ncid, grp1_full_name, grpid1))
+ at end example
+
+ at node NF90_DEF_GRP,  , NF90_INQ_GRP_FULL_NCID, Groups
+ at section Create a New Group: NF90_DEF_GRP
+ at findex NF90_DEF_GRP
+
+Create a group. Its location id is returned in new_ncid. 
+
+ at heading Usage 
+
+ at example
+  function nf90_def_grp(parent_ncid, name, new_ncid)
+    integer, intent(in) :: parent_ncid
+    character (len = *), intent(in) :: name
+    integer, intent(out) :: new_ncid
+    integer :: nf90_def_grp
+ at end example
+
+ at table @code
+
+ at item PARENT_NCID
+The group id of the parent group.
+
+ at item NAME
+The name of the new group, which must be different from the name of
+any variable within the same parent group.
+
+ at item NEW_NCID
+The ncid of the new group will be placed there.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADID
+Bad group id. 
+
+ at item NF90_ENAMEINUSE
+That name is in use. Group names must be unique within a group.
+
+ at item NF90_EMAXNAME
+Name exceed max length NF90_MAX_NAME.
+
+ at item NF90_EBADNAME
+Name contains illegal characters.
+
+ at item NF90_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag HDF5. (@pxref{NF90_OPEN}).
+
+ at item NF90_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF90_OPEN}).
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at item NF90_EPERM
+Attempt to write to a read-only file.
+
+ at item NF90_ENOTINDEFINE
+Not in define mode.
+
+ at end table
+
+ at heading Example
+
+ at example
+C     Create the netCDF file.
+      retval = nf90_create(file_name, NF90_NETCDF4, ncid)
+      if (retval .ne. nf90_noerr) call handle_err(retval)
+
+C     Create a group and a subgroup.
+      retval = nf90_def_grp(ncid, group_name, grpid)
+      if (retval .ne. nf90_noerr) call handle_err(retval)
+      retval = nf90_def_grp(grpid, sub_group_name, sub_grpid)
+      if (retval .ne. nf90_noerr) call handle_err(retval)
+ at end example
+
+ at node Dimensions, User Defined Data Types, Groups, Top
+ at chapter Dimensions
+
+ at menu
+* Dimensions Introduction::     
+* NF90_DEF_DIM::                
+* NF90_INQ_DIMID::              
+* NF90_INQUIRE_DIMENSION::      
+* NF90_RENAME_DIM::             
+ at end menu
+
+ at node Dimensions Introduction, NF90_DEF_DIM, Dimensions, Dimensions
+ at section Dimensions Introduction
+
+Dimensions for a netCDF dataset are defined when it is created, while
+the netCDF dataset is in define mode. Additional dimensions may be
+added later by reentering define mode. A netCDF dimension has a name
+and a length. At most one dimension in a netCDF dataset can have the
+unlimited length, which means variables using this dimension can grow
+along this dimension.
+
+There is a suggested limit (512) to the number of dimensions that can
+be defined in a single netCDF dataset. The limit is the value of the
+constant NF90_MAX_DIMS. The purpose of the limit is to make writing
+generic applications simpler. They need only provide an array of
+NF90_MAX_DIMS dimensions to handle any netCDF dataset. The
+implementation of the netCDF library does not enforce this advisory
+maximum, so it is possible to use more dimensions, if necessary, but
+netCDF utilities that assume the advisory maximums may not be able to
+handle the resulting netCDF datasets.
+
+Ordinarily, the name and length of a dimension are fixed when the
+dimension is first defined. The name may be changed later, but the
+length of a dimension (other than the unlimited dimension) cannot be
+changed without copying all the data to a new netCDF dataset with a
+redefined dimension length.
+
+A netCDF dimension in an open netCDF dataset is referred to by a small
+integer called a dimension ID. In the Fortran 90 interface, dimension
+IDs are 1, 2, 3, ..., in the order in which the dimensions were
+defined.
+
+Operations supported on dimensions are: 
+ at itemize
+
+ at item
+Create a dimension, given its name and length. 
+
+ at item
+Get a dimension ID from its name. 
+
+ at item
+Get a dimension's name and length from its ID. 
+
+ at item
+Rename a dimension. 
+ at end itemize
+
+ at node NF90_DEF_DIM, NF90_INQ_DIMID, Dimensions Introduction, Dimensions
+ at section NF90_DEF_DIM 
+ at findex NF90_DEF_DIM
+ at cindex NF90_DEF_DIM, example
+
+The function NF90_DEF_DIM adds a new dimension to an open netCDF dataset
+in define mode. It returns (as an argument) a dimension ID, given the
+netCDF ID, the dimension name, and the dimension length. At most one
+unlimited length dimension, called the record dimension, may be
+defined for each netCDF dataset.
+
+ at heading Usage 
+ at example
+ function nf90_def_dim(ncid, name, len, dimid)
+   integer,             intent( in) :: ncid
+   character (len = *), intent( in) :: name
+   integer,             intent( in) :: len
+   integer,             intent(out) :: dimid
+   integer                          :: nf90_def_dim
+ at end example
+
+ at table @code
+ at item ncid
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
+ 
+ at item name
+Dimension name.
+ 
+ at item len
+Length of dimension; that is, number of values for this dimension as
+an index to variables that use it. This should be either a positive
+integer or the predefined constant NF90_UNLIMITED.
+ 
+ at item dimid
+Returned dimension ID.
+ at end table
+
+ at heading Errors 
+
+NF90_DEF_DIM returns the value NF90_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+ at itemize
+
+ at item
+The netCDF dataset is not in definition mode. 
+
+ at item
+The specified dimension name is the name of another existing
+dimension.
+
+ at item
+The specified length is not greater than zero. 
+
+ at item
+The specified length is unlimited, but there is already an unlimited
+length dimension defined for this netCDF dataset.
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset.
+
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF90_DEF_DIM to create a dimension named lat of
+length 18 and a unlimited dimension named rec in a new netCDF dataset
+named foo.nc:
+
+ at example
+ use netcdf
+ implicit none
+ integer :: ncid, status, LatDimID, RecordDimID
+ ...
+ status = nf90_create("foo.nc", nf90_noclobber, ncid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ ...  
+ status = nf90_def_dim(ncid, "Lat", 18, LatDimID) 
+ if (status /= nf90_noerr) call handle_err(status)
+ status = nf90_def_dim(ncid, "Record", nf90_unlimited, RecordDimID)
+ if (status /= nf90_noerr) call handle_err(status)
+ at end example
+
+ at node NF90_INQ_DIMID, NF90_INQUIRE_DIMENSION, NF90_DEF_DIM, Dimensions
+ at section NF90_INQ_DIMID 
+ at findex NF90_INQ_DIMID 
+ at cindex NF90_INQ_DIMID , example
+
+The function NF90_INQ_DIMID returns (as an argument) the ID of a netCDF
+dimension, given the name of the dimension. If ndims is the number of
+dimensions defined for a netCDF dataset, each dimension has an ID
+between 1 and ndims.
+
+ at heading Usage 
+ at example
+ function nf90_inq_dimid(ncid, name, dimid)
+   integer,             intent( in) :: ncid
+   character (len = *), intent( in) :: name
+   integer,             intent(out) :: dimid
+   integer                          :: nf90_inq_dimid
+ at end example
+
+ at table @code
+ at item ncid
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
+ 
+ at item name
+Dimension name.
+ 
+ at item dimid
+Returned dimension ID.
+ at end table
+ 
+ at heading Errors 
+
+NF90_INQ_DIMID returns the value NF90_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The name that was specified is not the name of a dimension in the
+netCDF dataset.  
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset.
+
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF90_INQ_DIMID to determine the dimension ID of
+a dimension named lat, assumed to have been defined previously in an
+existing netCDF dataset named foo.nc:
+
+ at example
+ use netcdf
+ implicit none
+ integer :: ncid, status, LatDimID
+ ...
+ status = nf90_open("foo.nc", nf90_nowrite, ncid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ ...  
+ status = nf90_inq_dimid(ncid, "Lat", LatDimID) 
+ if (status /= nf90_noerr) call handle_err(status)
+ at end example
+
+ at node NF90_INQUIRE_DIMENSION, NF90_RENAME_DIM, NF90_INQ_DIMID, Dimensions
+ at section NF90_INQUIRE_DIMENSION 
+ at findex NF90_INQUIRE_DIMENSION 
+ at cindex NF90_INQUIRE_DIMENSION , example
+
+This function information about a netCDF dimension. Information about
+a dimension includes its name and its length. The length for the
+unlimited dimension, if any, is the number of records written so far.
+
+ at heading Usage 
+
+ at example
+ function nf90_inquire_dimension(ncid, dimid, name, len)
+   integer,                       intent( in) :: ncid, dimid
+   character (len = *), optional, intent(out) :: name
+   integer,             optional, intent(out) :: len
+   integer                                    :: nf90_inquire_dimension
+ at end example
+
+ at table @code
+ at item ncid
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE. 
+ 
+ at item dimid
+Dimension ID, from a previous call to NF90_INQ_DIMID or NF90_DEF_DIM.
+ 
+ at item name
+Returned dimension name. The caller must allocate space for the
+returned name. The maximum possible length, in characters, of a
+dimension name is given by the predefined constant NF90_MAX_NAME.
+ 
+ at item len
+Returned length of dimension. For the unlimited dimension, this is the
+current maximum value used for writing any variables with this
+dimension, that is the maximum record number.
+ at end table
+
+ at heading Errors 
+
+These functions return the value NF90_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The dimension ID is invalid for the specified netCDF dataset. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF90_INQ_DIM to determine the length of a
+dimension named lat, and the name and current maximum length of the
+unlimited dimension for an existing netCDF dataset named foo.nc:
+
+ at example
+ use netcdf
+ implicit none
+ integer :: ncid, status, LatDimID, RecordDimID
+ integer :: nLats, nRecords
+ character(len = nf90_max_name) :: RecordDimName
+ ...
+ status = nf90_open("foo.nc", nf90_nowrite, ncid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ ! Get ID of unlimited dimension
+ status = nf90_inquire(ncid, unlimitedDimId = RecordDimID)
+ if (status /= nf90_noerr) call handle_err(status)
+ ...  
+ status = nf90_inq_dimid(ncid, "Lat", LatDimID) 
+ if (status /= nf90_noerr) call handle_err(status)
+ ! How many values of "lat" are there?
+ status = nf90_inquire_dimension(ncid, LatDimID, len = nLats)
+ if (status /= nf90_noerr) call handle_err(status)
+ ! What is the name of the unlimited dimension, how many records are there?
+ status = nf90_inquire_dimension(ncid, RecordDimID, &
+                                 name = RecordDimName, len = Records)
+ if (status /= nf90_noerr) call handle_err(status)
+ at end example
+
+ at node NF90_RENAME_DIM,  , NF90_INQUIRE_DIMENSION, Dimensions
+ at section NF90_RENAME_DIM 
+ at findex NF90_RENAME_DIM 
+ at cindex NF90_RENAME_DIM , example
+
+The function NF90_RENAME_DIM renames an existing dimension in a netCDF
+dataset open for writing. If the new name is longer than the old name,
+the netCDF dataset must be in define mode. You cannot rename a
+dimension to have the same name as another dimension.
+
+ at heading Usage 
+
+ at example
+ function nf90_rename_dim(ncid, dimid, name)
+   integer,             intent( in) :: ncid
+   character (len = *), intent( in) :: name
+   integer,             intent( in) :: dimid
+   integer                          :: nf90_rename_dim
+ at end example
+
+ at table @code
+ at item ncid
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
+ 
+ at item dimid
+Dimension ID, from a previous call to NF90_INQ_DIMID or NF90_DEF_DIM.
+ 
+ at item name
+New dimension name.
+
+ at end table
+
+ at heading Errors 
+
+NF90_RENAME_DIM returns the value NF90_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The new name is the name of another dimension. 
+
+ at item
+The dimension ID is invalid for the specified netCDF dataset. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+
+ at item
+The new name is longer than the old name and the netCDF dataset is not
+in define mode.
+ at end itemize
+
+ at heading Example 
+Here is an example using NF90_RENAME_DIM to rename the dimension lat to
+latitude in an existing netCDF dataset named foo.nc:
+
+ at example
+ use netcdf
+ implicit none
+ integer :: ncid, status, LatDimID
+ ...
+ status = nf90_open("foo.nc", nf90_write, ncid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ ...  
+ ! Put in define mode so we can rename the dimension
+ status = nf90_redef(ncid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ ! Get the dimension ID for "Lat"...
+ status = nf90_inq_dimid(ncid, "Lat", LatDimID)
+ if (status /= nf90_noerr) call handle_err(status)
+ ! ... and change the name to "Latitude". 
+ status = nf90_rename_dim(ncid, LatDimID, "Latitude")
+ if (status /= nf90_noerr) call handle_err(status)
+ ! Leave define mode
+ status = nf90_enddef(ncid)
+ if (status /= nf90_noerr) call handle_err(status)
+ at end example
+
+ at node User Defined Data Types, Variables, Dimensions, Top
+ at chapter User Defined Data Types
+ at cindex variable length array type, overview
+ at cindex user defined types
+
+ at menu
+* User Defined Types::          
+* NF90_INQ_TYPEIDS::            
+* nf90_inq_typeid::             
+* NF90_INQ_TYPE::               
+* NF90_INQ_USER_TYPE::          
+* Compound Types::              
+* Variable Length Array::       
+* Opaque Type::                 
+* Enum Type::                   
+ at end menu
+
+ at node User Defined Types, NF90_INQ_TYPEIDS, User Defined Data Types, User Defined Data Types
+ at section User Defined Types Introduction
+ at cindex user defined types, overview
+
+NetCDF-4 has added support for four different user defined data types.
+
+ at table @code
+
+ at item compound type
+Like a C struct, a compound type is a collection of types, including
+other user defined types, in one package.
+
+ at item variable length array type
+The variable length array may be used to store ragged arrays.
+
+ at item opaque type
+This type has only a size per element, and no other type information.
+
+ at item enum type
+Like an enumeration in C, this type lets you assign text values to
+integer values, and store the integer values.
+
+ at end table
+
+Users may construct user defined type with the various NF90_DEF_*
+functions described in this section. They may learn about user defined
+types by using the NF90_INQ_ functions defined in this section.
+
+Once types are constructed, define variables of the new type with
+NF90_DEF_VAR (@pxref{NF90_DEF_VAR}). Write to them with NF90_PUT_VAR
+(@pxref{NF90_PUT_VAR}). Read data of user-defined type with
+NF90_GET_VAR (@pxref{NF90_GET_VAR}).
+
+Create attributes of the new type with NF90_PUT_ATT
+(@pxref{NF90_PUT_ATT}). Read attributes of the new type with
+NF90_GET_ATT (@pxref{NF90_GET_ATT}).
+
+ at node NF90_INQ_TYPEIDS, nf90_inq_typeid, User Defined Types, User Defined Data Types
+ at section Learn the IDs of All Types in Group: NF90_INQ_TYPEIDS
+ at findex NF90_INQ_TYPEIDS
+
+Learn the number of types defined in a group, and their IDs.
+
+ at heading Usage 
+
+ at example
+  function nf90_inq_typeids(ncid, ntypes, typeids)
+    integer, intent(in) :: ncid
+    integer, intent(out) :: ntypes
+    integer, intent(out) :: typeids
+    integer :: nf90_inq_typeids
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id.
+
+ at item NTYPES
+A pointer to int which will get the number of types defined in the
+group. If NULL, ignored.
+
+ at item TYPEIDS
+A pointer to an int array which will get the typeids. If NULL,
+ignored.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_BADID
+Bad ncid.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node nf90_inq_typeid, NF90_INQ_TYPE, NF90_INQ_TYPEIDS, User Defined Data Types
+ at section Find a Typeid from Group and Name: nf90_inq_typeid
+ at findex nf90_inq_typeid
+
+Given a group ID and a type name, find the ID of the type. If the type
+is not found in the group, then the parents are searched. If still not
+found, the entire file is searched.
+
+ at heading Usage 
+
+ at example
+int nf90_inq_typeid(int ncid, char *name, nf90_type *typeidp);
+ at end example
+
+ at table @code
+
+ at item ncid
+The group id.
+
+ at item name
+The name of a type.
+
+ at item typeidp
+The typeid, if found.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADID
+Bad ncid.
+
+ at item NF90_EBADTYPE
+Can't find type.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node NF90_INQ_TYPE, NF90_INQ_USER_TYPE, nf90_inq_typeid, User Defined Data Types
+ at section Learn About a User Defined Type: NF90_INQ_TYPE
+ at findex NF90_INQ_TYPE
+
+Given an ncid and a typeid, get the information about a type. This
+function will work on any type, including atomic and any user defined
+type, whether compound, opaque, enumeration, or variable length array.
+
+For even more information about a user defined type @ref{NF90_INQ_USER_TYPE}.
+
+ at heading Usage 
+
+ at example
+  function nf90_inq_type(ncid, xtype, name, size)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: xtype
+    character (len = *), intent(out) :: name
+    integer, intent(out) :: size
+    integer :: nf90_inq_type
+ at end example
+
+ at table @code
+
+ at item NCID
+The ncid for the group containing the type (ignored for atomic types).
+
+ at item XTYPE
+The typeid for this type, as returned by NF90_DEF_COMPOUND,
+NF90_DEF_OPAQUE, NF90_DEF_ENUM, NF90_DEF_VLEN, or NF90_INQ_VAR, or as found in
+netcdf.inc in the list of atomic types (NF90_CHAR, NF90_INT, etc.).
+
+ at item NAME
+The name of the user defined type will be copied here. It will be
+NF90_MAX_NAME bytes or less. For atomic types, the type name from CDL
+will be given.
+
+ at item SIZEP
+The (in-memory) size of the type (in bytes) will be copied here. VLEN
+type size is the size of one element of the VLEN. String size is
+returned as the size of one char.
+
+ at end table
+
+ at heading Return Codes
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADTYPEID
+Bad typeid.
+
+ at item NF90_ENOTNC4
+Seeking a user-defined type in a netCDF-3 file.
+
+ at item NF90_ESTRICTNC3
+Seeking a user-defined type in a netCDF-4 file for which classic model
+has been turned on.
+
+ at item NF90_EBADGRPID
+Bad group ID in ncid.
+
+ at item NF90_EBADID
+Type ID not found.
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node NF90_INQ_USER_TYPE, Compound Types, NF90_INQ_TYPE, User Defined Data Types
+ at section Learn About a User Defined Type: NF90_INQ_USER_TYPE
+ at findex NF90_INQ_USER_TYPE
+
+Given an ncid and a typeid, get the information about a user defined
+type. This function will work on any user defined type, whether
+compound, opaque, enumeration, or variable length array.
+
+ at heading Usage 
+
+ at example
+  function nf90_inq_user_type(ncid, xtype, name, size, base_typeid, nfields, class)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: xtype
+    character (len = *), intent(out) :: name
+    integer, intent(out) :: size
+    integer, intent(out) :: base_typeid
+    integer, intent(out) :: nfields
+    integer, intent(out) :: class
+    integer :: nf90_inq_user_type
+ at end example
+
+ at table @code
+
+ at item NCID
+The ncid for the group containing the user defined type.
+
+ at item XTYPE
+The typeid for this type, as returned by NF90_DEF_COMPOUND,
+NF90_DEF_OPAQUE, NF90_DEF_ENUM, NF90_DEF_VLEN, or NF90_INQ_VAR.
+
+ at item NAME
+The name of the user defined type will be copied here. It
+will be NF90_MAX_NAME bytes or less.
+
+ at item SIZE
+The (in-memory) size of the user defined type will be copied here.
+
+ at item BASE_NF90_TYPE
+The base typeid will be copied here for vlen and enum types.
+
+ at item NFIELDS
+The number of fields will be copied here for enum and compound types.
+
+ at item CLASS
+The class of the user defined type, NF90_VLEN, NF90_OPAQUE, NF90_ENUM, or
+NF90_COMPOUND, will be copied here.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADTYPEID
+Bad typeid.
+
+ at item NF90_EBADFIELDID
+Bad fieldid.
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at menu
+* NF90_PUT_VLEN_ELEMENT::       
+* NF90_GET_VLEN_ELEMENT::       
+ at end menu
+
+ at node NF90_PUT_VLEN_ELEMENT, NF90_GET_VLEN_ELEMENT, NF90_INQ_USER_TYPE, NF90_INQ_USER_TYPE
+ at subsection Set a Variable Length Array with NF90_PUT_VLEN_ELEMENT
+ at findex NF90_PUT_VLEN_ELEMENT
+
+Use this to set the element of the (potentially) n-dimensional array
+of VLEN. That is, this sets the data in one variable length array.
+
+ at heading Usage
+
+ at example
+INTEGER FUNCTION NF90_PUT_VLEN_ELEMENT(INTEGER NCID, INTEGER XTYPE,
+        CHARACTER*(*) VLEN_ELEMENT, INTEGER LEN, DATA)
+ at end example
+
+ at table @code
+
+ at item NCID
+The ncid of the file that contains the VLEN type.
+
+ at item XTYPE
+The type of the VLEN.
+
+ at item VLEN_ELEMENT
+The VLEN element to be set.
+
+ at item LEN
+The number of entries in this array.
+
+ at item DATA
+The data to be stored. Must match the base type of this VLEN.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADTYPE
+Can't find the typeid.
+
+ at item NF90_EBADID
+ncid invalid.
+
+ at item NF90_EBADGRPID
+Group ID part of ncid was invalid.
+
+ at end table
+
+ at heading Example
+
+This example is from nf90_test/ftst_vars4.F.
+
+ at example
+C     Set up the vlen with this helper function, since F90 can't deal
+C     with pointers.
+      retval = nf90_put_vlen_element(ncid, vlen_typeid, vlen, 
+     &     vlen_len, data1)
+      if (retval .ne. nf90_noerr) call handle_err(retval)
+ at end example
+
+ at node NF90_GET_VLEN_ELEMENT,  , NF90_PUT_VLEN_ELEMENT, NF90_INQ_USER_TYPE
+ at subsection Set a Variable Length Array with NF90_GET_VLEN_ELEMENT
+ at findex NF90_GET_VLEN_ELEMENT
+
+Use this to set the element of the (potentially) n-dimensional array
+of VLEN. That is, this sets the data in one variable length array.
+
+ at heading Usage
+
+ at example
+INTEGER FUNCTION NF90_GET_VLEN_ELEMENT(INTEGER NCID, INTEGER XTYPE,
+        CHARACTER*(*) VLEN_ELEMENT, INTEGER LEN, DATA)
+ at end example
+
+ at table @code
+
+ at item NCID
+The ncid of the file that contains the VLEN type.
+
+ at item XTYPE
+The type of the VLEN.
+
+ at item VLEN_ELEMENT
+The VLEN element to be set.
+
+ at item LEN
+This will be set to the number of entries in this array.
+
+ at item DATA
+The data will be copied here. Sufficient storage must be available or
+bad things will happen to you.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADTYPE
+Can't find the typeid.
+
+ at item NF90_EBADID
+ncid invalid.
+
+ at item NF90_EBADGRPID
+Group ID part of ncid was invalid.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node Compound Types, Variable Length Array, NF90_INQ_USER_TYPE, User Defined Data Types
+ at section Compound Types Introduction
+ at cindex compound types, overview
+
+NetCDF-4 added support for compound types, which allow users to
+construct a new type - a combination of other types, like a C struct.
+
+Compound types are not supported in classic or 64-bit offset format
+files. 
+
+To write data in a compound type, first use nf90_def_compound to create the
+type, multiple calls to nf90_insert_compound to add to the compound type, and
+then write data with the appropriate nf90_put_var1, nf90_put_vara,
+nf90_put_vars, or nf90_put_varm call.
+
+To read data written in a compound type, you must know its
+structure. Use the NF90_INQ_COMPOUND functions to learn about the compound
+type.
+
+In Fortran a character buffer must be used for the compound data. The
+user must read the data from within that buffer in the same way that
+the C compiler which compiled netCDF would store the structure.
+
+The use of compound types introduces challenges and portability issues
+for Fortran users.
+
+ at menu
+* NF90_DEF_COMPOUND::           
+* NF90_INSERT_COMPOUND::        
+* NF90_INSERT_ARRAY_COMPOUND::  
+* NF90_INQ_COMPOUND::           
+* NF90_INQ_COMPOUND_FIELD::     
+ at end menu
+
+ at node NF90_DEF_COMPOUND, NF90_INSERT_COMPOUND, Compound Types, Compound Types
+ at subsection Creating a Compound Type: NF90_DEF_COMPOUND
+ at findex NF90_DEF_COMPOUND
+
+Create a compound type. Provide an ncid, a name, and a total size (in
+bytes) of one element of the completed compound type.
+
+After calling this function, fill out the type with repeated calls to
+NF90_INSERT_COMPOUND (@pxref{NF90_INSERT_COMPOUND}). Call
+NF90_INSERT_COMPOUND once for each field you wish to insert into the
+compound type.
+
+Note that there does not seem to be a fully portable way to read such
+types into structures in Fortran 90 (and there are no structures in
+Fortran 77). Dozens of top-notch programmers are swarming over this
+problem in a sub-basement of Unidata's giant underground bunker in
+Wyoming.
+
+Fortran users may use character buffers to read and write compound
+types. User are invited to try classic Fortran features such as the
+equivilence and the common block statment. 
+
+ at heading Usage 
+
+ at example
+  function nf90_def_compound(ncid, size, name, typeid)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: size
+    character (len = *), intent(in) :: name
+    integer, intent(out) :: typeid
+    integer :: nf90_def_compound
+ at end example
+
+ at table @code
+
+ at item NCID
+The groupid where this compound type will be created.
+
+ at item SIZE
+The size, in bytes, of the compound type. 
+
+ at item NAME
+The name of the new compound type.
+
+ at item TYPEIDP
+The typeid of the new type will be placed here.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADID
+Bad group id. 
+
+ at item NF90_ENAMEINUSE
+That name is in use. Compound type names must be unique in the data
+file. 
+
+ at item NF90_EMAXNAME
+Name exceeds max length NF90_MAX_NAME.
+
+ at item NF90_EBADNAME
+Name contains illegal characters.
+
+ at item NF90_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag NF90_NETCDF4. (@pxref{NF90_OPEN}).
+
+ at item NF90_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF90_OPEN}).
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at item NF90_EPERM
+Attempt to write to a read-only file.
+
+ at item NF90_ENOTINDEFINE
+Not in define mode.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node NF90_INSERT_COMPOUND, NF90_INSERT_ARRAY_COMPOUND, NF90_DEF_COMPOUND, Compound Types
+ at subsection Inserting a Field into a Compound Type: NF90_INSERT_COMPOUND
+ at findex NF90_INSERT_COMPOUND
+
+Insert a named field into a compound type.
+
+ at heading Usage 
+
+ at example
+  function nf90_insert_compound(ncid, xtype, name, offset, field_typeid)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: xtype
+    character (len = *), intent(in) :: name
+    integer, intent(in) :: offset
+    integer, intent(in) :: field_typeid
+    integer :: nf90_insert_compound
+ at end example
+
+ at table @code
+
+ at item TYPEID
+The typeid for this compound type, as returned by NF90_DEF_COMPOUND, or
+NF90_INQ_VAR.
+
+ at item NAME
+The name of the new field.
+
+ at item OFFSET
+Offset in byte from the beginning of the compound type for this
+field.
+
+ at item FIELD_TYPEID
+The type of the field to be inserted.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADID
+Bad group id. 
+
+ at item NF90_ENAMEINUSE
+That name is in use. Field names must be unique within a compound type.
+
+ at item NF90_EMAXNAME
+Name exceed max length NF90_MAX_NAME.
+
+ at item NF90_EBADNAME
+Name contains illegal characters.
+
+ at item NF90_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag NF90_NETCDF4. (@pxref{NF90_OPEN}).
+
+ at item NF90_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF90_OPEN}).
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at item NF90_ENOTINDEFINE
+Not in define mode.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node NF90_INSERT_ARRAY_COMPOUND, NF90_INQ_COMPOUND, NF90_INSERT_COMPOUND, Compound Types
+ at subsection Inserting an Array Field into a Compound Type: NF90_INSERT_ARRAY_COMPOUND
+ at findex NF90_INSERT_ARRAY_COMPOUND
+
+Insert a named array field into a compound type.
+
+ at heading Usage 
+
+ at example
+  function nf90_insert_array_compound(ncid, xtype, name, offset, field_typeid, &
+       ndims, dim_sizes)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: xtype
+    character (len = *), intent(in) :: name
+    integer, intent(in) :: offset
+    integer, intent(in) :: field_typeid
+    integer, intent(in) :: ndims
+    integer, intent(in) :: dim_sizes
+    integer :: nf90_insert_array_compound
+ at end example
+
+ at table @code
+
+ at item NCID
+The ID of the file that contains the array type and the compound type.
+
+ at item XTYPE
+The typeid for this compound type, as returned by nf90_def_compound, or
+nf90_inq_var.
+
+ at item NAME
+The name of the new field.
+
+ at item OFFSET
+Offset in byte from the beginning of the compound type for this
+field.
+
+ at item FIELD_TYPEID
+The base type of the array to be inserted.
+
+ at item NDIMS
+The number of dimensions for the array to be inserted.
+
+ at item DIM_SIZES
+An array containing the sizes of each dimension.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADID
+Bad group id. 
+
+ at item NF90_ENAMEINUSE
+That name is in use. Field names must be unique within a compound type.
+
+ at item NF90_EMAXNAME
+Name exceed max length NF90_MAX_NAME.
+
+ at item NF90_EBADNAME
+Name contains illegal characters.
+
+ at item NF90_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag NF90_NETCDF4. (@pxref{NF90_OPEN}).
+
+ at item NF90_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF90_OPEN}).
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at item NF90_ENOTINDEFINE
+Not in define mode.
+
+ at item NF90_ETYPEDEFINED
+Attempt to change type that has already been committed. The first time
+the file leaves define mode, all defined types are committed, and
+can't be changed. If you wish to add an array to a compound type, you
+must do so before the compound type is committed.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node NF90_INQ_COMPOUND, NF90_INQ_COMPOUND_FIELD, NF90_INSERT_ARRAY_COMPOUND, Compound Types
+ at subsection Learn About a Compound Type: NF90_INQ_COMPOUND
+ at findex NF90_INQ_COMPOUND
+ at findex NF90_INQ_COMPOUND_NAME
+ at findex NF90_INQ_COMPOUND_SIZE
+ at findex NF90_INQ_COMPOUND_NFIELDS
+
+Get the number of fields, length in bytes, and name of a compound
+type.
+
+In addtion to the NF90_INQ_COMPOUND function, three additional functions
+are provided which get only the name, size, and number of fields.
+
+ at heading Usage 
+
+ at example
+  function nf90_inq_compound(ncid, xtype, name, size, nfields)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: xtype
+    character (len = *), intent(out) :: name
+    integer, intent(out) :: size
+    integer, intent(out) :: nfields
+    integer :: nf90_inq_compound
+
+  function nf90_inq_compound_name(ncid, xtype, name)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: xtype
+    character (len = *), intent(out) :: name
+    integer :: nf90_inq_compound_name
+
+  function nf90_inq_compound_size(ncid, xtype, size)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: xtype
+    integer, intent(out) :: size
+    integer :: nf90_inq_compound_size
+
+  function nf90_inq_compound_nfields(ncid, xtype, nfields)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: xtype
+    integer, intent(out) :: nfields
+    integer :: nf90_inq_compound_nfields
+ at end example
+
+ at table @code
+
+ at item NCID
+The ID of any group in the file that contains the compound type.
+
+ at item XTYPE
+The typeid for this compound type, as returned by NF90_DEF_COMPOUND, or
+NF90_INQ_VAR.
+
+ at item NAME
+Character array which will get the name of the compound type. It will
+have a maximum length of NF90_MAX_NAME.
+
+ at item SIZEP
+The size of the compound type in bytes will be put here.
+
+ at item NFIELDSP
+The number of fields in the compound type will be placed here.
+
+ at end table
+
+ at heading Return Codes
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADID
+Couldn't find this ncid.
+
+ at item NF90_ENOTNC4
+Not a netCDF-4/HDF5 file.
+
+ at item NF90_ESTRICTNC3
+A netCDF-4/HDF5 file, but with CLASSIC_MODEL. No user defined types
+are allowed in the classic model.
+
+ at item NF90_EBADTYPE
+This type not a compound type.
+
+ at item NF90_EBADTYPEID
+Bad type id. 
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node NF90_INQ_COMPOUND_FIELD,  , NF90_INQ_COMPOUND, Compound Types
+ at subsection Learn About a Field of a Compound Type: NF90_INQ_COMPOUND_FIELD
+ at findex NF90_INQ_COMPOUND_FIELD
+ at findex NF90_INQ_COMPOUND_FIELDNAME
+ at findex NF90_INQ_COMPOUND_FIELDINDEX
+ at findex NF90_INQ_COMPOUND_FIELDOFFSET
+ at findex NF90_INQ_COMPOUND_FIELDTYPE
+ at findex NF90_INQ_COMPOUND_FIELDNDIMS
+ at findex NF90_INQ_CMP_FIELDDIM_SIZES
+
+Get information about one of the fields of a compound type.
+
+ at heading Usage 
+
+ at example
+  function nf90_inq_compound_field(ncid, xtype, fieldid, name, offset, &
+       field_typeid, ndims, dim_sizes)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: xtype
+    integer, intent(in) :: fieldid
+    character (len = *), intent(out) :: name
+    integer, intent(out) :: offset
+    integer, intent(out) :: field_typeid
+    integer, intent(out) :: ndims
+    integer, intent(out) :: dim_sizes
+    integer :: nf90_inq_compound_field
+
+  function nf90_inq_compound_fieldname(ncid, xtype, fieldid, name)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: xtype
+    integer, intent(in) :: fieldid
+    character (len = *), intent(out) :: name
+    integer :: nf90_inq_compound_fieldname
+  
+  function nf90_inq_compound_fieldindex(ncid, xtype, name, fieldid)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: xtype
+    character (len = *), intent(in) :: name
+    integer, intent(out) :: fieldid
+    integer :: nf90_inq_compound_fieldindex
+  
+  function nf90_inq_compound_fieldoffset(ncid, xtype, fieldid, offset)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: xtype
+    integer, intent(in) :: fieldid
+    integer, intent(out) :: offset
+    integer :: nf90_inq_compound_fieldoffset
+  
+  function nf90_inq_compound_fieldtype(ncid, xtype, fieldid, field_typeid)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: xtype
+    integer, intent(in) :: fieldid
+    integer, intent(out) :: field_typeid
+    integer :: nf90_inq_compound_fieldtype
+  
+  function nf90_inq_compound_fieldndims(ncid, xtype, fieldid, ndims)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: xtype
+    integer, intent(in) :: fieldid
+    integer, intent(out) :: ndims
+    integer :: nf90_inq_compound_fieldndims
+  
+  function nf90_inq_cmp_fielddim_sizes(ncid, xtype, fieldid, dim_sizes)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: xtype
+    integer, intent(in) :: fieldid
+    integer, intent(out) :: dim_sizes
+    integer :: nf90_inq_cmp_fielddim_sizes
+ at end example
+
+ at table @code
+
+ at item NCID
+The groupid where this compound type exists.
+
+ at item XTYPE
+The typeid for this compound type, as returned by NF90_DEF_COMPOUND, or
+NF90_INQ_VAR.
+
+ at item FIELDID
+A one-based index number specifying a field in the compound type.
+
+ at item NAME
+A character array which will get the name of the field. The name will
+be NF90_MAX_NAME characters, at most.
+
+ at item OFFSETP
+An integer which will get the offset of the field.
+
+ at item FIELD_TYPEID
+An integer which will get the typeid of the field.
+
+ at item NDIMSP
+An integer which will get the number of dimensions of the field.
+
+ at item DIM_SIZESP
+An integer array which will get the dimension sizes of the field.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADTYPEID
+Bad type id. 
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node Variable Length Array, Opaque Type, Compound Types, User Defined Data Types
+ at section Variable Length Array Introduction
+ at cindex variable length arrays
+ at cindex VLEN
+
+NetCDF-4 added support for a variable length array type. This is not
+supported in classic or 64-bit offset files, or in netCDF-4 files
+which were created with the NF90_CLASSIC_MODEL flag.
+
+A variable length array is represented in C as a structure from HDF5,
+the nf90_vlen_t structure. It contains a len member, which contains the
+length of that array, and a pointer to the array.
+
+So an array of VLEN in C is an array of nc_vlen_t structures. The only
+way to handle this in Fortran is with a character buffer sized
+correctly for the platform.
+
+VLEN arrays are handled differently with respect to allocation of
+memory. Generally, when reading data, it is up to the user to malloc
+(and subsequently free) the memory needed to hold the data. It is up to
+the user to ensure that enough memory is allocated.
+
+With VLENs, this is impossible. The user cannot know the size of an
+array of VLEN until after reading the array. Therefore when reading
+VLEN arrays, the netCDF library will allocate the memory for the data within
+each VLEN.
+
+It is up to the user, however, to eventually free this memory. This is
+not just a matter of one call to free, with the pointer to the array
+of VLENs; each VLEN contains a pointer which must be freed.
+
+Compression is permitted but may not be effective for VLEN data,
+because the compression is applied to the nc_vlen_t structures, rather
+than the actual data.
+
+ at menu
+* NF90_DEF_VLEN::               
+* NF90_INQ_VLEN::               
+* NF90_FREE_VLEN::              
+ at end menu
+
+ at node NF90_DEF_VLEN, NF90_INQ_VLEN, Variable Length Array, Variable Length Array
+ at subsection Define a Variable Length Array (VLEN): NF90_DEF_VLEN
+ at findex NF90_DEF_VLEN
+ at cindex VLEN, defining
+
+Use this function to define a variable length array type. 
+
+ at heading Usage
+
+ at example
+  function nf90_def_vlen(ncid, name, base_typeid, xtypeid)
+    integer, intent(in) :: ncid
+    character (len = *), intent(in) :: name
+    integer, intent(in) :: base_typeid
+    integer, intent(out) :: xtypeid
+    integer :: nf90_def_vlen
+ at end example
+
+ at table @code
+
+ at item NCID
+The ncid of the file to create the VLEN type in.
+
+ at item NAME 
+A name for the VLEN type.
+
+ at item BASE_TYPEID
+The typeid of the base type of the VLEN. For example, for a VLEN of
+shorts, the base type is NF90_SHORT. This can be a user defined type.
+
+ at item XTYPEP
+The typeid of the new VLEN type will be set here.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EMAXNAME
+NF90_MAX_NAME exceeded.
+
+ at item NF90_ENAMEINUSE
+Name is already in use.
+
+ at item NF90_EBADNAME
+Attribute or variable name contains illegal characters.
+
+ at item NF90_EBADID
+ncid invalid.
+
+ at item NF90_EBADGRPID
+Group ID part of ncid was invalid.
+
+ at item NF90_EINVAL
+Size is invalid.
+
+ at item NF90_ENOMEM
+Out of memory.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node NF90_INQ_VLEN, NF90_FREE_VLEN, NF90_DEF_VLEN, Variable Length Array
+ at subsection Learning about a Variable Length Array (VLEN) Type: NF90_INQ_VLEN
+ at findex NF90_INQ_VLEN
+ at cindex VLEN, defining
+
+Use this type to learn about a vlen.
+
+ at heading Usage
+
+ at example
+  function nf90_inq_vlen(ncid, xtype, name, datum_size, base_nc_type)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: xtype
+    character (len = *), intent(out) :: name
+    integer, intent(out) :: datum_size
+    integer, intent(out) :: base_nc_type
+    integer :: nf90_inq_vlen
+ at end example
+
+ at table @code
+
+ at item NCID
+The ncid of the file that contains the VLEN type.
+
+ at item XTYPE
+The type of the VLEN to inquire about.
+
+ at item NAME
+The name of the VLEN type. The name will be NF90_MAX_NAME characters or
+less.
+
+ at item DATUM_SIZEP
+A pointer to a size_t, this will get the size of one element of this
+vlen.
+
+ at item BASE_NF90_TYPEP
+An integer that will get the type of the VLEN base type. (In other
+words, what type is this a VLEN of?)
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADTYPE
+Can't find the typeid.
+
+ at item NF90_EBADID
+ncid invalid.
+
+ at item NF90_EBADGRPID
+Group ID part of ncid was invalid.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node NF90_FREE_VLEN,  , NF90_INQ_VLEN, Variable Length Array
+ at subsection Releasing Memory for a Variable Length Array (VLEN) Type: NF90_FREE_VLEN
+ at findex NF90_FREE_VLEN
+ at cindex VLEN, defining
+
+When a VLEN is read into user memory from the file, the HDF5 library
+performs memory allocations for each of the variable length arrays
+contained within the VLEN structure. This memory must be freed by the
+user to avoid memory leaks.
+
+This violates the normal netCDF expectation that the user is
+responsible for all memory allocation. But, with VLEN arrays, the
+underlying HDF5 library allocates the memory for the user, and the user
+is responsible for deallocating that memory.
+
+ at heading Usage
+
+ at example
+  function nf90_free_vlen(vl)
+    character (len = *), intent(in) :: vlen
+    integer :: nf90_free_vlen
+  end function nf90_free_vlen
+ at end example
+
+ at table @code
+
+ at item VL
+The variable length array structure which is to be freed.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADTYPE
+Can't find the typeid.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node Opaque Type, Enum Type, Variable Length Array, User Defined Data Types
+ at section Opaque Type Introduction
+ at cindex opaque type
+
+NetCDF-4 added support for the opaque type. This is not supported in
+classic or 64-bit offset files.
+
+The opaque type is a type which is a collection of objects of a known
+size. (And each object is the same size). Nothing is known to netCDF
+about the contents of these blobs of data, except their size in bytes,
+and the name of the type.
+
+To use an opaque type, first define it with @ref{NF90_DEF_OPAQUE}. If
+encountering an enum type in a new data file, use @ref{NF90_INQ_OPAQUE}
+to learn its name and size.
+
+ at menu
+* NF90_DEF_OPAQUE::             
+* NF90_INQ_OPAQUE::             
+ at end menu
+
+ at node NF90_DEF_OPAQUE, NF90_INQ_OPAQUE, Opaque Type, Opaque Type
+ at subsection Creating Opaque Types: NF90_DEF_OPAQUE
+ at findex NF90_DEF_OPAQUE
+
+Create an opaque type. Provide a size and a name.
+
+ at heading Usage 
+
+ at example
+  function nf90_def_opaque(ncid, size, name, xtype)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: size
+    character (len = *), intent(in) :: name
+    integer, intent(out) :: xtype
+    integer :: nf90_def_opaque
+ at end example
+
+ at table @code
+
+ at item NCID
+The groupid where the type will be created. The type may be used
+anywhere in the file, no matter what group it is in.
+
+ at item NAME
+The name for this type. Must be shorter than NF90_MAX_NAME.
+
+ at item SIZE
+The size of each opaque object.
+
+ at item TYPEIDP
+Pointer where the new typeid for this type is returned. Use this
+typeid when defining variables of this type with @ref{NF90_DEF_VAR}.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADTYPEID
+Bad typeid.
+
+ at item NF90_EBADFIELDID
+Bad fieldid.
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at menu
+* NF90_INQ_OPAQUE::               
+ at end menu
+
+ at node NF90_INQ_OPAQUE,  , NF90_DEF_OPAQUE, Opaque Type
+ at subsection Learn About an Opaque Type: NF90_INQ_OPAQUE
+ at findex NF90_INQ_OPAQUE
+
+Given a typeid, get the information about an opaque type.
+
+ at heading Usage 
+
+ at example
+  function nf90_inq_opaque(ncid, xtype, name, size)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: xtype
+    character (len = *), intent(out) :: name
+    integer, intent(out) :: size
+    integer :: nf90_inq_opaque
+ at end example
+
+ at table @code
+
+ at item NCID
+The ncid for the group containing the opaque type.
+
+ at item XTYPE
+The typeid for this opaque type, as returned by NF90_DEF_COMPOUND, or
+NF90_INQ_VAR.
+
+ at item NAME
+The name of the opaque type will be copied here. It will
+be NF90_MAX_NAME bytes or less.
+
+ at item SIZEP
+The size of the opaque type will be copied here.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADTYPEID
+Bad typeid.
+
+ at item NF90_EBADFIELDID
+Bad fieldid.
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node Enum Type,  , Opaque Type, User Defined Data Types
+ at section Enum Type Introduction
+ at cindex enum type
+
+NetCDF-4 added support for the enum type. This is not supported in
+classic or 64-bit offset files.
+
+ at menu
+* NF90_DEF_ENUM::               
+* NF90_INSERT_ENUM::            
+* NF90_INQ_ENUM::               
+* NF90_INQ_ENUM_MEMBER::        
+* NF90_INQ_ENUM_IDENT::         
+ at end menu
+
+ at node NF90_DEF_ENUM, NF90_INSERT_ENUM, Enum Type, Enum Type
+ at subsection Creating a Enum Type: NF90_DEF_ENUM
+ at findex NF90_DEF_ENUM
+
+Create an enum type. Provide an ncid, a name, and a base integer
+type. 
+
+After calling this function, fill out the type with repeated calls to
+NF90_INSERT_ENUM (@pxref{NF90_INSERT_ENUM}). Call NF90_INSERT_ENUM once for
+each value you wish to make part of the enumeration.
+
+ at heading Usage 
+
+ at example
+  function nf90_def_enum(ncid, base_typeid, name, typeid)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: base_typeid
+    character (len = *), intent(in) :: name
+    integer, intent(out) :: typeid
+    integer :: nf90_def_enum
+ at end example
+
+ at table @code
+
+ at item NCID
+The groupid where this compound type will be created.
+
+ at item BASE_TYPEID
+The base integer type for this enum. Must be one of: NF90_BYTE,
+NF90_UBYTE, NF90_SHORT, NF90_USHORT, NF90_INT, NF90_UINT, NF90_INT64, NF90_UINT64.
+
+ at item NAME
+The name of the new enum type.
+
+ at item TYPEIDP
+The typeid of the new type will be placed here.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADID
+Bad group id. 
+
+ at item NF90_ENAMEINUSE
+That name is in use. Compound type names must be unique in the data
+file. 
+
+ at item NF90_EMAXNAME
+Name exceeds max length NF90_MAX_NAME.
+
+ at item NF90_EBADNAME
+Name contains illegal characters.
+
+ at item NF90_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag NF90_NETCDF4. (@pxref{NF90_OPEN}).
+
+ at item NF90_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF90_OPEN}).
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at item NF90_EPERM
+Attempt to write to a read-only file.
+
+ at item NF90_ENOTINDEFINE
+Not in define mode.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node NF90_INSERT_ENUM, NF90_INQ_ENUM, NF90_DEF_ENUM, Enum Type
+ at subsection Inserting a Field into a Enum Type: NF90_INSERT_ENUM
+ at findex NF90_INSERT_ENUM
+
+Insert a named member into a enum type.
+
+ at heading Usage 
+
+ at example
+  function nf90_insert_enum(ncid, xtype, name, value)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: xtype
+    character (len = *), intent(in) :: name
+    integer, intent(in) :: value
+    integer :: nf90_insert_enum
+ at end example
+
+ at table @code
+
+ at item NCID
+The ncid of the group which contains the type.
+
+ at item TYPEID
+The typeid for this enum type, as returned by nf90_def_enum, or
+nf90_inq_var.
+
+ at item IDENTIFIER
+The identifier of the new member.
+
+ at item VALUE
+The value that is to be associated with this member.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADID
+Bad group id. 
+
+ at item NF90_ENAMEINUSE
+That name is in use. Field names must be unique within a enum type.
+
+ at item NF90_EMAXNAME
+Name exceed max length NF90_MAX_NAME.
+
+ at item NF90_EBADNAME
+Name contains illegal characters.
+
+ at item NF90_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag NF90_NETCDF4. (@pxref{NF90_OPEN}).
+
+ at item NF90_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF90_OPEN}).
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at item NF90_ENOTINDEFINE
+Not in define mode.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node NF90_INQ_ENUM, NF90_INQ_ENUM_MEMBER, NF90_INSERT_ENUM, Enum Type
+ at subsection Learn About a Enum Type: NF90_INQ_ENUM
+ at findex NF90_INQ_ENUM
+
+Get information about a user-defined enumeration type.
+
+ at heading Usage 
+
+ at example
+  function nf90_inq_enum(ncid, xtype, name, base_nc_type, base_size, num_members)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: xtype
+    character (len = *), intent(out) :: name
+    integer, intent(out) :: base_nc_type
+    integer, intent(out) :: base_size
+    integer, intent(out) :: num_members
+    integer :: nf90_inq_enum
+ at end example
+
+ at table @code
+
+ at item NCID
+The group ID of the group which holds the enum type.
+
+ at item XTYPE
+The typeid for this enum type, as returned by NF90_DEF_ENUM, or
+NF90_INQ_VAR.
+
+ at item NAME
+Character array which will get the name. It will have a maximum length
+of NF90_MAX_NAME.
+
+ at item BASE_NF90_TYPE
+An integer which will get the base integer type of this enum.
+
+ at item BASE_SIZE
+An integer which will get the size (in bytes) of the base integer type
+of this enum.
+
+ at item NUM_MEMBERS
+An integer which will get the number of members defined for this
+enumeration type.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADTYPEID
+Bad type id. 
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node NF90_INQ_ENUM_MEMBER, NF90_INQ_ENUM_IDENT, NF90_INQ_ENUM, Enum Type
+ at subsection Learn the Name of a Enum Type: nf90_inq_enum_member
+ at findex nf90_inq_enum_member
+
+Get information about a member of an enum type.
+
+ at heading Usage 
+
+ at example
+  function nf90_inq_enum_member(ncid, xtype, idx, name, value)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: xtype
+    integer, intent(in) :: idx
+    character (len = *), intent(out) :: name
+    integer, intent(in) :: value
+    integer :: nf90_inq_enum_member
+ at end example
+
+ at table @code
+
+ at item NCID
+The groupid where this enum type exists.
+
+ at item XTYPE
+The typeid for this enum type.
+
+ at item IDX
+The one-based index number for the member of interest. 
+
+ at item NAME
+A character array which will get the name of the member. It will have
+a maximum length of NF90_MAX_NAME.
+
+ at item VALUE
+An integer that will get the value associated with this member.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADTYPEID
+Bad type id. 
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node NF90_INQ_ENUM_IDENT,  , NF90_INQ_ENUM_MEMBER, Enum Type
+ at subsection Learn the Name of a Enum Type: NF90_INQ_ENUM_IDENT
+ at findex NF90_INQ_ENUM_IDENT
+
+Get the name which is associated with an enum member value.
+
+This is similar to NF90_INQ_ENUM_MEMBER, but instead of using the index
+of the member, you use the value of the member.
+
+ at heading Usage 
+
+ at example
+  function nf90_inq_enum_ident(ncid, xtype, value, idx)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: xtype
+    integer, intent(in) :: value
+    integer, intent(out) :: idx
+    integer :: nf90_inq_enum_ident
+ at end example
+
+ at table @code
+
+ at item NCID
+The groupid where this enum type exists.
+
+ at item XTYPE
+The typeid for this enum type.
+
+ at item VALUE
+The value for which an identifier is sought.
+
+ at item IDENTIFIER
+A character array that will get the identifier. It will have a maximum
+length of NF90_MAX_NAME.
+
+ at end table
+
+ at heading Return Code
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_EBADTYPEID
+Bad type id, or not an enum type.
+
+ at item NF90_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at item NF90_EINVAL
+The value was not found in the enum.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node Variables, Attributes, User Defined Data Types, Top
+ at chapter Variables
+
+ at menu
+* Variables Introduction::      
+* Language-Types::              
+* NF90_DEF_VAR::                Create a Variable
+* NF90_DEF_VAR_FILL::           
+* NF90_INQ_VAR_FILL::           
+* NF90_INQUIRE_VARIABLE::       Get Var Metadata
+* NF90_INQ_VARID::              
+* NF90_PUT_VAR::                Write data
+* NF90_GET_VAR::                Read data
+* Reading and Writing Character String Values::  
+* Fill Values::                 What's Written Where there's No Data?
+* NF90_RENAME_VAR::             
+* NF90_VAR_PAR_ACCESS::         
+ at end menu
+
+ at node Variables Introduction, Language-Types, Variables, Variables
+ at section Variables Introduction
+
+Variables for a netCDF dataset are defined when the dataset is
+created, while the netCDF dataset is in define mode. Other variables
+may be added later by reentering define mode. A netCDF variable has a
+name, a type, and a shape, which are specified when it is defined. A
+variable may also have values, which are established later in data
+mode.
+
+Ordinarily, the name, type, and shape are fixed when the variable is
+first defined. The name may be changed, but the type and shape of a
+variable cannot be changed. However, a variable defined in terms of
+the unlimited dimension can grow without bound in that dimension.
+
+A netCDF variable in an open netCDF dataset is referred to by a small
+integer called a variable ID.
+
+Variable IDs reflect the order in which variables were defined within
+a netCDF dataset. Variable IDs are 1, 2, 3,..., in the order in which
+the variables were defined. A function is available for getting the
+variable ID from the variable name and vice-versa.
+
+Attributes (see @ref{Attributes}) may be associated with a variable to
+specify such properties as units.
+
+Operations supported on variables are:
+ at itemize
+
+ at item
+Create a variable, given its name, data type, and shape. 
+
+ at item
+Get a variable ID from its name. 
+
+ at item
+Get a variable's name, data type, shape, and number of attributes from
+its ID.
+
+ at item
+Put a data value into a variable, given variable ID, indices, and
+value.
+
+ at item
+Put an array of values into a variable, given variable ID, corner
+indices, edge lengths, and a block of values.
+
+ at item
+Put a subsampled or mapped array-section of values into a variable,
+given variable ID, corner indices, edge lengths, stride vector, index
+mapping vector, and a block of values.
+
+ at item
+Get a data value from a variable, given variable ID and indices. 
+
+ at item
+Get an array of values from a variable, given variable ID, corner
+indices, and edge lengths.
+
+ at item
+Get a subsampled or mapped array-section of values from a variable,
+given variable ID, corner indices, edge lengths, stride vector, and
+index mapping vector.
+
+ at item
+Rename a variable. 
+ at end itemize
+
+ at node Language-Types, NF90_DEF_VAR, Variables Introduction, Variables
+ at section Language Types Corresponding to netCDF external data types
+
+The following table gives the netCDF external data types and the
+corresponding type constants for defining variables in the FORTRAN
+interface:
+
+ at multitable @columnfractions .25 .60 .15
+ at item Type @tab FORTRAN API Mnemonic @tab Bits
+
+ at item byte
+ at tab NF90_BYTE 
+ at tab 8
+ 
+ at item char
+ at tab NF90_CHAR 
+ at tab 8
+ 
+ at item short
+ at tab NF90_SHORT 
+ at tab 16
+ 
+ at item int
+ at tab NF90_INT 
+ at tab 32
+ 
+ at item float
+ at tab NF90_FLOAT 
+ at tab 32
+ 
+ at item double
+ at tab NF90_DOUBLE 
+ at tab 64
+ at end multitable
+ 
+The first column gives the netCDF external data type, which is the
+same as the CDL data type. The next column gives the corresponding
+Fortran 90 parameter for use in netCDF functions (the parameters are
+defined in the netCDF Fortran 90 module netcdf.f90). The last column
+gives the number of bits used in the external representation of values
+of the corresponding type.
+
+Note that there are no netCDF types corresponding to 64-bit integers
+or to characters wider than 8 bits in the current version of the
+netCDF library.
+
+ at node NF90_DEF_VAR, NF90_DEF_VAR_FILL, Language-Types, Variables
+ at section Create a Variable: @code{NF90_DEF_VAR} 
+ at findex NF90_DEF_VAR
+ at cindex NF90_DEF_VAR, example
+
+The function NF90_DEF_VAR adds a new variable to an open netCDF dataset
+in define mode. It returns (as an argument) a variable ID, given the
+netCDF ID, the variable name, the variable type, the number of
+dimensions, and a list of the dimension IDs.
+
+Optional arguments allow additional settings for variables in
+netCDF-4/HDF5 files. These parameters allow data compression and
+control of the layout of the data on disk for performance tuning.
+These parameters may also be used to set the chunk sizes to get chunked
+storage, or to set the contiguous flag to get contiguous storage.
+
+Variables that make use of one or more unlimited dimensions,
+compression, or checksums must use chunking.  Such variables are
+created with default chunk sizes of 1 for each unlimited dimension and
+the dimension length for other dimensions, except that if the
+resulting chunks are too large, the default chunk sizes for non-record
+dimensions are reduced.
+
+All parameters after the varid are optional, and only supported if
+netCDF was built with netCDF-4 features enabled, and if the variable
+is in a netCDF-4/HDF5 file.
+
+ at heading Usage 
+ at example
+ function nf90_def_var(ncid, name, xtype, dimids, varid, contiguous, &
+       chunksizes, deflate_level, shuffle, fletcher32, endianness, &
+       cache_size, cache_nelems, cache_preemption)
+   integer, intent(in) :: ncid
+   character (len = *), intent(in) :: name
+   integer, intent( in) :: xtype
+   integer, scalar or dimension(:), intent(in), optional :: dimids
+   integer, intent(out) :: varid
+   logical, optional, intent(in) :: contiguous
+   integer, optional, dimension(:), intent(in) :: chunksizes
+   integer, optional, intent(in) :: deflate_level
+   logical, optional, intent(in) :: shuffle, fletcher32
+   integer, optional, intent(in) :: endianness
+    integer, optional, intent(in) :: cache_size, cache_nelems, cache_preemption
+   integer                                      :: nf90_def_var
+ at end example
+
+ at table @code
+ at item ncid
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
+ 
+ at item name
+Variable name.
+ 
+ at item xtype
+One of the set of predefined netCDF external data types. The type of
+this parameter, NF90_TYPE, is defined in the netCDF header file. The
+valid netCDF external data types are NF90_BYTE, NF90_CHAR, NF90_SHORT,
+NF90_INT, NF90_FLOAT, and NF90_DOUBLE. If the file is a NetCDF-4/HDF5 file,
+the additional types NF90_UBYTE, NF90_USHORT, NF90_UINT, NF90_INT64,
+NF90_UINT64, and NF90_STRING may be used, as well as a user defined type
+ID.
+ 
+ at item dimids
+Scalar or vector of dimension IDs corresponding to the variable dimensions. For
+example, a vector of 2 dimension IDs specifies a 2-dimensional matrix.
+
+If an integer is passed for this parameter, a 1-D variable is created.
+
+If this parameter is not passed (or is a 1D array of size zero) it
+means the variable is a scalar with no dimensions.
+
+For classic data model files, if the ID of the unlimited dimension is
+included, it must be first.  In expanded model netCDF4/HDF5 files,
+there may be any number of unlimited dimensions, and they may be used
+in any element of the dimids array.
+
+This argument is optional, and if absent specifies a scalar with no
+dimensions.
+ 
+ at item varid
+Returned variable ID.
+
+ at item storage
+If NF90_CONTIGUOUS, then contiguous storage is used for this
+variable. Variables that use deflation, shuffle filter, or checksums,
+or that have one or more unlimited dimensions cannot use contiguous
+storage.
+
+If NF90_CHUNKED, then chunked storage is used for this variable.
+Chunk sizes may be specified with the chunksizes parameter.
+Default sizes will be used if chunking is required and this function
+is not called.
+
+By default contiguous storage is used for fix-sized variables when
+conpression, chunking, shuffle, and checksums are not used.
+
+ at item chunksizes
+An array of chunk number of elements. This array has the number of
+elements along each dimension of the data chunk. The array must have
+the one chunksize for each dimension in the variable.
+
+The total size of a chunk must be less than 4 GiB. That is, the product
+of all chunksizes and the size of the data (or the size of nc_vlen_t
+for VLEN types) must be less than 4 GiB. (This is a very large chunk
+size in any case.)
+
+If not provided, but chunked data are needed, then default chunksizes
+will be chosen. For more information see @ref{Chunking,
+ at value{n-man},, netcdf, @value{n-man}}.
+
+ at item shuffle
+If non-zero, turn on the shuffle filter.
+
+ at item deflate_level
+If the deflate parameter is non-zero, set the deflate level to this
+value. Must be between 1 and 9.
+
+ at item fletcher32
+Set to true to turn on fletcher32 checksums for this variable.
+ 
+ at item endianness
+Set to NF90_ENDIAN_LITTLE for little-endian format, NF90_ENDIAN_BIG
+for big-endian format, and NF90_ENDIAN_NATIVE (the default) for the
+native endianness of the platform.
+
+ at item cache_size
+The size of the per-variable cache in MegaBytes.
+
+ at item cache_nelems
+The number slots in the per-variable chunk cache (should be a prime number
+larger than the number of chunks in the cache).
+
+ at item cache_preemption
+The preemtion value must be between 0 and 100 inclusive and indicates
+how much chunks that have been fully read are favored for
+preemption. A value of zero means fully read chunks are treated no
+differently than other chunks (the preemption is strictly LRU) while a
+value of 100 means fully read chunks are always preempted before other
+chunks. 
+
+ at end table
+
+ at heading Return Codes
+
+NF90_DEF_VAR returns the value NF90_NOERR if no errors occurred.
+Otherwise, the returned status indicates an error. 
+
+ at itemize
+
+ at item NF90_EBADNAME
+The specified variable name is the name of another existing variable. 
+
+ at item NF90_EBADTYPE
+The specified type is not a valid netCDF type. 
+
+ at item NF90_EMAXDIMS
+The specified number of dimensions is negative or more than the
+constant NF90_MAX_VAR_DIMS, the maximum number of dimensions permitted
+for a netCDF variable. (Does not apply to netCDF-4/HDF5 files unless they were
+created with the CLASSIC_MODE flag.)
+
+ at item NF90_EBADDIM
+One or more of the dimension IDs in the list of dimensions is not a
+valid dimension ID for the netCDF dataset.
+
+ at item NF90_EMAXVARS
+The number of variables would exceed the constant NF90_MAX_VARS, the
+maximum number of variables permitted in a classic netCDF
+dataset. (Does not apply to netCDF-4/HDF5 files unless they were
+created with the CLASSIC_MODE flag.)
+
+ at item NF90_BADID
+The specified netCDF ID does not refer to an open netCDF dataset. 
+
+ at item NF90_ENOTNC4
+NetCDF-4 operation attempted on a files that is not a netCDF-4/HDF5
+file. Only variables in NetCDF-4/HDF5 files may use compression,
+chunking, and endianness control.
+
+ at item NF90_ENOTVAR
+Can't find this variable.
+
+ at item NF90_EINVAL
+Invalid input. This may be because contiguous storage is requested for
+a variable that has compression, checksums, chunking, or one or more
+unlimited dimensions.
+
+ at item NF90_ELATEDEF
+This variable has already been the subject of a NF90_ENDDEF call. Once
+enddef has been called, it is impossible to set the chunking for a
+variable. (In netCDF-4/HDF5 files NF90_ENDDEF will be called
+automatically for any data read or write.)
+
+ at item NF90_ENOTINDEFINE
+Not in define mode. This is returned for netCDF classic or 64-bit
+offset files, or for netCDF-4 files, when they were been created with
+NF90_STRICT_NC3 flag. (@pxref{NF90_CREATE}).
+
+ at item NF90_ESTRICTNC3
+Trying to create a var some place other than the root group in a
+netCDF file with NF90_STRICT_NC3 turned on.
+
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF90_DEF_VAR to create a variable named rh of
+type double with three dimensions, time, lat, and lon in a new netCDF
+dataset named foo.nc:
+
+ at example
+ use netcdf
+ implicit none
+ integer :: status, ncid
+ integer :: LonDimId, LatDimId, TimeDimId
+ integer :: RhVarId
+ ...
+ status = nf90_create("foo.nc", nf90_NoClobber, ncid)
+ if(status /= nf90_NoErr) call handle_error(status)
+ ...
+ ! Define the dimensions
+ status = nf90_def_dim(ncid, "lat", 5, LatDimId)
+ if(status /= nf90_NoErr) call handle_error(status)
+ status = nf90_def_dim(ncid, "lon", 10, LonDimId)
+ if(status /= nf90_NoErr) call handle_error(status)
+ status = nf90_def_dim(ncid, "time", nf90_unlimited, TimeDimId)
+ if(status /= nf90_NoErr) call handle_error(status)
+ ...
+ ! Define the variable
+ status = nf90_def_var(ncid, "rh", nf90_double, &
+                       (/ LonDimId, LatDimID, TimeDimID /), RhVarId)
+ if(status /= nf90_NoErr) call handle_error(status)
+ at end example
+
+In the following example, from nf_test/f90tst_vars2.f90, chunking,
+checksums, and endianness control are all used in a netCDF-4/HDF5
+file.
+
+ at example
+  ! Create the netCDF file. 
+  call check(nf90_create(FILE_NAME, nf90_netcdf4, ncid, cache_nelems = CACHE_NELEMS, &
+       cache_size = CACHE_SIZE))
+
+  ! Define the dimensions.
+  call check(nf90_def_dim(ncid, "x", NX, x_dimid))
+  call check(nf90_def_dim(ncid, "y", NY, y_dimid))
+  dimids =  (/ y_dimid, x_dimid /)
+
+  ! Define some variables. 
+  chunksizes = (/ NY, NX /)
+  call check(nf90_def_var(ncid, VAR1_NAME, NF90_INT, dimids, varid1, chunksizes = chunksizes, &
+       shuffle = .TRUE., fletcher32 = .TRUE., endianness = nf90_endian_big, deflate_level = DEFLATE_LEVEL))
+  call check(nf90_def_var(ncid, VAR2_NAME, NF90_INT, dimids, varid2, contiguous = .TRUE.))
+  call check(nf90_def_var(ncid, VAR3_NAME, NF90_INT64, varid3))
+  call check(nf90_def_var(ncid, VAR4_NAME, NF90_INT, x_dimid, varid4, contiguous = .TRUE.))
+ at end example
+
+ at node NF90_DEF_VAR_FILL, NF90_INQ_VAR_FILL, NF90_DEF_VAR, Variables
+ at section Define Fill Parameters for a Variable: @code{nf90_def_var_fill}
+ at findex NF90_DEF_VAR_FILL
+ at cindex fill
+ at cindex variables, fill
+
+The function NF90_DEF_VAR_FILL sets the fill parameters for a
+variable in a netCDF-4 file. 
+
+This function must be called after the variable is defined, but before
+NF90_ENDDEF is called.
+
+ at heading Usage 
+
+ at example
+NF90_DEF_VAR_FILL(INTEGER NCID, INTEGER VARID, INTEGER NO_FILL, FILL_VALUE);
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
+ 
+ at item VARID
+Variable ID.
+
+ at item NO_FILL
+Set to non-zero value to set no_fill mode on a variable. When this
+mode is on, fill values will not be written for the variable. This is
+helpful in high performance applications. For netCDF-4/HDF5 files
+(whether classic model or not), this may only be changed after the
+variable is defined, but before it is committed to disk (i.e. before
+the first NF90_ENDDEF after the NF90_DEF_VAR.) For classic and 64-bit
+offset file, the no_fill mode may be turned on and off at any time.
+
+ at item FILL_VALUE
+A value which will be used as the fill value for the variable. Must be
+the same type as the variable. This will be written to a _FillValue
+attribute, created for this purpose. If NULL, this argument will be
+ignored.
+ 
+ at end table
+
+ at heading Return Codes
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_BADID
+Bad ncid.
+
+ at item NF90_ENOTNC4
+Not a netCDF-4 file.
+
+ at item NF90_ENOTVAR
+Can't find this variable.
+
+ at item NF90_ELATEDEF
+This variable has already been the subject of a NF90_ENDDEF call. In
+netCDF-4 files NF90_ENDDEF will be called automatically for any data
+read or write. Once enddef has been called, it is impossible to set
+the fill for a variable.
+
+ at item NF90_ENOTINDEFINE
+Not in define mode. This is returned for netCDF classic or 64-bit
+offset files, or for netCDF-4 files, when they were been created with
+NF90_STRICT_NC3 flag. (@pxref{NF90_CREATE}).
+
+ at item NF90_EPERM
+Attempt to create object in read-only file.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node NF90_INQ_VAR_FILL, NF90_INQUIRE_VARIABLE, NF90_DEF_VAR_FILL, Variables
+ at section Learn About Fill Parameters for a Variable: @code{NF90_INQ_VAR_FILL}
+ at findex NF90_INQ_VAR_FILL
+
+The function NF90_INQ_VAR_FILL returns the fill settings for a
+variable in a netCDF-4 file. 
+
+ at heading Usage 
+
+ at example
+NF90_INQ_VAR_FILL(INTEGER NCID, INTEGER VARID, INTEGER NO_FILL, FILL_VALUE)
+ at end example
+
+ at table @code
+
+ at item NCID
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
+ 
+ at item VARID
+Variable ID.
+
+ at item NO_FILL
+An integer which will get a 1 if no_fill mode is set for this
+variable, and a zero if it is not set
+
+ at item FILL_VALUE
+This will get the fill value for this variable. This
+parameter will be ignored if it is NULL.
+
+ at end table
+
+ at heading Return Codes
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_BADID
+Bad ncid.
+
+ at item NF90_ENOTNC4
+Not a netCDF-4 file.
+
+ at item NF90_ENOTVAR
+Can't find this variable.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node NF90_INQUIRE_VARIABLE, NF90_INQ_VARID, NF90_INQ_VAR_FILL, Variables
+ at section Get Information about a Variable from Its ID: NF90_INQUIRE_VARIABLE
+ at findex NF90_INQUIRE_VARIABLE 
+ at cindex NF90_INQUIRE_VARIABLE , example
+
+NF90_INQUIRE_VARIABLE returns information about a netCDF variable
+given its ID. Information about a variable includes its name, type,
+number of dimensions, a list of dimension IDs describing the shape of
+the variable, and the number of variable attributes that have been
+assigned to the variable.
+
+All parameters after nAtts are optional, and only supported if netCDF
+was built with netCDF-4 features enabled, and if the variable is in a
+netCDF-4/HDF5 file.
+
+ at heading Usage 
+ at example
+  function nf90_inquire_variable(ncid, varid, name, xtype, ndims, dimids, nAtts, &
+       contiguous, chunksizes, deflate_level, shuffle, fletcher32, endianness)
+    integer, intent(in) :: ncid, varid
+    character (len = *), optional, intent(out) :: name
+    integer, optional, intent(out) :: xtype, ndims 
+    integer, dimension(:), optional, intent(out) :: dimids
+    integer, optional, intent(out) :: nAtts
+    logical, optional, intent(out) :: contiguous
+    integer, optional, dimension(:), intent(out) :: chunksizes
+    integer, optional, intent(out) :: deflate_level
+    logical, optional, intent(out) :: shuffle, fletcher32
+    integer, optional, intent(out) :: endianness
+    integer :: nf90_inquire_variable
+ at end example
+
+ at table @code
+ at item ncid
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
+ 
+ at item varid
+Variable ID.
+ 
+ at item name
+Returned variable name. The caller must allocate space for the
+returned name. The maximum possible length, in characters, of a
+variable name is given by the predefined constant NF90_MAX_NAME.
+ 
+ at item xtype
+Returned variable type, one of the set of predefined netCDF external
+data types. The valid netCDF external data types are NF90_BYTE,
+NF90_CHAR, NF90_SHORT, NF90_INT, NF90_FLOAT, AND NF90_DOUBLE.
+ 
+ at item ndims
+Returned number of dimensions the variable was defined as using. For
+example, 2 indicates a matrix, 1 indicates a vector, and 0 means the
+variable is a scalar with no dimensions.
+ 
+ at item dimids
+Returned vector of *ndimsp dimension IDs corresponding to the
+variable dimensions. The caller must allocate enough space for a
+vector of at least *ndimsp integers to be returned. The maximum
+possible number of dimensions for a variable is given by the
+predefined constant NF90_MAX_VAR_DIMS.
+ 
+ at item natts
+Returned number of variable attributes assigned to this variable.
+
+ at item contiguous
+On return, set to NF90_CONTIGUOUS if this variable uses contiguous
+storage, NF90_CHUNKED if it uses chunked storage.
+
+ at item chunksizes
+An array of chunk sizes. The array must have the one element for
+each dimension in the variable.
+
+ at item shuffle
+True if the shuffle filter is turned on for this variable.
+
+ at item deflate_level
+The deflate_level from 0 to 9. A value of zero indicates no deflation
+is in use.
+
+ at item fletcher32
+Set to true if the fletcher32 checksum filter is turned on for this
+variable.
+ 
+ at item endianness
+Will be set to NF90_ENDIAN_LITTLE if this variable is stored in
+little-endian format, NF90_ENDIAN_BIG if it is stored in big-endian
+format, and NF90_ENDIAN_NATIVE if the endianness is not set, and the
+variable is not created yet.
+
+ at end table
+
+These functions return the value NF90_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The variable ID is invalid for the specified netCDF dataset. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF90_INQ_VAR to find out about a variable named
+rh in an existing netCDF dataset named foo.nc:
+
+ at example
+    use netcdf
+    implicit none
+    integer                            :: status, ncid, &
+                                          RhVarId       &
+                                          numDims, numAtts
+ integer, dimension(nf90_max_var_dims) :: rhDimIds
+ ...
+ status = nf90_open("foo.nc", nf90_NoWrite, ncid)
+ if(status /= nf90_NoErr) call handle_error(status)
+ ...
+ status = nf90_inq_varid(ncid, "rh", RhVarId)
+ if(status /= nf90_NoErr) call handle_err(status)
+ status = nf90_inquire_variable(ncid, RhVarId, ndims = numDims, natts = numAtts)
+ if(status /= nf90_NoErr) call handle_err(status)
+ status = nf90_inquire_variable(ncid, RhVarId, dimids = rhDimIds(:numDims))
+ if(status /= nf90_NoErr) call handle_err(status)
+ at end example
+
+ at node NF90_INQ_VARID, NF90_PUT_VAR, NF90_INQUIRE_VARIABLE, Variables
+ at section Get the ID of a variable from the name: NF90_INQ_VARID
+ at findex NF90_INQ_VARID 
+ at cindex NF90_INQ_VARID, example
+
+Given the name of a varaible, nf90_inq_varid finds the variable ID.
+
+ at heading Usage 
+ at example
+  function nf90_inq_varid(ncid, name, varid)
+    integer, intent(in) :: ncid
+    character (len = *), intent( in) :: name
+    integer, intent(out) :: varid
+    integer :: nf90_inq_varid
+ at end example
+
+ at table @code
+ at item ncid
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
+ 
+ at item name
+The variable name. The maximum possible length, in characters, of a
+variable name is given by the predefined constant NF90_MAX_NAME.
+ 
+ at item varid
+Variable ID.
+ 
+ at end table
+
+These functions return the value NF90_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+Variable not found.
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF90_INQ_VARID to find out about a variable
+named rh in an existing netCDF dataset named foo.nc:
+
+ at example
+    use netcdf
+    implicit none
+    integer                            :: status, ncid, &
+                                          RhVarId       &
+                                          numDims, numAtts
+ integer, dimension(nf90_max_var_dims) :: rhDimIds
+ ...
+ status = nf90_open("foo.nc", nf90_NoWrite, ncid)
+ if(status /= nf90_NoErr) call handle_error(status)
+ ...
+ status = nf90_inq_varid(ncid, "rh", RhVarId)
+ if(status /= nf90_NoErr) call handle_err(status)
+ status = nf90_inquire_variable(ncid, RhVarId, ndims = numDims, natts = numAtts)
+ if(status /= nf90_NoErr) call handle_err(status)
+ status = nf90_inquire_variable(ncid, RhVarId, dimids = rhDimIds(:numDims))
+ if(status /= nf90_NoErr) call handle_err(status)
+ at end example
+
+ at node NF90_PUT_VAR, NF90_GET_VAR, NF90_INQ_VARID, Variables
+ at section Writing Data Values: NF90_PUT_VAR
+ at findex NF90_PUT_VAR
+ at cindex NF90_PUT_VAR, example
+
+The function NF90_PUT_VAR puts one or more data values into the
+variable of an open netCDF dataset that is in data mode. Required
+inputs are the netCDF ID, the variable ID, and one or more data
+values. Optional inputs may indicate the starting position of the data
+values in the netCDF variable (argument start), the sampling frequency
+with which data values are written into the netCDF variable (argument
+stride), and a mapping between the dimensions of the data array and
+the netCDF variable (argument map). The values to be written are
+associated with the netCDF variable by assuming that the first
+dimension of the netCDF variable varies fastest in the Fortran 90
+interface. Data values are converted to the external type of the variable,
+if necessary.
+
+Take care when using the simplest forms of this interface with record
+variables (variables that use the NF90_UNLIMITED dimension) when you
+don't specify how many records are to be written. If you try to write
+all the values of a record variable into a netCDF file that has no
+record data yet (hence has 0 records), nothing will be
+written. Similarly, if you try to write all the values of a record
+variable from an array but there are more records in the file than you
+assume, more in-memory data will be accessed than you expect, which may
+cause a segmentation violation.  To avoid such problems, it is better
+to specify start and count arguments for variables that use the
+NF90_UNLIMITED dimension.
+
+ at heading Usage 
+ at example
+ function nf90_put_var(ncid, varid, values, start, count, stride, map)
+   integer,                         intent( in) :: ncid, varid
+   any valid type, scalar or array of any rank, &
+                                    intent( in) :: values
+   integer, dimension(:), optional, intent( in) :: start, count, stride, map
+   integer                                      :: nf90_put_var
+ at end example
+
+ at table @code
+ at item ncid
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
+ 
+ at item varid
+Variable ID.
+ 
+ at item values
+The data value(s) to be written. The data may be of any type, and may
+be a scalar or an array of any rank.  You cannot put CHARACTER data
+into a numeric variable or numeric data into a text variable. For
+numeric data, if the type of data differs from the netCDF variable
+type, type conversion will occur. @xref{Type Conversion,,, netcdf,
+NetCDF Users Guide}.
+
+ at item start
+A vector of integers specifying the index in the variable where the
+first (or only) of the data values will be written. The indices are
+relative to 1, so for example, the first data value of a variable
+would have index (1, 1, ..., 1). The elements of start correspond, in
+order, to the variable's dimensions. Hence, if the variable is a
+record variable, the last index would correspond to the starting
+record number for writing the data values.  
+
+By default, start(:) = 1.
+
+ at item count
+A vector of integers specifying the number of indices selected along
+each dimension. To write a single value, for example, specify count as
+(1, 1, ..., 1). The elements of count correspond, in order, to the
+variable's dimensions. Hence, if the variable is a record variable,
+the last element of count corresponds to a count of the number of
+records to write.  
+
+By default, count(:numDims) = shape(values) and
+count(numDims + 1:) = 1, where numDims = size(shape(values)).
+
+ at item stride
+A vector of integers that specifies the sampling interval along each
+dimension of the netCDF variable. The elements of the stride vector
+correspond, in order, to the netCDF variable's dimensions (stride(1)
+gives the sampling interval along the most rapidly varying dimension
+of the netCDF variable). Sampling intervals are specified in
+type-independent units of elements (a value of 1 selects consecutive
+elements of the netCDF variable along the corresponding dimension, a
+value of 2 selects every other element, etc.).
+
+By default, stride(:) = 1. 
+
+ at item imap
+A vector of integers that specifies the mapping between the dimensions
+of a netCDF variable and the in-memory structure of the internal data
+array. The elements of the index mapping vector correspond, in order,
+to the netCDF variable's dimensions (map(1) gives the distance between
+elements of the internal array corresponding to the most rapidly
+varying dimension of the netCDF variable). Distances between elements
+are specified in units of elements.
+
+By default, edgeLengths = shape(values), and 
+map = (/ 1, (product(edgeLengths(:i)), i = 1, size(edgeLengths) - 1) /), 
+that is, there is no mapping. 
+
+Use of Fortran 90 intrinsic functions (including reshape, transpose,
+and spread) may let you avoid using this argument. 
+ at end table
+
+ at heading Errors 
+
+NF90_PUT_VAR1_  type returns the value NF90_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The variable ID is invalid for the specified netCDF dataset.
+
+ at item
+The specified indices were out of range for the rank of the specified
+variable. For example, a negative index or an index that is larger
+than the corresponding dimension length will cause an error.
+
+ at item
+The specified value is out of the range of values representable by the
+external data type of the variable.
+
+ at item
+The specified netCDF is in define mode rather than data mode. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF90_PUT_VAR to set the (4,3,2) element of
+the variable named rh to 0.5 in an existing netCDF dataset named
+foo.nc. For simplicity in this example, we assume that we know that rh
+is dimensioned with lon, lat, and time, so we want to set the value of
+rh that corresponds to the fourth lon value, the third lat value, and
+the second time value:
+
+ at example
+ use netcdf
+ implicit none
+ integer :: ncId, rhVarId, status
+ ...
+ status = nf90_open("foo.nc", nf90_Write, ncid)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ...
+ status = nf90_inq_varid(ncid, "rh", rhVarId)
+ if(status /= nf90_NoErr) call handle_err(status)
+ status = nf90_put_var(ncid, rhVarId, 0.5, start = (/ 4, 3, 2 /) )
+ if(status /= nf90_NoErr) call handle_err(status)
+ at end example
+
+In this example we use NF90_PUT_VAR to add or change all the values of
+the variable named rh to 0.5 in an existing netCDF dataset named
+foo.nc. We assume that we know that rh is dimensioned with lon, lat,
+and time. In this example we query the netCDF file to discover the
+lengths of the dimensions, then use the Fortran 90 intrinsic function
+reshape to create a temporary array of data values which is the same
+shape as the netCDF variable.
+
+ at example
+ use netcdf
+ implicit none
+ integer                               :: ncId, rhVarId,status,          &
+                                          lonDimID, latDimId, timeDimId, &
+                                          numLons, numLats, numTimes,    &
+                                          i
+ integer, dimension(nf90_max_var_dims) :: dimIDs
+ ...
+ status = nf90_open("foo.nc", nf90_Write, ncid)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ...
+ status = nf90_inq_varid(ncid, "rh", rhVarId)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ! How big is the netCDF variable, that is, what are the lengths of 
+ !   its constituent dimensions? 
+ status = nf90_inquire_variable(ncid, rhVarId, dimids = dimIDs)
+ if(status /= nf90_NoErr) call handle_err(status)
+ status = nf90_inquire_dimension(ncid, dimIDs(1), len = numLons)
+ if(status /= nf90_NoErr) call handle_err(status)
+ status = nf90_inquire_dimension(ncid, dimIDs(2), len = numLats)
+ if(status /= nf90_NoErr) call handle_err(status)
+ status = nf90_inquire_dimension(ncid, dimIDs(3), len = numTimes)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ...
+ ! Make a temporary array the same shape as the netCDF variable. 
+ status = nf90_put_var(ncid, rhVarId, &
+                       reshape( &
+                         (/ (0.5, i = 1, numLons * numLats * numTimes) /) , &
+                        shape = (/ numLons, numLats, numTimes /) )
+ if(status /= nf90_NoErr) call handle_err(status)
+ at end example
+
+Here is an example using NF90_PUT_VAR to add or change a section of
+the variable named rh to 0.5 in an existing netCDF dataset named
+foo.nc. For simplicity in this example, we assume that we know that rh
+is dimensioned with lon, lat, and time, that there are ten lon values,
+five lat values, and three time values, and that we want to replace
+all the values at the last time.
+
+ at example
+ use netcdf
+ implicit none
+ integer            :: ncId, rhVarId, status
+ integer, parameter :: numLons = 10, numLats = 5, numTimes = 3
+ real, dimension(numLons, numLats) &
+                    :: rhValues
+ ...
+ status = nf90_open("foo.nc", nf90_Write, ncid)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ...
+ status = nf90_inq_varid(ncid, "rh", rhVarId)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ! Fill in all values at the last time
+ rhValues(:, :) = 0.5
+ status = nf90_put_var(ncid, rhVarId,rhvalues,       &
+                       start = (/ 1, 1, numTimes /), &
+                       count = (/ numLats, numLons, 1 /))
+ if(status /= nf90_NoErr) call handle_err(status)
+ at end example
+
+Here is an example of using NF90_PUT_VAR to write every other point of a
+netCDF variable named rh having dimensions (6, 4).
+
+ at example
+ use netcdf
+ implicit none
+ integer            :: ncId, rhVarId, status
+ integer, parameter :: numLons = 6, numLats = 4
+ real, dimension(numLons, numLats) &
+                    :: rhValues = 0.5
+ ...
+ status = nf90_open("foo.nc", nf90_Write, ncid)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ...
+ status = nf90_inq_varid(ncid, "rh", rhVarId)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ...
+ ! Fill in every other value using an array section 
+ status = nf90_put_var(ncid, rhVarId, rhValues(::2, ::2), &
+                       stride = (/ 2, 2 /))
+ if(status /= nf90_NoErr) call handle_err(status)
+ at end example
+
+The following map vector shows the default mapping between a 2x3x4
+netCDF variable and an internal array of the same shape:
+
+ at example
+ real,    dimension(2, 3, 4):: a  ! same shape as netCDF variable
+ integer, dimension(3)      :: map  = (/ 1, 2, 6 /) 
+                     ! netCDF dimension inter-element distance
+                     ! ---------------- ----------------------
+                     ! most rapidly varying       1
+                     ! intermediate               2 (= map(1)*2)
+                     ! most slowly varying        6 (= map(2)*3)
+ at end example
+
+Using the map vector above obtains the same result as simply not passing a map vector at all. 
+
+Here is an example of using nf90_put_var to write a netCDF variable
+named rh whose dimensions are the transpose of the Fortran 90 array:
+
+ at example
+ use netcdf
+ implicit none
+ integer                           :: ncId, rhVarId, status
+ integer, parameter                :: numLons = 6, numLats = 4
+ real, dimension(numLons, numLats) :: rhValues
+ ! netCDF variable has dimensions (numLats, numLons)
+ ...
+ status = nf90_open("foo.nc", nf90_Write, ncid)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ...
+ status = nf90_inq_varid(ncid, "rh", rhVarId)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ...
+ !Write transposed values: map vector would be (/ 1, numLats /) for 
+ !   no transposition
+ status = nf90_put_var(ncid, rhVarId,rhValues, map = (/ numLons, 1 /)) 
+ if(status /= nf90_NoErr) call handle_err(status)
+ at end example
+
+The same effect can be obtained more simply using Fortran 90 intrinsic functions: 
+
+ at example
+ use netcdf
+ implicit none
+ integer                           :: ncId, rhVarId, status
+ integer, parameter                :: numLons = 6, numLats = 4
+ real, dimension(numLons, numLats) :: rhValues
+ ! netCDF variable has dimensions (numLats, numLons)
+ ...
+ status = nf90_open("foo.nc", nf90_Write, ncid)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ...
+ status = nf90_inq_varid(ncid, "rh", rhVarId)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ...
+ status = nf90_put_var(ncid, rhVarId, transpose(rhValues)) 
+ if(status /= nf90_NoErr) call handle_err(status)
+ at end example
+
+ at node NF90_GET_VAR, Reading and Writing Character String Values, NF90_PUT_VAR, Variables
+ at section Reading Data Values: NF90_GET_VAR
+ at findex NF90_GET_VAR
+ at cindex NF90_GET_VAR, example
+
+The function NF90_GET_VAR gets one or more data values from a netCDF
+variable of an open netCDF dataset that is in data mode. Required
+inputs are the netCDF ID, the variable ID, and a specification for the
+data values into which the data will be read. Optional inputs may
+indicate the starting position of the data values in the netCDF
+variable (argument start), the sampling frequency with which data
+values are read from the netCDF variable (argument stride), and a
+mapping between the dimensions of the data array and the netCDF
+variable (argument map). The values to be read are associated with the
+netCDF variable by assuming that the first dimension of the netCDF
+variable varies fastest in the Fortran 90 interface. Data values are
+converted from the external type of the variable, if necessary.
+
+Take care when using the simplest forms of this interface with record
+variables (variables that use the NF90_UNLIMITED dimension) when you
+don't specify how many records are to be read. If you try to read all
+the values of a record variable into an array but there are more
+records in the file than you assume, more data will be read than you
+expect, which may cause a segmentation violation.  To avoid such
+problems, it is better to specify the optional start and count
+arguments for variables that use the NF90_UNLIMITED dimension.
+
+In netCDF classic model the maximum integer size is NF90_INT, the
+4-byte signed integer. Reading variables into an eight-byte integer
+array from a classic model file will read from an NF90_INT. Reading
+variables into an eight-byte integer in a netCDF-4/HDF5 (without
+classic model flag) will read from an NF90_INT64
+
+ at heading Usage 
+ at example
+ function nf90_get_var(ncid, varid, values, start, count, stride, map)
+   integer,                         intent( in) :: ncid, varid
+   any valid type, scalar or array of any rank, &
+                                    intent(out) :: values
+   integer, dimension(:), optional, intent( in) :: start, count, stride, map
+   integer                                      :: nf90_get_var
+ at end example
+
+ at table @code
+ at item ncid
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
+ 
+ at item varid
+Variable ID.
+ 
+ at item values
+The data value(s) to be read. The data may be of any type, and may be
+a scalar or an array of any rank.  You cannot read CHARACTER data from
+a numeric variable or numeric data from a text variable. For numeric
+data, if the type of data differs from the netCDF variable type, type
+conversion will occur. @xref{Type Conversion,,, netcdf, NetCDF Users
+Guide}.
+
+ at item start
+A vector of integers specifying the index in the variable from which
+the first (or only) of the data values will be read. The indices are
+relative to 1, so for example, the first data value of a variable
+would have index (1, 1, ..., 1). The elements of start correspond, in
+order, to the variable's dimensions. Hence, if the variable is a
+record variable, the last index would correspond to the starting
+record number for writing the data values.
+
+By default, start(:) = 1. 
+
+ at item count
+A vector of integers specifying the number of indices selected along
+each dimension. To read a single value, for example, specify count as
+(1, 1, ..., 1). The elements of count correspond, in order, to the
+variable's dimensions. Hence, if the variable is a record variable,
+the last element of count corresponds to a count of the number of
+records to read.
+
+By default, count(:numDims) = shape(values) and 
+count(numDims + 1:) = 1, where numDims = size(shape(values)).
+
+ at item stride
+A vector of integers that specifies the sampling interval along each
+dimension of the netCDF variable. The elements of the stride vector
+correspond, in order, to the netCDF variable's dimensions (stride(1)
+gives the sampling interval along the most rapidly varying dimension
+of the netCDF variable). Sampling intervals are specified in
+type-independent units of elements (a value of 1 selects consecutive
+elements of the netCDF variable along the corresponding dimension, a
+value of 2 selects every other element, etc.).
+
+By default, stride(:) = 1. 
+
+ at item map
+A vector of integers that specifies the mapping between the dimensions
+of a netCDF variable and the in-memory structure of the internal data
+array. The elements of the index mapping vector correspond, in order,
+to the netCDF variable's dimensions (map(1) gives the distance between
+elements of the internal array corresponding to the most rapidly
+varying dimension of the netCDF variable). Distances between elements
+are specified in units of elements.
+
+By default, edgeLengths = shape(values), and 
+map = (/ 1, (product(edgeLengths(:i)), i = 1, size(edgeLengths) - 1) /), 
+that is, there is no mapping. 
+
+Use of Fortran 90 intrinsic functions (including reshape, transpose,
+and spread) may let you avoid using this argument.
+
+ at end table
+
+ at heading Errors 
+
+NF90_GET_VAR returns the value NF90_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The variable ID is invalid for the specified netCDF dataset. 
+
+ at item
+The assumed or specified start, count, and stride generate an index
+which is out of range. Note that no error checking is possible on the
+map vector.
+
+ at item
+One or more of the specified values are out of the range of values
+representable by the desired type.
+
+ at item
+The specified netCDF is in define mode rather than data mode. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+ at end itemize
+
+(As noted above, another possible source of error is using this
+interface to read all the values of a record variable without
+specifying the number of records. If there are more records in the
+file than you assume, more data will be read than you expect!)
+
+ at heading Example 
+
+Here is an example using NF90_GET_VAR to read the (4,3,2) element of
+the variable named rh from an existing netCDF dataset named
+foo.nc. For simplicity in this example, we assume that we know that rh
+is dimensioned with lon, lat, and time, so we want to read the value
+of rh that corresponds to the fourth lon value, the third lat value,
+and the second time value:
+
+ at example
+ use netcdf
+ implicit none
+ integer :: ncId, rhVarId, status
+ real    :: rhValue
+ ...
+ status = nf90_open("foo.nc", nf90_NoWrite, ncid)
+ if(status /= nf90_NoErr) call handle_err(status)
+ -
+ status = nf90_inq_varid(ncid, "rh", rhVarId)
+ if(status /= nf90_NoErr) call handle_err(status)
+ status = nf90_get_var(ncid, rhVarId, rhValue, start = (/ 4, 3, 2 /) )
+ if(status /= nf90_NoErr) call handle_err(status)
+ at end example
+
+In this example we use NF90_GET_VAR to read all the values of the
+variable named rh from an existing netCDF dataset named foo.nc. We
+assume that we know that rh is dimensioned with lon, lat, and time. In
+this example we query the netCDF file to discover the lengths of the
+dimensions, then allocate a Fortran 90 array the same shape as the
+netCDF variable.
+
+ at example
+ use netcdf
+ implicit none
+ integer                               :: ncId, rhVarId, &
+                                          lonDimID, latDimId, timeDimId, &
+                                          numLons, numLats, numTimes,    &
+                                          status
+ integer, dimension(nf90_max_var_dims) :: dimIDs
+ real, dimension(:, :, :), allocatable :: rhValues
+ ...
+ status = nf90_open("foo.nc", nf90_NoWrite, ncid)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ...
+ status = nf90_inq_varid(ncid, "rh", rhVarId)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ! How big is the netCDF variable, that is, what are the lengths of 
+ !   its constituent dimensions? 
+ status = nf90_inquire_variable(ncid, rhVarId, dimids = dimIDs)
+ if(status /= nf90_NoErr) call handle_err(status)
+ status = nf90_inquire_dimension(ncid, dimIDs(1), len = numLons)
+ if(status /= nf90_NoErr) call handle_err(status)
+ status = nf90_inquire_dimension(ncid, dimIDs(2), len = numLats)
+ if(status /= nf90_NoErr) call handle_err(status)
+ status = nf90_inquire_dimension(ncid, dimIDs(3), len = numTimes)
+ if(status /= nf90_NoErr) call handle_err(status)
+ allocate(rhValues(numLons, numLats, numTimes))
+ ...
+ status = nf90_get_var(ncid, rhVarId, rhValues)
+ if(status /= nf90_NoErr) call handle_err(status)
+ at end example
+
+Here is an example using NF90_GET_VAR to read a section of the
+variable named rh from an existing netCDF dataset named foo.nc. For
+simplicity in this example, we assume that we know that rh is
+dimensioned with lon, lat, and time, that there are ten lon values,
+five lat values, and three time values, and that we want to replace
+all the values at the last time.
+
+ at example
+ use netcdf
+ implicit none
+ integer            :: ncId, rhVarId, status
+ integer, parameter :: numLons = 10, numLats = 5, numTimes = 3
+ real, dimension(numLons, numLats, numTimes) &
+                    :: rhValues
+ ...
+ status = nf90_open("foo.nc", nf90_NoWrite, ncid)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ...
+ status = nf90_inq_varid(ncid, "rh", rhVarId)
+ if(status /= nf90_NoErr) call handle_err(status)
+ !Read the values at the last time by passing an array section 
+ status = nf90_get_var(ncid, rhVarId, rhValues(:, :, 3), &
+                       start = (/ 1, 1, numTimes /),     &
+                       count = (/ numLons, numLats, 1 /))
+ if(status /= nf90_NoErr) call handle_err(status)
+ at end example
+
+Here is an example of using NF90_GET_VAR to read every other point of a
+netCDF variable named rh having dimensions (6, 4).
+
+ at example
+ use netcdf
+ implicit none
+ integer            :: ncId, rhVarId, status
+ integer, parameter :: numLons = 6, numLats = 4
+ real, dimension(numLons, numLats) &
+                    :: rhValues
+ ...
+ status = nf90_open("foo.nc", nf90_NoWrite, ncid)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ...
+ status = nf90_inq_varid(ncid, "rh", rhVarId)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ...
+ ! Read every other value into an array section 
+ status = nf90_get_var(ncid, rhVarId, rhValues(::2, ::2) &
+                       stride = (/ 2, 2 /))
+ if(status /= nf90_NoErr) call handle_err(status)
+ at end example
+
+The following map vector shows the default mapping between a 2x3x4
+netCDF variable and an internal array of the same shape:
+
+ at example
+ real,    dimension(2, 3, 4):: a  ! same shape as netCDF variable
+ integer, dimension(3)      :: map  = (/ 1, 2, 6 /) 
+                     ! netCDF dimension inter-element distance
+                     ! ---------------- ----------------------
+                     ! most rapidly varying       1
+                     ! intermediate               2 (= map(1)*2)
+                     ! most slowly varying        6 (= map(2)*3)
+ at end example
+
+Using the map vector above obtains the same result as simply not
+passing a map vector at all.
+
+Here is an example of using nf90_get_var to read a netCDF variable
+named rh whose dimensions are the transpose of the Fortran 90 array:
+
+ at example
+ use netcdf
+ implicit none
+ integer                           :: ncId, rhVarId, status
+ integer, parameter                :: numLons = 6, numLats = 4
+ real, dimension(numLons, numLats) :: rhValues
+ ! netCDF variable has dimensions (numLats, numLons)
+ ...
+ status = nf90_open("foo.nc", nf90_NoWrite, ncid)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ...
+ status = nf90_inq_varid(ncid, "rh", rhVarId)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ...
+ ! Read transposed values: map vector would be (/ 1, numLats /) for 
+ !   no transposition
+ status = nf90_get_var(ncid, rhVarId,rhValues, map = (/ numLons, 1 /)) 
+ if(status /= nf90_NoErr) call handle_err(status)
+ at end example
+
+The same effect can be obtained more simply, though using more memory,
+using Fortran 90 intrinsic functions:
+
+ at example
+ use netcdf
+ implicit none
+ integer                           :: ncId, rhVarId, status
+ integer, parameter                :: numLons = 6, numLats = 4
+ real, dimension(numLons, numLats) :: rhValues
+ ! netCDF variable has dimensions (numLats, numLons)
+ real, dimension(numLons, numLats) :: tempValues
+ ...
+ status = nf90_open("foo.nc", nf90_NoWrite, ncid)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ...
+ status = nf90_inq_varid(ncid, "rh", rhVarId)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ...
+ status = nf90_get_var(ncid, rhVarId, tempValues)) 
+ if(status /= nf90_NoErr) call handle_err(status)
+ rhValues(:, :) = transpose(tempValues)
+ at end example
+
+ at node Reading and Writing Character String Values, Fill Values, NF90_GET_VAR, Variables
+ at section Reading and Writing Character String Values
+
+Character strings are not a primitive netCDF external data type under
+the classic netCDF data model, in
+part because FORTRAN does not support the abstraction of
+variable-length character strings (the FORTRAN LEN function returns
+the static length of a character string, not its dynamic length). As a
+result, a character string cannot be written or read as a single
+object in the netCDF interface. Instead, a character string must be
+treated as an array of characters, and array access must be used to
+read and write character strings as variable data in netCDF
+datasets. Furthermore, variable-length strings are not supported by
+the netCDF classic interface except by convention; for example, you may treat
+a zero byte as terminating a character string, but you must explicitly
+specify the length of strings to be read from and written to netCDF
+variables.
+
+Character strings as attribute values are easier to use, since the
+strings are treated as a single unit for access. However, the value of
+a character-string attribute in the classic netCDF interface is still
+an array of characters with an
+explicit length that must be specified when the attribute is defined.
+
+When you define a variable that will have character-string values, use
+a character-position dimension as the most quickly varying dimension
+for the variable (the first dimension for the variable in Fortran
+90). The length of the character-position dimension will be the
+maximum string length of any value to be stored in the
+character-string variable. Space for maximum-length strings will be
+allocated in the disk representation of character-string variables
+whether you use the space or not. If two or more variables have the
+same maximum length, the same character-position dimension may be used
+in defining the variable shapes.
+
+To write a character-string value into a character-string variable,
+use either entire variable access or array access. The latter requires
+that you specify both a corner and a vector of edge lengths. The
+character-position dimension at the corner should be one for Fortran
+90. If the length of the string to be written is n, then the vector of
+edge lengths will specify n in the character-position dimension, and
+one for all the other dimensions: (n, 1, 1, ..., 1).
+
+In Fortran 90, fixed-length strings may be written to a netCDF dataset
+without a terminating character, to save space. Variable-length
+strings should follow the C convention of writing strings with a
+terminating zero byte so that the intended length of the string can be
+determined when it is later read by either C or Fortran 90 programs.
+It is the users responsibility to provide such null termination.
+
+If you are writing data in the default prefill mode (see next section),
+you can ensure that simple strings represented as 1-dimensional
+character arrays are null terminated in the netCDF file by writing fewer
+characters than the length declared when the variable was defined.
+That way, the extra unwritten characters will be filled with the
+default character fill value, which is a null byte.  The Fortran
+intrinsic TRIM function can be used to trim trailing blanks from the
+character string argument to NF90_PUT_VAR to make the argument shorter
+than the declared length.  If prefill is not on, the data writer must
+explicitly provide a null terminating byte.
+
+Here is an example illustrating this way of writing strings to
+character array variables:
+
+ at example
+ use netcdf
+ implicit none
+ integer status
+ integer                           :: ncid, oceanStrLenID, oceanId
+ integer, parameter                :: MaxOceanNameLen = 20
+ character, (len = MaxOceanNameLen):: ocean
+ ...
+ status = nf90_create("foo.nc", nf90_NoClobber, ncid)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ...
+ status = nf90_def_dim(ncid, "oceanStrLen", MaxOceanNameLen, oceanStrLenId)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ...
+ status = nf90_def_var(ncid, "ocean", nf90_char, (/ oceanStrLenId /), oceanId)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ...
+ ! Leave define mode, which prefills netCDF variables with fill values
+ status = nf90_enddef(ncid)
+ if (status /= nf90_noerr) call handle_err(status)
+ ...
+ ! Note that this assignment adds blank fill
+ ocean = "Pacific"
+ ! Using trim removes trailing blanks, prefill provides null
+ ! termination, so C programs can later get intended string.
+ status = nf90_put_var(ncid, oceanId, trim(ocean)) 
+ if(status /= nf90_NoErr) call handle_err(status)
+ at end example
+
+ at node Fill Values, NF90_RENAME_VAR, Reading and Writing Character String Values, Variables
+ at section Fill Values
+
+What happens when you try to read a value that was never written in an
+open netCDF dataset? You might expect that this should always be an
+error, and that you should get an error message or an error status
+returned. You do get an error if you try to read data from a netCDF
+dataset that is not open for reading, if the variable ID is invalid
+for the specified netCDF dataset, or if the specified indices are not
+properly within the range defined by the dimension lengths of the
+specified variable. Otherwise, reading a value that was not written
+returns a special fill value used to fill in any undefined values when
+a netCDF variable is first written.
+
+You may ignore fill values and use the entire range of a netCDF
+external data type, but in this case you should make sure you write
+all data values before reading them. If you know you will be writing
+all the data before reading it, you can specify that no prefilling of
+variables with fill values will occur by calling writing. This may
+provide a significant performance gain for netCDF writes.
+
+The variable attribute _FillValue may be used to specify the fill
+value for a variable. There are default fill values for each type,
+defined in module netcdf: NF90_FILL_CHAR, NF90_FILL_INT1 (same as
+NF90_FILL_BYTE), NF90_FILL_INT2 (same as NF90_FILL_SHORT),
+NF90_FILL_INT, NF90_FILL_REAL (same as NF90_FILL_FLOAT), and
+NF90_FILL_DOUBLE
+
+The netCDF byte and character types have different default fill
+values. The default fill value for characters is the zero byte, a
+useful value for detecting the end of variable-length C character
+strings. If you need a fill value for a byte variable, it is
+recommended that you explicitly define an appropriate _FillValue
+attribute, as generic utilities such as ncdump will not assume a
+default fill value for byte variables.
+
+Type conversion for fill values is identical to type conversion for
+other values: attempting to convert a value from one type to another
+type that can't represent the value results in a range error. Such
+errors may occur on writing or reading values from a larger type (such
+as double) to a smaller type (such as float), if the fill value for
+the larger type cannot be represented in the smaller type.
+
+ at node NF90_RENAME_VAR, NF90_VAR_PAR_ACCESS, Fill Values, Variables
+ at section NF90_RENAME_VAR 
+ at findex NF90_RENAME_VAR 
+ at cindex NF90_RENAME_VAR , example
+
+The function NF90_RENAME_VAR changes the name of a netCDF variable in an
+open netCDF dataset. If the new name is longer than the old name, the
+netCDF dataset must be in define mode. You cannot rename a variable to
+have the name of any existing variable.
+
+ at heading Usage 
+ at example
+ function nf90_rename_var(ncid, varid, newname)
+   integer,             intent( in) :: ncid, varid
+   character (len = *), intent( in) :: newname
+   integer                          :: nf90_rename_var
+ at end example
+
+ at table @code
+ at item ncid
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
+ 
+ at item varid
+Variable ID.
+ 
+ at item newname
+New name for the specified variable.
+ at end table
+ 
+ at heading Errors 
+
+NF90_RENAME_VAR returns the value NF90_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+ at item
+The new name is in use as the name of another variable. 
+
+ at item
+The variable ID is invalid for the specified netCDF dataset. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF90_RENAME_VAR to rename the variable rh to
+rel_hum in an existing netCDF dataset named foo.nc:
+
+ at example
+ use netcdf
+ implicit none
+ integer :: ncId, rhVarId, status
+ ...
+ status = nf90_open("foo.nc", nf90_Write, ncid)
+ if(status /= nf90_NoErr) call handle_err(status)
+ ...
+ status = nf90_inq_varid(ncid, "rh", rhVarId)
+ if(status /= nf90_NoErr) call handle_err(status)
+ status = nf90_redef(ncid)  ! Enter define mode to change variable name
+ if(status /= nf90_NoErr) call handle_err(status)
+ status = nf90_rename_var(ncid, rhVarId, "rel_hum")
+ if(status /= nf90_NoErr) call handle_err(status)
+ status = nf90_enddef(ncid) ! Leave define mode
+ if(status /= nf90_NoErr) call handle_err(status)
+ at end example
+
+ at node NF90_VAR_PAR_ACCESS,  , NF90_RENAME_VAR, Variables
+ at section Change between Collective and Independent Parallel Access: NF90_VAR_PAR_ACCESS
+ at findex NF90_VAR_PAR_ACCESS
+ at cindex NF90_VAR_PAR_ACCESS, example
+
+The function NF90_VAR_PAR_ACCESS changes whether read/write operations
+on a parallel file system are performed collectively or independently
+(the default) on the variable. This function can only be called if the
+file was created (see @ref{NF90_CREATE}) or opened (see
+ at ref{NF90_OPEN}) for parallel I/O.
+
+This function is only available if the netCDF library was built with
+parallel I/O enabled.
+
+Calling this function affects only the open file - information about
+whether a variable is to be accessed collectively or independently is
+not written to the data file. Every time you open a file on a parallel
+file system, all variables default to independent operations. The
+change of a variable to collective access lasts only as long as that
+file is open.
+
+The variable can be changed from collective to independent, and back,
+as often as desired.
+
+Classic and 64-bit offset files, when opened for parallel access, use
+the parallel-netcdf (a.k.a. pnetcdf) library, which does not allow
+per-variable changes of access mode - the entire file must be access
+independently or collectively. For classic and 64-bit offset files,
+the nf90_var_par_access function changes the access for all variables
+in the file.
+
+ at heading Usage 
+
+ at example
+  function nf90_var_par_access(ncid, varid, access)
+    integer, intent(in) :: ncid
+    integer, intent(in) :: varid
+    integer, intent(in) :: access
+    integer :: nf90_var_par_access
+  end function nf90_var_par_access
+ at end example
+
+ at table @code
+
+ at item ncid
+NetCDF ID, from a previous call to NF90_OPEN (see @ref{NF90_OPEN}) or
+NF90_CREATE (see @ref{NF90_CREATE}).
+ 
+ at item varid
+Variable ID.
+ 
+ at item access
+NF90_INDEPENDENT to set this variable to independent
+operations. NF90_COLLECTIVE to set it to collective operations.
+
+ at end table
+ 
+ at heading Return Values
+
+ at table @code
+
+ at item NF90_NOERR
+No error.
+
+ at item NF90_ENOTVAR
+No variable found.
+
+ at item NF90_NOPAR
+File not opened for parallel access.
+
+ at end table
+
+ at heading Example
+This example comes from test program nf_test/f90tst_parallel.f90. For
+this test to be run, netCDF must have been built with a
+parallel-enabled HDF5, and --enable-parallel-tests must have been used
+when configuring netcdf.
+
+ at example
+  ! Reopen the file.
+  call handle_err(nf90_open(FILE_NAME, nf90_nowrite, ncid, comm = MPI_COMM_WORLD, &
+       info = MPI_INFO_NULL))
+
+  ! Set collective access on this variable. This will cause all
+  ! reads/writes to happen together on every processor.
+  call handle_err(nf90_var_par_access(ncid, varid, nf90_collective))
+      
+  ! Read this processor's data.
+  call handle_err(nf90_get_var(ncid, varid, data_in, start = start, count = count))
+ at end example
+
+ at node Attributes, Summary of Fortran 90 Interface, Variables, Top
+ at chapter Attributes
+
+ at menu
+* Attributes Introduction::     
+* NF90_PUT_ATT::                
+* NF90_INQUIRE_ATTRIBUTE::      
+* NF90_GET_ATT::                
+* NF90_COPY_ATT::               
+* NF90_RENAME_ATT::             
+* NF90_DEL_ATT::                
+ at end menu
+
+ at node Attributes Introduction, NF90_PUT_ATT, Attributes, Attributes
+ at section Attributes Introduction
+
+Attributes may be associated with each netCDF variable to specify such
+properties as units, special values, maximum and minimum valid values,
+scaling factors, and offsets. Attributes for a netCDF dataset are
+defined when the dataset is first created, while the netCDF dataset is
+in define mode. Additional attributes may be added later by reentering
+define mode. A netCDF attribute has a netCDF variable to which it is
+assigned, a name, a type, a length, and a sequence of one or more
+values. An attribute is designated by its variable ID and name. When
+an attribute name is not known, it may be designated by its variable
+ID and number in order to determine its name, using the function
+NF90_INQ_ATTNAME.
+
+The attributes associated with a variable are typically defined
+immediately after the variable is created, while still in define
+mode. The data type, length, and value of an attribute may be changed
+even when in data mode, as long as the changed attribute requires no
+more space than the attribute as originally defined.
+
+It is also possible to have attributes that are not associated with
+any variable. These are called global attributes and are identified by
+using NF90_GLOBAL as a variable pseudo-ID. Global attributes are
+usually related to the netCDF dataset as a whole and may be used for
+purposes such as providing a title or processing history for a netCDF
+dataset.
+
+Attributes are much more useful when they follow established community
+conventions. @xref{Attribute Conventions,,,netcdf, @value{n-man}}.
+
+Operations supported on attributes are: 
+
+ at itemize
+
+ at item
+Create an attribute, given its variable ID, name, data type, length, and value. 
+
+ at item
+Get attribute's data type and length from its variable ID and name. 
+
+ at item
+Get attribute's value from its variable ID and name. 
+
+ at item
+Copy attribute from one netCDF variable to another. 
+
+ at item
+Get name of attribute from its number. 
+
+ at item
+Rename an attribute. 
+
+ at item
+Delete an attribute. 
+ at end itemize
+
+ at node NF90_PUT_ATT, NF90_INQUIRE_ATTRIBUTE, Attributes Introduction, Attributes
+ at section Create an Attribute: NF90_PUT_ATT
+ at findex NF90_PUT_ATT
+ at cindex NF90_PUT_ATT, example
+
+The function NF90_PUT_ATTadds or changes a variable attribute or
+global attribute of an open netCDF dataset. If this attribute is new,
+or if the space required to store the attribute is greater than
+before, the netCDF dataset must be in define mode.
+
+ at heading Usage 
+
+Although it's possible to create attributes of all types, text and
+double attributes are adequate for most purposes.
+
+ at example
+ function nf90_put_att(ncid, varid, name, values)
+   integer,            intent( in) :: ncid, varid
+   character(len = *), intent( in) :: name
+   scalar character string or any numeric type, scalar, or array of rank 1, &
+                       intent( in) :: values
+   integer                         :: nf90_put_att
+ at end example
+
+ at table @code
+ at item ncid
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
+ 
+ at item varid
+Variable ID of the variable to which the attribute will be assigned or
+NF90_GLOBAL for a global attribute.
+ 
+ at item name
+Attribute name.  Attribute name conventions are assumed by some netCDF
+generic applications, e.g., @samp{units} as the name for a string
+attribute that gives the units for a netCDF variable. @xref{Attribute
+Conventions,,,netcdf, @value{n-man}}.
+ 
+ at item values
+A numeric rank 1 array of attribute values or a scalar.  The external data type
+of the attribute is set to match the internal representation of the
+argument, that is if values is a two byte integer array, the attribute
+will be of type NF90_INT2. Fortran 90 intrinsic functions can be used
+to convert attributes to the desired type.
+
+ at end table
+ 
+ at heading Errors 
+
+NF90_PUT_ATT returns the value NF90_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The variable ID is invalid for the specified netCDF dataset. 
+
+ at item
+The specified netCDF type is invalid. 
+
+ at item
+The specified length is negative. 
+
+ at item
+The specified open netCDF dataset is in data mode and the specified
+attribute would expand.
+
+ at item
+The specified open netCDF dataset is in data mode and the specified
+attribute does not already exist.
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+
+ at item
+The number of attributes for this variable exceeds NF90_MAX_ATTRS. 
+
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF90_PUT_ATT to add a variable attribute
+named valid_range for a netCDF variable named rh and a global
+attribute named title to an existing netCDF dataset named foo.nc:
+
+ at example
+ use netcdf
+ implicit none
+ integer :: ncid, status, RHVarID
+ ...
+ status = nf90_open("foo.nc", nf90_write, ncid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ ...  
+ ! Enter define mode so we can add the attribute
+ status = nf90_redef(ncid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ ! Get the variable ID for "rh"...
+ status = nf90_inq_varid(ncid, "rh", RHVarID)
+ if (status /= nf90_noerr) call handle_err(status)
+ ! ...  put the range attribute, setting it to eight byte reals... 
+ status = nf90_put_att(ncid, RHVarID, "valid_range", real((/ 0, 100 /))
+ ! ... and the title attribute. 
+ if (status /= nf90_noerr) call handle_err(status)
+ status = nf90_put_att(ncid, RHVarID, "title", "example netCDF dataset") )
+ if (status /= nf90_noerr) call handle_err(status)
+ ! Leave define mode
+ status = nf90_enddef(ncid)
+ if (status /= nf90_noerr) call handle_err(status)
+ at end example
+
+ at node NF90_INQUIRE_ATTRIBUTE, NF90_GET_ATT, NF90_PUT_ATT, Attributes
+ at section Get Information about an Attribute: NF90_INQUIRE_ATTRIBUTE and NF90_INQ_ATTNAME
+ at findex NF90_INQUIRE_ATTRIBUTE
+ at cindex NF90_INQUIRE_ATTRIBUTE, example
+ at findex NF90_INQ_ATTNAME
+ at cindex NF90_INQ_ATTNAME, example
+
+The function NF90_INQUIRE_ATTRIBUTE returns information about a netCDF
+attribute given the variable ID and attribute name. Information about
+an attribute includes its type, length, name, and number. See
+NF90_GET_ATT for getting attribute values.
+
+The function NF90_INQ_ATTNAME gets the name of an attribute, given its
+variable ID and number. This function is useful in generic
+applications that need to get the names of all the attributes
+associated with a variable, since attributes are accessed by name
+rather than number in all other attribute functions. The number of an
+attribute is more volatile than the name, since it can change when
+other attributes of the same variable are deleted. This is why an
+attribute number is not called an attribute ID.
+
+ at heading Usage 
+ at example
+ function nf90_inquire_attribute(ncid, varid, name, xtype, len, attnum)
+   integer,             intent( in)           :: ncid, varid
+   character (len = *), intent( in)           :: name
+   integer,             intent(out), optional :: xtype, len, attnum
+   integer                                    :: nf90_inquire_attribute
+ function nf90_inq_attname(ncid, varid, attnum, name)
+   integer,             intent( in) :: ncid, varid, attnum
+   character (len = *), intent(out) :: name
+   integer                          :: nf90_inq_attname
+ at end example
+
+ at table @code
+ at item ncid
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
+ 
+ at item varid
+Variable ID of the attribute's variable, or NF90_GLOBAL for a global
+attribute.
+ 
+ at item name
+Attribute name. For NF90_INQ_ATTNAME, this is a pointer to the location
+for the returned attribute name.
+ 
+ at item xtype
+Returned attribute type, one of the set of predefined netCDF external
+data types. The valid netCDF external data types are NF90_BYTE, NF90_CHAR,
+NF90_SHORT, NF90_INT, NF90_FLOAT, and NF90_DOUBLE.
+ 
+ at item len
+Returned number of values currently stored in the attribute. For a
+string-valued attribute, this is the number of characters in the
+string.
+ 
+ at item attnum
+For NF90_INQ_ATTNAME, the input attribute number; for NF90_INQ_ATTID, the
+returned attribute number. The attributes for each variable are
+numbered from 1 (the first attribute) to NATTS, where NATTS is the
+number of attributes for the variable, as returned from a call to
+NF90_INQ_VARNATTS.
+
+(If you already know an attribute name, knowing its number is not very
+useful, because accessing information about an attribute requires its
+name.)
+ at end table
+
+ at heading Errors 
+
+Each function returns the value NF90_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+ at itemize
+
+ at item
+The variable ID is invalid for the specified netCDF dataset. 
+
+ at item
+The specified attribute does not exist. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+
+ at item
+For NF90_INQ_ATTNAME, the specified attribute number is negative or more
+than the number of attributes defined for the specified variable.
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF90_INQUIRE_ATTRIBUTE to inquire about the lengths
+of an attribute named valid_range for a netCDF variable named rh and a
+global attribute named title in an existing netCDF dataset named
+foo.nc:
+
+ at example
+ use netcdf
+ implicit none
+ integer :: ncid, status
+ integer :: RHVarID                       ! Variable ID
+ integer :: validRangeLength, titleLength ! Attribute lengths
+ ... 
+ status = nf90_open("foo.nc", nf90_nowrite, ncid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ ...  
+ ! Get the variable ID for "rh"...
+ status = nf90_inq_varid(ncid, "rh", RHVarID)
+ if (status /= nf90_noerr) call handle_err(status)
+ ! ...  get the length of the "valid_range" attribute... 
+ status = nf90_inquire_attribute(ncid, RHVarID, "valid_range", &
+                           len = validRangeLength)
+ if (status /= nf90_noerr) call handle_err(status)
+ ! ... and the global title attribute. 
+ status = nf90_inquire_attribute(ncid, nf90_global, "title", len = titleLength)
+ if (status /= nf90_noerr) call handle_err(status)
+ at end example
+
+ at node NF90_GET_ATT, NF90_COPY_ATT, NF90_INQUIRE_ATTRIBUTE, Attributes
+ at section Get Attribute's Values: NF90_GET_ATT
+ at findex NF90_GET_ATT
+ at cindex NF90_GET_ATT, example
+
+Function nf90_get_att gets the value(s) of a netCDF attribute, given
+its variable ID and name.
+
+ at heading Usage 
+ at example
+ function nf90_get_att(ncid, varid, name, values)
+   integer,            intent( in) :: ncid, varid
+   character(len = *), intent( in) :: name
+   any valid type, scalar or array of rank 1, &
+                       intent(out) :: values
+   integer                         :: nf90_get_att
+ at end example
+
+ at table @code
+ at item ncid
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
+ 
+ at item varid
+Variable ID of the attribute's variable, or NF90_GLOBAL for a global attribute.
+ 
+ at item name
+Attribute name.
+ 
+ at item values
+Returned attribute values. All elements of the vector of attribute
+values are returned, so you must provide enough space to hold them. If
+you don't know how much space to reserve, call NF90_INQUIRE_ATTRIBUTE first
+to find out the length of the attribute. If there is only a single
+attribute values may be a scalar. If the attribute is of type
+character values should be a variable of type character with the len
+Fortran 90 attribute set to an appropriate value (i.e. character (len
+= 80) :: values). You cannot read character data from a numeric
+variable or numeric data from a text variable. For numeric data, if
+the type of data differs from the netCDF variable type, type
+conversion will occur. @xref{Type Conversion,,, netcdf, NetCDF Users
+Guide}.
+
+ at end table
+ 
+ at heading Errors 
+
+NF90_GET_ATT_ type returns the value NF90_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+ at itemize
+
+ at item
+The variable ID is invalid for the specified netCDF dataset. 
+
+ at item
+The specified attribute does not exist. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+
+ at item
+One or more of the attribute values are out of the range of values
+representable by the desired type.
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF90_GET_ATT to determine the values of an
+attribute named valid_range for a netCDF variable named rh and a
+global attribute named title in an existing netCDF dataset named
+foo.nc. In this example, it is assumed that we don't know how many
+values will be returned, so we first inquire about the length of the
+attributes to make sure we have enough space to store them:
+
+ at example
+ use netcdf
+ implicit none
+ integer              :: ncid, status
+ integer              :: RHVarID                       ! Variable ID
+ integer              :: validRangeLength, titleLength ! Attribute lengths
+ real, dimension(:), allocatable, &
+                      :: validRange
+ character (len = 80) :: title                          
+ ... 
+ status = nf90_open("foo.nc", nf90_nowrite, ncid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ ... 
+ ! Find the lengths of the attributes
+ status = nf90_inq_varid(ncid, "rh", RHVarID)
+ if (status /= nf90_noerr) call handle_err(status)
+ status = nf90_inquire_attribute(ncid, RHVarID, "valid_range", &
+                           len = validRangeLength)
+ if (status /= nf90_noerr) call handle_err(status)
+ status = nf90_inquire_attribute(ncid, nf90_global, "title", len = titleLength)
+ if (status /= nf90_noerr) call handle_err(status)
+ ... 
+ !Allocate space to hold attribute values, check string lengths
+ allocate(validRange(validRangeLength), stat = status)
+ if(status /= 0 .or. len(title) < titleLength)
+   print *, "Not enough space to put attribute values."
+   exit
+ end if
+ ! Read the attributes. 
+ status = nf90_get_att(ncid, RHVarID, "valid_range", validRange)
+ if (status /= nf90_noerr) call handle_err(status)
+ status = nf90_get_att(ncid, nf90_global, "title", title)
+ if (status /= nf90_noerr) call handle_err(status)
+ at end example
+
+ at node NF90_COPY_ATT, NF90_RENAME_ATT, NF90_GET_ATT, Attributes
+ at section Copy Attribute from One NetCDF to Another: NF90_COPY_ATT
+ at findex NF90_COPY_ATT
+ at cindex NF90_COPY_ATT, example
+
+The function NF90_COPY_ATT copies an attribute from one open netCDF
+dataset to another. It can also be used to copy an attribute from one
+variable to another within the same netCDF dataset.
+
+If used to copy an attribute of user-defined type, then that
+user-defined type must already be defined in the target file. In the
+case of user-defined attributes, enddef/redef is called for 
+ncid_in and ncid_out if they are in define mode. (This is the ensure
+that all user-defined types are committed to the file(s) before the
+copy is attempted.)
+
+ at heading Usage 
+ at example
+ function nf90_copy_att(ncid_in, varid_in, name, ncid_out, varid_out)
+   integer,             intent( in) :: ncid_in,  varid_in
+   character (len = *), intent( in) :: name
+   integer,             intent( in) :: ncid_out, varid_out
+   integer                          :: nf90_copy_att
+ at end example
+
+ at table @code
+ at item ncid_in
+The netCDF ID of an input netCDF dataset from which the attribute
+will be copied, from a previous call to NF90_OPEN or NF90_CREATE.
+ 
+ at item varid_in
+ID of the variable in the input netCDF dataset from which the
+attribute will be copied, or NF90_GLOBAL for a global attribute.
+ 
+ at item name
+Name of the attribute in the input netCDF dataset to be copied.
+ 
+ at item ncid_out
+The netCDF ID of the output netCDF dataset to which the attribute
+will be copied, from a previous call to NF90_OPEN or NF90_CREATE. It is
+permissible for the input and output netCDF IDs to be the same. The
+output netCDF dataset should be in define mode if the attribute to be
+copied does not already exist for the target variable, or if it would
+cause an existing target attribute to grow.
+ 
+ at item varid_out
+ID of the variable in the output netCDF dataset to which the
+attribute will be copied, or NF90_GLOBAL to copy to a global attribute.
+ at end table
+ 
+ at heading Errors 
+
+NF90_COPY_ATT returns the value NF90_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The input or output variable ID is invalid for the specified netCDF
+dataset.
+
+ at item
+The specified attribute does not exist. 
+
+ at item
+The output netCDF is not in define mode and the attribute is new for
+the output dataset is larger than the existing attribute.
+
+ at item
+The input or output netCDF ID does not refer to an open netCDF
+dataset.
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF90_COPY_ATT to copy the variable attribute
+units from the variable rh in an existing netCDF dataset named foo.nc
+to the variable avgrh in another existing netCDF dataset named bar.nc,
+assuming that the variable avgrh already exists, but does not yet have
+a units attribute:
+
+ at example
+ use netcdf
+ implicit none
+ integer :: ncid1, ncid2, status
+ integer :: RHVarID, avgRHVarID    ! Variable ID
+ ... 
+ status = nf90_open("foo.nc", nf90_nowrite, ncid1) 
+ if (status /= nf90_noerr) call handle_err(status)
+ status = nf90_open("bar.nc", nf90_write, ncid2) 
+ if (status /= nf90_noerr) call handle_err(status)
+ ... 
+ ! Find the IDs of the variables
+ status = nf90_inq_varid(ncid1, "rh", RHVarID)
+ if (status /= nf90_noerr) call handle_err(status)
+ status = nf90_inq_varid(ncid1, "avgrh", avgRHVarID)
+ if (status /= nf90_noerr) call handle_err(status)
+ ... 
+ status = nf90_redef(ncid2)   ! Enter define mode
+ if (status /= nf90_noerr) call handle_err(status)
+ ! Copy variable attribute from "rh" in file 1 to "avgrh" in file 1
+ status = nf90_copy_att(ncid1, RHVarID, "units", ncid2, avgRHVarID)
+ if (status /= nf90_noerr) call handle_err(status)
+ status = nf90_enddef(ncid2)
+ if (status /= nf90_noerr) call handle_err(status)
+ at end example
+
+ at node NF90_RENAME_ATT, NF90_DEL_ATT, NF90_COPY_ATT, Attributes
+ at section Rename an Attribute: NF90_RENAME_ATT
+ at findex NF90_RENAME_ATT
+ at cindex NF90_RENAME_ATT, example
+
+The function NF90_RENAME_ATT changes the name of an attribute. If the
+new name is longer than the original name, the netCDF dataset must be
+in define mode. You cannot rename an attribute to have the same name
+as another attribute of the same variable.
+
+ at heading Usage 
+ at example
+ function nf90_rename_att(ncid, varid, curname, newname)
+   integer,             intent( in) :: ncid,  varid
+   character (len = *), intent( in) :: curname, newname
+   integer                          :: nf90_rename_att
+ at end example
+
+ at table @code
+ at item ncid
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE
+ 
+ at item varid
+ID of the attribute's variable, or NF90_GLOBAL for a global attribute
+ 
+ at item curname
+The current attribute name.
+ 
+ at item newname
+The new name to be assigned to the specified attribute. If the new
+name is longer than the current name, the netCDF dataset must be in
+define mode.
+ at end table
+ 
+ at heading Errors 
+
+NF90_RENAME_ATT returns the value NF90_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+ at itemize
+
+ at item
+The specified variable ID is not valid. 
+
+ at item
+The new attribute name is already in use for another attribute of the
+specified variable.
+
+ at item
+The specified netCDF dataset is in data mode and the new name is
+longer than the old name.
+
+ at item
+The specified attribute does not exist. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset.
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF90_RENAME_ATT to rename the variable
+attribute units to Units for a variable rh in an existing netCDF
+dataset named foo.nc:
+
+ at example
+ use netcdf
+ implicit none
+ integer :: ncid1, status
+ integer :: RHVarID         ! Variable ID
+ ... 
+ status = nf90_open("foo.nc", nf90_nowrite, ncid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ ... 
+ ! Find the IDs of the variables
+ status = nf90_inq_varid(ncid, "rh", RHVarID)
+ if (status /= nf90_noerr) call handle_err(status)
+ ... 
+ status = nf90_rename_att(ncid, RHVarID, "units", "Units")
+ if (status /= nf90_noerr) call handle_err(status)
+ at end example
+
+ at node NF90_DEL_ATT,  , NF90_RENAME_ATT, Attributes
+ at section NF90_DEL_ATT 
+ at findex NF90_DEL_ATT 
+ at cindex NF90_DEL_ATT , example
+
+The function NF90_DEL_ATT deletes a netCDF attribute from an open netCDF
+dataset. The netCDF dataset must be in define mode.
+
+ at heading Usage 
+ at example
+ function nf90_del_att(ncid, varid, name)
+   integer,             intent( in) :: ncid, varid
+   character (len = *), intent( in) :: name
+   integer                          :: nf90_del_att
+ at end example
+
+ at table @code
+ at item ncid
+NetCDF ID, from a previous call to NF90_OPEN or NF90_CREATE.
+ 
+ at item varid
+ID of the attribute's variable, or NF90_GLOBAL for a global attribute.
+ 
+ at item name
+The name of the attribute to be deleted.
+ at end table
+ 
+ at heading Errors 
+
+NF90_DEL_ATT returns the value NF90_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The specified variable ID is not valid. 
+
+ at item
+The specified netCDF dataset is in data mode. 
+
+ at item
+The specified attribute does not exist. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset.
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF90_DEL_ATT to delete the variable attribute
+Units for a variable rh in an existing netCDF dataset named foo.nc:
+
+ at example
+ use netcdf
+ implicit none
+ integer :: ncid1, status
+ integer :: RHVarID         ! Variable ID
+ ... 
+ status = nf90_open("foo.nc", nf90_nowrite, ncid) 
+ if (status /= nf90_noerr) call handle_err(status)
+ ... 
+ ! Find the IDs of the variables
+ status = nf90_inq_varid(ncid, "rh", RHVarID)
+ if (status /= nf90_noerr) call handle_err(status)
+ ... 
+ status = nf90_redef(ncid)   ! Enter define mode
+ if (status /= nf90_noerr) call handle_err(status)
+ status = nf90_del_att(ncid, RHVarID, "Units")
+ if (status /= nf90_noerr) call handle_err(status)
+ status = nf90_enddef(ncid)
+ if (status /= nf90_noerr) call handle_err(status)
+ at end example
+
+ at node Summary of Fortran 90 Interface, FORTRAN 77 to Fortran 90 Transition Guide, Attributes, Top
+ at appendix Appendix A - Summary of Fortran 90 Interface
+
+ Dataset Functions
+
+ at example
+ function nf90_inq_libvers()
+   character(len = 80) :: nf90_inq_libvers
+ function nf90_strerror(ncerr)
+   integer, intent( in) :: ncerr
+   character(len = 80)  :: nf90_strerror
+ function nf90_create(path, cmode, ncid)
+   character (len = *), intent(in   ) :: path
+   integer,             intent(in   ) :: cmode
+   integer, optional,   intent(in   ) :: initialsize
+   integer, optional,   intent(inout) :: chunksize
+   integer,             intent(  out) :: ncid
+   integer                            :: nf90_create
+ function nf90_open(path, mode, ncid, chunksize)
+   character (len = *), intent(in   ) :: path
+   integer,             intent(in   ) :: mode
+   integer,             intent(  out) :: ncid
+   integer, optional,   intent(inout) :: chunksize
+   integer                            :: nf90_open
+ function nf90_set_fill(ncid, fillmode, old_mode)
+   integer, intent( in) :: ncid, fillmode 
+   integer, intent(out) :: old_mode
+   integer              :: nf90_set_fill
+ function nf90_redef(ncid)
+   integer, intent( in) :: ncid
+   integer              :: nf90_redef
+ function nf90_enddef(ncid, h_minfree, v_align, v_minfree, r_align)
+   integer,           intent( in) :: ncid
+   integer, optional, intent( in) :: h_minfree, v_align, v_minfree, r_align
+   integer                        :: nf90_enddef
+ function nf90_sync(ncid)
+   integer, intent( in) :: ncid
+   integer              :: nf90_sync
+ function nf90_abort(ncid)
+   integer, intent( in) :: ncid
+   integer              :: nf90_abort
+ function nf90_close(ncid)
+   integer, intent( in) :: ncid
+   integer              :: nf90_close
+ function nf90_Inquire(ncid, nDimensions, nVariables, nAttributes, &
+                      unlimitedDimId)
+   integer,           intent( in) :: ncid
+   integer, optional, intent(out) :: nDimensions, nVariables, nAttributes, &  
+                               unlimitedDimId
+   integer                        :: nf90_Inquire
+ at end example
+
+ Dimension functions
+
+ at example
+ function nf90_def_dim(ncid, name, len, dimid)
+   integer,             intent( in) :: ncid
+   character (len = *), intent( in) :: name
+   integer,             intent( in) :: len
+   integer,             intent(out) :: dimid
+   integer                          :: nf90_def_dim
+ function nf90_inq_dimid(ncid, name, dimid)
+   integer,             intent( in) :: ncid
+   character (len = *), intent( in) :: name
+   integer,             intent(out) :: dimid
+   integer                          :: nf90_inq_dimid
+ function nf90_inquire_dimension(ncid, dimid, name, len)
+   integer,                       intent( in) :: ncid, dimid
+   character (len = *), optional, intent(out) :: name
+   integer,             optional, intent(out) :: len
+   integer                                    :: nf90_inquire_dimension
+ function nf90_rename_dim(ncid, dimid, name)
+   integer,             intent( in) :: ncid
+   character (len = *), intent( in) :: name
+   integer,             intent( in) :: dimid
+   integer                          :: nf90_rename_dim
+ at end example
+
+ Variable functions
+
+ at example
+ function nf90_def_var(ncid, name, xtype, dimids, varid)
+   integer,               intent( in) :: ncid
+   character (len = *),   intent( in) :: name
+   integer,               intent( in) :: xtype
+   integer, dimension(:), intent( in) :: dimids ! May be omitted, scalar, 
+                                             ! vector
+   integer                            :: nf90_def_var
+ function nf90_inq_varid(ncid, name, varid)
+   integer,             intent( in) :: ncid
+   character (len = *), intent( in) :: name
+   integer,             intent(out) :: varid
+   integer                          :: nf90_inq_varid
+ function nf90_inquire_variable(ncid, varid, name, xtype, ndims, &
+                                dimids, nAtts)
+   integer,                         intent( in) :: ncid, varid
+   character (len = *),   optional, intent(out) :: name
+   integer,               optional, intent(out) :: xtype, ndims 
+   integer, dimension(*), optional, intent(out) :: dimids
+   integer,               optional, intent(out) :: nAtts
+   integer                                      :: nf90_inquire_variable
+ function nf90_put_var(ncid, varid, values, start, stride, map)
+   integer,                         intent( in) :: ncid, varid
+   any valid type, scalar or array of any rank, &
+                                    intent( in) :: values
+   integer, dimension(:), optional, intent( in) :: start, count, stride, map
+   integer                                      :: nf90_put_var
+ function nf90_get_var(ncid, varid, values, start, stride, map)
+   integer,                         intent( in) :: ncid, varid
+   any valid type, scalar or array of any rank, &
+                                    intent(out) :: values
+   integer, dimension(:), optional, intent( in) :: start, count, stride, map
+   integer                                      :: nf90_get_var
+ function nf90_rename_var(ncid, varid, newname)
+   integer,             intent( in) :: ncid, varid
+   character (len = *), intent( in) :: newname
+   integer                          :: nf90_rename_var
+ at end example
+
+ Attribute functions
+
+ at example
+ function nf90_inquire_attribute(ncid, varid, name, xtype, len, attnum)
+   integer,             intent( in)           :: ncid, varid
+   character (len = *), intent( in)           :: name
+   integer,             intent(out), optional :: xtype, len, attnum
+   integer                                    :: nf90_inquire_attribute
+ function nf90_inq_attname(ncid, varid, attnum, name)
+   integer,             intent( in) :: ncid, varid, attnum
+   character (len = *), intent(out) :: name
+   integer                          :: nf90_inq_attname
+ function nf90_put_att(ncid, varid, name, values)
+   integer,            intent( in) :: ncid, varid
+   character(len = *), intent( in) :: name
+   scalar character string or any numeric type, scalar, or array of rank 1, &
+                       intent( in) :: values
+   integer                         :: nf90_put_att
+ function nf90_get_att(ncid, varid, name, values)
+   integer,            intent( in) :: ncid, varid
+   character(len = *), intent( in) :: name
+   any valid type, scalar or array of rank 1, &
+                       intent(out) :: values
+   integer                          :: nf90_get_att
+ function nf90_copy_att(ncid_in, varid_in, name, ncid_out, varid_out)
+   integer,             intent( in) :: ncid_in,  varid_in
+   character (len = *), intent( in) :: name
+   integer,             intent( in) :: ncid_out, varid_out
+   integer                          :: nf90_copy_att
+ function nf90_rename_att(ncid, varid, curname, newname)
+   integer,             intent( in) :: ncid,  varid
+   character (len = *), intent( in) :: curname, newname
+   integer                          :: nf90_rename_att
+ function nf90_del_att(ncid, varid, name)
+   integer,             intent( in) :: ncid, varid
+   character (len = *), intent( in) :: name
+   integer                          :: nf90_del_att
+ at end example
+
+ at node FORTRAN 77 to Fortran 90 Transition Guide, Combined Index, Summary of Fortran 90 Interface, Top
+ at appendix Appendix B - FORTRAN 77 to Fortran 90 Transition Guide
+
+ at unnumberedsec The new Fortran 90 interface 
+
+The Fortran 90 interface to the netCDF library closely follows the
+FORTRAN 77 interface. In most cases, function and constant names and
+argument lists are the same, except that nf90_ replaces nf_ in
+names. The Fortran 90 interface is much smaller than the FORTRAN 77
+interface, however. This has been accomplished by using optional
+arguments and overloaded functions wherever possible.
+
+Because FORTRAN 77 is a subset of Fortran 90, there is no reason to
+modify working FORTRAN code to use the Fortran 90 interface. New code,
+however, can easily be patterned after existing FORTRAN while taking
+advantage of the simpler interface. Some compilers may provide
+additional support when using Fortran 90. For example, compilers may
+issue warnings if arguments with intent( in) are not set before they
+are passed to a procedure.
+
+The Fortran 90 interface is currently implemented as a set of wrappers
+around the base FORTRAN subroutines in the netCDF distribution. Future
+versions may be implemented entirely in Fortran 90, adding additional
+error checking possibilities.
+
+ at unnumberedsec Changes to Inquiry functions 
+
+In the Fortran 90 interface there are two inquiry functions each for
+dimensions, variables, and attributes, and a single inquiry function
+for datasets. These functions take optional arguments, allowing users
+to request only the information they need. These functions replace the
+many-argument and single-argument inquiry functions in the FORTRAN
+interface.
+
+As an example, compare the attribute inquiry functions in the Fortran
+90 interface
+
+ at example
+ function nf90_inquire_attribute(ncid, varid, name, xtype, len, attnum)
+   integer,             intent( in)           :: ncid, varid
+   character (len = *), intent( in)           :: name
+   integer,             intent(out), optional :: xtype, len, attnum
+   integer                                    :: nf90_inquire_attribute
+ function nf90_inq_attname(ncid, varid, attnum, name)
+   integer,             intent( in) :: ncid, varid, attnum
+   character (len = *), intent(out) :: name
+   integer                          :: nf90_inq_attname
+ at end example
+
+with those in the FORTRAN interface 
+
+ at example
+ INTEGER FUNCTION  NF_INQ_ATT        (NCID, VARID, NAME, xtype, len)
+ INTEGER FUNCTION  NF_INQ_ATTID      (NCID, VARID, NAME, attnum)
+ INTEGER FUNCTION  NF_INQ_ATTTYPE    (NCID, VARID, NAME, xtype)
+ INTEGER FUNCTION  NF_INQ_ATTLEN     (NCID, VARID, NAME, len)
+ INTEGER FUNCTION  NF_INQ_ATTNAME    (NCID, VARID, ATTNUM, name)
+ at end example
+
+ at unnumberedsec Changes to put and get function 
+
+The biggest simplification in the Fortran 90 is in the nf90_put_var
+and nf90_get_var functions. Both functions are overloaded: the values
+argument can be a scalar or an array any rank (7 is the maximum rank
+allowed by Fortran 90), and may be of any numeric type or the default
+character type. The netCDF library provides transparent conversion
+between the external representation of the data and the desired
+internal representation.
+
+The start, count, stride, and map arguments to nf90_put_var and
+nf90_get_var are optional. By default, data is read from or written to
+consecutive values of starting at the origin of the netCDF variable;
+the shape of the argument determines how many values are read from or
+written to each dimension. Any or all of these arguments may be
+supplied to override the default behavior.
+
+Note also that Fortran 90 allows arbitrary array sections to be passed
+to any procedure, which may greatly simplify programming. For examples
+see @ref{NF90_PUT_VAR} and @ref{NF90_GET_VAR}.
+
+ at node Combined Index,  , FORTRAN 77 to Fortran 90 Transition Guide, Top
+ at unnumbered Index
+
+ at printindex cp
+
+ at bye
+End:
diff --git a/docs/old/netcdf-f77.texi b/docs/old/netcdf-f77.texi
new file mode 100644
index 0000000..633c79f
--- /dev/null
+++ b/docs/old/netcdf-f77.texi
@@ -0,0 +1,9560 @@
+\input texinfo @c -*-texinfo-*-
+ at comment This is part of the netCDF documentation. See COPYRIGHT file
+ at c $Id: netcdf-f77.texi,v 1.72 2010/03/25 15:26:06 ed Exp $
+ at c %**start of header
+ at setfilename netcdf-f77.info
+ at setcontentsaftertitlepage
+ at settitle NetCDF Fortran 77 Interface Guide
+ at c Combine the variable, concept, and function indices.
+ at synindex vr cp
+ at synindex fn cp
+ at c %**end of header
+
+ at c version.texi is automatically generated by automake and contains
+ at c defined variables VERSION, UPDATED, UPDATED-MONTH.
+ at include version-f77.texi
+
+ at include defines.texi
+
+ at ifinfo
+ at dircategory netCDF scientific data format
+ at direntry
+* netcdf-f77: (netcdf-f77).         @value{f77-man}
+ at end direntry
+ at end ifinfo
+
+ at titlepage
+ at title @value{f77-man}
+ at subtitle NetCDF Version @value{VERSION}
+ at subtitle @value{UPDATED-MONTH}
+ at author Russ Rew, Glenn Davis, Steve Emmerson, and Harvey Davies
+ at author Unidata Program Center
+
+
+ at page
+ at vskip 0pt plus 1filll
+ at insertcopying
+ at end titlepage
+
+ at ifnottex
+ at node Top, Use of the NetCDF Library, (dir), (dir)
+ at top @value{f77-man}
+
+This document describes the FORTRAN-77 interface to the netCDF
+library. This document applies to netCDF version @value{VERSION}. This
+document was last updated in @value{UPDATED}.
+
+For a complete description of the netCDF format and utilities see 
+ at ref{Top,, , netcdf, @value{n-man}}.
+
+ at end ifnottex
+
+ at menu
+* Use of the NetCDF Library::   
+* Datasets::                    
+* Groups::                      
+* Dimensions::                  
+* User Defined Data Types::     
+* Variables::                   
+* Attributes::                  
+* V2 FORTRAN Transition::       
+* Summary of FORTRAN 77 Interface::  
+* Combined Index::              
+
+ at detailmenu
+ --- The Detailed Node Listing ---
+
+Use of the NetCDF Library
+
+* Creating a NetCDF Dataset::   
+* Reading a NetCDF Dataset with Known Names::  
+* Reading a netCDF Dataset with Unknown Names::  
+* Adding New Dimensions::       
+* Error Handling::              
+* Compiling and Linking with the NetCDF Library::  
+
+Datasets
+
+* Datasets Introduction::       
+* NetCDF Library Interface Descriptions::  
+* NF_STRERROR::                 
+* NF_INQ_LIBVERS::              Get netCDF library version
+* NF_CREATE::                   
+* NF__CREATE::                  
+* NF_CREATE_PAR::               
+* NF_OPEN::                     
+* NF__OPEN::                    
+* NF_OPEN_PAR::                 
+* NF_REDEF::                    
+* NF_ENDDEF::                   
+* NF__ENDDEF::                  
+* NF_CLOSE::                    
+* NF_INQ Family::               Inquire about an Open NetCDF Dataset
+* NF_SYNC::                     
+* NF_ABORT::                    
+* NF_SET_FILL::                 
+* NF_SET_DEFAULT_FORMAT::       
+* NF_SET_CHUNK_CACHE::          
+* NF_GET_CHUNK_CACHE::          
+
+Groups
+
+* NF_INQ_NCID::                 
+* NF_INQ_GRPS::                 
+* NF_INQ_VARIDS::               
+* NF_INQ_DIMIDS::               
+* NF_INQ_GRPNAME_LEN::          
+* NF_INQ_GRPNAME::              
+* NF_INQ_GRPNAME_FULL::         
+* NF_INQ_GRP_PARENT::           
+* NF_INQ_GRP_NCID::             
+* NF_INQ_GRP_FULL_NCID::        
+* NF_DEF_GRP::                  
+
+Dimensions
+
+* Dimensions Introduction::     
+* NF_DEF_DIM::                  
+* NF_INQ_DIMID::                
+* NF_INQ_DIM Family::           Inquire about a Dimension
+* NF_RENAME_DIM::               
+
+User Defined Data Types
+
+* User Defined Types::          
+* NF_INQ_TYPEIDS::              
+* NF_INQ_TYPEID::               
+* NF_INQ_TYPE::                 
+* NF_INQ_USER_TYPE::            
+* Compound Types::              
+* Variable Length Array::       
+* Opaque Type::                 
+* Enum Type::                   
+
+Compound Types Introduction
+
+* NF_DEF_COMPOUND::             
+* NF_INSERT_COMPOUND::          
+* NF_INSERT_ARRAY_COMPOUND::    
+* NF_INQ_COMPOUND::             
+* NF_INQ_COMPOUND_FIELD::       
+
+Variable Length Array Introduction
+
+* NF_DEF_VLEN::                 
+* NF_INQ_VLEN::                 
+* NF_FREE_VLEN::                
+* NF_PUT_VLEN_ELEMENT::         
+* NF_GET_VLEN_ELEMENT::         
+
+Opaque Type Introduction
+
+* NF_DEF_OPAQUE::               
+* NF_INQ_OPAQUE::               
+
+Example
+
+* NF_INQ_OPAQUE::               
+
+Enum Type Introduction
+
+* NF_DEF_ENUM::                 
+* NF_INSERT_ENUM::              
+* NF_INQ_ENUM::                 
+* NF_INQ_ENUM_MEMBER::          
+* NF_INQ_ENUM_IDENT::           
+
+Variables
+
+* Variables Introduction::      
+* Variable Types::              
+* NF_DEF_VAR::                  Create a Variable
+* NF_DEF_VAR_CHUNKING::         
+* NF_INQ_VAR_CHUNKING::         
+* NF_SET_VAR_CHUNK_CACHE::      
+* NF_GET_VAR_CHUNK_CACHE::      
+* NF_DEF_VAR_FILL::             
+* NF_INQ_VAR_FILL::             
+* NF_DEF_VAR_DEFLATE::          
+* NF_INQ_VAR_DEFLATE::          
+* NF_INQ_VAR_SZIP::             
+* NF_DEF_VAR_FLETCHER32::       
+* NF_INQ_VAR_FLETCHER32::       
+* NF_DEF_VAR_ENDIAN::           
+* NF_INQ_VAR_ENDIAN::           
+* NF_INQ_VARID::                
+* NF_INQ_VAR family::           Get Information about a Variable from Its ID:
+* NF_PUT_VAR1_  type::          
+* NF_PUT_VAR_ type::            
+* NF_PUT_VARA_ type::           
+* NF_PUT_VARS_ type::           
+* NF_PUT_VARM_ type::           
+* NF_GET_VAR1_ type::           
+* NF_GET_VAR_ type::            
+* NF_GET_VARA_ type::           
+* NF_GET_VARS_ type::           
+* NF_GET_VARM_ type::           
+* Reading and Writing Character String Values::  
+* Fill Values::                 What's Written Where there's No Data?
+* NF_RENAME_VAR::               
+* NF_VAR_PAR_ACCESS::           
+
+Attributes
+
+* Attributes Introduction::     
+* NF_PUT_ATT_ type::            Create an Attribute
+* NF_INQ_ATT Family::           Get Information about an Attribute
+* NF_GET_ATT_ type::            
+* NF_COPY_ATT::                 
+* NF_RENAME_ATT::               
+* NF_DEL_ATT::                  
+
+ at end detailmenu
+ at end menu
+
+ at node Use of the NetCDF Library, Datasets, Top, Top
+ at chapter Use of the NetCDF Library
+
+You can use the netCDF library without knowing about all of the netCDF
+interface. If you are creating a netCDF dataset, only a handful of
+routines are required to define the necessary dimensions, variables,
+and attributes, and to write the data to the netCDF dataset. (Even
+less are needed if you use the ncgen utility to create the dataset
+before running a program using netCDF library calls to write
+data. @xref{ncgen,,,netcdf, @value{n-man}}.)
+Similarly, if you are writing software to access data stored in a
+particular netCDF object, only a small subset of the netCDF library is
+required to open the netCDF dataset and access the data. Authors of
+generic applications that access arbitrary netCDF datasets need to be
+familiar with more of the netCDF library.
+
+In this chapter we provide templates of common sequences of netCDF
+calls needed for common uses. For clarity we present only the names of
+routines; omit declarations and error checking; omit the type-specific
+suffixes of routine names for variables and attributes; indent
+statements that are typically invoked multiple times; and use ... to
+represent arbitrary sequences of other statements. Full parameter
+lists are described in later chapters.
+
+ at menu
+* Creating a NetCDF Dataset::   
+* Reading a NetCDF Dataset with Known Names::  
+* Reading a netCDF Dataset with Unknown Names::  
+* Adding New Dimensions::       
+* Error Handling::              
+* Compiling and Linking with the NetCDF Library::  
+ at end menu
+
+ at node Creating a NetCDF Dataset, Reading a NetCDF Dataset with Known Names, Use of the NetCDF Library, Use of the NetCDF Library
+ at section Creating a NetCDF Dataset
+ at cindex creating dataset
+ at findex NF_CREATE, typical use
+ at findex NF_DEF_DIM, typical use
+ at findex NF_DEF_VAR, typical use
+ at findex NF_PUT_ATT, typical use
+ at findex NF_ENDDEF, typical use
+ at findex NF_PUT_VAR, typical use
+ at findex NF_CLOSE, typical use
+
+Here is a typical sequence of netCDF calls used to create a new netCDF
+dataset: 
+
+ at example
+    NF_CREATE           ! create netCDF dataset: enter define mode
+         ... 
+       NF_DEF_DIM       ! define dimensions: from name and length
+         ... 
+       NF_DEF_VAR       ! define variables: from name, type, dims
+         ... 
+       NF_PUT_ATT       ! assign attribute values
+         ... 
+    NF_ENDDEF           ! end definitions: leave define mode
+         ... 
+       NF_PUT_VAR       ! provide values for variable
+         ... 
+    NF_CLOSE            ! close: save new netCDF dataset
+ at end example
+
+Only one call is needed to create a netCDF dataset, at which point you
+will be in the first of two netCDF modes. When accessing an open
+netCDF dataset, it is either in define mode or data mode. In define
+mode, you can create dimensions, variables, and new attributes, but
+you cannot read or write variable data. In data mode, you can access
+data and change existing attributes, but you are not permitted to
+create new dimensions, variables, or attributes.
+
+One call to NF_DEF_DIM is needed for each dimension
+created. Similarly, one call to NF_DEF_VAR is needed for each variable
+creation, and one call to a member of the NF_PUT_ATT family is needed
+for each attribute defined and assigned a value. To leave define mode
+and enter data mode, call NF_ENDDEF.
+
+Once in data mode, you can add new data to variables, change old
+values, and change values of existing attributes (so long as the
+attribute changes do not require more storage space). Single values
+may be written to a netCDF variable with one of the members of the
+NF_PUT_VAR1 family, depending on what type of data you have to
+write. All the values of a variable may be written at once with one of
+the members of the NF_PUT_VAR family. Arrays or array cross-sections
+of a variable may be written using members of the NF_PUT_VARA
+family. Subsampled array sections may be written using members of the
+NF_PUT_VARS family. Mapped array sections may be written using members
+of the NF_PUT_VARM family. (Subsampled and mapped access are general
+forms of data access that are explained later.)
+
+Finally, you should explicitly close all netCDF datasets that have
+been opened for writing by calling NF_CLOSE. By default, access to the
+file system is buffered by the netCDF library. If a program terminates
+abnormally with netCDF datasets open for writing, your most recent
+modifications may be lost. This default buffering of data is disabled
+by setting the NF_SHARE flag when opening the dataset. But even if
+this flag is set, changes to attribute values or changes made in
+define mode are not written out until NF_SYNC or NF_CLOSE is called.
+
+ at node Reading a NetCDF Dataset with Known Names, Reading a netCDF Dataset with Unknown Names, Creating a NetCDF Dataset, Use of the NetCDF Library
+ at section Reading a NetCDF Dataset with Known Names
+ at findex NF_INQ_DIMID, typical use
+ at findex NF_INQ_VARID, typical use
+ at findex NF_GET_ATT, typical use
+ at findex NF_GET_VAR, typical use
+ at cindex reading datasets with known names
+
+Here we consider the case where you know the names of not only the
+netCDF datasets, but also the names of their dimensions, variables,
+and attributes. (Otherwise you would have to do "inquire" calls.) The
+order of typical C calls to read data from those variables in a netCDF
+dataset is:
+
+ at example
+    NF_OPEN               ! open existing netCDF dataset
+         ... 
+       NF_INQ_DIMID       ! get dimension IDs
+         ... 
+       NF_INQ_VARID       ! get variable IDs
+         ... 
+       NF_GET_ATT         ! get attribute values
+         ... 
+       NF_GET_VAR         ! get values of variables
+         ... 
+    NF_CLOSE              ! close netCDF dataset
+ at end example
+
+First, a single call opens the netCDF dataset, given the dataset name,
+and returns a netCDF ID that is used to refer to the open netCDF
+dataset in all subsequent calls.
+
+Next, a call to NF_INQ_DIMID for each dimension of interest gets the
+dimension ID from the dimension name. Similarly, each required
+variable ID is determined from its name by a call to NF_INQ_VARID.Once
+variable IDs are known, variable attribute values can be retrieved
+using the netCDF ID, the variable ID, and the desired attribute name
+as input to a member of the NF_GET_ATT family (typically
+NF_GET_ATT_TEXT or NF_GET_ATT_DOUBLE) for each desired
+attribute. Variable data values can be directly accessed from the
+netCDF dataset with calls to members of the NF_GET_VAR1 family for
+single values, the NF_GET_VAR family for entire variables, or various
+other members of the NF_GET_VARA, NF_GET_VARS, or NF_GET_VARM families
+for array, subsampled or mapped access.
+
+Finally, the netCDF dataset is closed with NF_CLOSE. There is no need
+to close a dataset open only for reading.
+
+ at node Reading a netCDF Dataset with Unknown Names, Adding New Dimensions, Reading a NetCDF Dataset with Known Names, Use of the NetCDF Library
+ at section Reading a netCDF Dataset with Unknown Names
+ at findex NF_INQ_ATTNAME, typical use
+ at findex NF_INQ, typical use
+ at cindex reading dataset with unknown names
+
+It is possible to write programs (e.g., generic software) which do
+such things as processing every variable, without needing to know in
+advance the names of these variables. Similarly, the names of
+dimensions and attributes may be unknown.
+
+Names and other information about netCDF objects may be obtained from
+netCDF datasets by calling inquire functions. These return information
+about a whole netCDF dataset, a dimension, a variable, or an
+attribute. The following template illustrates how they are used:
+
+ at example
+    NF_OPEN                   ! open existing netCDF dataset
+      ... 
+    NF_INQ                    ! find out what is in it
+         ... 
+       NF_INQ_DIM             ! get dimension names, lengths
+         ... 
+       NF_INQ_VAR             ! get variable names, types, shapes
+            ... 
+          NF_INQ_ATTNAME      ! get attribute names
+            ... 
+          NF_INQ_ATT          ! get attribute values
+            ... 
+          NF_GET_ATT          ! get attribute values
+            ... 
+       NF_GET_VAR             ! get values of variables
+         ... 
+    NF_CLOSE                  ! close netCDF dataset
+ at end example
+
+As in the previous example, a single call opens the existing netCDF
+dataset, returning a netCDF ID. This netCDF ID is given to the NF_INQ
+routine, which returns the number of dimensions, the number of
+variables, the number of global attributes, and the ID of the
+unlimited dimension, if there is one.
+
+All the inquire functions are inexpensive to use and require no I/O,
+since the information they provide is stored in memory when a netCDF
+dataset is first opened.
+
+Dimension IDs use consecutive integers, beginning at 1. Also
+dimensions, once created, cannot be deleted. Therefore, knowing the
+number of dimension IDs in a netCDF dataset means knowing all the
+dimension IDs: they are the integers 1, 2, 3, ... up to the number of
+dimensions. For each dimension ID, a call to the inquire function
+NF_INQ_DIM returns the dimension name and length.
+
+Variable IDs are also assigned from consecutive integers 1, 2, 3,
+... up to the number of variables. These can be used in NF_INQ_VAR
+calls to find out the names, types, shapes, and the number of
+attributes assigned to each variable.
+
+Once the number of attributes for a variable is known, successive
+calls to NF_INQ_ATTNAME return the name for each attribute given the
+netCDF ID, variable ID, and attribute number. Armed with the attribute
+name, a call to NF_INQ_ATT returns its type and length. Given the type
+and length, you can allocate enough space to hold the attribute
+values. Then a call to a member of the NF_GET_ATT family returns the
+attribute values.
+
+Once the IDs and shapes of netCDF variables are known, data values can
+be accessed by calling a member of the NF_GET_VAR1 family for single
+values, or members of the NF_GET_VAR, NF_GET_VARA, NF_GET_VARS, or
+NF_GET_VARM for various kinds of array access.
+
+ at node Adding New Dimensions, Error Handling, Reading a netCDF Dataset with Unknown Names, Use of the NetCDF Library
+ at section Adding New Dimensions, Variables, Attributes
+ at cindex dimensions, adding
+ at cindex variables, adding
+ at cindex attributes, adding
+
+An existing netCDF dataset can be extensively altered. New dimensions,
+variables, and attributes can be added or existing ones renamed, and
+existing attributes can be deleted. Existing dimensions, variables,
+and attributes can be renamed. The following code template lists a
+typical sequence of calls to add new netCDF components to an existing
+dataset:
+
+ at example
+    NF_OPEN             ! open existing netCDF dataset
+      ... 
+    NF_REDEF            ! put it into define mode
+        ... 
+      NF_DEF_DIM        ! define additional dimensions (if any)
+        ... 
+      NF_DEF_VAR        ! define additional variables (if any)
+        ... 
+      NF_PUT_ATT        ! define other attributes (if any)
+        ... 
+    NF_ENDDEF           ! check definitions, leave define mode
+        ... 
+      NF_PUT_VAR        ! provide new variable values
+        ... 
+    NF_CLOSE            ! close netCDF dataset
+ at end example
+
+A netCDF dataset is first opened by the NF_OPEN call. This call puts
+the open dataset in data mode, which means existing data values can be
+accessed and changed, existing attributes can be changed (so long as
+they do not grow), but nothing can be added. To add new netCDF
+dimensions, variables, or attributes you must enter define mode, by
+calling NF_REDEF.In define mode, call NF_DEF_DIM to define new
+dimensions, NF_DEF_VAR to define new variables, and a member of the
+NF_PUT_ATT family to assign new attributes to variables or enlarge old
+attributes.
+
+You can leave define mode and reenter data mode, checking all the new
+definitions for consistency and committing the changes to disk, by
+calling NF_ENDDEF. If you do not wish to reenter data mode, just call
+NF_CLOSE, which will have the effect of first calling NF_ENDDEF.
+
+Until the NF_ENDDEF call, you may back out of all the redefinitions
+made in define mode and restore the previous state of the netCDF
+dataset by calling NF_ABORT. You may also use the NF_ABORT call to
+restore the netCDF dataset to a consistent state if the call to
+NF_ENDDEF fails. If you have called NF_CLOSE from definition mode and
+the implied call to NF_ENDDEF fails, NF_ABORT will automatically be
+called to close the netCDF dataset and leave it in its previous
+consistent state (before you entered define mode).
+
+At most one process should have a netCDF dataset open for writing at
+one time. The library is designed to provide limited support for
+multiple concurrent readers with one writer, via disciplined use of
+the NF_SYNC function and the NF_SHARE flag. If a writer makes changes
+in define mode, such as the addition of new variables, dimensions, or
+attributes, some means external to the library is necessary to prevent
+readers from making concurrent accesses and to inform readers to call
+NF_SYNC before the next access.
+
+ at node Error Handling, Compiling and Linking with the NetCDF Library, Adding New Dimensions, Use of the NetCDF Library
+ at section Error Handling
+
+The netCDF library provides the facilities needed to handle errors in
+a flexible way. Each netCDF function returns an integer status
+value. If the returned status value indicates an error, you may handle
+it in any way desired, from printing an associated error message and
+exiting to ignoring the error indication and proceeding (not
+recommended!). For simplicity, the examples in this guide check the
+error status and call a separate function to handle any errors.
+
+The NF_STRERROR function is available to convert a returned integer
+error status into an error message string.
+
+Occasionally, low-level I/O errors may occur in a layer below the
+netCDF library. For example, if a write operation causes you to exceed
+disk quotas or to attempt to write to a device that is no longer
+available, you may get an error from a layer below the netCDF library,
+but the resulting write error will still be reflected in the returned
+status value.
+
+ at node Compiling and Linking with the NetCDF Library,  , Error Handling, Use of the NetCDF Library
+ at section Compiling and Linking with the NetCDF Library
+ at cindex linking to netCDF library
+ at cindex compiling with netCDF library
+ at cindex nf-config
+
+Details of how to compile and link a program that uses the netCDF C or
+FORTRAN interfaces differ, depending on the operating system, the
+available compilers, and where the netCDF library and include files
+are installed. Nevertheless, we provide here examples of how to
+compile and link a program that uses the netCDF library on a Unix
+platform, so that you can adjust these examples to fit your
+installation.
+
+Every FORTRAN file that references netCDF functions or constants must
+contain an appropriate INCLUDE statement before the first such
+reference:
+
+ at example
+INCLUDE 'netcdf.inc'
+ at end example
+
+Unless the netcdf.inc file is installed in a standard directory where
+the FORTRAN compiler always looks, you must use the -I option when
+invoking the compiler, to specify a directory where netcdf.inc is
+installed, for example:
+
+ at example
+f77 -c -I/usr/local/include myprogram.f
+ at end example
+
+Unless the netCDF library is installed in a standard directory where
+the linker always looks, you must use the -L and -l options to link an
+object file that uses the netCDF library. Since version 4.1.3, the
+netCDF Fortran library (named `libnetcdff') is distinct from the
+netCDF C library (named `libnetcdf'), but depends on it.  If it is
+installed as a shared library, you need only use `-lnetcdff' to
+specify the Fortran library for linking.
+
+For example, if installed as a shared library, use something like:
+
+ at example
+f77 -o myprogram myprogram.o -L/usr/local/lib -lnetcdff
+ at end example
+
+If installed as a static library, you will at least need to mention
+the netCDF C library and perhaps other libraries, such as hdf5 or
+curl, depending on how the C library was built.  For example:
+
+ at example
+f77 -o myprogram myprogram.o -L/usr/local/lib -lnetcdff -lnetcdf
+ at end example
+
+Use of the nf-config utility program, installed as part of the
+netcdf-fortran software, provides an easier way to compile and link,
+without needing to know the details of where the library has been
+installed, or whether it is installed as a shared or static library.
+
+To see all the options for `nf-config', invoke it with the `--help'
+argument. 
+
+Here's an example of how you could use `nf-config' to compile and link
+a Fortran program in one step:
+
+ at example
+f77 myprogram.f -o myprogram `nf-config --fflags --flibs`
+ at end example
+
+If it is installed on your system, you could also use the `pkg-config'
+utility to compile and link Fortran programs with the netCDF
+libraries.  This is especially useful in Makefiles, to insulate them
+from changes to library versions and dependencies.  Here is an example
+of how you could compile and link a Fortran program with netCDF
+libraries using pkg-config:
+
+ at example
+export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
+f77 myprogram.f -o myprogram `pkg-config --cflags --libs netcdf-fortran`
+ at end example
+
+where here `--cflags' means compiler flags and `libs' requests that
+the approriate libraries be linked in.
+
+ at node Datasets, Groups, Use of the NetCDF Library, Top
+ at chapter Datasets
+
+ at menu
+* Datasets Introduction::       
+* NetCDF Library Interface Descriptions::  
+* NF_STRERROR::                 
+* NF_INQ_LIBVERS::              Get netCDF library version
+* NF_CREATE::                   
+* NF__CREATE::                  
+* NF_CREATE_PAR::               
+* NF_OPEN::                     
+* NF__OPEN::                    
+* NF_OPEN_PAR::                 
+* NF_REDEF::                    
+* NF_ENDDEF::                   
+* NF__ENDDEF::                  
+* NF_CLOSE::                    
+* NF_INQ Family::               Inquire about an Open NetCDF Dataset
+* NF_SYNC::                     
+* NF_ABORT::                    
+* NF_SET_FILL::                 
+* NF_SET_DEFAULT_FORMAT::       
+* NF_SET_CHUNK_CACHE::          
+* NF_GET_CHUNK_CACHE::          
+ at end menu
+
+ at node Datasets Introduction, NetCDF Library Interface Descriptions, Datasets, Datasets
+ at section Datasets Introduction
+ at cindex datasets, introduction
+
+This chapter presents the interfaces of the netCDF functions that deal
+with a netCDF dataset or the whole netCDF library.
+
+A netCDF dataset that has not yet been opened can only be referred to
+by its dataset name. Once a netCDF dataset is opened, it is referred
+to by a netCDF ID, which is a small nonnegative integer returned when
+you create or open the dataset. A netCDF ID is much like a file
+descriptor in C or a logical unit number in FORTRAN. In any single
+program, the netCDF IDs of distinct open netCDF datasets are
+distinct. A single netCDF dataset may be opened multiple times and
+will then have multiple distinct netCDF IDs; however at most one of
+the open instances of a single netCDF dataset should permit
+writing. When an open netCDF dataset is closed, the ID is no longer
+associated with a netCDF dataset.
+
+Functions that deal with the netCDF library include:
+ at itemize
+
+ at item
+Get version of library. 
+
+ at item
+Get error message corresponding to a returned error code. 
+ at end itemize
+
+The operations supported on a netCDF dataset as a single object are:
+ at itemize
+
+ at item
+Create, given dataset name and whether to overwrite or not. 
+
+ at item
+Open for access, given dataset name and read or write intent. 
+
+ at item
+Put into define mode, to add dimensions, variables, or attributes.
+
+ at item
+Take out of define mode, checking consistency of additions. 
+
+ at item
+Close, writing to disk if required. 
+
+ at item
+Inquire about the number of dimensions, number of variables, number of
+global attributes, and ID of the unlimited dimension, if any.
+
+ at item
+Synchronize to disk to make sure it is current. 
+
+ at item
+Set and unset nofill mode for optimized sequential writes. 
+
+ at item
+After a summary of conventions used in describing the netCDF
+interfaces, the rest of this chapter presents a detailed description
+of the interfaces for these operations.
+ at end itemize
+
+ at node NetCDF Library Interface Descriptions, NF_STRERROR, Datasets Introduction, Datasets
+ at section NetCDF Library Interface Descriptions
+ at cindex interface descriptions
+
+Each interface description for a particular netCDF function in this
+and later chapters contains:
+
+ at itemize
+
+ at item
+a description of the purpose of the function; 
+
+ at item
+a FORTRAN function prototype that presents the type and order of the formal
+parameters to the function;
+
+ at item
+a description of each formal parameter in the C interface; 
+
+ at item
+a list of possible error conditions; and 
+
+ at item
+an example of a FORTRAN program fragment calling the netCDF function (and
+perhaps other netCDF functions).
+ at end itemize
+
+The examples follow a simple convention for error handling, always
+checking the error status returned from each netCDF function call and
+calling a handle_error function in case an error was detected. For an
+example of such a function, see Section 5.2 "Get error message
+corresponding to error status: nf_strerror".
+
+ at node NF_STRERROR, NF_INQ_LIBVERS, NetCDF Library Interface Descriptions, Datasets
+ at section NF_STRERROR
+ at findex NF_STRERROR
+
+The function NF_STRERROR returns a static reference to an error
+message string corresponding to an integer netCDF error status or to a
+system error number, presumably returned by a previous call to some
+other netCDF function. The list of netCDF error status codes is
+available in the appropriate include file for each language binding.
+
+ at heading Usage 
+ at example
+CHARACTER*80 FUNCTION NF_STRERROR(INTEGER NCERR)
+ at end example
+
+ at table @code
+ at item NCERR
+An error status that might have been returned from a previous call to
+some netCDF function.
+ at end table
+
+ at heading Errors 
+
+If you provide an invalid integer error status that does not
+correspond to any netCDF error message or or to any system error
+message (as understood by the system strerror function), NF_STRERROR
+returns a string indicating that there is no such error status.
+
+ at heading Example 
+
+Here is an example of a simple error handling function that uses
+NF_STRERROR to print the error message corresponding to the netCDF
+error status returned from any netCDF function call and then exit:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+SUBROUTINE HANDLE_ERR(STATUS)
+INTEGER STATUS
+IF (STATUS .NE. NF_NOERR) THEN
+  PRINT *, NF_STRERROR(STATUS)
+  STOP 'Stopped'
+ENDIF
+END
+ at end example
+
+ at node NF_INQ_LIBVERS, NF_CREATE, NF_STRERROR, Datasets
+ at section Get netCDF library version: NF_INQ_LIBVERS
+ at findex NF_INQ_LIBVERS
+
+The function NF_INQ_LIBVERS returns a string identifying the version
+of the netCDF library, and when it was built.
+
+ at heading Usage 
+ at example
+CHARACTER*80 FUNCTION NF_INQ_LIBVERS()
+ at end example
+
+ at heading Errors 
+
+This function takes no arguments, and thus no errors are possible in
+its invocation.
+
+ at heading Example 
+
+Here is an example using nf_inq_libvers to print the version of the
+netCDF library with which the program is linked:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+PRINT *, NF_INQ_LIBVERS()
+ at end example
+
+ at node NF_CREATE, NF__CREATE, NF_INQ_LIBVERS, Datasets
+ at section NF_CREATE 
+ at findex NF_CREATE 
+
+This function creates a new netCDF dataset, returning a netCDF ID that
+can subsequently be used to refer to the netCDF dataset in other
+netCDF function calls. The new netCDF dataset opened for write access
+and placed in define mode, ready for you to add dimensions, variables,
+and attributes.
+
+A creation mode flag specifies whether to overwrite any existing
+dataset with the same name and whether access to the dataset is
+shared.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_CREATE (CHARACTER*(*) PATH, INTEGER CMODE, 
+                            INTEGER ncid)
+ at end example
+
+ at table @code
+ at item PATH
+The file name of the new netCDF dataset.
+ 
+ at item CMODE
+The creation mode flag. The following flags are available:
+NF_NOCLOBBER, NF_SHARE, NF_64BIT_OFFSET, NF_NETCDF4 and
+NF_CLASSIC_MODEL.  You can combine the affect of multiple flags in a
+single argument by using the bitwise OR operator.  For example, to
+specify both NF_NOCLOBBER and NF_SHARE, you could provide the argument
+OR(NF_NOCLOBBER, NF_SHARE).
+
+A zero value (defined for convenience as NF_CLOBBER) specifies the
+default behavior: overwrite any existing dataset with the same file
+name and buffer and cache accesses for efficiency. The dataset will be
+in netCDF classic format. @xref{NetCDF Classic Format Limitations,,,
+netcdf, @value{n-man}}.
+
+Setting NF_NOCLOBBER means you do not want to clobber (overwrite) an
+existing dataset; an error (NF_EEXIST) is returned if the specified
+dataset already exists.
+
+The NF_SHARE flag is appropriate when one process may be writing the
+dataset and one or more other processes reading the dataset
+concurrently; it means that dataset accesses are not buffered and
+caching is limited. Since the buffering scheme is optimized for
+sequential access, programs that do not access data sequentially may
+see some performance improvement by setting the NF_SHARE flag. This
+only applied to classic and 64-bit offset format files.
+
+Setting NF_64BIT_OFFSET causes netCDF to create a 64-bit offset format
+file, instead of a netCDF classic format file. The 64-bit offset
+format imposes far fewer restrictions on very large (i.e. over 2 GB)
+data files. @xref{Large File Support,,, netcdf, @value{n-man}}.
+
+Setting NF_NETCDF4 causes netCDF to create a netCDF-4/HDF5 format
+file. Oring NF_CLASSIC_MODEL with NF_NETCDF4 causes the netCDF library
+to create a netCDF-4/HDF5 data file, with the netCDF classic model
+enforced - none of the new features of the netCDF-4 data model may be
+usedin such a file, for example groups and user-defined types. 
+
+ at item ncid
+Returned netCDF ID.
+ at end table
+
+ at heading Errors 
+NF_CREATE returns the value NF_NOERR if no errors occurred. Possible
+causes of errors include:
+ at itemize
+
+ at item
+Passing a dataset name that includes a directory that does not exist.
+ at item
+Specifying a dataset name of a file that exists and also specifying
+NF_NOCLOBBER.
+ at item
+Specifying a meaningless value for the creation mode.
+ at item
+Attempting to create a netCDF dataset in a directory where you don't
+have permission to create files.
+ at end itemize
+
+ at heading Example 
+
+In this example we create a netCDF dataset named foo.nc; we want the
+dataset to be created in the current directory only if a dataset with
+that name does not already exist:
+
+ at example
+INCLUDE 'netcdf.inc'
+  ... 
+INTEGER NCID, STATUS
+... 
+STATUS = NF_CREATE('foo.nc', NF_NOCLOBBER, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF__CREATE, NF_CREATE_PAR, NF_CREATE, Datasets
+ at section NF__CREATE 
+ at findex NF__CREATE 
+
+This function is a variant of NF_CREATE, NF__CREATE (note the double
+underscore) allows users to specify two tuning parameters for the
+file that it is creating. These tuning parameters are not written to
+the data file, they are only used for so long as the file remains open
+after an NF__CREATE.
+
+This function creates a new netCDF dataset, returning a netCDF ID that
+can subsequently be used to refer to the netCDF dataset in other
+netCDF function calls. The new netCDF dataset opened for write access
+and placed in define mode, ready for you to add dimensions, variables,
+and attributes.
+
+A creation mode flag specifies whether to overwrite any existing
+dataset with the same name and whether access to the dataset is
+shared.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF__CREATE (CHARACTER*(*) PATH, INTEGER CMODE, INTEGER INITIALSZ, 
+                            INTEGER BUFRSIZEHINT, INTEGER ncid)
+ at end example
+
+ at table @code
+ at item PATH
+The file name of the new netCDF dataset.
+ 
+ at item CMODE
+The creation mode flag. The following flags are available:
+NF_NOCLOBBER, NF_SHARE, NF_64BIT_OFFSET, NF_NETCDF4, and
+NF_CLASSIC_MODEL.
+
+Setting NF_NOCLOBBER means you do not want to clobber (overwrite) an
+existing dataset; an error (NF_EEXIST) is returned if the specified
+dataset already exists.
+
+The NF_SHARE flag is appropriate when one process may be writing the
+dataset and one or more other processes reading the dataset
+concurrently; it means that dataset accesses are not buffered and
+caching is limited. Since the buffering scheme is optimized for
+sequential access, programs that do not access data sequentially may
+see some performance improvement by setting the NF_SHARE flag. This
+flag has no effect with netCDF-4/HDF5 files.
+
+Setting NF_64BIT_OFFSET causes netCDF to create a 64-bit offset format
+file, instead of a netCDF classic format file. The 64-bit offset
+format imposes far fewer restrictions on very large (i.e. over 2 GB)
+data files. @xref{Large File Support,,, netcdf, @value{n-man}}.
+
+Setting NF_CLASSIC_MODEL causes netCDF to enforce the classic data
+model in this file. (This only has effect for netCDF-4/HDF5 files, as
+classic and 64-bit offset files always use the classic model.) When
+used with NF_NETCDF4, this flag ensures that the resulting
+netCDF-4/HDF5 file may never contain any new constructs from the
+enhanced data model. That is, it cannot contain groups, user defined
+types, multiple unlimited dimensions, or new atomic types. The
+advantage of this restriction is that such files are guarenteed to
+work with existing netCDF software.
+
+A zero value (defined for convenience as NF_CLOBBER) specifies the
+default behavior: overwrite any existing dataset with the same file
+name and buffer and cache accesses for efficiency. The dataset will be
+in netCDF classic format. @xref{NetCDF Classic Format Limitations,,,
+netcdf, @value{n-man}}.
+
+ at item INITIALSZ
+This parameter sets the initial size of the file at creation time.
+
+ at item BUFRSIZEHINT
+The argument referenced by BUFRSIZEHINT controls a space versus time
+tradeoff, memory allocated in the netcdf library versus number of system
+calls.
+
+Because of internal requirements, the value may not be set to exactly
+the value requested. The actual value chosen is returned by reference.
+
+Using the value NF_SIZEHINT_DEFAULT causes the library to choose a
+default. How the system chooses the default depends on the system. On
+many systems, the "preferred I/O block size" is available from the
+stat() system call, struct stat member st_blksize. If this is
+available it is used. Lacking that, twice the system pagesize is used.
+
+Lacking a call to discover the system pagesize, we just set default
+bufrsize to 8192.
+
+The BUFRSIZE is a property of a given open netcdf descriptor
+ncid, it is not a persistent property of the netcdf dataset.
+
+ at item ncid
+Returned netCDF ID.
+ at end table
+
+ at heading Errors 
+NF__CREATE returns the value NF_NOERR if no errors occurred. Possible
+causes of errors include:
+ at itemize
+
+ at item
+Passing a dataset name that includes a directory that does not exist.
+ at item
+Specifying a dataset name of a file that exists and also specifying
+NF_NOCLOBBER.
+ at item
+Specifying a meaningless value for the creation mode.
+ at item
+Attempting to create a netCDF dataset in a directory where you don't
+have permission to create files.
+ at end itemize
+
+ at heading Example 
+
+In this example we create a netCDF dataset named foo.nc; we want the
+dataset to be created in the current directory only if a dataset with
+that name does not already exist:
+
+ at example
+INCLUDE 'netcdf.inc'
+  ... 
+INTEGER NCID, STATUS, INITIALSZ, BUFRSIZEHINT
+... 
+INITIALSZ = 2048
+BUFRSIZEHINT = 1024
+STATUS = NF__CREATE('foo.nc', NF_NOCLOBBER, INITIALSZ, BUFRSIZEHINT, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_CREATE_PAR, NF_OPEN, NF__CREATE, Datasets
+ at section NF_CREATE_PAR
+ at findex NF_CREATE_PAR
+
+This function is a variant of nf_create, nf_create_par allows users to
+open a file on a MPI/IO or MPI/Posix parallel file system.
+
+The parallel parameters are not written to the data file, they are
+only used for so long as the file remains open after an nf_create_par.
+
+This function is only available if the netCDF library was built with
+parallel I/O.
+
+This function creates a new netCDF dataset, returning a netCDF ID that
+can subsequently be used to refer to the netCDF dataset in other
+netCDF function calls. The new netCDF dataset opened for write access
+and placed in define mode, ready for you to add dimensions, variables,
+and attributes.
+
+When a netCDF-4 file is created for parallel access, independent
+operations are the default. To use collective access on a variable,
+ at xref{NF_VAR_PAR_ACCESS}.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_CREATE_PAR(CHARACTER*(*) PATH, INTEGER CMODE, 
+                               INTEGER MPI_COMM, INTEGER MPI_INFO, 
+                               INTEGER ncid)
+ at end example
+
+ at table @code
+ at item PATH
+The file name of the new netCDF dataset.
+ 
+ at item CMODE
+The creation mode flag. The following flags are available:
+NF_NOCLOBBER, NF_NETCDF4 and NF_CLASSIC_MODEL.  You can combine the
+affect of multiple flags in a single argument by using the bitwise OR
+operator.  For example, to specify both NF_NOCLOBBER and NF_NETCDF4, you
+could provide the argument OR(NF_NOCLOBBER, NF_NETCDF4).
+
+Setting NF_NETCDF4 causes netCDF to create a netCDF-4/HDF5 format
+file. Oring NF_CLASSIC_MODEL with NF_NETCDF4 causes the netCDF library
+to create a netCDF-4/HDF5 data file, with the netCDF classic model
+enforced - none of the new features of the netCDF-4 data model may be
+usedin such a file, for example groups and user-defined types. 
+
+Only netCDF-4/HDF5 files may be used with parallel I/O.
+
+ at item MPI_COMM
+The MPI communicator.
+
+ at item MPI_INFO
+The MPI info.
+
+ at item ncid
+Returned netCDF ID.
+
+ at end table
+
+ at heading Errors 
+NF_CREATE returns the value NF_NOERR if no errors occurred. Possible
+causes of errors include:
+ at itemize
+
+ at item
+Passing a dataset name that includes a directory that does not exist.
+ at item
+Specifying a dataset name of a file that exists and also specifying
+NF_NOCLOBBER.
+ at item
+Specifying a meaningless value for the creation mode.
+ at item
+Attempting to create a netCDF dataset in a directory where you don't
+have permission to create files.
+ at end itemize
+
+ at heading Example 
+This example is from test program nf_test/ftst_parallel.F.
+
+ at example
+!     Create the netCDF file. 
+      mode_flag = IOR(nf_netcdf4, nf_classic_model) 
+      retval = nf_create_par(FILE_NAME, mode_flag, MPI_COMM_WORLD, 
+     $     MPI_INFO_NULL, ncid)
+      if (retval .ne. nf_noerr) stop 2
+ at end example
+
+ at node NF_OPEN, NF__OPEN, NF_CREATE_PAR, Datasets
+ at section NF_OPEN 
+ at findex NF_OPEN 
+
+The function NF_OPEN opens an existing netCDF dataset for access.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_OPEN(CHARACTER*(*) PATH, INTEGER OMODE, INTEGER ncid)
+ at end example
+
+ at table @code
+
+ at item PATH
+File name for netCDF dataset to be opened.
+This may be an OPeNDAP URL if DAP support is enabled.
+ 
+ at item OMODE
+A zero value (or NF_NOWRITE) specifies: open the
+dataset with read-only access, buffering and caching accesses for
+efficiency.
+
+Otherwise, the creation mode is NF_WRITE, NF_SHARE, or
+OR(NF_WRITE, NF_SHARE). Setting the NF_WRITE flag opens the dataset with
+read-write access. ("Writing" means any kind of change to the dataset,
+including appending or changing data, adding or renaming dimensions,
+variables, and attributes, or deleting attributes.) The NF_SHARE flag
+is appropriate when one process may be writing the dataset and one or
+more other processes reading the dataset concurrently; it means that
+dataset accesses are not buffered and caching is limited. Since the
+buffering scheme is optimized for sequential access, programs that do
+not access data sequentially may see some performance improvement by
+setting the NF_SHARE flag.
+
+ at item ncid
+Returned netCDF ID.
+ at end table
+
+ at heading Errors 
+
+NF_OPEN returns the value NF_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+ at itemize
+
+ at item
+The specified netCDF dataset does not exist. 
+ at item
+A meaningless mode was specified. 
+ at end itemize
+
+ at heading Example 
+Here is an example using NF_OPEN to open an existing netCDF dataset
+named foo.nc for read-only, non-shared access:
+
+ at example
+INCLUDE 'netcdf.inc'
+ ... 
+INTEGER NCID, STATUS
+... 
+STATUS = NF_OPEN('foo.nc', 0, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF__OPEN, NF_OPEN_PAR, NF_OPEN, Datasets
+ at section NF__OPEN 
+ at findex NF__OPEN 
+
+The function NF)_OPEN opens an existing netCDF dataset for access,
+with a performance tuning parameter.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF__OPEN(CHARACTER*(*) PATH, INTEGER OMODE, INTEGER
+BUFRSIZEHINT, INTEGER ncid)
+ at end example
+
+ at table @code
+
+ at item PATH
+File name for netCDF dataset to be opened.
+ 
+ at item OMODE
+A zero value (or NF_NOWRITE) specifies: open the
+dataset with read-only access, buffering and caching accesses for
+efficiency
+
+Otherwise, the creation mode is NF_WRITE, NF_SHARE, or
+OR(NF_WRITE,NF_SHARE). Setting the NF_WRITE flag opens the dataset with
+read-write access. ("Writing" means any kind of change to the dataset,
+including appending or changing data, adding or renaming dimensions,
+variables, and attributes, or deleting attributes.) The NF_SHARE flag
+is appropriate when one process may be writing the dataset and one or
+more other processes reading the dataset concurrently; it means that
+dataset accesses are not buffered and caching is limited. Since the
+buffering scheme is optimized for sequential access, programs that do
+not access data sequentially may see some performance improvement by
+setting the NF_SHARE flag.
+ 
+ at item BUFRSIZEHINT
+This argument controls a space versus time tradeoff, memory allocated
+in the netcdf library versus number of system calls.
+
+Because of internal requirements, the value may not be set to exactly
+the value requested. The actual value chosen is returned by reference.
+
+Using the value NF_SIZEHINT_DEFAULT causes the library to choose a
+default. How the system chooses the default depends on the system. On
+many systems, the "preferred I/O block size" is available from the
+stat() system call, struct stat member st_blksize. If this is
+available it is used. Lacking that, twice the system pagesize is used.
+
+Lacking a call to discover the system pagesize, we just set default
+bufrsize to 8192.
+
+The bufrsize is a property of a given open netcdf descriptor
+ncid, it is not a persistent property of the netcdf dataset.
+
+ at item ncid
+Returned netCDF ID.
+ at end table
+
+ at heading Errors 
+
+NF__OPEN returns the value NF_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+ at itemize
+
+ at item
+The specified netCDF dataset does not exist. 
+ at item
+A meaningless mode was specified. 
+ at end itemize
+
+ at heading Example 
+Here is an example using NF__OPEN to open an existing netCDF dataset
+named foo.nc for read-only, non-shared access:
+
+ at example
+INCLUDE 'netcdf.inc'
+ ... 
+INTEGER NCID, STATUS, BUFRSIZEHINT
+... 
+BUFRSIZEHINT = 1024
+STATUS = NF_OPEN('foo.nc', 0, BUFRSIZEHINT, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_OPEN_PAR, NF_REDEF, NF__OPEN, Datasets
+ at section NF_OPEN_PAR 
+ at findex NF_OPEN_PAR
+
+This function opens a netCDF-4 dataset for parallel access.
+
+This function is only available if the netCDF library was built with a
+HDF5 library for which --enable-parallel was used, and which was
+linked (like HDF5) to MPI libraries.
+
+This opens the file using either MPI-IO or MPI-POSIX. The file must be
+a netCDF-4 file. (That is, it must have been created using NF_NETCDF4
+in the creation mode).
+
+This function is only available if netCDF-4 was build with a version
+of the HDF5 library which was built with --enable-parallel.
+
+Before either HDF5 or netCDF-4 can be installed with support for
+parallel programming, and MPI layer must also be installed on the
+machine, and usually a parallel file system.
+
+NetCDF-4 exposes the parallel access functionality of HDF5. For more
+information about what is required to install and use the parallel
+access functions, see the HDF5 web site.
+
+When a netCDF-4 file is opened for parallel access, collective
+operations are the default. To use independent access on a variable,
+ at xref{NF_VAR_PAR_ACCESS}.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_OPEN_PAR(CHARACTER*(*) PATH, INTEGER OMODE, 
+                             INTEGER MPI_COMM, INTEGER MPI_INFO, 
+                             INTEGER ncid)
+ at end example
+
+ at table @code
+
+ at item PATH
+File name for netCDF dataset to be opened.
+ 
+ at item OMODE
+A zero value (or NF_NOWRITE) specifies: open the
+dataset with read-only access.
+
+Otherwise, the mode may be NF_WRITE. Setting the NF_WRITE flag opens
+the dataset with read-write access. ("Writing" means any kind of
+change to the dataset, including appending or changing data, adding or
+renaming dimensions, variables, and attributes, or deleting
+attributes.)
+
+Setting NF_NETCDF4 is not necessary (or allowed). The file type is
+detected automatically.
+
+ at item MPI_COMM
+The MPI communicator.
+
+ at item MPI_INFO
+The MPI info.
+
+ at item ncid
+Returned netCDF ID.
+
+ at end table
+
+ at heading Errors 
+
+NF_OPEN returns the value NF_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+ at itemize
+
+ at item
+The specified netCDF dataset does not exist. 
+
+ at item
+A meaningless mode was specified. 
+
+ at item
+Not a netCDF-4 file.
+
+ at end itemize
+
+ at heading Example 
+This example is from the test program nf_test/ftst_parallel.F.
+
+ at example
+!     Reopen the file.
+      retval = nf_open_par(FILE_NAME, nf_nowrite, MPI_COMM_WORLD, 
+     $     MPI_INFO_NULL, ncid)
+      if (retval .ne. nf_noerr) stop 2
+ at end example
+
+ at node NF_REDEF, NF_ENDDEF, NF_OPEN_PAR, Datasets
+ at section NF_REDEF 
+ at findex NF_REDEF 
+
+The function NF_REDEF puts an open netCDF dataset into define mode, so
+dimensions, variables, and attributes can be added or renamed and
+attributes can be deleted.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_REDEF(INTEGER NCID)
+ at end example
+
+ at table @code
+ at item NCID
+netCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ at end table
+
+ at heading Errors 
+NF_REDEF returns the value NF_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+ at itemize
+
+ at item
+The specified netCDF dataset is already in define mode. 
+
+ at item
+The specified netCDF dataset was opened for read-only. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+ at end itemize
+
+ at heading Example 
+Here is an example using NF_REDEF to open an existing netCDF dataset
+named foo.nc and put it into define mode:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER NCID, STATUS
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_WRITE, NCID)   ! open dataset
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_REDEF(NCID)                      ! put in define mode
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_ENDDEF, NF__ENDDEF, NF_REDEF, Datasets
+ at section NF_ENDDEF 
+ at findex NF_ENDDEF 
+
+The function NF_ENDDEF takes an open netCDF dataset out of define
+mode. The changes made to the netCDF dataset while it was in define
+mode are checked and committed to disk if no problems
+occurred. Non-record variables may be initialized to a "fill value" as
+well (@pxref{NF_SET_FILL}). The netCDF dataset is then placed in data
+mode, so variable data can be read or written.
+
+This call may involve copying data under some
+circumstances. @xref{File Structure and Performance,,, netcdf, NetCDF
+Users' Guide}.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_ENDDEF(INTEGER NCID)
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ at end table
+
+ at heading Errors 
+
+NF_ENDDEF returns the value NF_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+ at itemize
+
+ at item
+The specified netCDF dataset is not in define mode. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset.
+The size of one or more variables exceed the size constraints for
+whichever variant of the file format is in use).
+ at xref{Large File Support,,, netcdf, @value{n-man}}.
+ at item
+
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_ENDDEF to finish the definitions of a new
+netCDF dataset named foo.nc and put it into data mode:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER NCID, STATUS
+   ... 
+STATUS = NF_CREATE('foo.nc', NF_NOCLOBBER, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+   ...   ! create dimensions, variables, attributes
+
+STATUS = NF_ENDDEF(NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF__ENDDEF, NF_CLOSE, NF_ENDDEF, Datasets
+ at section NF__ENDDEF 
+ at findex NF__ENDDEF 
+
+The function NF__ENDDEF takes an open netCDF dataset out of define
+mode. The changes made to the netCDF dataset while it was in define
+mode are checked and committed to disk if no problems
+occurred. Non-record variables may be initialized to a "fill value" as
+well (@pxref{NF_SET_FILL}). The netCDF dataset is then placed in data
+mode, so variable data can be read or written.
+
+This call may involve copying data under some
+circumstances. @xref{File Structure and Performance,,, netcdf, NetCDF
+Users' Guide}.
+
+This function assumes specific characteristics of the netcdf version
+1 and version 2 file formats. Users should use nf_enddef in most
+circumstances.  Although this function will be available in future netCDF
+implementations, it may not continue to have any effect on performance.
+
+The current netcdf file format has three sections, the "header"
+section, the data section for fixed size variables, and the data
+section for variables which have an unlimited dimension (record
+variables).
+
+The header begins at the beginning of the file. The index (offset) of
+the beginning of the other two sections is contained in the
+header. Typically, there is no space between the sections. This causes
+copying overhead to accrue if one wishes to change the size of the
+sections, as may happen when changing names of things, text attribute
+values, adding attributes or adding variables. Also, for buffered i/o,
+there may be advantages to aligning sections in certain ways.
+
+The minfree parameters allow one to control costs of future calls to
+nf_redef, nf_enddef by requesting that minfree bytes be available at
+the end of the section.
+
+The align parameters allow one to set the alignment of the beginning
+of the corresponding sections. The beginning of the section is rounded
+up to an index which is a multiple of the align parameter. The flag
+value ALIGN_CHUNK tells the library to use the bufrsize (see above)
+as the align parameter.
+
+The file format requires mod 4 alignment, so the align parameters
+are silently rounded up to multiples of 4. The usual call,
+
+ at example
+nf_enddef(ncid);
+ at end example
+
+is equivalent to
+
+ at example
+nf_enddef(ncid, 0, 4, 0, 4);
+ at end example
+
+The file format does not contain a "record size" value, this is
+calculated from the sizes of the record variables. This unfortunate
+fact prevents us from providing minfree and alignment control of the
+"records" in a netcdf file. If you add a variable which has an
+unlimited dimension, the third section will always be copied with the
+new variable added.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_ENDDEF(INTEGER NCID, INTEGER H_MINFREE, INTEGER V_ALIGN,
+               INTEGER V_MINFREE, INTEGER R_ALIGN)
+ at end example
+
+ at table @code
+
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+
+ at item H_MINFREE
+Sets the pad at the end of the "header" section.
+
+ at item V_ALIGN
+Controls the alignment of the beginning of the data section for fixed
+size variables.
+
+ at item V_MINFREE
+Sets the pad at the end of the data section for fixed size variables.
+
+ at item R_ALIGN
+Controls the alignment of the beginning of the data section for
+variables which have an unlimited dimension (record variables).
+
+ at end table
+
+ at heading Errors 
+
+NF__ENDDEF returns the value NF_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+ at itemize
+
+ at item
+The specified netCDF dataset is not in define mode. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset.
+
+ at item
+The size of one or more variables exceed the size constraints for
+whichever variant of the file format is in use).
+ at xref{Large File Support,,, netcdf, @value{n-man}}.
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF__ENDDEF to finish the definitions of a new
+netCDF dataset named foo.nc and put it into data mode:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER NCID, STATUS, H_MINFREE, V_ALIGN, V_MINFREE, R_ALIGN
+   ... 
+STATUS = NF_CREATE('foo.nc', NF_NOCLOBBER, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+   ...   ! create dimensions, variables, attributes
+
+H_MINFREE = 512
+V_ALIGN = 512
+V_MINFREE = 512
+R_ALIGN = 512
+STATUS = NF_ENDDEF(NCID, H_MINFREE, V_ALIGN, V_MINFREE, R_ALIGN)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_CLOSE, NF_INQ Family, NF__ENDDEF, Datasets
+ at section NF_CLOSE 
+ at findex NF_CLOSE 
+
+The function NF_CLOSE closes an open netCDF dataset. If the dataset is
+in define mode, NF_ENDDEF will be called before closing. (In this
+case, if NF_ENDDEF returns an error, NF_ABORT will automatically be
+called to restore the dataset to the consistent state before define
+mode was last entered.) After an open netCDF dataset is closed, its
+netCDF ID may be reassigned to the next netCDF dataset that is opened
+or created.
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION NF_CLOSE(INTEGER NCID)
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ at end table
+
+ at heading Errors 
+
+NF_CLOSE returns the value NF_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+ at itemize
+
+ at item
+Define mode was entered and the automatic call made to NF_ENDDEF
+failed.
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset.
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_CLOSE to finish the definitions of a new
+netCDF dataset named foo.nc and release its netCDF ID:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER NCID, STATUS
+   ... 
+STATUS = NF_CREATE('foo.nc', NF_NOCLOBBER, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+   ...   ! create dimensions, variables, attributes
+
+STATUS = NF_CLOSE(NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_INQ Family, NF_SYNC, NF_CLOSE, Datasets
+ at section NF_INQ Family
+ at findex NF_INQ Family
+ at findex NF_INQ_NDIMS
+ at findex NF_INQ_NVARS
+ at findex NF_INQ_NATTS
+ at findex NF_INQ_UNLIMDIM
+ at findex NF_INQ_FORMAT
+
+Members of the NF_INQ family of functions return information about an
+open netCDF dataset, given its netCDF ID. Dataset inquire functions
+may be called from either define mode or data mode. The first
+function, NF_INQ, returns values for the number of dimensions, the
+number of variables, the number of global attributes, and the
+dimension ID of the dimension defined with unlimited length, if
+any. The other functions in the family each return just one of these
+items of information.
+
+For FORTRAN, these functions include NF_INQ, NF_INQ_NDIMS,
+NF_INQ_NVARS, NF_INQ_NATTS, and NF_INQ_UNLIMDIM.  An additional function,
+NF_INQ_FORMAT, returns the (rarely needed) format version.
+
+No I/O is performed when these functions are called, since the
+required information is available in memory for each open netCDF
+dataset.
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION NF_INQ          (INTEGER NCID, INTEGER ndims,
+                                  INTEGER nvars,INTEGER ngatts,
+                                  INTEGER unlimdimid)
+INTEGER FUNCTION NF_INQ_NDIMS    (INTEGER NCID, INTEGER ndims)
+INTEGER FUNCTION NF_INQ_NVARS    (INTEGER NCID, INTEGER nvars)
+INTEGER FUNCTION NF_INQ_NATTS    (INTEGER NCID, INTEGER ngatts)
+INTEGER FUNCTION NF_INQ_UNLIMDIM (INTEGER NCID, INTEGER unlimdimid)
+INTEGER FUNCTION NF_INQ_FORMAT   (INTEGER NCID, INTEGER format)
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item ndims
+Returned number of dimensions defined for this netCDF dataset.
+ 
+ at item nvars
+Returned number of variables defined for this netCDF dataset.
+ 
+ at item ngatts
+Returned number of global attributes defined for this netCDF dataset.
+ 
+ at item unlimdimid
+Returned ID of the unlimited dimension, if there is one for this
+netCDF dataset. If no unlimited length dimension has been defined, -1
+is returned.
+
+ at item format
+Returned format version, one of 
+NF_FORMAT_CLASSIC, NF_FORMAT_64BIT, NF_FORMAT_NETCDF4,
+NF_FORMAT_NETCDF4_CLASSIC.
+ at end table
+
+ at heading Errors 
+
+All members of the NF_INQ family return the value NF_NOERR if no
+errors occurred. Otherwise, the returned status indicates an
+error. Possible causes of errors include:
+ at itemize
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_INQ to find out about a netCDF dataset
+named foo.nc:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS, NCID, NDIMS, NVARS, NGATTS, UNLIMDIMID
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ(NCID, NDIMS, NVARS, NGATTS, UNLIMDIMID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_SYNC, NF_ABORT, NF_INQ Family, Datasets
+ at section NF_SYNC 
+ at findex NF_SYNC 
+
+The function NF_SYNC offers a way to synchronize the disk copy of a
+netCDF dataset with in-memory buffers. There are two reasons you might
+want to synchronize after writes:
+ at itemize
+
+ at item
+To minimize data loss in case of abnormal termination, or 
+
+ at item
+To make data available to other processes for reading immediately
+after it is written. But note that a process that already had the
+dataset open for reading would not see the number of records increase
+when the writing process calls NF_SYNC; to accomplish this, the
+reading process must call NF_SYNC.
+ at end itemize
+
+This function is backward-compatible with previous versions of the
+netCDF library. The intent was to allow sharing of a netCDF dataset
+among multiple readers and one writer, by having the writer call
+NF_SYNC after writing and the readers call NF_SYNC before each
+read. For a writer, this flushes buffers to disk. For a reader, it
+makes sure that the next read will be from disk rather than from
+previously cached buffers, so that the reader will see changes made by
+the writing process (e.g., the number of records written) without
+having to close and reopen the dataset. If you are only accessing a
+small amount of data, it can be expensive in computer resources to
+always synchronize to disk after every write, since you are giving up
+the benefits of buffering.
+
+An easier way to accomplish sharing (and what is now recommended) is
+to have the writer and readers open the dataset with the NF_SHARE
+flag, and then it will not be necessary to call NF_SYNC at
+all. However, the NF_SYNC function still provides finer granularity
+than the NF_SHARE flag, if only a few netCDF accesses need to be
+synchronized among processes.
+
+It is important to note that changes to the ancillary data, such as
+attribute values, are not propagated automatically by use of the
+NF_SHARE flag. Use of the NF_SYNC function is still required for this
+purpose.
+
+Sharing datasets when the writer enters define mode to change the data
+schema requires extra care. In previous releases, after the writer
+left define mode, the readers were left looking at an old copy of the
+dataset, since the changes were made to a new copy. The only way
+readers could see the changes was by closing and reopening the
+dataset. Now the changes are made in place, but readers have no
+knowledge that their internal tables are now inconsistent with the new
+dataset schema. If netCDF datasets are shared across redefinition,
+some mechanism external to the netCDF library must be provided that
+prevents access by readers during redefinition and causes the readers
+to call NF_SYNC before any subsequent access.
+
+When calling NF_SYNC, the netCDF dataset must be in data mode. A
+netCDF dataset in define mode is synchronized to disk only when
+NF_ENDDEF is called. A process that is reading a netCDF dataset that
+another process is writing may call NF_SYNC to get updated with the
+changes made to the data by the writing process (e.g., the number of
+records written), without having to close and reopen the dataset.
+
+Data is automatically synchronized to disk when a netCDF dataset is
+closed, or whenever you leave define mode.
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION NF_SYNC(INTEGER NCID)
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ at end table
+
+ at heading Errors 
+
+NF_SYNC returns the value NF_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+ at itemize
+
+ at item
+The netCDF dataset is in define mode. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_SYNC to synchronize the disk writes of a
+netCDF dataset named foo.nc:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS, NCID
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+! write data or change attributes
+   ... 
+STATUS = NF_SYNC(NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_ABORT, NF_SET_FILL, NF_SYNC, Datasets
+ at section NF_ABORT 
+ at findex NF_ABORT 
+
+You no longer need to call this function, since it is called
+automatically by NF_CLOSE in case the dataset is in define mode and
+something goes wrong with committing the changes. The function
+NF_ABORT just closes the netCDF dataset, if not in define mode. If the
+dataset is being created and is still in define mode, the dataset is
+deleted. If define mode was entered by a call to NF_REDEF, the netCDF
+dataset is restored to its state before definition mode was entered
+and the dataset is closed.
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION NF_ABORT(INTEGER NCID)
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ at end table
+
+ at heading Errors 
+
+NF_ABORT returns the value NF_NOERR if no errors occurred. Otherwise,
+the returned status indicates an error. Possible causes of errors
+include:
+ at itemize
+
+ at item
+When called from define mode while creating a netCDF dataset, deletion
+of the dataset failed.
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_ABORT to back out of redefinitions of a
+dataset named foo.nc:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS, NCID, LATID
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_REDEF(NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_DEF_DIM(NCID, 'LAT', 18, LATID)
+IF (STATUS .NE. NF_NOERR) THEN  ! dimension definition failed
+   CALL HANDLE_ERR(STATUS)
+   STATUS = NF_ABORT(NCID)  ! abort redefinitions
+   IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ENDIF
+...
+ at end example
+
+ at node NF_SET_FILL, NF_SET_DEFAULT_FORMAT, NF_ABORT, Datasets
+ at section NF_SET_FILL 
+ at findex NF_SET_FILL 
+
+This function is intended for advanced usage, to optimize writes under
+some circumstances described below. The function NF_SET_FILL sets the
+fill mode for a netCDF dataset open for writing and returns the
+current fill mode in a return parameter. The fill mode can be
+specified as either NF_FILL or NF_NOFILL. The default behavior
+corresponding to NF_FILL is that data is pre-filled with fill values,
+that is fill values are written when you create non-record variables
+or when you write a value beyond data that has not yet been
+written. This makes it possible to detect attempts to read data before
+it was written. @xref{Fill Values}, for more information on the use of
+fill values. @xref{Attribute Conventions,,,netcdf, @value{n-man}}, for
+information about how to define your own fill values.
+
+The behavior corresponding to NF_NOFILL overrides the default behavior
+of prefilling data with fill values. This can be used to enhance
+performance, because it avoids the duplicate writes that occur when
+the netCDF library writes fill values that are later overwritten with
+data.
+
+A value indicating which mode the netCDF dataset was already in is
+returned. You can use this value to temporarily change the fill mode
+of an open netCDF dataset and then restore it to the previous mode.
+
+After you turn on NF_NOFILL mode for an open netCDF dataset, you must
+be certain to write valid data in all the positions that will later be
+read. Note that nofill mode is only a transient property of a netCDF
+dataset open for writing: if you close and reopen the dataset, it will
+revert to the default behavior. You can also revert to the default
+behavior by calling NF_SET_FILL again to explicitly set the fill mode
+to NF_FILL.
+
+There are three situations where it is advantageous to set nofill
+mode:
+ at enumerate
+ at item
+Creating and initializing a netCDF dataset. In this case, you should
+set nofill mode before calling NF_ENDDEF and then write completely all
+non-record variables and the initial records of all the record
+variables you want to initialize.
+ at item
+Extending an existing record-oriented netCDF dataset. Set nofill mode
+after opening the dataset for writing, then append the additional
+records to the dataset completely, leaving no intervening unwritten
+records.
+ at item
+Adding new variables that you are going to initialize to an existing
+netCDF dataset. Set nofill mode before calling NF_ENDDEF then write
+all the new variables completely.
+ at end enumerate
+
+If the netCDF dataset has an unlimited dimension and the last record
+was written while in nofill mode, then the dataset may be shorter than
+if nofill mode was not set, but this will be completely transparent if
+you access the data only through the netCDF interfaces.
+
+The use of this feature may not be available (or even needed) in
+future releases. Programmers are cautioned against heavy reliance upon
+this feature.
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION NF_SET_FILL(INTEGER NCID, INTEGER FILLMODE,
+                             INTEGER old_mode)
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item FILLMODE
+Desired fill mode for the dataset, either NF_NOFILL or NF_FILL.
+ 
+ at item old_mode
+Returned current fill mode of the dataset before this call, either
+NF_NOFILL or NF_FILL.
+ at end table
+
+ at heading Errors 
+
+NF_SET_FILL returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+ at itemize
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+
+ at item
+The specified netCDF ID refers to a dataset open for read-only access. 
+
+ at item
+The fill mode argument is neither NF_NOFILL nor NF_FILL.. 
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_SET_FILL to set nofill mode for subsequent
+writes of a netCDF dataset named foo.nc:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER NCID, STATUS, OMODE
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+! write data with default prefilling behavior
+   ... 
+STATUS = NF_SET_FILL(NCID, NF_NOFILL, OMODE)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+! write data with no prefilling
+   ... 
+ at end example
+
+ at node NF_SET_DEFAULT_FORMAT, NF_SET_CHUNK_CACHE, NF_SET_FILL, Datasets
+ at section NF_SET_DEFAULT_FORMAT 
+ at findex NF_SET_DEFAULT_FORMAT 
+
+This function is intended for advanced users. 
+
+In version 3.6, netCDF introduced a new data format, the first change
+in the underlying binary data format since the netCDF interface was
+released. The new format, 64-bit offset format, was introduced to
+greatly relax the limitations on creating very large files.
+
+In version 4.0, another new binary format was introduced:
+netCDF-4/HDF5.
+
+Users are warned that creating files in the 64-bit offset format makes
+them unreadable by the netCDF library prior to version 3.6.0, and
+creating files in netcdf-4/HDF5 format makes them unreadable by the
+netCDF library prior to version 4.0. For reasons of compatibility,
+users should continue to create files in netCDF classic format.
+
+Users who do want to use 64-bit offset or netCDF-4/HDF5 format files
+can create them directory from NF_CREATE, using the proper cmode flag.
+(@pxref{NF_CREATE}).
+
+The function NF_SET_DEFAULT_FORMAT allows the user to change the
+format of the netCDF file to be created by future calls to NF_CREATE
+without changing the cmode flag.
+
+This allows the user to convert a program to use the new formats
+without changing all calls the NF_CREATE.
+
+Once the default format is set, all future created files will be in
+the desired format.
+
+Constants are provided in the netcdf.inc file to be used with this
+function: nf_format_classic, nf_format_64bit, nf_format_netcdf4 and
+nf_format_netcdf4_classic.
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION NF_SET_DEFAULT_FORMAT(INTEGER FORMAT, INTEGER OLD_FORMT)
+ at end example
+
+ at table @code
+ 
+ at item FORMAT
+Either nf_format_classic, nf_format_64bit, nf_format_netcdf4 or
+nf_format_netcdf4_classic.
+ 
+ at item OLD_FORMAT
+The default format at the time the function is called is returned
+here.
+
+ at end table
+
+ at heading Errors
+
+The following error codes may be returned by this function:
+
+ at itemize
+
+ at item
+An NF_EINVAL error is returned if an invalid default format is
+specified.
+
+ at end itemize
+
+ at heading Example 
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS, OLD_FORMAT
+   ... 
+STATUS = NF_SET_DEFAULT_FORMAT(nf_format_64bit, OLD_FORMAT)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+ at end example
+
+ at node NF_SET_CHUNK_CACHE, NF_GET_CHUNK_CACHE, NF_SET_DEFAULT_FORMAT, Datasets
+ at section Set HDF5 Chunk Cache for Future File Opens/Creates: NF_SET_CHUNK_CACHE
+ at findex nc_set_chunk_cache
+ at cindex HDF5 chunk cache
+
+This function changes the chunk cache settings in the HDF5
+library. The settings apply for subsequent file opens/creates. This
+function does not change the chunk cache settings of already open
+files.
+
+This affects the per-file chunk cache which the HDF5 layer
+maintains. The chunk cache size can be tuned for better performance.
+
+For more information, see the documentation for the H5Pset_cache()
+function in the HDF5 library at the HDF5 website:
+ at uref{@value{hdf5-url}}.
+
+ at heading Usage 
+
+ at example
+INTEGER NF_SET_CHUNK_CACHE(INTEGER SIZE, INTEGER NELEMS, INTEGER PREEMPTION);
+ at end example
+
+ at table @code
+
+ at item SIZE
+The total size of the raw data chunk cache in MegaBytes.
+
+ at item NELEMS
+The number slots in the per-variable chunk cache (should be a prime number
+larger than the number of chunks in the cache).
+
+ at item PREEMPTION
+The preemtion value must be between 0 and 100 inclusive and indicates
+how much chunks that have been fully read are favored for
+preemption. A value of zero means fully read chunks are treated no
+differently than other chunks (the preemption is strictly LRU) while a
+value of 100 means fully read chunks are always preempted before other
+chunks. 
+
+ at end table
+
+ at heading Return Codes
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EINVAL
+Parameters size and nelems must be non-zero positive integers, and
+preemption must be between zero and 100 (inclusive). An NF_EINVAL will
+be returned otherwise.
+
+ at end table
+
+ at node NF_GET_CHUNK_CACHE,  , NF_SET_CHUNK_CACHE, Datasets
+ at section Get the HDF5 Chunk Cache Settings for Future File Opens/Creates: NF_GET_CHUNK_CACHE
+ at findex nc_get_chunk_cache
+ at cindex HDF5 chunk cache
+
+This function gets the chunk cache settings for the HDF5
+library. The settings apply for subsequent file opens/creates. 
+
+This affects the per-file chunk cache which the HDF5 layer
+maintains. The chunk cache size can be tuned for better performance.
+
+For more information, see the documentation for the H5Pget_cache()
+function in the HDF5 library at the HDF5 website:
+ at uref{@value{hdf5-url}}.
+
+ at heading Usage 
+
+ at example
+INTEGER NC_GET_CHUNK_CACHE(INTEGER SIZE, INTEGER NELEMS, INTEGER PREEMPTION);
+ at end example
+
+ at table @code
+
+ at item SIZE
+The total size of the raw data chunk cache will be put here. 
+
+ at item NELEMS
+The number of chunk slots in the raw data chunk cache hash table will
+be put here.  
+
+
+ at item PREEMPTION
+The preemption will be put here.  The preemtion value is between 0 and
+100 inclusive and indicates how much chunks that have been fully read
+are favored for preemption.  A value of zero means fully read chunks
+are treated no differently than other chunks (the preemption is
+strictly LRU) while a value of 100 means fully read chunks are always
+preempted before other chunks. 
+
+ at end table
+
+ at heading Return Codes
+
+ at table @code
+
+ at item NC_NOERR
+No error.
+
+ at end table
+
+ at node Groups, Dimensions, Datasets, Top
+ at chapter Groups
+ at cindex groups, overview
+
+NetCDF-4 added support for hierarchical groups within netCDF
+datasets. 
+
+Groups are identified with a ncid, which identifies both the open
+file, and the group within that file. When a file is opened with
+NF_OPEN or NF_CREATE, the ncid for the root group of that file is
+provided. Using that as a starting point, users can add new groups, or
+list and navigate existing groups.
+
+All netCDF calls take a ncid which determines where the call will
+take its action. For example, the NF_DEF_VAR function takes a ncid as
+its first parameter. It will create a variable in whichever group
+its ncid refers to. Use the root ncid provided by NF_CREATE or
+NF_OPEN to create a variable in the root group. Or use NF_DEF_GRP to
+create a group and use its ncid to define a variable in the new
+group.
+
+Variable are only visible in the group in which they are defined. The
+same applies to attributes. ``Global'' attributes are defined in
+whichever group is refered to by the ncid. 
+
+Dimensions are visible in their groups, and all child groups.
+
+Group operations are only permitted on netCDF-4 files - that is, files
+created with the HDF5 flag in nf_create. (@pxref{NF_CREATE}). Groups
+are not compatible with the netCDF classic data model, so files
+created with the NF_CLASSIC_MODEL file cannot contain groups (except
+the root group).
+
+ at menu
+* NF_INQ_NCID::                 
+* NF_INQ_GRPS::                 
+* NF_INQ_VARIDS::               
+* NF_INQ_DIMIDS::               
+* NF_INQ_GRPNAME_LEN::          
+* NF_INQ_GRPNAME::              
+* NF_INQ_GRPNAME_FULL::         
+* NF_INQ_GRP_PARENT::           
+* NF_INQ_GRP_NCID::             
+* NF_INQ_GRP_FULL_NCID::        
+* NF_DEF_GRP::                  
+ at end menu
+
+ at node NF_INQ_NCID, NF_INQ_GRPS, Groups, Groups
+ at section Find a Group ID: NF_INQ_NCID
+ at findex NF_INQ_NCID
+
+Given an ncid and group name (NULL or "" gets root group), return
+ncid of the named group.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INQ_NCID(INTEGER NCID, CHARACTER*(*) NAME, INTEGER GRPID)
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id for this operation.
+
+ at item NAME
+A character array that holds the name of the desired group. Must be
+less then NF_MAX_NAME.
+
+ at item GRPID
+The ID of the group will go here.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADID
+Bad group id. 
+
+ at item NF_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag HDF5. (@pxref{NF_OPEN}).
+
+ at item NF_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF_OPEN}).
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+This example is from nf_test/ftst_groups.F.
+
+ at example
+C     Check getting the group by name
+      retval = nf_inq_ncid(ncid, group_name, grpid_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+ at end example
+
+ at node NF_INQ_GRPS, NF_INQ_VARIDS, NF_INQ_NCID, Groups
+ at section Get a List of Groups in a Group: NF_INQ_GRPS
+ at findex NF_INQ_GRPS
+
+Given a location id, return the number of groups it contains, and an
+array of their ncids.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INQ_GRPS(INTEGER NCID, INTEGER NUMGRPS, INTEGER NCIDS)
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id for this operation.
+
+ at item NUMGRPS
+An integer which will get number of groups in this group. 
+
+ at item NCIDS
+An array of ints which will receive the IDs of all the groups in this
+group.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADID
+Bad group id. 
+
+ at item NF_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag HDF5. (@pxref{NF_OPEN}).
+
+ at item NF_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF_OPEN}).
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+This example is from nf_test/ftst_groups.F.
+
+ at example
+C     What groups are there from the root group?
+      retval = nf_inq_grps(ncid, ngroups_in, grpids)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at node NF_INQ_VARIDS, NF_INQ_DIMIDS, NF_INQ_GRPS, Groups
+ at section Find all the Variables in a Group: NF_INQ_VARIDS
+ at findex NF_INQ_VARIDS
+
+Find all varids for a location.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INQ_VARIDS(INTEGER NCID, INTEGERS VARIDS)
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id for this operation.
+
+ at item VARIDS
+An already allocated array to store the list of varids. Use
+nf_inq_nvars to find out how many variables there are. (@pxref{NF_INQ
+Family}).
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADID
+Bad group id. 
+
+ at item NF_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag HDF5. (@pxref{NF_OPEN}).
+
+ at item NF_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF_OPEN}).
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+This example is from nf_test/ftst_groups.F.
+
+ at example
+C     Check varids in subgroup.
+      retval = nf_inq_varids(subgrp_in, nvars, varids_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at node NF_INQ_DIMIDS, NF_INQ_GRPNAME_LEN, NF_INQ_VARIDS, Groups
+ at section Find all Dimensions Visible in a Group: NF_INQ_DIMIDS
+ at findex NF_INQ_DIMIDS
+
+Find all dimids for a location. This finds all dimensions in a group,
+or any of its parents.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INQ_DIMIDS(INTEGER NCID, INTEGER NDIMS, INTEGER DIMIDS, INTEGER INCLUDE_PARENTS)
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id for this operation.
+
+ at item NDIMS
+Returned number of dimensions for this location.  If INCLUDE_PARENTS
+is non-zero, number of dimensions visible from this group, which
+includes dimensions in parent groups.
+
+ at item DIMIDS
+An array of ints when the dimids of the visible dimensions will be
+stashed. Use nf_inq_ndims to find out how many dims are visible from
+this group. (@pxref{NF_INQ Family}).
+
+ at item INCLUDE_PARENTS
+If zero, only the group specified by NCID will be searched for
+dimensions. Otherwise parent groups will be searched too.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADID
+Bad group id. 
+
+ at item NF_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag HDF5. (@pxref{NF_OPEN}).
+
+ at item NF_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF_OPEN}).
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+This example is from nf_test/ftst_groups.F.
+
+ at example
+C     Check dimids in subgroup.
+      retval = nf_inq_dimids(subgrp_in, ndims, dimids_in, 0)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (ndims .ne. 2 .or. dimids_in(1) .ne. dimids(1) .or.
+     &     dimids_in(2) .ne. dimids(2)) stop 2
+
+ at end example
+
+ at node NF_INQ_GRPNAME_LEN, NF_INQ_GRPNAME, NF_INQ_DIMIDS, Groups
+ at section Find the Length of a Group's Name: NF_INQ_GRPNAME_LEN
+ at findex NF_INQ_GRPNAME_LEN
+
+Given ncid, find length of the full name. (Root group is named "/",
+with length 1.)
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INQ_GRPNAME_LEN(INTEGER NCID, INTEGER LEN)
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id for this operation.
+
+ at item LEN
+An integer where the length will be placed.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADID
+Bad group id. 
+
+ at item NF_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag HDF5. (@pxref{NF_OPEN}).
+
+ at item NF_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF_OPEN}).
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+This example is from nf_test/ftst_groups.F.
+
+ at example
+C     Check the length of the full name.
+      retval = nf_inq_grpname_len(grpids(1), full_name_len)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at node NF_INQ_GRPNAME, NF_INQ_GRPNAME_FULL, NF_INQ_GRPNAME_LEN, Groups
+ at section Find a Group's Name: NF_INQ_GRPNAME
+ at findex NF_INQ_GRPNAME
+
+Given ncid, find relative name of group. (Root group is named "/").
+
+The name provided by this function is relative to the parent
+group. For a full path name for the group is, with all parent groups
+included, separated with a forward slash (as in Unix directory names) @xref{NF_INQ_GRPNAME_FULL}.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INQ_GRPNAME(INTEGER NCID, CHARACTER*(*) NAME)
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id for this operation.
+
+ at item NAME
+The name of the
+group will be copied to this character array. The name will be less
+than NF_MAX_NAME in length.
+ at item
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADID
+Bad group id. 
+
+ at item NF_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag HDF5. (@pxref{NF_OPEN}).
+
+ at item NF_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF_OPEN}).
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+This example is from nf_test/ftst_groups.F.
+
+ at example
+C     Check the name of the root group.
+      retval = nf_inq_grpname(ncid, name_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:1) .ne. '/') stop 2
+ at end example
+
+ at node NF_INQ_GRPNAME_FULL, NF_INQ_GRP_PARENT, NF_INQ_GRPNAME, Groups
+ at section Find a Group's Full Name: NF_INQ_GRPNAME_FULL
+ at findex NF_INQ_GRPNAME_FULL
+
+Given ncid, find complete name of group. (Root group is named "/").
+
+The name provided by this function is a full path name for the group
+is, with all parent groups included, separated with a forward slash
+(as in Unix directory names). For a name relative to the parent group
+ at xref{NF_INQ_GRPNAME}.
+
+To find the length of the full name @xref{NF_INQ_GRPNAME_LEN}.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INQ_GRPNAME_FULL(INTEGER NCID, INTEGER LEN, CHARACTER*(*) NAME)
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id for this operation.
+
+ at item LEN
+The length of the full group name will go here.      
+
+ at item NAME
+The name of the group will be copied to this character array. 
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADID
+Bad group id. 
+
+ at item NF_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag HDF5. (@pxref{NF_OPEN}).
+
+ at item NF_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF_OPEN}).
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+This example is from nf_test/ftst_groups.F.
+
+ at example
+C     Check the full name.
+      retval = nf_inq_grpname_full(grpids(1), full_name_len, name_in2)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at node NF_INQ_GRP_PARENT, NF_INQ_GRP_NCID, NF_INQ_GRPNAME_FULL, Groups
+ at section Find a Group's Parent: NF_INQ_GRP_PARENT
+ at findex NF_INQ_GRP_PARENT
+
+Given ncid, find the ncid of the parent group. 
+
+When used with the root group, this function returns the NF_ENOGRP
+error (since the root group has no parent.)
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INQ_GRP_PARENT(INTEGER NCID, INTEGER PARENT_NCID)
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id.
+
+ at item PARENT_NCID
+The ncid of the parent group will be copied here.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADID
+Bad group id. 
+
+ at item NF_ENOGRP
+No parent group found (i.e. this is the root group).
+
+ at item NF_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag HDF5. (@pxref{NF_OPEN}).
+
+ at item NF_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF_OPEN}).
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+This example is from nf_test/ftst_groups.F.
+
+ at example
+C     Check the parent ncid.
+      retval = nf_inq_grp_parent(grpids(1), grpid_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at node NF_INQ_GRP_NCID, NF_INQ_GRP_FULL_NCID, NF_INQ_GRP_PARENT, Groups
+ at section Find a Group by Name: NF_INQ_GRP_NCID
+ at findex NF_INQ_GRP_PARENT
+
+Given a group name an an ncid, find the ncid of the group id. 
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INQ_GRP_NCID(INTEGER NCID, CHARACTER GRP_NAME, INTEGER GRP_NCID)
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id to look in.
+
+ at item GRP_NAME
+The name of the group that should be found.
+
+ at item GRP_NCID
+This will get the group id, if it is found.
+
+ at end table
+
+ at heading Return Codes
+
+The following return codes may be returned by this function.
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADID
+Bad group id. 
+
+ at item NF_EINVAL
+No name provided or name longer than NF_MAX_NAME.
+
+ at item NF_ENOGRP
+Named group not found.
+
+ at item NF_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag HDF5. (@pxref{NF_OPEN}).
+
+ at item NF_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF_OPEN}).
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+This example is from nf_test/ftst_types3.F.
+
+ at example
+C     Go to a child group and find the id of our type.
+      retval = nf_inq_grp_ncid(ncid, group_name, sub_grpid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at node NF_INQ_GRP_FULL_NCID, NF_DEF_GRP, NF_INQ_GRP_NCID, Groups
+ at section Find a Group by its Fully-qualified Name: NF_INQ_GRP_FULL_NCID
+ at findex NF_INQ_GRP_PARENT
+
+Given a fully qualified group name an an ncid, find the ncid of the
+group id.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INQ_GRP_FULL_NCID(INTEGER NCID, CHARACTER FULL_NAME, INTEGER GRP_NCID)
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id to look in.
+
+ at item FULL_NAME
+The fully-qualified group name.
+
+ at item GRP_NCID
+This will get the group id, if it is found.
+
+ at end table
+
+ at heading Return Codes
+
+The following return codes may be returned by this function.
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADID
+Bad group id. 
+
+ at item NF_EINVAL
+No name provided or name longer than NF_MAX_NAME.
+
+ at item NF_ENOGRP
+Named group not found.
+
+ at item NF_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag HDF5. (@pxref{NF_OPEN}).
+
+ at item NF_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF_OPEN}).
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+This example is from nf_test/ftst_groups.F.
+
+ at example
+C     Check the full name of the root group (also "/").
+      retval = nf_inq_grpname_full(ncid, full_name_len, name_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at node NF_DEF_GRP,  , NF_INQ_GRP_FULL_NCID, Groups
+ at section Create a New Group: NF_DEF_GRP
+ at findex NF_DEF_GRP
+
+Create a group. Its location id is returned in new_ncid. 
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_DEF_GRP(INTEGER PARENT_NCID, CHARACTER*(*) NAME,
+        INTEGER NEW_NCID)
+ at end example
+
+ at table @code
+
+ at item PARENT_NCID
+The group id of the parent group.
+
+ at item NAME
+The name of the new group, which must be different from the name of
+any variable within the same parent group.
+
+ at item NEW_NCID
+The ncid of the new group will be placed there.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADID
+Bad group id. 
+
+ at item NF_ENAMEINUSE
+That name is in use. Group names must be unique within a group.
+
+ at item NF_EMAXNAME
+Name exceed max length NF_MAX_NAME.
+
+ at item NF_EBADNAME
+Name contains illegal characters.
+
+ at item NF_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag HDF5. (@pxref{NF_OPEN}).
+
+ at item NF_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF_OPEN}).
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at item NF_EPERM
+Attempt to write to a read-only file.
+
+ at item NF_ENOTINDEFINE
+Not in define mode.
+
+ at end table
+
+ at heading Example
+
+In this exampe rom nf_test/ftst_groups.F, a groups is reated, and then
+a sub-group is created in that group.
+
+ at example
+C     Create the netCDF file.
+      retval = nf_create(file_name, NF_NETCDF4, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Create a group and a subgroup.
+      retval = nf_def_grp(ncid, group_name, grpid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_def_grp(grpid, sub_group_name, sub_grpid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at node Dimensions, User Defined Data Types, Groups, Top
+ at chapter Dimensions
+
+ at menu
+* Dimensions Introduction::     
+* NF_DEF_DIM::                  
+* NF_INQ_DIMID::                
+* NF_INQ_DIM Family::           Inquire about a Dimension
+* NF_RENAME_DIM::               
+ at end menu
+
+ at node Dimensions Introduction, NF_DEF_DIM, Dimensions, Dimensions
+ at section Dimensions Introduction
+
+Dimensions for a netCDF dataset are defined when it is created, while
+the netCDF dataset is in define mode. Additional dimensions may be
+added later by reentering define mode. A netCDF dimension has a name
+and a length. At most one dimension in a netCDF dataset can have the
+unlimited length, which means variables using this dimension can grow
+along this dimension.
+
+There is a suggested limit (100) to the number of dimensions that can
+be defined in a single netCDF dataset. The limit is the value of the
+predefined macro NF_MAX_DIMS. The purpose of the limit is to make
+writing generic applications simpler. They need only provide an array
+of NF_MAX_DIMS dimensions to handle any netCDF dataset. The
+implementation of the netCDF library does not enforce this advisory
+maximum, so it is possible to use more dimensions, if necessary, but
+netCDF utilities that assume the advisory maximums may not be able to
+handle the resulting netCDF datasets.
+
+Ordinarily, the name and length of a dimension are fixed when the
+dimension is first defined. The name may be changed later, but the
+length of a dimension (other than the unlimited dimension) cannot be
+changed without copying all the data to a new netCDF dataset with a
+redefined dimension length.
+
+A netCDF dimension in an open netCDF dataset is referred to by a small
+integer called a dimension ID. In the FORTRAN interface, dimension IDs
+are 1, 2, 3, ..., in the order in which the dimensions were defined.
+
+Operations supported on dimensions are:
+ at itemize
+
+ at item
+Create a dimension, given its name and length. 
+
+ at item
+Get a dimension ID from its name. 
+
+ at item
+Get a dimension's name and length from its ID. 
+
+ at item
+Rename a dimension. 
+ at end itemize
+
+ at node NF_DEF_DIM, NF_INQ_DIMID, Dimensions Introduction, Dimensions
+ at section NF_DEF_DIM 
+ at findex NF_DEF_DIM
+
+The function NF_DEF_DIM adds a new dimension to an open netCDF dataset
+in define mode. It returns (as an argument) a dimension ID, given the
+netCDF ID, the dimension name, and the dimension length. At most one
+unlimited length dimension, called the record dimension, may be
+defined for each netCDF dataset.
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION NF_DEF_DIM (INTEGER NCID, CHARACTER*(*) NAME,
+                          INTEGER LEN, INTEGER dimid)
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item NAME
+Dimension name.
+ 
+ at item LEN
+Length of dimension; that is, number of values for this dimension as
+an index to variables that use it. This should be either a positive
+integer or the predefined constant NF_UNLIMITED.
+ 
+ at item dimid
+Returned dimension ID.
+ at end table
+
+ at heading Errors 
+
+NF_DEF_DIM returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+ at itemize
+
+ at item
+The netCDF dataset is not in definition mode. 
+
+ at item
+The specified dimension name is the name of another existing
+dimension.
+
+ at item
+The specified length is not greater than zero. 
+
+ at item
+The specified length is unlimited, but there is already an unlimited
+length dimension defined for this netCDF dataset.
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset.
+
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_DEF_DIM to create a dimension named lat of
+length 18 and a unlimited dimension named rec in a new netCDF dataset
+named foo.nc:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS, NCID, LATID, RECID
+   ... 
+STATUS = NF_CREATE('foo.nc', NF_NOCLOBBER, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_DEF_DIM(NCID, 'lat', 18, LATID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_DEF_DIM(NCID, 'rec', NF_UNLIMITED, RECID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_INQ_DIMID, NF_INQ_DIM Family, NF_DEF_DIM, Dimensions
+ at section NF_INQ_DIMID 
+ at findex NF_INQ_DIMID 
+
+The function NF_INQ_DIMID returns (as an argument) the ID of a netCDF
+dimension, given the name of the dimension. If ndims is the number of
+dimensions defined for a netCDF dataset, each dimension has an ID
+between 1 and ndims.
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION NF_INQ_DIMID (INTEGER NCID, CHARACTER*(*) NAME,
+                               INTEGER dimid)
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item NAME
+Dimension name.
+ 
+ at item dimid
+Returned dimension ID.
+ at end table
+ 
+ at heading Errors 
+
+NF_INQ_DIMID returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The name that was specified is not the name of a dimension in the
+netCDF dataset.  
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset.
+
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_INQ_DIMID to determine the dimension ID of
+a dimension named lat, assumed to have been defined previously in an
+existing netCDF dataset named foo.nc:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS, NCID, LATID
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_DIMID(NCID, 'lat', LATID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_INQ_DIM Family, NF_RENAME_DIM, NF_INQ_DIMID, Dimensions
+ at section NF_INQ_DIM Family
+ at findex NF_INQ_DIM Family
+
+This family of functions returns information about a netCDF
+dimension. Information about a dimension includes its name and its
+length. The length for the unlimited dimension, if any, is the number
+of records written so far.
+
+The functions in this family include NF_INQ_DIM, NF_INQ_DIMNAME, and
+NF_INQ_DIMLEN. The function NF_INQ_DIM returns all the information
+about a dimension; the other functions each return just one item of
+information.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INQ_DIM     (INTEGER NCID, INTEGER DIMID,
+                                 CHARACTER*(*) name, INTEGER len)
+INTEGER FUNCTION NF_INQ_DIMNAME (INTEGER NCID, INTEGER DIMID,
+                                 CHARACTER*(*) name)
+INTEGER FUNCTION NF_INQ_DIMLEN  (INTEGER NCID, INTEGER DIMID,
+                                 INTEGER len)
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE. 
+ 
+ at item DIMID
+Dimension ID, from a previous call to NF_INQ_DIMID or NF_DEF_DIM.
+ 
+ at item NAME
+Returned dimension name. The caller must allocate space for the
+returned name. The maximum possible length, in characters, of a
+dimension name is given by the predefined constant NF_MAX_NAME.
+ 
+ at item len
+Returned length of dimension. For the unlimited dimension, this is the
+current maximum value used for writing any variables with this
+dimension, that is the maximum record number.
+ at end table
+
+ at heading Errors 
+
+These functions return the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The dimension ID is invalid for the specified netCDF dataset. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_INQ_DIM to determine the length of a
+dimension named lat, and the name and current maximum length of the
+unlimited dimension for an existing netCDF dataset named foo.nc:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS, NCID, LATID, LATLEN, RECID, NRECS
+CHARACTER*(NF_MAX_NAME) LATNAM, RECNAM
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+! get ID of unlimited dimension
+STATUS = NF_INQ_UNLIMDIM(NCID, RECID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_DIMID(NCID, 'lat', LATID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+! get lat length
+STATUS = NF_INQ_DIMLEN(NCID, LATID, LATLEN)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+! get unlimited dimension name and current length
+STATUS = NF_INQ_DIM(NCID, RECID, RECNAME, NRECS)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_RENAME_DIM,  , NF_INQ_DIM Family, Dimensions
+ at section NF_RENAME_DIM 
+ at findex NF_RENAME_DIM 
+
+The function NF_RENAME_DIM renames an existing dimension in a netCDF
+dataset open for writing. If the new name is longer than the old name,
+the netCDF dataset must be in define mode. You cannot rename a
+dimension to have the same name as another dimension.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_RENAME_DIM (INTEGER NCID, INTEGER DIMID,
+                                CHARACTER*(*) NAME)
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item DIMID
+Dimension ID, from a previous call to NF_INQ_DIMID or NF_DEF_DIM.
+ 
+ at item NAME
+New dimension name.
+
+ at end table
+
+ at heading Errors 
+
+NF_RENAME_DIM returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The new name is the name of another dimension. 
+
+ at item
+The dimension ID is invalid for the specified netCDF dataset. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+
+ at item
+The new name is longer than the old name and the netCDF dataset is not
+in define mode.
+ at end itemize
+
+ at heading Example 
+Here is an example using NF_RENAME_DIM to rename the dimension lat to
+latitude in an existing netCDF dataset named foo.nc:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS, NCID, LATID
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+! put in define mode to rename dimension
+STATUS = NF_REDEF(NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_INQ_DIMID(NCID, 'lat', LATID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_RENAME_DIM(NCID, LATID, 'latitude')
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+! leave define mode
+STATUS = NF_ENDDEF(NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node User Defined Data Types, Variables, Dimensions, Top
+ at chapter User Defined Data Types
+ at cindex variable length array type, overview
+ at cindex user defined types
+
+ at menu
+* User Defined Types::          
+* NF_INQ_TYPEIDS::              
+* NF_INQ_TYPEID::               
+* NF_INQ_TYPE::                 
+* NF_INQ_USER_TYPE::            
+* Compound Types::              
+* Variable Length Array::       
+* Opaque Type::                 
+* Enum Type::                   
+ at end menu
+
+ at node User Defined Types, NF_INQ_TYPEIDS, User Defined Data Types, User Defined Data Types
+ at section User Defined Types Introduction
+ at cindex user defined types, overview
+
+NetCDF-4 has added support for four different user defined data types.
+
+ at table @code
+
+ at item compound type
+Like a C struct, a compound type is a collection of types, including
+other user defined types, in one package.
+
+ at item variable length array type
+The variable length array may be used to store ragged arrays.
+
+ at item opaque type
+This type has only a size per element, and no other type information.
+
+ at item enum type
+Like an enumeration in C, this type lets you assign text values to
+integer values, and store the integer values.
+
+ at end table
+
+Users may construct user defined type with the various NF_DEF_*
+functions described in this section. They may learn about user defined
+types by using the NF_INQ_ functions defined in this section.
+
+Once types are constructed, define variables of the new type with
+NF_DEF_VAR (@pxref{NF_DEF_VAR}). Write to them with NF_PUT_VAR1,
+NF_PUT_VAR, NF_PUT_VARA, or NF_PUT_VARS (@pxref{Variables}). Read data
+of user-defined type with NF_GET_VAR1, NF_GET_VAR, NF_GET_VARA, or
+NF_GET_VARS (@pxref{Variables}).
+
+Create attributes of the new type with NF_PUT_ATT
+(@pxref{NF_PUT_ATT_ type}). Read attributes of the new type with NF_GET_ATT
+(@pxref{NF_GET_ATT_ type}).
+
+ at node NF_INQ_TYPEIDS, NF_INQ_TYPEID, User Defined Types, User Defined Data Types
+ at section Learn the IDs of All Types in Group: NF_INQ_TYPEIDS
+ at findex NF_INQ_TYPEIDS
+
+Learn the number of types defined in a group, and their IDs.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INQ_TYPEIDS(INTEGER NCID, INTEGER NTYPES, 
+        INTEGER TYPEIDS)
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id.
+
+ at item NTYPES
+A pointer to int which will get the number of types defined in the
+group. If NULL, ignored.
+
+ at item TYPEIDS
+A pointer to an int array which will get the typeids. If NULL,
+ignored.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_BADID
+Bad ncid.
+
+ at end table
+
+ at heading Example
+
+The following example is from the test program nf_test/ftst_vars3.F.
+
+ at example
+      retval = nf_inq_typeids(ncid, num_types, typeids)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at node NF_INQ_TYPEID, NF_INQ_TYPE, NF_INQ_TYPEIDS, User Defined Data Types
+ at section Find a Typeid from Group and Name: NF_INQ_TYPEID
+ at findex NF_INQ_TYPEID
+
+Given a group ID and a type name, find the ID of the type. If the type
+is not found in the group, then the parents are searched. If still not
+found, the entire file is searched.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INQ_TYPEID(INTEGER NCID, CHARACTER NAME, NF_TYPE TYPEIDP)
+ at end example
+
+ at table @code
+
+ at item NCID
+The group id.
+
+ at item NAME
+The name of a type.
+
+ at item TYPEIDP
+The typeid of the named type (if found).
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADID
+Bad ncid.
+
+ at item NF_EBADTYPE
+Can't find type.
+
+ at end table
+
+ at heading Example
+
+The following example is from nf_test/ftst_types3.F:
+
+ at example
+C     Go to a child group and find the id of our type.
+      retval = nf_inq_grp_ncid(ncid, group_name, sub_grpid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_inq_typeid(sub_grpid, type_name, typeid_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at node NF_INQ_TYPE, NF_INQ_USER_TYPE, NF_INQ_TYPEID, User Defined Data Types
+ at section Learn About a User Defined Type: NF_INQ_TYPE
+ at findex NF_INQ_TYPE
+
+Given an ncid and a typeid, get the information about a type. This
+function will work on any type, including atomic and any user defined
+type, whether compound, opaque, enumeration, or variable length array.
+
+For even more information about a user defined type @ref{NF_INQ_USER_TYPE}.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INQ_TYPE(INTEGER NCID, INTEGER XTYPE, 
+        CHARACTER*(*) NAME, INTEGER SIZE)
+ at end example
+
+ at table @code
+
+ at item NCID
+The ncid for the group containing the type (ignored for atomic types).
+
+ at item XTYPE
+The typeid for this type, as returned by NF_DEF_COMPOUND,
+NF_DEF_OPAQUE, NF_DEF_ENUM, NF_DEF_VLEN, or NF_INQ_VAR, or as found in
+netcdf.inc in the list of atomic types (NF_CHAR, NF_INT, etc.).
+
+ at item NAME
+The name of the user defined type will be copied here. It will be
+NF_MAX_NAME bytes or less. For atomic types, the type name from CDL
+will be given.
+
+ at item SIZEP
+The (in-memory) size of the type (in bytes) will be copied here. VLEN
+type size is the size of one vlen sturture (i.e. the sice of
+nc_vlen_t). String size is returned as the size of one C character
+pointer.
+
+ at end table
+
+ at heading Return Codes
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADTYPEID
+Bad typeid.
+
+ at item NF_ENOTNC4
+Seeking a user-defined type in a netCDF-3 file.
+
+ at item NF_ESTRICTNC3
+Seeking a user-defined type in a netCDF-4 file for which classic model
+has been turned on.
+
+ at item NF_EBADGRPID
+Bad group ID in ncid.
+
+ at item NF_EBADID
+Type ID not found.
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+This example is from the test program nf_test/ftst_vars3.F, and it uses all the
+possible inquiry functions on an enum type.
+
+ at example
+C     Check the enum type.
+      retval = NF_INQ_TYPEIDS(ncid, num_types, typeids)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (num_types .ne. MAX_TYPES) stop 2
+      retval = nf_inq_enum(ncid, typeids(1), type_name, base_type, 
+     &     base_size, num_members)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (base_type .ne. NF_INT .or. num_members .ne. 2) stop 2
+      retval = nf_inq_enum_member(ncid, typeids(1), 1, member_name, 
+     &     member_value)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (member_name(1:len(one_name)) .ne. one_name) stop 2
+
+ at end example
+
+ at node NF_INQ_USER_TYPE, Compound Types, NF_INQ_TYPE, User Defined Data Types
+ at section Learn About a User Defined Type: NF_INQ_USER_TYPE
+ at findex NF_INQ_USER_TYPE
+
+Given an ncid and a typeid, get the information about a user defined
+type. This function will work on any user defined type, whether
+compound, opaque, enumeration, or variable length array.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INQ_USER_TYPE(INTEGER NCID, INTEGER XTYPE,
+        CHARACTER*(*) NAME, INTEGER SIZE, INTEGER BASE_NF_TYPE, 
+        INTEGER NFIELDS, INTEGER CLASS)
+ at end example
+
+ at table @code
+
+ at item NCID
+The ncid for the group containing the user defined type.
+
+ at item XTYPE
+The typeid for this type, as returned by NF_DEF_COMPOUND,
+NF_DEF_OPAQUE, NF_DEF_ENUM, NF_DEF_VLEN, or NF_INQ_VAR.
+
+ at item NAME
+The name of the user defined type will be copied here. It
+will be NF_MAX_NAME bytes or less.
+
+ at item SIZE
+The (in-memory) size of the user defined type will be copied here.
+
+ at item BASE_NF_TYPE
+The base typeid will be copied here for vlen and enum types.
+
+ at item NFIELDS
+The number of fields will be copied here for enum and compound types.
+
+ at item CLASS
+The class of the user defined type, NF_VLEN, NF_OPAQUE, NF_ENUM, or
+NF_COMPOUND, will be copied here.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADTYPEID
+Bad typeid.
+
+ at item NF_EBADFIELDID
+Bad fieldid.
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+This example is from nf_test/ftst_types2.F.
+
+ at example
+C     Check the type.
+      retval = nf_inq_user_type(ncid, typeids(1), name_in, size_in, 
+     &     base_type_in, nfields_in, class_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at node Compound Types, Variable Length Array, NF_INQ_USER_TYPE, User Defined Data Types
+ at section Compound Types Introduction
+ at cindex compound types, overview
+
+NetCDF-4 added support for compound types, which allow users to
+construct a new type - a combination of other types, like a C struct.
+
+Compound types are not supported in classic or 64-bit offset format
+files. 
+
+To write data in a compound type, first use nf_def_compound to create the
+type, multiple calls to nf_insert_compound to add to the compound type, and
+then write data with the appropriate nf_put_var1, nf_put_vara,
+nf_put_vars, or nf_put_varm call.
+
+To read data written in a compound type, you must know its
+structure. Use the NF_INQ_COMPOUND functions to learn about the compound
+type.
+
+In Fortran a character buffer must be used for the compound data. The
+user must read the data from within that buffer in the same way that
+the C compiler which compiled netCDF would store the structure.
+
+The use of compound types introduces challenges and portability issues
+for Fortran users.
+
+ at menu
+* NF_DEF_COMPOUND::             
+* NF_INSERT_COMPOUND::          
+* NF_INSERT_ARRAY_COMPOUND::    
+* NF_INQ_COMPOUND::             
+* NF_INQ_COMPOUND_FIELD::       
+ at end menu
+
+ at node NF_DEF_COMPOUND, NF_INSERT_COMPOUND, Compound Types, Compound Types
+ at subsection Creating a Compound Type: NF_DEF_COMPOUND
+ at findex NF_DEF_COMPOUND
+
+Create a compound type. Provide an ncid, a name, and a total size (in
+bytes) of one element of the completed compound type.
+
+After calling this function, fill out the type with repeated calls to
+NF_INSERT_COMPOUND (@pxref{NF_INSERT_COMPOUND}). Call
+NF_INSERT_COMPOUND once for each field you wish to insert into the
+compound type.
+
+Note that there does not seem to be a way to read such types into
+structures in Fortran 90 (and there are no structures in Fortran
+77). 
+
+Fortran users may use character buffers to read and write
+compound types.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_DEF_COMPOUND(INTEGER NCID, INTEGER SIZE,
+        CHARACTER*(*) NAME, INTEGER TYPEIDP)
+ at end example
+
+ at table @code
+
+ at item NCID
+The groupid where this compound type will be created.
+
+ at item SIZE
+The size, in bytes, of the compound type. 
+
+ at item NAME
+The name of the new compound type.
+
+ at item TYPEIDP
+The typeid of the new type will be placed here.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADID
+Bad group id. 
+
+ at item NF_ENAMEINUSE
+That name is in use. Compound type names must be unique in the data
+file. 
+
+ at item NF_EMAXNAME
+Name exceeds max length NF_MAX_NAME.
+
+ at item NF_EBADNAME
+Name contains illegal characters.
+
+ at item NF_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag NF_NETCDF4. (@pxref{NF_OPEN}).
+
+ at item NF_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF_OPEN}).
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at item NF_EPERM
+Attempt to write to a read-only file.
+
+ at item NF_ENOTINDEFINE
+Not in define mode.
+
+ at end table
+
+ at heading Example
+
+This example is from nf_test/ftst_types2.F.
+
+ at example
+C     Define a compound type.
+      retval = nf_def_compound(ncid, cmp_size, type_name, 
+     &     cmp_typeid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at node NF_INSERT_COMPOUND, NF_INSERT_ARRAY_COMPOUND, NF_DEF_COMPOUND, Compound Types
+ at subsection Inserting a Field into a Compound Type: NF_INSERT_COMPOUND
+ at findex NF_INSERT_COMPOUND
+
+Insert a named field into a compound type.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNTION NF_INSERT_COMPOUND(INTEGER TYPEID, CHARACTER*(*) NAME, INTEGER OFFSET, 
+        INTEGER FIELD_TYPEID)
+ at end example
+
+ at table @code
+
+ at item TYPEID
+The typeid for this compound type, as returned by NF_DEF_COMPOUND, or
+NF_INQ_VAR.
+
+ at item NAME
+The name of the new field.
+
+ at item OFFSET
+Offset in byte from the beginning of the compound type for this
+field.
+
+ at item FIELD_TYPEID
+The type of the field to be inserted.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADID
+Bad group id. 
+
+ at item NF_ENAMEINUSE
+That name is in use. Field names must be unique within a compound type.
+
+ at item NF_EMAXNAME
+Name exceed max length NF_MAX_NAME.
+
+ at item NF_EBADNAME
+Name contains illegal characters.
+
+ at item NF_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag NF_NETCDF4. (@pxref{NF_OPEN}).
+
+ at item NF_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF_OPEN}).
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at item NF_ENOTINDEFINE
+Not in define mode.
+
+ at end table
+
+ at heading Example
+
+This example is from nf_test/ftst_types.F.
+
+ at example
+C     Define a compound type.
+      retval = nf_def_compound(ncid, WIND_T_SIZE, type_name, 
+     &     wind_typeid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_insert_compound(ncid, wind_typeid, u_name, 0, NF_INT)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_insert_compound(ncid, wind_typeid, v_name, 4, NF_INT)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at node NF_INSERT_ARRAY_COMPOUND, NF_INQ_COMPOUND, NF_INSERT_COMPOUND, Compound Types
+ at subsection Inserting an Array Field into a Compound Type: NF_INSERT_ARRAY_COMPOUND
+ at findex NF_INSERT_ARRAY_COMPOUND
+
+Insert a named array field into a compound type.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INSERT_ARRAY_COMPOUND(INTEGER NCID, INTEGER XTYPE,
+        CHARACTER*(*) NAME, INTEGER OFFSET, INTEGER FIELD_TYPEID,
+        INTEGER NDIMS, INTEGER DIM_SIZES) 
+ at end example
+
+ at table @code
+
+ at item NCID
+The ID of the file that contains the array type and the compound type.
+
+ at item XTYPE
+The typeid for this compound type, as returned by nf_def_compound, or
+nf_inq_var.
+
+ at item NAME
+The name of the new field.
+
+ at item OFFSET
+Offset in byte from the beginning of the compound type for this
+field.
+
+ at item FIELD_TYPEID
+The base type of the array to be inserted.
+
+ at item NDIMS
+The number of dimensions for the array to be inserted.
+
+ at item DIM_SIZES
+An array containing the sizes of each dimension.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADID
+Bad group id. 
+
+ at item NF_ENAMEINUSE
+That name is in use. Field names must be unique within a compound type.
+
+ at item NF_EMAXNAME
+Name exceed max length NF_MAX_NAME.
+
+ at item NF_EBADNAME
+Name contains illegal characters.
+
+ at item NF_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag NF_NETCDF4. (@pxref{NF_OPEN}).
+
+ at item NF_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF_OPEN}).
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at item NF_ENOTINDEFINE
+Not in define mode.
+
+ at item NF_ETYPEDEFINED
+Attempt to change type that has already been committed. The first time
+the file leaves define mode, all defined types are committed, and
+can't be changed. If you wish to add an array to a compound type, you
+must do so before the compound type is committed.
+
+ at end table
+
+ at heading Example
+
+This example is from nf_test/ftst_types2.F.
+
+ at example
+C     Define a compound type.
+      retval = nf_def_compound(ncid, cmp_size, type_name, 
+     &     cmp_typeid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Include an array.
+      dim_sizes(1) = NX
+      dim_sizes(2) = NY
+      retval = nf_insert_array_compound(ncid, cmp_typeid, ary_name, 0, 
+     &     NF_INT, NDIMS, dim_sizes)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at node NF_INQ_COMPOUND, NF_INQ_COMPOUND_FIELD, NF_INSERT_ARRAY_COMPOUND, Compound Types
+ at subsection Learn About a Compound Type: NF_INQ_COMPOUND
+ at findex NF_INQ_COMPOUND
+ at findex NF_INQ_COMPOUND_NAME
+ at findex NF_INQ_COMPOUND_SIZE
+ at findex NF_INQ_COMPOUND_NFIELDS
+
+Get the number of fields, length in bytes, and name of a compound
+type.
+
+In addtion to the NF_INQ_COMPOUND function, three additional functions
+are provided which get only the name, size, and number of fields.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INQ_COMPOUND(INTEGER NCID, INTEGER XTYPE,
+        CHARACTER*(*) NAME, INTEGER SIZEP, INTEGER NFIELDSP)
+
+INTEGER FUNCTION NF_INQ_COMPOUND_NAME(INTEGER NCID, INTEGER XTYPE, 
+        CHARACTER*(*) NAME)
+
+INTEGER FUNCTION NF_INQ_COMPOUND_SIZE(INTEGER NCID, INTEGER XTYPE, 
+        INTEGER SIZEP)
+
+INTEGER FUNCTION NF_INQ_COMPOUND_NFIELDS(INTEGER NCID, INTEGER XTYPE, 
+        INTEGER NFIELDSP)
+ at end example
+
+ at table @code
+
+ at item NCID
+The ID of any group in the file that contains the compound type.
+
+ at item XTYPE
+The typeid for this compound type, as returned by NF_DEF_COMPOUND, or
+NF_INQ_VAR.
+
+ at item NAME
+Character array which will get the name of the compound type. It will
+have a maximum length of NF_MAX_NAME.
+
+ at item SIZEP
+The size of the compound type in bytes will be put here.
+
+ at item NFIELDSP
+The number of fields in the compound type will be placed here.
+
+ at end table
+
+ at heading Return Codes
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADID
+Couldn't find this ncid.
+
+ at item NF_ENOTNC4
+Not a netCDF-4/HDF5 file.
+
+ at item NF_ESTRICTNC3
+A netCDF-4/HDF5 file, but with CLASSIC_MODEL. No user defined types
+are allowed in the classic model.
+
+ at item NF_EBADTYPE
+This type not a compound type.
+
+ at item NF_EBADTYPEID
+Bad type id. 
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+This example is from nf_test/ftst_types.F.
+
+ at example
+C     Check it differently.
+      retval = nf_inq_compound(ncid, typeids(1), name_in, size_in, 
+     &     nfields_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:len(type_name)) .ne. type_name .or. 
+     &     size_in .ne. WIND_T_SIZE .or. nfields_in .ne. 2) stop 2
+
+C     Check it one piece at a time.
+      retval = nf_inq_compound_nfields(ncid, typeids(1), nfields_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (nfields_in .ne. 2) stop 2
+      retval = nf_inq_compound_size(ncid, typeids(1), size_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (size_in .ne. WIND_T_SIZE) stop 2
+      retval = nf_inq_compound_name(ncid, typeids(1), name_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:len(type_name)) .ne. type_name) stop 2
+ at end example
+
+ at node NF_INQ_COMPOUND_FIELD,  , NF_INQ_COMPOUND, Compound Types
+ at subsection Learn About a Field of a Compound Type: NF_INQ_COMPOUND_FIELD
+ at findex NF_INQ_COMPOUND_FIELD
+ at findex NF_INQ_COMPOUND_FIELDNAME
+ at findex NF_INQ_COMPOUND_FIELDINDEX
+ at findex NF_INQ_COMPOUND_FIELDOFFSET
+ at findex NF_INQ_COMPOUND_FIELDTYPE
+ at findex NF_INQ_COMPOUND_FIELDNDIMS
+ at findex NF_INQ_COMPOUND_FIELDDIM_SIZES
+
+Get information about one of the fields of a compound type.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INQ_COMPOUND_FIELD(INTEGER NCID, INTEGER XTYPE,
+        INTEGER FIELDID, CHARACTER*(*) NAME, INTEGER OFFSETP, 
+        INTEGER FIELD_TYPEIDP, INTEGER NDIMSP, INTEGER DIM_SIZESP)
+
+INTEGER FUNCTION NF_INQ_COMPOUND_FIELDNAME(INTEGER TYPEID, 
+        INTEGER FIELDID, CHARACTER*(*) NAME)
+
+INTEGER FUNCTION NF_INQ_COMPOUND_FIELDINDEX(INTEGER TYPEID,    
+        CHARACTER*(*) NAME, INTEGER FIELDIDP)
+
+INTEGER FUNCTION NF_INQ_COMPOUND_FIELDOFFSET(INTEGER TYPEID, 
+        INTEGER FIELDID, INTEGER OFFSETP)
+
+INTEGER FUNCTION NF_INQ_COMPOUND_FIELDTYPE(INTEGER TYPEID, 
+        INTEGER FIELDID, INTEGER FIELD_TYPEIDP)
+
+INTEGER FUNCTION NF_INQ_COMPOUND_FIELDNDIMS(INTEGER NCID, 
+        INTEGER XTYPE, INTEGER FIELDID, INTEGER NDIMSP)
+
+INTEGER FUNCTION NF_INQ_COMPOUND_FIELDDIM_SIZES(INTEGER NCID, 
+        INTEGER XTYPE, INTEGER FIELDID, INTEGER DIM_SIZES)
+ at end example
+
+ at table @code
+
+ at item NCID
+The groupid where this compound type exists.
+
+ at item XTYPE
+The typeid for this compound type, as returned by NF_DEF_COMPOUND, or
+NF_INQ_VAR.
+
+ at item FIELDID
+A one-based index number specifying a field in the compound type.
+
+ at item NAME
+A character array which will get the name of the field. The name will
+be NF_MAX_NAME characters, at most.
+
+ at item OFFSETP
+An integer which will get the offset of the field.
+
+ at item FIELD_TYPEID
+An integer which will get the typeid of the field.
+
+ at item NDIMSP
+An integer which will get the number of dimensions of the field.
+
+ at item DIM_SIZESP
+An integer array which will get the dimension sizes of the field.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADTYPEID
+Bad type id. 
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+This example is from nf_test/fst_types.F.
+
+ at example
+C     Check the first field of the compound type.
+      retval = nf_inq_compound_field(ncid, typeids(1), 1, name_in, 
+     &     offset_in, field_typeid_in, ndims_in, dim_sizes_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:len(u_name)) .ne. u_name .or. offset_in .ne. 0 .or.
+     &     field_typeid_in .ne. NF_INT .or. ndims_in .ne. 0) stop 2
+      retval = nf_inq_compound_fieldname(ncid, typeids(1), 1, name_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:len(u_name)) .ne. u_name) stop 2
+      retval = nf_inq_compound_fieldoffset(ncid, typeids(1), 1, 
+     &     offset_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (offset_in .ne. 0) stop 2
+      retval = nf_inq_compound_fieldtype(ncid, typeids(1), 1, 
+     &     field_typeid_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (field_typeid_in .ne. NF_INT) stop 2
+      retval = nf_inq_compound_fieldndims(ncid, typeids(1), 1, 
+     &     ndims_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (ndims_in .ne. 0) stop 2
+ at end example
+
+ at node Variable Length Array, Opaque Type, Compound Types, User Defined Data Types
+ at section Variable Length Array Introduction
+ at cindex variable length arrays
+ at cindex VLEN
+
+NetCDF-4 added support for a variable length array type. This is not
+supported in classic or 64-bit offset files, or in netCDF-4 files
+which were created with the NF_CLASSIC_MODEL flag.
+
+A variable length array is represented in C as a structure from HDF5,
+the nf_vlen_t structure. It contains a len member, which contains the
+length of that array, and a pointer to the array.
+
+So an array of VLEN in C is an array of nc_vlen_t structures. The only
+way to handle this in Fortran is with a character buffer sized
+correctly for the platform.
+
+The extra access functions NF_GET_VLEN_ELEMENT and NF_PUT_VLEN_ELEMENT
+to get and put one VLEN element. (That is, one array of variable
+length.) When calling the put, the data are not copied from the
+source. When calling the get the data are copied from VLEN allocated
+memory, which must still be freed (see below).
+
+VLEN arrays are handled differently with respect to allocation of
+memory. Generally, when reading data, it is up to the user to malloc
+(and subsequently free) the memory needed to hold the data. It is up to
+the user to ensure that enough memory is allocated.
+
+With VLENs, this is impossible. The user cannot know the size of an
+array of VLEN until after reading the array. Therefore when reading
+VLEN arrays, the netCDF library will allocate the memory for the data within
+each VLEN.
+
+It is up to the user, however, to eventually free this memory. This is
+not just a matter of one call to free, with the pointer to the array
+of VLENs; each VLEN contains a pointer which must be freed.
+
+Compression is permitted but may not be effective for VLEN data,
+because the compression is applied to the nc_vlen_t structures, rather
+than the actual data.
+
+ at menu
+* NF_DEF_VLEN::                 
+* NF_INQ_VLEN::                 
+* NF_FREE_VLEN::                
+* NF_PUT_VLEN_ELEMENT::         
+* NF_GET_VLEN_ELEMENT::         
+ at end menu
+
+ at node NF_DEF_VLEN, NF_INQ_VLEN, Variable Length Array, Variable Length Array
+ at subsection Define a Variable Length Array (VLEN): NF_DEF_VLEN
+ at findex NF_DEF_VLEN
+ at cindex VLEN, defining
+
+Use this function to define a variable length array type. 
+
+ at heading Usage
+
+ at example
+INTEGER FUNCTION NF_DEF_VLEN(INTEGER NCID, CHARACTER*(*) NAME, 
+        INTEGER BASE_TYPEID, INTEGER XTYPEP)
+ at end example
+
+ at table @code
+
+ at item NCID
+The ncid of the file to create the VLEN type in.
+
+ at item NAME 
+A name for the VLEN type.
+
+ at item BASE_TYPEID
+The typeid of the base type of the VLEN. For example, for a VLEN of
+shorts, the base type is NF_SHORT. This can be a user defined type.
+
+ at item XTYPEP
+The typeid of the new VLEN type will be set here.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EMAXNAME
+NF_MAX_NAME exceeded.
+
+ at item NF_ENAMEINUSE
+Name is already in use.
+
+ at item NF_EBADNAME
+Attribute or variable name contains illegal characters.
+
+ at item NF_EBADID
+ncid invalid.
+
+ at item NF_EBADGRPID
+Group ID part of ncid was invalid.
+
+ at item NF_EINVAL
+Size is invalid.
+
+ at item NF_ENOMEM
+Out of memory.
+
+ at end table
+
+ at heading Example
+
+This example is from nf_test/ftst_vars4.F.
+
+ at example
+C     Create the vlen type.
+      retval = nf_def_vlen(ncid, vlen_type_name, nf_int, vlen_typeid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at node NF_INQ_VLEN, NF_FREE_VLEN, NF_DEF_VLEN, Variable Length Array
+ at subsection Learning about a Variable Length Array (VLEN) Type: NF_INQ_VLEN
+ at findex NF_DEF_VLEN
+ at cindex VLEN, defining
+
+Use this type to learn about a vlen.
+
+ at heading Usage
+
+ at example
+INTEGER FUNCTION NF_INQ_VLEN(INTEGER NCID, INTEGER XTYPE,
+        CHARACTER*(*) NAME, INTEGER DATUM_SIZEP, INTEGER  
+        BASE_NF_TYPEP)
+ at end example
+
+ at table @code
+
+ at item NCID
+The ncid of the file that contains the VLEN type.
+
+ at item XTYPE
+The type of the VLEN to inquire about.
+
+ at item NAME
+The name of the VLEN type. The name will be NF_MAX_NAME characters or
+less.
+
+ at item DATUM_SIZEP
+A pointer to a size_t, this will get the size of one element of this
+vlen.
+
+ at item BASE_NF_TYPEP
+An integer that will get the type of the VLEN base type. (In other
+words, what type is this a VLEN of?)
+
+ at end table
+
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADTYPE
+Can't find the typeid.
+
+ at item NF_EBADID
+ncid invalid.
+
+ at item NF_EBADGRPID
+Group ID part of ncid was invalid.
+
+ at end table
+
+ at heading Example
+
+This example is from nf_test/ftst_vars4.F.
+
+ at example
+C     Use nf_inq_vlen and make sure we get the same answers as we did
+C     with nf_inq_user_type.
+      retval = nf_inq_vlen(ncid, typeids(1), type_name, base_size, 
+     &     base_type)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at node NF_FREE_VLEN, NF_PUT_VLEN_ELEMENT, NF_INQ_VLEN, Variable Length Array
+ at subsection Releasing Memory for a Variable Length Array (VLEN) Type: NF_FREE_VLEN
+ at findex NF_FREE_VLEN
+ at cindex VLEN, defining
+
+When a VLEN is read into user memory from the file, the HDF5 library
+performs memory allocations for each of the variable length arrays
+contained within the VLEN structure. This memory must be freed by the
+user to avoid memory leaks.
+
+This violates the normal netCDF expectation that the user is
+responsible for all memory allocation. But, with VLEN arrays, the
+underlying HDF5 library allocates the memory for the user, and the user
+is responsible for deallocating that memory.
+
+ at heading Usage
+
+ at example
+INTEGER FUNCTION NF_FREE_VLEN(CHARACTER VL);
+ at end example
+
+ at table @code
+
+ at item VL
+The variable length array structure which is to be freed.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADTYPE
+Can't find the typeid.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node NF_PUT_VLEN_ELEMENT, NF_GET_VLEN_ELEMENT, NF_FREE_VLEN, Variable Length Array
+ at subsection Set a Variable Length Array with NF_PUT_VLEN_ELEMENT
+ at findex NF_PUT_VLEN_ELEMENT
+
+Use this to set the element of the (potentially) n-dimensional array
+of VLEN. That is, this sets the data in one variable length array.
+
+ at heading Usage
+
+ at example
+INTEGER FUNCTION NF_PUT_VLEN_ELEMENT(INTEGER NCID, INTEGER XTYPE,
+        CHARACTER*(*) VLEN_ELEMENT, INTEGER LEN, DATA)
+ at end example
+
+ at table @code
+
+ at item NCID
+The ncid of the file that contains the VLEN type.
+
+ at item XTYPE
+The type of the VLEN.
+
+ at item VLEN_ELEMENT
+The VLEN element to be set.
+
+ at item LEN
+The number of entries in this array.
+
+ at item DATA
+The data to be stored. Must match the base type of this VLEN.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADTYPE
+Can't find the typeid.
+
+ at item NF_EBADID
+ncid invalid.
+
+ at item NF_EBADGRPID
+Group ID part of ncid was invalid.
+
+ at end table
+
+ at heading Example
+
+This example is from nf_test/ftst_vars4.F.
+
+ at example
+C     Set up the vlen with this helper function, since F77 can't deal
+C     with pointers.
+      retval = nf_put_vlen_element(ncid, vlen_typeid, vlen, 
+     &     vlen_len, data1)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at node NF_GET_VLEN_ELEMENT,  , NF_PUT_VLEN_ELEMENT, Variable Length Array
+ at subsection Set a Variable Length Array with NF_GET_VLEN_ELEMENT
+ at findex NF_GET_VLEN_ELEMENT
+
+Use this to set the element of the (potentially) n-dimensional array
+of VLEN. That is, this sets the data in one variable length array.
+
+ at heading Usage
+
+ at example
+INTEGER FUNCTION NF_GET_VLEN_ELEMENT(INTEGER NCID, INTEGER XTYPE,
+        CHARACTER*(*) VLEN_ELEMENT, INTEGER LEN, DATA)
+ at end example
+
+ at table @code
+
+ at item NCID
+The ncid of the file that contains the VLEN type.
+
+ at item XTYPE
+The type of the VLEN.
+
+ at item VLEN_ELEMENT
+The VLEN element to be set.
+
+ at item LEN
+This will be set to the number of entries in this array.
+
+ at item DATA
+The data will be copied here. Sufficient storage must be available or
+bad things will happen to you.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADTYPE
+Can't find the typeid.
+
+ at item NF_EBADID
+ncid invalid.
+
+ at item NF_EBADGRPID
+Group ID part of ncid was invalid.
+
+ at end table
+
+ at heading Example
+
+This example is from nf_test/ftst_vars4.F.
+
+ at example
+C     Read the vlen attribute.
+      retval = nf_get_att(ncid, NF_GLOBAL, 'att1', vlen_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Get the data from the vlen we just read.
+      retval = nf_get_vlen_element(ncid, vlen_typeid, vlen_in, 
+     &     vlen_len_in, data1_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at node Opaque Type, Enum Type, Variable Length Array, User Defined Data Types
+ at section Opaque Type Introduction
+ at cindex opaque type
+
+NetCDF-4 added support for the opaque type. This is not supported in
+classic or 64-bit offset files.
+
+The opaque type is a type which is a collection of objects of a known
+size. (And each object is the same size). Nothing is known to netCDF
+about the contents of these blobs of data, except their size in bytes,
+and the name of the type.
+
+To use an opaque type, first define it with @ref{NF_DEF_OPAQUE}. If
+encountering an enum type in a new data file, use @ref{NF_INQ_OPAQUE}
+to learn its name and size.
+
+ at menu
+* NF_DEF_OPAQUE::               
+* NF_INQ_OPAQUE::               
+ at end menu
+
+ at node NF_DEF_OPAQUE, NF_INQ_OPAQUE, Opaque Type, Opaque Type
+ at subsection Creating Opaque Types: NF_DEF_OPAQUE
+ at findex NF_DEF_OPAQUE
+
+Create an opaque type. Provide a size and a name.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_DEF_OPAQUE(INTEGER NCID, INTEGER SIZE, 
+        CHARACTER*(*) NAME, INTEGER TYPEIDP)
+ at end example
+
+ at table @code
+
+ at item NCID
+The groupid where the type will be created. The type may be used
+anywhere in the file, no matter what group it is in.
+
+ at item SIZE
+The size of each opaque object.
+
+ at item NAME
+The name for this type. Must be shorter than NF_MAX_NAME.
+
+ at item TYPEIDP
+Pointer where the new typeid for this type is returned. Use this
+typeid when defining variables of this type with @ref{NF_DEF_VAR}.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADTYPEID
+Bad typeid.
+
+ at item NF_EBADFIELDID
+Bad fieldid.
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+This example is from nf_test/ftst_vars3.F.
+
+ at example
+C     Create the opaque type.
+      retval = nf_def_opaque(ncid, opaque_size, opaque_type_name, 
+     &     opaque_typeid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at menu
+* NF_INQ_OPAQUE::               
+ at end menu
+
+ at node NF_INQ_OPAQUE,  , NF_DEF_OPAQUE, Opaque Type
+ at subsection Learn About an Opaque Type: NF_INQ_OPAQUE
+ at findex NF_INQ_OPAQUE
+
+Given a typeid, get the information about an opaque type.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INQ_OPAQUE(INTEGER NCID, INTEGER XTYPE,
+        CHARACTER*(*) NAME, INTEGER SIZEP)
+ at end example
+
+ at table @code
+
+ at item NCID
+The ncid for the group containing the opaque type.
+
+ at item XTYPE
+The typeid for this opaque type, as returned by NF_DEF_COMPOUND, or
+NF_INQ_VAR.
+
+ at item NAME
+The name of the opaque type will be copied here. It will
+be NF_MAX_NAME bytes or less.
+
+ at item SIZEP
+The size of the opaque type will be copied here.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADTYPEID
+Bad typeid.
+
+ at item NF_EBADFIELDID
+Bad fieldid.
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+This example is from nf_test/ftst_vars3.F.
+
+ at example
+C     Use nf_inq_opaque and make sure we get the same answers as we did
+C     with nf_inq_user_type.
+      retval = nf_inq_opaque(ncid, typeids(2), type_name, base_size)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at node Enum Type,  , Opaque Type, User Defined Data Types
+ at section Enum Type Introduction
+ at cindex enum type
+
+NetCDF-4 added support for the enum type. This is not supported in
+classic or 64-bit offset files.
+
+ at menu
+* NF_DEF_ENUM::                 
+* NF_INSERT_ENUM::              
+* NF_INQ_ENUM::                 
+* NF_INQ_ENUM_MEMBER::          
+* NF_INQ_ENUM_IDENT::           
+ at end menu
+
+ at node NF_DEF_ENUM, NF_INSERT_ENUM, Enum Type, Enum Type
+ at subsection Creating a Enum Type: NF_DEF_ENUM
+ at findex NF_DEF_ENUM
+
+Create an enum type. Provide an ncid, a name, and a base integer
+type. 
+
+After calling this function, fill out the type with repeated calls to
+NF_INSERT_ENUM (@pxref{NF_INSERT_ENUM}). Call NF_INSERT_ENUM once for
+each value you wish to make part of the enumeration.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_DEF_ENUM(INTEGER NCID, INTEGER BASE_TYPEID, 
+        CHARACTER*(*) NAME, INTEGER TYPEIDP)
+ at end example
+
+ at table @code
+
+ at item NCID
+The groupid where this compound type will be created.
+
+ at item BASE_TYPEID
+The base integer type for this enum. Must be one of: NF_BYTE,
+NF_UBYTE, NF_SHORT, NF_USHORT, NF_INT, NF_UINT, NF_INT64, NF_UINT64.
+
+ at item NAME
+The name of the new enum type.
+
+ at item TYPEIDP
+The typeid of the new type will be placed here.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADID
+Bad group id. 
+
+ at item NF_ENAMEINUSE
+That name is in use. Compound type names must be unique in the data
+file. 
+
+ at item NF_EMAXNAME
+Name exceeds max length NF_MAX_NAME.
+
+ at item NF_EBADNAME
+Name contains illegal characters.
+
+ at item NF_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag NF_NETCDF4. (@pxref{NF_OPEN}).
+
+ at item NF_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF_OPEN}).
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at item NF_EPERM
+Attempt to write to a read-only file.
+
+ at item NF_ENOTINDEFINE
+Not in define mode.
+
+ at end table
+
+This example is from nf_test/ftst_vars3.F.
+
+ at example
+C     Create the enum type.
+      retval = nf_def_enum(ncid, NF_INT, enum_type_name, enum_typeid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at node NF_INSERT_ENUM, NF_INQ_ENUM, NF_DEF_ENUM, Enum Type
+ at subsection Inserting a Field into a Enum Type: NF_INSERT_ENUM
+ at findex NF_INSERT_ENUM
+
+Insert a named member into a enum type.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INSERT_ENUM(INTEGER NCID, INTEGER XTYPE, 
+        CHARACTER IDENTIFIER, INTEGER VALUE)
+ at end example
+
+ at table @code
+
+ at item NCID
+The ncid of the group which contains the type.
+
+ at item TYPEID
+The typeid for this enum type, as returned by nf_def_enum, or
+nf_inq_var.
+
+ at item IDENTIFIER
+The identifier of the new member.
+
+ at item VALUE
+The value that is to be associated with this member.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADID
+Bad group id. 
+
+ at item NF_ENAMEINUSE
+That name is in use. Field names must be unique within a enum type.
+
+ at item NF_EMAXNAME
+Name exceed max length NF_MAX_NAME.
+
+ at item NF_EBADNAME
+Name contains illegal characters.
+
+ at item NF_ENOTNC4
+Attempting a netCDF-4 operation on a netCDF-3 file. NetCDF-4
+operations can only be performed on files defined with a create mode
+which includes flag NF_NETCDF4. (@pxref{NF_OPEN}).
+
+ at item NF_ESTRICTNC3
+This file was created with the strict netcdf-3 flag, therefore
+netcdf-4 operations are not allowed. (@pxref{NF_OPEN}).
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at item NF_ENOTINDEFINE
+Not in define mode.
+
+ at end table
+
+ at heading Example
+
+This example is from nf_test/ftst_vars3.F.
+
+ at example
+      one = 1
+      zero = 0
+      retval = nf_insert_enum(ncid, enum_typeid, zero_name, zero)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_insert_enum(ncid, enum_typeid, one_name, one)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at node NF_INQ_ENUM, NF_INQ_ENUM_MEMBER, NF_INSERT_ENUM, Enum Type
+ at subsection Learn About a Enum Type: NF_INQ_ENUM
+ at findex NF_INQ_ENUM
+
+Get information about a user-defined enumeration type.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INQ_ENUM(INTEGER NCID, INTEGER XTYPE,
+        CHARACTER*(*) NAME, INTEGER BASE_NF_TYPE, INTEGER BASE_SIZE, 
+        INTEGER NUM_MEMBERS)
+ at end example
+
+ at table @code
+
+ at item NCID
+The group ID of the group which holds the enum type.
+
+ at item XTYPE
+The typeid for this enum type, as returned by NF_DEF_ENUM, or
+NF_INQ_VAR.
+
+ at item NAME
+Character array which will get the name. It will have a maximum length
+of NF_MAX_NAME.
+
+ at item BASE_NF_TYPE
+An integer which will get the base integer type of this enum.
+
+ at item BASE_SIZE
+An integer which will get the size (in bytes) of the base integer type
+of this enum.
+
+ at item NUM_MEMBERS
+An integer which will get the number of members defined for this
+enumeration type.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADTYPEID
+Bad type id. 
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+In this example from nf_test/ftst_vars3.F, an enum type is created and
+then examined:
+
+ at example
+      retval = nf_inq_enum(ncid, typeids(1), type_name, base_type, 
+     &     base_size, num_members)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (base_type .ne. NF_INT .or. num_members .ne. 2) stop 2
+ at end example
+
+ at node NF_INQ_ENUM_MEMBER, NF_INQ_ENUM_IDENT, NF_INQ_ENUM, Enum Type
+ at subsection Learn the Name of a Enum Type: nf_inq_enum_member
+ at findex nf_inq_enum_member
+
+Get information about a member of an enum type.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INQ_ENUM_MEMBER(INTEGER NCID, INTEGER XTYPE, 
+        INTEGER IDX, CHARACTER*(*) NAME, INTEGER VALUE)
+ at end example
+
+ at table @code
+
+ at item NCID
+The groupid where this enum type exists.
+
+ at item XTYPE
+The typeid for this enum type.
+
+ at item IDX
+The one-based index number for the member of interest. 
+
+ at item NAME
+A character array which will get the name of the member. It will have
+a maximum length of NF_MAX_NAME.
+
+ at item VALUE
+An integer that will get the value associated with this member.
+
+ at end table
+
+ at heading Errors
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADTYPEID
+Bad type id. 
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at end table
+
+ at heading Example
+
+This example is from nf_test/ftst_vars3.F:
+
+ at example
+C     Check the members of the enum type.
+      retval = nf_inq_enum_member(ncid, typeids(1), 1, member_name, 
+     &     member_value)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (member_name(1:len(zero_name)) .ne. zero_name .or.
+     &     member_value .ne. 0) stop 2
+      retval = nf_inq_enum_member(ncid, typeids(1), 2, member_name, 
+     &     member_value)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (member_name(1:len(one_name)) .ne. one_name .or.
+     &     member_value .ne. 1) stop 2
+ at end example
+
+ at node NF_INQ_ENUM_IDENT,  , NF_INQ_ENUM_MEMBER, Enum Type
+ at subsection Learn the Name of a Enum Type: NF_INQ_ENUM_IDENT
+ at findex NF_INQ_ENUM_IDENT
+
+Get the name which is associated with an enum member value.
+
+This is similar to NF_INQ_ENUM_MEMBER, but instead of using the index
+of the member, you use the value of the member.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_INQ_ENUM_IDENT(INTEGER NCID, INTEGER XTYPE,
+        INTEGER VALUE, CHARACTER*(*) IDENTIFIER)
+ at end example
+
+ at table @code
+
+ at item NCID
+The groupid where this enum type exists.
+
+ at item XTYPE
+The typeid for this enum type.
+
+ at item VALUE
+The value for which an identifier is sought.
+
+ at item IDENTIFIER
+A character array that will get the identifier. It will have a maximum
+length of NF_MAX_NAME.
+
+ at end table
+
+ at heading Return Code
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EBADTYPEID
+Bad type id, or not an enum type.
+
+ at item NF_EHDFERR
+An error was reported by the HDF5 layer.
+
+ at item NF_EINVAL
+The value was not found in the enum.
+
+ at end table
+
+ at heading Example
+
+In this example from nf_test/ftst_vars3.F, the values for 0 and 1 are
+checked in an enum.
+
+ at example
+      retval = nf_inq_enum_ident(ncid, typeids(1), 0, member_name)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (member_name(1:len(zero_name)) .ne. zero_name) stop 2
+      retval = nf_inq_enum_ident(ncid, typeids(1), 1, member_name)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (member_name(1:len(one_name)) .ne. one_name) stop 2
+ at end example
+
+ at node Variables, Attributes, User Defined Data Types, Top
+ at chapter Variables
+
+ at menu
+* Variables Introduction::      
+* Variable Types::              
+* NF_DEF_VAR::                  Create a Variable
+* NF_DEF_VAR_CHUNKING::         
+* NF_INQ_VAR_CHUNKING::         
+* NF_SET_VAR_CHUNK_CACHE::      
+* NF_GET_VAR_CHUNK_CACHE::      
+* NF_DEF_VAR_FILL::             
+* NF_INQ_VAR_FILL::             
+* NF_DEF_VAR_DEFLATE::          
+* NF_INQ_VAR_DEFLATE::          
+* NF_INQ_VAR_SZIP::             
+* NF_DEF_VAR_FLETCHER32::       
+* NF_INQ_VAR_FLETCHER32::       
+* NF_DEF_VAR_ENDIAN::           
+* NF_INQ_VAR_ENDIAN::           
+* NF_INQ_VARID::                
+* NF_INQ_VAR family::           Get Information about a Variable from Its ID:
+* NF_PUT_VAR1_  type::          
+* NF_PUT_VAR_ type::            
+* NF_PUT_VARA_ type::           
+* NF_PUT_VARS_ type::           
+* NF_PUT_VARM_ type::           
+* NF_GET_VAR1_ type::           
+* NF_GET_VAR_ type::            
+* NF_GET_VARA_ type::           
+* NF_GET_VARS_ type::           
+* NF_GET_VARM_ type::           
+* Reading and Writing Character String Values::  
+* Fill Values::                 What's Written Where there's No Data?
+* NF_RENAME_VAR::               
+* NF_VAR_PAR_ACCESS::           
+ at end menu
+
+ at node Variables Introduction, Variable Types, Variables, Variables
+ at section Variables Introduction
+
+Variables for a netCDF dataset are defined when the dataset is
+created, while the netCDF dataset is in define mode. Other variables
+may be added later by reentering define mode. A netCDF variable has a
+name, a type, and a shape, which are specified when it is defined. A
+variable may also have values, which are established later in data
+mode.
+
+Ordinarily, the name, type, and shape are fixed when the variable is
+first defined. The name may be changed, but the type and shape of a
+variable cannot be changed. However, a variable defined in terms of
+the unlimited dimension can grow without bound in that dimension.
+
+A netCDF variable in an open netCDF dataset is referred to by a small
+integer called a variable ID.
+
+Variable IDs reflect the order in which variables were defined within
+a netCDF dataset. Variable IDs are 1, 2, 3,..., in the order in which
+the variables were defined. A function is available for getting the
+variable ID from the variable name and vice-versa.
+
+Attributes (see @ref{Attributes}) may be associated with a variable to
+specify such properties as units.
+
+Operations supported on variables are:
+ at itemize
+
+ at item
+Create a variable, given its name, data type, and shape. 
+
+ at item
+Get a variable ID from its name. 
+
+ at item
+Get a variable's name, data type, shape, and number of attributes from
+its ID.
+
+ at item
+Put a data value into a variable, given variable ID, indices, and
+value.
+
+ at item
+Put an array of values into a variable, given variable ID, corner
+indices, edge lengths, and a block of values.
+
+ at item
+Put a subsampled or mapped array-section of values into a variable,
+given variable ID, corner indices, edge lengths, stride vector, index
+mapping vector, and a block of values.
+
+ at item
+Get a data value from a variable, given variable ID and indices. 
+
+ at item
+Get an array of values from a variable, given variable ID, corner
+indices, and edge lengths.
+
+ at item
+Get a subsampled or mapped array-section of values from a variable,
+given variable ID, corner indices, edge lengths, stride vector, and
+index mapping vector.
+
+ at item
+Rename a variable. 
+ at end itemize
+
+ at node Variable Types, NF_DEF_VAR, Variables Introduction, Variables
+ at section Language Types Corresponding to netCDF external data types
+
+The following table gives the netCDF external data types and the
+corresponding type constants for defining variables in the FORTRAN
+interface:
+
+ at multitable @columnfractions .25 .60 .15
+ at item Type @tab FORTRAN API Mnemonic @tab Bits
+
+ at item byte
+ at tab NF_BYTE 
+ at tab 8
+ 
+ at item char
+ at tab NF_CHAR 
+ at tab 8
+ 
+ at item short
+ at tab NF_SHORT 
+ at tab 16
+ 
+ at item int
+ at tab NF_INT 
+ at tab 32
+ 
+ at item float
+ at tab NF_FLOAT 
+ at tab 32
+ 
+ at item double
+ at tab NF_DOUBLE 
+ at tab 64
+ at end multitable
+ 
+The first column gives the netCDF external data type, which is the
+same as the CDL data type. The next column gives the corresponding
+FORTRAN parameter for use in netCDF functions (the parameters are
+defined in the netCDF FORTRAN include-file netcdf.inc). The last
+column gives the number of bits used in the external representation of
+values of the corresponding type.
+
+Note that there are no netCDF types corresponding to 64-bit integers
+or to characters wider than 8 bits in the current version of the
+netCDF library.
+
+ at node NF_DEF_VAR, NF_DEF_VAR_CHUNKING, Variable Types, Variables
+ at section Create a Variable: @code{NF_DEF_VAR} 
+ at findex NF_DEF_VAR
+
+The function NF_DEF_VAR adds a new variable to an open netCDF dataset
+in define mode. It returns (as an argument) a variable ID, given the
+netCDF ID, the variable name, the variable type, the number of
+dimensions, and a list of the dimension IDs.
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION NF_DEF_VAR(INTEGER NCID, CHARACTER*(*) NAME,
+                            INTEGER XTYPE, INTEGER NVDIMS,
+                            INTEGER VDIMS(*), INTEGER varid)
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item NAME
+Variable name.
+ 
+ at item XTYPE
+One of the set of predefined netCDF external data types. The type of
+this parameter, NF_TYPE, is defined in the netCDF header file. The
+valid netCDF external data types are NF_BYTE, NF_CHAR, NF_SHORT,
+NF_INT, NF_FLOAT, and NF_DOUBLE. If the file is a NetCDF-4/HDF5 file,
+the additional types NF_UBYTE, NF_USHORT, NF_UINT, NF_INT64,
+NF_UINT64, and NF_STRING may be used, as well as a user defined type
+ID.
+ 
+ at item NVDIMS
+Number of dimensions for the variable. For example, 2 specifies a
+matrix, 1 specifies a vector, and 0 means the variable is a scalar
+with no dimensions. Must not be negative or greater than the
+predefined constant NF_MAX_VAR_DIMS.
+ 
+ at item VDIMS
+Vector of ndims dimension IDs corresponding to the variable
+dimensions. If the ID of the unlimited dimension is included, it must
+be first. This argument is ignored if ndims is 0. For expanded model
+netCDF4/HDF5 files, there may be any number of unlimited dimensions,
+and they may be used in any element of the dimids array.
+ 
+ at item varid
+Returned variable ID.
+
+ at end table
+
+ at heading Errors 
+
+NF_DEF_VAR returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The netCDF dataset is not in define mode. 
+
+ at item
+The specified variable name is the name of another existing variable. 
+
+ at item
+The specified type is not a valid netCDF type. 
+
+ at item
+The specified number of dimensions is negative or more than the
+constant NF_MAX_VAR_DIMS, the maximum number of dimensions permitted
+for a netCDF variable.
+
+ at item
+One or more of the dimension IDs in the list of dimensions is not a
+valid dimension ID for the netCDF dataset.
+
+ at item
+The number of variables would exceed the constant NF_MAX_VARS, the
+maximum number of variables permitted in a netCDF dataset.
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_DEF_VAR to create a variable named rh of
+type double with three dimensions, time, lat, and lon in a new netCDF
+dataset named foo.nc:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER  STATUS, NCID
+INTEGER  LATDIM, LONDIM, TIMDIM  ! dimension IDs
+INTEGER  RHID                    ! variable ID
+INTEGER  RHDIMS(3)               ! variable shape
+   ... 
+STATUS = NF_CREATE ('foo.nc', NF_NOCLOBBER, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+                                 ! define dimensions
+STATUS = NF_DEF_DIM(NCID, 'lat', 5, LATDIM)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_DEF_DIM(NCID, 'lon', 10, LONDIM)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_DEF_DIM(NCID, 'time', NF_UNLIMITED, TIMDIM)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+         ... 
+                                 ! define variable
+RHDIMS(1) = LONDIM
+RHDIMS(2) = LATDIM
+RHDIMS(3) = TIMDIM
+STATUS = NF_DEF_VAR (NCID, 'rh', NF_DOUBLE, 3, RHDIMS, RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_DEF_VAR_CHUNKING, NF_INQ_VAR_CHUNKING, NF_DEF_VAR, Variables
+ at section Define Chunking Parameters for a Variable: @code{NF_DEF_VAR_CHUNKING}
+ at findex NF_DEF_VAR_CHUNKING
+ at cindex chunking
+ at cindex chunksizes
+ at cindex variables, chunking
+ at cindex variables, contiguous
+ at cindex contiguous
+
+The function NF_DEF_VAR_CHUNKING sets the storage parameters for a
+variable in a netCDF-4 file. It can set the chunk sizes to get chunked
+storage, or it can set the contiguous flag to get contiguous storage.
+
+Variables that make use of one or more unlimited dimensions,
+compression, or checksums must use chunking.  Such variables are
+created with default chunk sizes of 1 for each unlimited dimension and
+the dimension length for other dimensions, except that if the
+resulting chunks are too large, the default chunk sizes for non-record
+dimensions are reduced.
+
+The total size of a chunk must be less than 4 GiB. That is, the product
+of all chunksizes and the size of the data (or the size of nc_vlen_t
+for VLEN types) must be less than 4 GiB.
+
+This function may only be called after the variable is defined, but
+before nc_enddef is called.  Once the chunking parameters are set for
+a variable, they cannot be changed.  This function can be used to
+change the default chunking for record, compressed, or checksummed
+variables before nc_enddef is called.
+
+Note that you cannot set chunking for scalar variables. Only non-scalar
+variables can have chunking.
+
+ at heading Usage 
+
+ at example
+NF_DEF_VAR_CHUNKING(INTEGER NCID, INTEGER VARID, INTEGER STORAGE, INTEGER CHUNKSIZES)
+ at end example
+
+ at table @code
+ at item ncid
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item varid
+Variable ID.
+
+ at item storage
+If NF_CONTIGUOUS, then contiguous storage is used for this
+variable. Variables with compression, shuffle filter, checksums, or
+one or more unlimited dimensions cannot use contiguous storage. If
+contiguous storage is turned on, the chunksizes parameter is ignored.
+
+If NF_CHUNKED, then chunked storage is used for this variable.
+Chunk sizes may be specified with the chunksizes parameter.
+Default sizes will be used if chunking is required and this function
+is not called.
+
+By default contiguous storage is used for fix-sized variables when
+conpression, chunking, checksums, or endianness control are not used.
+
+ at item chunksizes
+An array of chunk sizes. The array must have the one chunksize for
+each dimension in the variable. If contiguous storage is used, 
+then the chunksizes parameter is ignored.
+ 
+ at end table
+
+ at heading Errors 
+
+NF_DEF_VAR_CHUNKING returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. 
+
+Possible return codes include:
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_BADID
+Bad ncid.
+
+ at item NF_EINVAL
+Invalid input. This can occur when the user attempts to set contiguous
+storage for a variable with compression or checksums, or one or more
+unlimited dimensions.
+
+ at item NF_ENOTNC4
+Not a netCDF-4 file.
+
+ at item NF_ENOTVAR
+Can't find this variable.
+
+ at item NF_ELATEDEF
+This variable has already been the subject of a NF_ENDDEF call. In
+netCDF-4 files NF_ENDDEF will be called automatically for any data
+read or write. Once enddef has been called, it is impossible to set
+the chunking for a variable.
+
+ at item NF_ENOTINDEFINE
+Not in define mode. This is returned for netCDF classic or 64-bit
+offset files, or for netCDF-4 files, when they were been created with
+NF_STRICT_NC3 flag. (@pxref{NF_CREATE}).
+
+ at item NF_ESTRICTNC3
+Trying to create a var some place other than the root group in a
+netCDF file with NF_STRICT_NC3 turned on.
+
+ at end table
+
+ at heading Example
+
+In this example from nf_test/ftst_vars.F, a file is created, two
+dimensions and a variable are defined, and the chunksizes of the data
+are set to the size of the data (that is, data will be written in one
+chunk).
+
+ at example
+C     Create the netCDF file.
+      retval = nf_create(FILE_NAME, NF_NETCDF4, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define the dimensions.
+      retval = nf_def_dim(ncid, "x", NX, x_dimid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_def_dim(ncid, "y", NY, y_dimid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define the variable. 
+      dimids(1) = y_dimid
+      dimids(2) = x_dimid
+      retval = NF_DEF_VAR(ncid, "data", NF_INT, NDIMS, dimids, varid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Turn on chunking.
+      chunks(1) = NY
+      chunks(2) = NX
+      retval = NF_DEF_VAR_chunking(ncid, varid, NF_CHUNKED, chunks)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+ at end example
+
+ at node NF_INQ_VAR_CHUNKING, NF_SET_VAR_CHUNK_CACHE, NF_DEF_VAR_CHUNKING, Variables
+ at section Learn About Chunking Parameters for a Variable: @code{NF_INQ_VAR_CHUNKING}
+ at findex NF_INQ_VAR_CHUNKING
+
+The function NF_INQ_VAR_CHUNKING returns the chunking settings for a
+variable in a netCDF-4 file. 
+
+ at heading Usage 
+
+ at example
+NF_INQ_VAR_CHUNKING(INTEGER NCID, INTEGER VARID, INTEGER STORAGE, INTEGER CHUNKSIZES);
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID.
+
+ at item STORAGE
+On return, set to NF_CONTIGUOUS if this variable uses contiguous
+storage, NF_CHUNKED if it uses chunked storage.
+
+ at item CHUNKSIZES
+An array of chunk sizes.  The length of CHUNKSIZES must be the same as
+the number of dimensions of the variable.
+
+ at end table
+
+ at heading Errors 
+
+NF_INQ_VAR_CHUNKING returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. 
+
+Possible return codes include:
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_BADID
+Bad ncid.
+
+ at item NF_ENOTNC4
+Not a netCDF-4 file.
+
+ at item NF_ENOTVAR
+Can't find this variable.
+
+ at end table
+
+ at heading Example
+
+In this example from nf_test/ftst_vars.F, a variable with chunked
+storage is checked to ensure that the chunksizes are set to expected
+values.
+
+ at example
+C     Is everything set that is supposed to be?
+      retval = nf_inq_var_chunking(ncid, varid, storage, chunks_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (storage .ne. NF_CHUNKED) stop 2
+      if (chunks(1) .ne. chunks_in(1)) stop 2
+      if (chunks(2) .ne. chunks_in(2)) stop 2
+ at end example
+
+ at node NF_SET_VAR_CHUNK_CACHE, NF_GET_VAR_CHUNK_CACHE, NF_INQ_VAR_CHUNKING, Variables
+ at section Set HDF5 Chunk Cache for a Variable: NF_SET_VAR_CHUNK_CACHE
+ at findex NF_SET_VAR_CHUNK_CACHE
+ at cindex HDF5 chunk cache, per-variable
+
+This function changes the chunk cache settings for a variable. The
+change in cache size happens immediately. This is a property of the
+open file - it does not persist the next time you open the file.
+
+For more information, see the documentation for the H5Pset_cache()
+function in the HDF5 library at the HDF5 website:
+ at uref{@value{hdf5-url}}.
+
+ at heading Usage 
+
+ at example
+NF_SET_VAR_CHUNK_CACHE(INTEGER NCID, INTEGER VARID, INTEGER SIZE, INTEGER NELEMS, 
+		       INTEGER PREEMPTION);
+ at end example
+
+ at table @code
+
+ at item NCID
+NetCDF ID, from a previous call to nc_open or nc_create.
+ 
+ at item VARID
+Variable ID.
+
+ at item SIZE
+The total size of the raw data chunk cache, in megabytes. This should be
+big enough to hold multiple chunks of data. (Note that the C API uses
+bytes, but the Fortran APIs uses megabytes to avoid numbers that can't
+fit in 4-byte integers.)
+
+ at item NELEMS
+The number of chunk slots in the raw data chunk cache hash table. This
+should be a prime number larger than the number of chunks that will be
+in the cache.
+
+ at item PREEMPTION
+The preemption value must be between 0 and 100 inclusive and indicates
+the degreee to which chunks that have been fully read are favored for
+kicking out of the chunk cache, when needed. A value of zero means
+fully read chunks are treated no differently than other chunks (the
+preemption is strictly Least Recently Used) while a value of 100 means
+fully read chunks are always preempted before other chunks. (The C API
+uses a float between 0 and 1 for this value).
+
+ at end table
+
+ at heading Return Codes
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_EINVAL
+Preemption must be between zero and 100 (inclusive). 
+
+ at end table
+
+ at heading Example 
+
+This example is from nf_test/ftst_vars2.F:
+
+ at example
+      include 'netcdf.inc'
+ ...
+C     These will be used to set the per-variable chunk cache.
+      integer CACHE_SIZE, CACHE_NELEMS, CACHE_PREEMPTION
+      parameter (CACHE_SIZE = 8, CACHE_NELEMS = 571)
+      parameter (CACHE_PREEMPTION = 42)
+...
+C        Set variable caches.
+         retval = nf_set_var_chunk_cache(ncid, varid(i), CACHE_SIZE, 
+     &        CACHE_NELEMS, CACHE_PREEMPTION)
+         if (retval .ne. nf_noerr) call handle_err(retval)
+
+ at end example
+
+ at node NF_GET_VAR_CHUNK_CACHE, NF_DEF_VAR_FILL, NF_SET_VAR_CHUNK_CACHE, Variables
+ at section Get the HDF5 Chunk Cache Settings for a variable: NF_GET_VAR_CHUNK_CACHE
+ at findex nf_get_chunk_cache
+ at cindex HDF5 chunk cache
+
+This function gets the current chunk cache settings for a variable in
+a netCDF-4/HDF5 file.
+
+For more information, see the documentation for the H5Pget_cache()
+function in the HDF5 library at the HDF5 website:
+ at uref{@value{hdf5-url}}.
+
+ at heading Usage 
+
+ at example
+INTEGER NF_GET_VAR_CHUNK_CACHE(INTEGER NCID, INTEGER VARID, INTEGER SIZE, INTEGER NELEMS, 
+                               INTEGER PREEMPTION);
+ at end example
+
+ at table @code
+
+ at item ncid
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item varid
+Variable ID.
+
+ at item sizep
+The total size of the raw data chunk cache, in megabytes, will be put
+here.
+
+ at item nelemsp
+The number of chunk slots in the raw data chunk cache hash table will
+be put here. 
+
+ at item preemptionp
+The preemption will be put here.  The preemtion value is between 0 and
+100 inclusive and indicates how much chunks that have been fully read
+are favored for preemption.  A value of zero means fully read chunks
+are treated no differently than other chunks (the preemption is
+strictly LRU) while a value of 100 means fully read chunks are always
+preempted before other chunks.  
+
+ at end table
+
+ at heading Return Codes
+
+ at table @code
+
+ at item NC_NOERR
+No error.
+
+ at end table
+
+ at heading Example 
+
+This example is from nf_test/ftst_vars2.c:
+
+ at example
+      include 'netcdf.inc'
+...
+C     These will be used to set the per-variable chunk cache.
+      integer CACHE_SIZE, CACHE_NELEMS, CACHE_PREEMPTION
+      parameter (CACHE_SIZE = 8, CACHE_NELEMS = 571)
+      parameter (CACHE_PREEMPTION = 42)
+
+C     These will be used to check the setting of the per-variable chunk
+C     cache.
+      integer cache_size_in, cache_nelems_in, cache_preemption_in
+
+...
+         retval = nf_get_var_chunk_cache(ncid, varid(i), cache_size_in, 
+     &        cache_nelems_in, cache_preemption_in)
+         if (retval .ne. nf_noerr) call handle_err(retval)
+         if (cache_size_in .ne. CACHE_SIZE .or. cache_nelems_in .ne. 
+     &        CACHE_NELEMS .or. cache_preemption .ne. CACHE_PREEMPTION)
+     &        stop 8
+
+ at end example
+
+ at node NF_DEF_VAR_FILL, NF_INQ_VAR_FILL, NF_GET_VAR_CHUNK_CACHE, Variables
+ at section Define Fill Parameters for a Variable: @code{nf_def_var_fill}
+ at findex NF_DEF_VAR_FILL
+ at cindex fill
+ at cindex variables, fill
+
+The function NF_DEF_VAR_FILL sets the fill parameters for a
+variable in a netCDF-4 file. 
+
+This function must be called after the variable is defined, but before
+NF_ENDDEF is called.
+
+ at heading Usage 
+
+ at example
+NF_DEF_VAR_FILL(INTEGER NCID, INTEGER VARID, INTEGER NO_FILL, FILL_VALUE);
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID.
+
+ at item NO_FILL
+Set to non-zero value to set no_fill mode on a variable. When this
+mode is on, fill values will not be written for the variable. This is
+helpful in high performance applications. For netCDF-4/HDF5 files
+(whether classic model or not), this may only be changed after the
+variable is defined, but before it is committed to disk (i.e. before
+the first NF_ENDDEF after the NF_DEF_VAR.) For classic and 64-bit
+offset file, the no_fill mode may be turned on and off at any time.
+
+ at item FILL_VALUE
+A value which will be used as the fill value for the variable. Must be
+the same type as the variable. This will be written to a _FillValue
+attribute, created for this purpose. If NULL, this argument will be
+ignored.
+ 
+ at end table
+
+ at heading Return Codes
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_BADID
+Bad ncid.
+
+ at item NF_ENOTNC4
+Not a netCDF-4 file.
+
+ at item NF_ENOTVAR
+Can't find this variable.
+
+ at item NF_ELATEDEF
+This variable has already been the subject of a NF_ENDDEF call. In
+netCDF-4 files NF_ENDDEF will be called automatically for any data
+read or write. Once enddef has been called, it is impossible to set
+the fill for a variable.
+
+ at item NF_ENOTINDEFINE
+Not in define mode. This is returned for netCDF classic or 64-bit
+offset files, or for netCDF-4 files, when they were been created with
+NF_STRICT_NC3 flag. (@pxref{NF_CREATE}).
+
+ at item NF_EPERM
+Attempt to create object in read-only file.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node NF_INQ_VAR_FILL, NF_DEF_VAR_DEFLATE, NF_DEF_VAR_FILL, Variables
+ at section Learn About Fill Parameters for a Variable: @code{NF_INQ_VAR_FILL}
+ at findex NF_INQ_VAR_FILL
+
+The function NF_INQ_VAR_FILL returns the fill settings for a
+variable in a netCDF-4 file. 
+
+ at heading Usage 
+
+ at example
+NF_INQ_VAR_FILL(INTEGER NCID, INTEGER VARID, INTEGER NO_FILL, FILL_VALUE)
+ at end example
+
+ at table @code
+
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID.
+
+ at item NO_FILL
+An integer which will get a 1 if no_fill mode is set for this
+variable, and a zero if it is not set
+
+ at item FILL_VALUE
+This will get the fill value for this variable. This
+parameter will be ignored if it is NULL.
+
+ at end table
+
+ at heading Return Codes
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_BADID
+Bad ncid.
+
+ at item NF_ENOTNC4
+Not a netCDF-4 file.
+
+ at item NF_ENOTVAR
+Can't find this variable.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node NF_DEF_VAR_DEFLATE, NF_INQ_VAR_DEFLATE, NF_INQ_VAR_FILL, Variables
+ at section Define Compression Parameters for a Variable: @code{NF_DEF_VAR_DEFLATE}
+ at findex NF_DEF_VAR_DEFLATE
+ at cindex deflate
+ at cindex variables, setting deflate
+ at cindex compression, setting parameters
+
+The function NF_DEF_VAR_DEFLATE sets the deflate parameters for a
+variable in a netCDF-4 file. 
+
+When using parallel I/O for writing data, deflate cannot be used. This
+is because the compression makes it impossible for the HDF5 library to
+exactly map the data to disk location.
+
+(Deflated data can be read with parallel I/O).
+
+NF_DEF_VAR_DEFLATE must be called after the variable is defined, but before
+NF_ENDDEF is called.
+
+ at heading Usage 
+
+ at example
+NF_DEF_VAR_DEFLATE(INTEGER NCID, INTEGER VARID, INTEGER SHUFFLE, INTEGER DEFLATE, 
+                   INTEGER DEFLATE_LEVEL);
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID.
+
+ at item SHUFFLE
+If non-zero, turn on the shuffle filter.
+
+ at item DEFLATE
+If non-zero, turn on the deflate filter at the level specified by the
+deflate_level parameter.
+
+ at item DEFLATE_LEVEL
+Must be between 0 (no deflate, the default) and 9 (slowest, but
+``best'' deflate). 
+
+If set to zero, no deflation takes place and the def_var_deflate call
+is ignored. This is slightly different from HDF5 handing of 0
+deflate, which turns on the filter but makes only trivial changes to
+the data.
+
+Informal testing at NetCDF World Headquarters suggests that there is
+little to be gained (with the limited set of test data used here), in
+setting the deflate level above 2 or 3.
+ 
+ at end table
+
+ at heading Errors 
+
+NF_DEF_VAR_DEFLATE returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. 
+
+Possible return codes include:
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_BADID
+Bad ncid.
+
+ at item NF_ENOTNC4
+Not a netCDF-4 file.
+
+ at item NF_ENOTVAR
+Can't find this variable.
+
+ at item NF_ELATEDEF
+This variable has already been the subject of a NF_ENDDEF call. In
+netCDF-4 files NF_ENDDEF will be called automatically for any data
+read or write. Once enddef has been called, it is impossible to set
+the deflate for a variable.
+
+ at item NF_ENOTINDEFINE
+Not in define mode. This is returned for netCDF classic or 64-bit
+offset files, or for netCDF-4 files, when they were been created with
+NF_STRICT_NC3 flag. (@pxref{NF_CREATE}).
+
+ at item NF_EPERM
+Attempt to create object in read-only file.
+
+ at item NF_EINVAL
+Invalid deflate_level. The deflate level must be between 0 and 9,
+inclusive.
+
+ at end table
+
+ at heading Example
+
+In this example from nf_test/ftst_vars.F, a file is created with two
+dimensions and one variable. Chunking, deflate, and the fletcher32
+filter are turned on. The deflate level is set to 4 below.
+
+ at example
+C     Create the netCDF file.
+      retval = nf_create(FILE_NAME, NF_NETCDF4, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define the dimensions.
+      retval = nf_def_dim(ncid, "x", NX, x_dimid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_def_dim(ncid, "y", NY, y_dimid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define the variable. 
+      dimids(1) = y_dimid
+      dimids(2) = x_dimid
+      retval = NF_DEF_VAR(ncid, "data", NF_INT, NDIMS, dimids, varid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Turn on chunking.
+      chunks(1) = NY
+      chunks(2) = NX
+      retval = NF_DEF_VAR_CHUNKING(ncid, varid, NF_CHUNKED, chunks)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Turn on deflate compression, fletcher32 checksum.
+      retval = NF_DEF_VAR_deflate(ncid, varid, 0, 1, 4)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = NF_DEF_VAR_FLETCHER32(ncid, varid, NF_FLETCHER32)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+ at end example
+
+ at node NF_INQ_VAR_DEFLATE, NF_INQ_VAR_SZIP, NF_DEF_VAR_DEFLATE, Variables
+ at section Learn About Deflate Parameters for a Variable: @code{NF_INQ_VAR_DEFLATE}
+ at findex NF_INQ_VAR_DEFLATE
+
+The function NF_INQ_VAR_DEFLATE returns the deflate settings for a
+variable in a netCDF-4 file. 
+
+It is not necessary to know the deflate settings to read the
+variable. (Deflate is completely transparent to readers of the data).
+
+ at heading Usage 
+
+ at example
+NF_INQ_VAR_DEFLATE(INTEGER NCID, INTEGER VARID, INTEGER SHUFFLE, 
+                   INTEGER DEFLATE, INTEGER DEFLATE_LEVEL);
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID.
+
+ at item SHUFFLE
+NF_INQ_VAR_DEFLATE will set this to a 1 if the shuffle filter is
+turned on for this variable, and a 0 otherwise.
+
+ at item DEFLATE
+NF_INQ_VAR_DEFLATE will set this to a 1 if the deflate filter is
+turned on for this variable, and a 0 otherwise.
+
+ at item DEFLATE_LEVEL
+NF_INQ_VAR_DEFLATE function will write the deflate_level here, if
+deflate is in use.
+ 
+ at end table
+
+ at heading Errors 
+
+NF_INQ_VAR_DEFLATE returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. 
+
+Possible return codes include:
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_BADID
+Bad ncid.
+
+ at item NF_ENOTNC4
+Not a netCDF-4 file.
+
+ at item NF_ENOTVAR
+Can't find this variable.
+
+ at end table
+
+ at heading Example
+
+In this example code from nf_test/ftst_vars.F, a file with a variable
+using deflate is opened, and the deflate level checked.
+
+ at example
+C     Is everything set that is supposed to be?
+      retval = nf_inq_var_deflate(ncid, varid, shuffle, deflate, 
+     +     deflate_level)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (shuffle .ne. 0 .or. deflate .ne. 1 .or. 
+     +     deflate_level .ne. 4) stop 2
+
+ at end example
+
+ at node NF_INQ_VAR_SZIP, NF_DEF_VAR_FLETCHER32, NF_INQ_VAR_DEFLATE, Variables
+ at section Learn About Szip Parameters for a Variable: @code{NF_INQ_VAR_SZIP}
+ at findex NF_INQ_VAR_SZIP
+
+The function NF_INQ_VAR_SZIP returns the szip settings for a
+variable in a netCDF-4 file. 
+
+It is not necessary to know the szip settings to read the
+variable. (Szip is completely transparent to readers of the data).
+
+ at heading Usage 
+
+ at example
+NF_INQ_VAR_SZIP(INTEGER NCID, INTEGER VARID, INTEGER OPTION_MASK, 
+                        PIXELS_PER_BLOCK);
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID.
+
+ at item OPTION_MASK
+This will be set to the option_mask value.
+
+ at item PIXELS_PER_BLOCK
+The number of bits per pixel will be put here.
+
+ at end table
+
+ at heading Errors 
+
+NF_INQ_VAR_SZIP returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. 
+
+Possible return codes include:
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_BADID
+Bad ncid.
+
+ at item NF_ENOTNC4
+Not a netCDF-4 file.
+
+ at item NF_ENOTVAR
+Can't find this variable.
+
+ at end table
+
+ at heading Example
+
+ at example
+ at end example
+
+ at node NF_DEF_VAR_FLETCHER32, NF_INQ_VAR_FLETCHER32, NF_INQ_VAR_SZIP, Variables
+ at section Define Checksum Parameters for a Variable: @code{NF_DEF_VAR_FLETCHER32}
+ at findex NF_DEF_VAR_FLETCHER32
+ at cindex fletcher32
+ at cindex variables, fletcher32
+ at cindex checksum
+ at cindex variables, checksum
+
+The function NF_DEF_VAR_FLETCHER32 sets the checksum property for a
+variable in a netCDF-4 file. 
+
+This function may only be called after the variable is defined, but before
+NF_ENDDEF is called.
+
+ at heading Usage 
+
+ at example
+NF_DEF_VAR_FLETCHER32(INTEGER NCID, INTEGER VARID, INTEGER CHECKSUM);
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID.
+
+ at item CHECKSUM
+If this is NF_FLETCHER32, fletcher32 checksums will be turned on for this
+variable.
+ 
+ at end table
+
+ at heading Errors 
+
+NF_DEF_VAR_FLETCHER32 returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. 
+
+Possible return codes include:
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_BADID
+Bad ncid.
+
+ at item NF_ENOTNC4
+Not a netCDF-4 file.
+
+ at item NF_ENOTVAR
+Can't find this variable.
+
+ at item NF_ELATEDEF
+This variable has already been the subject of a NF_ENDDEF call. In
+netCDF-4 files NF_ENDDEF will be called automatically for any data
+read or write. Once enddef has been called, it is impossible to set
+the checksum property for a variable.
+
+ at item NF_ENOTINDEFINE
+Not in define mode. This is returned for netCDF classic or 64-bit
+offset files, or for netCDF-4 files, when they were been created with
+NF_STRICT_NC3 flag. (@pxref{NF_CREATE}).
+
+ at item NF_EPERM
+Attempt to create object in read-only file.
+
+ at end table
+
+ at heading Example
+
+In this example from nf_test/ftst_vars.F, the variable in a file has
+the Fletcher32 checksum filter turned on.
+
+ at example
+
+C     Create the netCDF file.
+      retval = nf_create(FILE_NAME, NF_NETCDF4, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define the dimensions.
+      retval = nf_def_dim(ncid, "x", NX, x_dimid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_def_dim(ncid, "y", NY, y_dimid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define the variable. 
+      dimids(1) = y_dimid
+      dimids(2) = x_dimid
+      retval = NF_DEF_VAR(ncid, "data", NF_INT, NDIMS, dimids, varid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Turn on chunking.
+      chunks(1) = NY
+      chunks(2) = NX
+      retval = NF_DEF_VAR_CHUNKING(ncid, varid, NF_CHUNKED, chunks)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Turn on deflate compression, fletcher32 checksums.
+      retval = NF_DEF_VAR_DEFLATE(ncid, varid, 0, 1, 4)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = NF_DEF_VAR_FLETCHER32(ncid, varid, NF_FLETCHER32)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+ at end example
+
+ at node NF_INQ_VAR_FLETCHER32, NF_DEF_VAR_ENDIAN, NF_DEF_VAR_FLETCHER32, Variables
+ at section Learn About Checksum Parameters for a Variable: @code{NF_INQ_VAR_FLETCHER32}
+ at findex NF_INQ_VAR_FLETCHER32
+
+The function NF_INQ_VAR_FLETCHER32 returns the checksum settings for a
+variable in a netCDF-4 file. 
+
+ at heading Usage 
+
+ at example
+NF_INQ_VAR_FLETCHER32(INTEGER NCID, INTEGER VARID, INTEGER CHECKSUM);
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID.
+
+ at item CHECKSUM
+NF_INQ_VAR_FLETCHER32 will set this to NF_FLETCHER32 if the fletcher32 filter is
+turned on for this variable, and NF_NOCHECKSUM if it is not.
+
+ at end table
+
+ at heading Errors 
+
+NF_INQ_VAR_FLETCHER32 returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. 
+
+Possible return codes include:
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_BADID
+Bad ncid.
+
+ at item NF_ENOTNC4
+Not a netCDF-4 file.
+
+ at item NF_ENOTVAR
+Can't find this variable.
+
+ at end table
+
+ at heading Example
+
+In this example from nf_test/ftst_vars.F the checksum filter is
+checked for a file. Since it was turned on for this variable, the
+checksum variable is set to NF_FLETCHER32.
+
+ at example
+      retval = nf_inq_var_fletcher32(ncid, varid, checksum)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (checksum .ne. NF_FLETCHER32) stop 2
+ at end example
+
+ at node NF_DEF_VAR_ENDIAN, NF_INQ_VAR_ENDIAN, NF_INQ_VAR_FLETCHER32, Variables
+ at section Define Endianness of a Variable: @code{NF_DEF_VAR_ENDIAN}
+ at findex NF_DEF_VAR_ENDIAN
+ at cindex endianness
+ at cindex big-endian
+ at cindex little-endian
+ at cindex variables, endian
+
+The function NF_DEF_VAR_ENDIAN sets the endianness for a variable in a
+netCDF-4 file.
+
+This function must be called after the variable is defined, but before
+NF_ENDDEF is called.
+
+By default, netCDF-4 variables are in native endianness. That is, they
+are big-endian on a big-endian machine, and little-endian on a little
+endian machine.
+
+In some cases a user might wish to change from native endianness to
+either big or little-endianness. This function allows them to do that.
+
+ at heading Usage 
+
+ at example
+NF_DEF_VAR_ENDIAN(INTEGER NCID, INTEGER VARID, INTEGER ENDIAN)
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID.
+
+ at item ENDIAN
+Set to NF_ENDIAN_NATIVE for native endianness. (This is the
+default). Set to NF_ENDIAN_LITTLE for little endian, or NF_ENDIAN_BIG
+for big endian.
+ 
+ at end table
+
+ at heading Errors 
+
+NF_DEF_VAR_ENDIAN returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. 
+
+Possible return codes include:
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_BADID
+Bad ncid.
+
+ at item NF_ENOTNC4
+Not a netCDF-4 file.
+
+ at item NF_ENOTVAR
+Can't find this variable.
+
+ at item NF_ELATEDEF
+This variable has already been the subject of a NF_ENDDEF call. In
+netCDF-4 files NF_ENDDEF will be called automatically for any data
+read or write. Once enddef has been called, it is impossible to set
+the endianness of a variable.
+
+ at item NF_ENOTINDEFINE
+Not in define mode. This is returned for netCDF classic or 64-bit
+offset files, or for netCDF-4 files, when they were been created with
+NF_STRICT_NC3 flag, and the file is not in define
+mode. (@pxref{NF_CREATE}).
+
+ at item NF_EPERM
+Attempt to create object in read-only file.
+
+ at end table
+
+ at heading Example
+
+In this example from nf_test/ftst_vars.c, a file is created with one
+variable, and its endianness is set to NF_ENDIAN_BIG.
+
+ at example
+C     Create the netCDF file.
+      retval = nf_create(FILE_NAME, NF_NETCDF4, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define the dimensions.
+      retval = nf_def_dim(ncid, "x", NX, x_dimid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_def_dim(ncid, "y", NY, y_dimid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define the variable. 
+      dimids(1) = y_dimid
+      dimids(2) = x_dimid
+      retval = NF_DEF_VAR(ncid, "data", NF_INT, NDIMS, dimids, varid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Turn on chunking.
+      chunks(1) = NY
+      chunks(2) = NX
+      retval = NF_DEF_VAR_chunking(ncid, varid, 0, chunks)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Set variable to big-endian (default is whatever is native to
+C     writing machine).
+      retval = NF_DEF_VAR_endian(ncid, varid, NF_ENDIAN_BIG)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+ at end example
+
+ at node NF_INQ_VAR_ENDIAN, NF_INQ_VARID, NF_DEF_VAR_ENDIAN, Variables
+ at section Learn About Endian Parameters for a Variable: @code{NF_INQ_VAR_ENDIAN}
+ at findex NF_INQ_VAR_ENDIAN
+
+The function NF_INQ_VAR_ENDIAN returns the endianness settings for a
+variable in a netCDF-4 file.
+
+ at heading Usage 
+
+ at example
+NF_INQ_VAR_ENDIAN(INTEGER NCID, INTEGER VARID, INTEGER ENDIAN)
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID.
+
+ at item ENDIAN
+NF_INQ_VAR_ENDIAN will set this to NF_ENDIAN_LITTLE if this variable
+is stored in little-endian format, NF_ENDIAN_BIG if it is stored in
+big-endian format, and NF_ENDIAN_NATIVE if the endianness is not set,
+and the variable is not created yet.
+
+ at end table
+
+ at heading Errors 
+
+NF_INQ_VAR_ENDIAN returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. 
+
+Possible return codes include:
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_BADID
+Bad ncid.
+
+ at item NF_ENOTNC4
+Not a netCDF-4 file.
+
+ at item NF_ENOTVAR
+Can't find this variable.
+
+ at end table
+
+ at heading Example
+
+In this example from nf_test/ftst_vars.F, the endianness of a variable
+is checked to make sure it is NF_ENDIAN_BIG.
+
+ at example
+      retval = nf_inq_var_endian(ncid, varid, endianness)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (endianness .ne. NF_ENDIAN_BIG) stop 2
+ at end example
+
+ at node NF_INQ_VARID, NF_INQ_VAR family, NF_INQ_VAR_ENDIAN, Variables
+ at section Get a Variable ID from Its Name: NF_INQ_VARID 
+ at findex NF_INQ_VARID 
+
+The function NF_INQ_VARID returns the ID of a netCDF variable, given
+its name.
+
+ at heading Usage
+ at example
+INTEGER FUNCTION NF_INQ_VARID(INTEGER NCID, CHARACTER*(*) NAME, 
+                              INTEGER varid)
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item NAME
+Variable name for which ID is desired.
+ 
+ at item varid
+Returned variable ID.
+ at end table
+
+ at heading Errors 
+
+NF_INQ_VARID returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The specified variable name is not a valid name for a variable in the
+specified netCDF dataset.
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_INQ_VARID to find out the ID of a variable
+named rh in an existing netCDF dataset named foo.nc:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER  STATUS, NCID, RHID
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+
+ at node NF_INQ_VAR family, NF_PUT_VAR1_  type, NF_INQ_VARID, Variables
+ at section Get Information about a Variable from Its ID: NF_INQ_VAR family
+ at findex NF_INQ_VAR family
+
+A family of functions that returns information about a netCDF
+variable, given its ID. Information about a variable includes its
+name, type, number of dimensions, a list of dimension IDs describing
+the shape of the variable, and the number of variable attributes that
+have been assigned to the variable.
+
+The function NF_INQ_VAR returns all the information about a netCDF
+variable, given its ID. The other functions each return just one item
+of information about a variable.
+
+These other functions include NF_INQ_VARNAME, NF_INQ_VARTYPE,
+NF_INQ_VARNDIMS, NF_INQ_VARDIMID, and NF_INQ_VARNATTS.
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION NF_INQ_VAR      (INTEGER NCID, INTEGER VARID,
+                                  CHARACTER*(*) name, INTEGER xtype,
+                                  INTEGER ndims, INTEGER dimids(*),
+                                  INTEGER natts)
+INTEGER FUNCTION NF_INQ_VARNAME  (INTEGER NCID, INTEGER VARID, 
+                                  CHARACTER*(*) name)
+INTEGER FUNCTION NF_INQ_VARTYPE  (INTEGER NCID, INTEGER VARID, 
+                                  INTEGER xtype)
+INTEGER FUNCTION NF_INQ_VARNDIMS (INTEGER NCID, INTEGER VARID, 
+                                  INTEGER ndims)
+INTEGER FUNCTION NF_INQ_VARDIMID (INTEGER NCID, INTEGER VARID, 
+                                  INTEGER dimids(*))
+INTEGER FUNCTION NF_INQ_VARNATTS (INTEGER NCID, INTEGER VARID, 
+                                  INTEGER natts)
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID.
+ 
+ at item NAME
+Returned variable name. The caller must allocate space for the
+returned name. The maximum possible length, in characters, of a
+variable name is given by the predefined constant NF_MAX_NAME.
+ 
+ at item xtype
+Returned variable type, one of the set of predefined netCDF external
+data types. The type of this parameter, NF_TYPE, is defined in the
+netCDF header file. The valid netCDF external data types are NF_BYTE,
+NF_CHAR, NF_SHORT, NF_INT, NF_FLOAT, AND NF_DOUBLE.
+ 
+ at item ndims
+Returned number of dimensions the variable was defined as using. For
+example, 2 indicates a matrix, 1 indicates a vector, and 0 means the
+variable is a scalar with no dimensions.
+ 
+ at item dimids
+Returned vector of *ndimsp dimension IDs corresponding to the
+variable dimensions. The caller must allocate enough space for a
+vector of at least *ndimsp integers to be returned. The maximum
+possible number of dimensions for a variable is given by the
+predefined constant NF_MAX_VAR_DIMS.
+ 
+ at item natts
+Returned number of variable attributes assigned to this variable.
+
+ at end table
+
+These functions return the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The variable ID is invalid for the specified netCDF dataset. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_INQ_VAR to find out about a variable named
+rh in an existing netCDF dataset named foo.nc:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER  STATUS, NCID
+INTEGER  RHID               ! variable ID
+CHARACTER*31 RHNAME         ! variable name
+INTEGER  RHTYPE             ! variable type
+INTEGER  RHN                ! number of dimensions
+INTEGER  RHDIMS(NF_MAX_VAR_DIMS)   ! variable shape
+INTEGER  RHNATT                    ! number of attributes
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)  ! get ID
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_INQ_VAR (NCID, RHID, RHNAME, RHTYPE, RHN, RHDIMS, RHNATT)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_PUT_VAR1_  type, NF_PUT_VAR_ type, NF_INQ_VAR family, Variables
+ at section Write a Single Data Value: NF_PUT_VAR1_  type 
+ at findex NF_PUT_VAR1_  type 
+
+The functions NF_PUT_VAR1_type (for various types) put a single data
+value of the specified type into a variable of an open netCDF dataset
+that is in data mode. Inputs are the netCDF ID, the variable ID, an
+index that specifies which value to add or alter, and the data
+value. The value is converted to the external data type of the
+variable, if necessary.
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION  NF_PUT_VAR1_TEXT(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), CHARACTER CHVAL)
+INTEGER FUNCTION  NF_PUT_VAR1_INT1(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), INTEGER*1 I1VAL)
+INTEGER FUNCTION  NF_PUT_VAR1_INT2(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), INTEGER*2 I2VAL)
+INTEGER FUNCTION  NF_PUT_VAR1_INT (INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), INTEGER   IVAL)
+INTEGER FUNCTION  NF_PUT_VAR1_REAL(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), REAL      RVAL)
+INTEGER FUNCTION  NF_PUT_VAR1_DOUBLE(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), DOUBLE    DVAL) 
+INTEGER FUNCTION  NF_PUT_VAR1(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), *) 
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID.
+ 
+ at item INDEX
+The index of the data value to be written. The indices are relative
+to 1, so for example, the first data value of a two-dimensional
+variable would have index (1,1). The elements of index must correspond
+to the variable's dimensions. Hence, if the variable uses the
+unlimited dimension, the last index would correspond to the record number.
+ 
+ at item CHVAL
+ at itemx I1VAL
+ at itemx I2VAL
+ at itemx IVAL
+ at itemx RVAL
+ at itemx DVAL
+Pointer to the data value to be written. If the type of data values
+differs from the netCDF variable type, type conversion will
+occur. @xref{Type Conversion,,, netcdf, @value{n-man}}.
+ at end table
+
+ at heading Errors 
+
+NF_PUT_VAR1_  type returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The variable ID is invalid for the specified netCDF dataset.
+
+ at item
+The specified indices were out of range for the rank of the specified
+variable. For example, a negative index or an index that is larger
+than the corresponding dimension length will cause an error.
+
+ at item
+The specified value is out of the range of values representable by the
+external data type of the variable.
+
+ at item
+The specified netCDF is in define mode rather than data mode. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_PUT_VAR1_DOUBLE to set the (4,3,2) element
+of the variable named rh to 0.5 in an existing netCDF dataset named
+foo.nc. For simplicity in this example, we assume that we know that rh
+is dimensioned with lon, lat, and time, so we want to set the value of
+rh that corresponds to the fourth lon value, the third lat value, and
+the second time value:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER  STATUS             ! error status
+INTEGER  NCID
+INTEGER  RHID               ! variable ID
+INTEGER  RHINDX(3)          ! where to put value
+DATA RHINDX /4, 3, 2/
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)  ! get ID
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_PUT_VAR1_DOUBLE (NCID, RHID, RHINDX, 0.5)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_PUT_VAR_ type, NF_PUT_VARA_ type, NF_PUT_VAR1_  type, Variables
+ at section Write an Entire Variable: NF_PUT_VAR_ @var{type} 
+ at findex NF_PUT_VAR_ type 
+
+The NF_PUT_VAR_ @var{type} family of functions write all the values of a
+variable into a netCDF variable of an open netCDF dataset. This is the
+simplest interface to use for writing a value in a scalar variable or
+whenever all the values of a multidimensional variable can all be
+written at once. The values to be written are associated with the
+netCDF variable by assuming that the last dimension of the netCDF
+variable varies fastest in the C interface. The values are converted
+to the external data type of the variable, if necessary.
+
+Take care when using the simplest forms of this interface with record
+variables (variables that use the NF_UNLIMITED dimension) when you
+don't specify how many records are to be written.  If you try to write
+all the values of a record variable into a netCDF file that has no
+record data yet (hence has 0 records), nothing will be written.
+Similarly, if you try to write all the values of a record variable
+from an array but there are more records in the file than you assume,
+more in-memory data will be accessed than you expect, which may cause
+a segmentation violation.  To avoid such problems, it is better to use
+the NF_PUT_VARA_type interfaces for variables that use the
+NF_UNLIMITED dimension.  @xref{NF_PUT_VARA_ type}.
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION NF_PUT_VAR_TEXT  (INTEGER NCID, INTEGER VARID,
+                                   CHARACTER*(*) TEXT)
+INTEGER FUNCTION NF_PUT_VAR_INT1  (INTEGER NCID, INTEGER VARID,
+                                   INTEGER*1 I1VALS(*))
+INTEGER FUNCTION NF_PUT_VAR_INT2  (INTEGER NCID, INTEGER VARID,
+                                   INTEGER*2 I2VALS(*))
+INTEGER FUNCTION NF_PUT_VAR_INT   (INTEGER NCID, INTEGER VARID,
+                                   INTEGER IVALS(*))
+INTEGER FUNCTION NF_PUT_VAR_REAL  (INTEGER NCID, INTEGER VARID,
+                                   REAL RVALS(*))
+INTEGER FUNCTION NF_PUT_VAR_DOUBLE(INTEGER NCID, INTEGER VARID,
+                                   DOUBLE DVALS(*))
+INTEGER FUNCTION NF_PUT_VAR       (INTEGER NCID, INTEGER VARID,
+                                   VALS(*))
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID.
+ 
+ at item TEXT
+ at itemx I1VALS
+ at itemx I2VALS
+ at itemx IVALS
+ at itemx RVALS
+ at itemx DVALS
+ at itemx VALS
+The block of data values to be written. The data should be of the type
+appropriate for the function called. You cannot put CHARACTER data
+into a numeric variable or numeric data into a text variable. For
+numeric data, if the type of data differs from the netCDF variable
+type, type conversion will occur (@pxref{Type Conversion,,, netcdf,
+ at value{n-man}}). The order in which the data will be written
+into the specified variable is with the first dimension varying
+fastest (like the ordinary FORTRAN convention).
+ at end table
+
+ at heading Errors 
+
+Members of the NF_PUT_VAR_ @var{type} family return the value NF_NOERR if no
+errors occurred. Otherwise, the returned status indicates an
+error. Possible causes of errors include:
+
+ at itemize
+
+ at item
+The variable ID is invalid for the specified netCDF dataset. 
+
+ at item
+One or more of the specified values are out of the range of values
+representable by the external data type of the variable.
+
+ at item
+One or more of the specified values are out of the range of values
+representable by the external data type of the variable.
+
+ at item
+The specified netCDF dataset is in define mode rather than data mode.
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_PUT_VAR_DOUBLE to add or change all the
+values of the variable named rh to 0.5 in an existing netCDF dataset
+named foo.nc. For simplicity in this example, we assume that we know
+that rh is dimensioned with lon and lat, and that there are ten
+lon values and five lat values.
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+PARAMETER (LATS=5, LONS=10) ! dimension lengths
+INTEGER  STATUS, NCID
+INTEGER  RHID                        ! variable ID
+DOUBLE RHVALS(LONS, LATS)
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+DO 10 ILON = 1, LONS
+   DO 10 ILAT = 1, LATS
+         RHVALS(ILON, ILAT) = 0.5
+10 CONTINUE
+STATUS = NF_PUT_var_DOUBLE (NCID, RHID, RHVALS)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_PUT_VARA_ type, NF_PUT_VARS_ type, NF_PUT_VAR_ type, Variables
+ at section Write an Array of Values: NF_PUT_VARA_ @var{type} 
+ at findex NF_PUT_VARA_ type 
+
+The function NF_PUT_VARA_ @var{type} writes values into a netCDF variable of
+an open netCDF dataset. The part of the netCDF variable to write is
+specified by giving a corner and a vector of edge lengths that refer
+to an array section of the netCDF variable. The values to be written
+are associated with the netCDF variable by assuming that the first
+dimension of the netCDF variable varies fastest in the FORTRAN
+interface. The netCDF dataset must be in data mode.
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION NF_PUT_VARA_TEXT(INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  CHARACTER*(*) TEXT)
+INTEGER FUNCTION NF_PUT_VARA_INT1(INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  INTEGER*1 I1VALS(*))
+INTEGER FUNCTION NF_PUT_VARA_INT2(INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  INTEGER*2 I2VALS(*))
+INTEGER FUNCTION NF_PUT_VARA_INT (INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  INTEGER IVALS(*))
+INTEGER FUNCTION NF_PUT_VARA_REAL(INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  REAL RVALS(*))
+INTEGER FUNCTION NF_PUT_VARA_DOUBLE(INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  DOUBLE DVALS(*)) 
+INTEGER FUNCTION NF_PUT_VARA     (INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  VALS(*)) 
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID.
+ 
+ at item START
+A vector of integers specifying the index in the variable where the
+first of the data values will be written. The indices are relative to
+1, so for example, the first data value of a variable would have index
+(1, 1, ..., 1). The length of START must be the same as the number of
+dimensions of the specified variable. The elements of START must
+correspond to the variable's dimensions in order. Hence, if the
+variable is a record variable, the last index would correspond to the
+starting record number for writing the data values.
+ 
+ at item COUNT
+A vector of integers specifying the edge lengths along each dimension
+of the block of data values to written. To write a single value, for
+example, specify COUNT as (1, 1, ..., 1). The length of COUNT is the
+number of dimensions of the specified variable. The elements of COUNT
+correspond to the variable's dimensions. Hence, if the variable is a
+record variable, the last element of COUNT corresponds to a count of
+the number of records to write.
+
+Note: setting any element of the count array to zero causes the
+function to exit without error, and without doing anything.
+ 
+ at item TEXT
+ at itemx I1VALS
+ at itemx I2VALS
+ at itemx IVALS
+ at itemx RVALS
+ at itemx DVALS
+ at itemx VALS
+The block of data values to be written. The data should be of the type
+appropriate for the function called. You cannot put CHARACTER data
+into a numeric variable or numeric data into a text variable. For
+numeric data, if the type of data differs from the netCDF variable
+type, type conversion will occur (@pxref{Type Conversion,,, netcdf,
+ at value{n-man}}).
+ at end table
+
+ at heading Errors 
+
+NF_PUT_VARA_ @var{type} returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The variable ID is invalid for the specified netCDF dataset. 
+
+ at item
+The specified corner indices were out of range for the rank of the
+specified variable. For example, a negative index, or an index that is
+larger than the corresponding dimension length will cause an error.
+
+ at item
+The specified edge lengths added to the specified corner would have
+referenced data out of range for the rank of the specified
+variable. For example, an edge length that is larger than the
+corresponding dimension length minus the corner index will cause an
+error.
+
+ at item
+One or more of the specified values are out of the range of values
+representable by the external data type of the variable.
+
+ at item
+The specified netCDF dataset is in define mode rather than data mode. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_PUT_VARA_DOUBLE to add or change all the
+values of the variable named rh to 0.5 in an existing netCDF dataset
+named foo.nc. For simplicity in this example, we assume that we know
+that rh is dimensioned with time, lat, and lon, and that there are
+three time values, five lat values, and ten lon values.
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+PARAMETER (NDIMS=3)         ! number of dimensions
+PARAMETER (TIMES=3, LATS=5, LONS=10) ! dimension lengths
+INTEGER  STATUS, NCID, TIMES
+INTEGER  RHID               ! variable ID
+INTEGER  START(NDIMS), COUNT(NDIMS)
+DOUBLE RHVALS(LONS, LATS, TIMES)
+DATA START /1, 1, 1/        ! start at first value
+DATA COUNT /LONS, LATS, TIMES/
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+DO 10 ILON = 1, LONS
+   DO 10 ILAT = 1, LATS
+      DO 10 ITIME = 1, TIMES
+         RHVALS(ILON, ILAT, ITIME) = 0.5
+10 CONTINUE
+STATUS = NF_PUT_VARA_DOUBLE (NCID, RHID, START, COUNT, RHVALS)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_PUT_VARS_ type, NF_PUT_VARM_ type, NF_PUT_VARA_ type, Variables
+ at section NF_PUT_VARS_ @var{type} 
+ at findex NF_PUT_VARS_ type 
+
+Each member of the family of functions NF_PUT_VARS_ @var{type} writes a
+subsampled (strided) array section of values into a netCDF variable of
+an open netCDF dataset. The subsampled array section is specified by
+giving a corner, a vector of counts, and a stride vector. The netCDF
+dataset must be in data mode.
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION NF_PUT_VARS_TEXT  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*),CHARACTER*(*) TEXT)
+INTEGER FUNCTION NF_PUT_VARS_INT1  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*),INTEGER*1 I1VALS(*))
+INTEGER FUNCTION NF_PUT_VARS_INT2  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*),INTEGER*2 I2VALS(*))
+INTEGER FUNCTION NF_PUT_VARS_INT   (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IVALS(*))
+INTEGER FUNCTION NF_PUT_VARS_REAL  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*),  REAL RVALS(*))
+INTEGER FUNCTION NF_PUT_VARS_DOUBLE(INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*),  DOUBLE DVALS(*))
+INTEGER FUNCTION NF_PUT_VARS       (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), VALS(*))
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID.
+ 
+ at item START
+A vector of integers specifying the index in the variable where the
+first of the data values will be written. The indices are relative to
+1, so for example, the first data value of a variable would have index
+(1, 1, ..., 1). The elements of START correspond, in order, to the
+variable's dimensions. Hence, if the variable is a record variable,
+the last index would correspond to the starting record number for
+writing the data values.
+ 
+ at item COUNT
+A vector of integers specifying the number of indices selected along
+each dimension. To write a single value, for example, specify COUNT as
+(1, 1, ..., 1). The elements of COUNT correspond, in order, to the
+variable's dimensions. Hence, if the variable is a record variable,
+the last element of COUNT corresponds to a count of the number of
+records to write.
+
+Note: setting any element of the count array to zero causes the
+function to exit without error, and without doing anything.
+ 
+ at item STRIDE
+A vector of integers that specifies the sampling interval along each
+dimension of the netCDF variable. The elements of the stride vector
+correspond, in order, to the netCDF variable's dimensions (STRIDE(1)
+gives the sampling interval along the most rapidly varying dimension
+of the netCDF variable). Sampling intervals are specified in
+type-independent units of elements (a value of 1 selects consecutive
+elements of the netCDF variable along the corresponding dimension, a
+value of 2 selects every other element, etc.).
+ 
+ at item TEXT
+ at itemx I1VALS
+ at itemx I2VALS
+ at itemx IVALS
+ at itemx RVALS
+ at itemx DVALS
+ at itemx VALS
+The block of data values to be written. The data should be of the type
+appropriate for the function called. You cannot put CHARACTER data
+into a numeric variable or numeric data into a text variable. For
+numeric data, if the type of data differs from the netCDF variable
+type, type conversion will occur (@pxref{Type Conversion,,, netcdf,
+ at value{n-man}}).
+ at end table
+
+ at heading Errors 
+
+NF_PUT_VARS_ @var{type} returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+ at itemize
+
+ at item
+The variable ID is invalid for the specified netCDF dataset. 
+
+ at item
+The specified start, count and stride generate an index which is out
+of range.
+
+ at item
+One or more of the specified values are out of the range of values
+representable by the external data type of the variable.
+
+ at item
+The specified netCDF is in define mode rather than data mode. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+
+ at end itemize
+
+ at heading Example 
+
+Here is an example of using NF_PUT_VARS_REAL to write -- from an
+internal array -- every other point of a netCDF variable named rh
+which is described by the FORTRAN declaration REAL RH(6,4) (note the
+size of the dimensions):
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+PARAMETER (NDIM=2)   ! rank of netCDF variable
+INTEGER NCID         ! netCDF dataset ID
+INTEGER STATUS       ! return code
+INTEGER RHID         ! variable ID
+INTEGER START(NDIM)  ! netCDF variable start point
+INTEGER COUNT(NDIM)  ! size of internal array
+INTEGER STRIDE(NDIM) ! netCDF variable subsampling intervals
+REAL RH(3,2)         ! note subsampled sizes for netCDF variable
+                     ! dimensions
+DATA START   /1, 1/  ! start at first netCDF variable value
+DATA COUNT   /3, 2/  ! size of internal array: entire (subsampled)
+                     ! netCDF variable
+DATA STRIDE /2, 2/   ! access every other netCDF element
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID(NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_PUT_VARS_REAL(NCID, RHID, START, COUNT, STRIDE, RH)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+
+
+ at end example
+
+ at node NF_PUT_VARM_ type, NF_GET_VAR1_ type, NF_PUT_VARS_ type, Variables
+ at section NF_PUT_VARM_ @var{type} 
+ at findex NF_PUT_VARM_ type 
+
+The NF_PUT_VARM_ @var{type} family of functions writes a mapped array
+section of values into a netCDF variable of an open netCDF
+dataset. The mapped array section is specified by giving a corner, a
+vector of counts, a stride vector, and an index mapping vector. The
+index mapping vector is a vector of integers that specifies the
+mapping between the dimensions of a netCDF variable and the in-memory
+structure of the internal data array. No assumptions are made about
+the ordering or length of the dimensions of the data array. The netCDF
+dataset must be in data mode.
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION NF_PUT_VARM_TEXT  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            CHARACTER*(*) TEXT)
+INTEGER FUNCTION NF_PUT_VARM_INT1  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            INTEGER*1 I1VALS(*))
+INTEGER FUNCTION NF_PUT_VARM_INT2  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            INTEGER*2 I2VALS(*))
+INTEGER FUNCTION NF_PUT_VARM_INT   (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            INTEGER IVALS(*))
+INTEGER FUNCTION NF_PUT_VARM_REAL  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            REAL RVALS(*))
+INTEGER FUNCTION NF_PUT_VARM_DOUBLE(INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            DOUBLE DVALS(*))
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID.
+ 
+ at item START
+A vector of integers specifying the index in the variable where the
+first of the data values will be written. The indices are relative to
+1, so for example, the first data value of a variable would have index
+(1, 1, ..., 1). The elements of START correspond, in order, to the
+variable's dimensions. Hence, if the variable is a record variable,
+the last index would correspond to the starting record number for
+writing the data values.
+ 
+ at item COUNT
+A vector of integers specifying the number of indices selected along
+each dimension. To write a single value, for example, specify COUNT as
+(1, 1, ..., 1). The elements of COUNT correspond, in order, to the
+variable's dimensions. Hence, if the variable is a record variable,
+the last element of COUNT corresponds to a count of the number of
+records to write.
+
+Note: setting any element of the count array to zero causes the
+function to exit without error, and without doing anything.
+ 
+ at item STRIDE
+A vector of integers that specifies the sampling interval along each
+dimension of the netCDF variable. The elements of the stride vector
+correspond, in order, to the netCDF variable's dimensions (STRIDE(1)
+gives the sampling interval along the most rapidly varying dimension
+of the netCDF variable). Sampling intervals are specified in
+type-independent units of elements (a value of 1 selects consecutive
+elements of the netCDF variable along the corresponding dimension, a
+value of 2 selects every other element, etc.).
+
+ at item IMAP
+A vector of integers that specifies the mapping between the dimensions
+of a netCDF variable and the in-memory structure of the internal data
+array. The elements of the index mapping vector correspond, in order,
+to the netCDF variable's dimensions (IMAP(1) gives the distance
+between elements of the internal array corresponding to the most
+rapidly varying dimension of the netCDF variable). Distances between
+elements are specified in units of elements (the distance between
+internal elements that occupy adjacent memory locations is 1 and not
+the element's byte-length as in netCDF 2).
+
+ at item TEXT
+ at itemx I1VALS
+ at itemx I2VALS
+ at itemx IVALS
+ at itemx RVALS
+ at itemx DVALS
+The data values to be written. The data should be of the type
+appropriate for the function called. You cannot put CHARACTER data
+into a numeric variable or numeric data into a text variable. For
+numeric data, if the type of data differs from the netCDF variable
+type, type conversion will occur (@pxref{Type Conversion,,, netcdf,
+ at value{n-man}}).
+
+ at end table
+ 
+ at heading Errors 
+
+NF_PUT_VARM_ @var{type} returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The variable ID is invalid for the specified netCDF dataset. 
+
+ at item
+The specified START, COUNT, and STRIDE generate an index which is out
+of range. Note that no error checking is possible on the imap vector.
+
+ at item
+One or more of the specified values are out of the range of values
+representable by the external data type of the variable.
+
+ at item
+The specified netCDF is in define mode rather than data mode. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+
+ at end itemize
+
+ at heading Example 
+
+The following IMAP vector maps in the trivial way a 2x3x4 netCDF
+variable and an internal array of the same shape:
+
+ at example
+REAL A(2,3,4)       ! same shape as netCDF variable
+INTEGER IMAP(3)
+DATA IMAP /1, 2, 6/ ! netCDF dimension       inter-element distance
+                    ! ----------------       ----------------------
+                    ! most rapidly varying       1
+                    ! intermediate               2 (=IMAP(1)*2)
+                    ! most slowly varying        6 (=IMAP(2)*3)
+ at end example
+
+Using the IMAP vector above with NF_PUT_VARM_REAL obtains the same
+result as simply using NF_PUT_VAR_REAL.
+
+Here is an example of using NF_PUT_VARM_REAL to write -- from a
+transposed, internal array -- a netCDF variable named rh which is
+described by the FORTRAN declaration REAL RH(4,6) (note the size and
+order of the dimensions):
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+PARAMETER (NDIM=2)   ! rank of netCDF variable
+INTEGER NCID         ! netCDF ID
+INTEGER STATUS       ! return code
+INTEGER RHID         ! variable ID
+INTEGER START(NDIM)  ! netCDF variable start point
+INTEGER COUNT(NDIM)  ! size of internal array
+INTEGER STRIDE(NDIM) ! netCDF variable subsampling intervals
+INTEGER IMAP(NDIM)   ! internal array inter-element distances
+REAL RH(6,4)         ! note transposition of netCDF variable dimensions
+DATA START   /1, 1/  ! start at first netCDF variable element
+DATA COUNT   /4, 6/  ! entire netCDF variable; order corresponds
+                     ! to netCDF variable -- not internal array
+DATA STRIDE /1, 1/   ! sample every netCDF element
+DATA IMAP   /6, 1/   ! would be /1, 4/ if not transposing
+
+STATUS = NF_OPEN('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID(NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_PUT_VARM_REAL(NCID, RHID, START, COUNT, STRIDE, IMAP, RH)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+Here is another example of using NF_PUT_VARM_REAL to write -- from a
+transposed, internal array -- a subsample of the same netCDF variable,
+by writing every other point of the netCDF variable:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+PARAMETER (NDIM=2)   ! rank of netCDF variable
+INTEGER NCID         ! netCDF dataset ID
+INTEGER STATUS       ! return code
+INTEGER RHID         ! variable ID
+INTEGER START(NDIM)  ! netCDF variable start point
+INTEGER COUNT(NDIM)  ! size of internal array
+INTEGER STRIDE(NDIM) ! netCDF variable subsampling intervals
+INTEGER IMAP(NDIM)   ! internal array inter-element distances
+REAL RH(3,2)         ! note transposition of (subsampled) dimensions
+DATA START   /1, 1/  ! start at first netCDF variable value
+DATA COUNT   /2, 3/  ! order of (subsampled) dimensions corresponds
+                     ! to netCDF variable -- not internal array
+DATA STRIDE /2, 2/   ! sample every other netCDF element
+DATA IMAP   /3, 1/   ! would be `1, 2' if not transposing
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID(NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_PUT_VARM_REAL(NCID, RHID, START, COUNT, STRIDE, IMAP, RH)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_GET_VAR1_ type, NF_GET_VAR_ type, NF_PUT_VARM_ type, Variables
+ at section NF_GET_VAR1_ @var{type} 
+ at findex NF_GET_VAR1_ type 
+
+The functions NF_GET_VAR1_ @var{type} get a single data value from a
+variable of an open netCDF dataset that is in data mode. Inputs are
+the netCDF ID, the variable ID, a multidimensional index that
+specifies which value to get, and the address of a location into which
+the data value will be read. The value is converted from the external
+data type of the variable, if necessary.
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION  NF_GET_VAR1_TEXT(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), CHARACTER CHVAL)
+INTEGER FUNCTION  NF_GET_VAR1_INT1(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), INTEGER*1 I1VAL)
+INTEGER FUNCTION  NF_GET_VAR1_INT2(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), INTEGER*2 I2VAL)
+INTEGER FUNCTION  NF_GET_VAR1_INT (INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), INTEGER   IVAL)
+INTEGER FUNCTION  NF_GET_VAR1_REAL(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), REAL      RVAL)
+INTEGER FUNCTION  NF_GET_VAR1_DOUBLE(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), DOUBLE    DVAL) 
+INTEGER FUNCTION  NF_GET_VAR1(INTEGER NCID, INTEGER VARID,
+                                   INTEGER INDEX(*), VAL) 
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID.
+ 
+ at item INDEX
+The index of the data value to be read. The indices are relative to 1,
+so for example, the first data value of a two-dimensional variable has
+index (1,1). The elements of index correspond to the variable's
+dimensions. Hence, if the variable is a record variable, the last
+index is the record number.
+ 
+ at item CHVAL
+ at itemx I1VAL
+ at itemx I2VAL
+ at itemx IVAL
+ at itemx RVAL
+ at itemx DVAL
+ at itemx VAL
+The location into which the data value will be read. You cannot get
+CHARACTER data from a numeric variable or numeric data from a
+character variable. For numeric data, if the type of data differs from
+the netCDF variable type, type conversion will occur. (@pxref{Type
+Conversion,,, netcdf, @value{n-man}}).
+ at end table
+
+ at heading Errors 
+
+NF_GET_VAR1_ @var{type} returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The variable ID is invalid for the specified netCDF dataset. 
+
+ at item
+The specified indices were out of range for the rank of the specified
+variable. For example, a negative index or an index that is larger
+than the corresponding dimension length will cause an error.
+
+ at item
+The value is out of the range of values representable by the desired
+data type.
+
+ at item
+The specified netCDF is in define mode rather than data mode. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_GET_VAR1_DOUBLE to get the (4,3,2) element
+of the variable named rh in an existing netCDF dataset named
+foo.nc. For simplicity in this example, we assume that we know that rh
+is dimensioned with lon, lat, and time, so we want to get the value of
+rh that corresponds to the fourth lon value, the third lat value, and
+the second time value:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS, NCID
+INTEGER RHID           ! variable ID
+INTEGER RHINDX(3)      ! where to get value
+DOUBLE PRECISION RHVAL ! put it here
+DATA RHINDX /4, 3, 2/
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_GET_VAR1_DOUBLE (NCID, RHID, RHINDX, RHVAL)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_GET_VAR_ type, NF_GET_VARA_ type, NF_GET_VAR1_ type, Variables
+ at section NF_GET_VAR_ @var{type} 
+ at findex NF_GET_VAR_ type 
+
+The members of the NF_GET_VAR_ @var{type} family of functions read all the
+values from a netCDF variable of an open netCDF dataset. This is the
+simplest interface to use for reading the value of a scalar variable
+or when all the values of a multidimensional variable can be read at
+once. The values are read into consecutive locations with the first
+dimension varying fastest. The netCDF dataset must be in data mode.
+
+Take care when using the simplest forms of this interface with record
+variables (variables that use the NF_UNLIMITED dimension) when you
+don't specify how many records are to be read. If you try to read all
+the values of a record variable into an array but there are more
+records in the file than you assume, more data will be read than you
+expect, which may cause a segmentation violation.  To avoid such
+problems, it is better to use the NF_GET_VARA_type interfaces for
+variables that use the NF_UNLIMITED dimension.  @xref{NF_GET_VARA_
+type}.
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION NF_GET_VAR_TEXT  (INTEGER NCID, INTEGER VARID,
+                                   CHARACTER*(*) text)
+INTEGER FUNCTION NF_GET_VAR_INT1  (INTEGER NCID, INTEGER VARID,
+                                   INTEGER*1 i1vals(*))
+INTEGER FUNCTION NF_GET_VAR_INT2  (INTEGER NCID, INTEGER VARID,
+                                   INTEGER*2 i2vals(*))
+INTEGER FUNCTION NF_GET_VAR_INT   (INTEGER NCID, INTEGER VARID,
+                                   INTEGER ivals(*))
+INTEGER FUNCTION NF_GET_VAR_REAL  (INTEGER NCID, INTEGER VARID,
+                                   REAL rvals(*))
+INTEGER FUNCTION NF_GET_VAR_DOUBLE(INTEGER NCID, INTEGER VARID,
+                                   DOUBLE dvals(*))
+INTEGER FUNCTION NF_GET_VAR       (INTEGER NCID, INTEGER VARID,
+                                   vals(*))
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID.
+ 
+ at item TEXT
+ at itemx I1VALS
+ at itemx I2VALS
+ at itemx IVALS
+ at itemx RVALS
+ at itemx DVALS
+ at itemx VALS
+The block of data values to be read. The data should be of the type
+appropriate for the function called. You cannot read CHARACTER data
+from a numeric variable or numeric data from a text variable. For
+numeric data, if the type of data differs from the netCDF variable
+type, type conversion will occur (@pxref{Type Conversion,,, netcdf,
+ at value{n-man}}).
+ at end table
+
+ at heading Errors 
+
+NF_GET_VAR_ @var{type} returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The variable ID is invalid for the specified netCDF dataset. 
+
+ at item
+One or more of the values are out of the range of values representable
+by the desired type.
+
+ at item
+The specified netCDF is in define mode rather than data mode. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_GET_VAR_DOUBLE to read all the values of
+the variable named rh from an existing netCDF dataset named
+foo.nc. For simplicity in this example, we assume that we know that rh
+is dimensioned with lon and lat, and that there are ten lon
+values and five lat values.
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+PARAMETER (LATS=5, LONS=10) ! dimension lengths
+INTEGER STATUS, NCID
+INTEGER RHID                         ! variable ID
+DOUBLE RHVALS(LONS, LATS)
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_GET_VAR_DOUBLE (NCID, RHID, RHVALS)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_GET_VARA_ type, NF_GET_VARS_ type, NF_GET_VAR_ type, Variables
+ at section NF_GET_VARA_ @var{type} 
+ at findex NF_GET_VARA_ type 
+
+The members of the NF_GET_VARA_ @var{type} family of functions read an array
+of values from a netCDF variable of an open netCDF dataset. The array
+is specified by giving a corner and a vector of edge lengths. The
+values are read into consecutive locations with the first dimension
+varying fastest. The netCDF dataset must be in data mode.
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION NF_GET_VARA_TEXT(INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  CHARACTER*(*) text)
+INTEGER FUNCTION NF_GET_VARA_INT1(INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  INTEGER*1 i1vals(*))
+INTEGER FUNCTION NF_GET_VARA_INT2(INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  INTEGER*2 i2vals(*))
+INTEGER FUNCTION NF_GET_VARA_INT (INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  INTEGER ivals(*))
+INTEGER FUNCTION NF_GET_VARA_REAL(INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  REAL rvals(*))
+INTEGER FUNCTION NF_GET_VARA_DOUBLE(INTEGER NCID, INTEGER VARID,
+                                  INTEGER START(*), INTEGER COUNT(*),
+                                  DOUBLE dvals(*))
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID.
+ 
+ at item START
+A vector of integers specifying the index in the variable where the
+first of the data values will be read. The indices are relative to 1,
+so for example, the first data value of a variable would have index
+(1, 1, ..., 1). The length of START must be the same as the number of
+dimensions of the specified variable. The elements of START
+correspond, in order, to the variable's dimensions. Hence, if the
+variable is a record variable, the last index would correspond to the
+starting record number for reading the data values.
+
+ at item COUNT
+A vector of integers specifying the edge lengths along each dimension
+of the block of data values to be read. To read a single value, for
+example, specify COUNT as (1, 1, ..., 1). The length of COUNT is the
+number of dimensions of the specified variable. The elements of COUNT
+correspond, in order, to the variable's dimensions. Hence, if the
+variable is a record variable, the last element of COUNT corresponds
+to a count of the number of records to read.
+
+Note: setting any element of the count array to zero causes the
+function to exit without error, and without doing anything.
+ 
+ at item text
+ at itemx i1vals
+ at itemx i2vals
+ at itemx ivals
+ at itemx rvals
+ at itemx dvals
+The block of data values to be read. The data should be of the type
+appropriate for the function called. You cannot read CHARACTER data
+from a numeric variable or numeric data from a text variable. For
+numeric data, if the type of data differs from the netCDF variable
+type, type conversion will occur (@pxref{Type Conversion,,, netcdf,
+ at value{n-man}}).
+ at end table
+ 
+ at heading Errors 
+
+NF_GET_VARA_ @var{type} returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The variable ID is invalid for the specified netCDF dataset. 
+
+ at item
+The specified corner indices were out of range for the rank of the
+specified variable. For example, a negative index or an index that is
+larger than the corresponding dimension length will cause an error.
+
+ at item
+The specified edge lengths added to the specified corner would have
+referenced data out of range for the rank of the specified
+variable. For example, an edge length that is larger than the
+corresponding dimension length minus the corner index will cause an
+error.
+
+ at item
+One or more of the values are out of the range of values representable
+by the desired type.
+
+ at item
+The specified netCDF is in define mode rather than data mode. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_GET_VARA_DOUBLE to read all the values of
+the variable named rh from an existing netCDF dataset named
+foo.nc. For simplicity in this example, we assume that we know that rh
+is dimensioned with lon, lat, and time, and that there are ten lon
+values, five lat values, and three time values.
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+PARAMETER (NDIMS=3)                  ! number of dimensions
+PARAMETER (TIMES=3, LATS=5, LONS=10) ! dimension lengths
+INTEGER STATUS, NCID
+INTEGER RHID                         ! variable ID
+INTEGER START(NDIMS), COUNT(NDIMS)
+DOUBLE RHVALS(LONS, LATS, TIMES)
+DATA START /1, 1, 1/                 ! start at first value
+DATA COUNT /LONS, LATS, TIMES/       ! get all the values
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_GET_VARA_DOUBLE (NCID, RHID, START, COUNT, RHVALS)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_GET_VARS_ type, NF_GET_VARM_ type, NF_GET_VARA_ type, Variables
+ at section NF_GET_VARS_ @var{type} 
+ at findex NF_GET_VARS_ type 
+
+The NF_GET_VARS_ @var{type} family of functions read a subsampled (strided)
+array section of values from a netCDF variable of an open netCDF
+dataset. The subsampled array section is specified by giving a corner,
+a vector of edge lengths, and a stride vector. The values are read
+with the first dimension of the netCDF variable varying fastest. The
+netCDF dataset must be in data mode.
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION NF_GET_VARS_TEXT  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*),CHARACTER*(*) text)
+INTEGER FUNCTION NF_GET_VARS_INT1  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*),INTEGER*1 i1vals(*))
+INTEGER FUNCTION NF_GET_VARS_INT2  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*),INTEGER*2 i2vals(*))
+INTEGER FUNCTION NF_GET_VARS_INT   (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER ivals(*))
+INTEGER FUNCTION NF_GET_VARS_REAL  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), REAL rvals(*))
+INTEGER FUNCTION NF_GET_VARS_DOUBLE(INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), DOUBLE dvals(*))
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID.
+ 
+ at item START
+A vector of integers specifying the index in the variable from which
+the first of the data values will be read. The indices are relative to
+1, so for example, the first data value of a variable would have index
+(1, 1, ..., 1). The elements of START correspond, in order, to the
+variable's dimensions. Hence, if the variable is a record variable,
+the last index would correspond to the starting record number for
+reading the data values.
+
+ at item COUNT
+A vector of integers specifying the number of indices selected along
+each dimension. To read a single value, for example, specify COUNT as
+(1, 1, ..., 1). The elements of COUNT correspond, in order, to the
+variable's dimensions. Hence, if the variable is a record variable,
+the last element of COUNT corresponds to a count of the number of
+records to read.
+
+Note: setting any element of the count array to zero causes the
+function to exit without error, and without doing anything.
+
+ at item STRIDE
+A vector of integers specifying, for each dimension, the interval
+between selected indices or the value 0. The elements of the vector
+correspond, in order, to the variable's dimensions. A value of 1
+accesses adjacent values of the netCDF variable in the corresponding
+dimension; a value of 2 accesses every other value of the netCDF
+variable in the corresponding dimension; and so on. A 0 argument is
+treated as (1, 1, ..., 1).
+
+ at item text
+ at itemx i1vals
+ at itemx i2vals
+ at itemx ivals
+ at itemx rvals
+ at itemx dvals
+The block of data values to be read. The data should be of the type
+appropriate for the function called. You cannot read CHARACTER data
+from a numeric variable or numeric data from a text variable. For
+numeric data, if the type of data differs from the netCDF variable
+type, type conversion will occur (@pxref{Type Conversion,,, netcdf,
+ at value{n-man}}).
+ at end table
+
+ at heading Errors 
+
+NF_GET_VARS_ @var{type} returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The variable ID is invalid for the specified netCDF dataset. 
+
+ at item
+The specified start, count and stride generate an index which is out
+of range.
+
+ at item
+One or more of the values are out of the range of values representable
+by the desired type.
+
+ at item
+The specified netCDF is in define mode rather than data mode. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_GET_VARS_DOUBLE to read every other value
+in each dimension of the variable named rh from an existing netCDF
+dataset named foo.nc. Values are assigned, using the same dimensional
+strides, to a 2-parameter array. For simplicity in this example, we
+assume that we know that rh is dimensioned with lon, lat, and time,
+and that there are ten lon values, five lat values, and three time
+values.
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+PARAMETER (NDIMS=3)                  ! number of dimensions
+PARAMETER (TIMES=3, LATS=5, LONS=10) ! dimension lengths
+INTEGER STATUS, NCID
+INTEGER RHID ! variable ID
+INTEGER START(NDIMS), COUNT(NDIMS), STRIDE(NDIMS)
+DOUBLE DATA(LONS, LATS, TIMES)
+DATA START /1, 1, 1/                 ! start at first value
+DATA COUNT /LONS, LATS, TIMES/
+DATA STRIDE /2, 2, 2/
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_GET_VARS_DOUBLE(NCID,RHID,START,COUNT,STRIDE,DATA(1,1,1))
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_GET_VARM_ type, Reading and Writing Character String Values, NF_GET_VARS_ type, Variables
+ at section NF_GET_VARM_ @var{type} 
+ at findex NF_GET_VARM_ type 
+
+The NF_GET_VARM_ @var{type} family of functions reads a mapped array section
+of values from a netCDF variable of an open netCDF dataset. The mapped
+array section is specified by giving a corner, a vector of edge
+lengths, a stride vector, and an index mapping vector. The index
+mapping vector is a vector of integers that specifies the mapping
+between the dimensions of a netCDF variable and the in-memory
+structure of the internal data array. No assumptions are made about
+the ordering or length of the dimensions of the data array. The netCDF
+dataset must be in data mode.
+
+ at heading Usage 
+
+ at example
+INTEGER FUNCTION NF_GET_VARM_TEXT  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            CHARACTER*(*) text)
+INTEGER FUNCTION NF_GET_VARM_INT1  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            INTEGER*1 i1vals(*))
+INTEGER FUNCTION NF_GET_VARM_INT2  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            INTEGER*2 i2vals(*))
+INTEGER FUNCTION NF_GET_VARM_INT   (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            INTEGER ivals(*))
+INTEGER FUNCTION NF_GET_VARM_REAL  (INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            REAL rvals(*))
+INTEGER FUNCTION NF_GET_VARM_DOUBLE(INTEGER NCID, INTEGER VARID,
+                            INTEGER START(*), INTEGER COUNT(*),
+                            INTEGER STRIDE(*), INTEGER IMAP(*),
+                            DOUBLE dvals(*))
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID.
+ 
+ at item START
+A vector of integers specifying the index in the variable from which
+the first of the data values will be read. The indices are relative to
+1, so for example, the first data value of a variable would have index
+(1, 1, ..., 1). The elements of START correspond, in order, to the
+variable's dimensions. Hence, if the variable is a record variable,
+the last index would correspond to the starting record number for
+reading the data values.
+
+ at item COUNT
+A vector of integers specifying the number of indices selected along
+each dimension. To read a single value, for example, specify COUNT as
+(1, 1, ..., 1). The elements of COUNT correspond, in order, to the
+variable's dimensions. Hence, if the variable is a record variable,
+the last element of COUNT corresponds to a count of the number of
+records to read.
+
+Note: setting any element of the count array to zero causes the
+function to exit without error, and without doing anything.
+ 
+ at item STRIDE
+A vector of integers specifying, for each dimension, the interval
+between selected indices or the value 0. The elements of the vector
+correspond, in order, to the variable's dimensions. A value of 1
+accesses adjacent values of the netCDF variable in the corresponding
+dimension; a value of 2 accesses every other value of the netCDF
+variable in the corresponding dimension; and so on. A 0 argument is
+treated as (1, 1, ..., 1).
+
+ at item IMAP
+A vector of integers that specifies the mapping between the dimensions
+of a netCDF variable and the in-memory structure of the internal data
+array. IMAP(1) gives the distance between elements of the internal
+array corresponding to the most rapidly varying dimension of the
+netCDF variable. IMAP(N) (where N is the rank of the netCDF variable)
+gives the distance between elements of the internal array
+corresponding to the most slowly varying dimension of the netCDF
+variable. Intervening IMAP elements correspond to other dimensions of
+the netCDF variable in the obvious way. Distances between elements are
+specified in units of elements (the distance between internal elements
+that occupy adjacent memory locations is 1 and not the element's
+byte-length as in netCDF 2).
+
+ at item text
+ at itemx i1vals
+ at itemx i2vals
+ at itemx ivals
+ at itemx rvals
+ at itemx dvals
+The block of data values to be read. The data should be of the type
+appropriate for the function called. You cannot read CHARACTER data
+from a numeric variable or numeric data from a text variable. For
+numeric data, if the type of data differs from the netCDF variable
+type, type conversion will occur (@pxref{Type Conversion,,, netcdf,
+ at value{n-man}}).
+ at end table
+
+ at heading Errors 
+
+NF_GET_VARM_ @var{type} returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The variable ID is invalid for the specified netCDF dataset. 
+
+ at item
+The specified START, COUNT, and STRIDE generate an index which is out
+of range. Note that no error checking is possible on the imap vector.
+
+ at item
+One or more of the values are out of the range of values representable
+by the desired type.
+
+ at item
+The specified netCDF is in define mode rather than data mode. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+
+ at end itemize
+
+ at heading Example 
+
+The following IMAP vector maps in the trivial way a 2x3x4 netCDF
+variable and an internal array of the same shape:
+
+ at example
+REAL A(2,3,4)       ! same shape as netCDF variable
+INTEGER IMAP(3)
+DATA IMAP /1, 2, 6/ ! netCDF dimension       inter-element distance
+                    ! ----------------       ----------------------
+                    ! most rapidly varying       1
+                    ! intermediate               2 (=IMAP(1)*2)
+                    ! most slowly varying        6 (=IMAP(2)*3)
+ at end example
+
+Using the IMAP vector above with NF_GET_VARM_REAL obtains the same
+result as simply using NF_GET_VAR_REAL.
+
+Here is an example of using NF_GET_VARM_REAL to transpose a netCDF
+variable named rh which is described by the FORTRAN declaration REAL
+RH(4,6) (note the size and order of the dimensions):
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+PARAMETER (NDIM=2)   ! rank of netCDF variable
+INTEGER NCID         ! netCDF dataset ID
+INTEGER STATUS       ! return code
+INTEGER RHID         ! variable ID
+INTEGER START(NDIM)  ! netCDF variable start point
+INTEGER COUNT(NDIM)  ! size of internal array
+INTEGER STRIDE(NDIM) ! netCDF variable subsampling intervals
+INTEGER IMAP(NDIM)   ! internal array inter-element distances
+REAL    RH(6,4)      ! note transposition of netCDF variable dimensions
+DATA START   /1, 1/  ! start at first netCDF variable element
+DATA COUNT   /4, 6/  ! entire netCDF variable; order corresponds
+                     ! to netCDF variable -- not internal array
+DATA STRIDE /1, 1/   ! sample every netCDF element
+DATA IMAP   /6, 1/   ! would be /1, 4/ if not transposing
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID(NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_GET_VARM_REAL(NCID, RHID, START, COUNT, STRIDE, IMAP, RH)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+Here is another example of using NF_GET_VARM_REAL to simultaneously
+transpose and subsample the same netCDF variable, by accessing every
+other point of the netCDF variable:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+PARAMETER (NDIM=2)   ! rank of netCDF variable
+INTEGER NCID         ! netCDF dataset ID
+INTEGER STATUS       ! return code
+INTEGER RHID         ! variable ID
+INTEGER START(NDIM)  ! netCDF variable start point
+INTEGER COUNT(NDIM)  ! size of internal array
+INTEGER STRIDE(NDIM) ! netCDF variable subsampling intervals
+INTEGER IMAP(NDIM)   ! internal array inter-element distances
+REAL    RH(3,2)      ! note transposition of (subsampled) dimensions
+DATA START   /1, 1/  ! start at first netCDF variable value
+DATA COUNT   /2, 3/  ! order of (subsampled) dimensions corresponds
+                     ! to netCDF variable -- not internal array
+DATA STRIDE /2, 2/   ! sample every other netCDF element
+DATA IMAP   /3, 1/   ! would be `1, 2' if not transposing
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID(NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_GET_VARM_REAL(NCID, RHID, START, COUNT, STRIDE, IMAP, RH)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node Reading and Writing Character String Values, Fill Values, NF_GET_VARM_ type, Variables
+ at section Reading and Writing Character String Values
+
+Character strings are not a primitive netCDF external data type, in
+part because FORTRAN does not support the abstraction of
+variable-length character strings (the FORTRAN LEN function returns
+the static length of a character string, not its dynamic length). As a
+result, a character string cannot be written or read as a single
+object in the netCDF interface. Instead, a character string must be
+treated as an array of characters, and array access must be used to
+read and write character strings as variable data in netCDF
+datasets. Furthermore, variable-length strings are not supported by
+the netCDF interface except by convention; for example, you may treat
+a zero byte as terminating a character string, but you must explicitly
+specify the length of strings to be read from and written to netCDF
+variables.
+
+Character strings as attribute values are easier to use, since the
+strings are treated as a single unit for access. However, the value of
+a character-string attribute is still an array of characters with an
+explicit length that must be specified when the attribute is defined.
+
+When you define a variable that will have character-string values, use
+a character-position dimension as the most quickly varying dimension
+for the variable (the first dimension for the variable in
+FORTRAN). The length of the character-position dimension will be the
+maximum string length of any value to be stored in the
+character-string variable. Space for maximum-length strings will be
+allocated in the disk representation of character-string variables
+whether you use the space or not. If two or more variables have the
+same maximum length, the same character-position dimension may be used
+in defining the variable shapes.
+
+To write a character-string value into a character-string variable,
+use either entire variable access or array access. The latter requires
+that you specify both a corner and a vector of edge lengths. The
+character-position dimension at the corner should be one for
+FORTRAN. If the length of the string to be written is n, then the
+vector of edge lengths will specify n in the character-position
+dimension, and one for all the other dimensions:(n, 1, 1, ..., 1).
+
+In FORTRAN, fixed-length strings may be written to a netCDF dataset
+without a terminating character, to save space. Variable-length
+strings should follow the C convention of writing strings with a
+terminating zero byte so that the intended length of the string can be
+determined when it is later read by either C or FORTRAN programs.
+
+The FORTRAN interface for reading and writing strings requires the use
+of different functions for accessing string values and numeric values,
+because standard FORTRAN does not permit the same formal parameter to
+be used for both character values and numeric values. An additional
+argument, specifying the declared length of the character string
+passed as a value, is required for NF_PUT_VARA_TEXT and
+NF_GET_VARA_TEXT. The actual length of the string is specified as the
+value of the edge-length vector corresponding to the
+character-position dimension.
+
+Here is an example that defines a record variable, tx, for character
+strings and stores a character-string value into the third record
+using NF_PUT_VARA_TEXT. In this example, we assume the string variable
+and data are to be added to an existing netCDF dataset named foo.nc
+that already has an unlimited record dimension time.
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER   TDIMS, TXLEN
+PARAMETER (TDIMS=2)    ! number of TX dimensions
+PARAMETER (TXLEN = 15) ! length of example string
+INTEGER  NCID
+INTEGER  CHID          ! char position dimension id
+INTEGER  TIMEID        ! record dimension id
+INTEGER  TXID          ! variable ID
+INTEGER  TXDIMS(TDIMS) ! variable shape
+INTEGER  TSTART(TDIMS), TCOUNT(TDIMS)
+CHARACTER*40 TXVAL     ! max length 40
+DATA TXVAL /'example string'/
+   ... 
+TXVAL(TXLEN:TXLEN) = CHAR(0)   ! null terminate
+   ... 
+STATUS = NF_OPEN('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_REDEF(NCID)        ! enter define mode
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+! define character-position dimension for strings of max length 40
+STATUS = NF_DEF_DIM(NCID, "chid", 40, CHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+! define a character-string variable
+TXDIMS(1) = CHID   ! character-position dimension first
+TXDIMS(2) = TIMEID
+STATUS = NF_DEF_VAR(NCID, "tx", NF_CHAR, TDIMS, TXDIMS, TXID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_ENDDEF(NCID) ! leave define mode
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+! write txval into tx netCDF variable in record 3
+TSTART(1) = 1      ! start at beginning of variable
+TSTART(2) = 3      ! record number to write
+TCOUNT(1) = TXLEN  ! number of chars to write
+TCOUNT(2) = 1      ! only write one record
+STATUS = NF_PUT_VARA_TEXT (NCID, TXID, TSTART, TCOUNT, TXVAL)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node Fill Values, NF_RENAME_VAR, Reading and Writing Character String Values, Variables
+ at section Fill Values
+
+What happens when you try to read a value that was never written in an
+open netCDF dataset? You might expect that this should always be an
+error, and that you should get an error message or an error status
+returned. You do get an error if you try to read data from a netCDF
+dataset that is not open for reading, if the variable ID is invalid
+for the specified netCDF dataset, or if the specified indices are not
+properly within the range defined by the dimension lengths of the
+specified variable. Otherwise, reading a value that was not written
+returns a special fill value used to fill in any undefined values when
+a netCDF variable is first written.
+
+You may ignore fill values and use the entire range of a netCDF
+external data type, but in this case you should make sure you write
+all data values before reading them. If you know you will be writing
+all the data before reading it, you can specify that no prefilling of
+variables with fill values will occur by calling NF_SET_FILL before
+writing. This may provide a significant performance gain for netCDF
+writes.
+
+The variable attribute _FillValue may be used to specify the fill
+value for a variable. Their are default fill values for each type,
+defined in the include file netcdf.inc: NF_FILL_CHAR, NF_FILL_INT1
+(same as NF_FILL_BYTE), NF_FILL_INT2 (same as NF_FILL_SHORT),
+NF_FILL_INT, NF_FILL_REAL (same as NF_FILL_FLOAT), and NF_FILL_DOUBLE.
+
+The netCDF byte and character types have different default fill
+values. The default fill value for characters is the zero byte, a
+useful value for detecting the end of variable-length C character
+strings. If you need a fill value for a byte variable, it is
+recommended that you explicitly define an appropriate _FillValue
+attribute, as generic utilities such as ncdump will not assume a
+default fill value for byte variables.
+
+Type conversion for fill values is identical to type conversion for
+other values: attempting to convert a value from one type to another
+type that can't represent the value results in a range error. Such
+errors may occur on writing or reading values from a larger type (such
+as double) to a smaller type (such as float), if the fill value for
+the larger type cannot be represented in the smaller type.
+
+ at node NF_RENAME_VAR, NF_VAR_PAR_ACCESS, Fill Values, Variables
+ at section NF_RENAME_VAR 
+ at findex NF_RENAME_VAR 
+
+The function NF_RENAME_VAR changes the name of a netCDF variable in an
+open netCDF dataset. If the new name is longer than the old name, the
+netCDF dataset must be in define mode. You cannot rename a variable to
+have the name of any existing variable.
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION NF_RENAME_VAR (INTEGER NCID, INTEGER VARID,
+                                CHARACTER*(*) NEWNAM)
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID.
+ 
+ at item NAME
+New name for the specified variable.
+ at end table
+ 
+ at heading Errors 
+
+NF_RENAME_VAR returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+ at item
+The new name is in use as the name of another variable. 
+
+ at item
+The variable ID is invalid for the specified netCDF dataset. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_RENAME_VAR to rename the variable rh to
+rel_hum in an existing netCDF dataset named foo.nc:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER  STATUS, NCID
+INTEGER  RHID             ! variable ID
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_REDEF (NCID)  ! enter definition mode
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_RENAME_VAR (NCID, RHID, 'rel_hum')
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_ENDDEF (NCID) ! leave definition mode
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_VAR_PAR_ACCESS,  , NF_RENAME_VAR, Variables
+ at section Change between Collective and Independent Parallel Access: NF_VAR_PAR_ACCESS
+ at findex NF_VAR_PAR_ACCESS
+ at cindex NF_VAR_PAR_ACCESS, example
+
+The function NF_VAR_PAR_ACCESS changes whether read/write operations
+on a parallel file system are performed collectively or
+independently (the default) on the variable. This function can only be called if the
+file was created with NF_CREATE_PAR (see @ref{NF_CREATE_PAR}) or opened
+with NF_OPEN_PAR (see @ref{NF_OPEN_PAR}).
+
+This function is only available if the netCDF library was built with a
+HDF5 library for which --enable-parallel was used, and which was
+linked (like HDF5) to MPI libraries.
+
+Calling this function affects only the open file - information about
+whether a variable is to be accessed collectively or independently is
+not written to the data file. Every time you open a file on a parallel
+file system, all variables default to independent operations. The change
+a variable to collective lasts only as long as that file is open.
+
+The variable can be changed from collective to independent, and back,
+as often as desired.
+
+ at heading Usage 
+
+ at example
+INTEGER NF_VAR_PAR_ACCESS(INTEGER NCID, INTEGER VARID, INTEGER ACCESS);
+ at end example
+
+ at table @code
+
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN_PAR (see @ref{NF_OPEN_PAR}) or
+NF_CREATE_PAR (see @ref{NF_CREATE_PAR}).
+ 
+ at item varid
+Variable ID.
+ 
+ at item access
+NF_INDEPENDENT to set this variable to independent
+operations. NF_COLLECTIVE to set it to collective operations.
+
+ at end table
+ 
+ at heading Return Values
+
+ at table @code
+
+ at item NF_NOERR
+No error.
+
+ at item NF_ENOTVAR
+No variable found.
+
+ at item NF_ENOTNC4
+Not a netCDF-4 file.
+
+ at item NF_NOPAR
+File not opened for parallel access.
+
+ at end table
+
+ at heading Example
+This example comes from test program nf_test/ftst_parallel.F. For this
+test to be run, netCDF must have been built with a parallel-enabled
+HDF5, and --enable-parallel-tests must have been used when configuring
+netcdf.
+
+ at example
+      retval = nf_var_par_access(ncid, varid, nf_collective)
+      if (retval .ne. nf_noerr) stop 2
+ at end example
+
+ at node Attributes, V2 FORTRAN Transition, Variables, Top
+ at chapter Attributes
+
+ at menu
+* Attributes Introduction::     
+* NF_PUT_ATT_ type::            Create an Attribute
+* NF_INQ_ATT Family::           Get Information about an Attribute
+* NF_GET_ATT_ type::            
+* NF_COPY_ATT::                 
+* NF_RENAME_ATT::               
+* NF_DEL_ATT::                  
+ at end menu
+
+ at node Attributes Introduction, NF_PUT_ATT_ type, Attributes, Attributes
+ at section Attributes Introduction
+
+Attributes may be associated with each netCDF variable to specify such
+properties as units, special values, maximum and minimum valid values,
+scaling factors, and offsets. Attributes for a netCDF dataset are
+defined when the dataset is first created, while the netCDF dataset is
+in define mode. Additional attributes may be added later by reentering
+define mode. A netCDF attribute has a netCDF variable to which it is
+assigned, a name, a type, a length, and a sequence of one or more
+values. An attribute is designated by its variable ID and name. When
+an attribute name is not known, it may be designated by its variable
+ID and number in order to determine its name, using the function
+NF_INQ_ATTNAME.
+
+The attributes associated with a variable are typically defined
+immediately after the variable is created, while still in define
+mode. The data type, length, and value of an attribute may be changed
+even when in data mode, as long as the changed attribute requires no
+more space than the attribute as originally defined.
+
+It is also possible to have attributes that are not associated with
+any variable. These are called global attributes and are identified by
+using NF_GLOBAL as a variable pseudo-ID. Global attributes are usually
+related to the netCDF dataset as a whole and may be used for purposes
+such as providing a title or processing history for a netCDF dataset.
+
+Attributes are much more useful when they follow established community
+conventions. @xref{Attribute Conventions,,,netcdf, @value{n-man}}.
+
+Operations supported on attributes are:
+ at itemize
+
+ at item
+Create an attribute, given its variable ID, name, data type, length, and value. 
+
+ at item
+Get attribute's data type and length from its variable ID and name. 
+
+ at item
+Get attribute's value from its variable ID and name. 
+
+ at item
+Copy attribute from one netCDF variable to another. 
+
+ at item
+Get name of attribute from its number. 
+
+ at item
+Rename an attribute. 
+
+ at item
+Delete an attribute. 
+ at end itemize
+
+ at node NF_PUT_ATT_ type, NF_INQ_ATT Family, Attributes Introduction, Attributes
+ at section NF_PUT_ATT_ @var{type}
+ at findex NF_PUT_ATT_ type
+
+The function NF_PUT_ATT_ @var{type} adds or changes a variable attribute or
+global attribute of an open netCDF dataset. If this attribute is new,
+or if the space required to store the attribute is greater than
+before, the netCDF dataset must be in define mode.
+
+ at heading Usage 
+
+Although it's possible to create attributes of all types, text and
+double attributes are adequate for most purposes.
+
+ at example
+INTEGER FUNCTION  NF_PUT_ATT_TEXT  (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME, INTEGER LEN,
+                                    CHARACTER*(*) TEXT)
+INTEGER FUNCTION  NF_PUT_ATT_INT1  (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME, INTEGER XTYPE,
+                                    LEN, INTEGER*1 I1VALS(*))
+INTEGER FUNCTION  NF_PUT_ATT_INT2  (INTEGER NCID, INTEGER VARID,
+                                     CHARACTER*(*) NAME, INTEGER XTYPE,
+                                    LEN, INTEGER*2 I2VALS(*))
+INTEGER FUNCTION  NF_PUT_ATT_INT   (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME, INTEGER XTYPE,
+                                    LEN, INTEGER IVALS(*))
+INTEGER FUNCTION  NF_PUT_ATT_REAL  (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME, INTEGER XTYPE,
+                                    LEN, REAL RVALS(*))
+INTEGER FUNCTION  NF_PUT_ATT_DOUBLE(INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME, INTEGER XTYPE,
+                                    LEN, DOUBLE DVALS(*))
+INTEGER FUNCTION  NF_PUT_ATT       (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME, INTEGER XTYPE,
+                                    LEN, * VALS(*))
+
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID of the variable to which the attribute will be assigned or
+NF_GLOBAL for a global attribute.
+ 
+ at item NAME
+Attribute name.  Attribute name conventions are assumed by some netCDF
+generic applications, e.g., @samp{units} as the name for a string
+attribute that gives the units for a netCDF variable. @xref{Attribute
+Conventions,,,netcdf, @value{n-man}}.
+ 
+ at item XTYPE
+One of the set of predefined netCDF external data types. The type of
+this parameter, NF_TYPE, is defined in the netCDF header file. The
+valid netCDF external data types are NF_BYTE, NF_CHAR, NF_SHORT,
+NF_INT, NF_FLOAT, and NF_DOUBLE. Although it's possible to create
+attributes of all types, NF_CHAR and NF_DOUBLE attributes are adequate
+for most purposes.
+ 
+ at item LEN
+Number of values provided for the attribute.
+ 
+ at item TEXT
+ at itemx I1VALS
+ at itemx I2VALS
+ at itemx IVALS
+ at itemx RVALS
+ at itemx DVALS
+ at itemx VALS
+An array of LEN attribute values. The data should be of a type
+appropriate for the function called. You cannot write CHARACTER data
+into a numeric attribute or numeric data into a text attribute. For
+numeric data, if the type of data differs from the attribute type,
+type conversion will occur @xref{Type Conversion,,, netcdf, The
+NetCDF Users Guide}.
+
+ at end table
+ 
+ at heading Errors 
+
+NF_PUT_ATT_ @var{type} returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The variable ID is invalid for the specified netCDF dataset. 
+
+ at item
+The specified netCDF type is invalid. 
+
+ at item
+The specified length is negative. 
+
+ at item
+The specified open netCDF dataset is in data mode and the specified
+attribute would expand.
+
+ at item
+The specified open netCDF dataset is in data mode and the specified
+attribute does not already exist.
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+
+ at item
+The number of attributes for this variable exceeds NF_MAX_ATTRS. 
+
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_PUT_ATT_DOUBLE to add a variable attribute
+named valid_range for a netCDF variable named rh and a global
+attribute named title to an existing netCDF dataset named foo.nc:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS, NCID
+INTEGER RHID                 ! variable ID
+DOUBLE RHRNGE(2)
+DATA RHRNGE /0.0D0, 100.0D0/
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_REDEF (NCID)     ! enter define mode
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_PUT_ATT_DOUBLE (NCID, RHID, 'valid_range', NF_DOUBLE, &
+                            2, RHRNGE)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_PUT_ATT_TEXT (NCID, NF_GLOBAL, 'title', 19, 
+                          'example netCDF dataset')
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_ENDDEF (NCID)    ! leave define mode
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_INQ_ATT Family, NF_GET_ATT_ type, NF_PUT_ATT_ type, Attributes
+ at section NF_INQ_ATT Family
+ at findex NF_INQ_ATT Family
+
+This family of functions returns information about a netCDF
+attribute. All but one of these functions require the variable ID and
+attribute name; the exception is NF_INQ_ATTNAME. Information about an
+attribute includes its type, length, name, and number. See the
+NF_GET_ATT family for getting attribute values.
+
+The function NF_INQ_ATTNAME gets the name of an attribute, given its
+variable ID and number. This function is useful in generic
+applications that need to get the names of all the attributes
+associated with a variable, since attributes are accessed by name
+rather than number in all other attribute functions. The number of an
+attribute is more volatile than the name, since it can change when
+other attributes of the same variable are deleted. This is why an
+attribute number is not called an attribute ID.
+
+The function NF_INQ_ATT returns the attribute's type and length. The
+other functions each return just one item of information about an
+attribute.
+
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION NF_INQ_ATT    (INTEGER NCID, INTEGER VARID,
+                                CHARACTER*(*) NAME, INTEGER xtype,
+                                INTEGER len)
+INTEGER FUNCTION NF_INQ_ATTTYPE(INTEGER NCID, INTEGER VARID,
+                                CHARACTER*(*) NAME, INTEGER xtype)
+INTEGER FUNCTION NF_INQ_ATTLEN (INTEGER NCID, INTEGER VARID,
+                                CHARACTER*(*) NAME, INTEGER len)
+INTEGER FUNCTION NF_INQ_ATTNAME(INTEGER NCID, INTEGER VARID,
+                                INTEGER ATTNUM, CHARACTER*(*) name)
+INTEGER FUNCTION NF_INQ_ATTID  (INTEGER NCID, INTEGER VARID,
+                                CHARACTER*(*) NAME, INTEGER attnum)
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID of the attribute's variable, or NF_GLOBAL for a global
+attribute.
+ 
+ at item NAME
+Attribute name. For NF_INQ_ATTNAME, this is a pointer to the location
+for the returned attribute name.
+ 
+ at item xtype
+Returned attribute type, one of the set of predefined netCDF external
+data types. The valid netCDF external data types are NF_BYTE, NF_CHAR,
+NF_SHORT, NF_INT, NF_FLOAT, and NF_DOUBLE.
+ 
+ at item len
+Returned number of values currently stored in the attribute. For a
+string-valued attribute, this is the number of characters in the
+string.
+ 
+ at item attnum
+For NF_INQ_ATTNAME, the input attribute number; for NF_INQ_ATTID, the
+returned attribute number. The attributes for each variable are
+numbered from 1 (the first attribute) to NATTS, where NATTS is the
+number of attributes for the variable, as returned from a call to
+NF_INQ_VARNATTS.
+
+(If you already know an attribute name, knowing its number is not very
+useful, because accessing information about an attribute requires its
+name.)
+ at end table
+
+ at heading Errors 
+
+Each function returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+ at itemize
+
+ at item
+The variable ID is invalid for the specified netCDF dataset. 
+
+ at item
+The specified attribute does not exist. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+
+ at item
+For NF_INQ_ATTNAME, the specified attribute number is negative or more
+than the number of attributes defined for the specified variable.
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_INQ_ATT to find out the type and length of
+a variable attribute named valid_range for a netCDF variable named rh
+and a global attribute named title in an existing netCDF dataset named
+foo.nc:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS, NCID
+INTEGER RHID               ! variable ID
+INTEGER VRLEN, TLEN        ! attribute lengths
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_ATTLEN (NCID, RHID, 'valid_range', VRLEN)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_INQ_ATTLEN (NCID, NF_GLOBAL, 'title', TLEN)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_GET_ATT_ type, NF_COPY_ATT, NF_INQ_ATT Family, Attributes
+ at section NF_GET_ATT_ @var{type} 
+ at findex NF_GET_ATT_ type 
+
+Members of the NF_GET_ATT_ @var{type} family of functions get the value(s)
+of a netCDF attribute, given its variable ID and name.
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION NF_GET_ATT_TEXT   (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME,
+                                    CHARACTER*(*) text)
+INTEGER FUNCTION NF_GET_ATT_INT1   (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME,
+                                    INTEGER*1 i1vals(*))
+INTEGER FUNCTION NF_GET_ATT_INT2   (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME,
+                                    INTEGER*2 i2vals(*))
+INTEGER FUNCTION NF_GET_ATT_INT    (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME,
+                                    INTEGER ivals(*))
+INTEGER FUNCTION NF_GET_ATT_REAL   (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME,
+                                    REAL rvals(*))
+INTEGER FUNCTION NF_GET_ATT_DOUBLE (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME,
+                                    DOUBLE dvals(*))
+INTEGER FUNCTION NF_GET_ATT        (INTEGER NCID, INTEGER VARID,
+                                    CHARACTER*(*) NAME, * vals(*))
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+Variable ID of the attribute's variable, or NF_GLOBAL for a global attribute.
+ 
+ at item NAME
+Attribute name.
+ 
+ at item TEXT
+ at itemx I1VALS
+ at itemx I2VALS
+ at itemx IVALS
+ at itemx RVALS
+ at itemx DVALS
+ at itemx VALS
+Returned attribute values. All elements of the vector of attribute
+values are returned, so you must provide enough space to hold them. If
+you don't know how much space to reserve, call NF_INQ_ATTLEN first to
+find out the length of the attribute. You cannot read character data
+from a numeric variable or numeric data from a text variable. For
+numeric data, if the type of data differs from the netCDF variable
+type, type conversion will occur. @xref{Type Conversion,,, netcdf, The
+ at value{n-man}}.
+
+ at end table
+ 
+ at heading Errors 
+
+NF_GET_ATT_ @var{type} returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+ at itemize
+
+ at item
+The variable ID is invalid for the specified netCDF dataset. 
+
+ at item
+The specified attribute does not exist. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset. 
+
+ at item
+One or more of the attribute values are out of the range of values
+representable by the desired type.
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_GET_ATT_DOUBLE to determine the values of
+a variable attribute named valid_range for a netCDF variable named rh
+and a global attribute named title in an existing netCDF dataset named
+foo.nc. In this example, it is assumed that we don't know how many
+values will be returned, but that we do know the types of the
+attributes. Hence, to allocate enough space to store them, we must
+first inquire about the length of the attributes.
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+PARAMETER (MVRLEN=3)           ! max number of "valid_range" values
+PARAMETER (MTLEN=80)           ! max length of "title" attribute
+INTEGER STATUS, NCID
+INTEGER RHID                   ! variable ID
+INTEGER VRLEN, TLEN            ! attribute lengths
+DOUBLE PRECISION VRVAL(MVRLEN) ! vr attribute values
+CHARACTER*80 TITLE             ! title attribute values
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+! find out attribute lengths, to make sure we have enough space
+STATUS = NF_INQ_ATTLEN (NCID, RHID, 'valid_range', VRLEN)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_INQ_ATTLEN (NCID, NF_GLOBAL, 'title', TLEN)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+! get attribute values, if not too big
+IF (VRLEN .GT. MVRLEN) THEN
+    WRITE (*,*) 'valid_range attribute too big!'
+    CALL EXIT
+ELSE
+    STATUS = NF_GET_ATT_DOUBLE (NCID, RHID, 'valid_range', VRVAL)
+    IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ENDIF
+IF (TLEN .GT. MTLEN) THEN
+    WRITE (*,*) 'title attribute too big!'
+    CALL EXIT
+ELSE
+    STATUS = NF_GET_ATT_TEXT (NCID, NF_GLOBAL, 'title', TITLE)
+    IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ENDIF
+ at end example
+
+ at node NF_COPY_ATT, NF_RENAME_ATT, NF_GET_ATT_ type, Attributes
+ at section NF_COPY_ATT 
+ at findex NF_COPY_ATT 
+
+The function NF_COPY_ATT copies an attribute from one open netCDF
+dataset to another. It can also be used to copy an attribute from one
+variable to another within the same netCDF.
+
+If used to copy an attribute of user-defined type, then that
+user-defined type must already be defined in the target file. In the
+case of user-defined attributes, enddef/redef is called for 
+ncid_in and ncid_out if they are in define mode. (This is the ensure
+that all user-defined types are committed to the file(s) before the
+copy is attempted.)
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION NF_COPY_ATT (INTEGER NCID_IN, INTEGER VARID_IN,
+                              CHARACTER*(*) NAME, INTEGER NCID_OUT,
+                              INTEGER VARID_OUT)
+ at end example
+
+ at table @code
+ at item NCID_IN
+The netCDF ID of an input netCDF dataset from which the attribute
+will be copied, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID_IN
+ID of the variable in the input netCDF dataset from which the
+attribute will be copied, or NF_GLOBAL for a global attribute.
+ 
+ at item NAME
+Name of the attribute in the input netCDF dataset to be copied.
+ 
+ at item NCID_OUT
+The netCDF ID of the output netCDF dataset to which the attribute
+will be copied, from a previous call to NF_OPEN or NF_CREATE. It is
+permissible for the input and output netCDF IDs to be the same. The
+output netCDF dataset should be in define mode if the attribute to be
+copied does not already exist for the target variable, or if it would
+cause an existing target attribute to grow.
+ 
+ at item VARID_OUT
+ID of the variable in the output netCDF dataset to which the
+attribute will be copied, or NF_GLOBAL to copy to a global attribute.
+ at end table
+ 
+ at heading Errors 
+
+NF_COPY_ATT returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The input or output variable ID is invalid for the specified netCDF
+dataset.
+
+ at item
+The specified attribute does not exist. 
+
+ at item
+The output netCDF is not in define mode and the attribute is new for
+the output dataset is larger than the existing attribute.
+
+ at item
+The input or output netCDF ID does not refer to an open netCDF
+dataset.
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_COPY_ATT to copy the variable attribute
+units from the variable rh in an existing netCDF dataset named foo.nc
+to the variable avgrh in another existing netCDF dataset named bar.nc,
+assuming that the variable avgrh already exists, but does not yet have
+a units attribute:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS             ! error status
+INTEGER NCID1, NCID2       ! netCDF IDs
+INTEGER RHID, AVRHID       ! variable IDs
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_NOWRITE, NCID1)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_OPEN ('bar.nc', NF_WRITE, NCID2)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID1, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_INQ_VARID (NCID2, 'avgrh', AVRHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_REDEF (NCID2)  ! enter define mode
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+! copy variable attribute from "rh" to "avgrh"
+STATUS = NF_COPY_ATT (NCID1, RHID, 'units', NCID2, AVRHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_ENDDEF (NCID2) ! leave define mode
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_RENAME_ATT, NF_DEL_ATT, NF_COPY_ATT, Attributes
+ at section NF_RENAME_ATT 
+ at findex NF_RENAME_ATT 
+
+The function NF_RENAME_ATT changes the name of an attribute. If the
+new name is longer than the original name, the netCDF dataset must be
+in define mode. You cannot rename an attribute to have the same name
+as another attribute of the same variable.
+
+ at heading Usage 
+ at example
+INTEGER FUNCTION NF_RENAME_ATT (INTEGER NCID, INTEGER VARID,
+                                CHARACTER*(*) NAME,
+                                CHARACTER*(*) NEWNAME)
+ at end example
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE
+ 
+ at item VARID
+ID of the attribute's variable, or NF_GLOBAL for a global attribute
+ 
+ at item NAME
+The current attribute name.
+ 
+ at item NEWNAME
+The new name to be assigned to the specified attribute. If the new
+name is longer than the current name, the netCDF dataset must be in
+define mode.
+ at end table
+ 
+ at heading Errors 
+
+NF_RENAME_ATT returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+ at itemize
+
+ at item
+The specified variable ID is not valid. 
+
+ at item
+The new attribute name is already in use for another attribute of the
+specified variable.
+
+ at item
+The specified netCDF dataset is in data mode and the new name is
+longer than the old name.
+
+ at item
+The specified attribute does not exist. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset.
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_RENAME_ATT to rename the variable
+attribute units to Units for a variable rh in an existing netCDF
+dataset named foo.nc:
+
+ at example
+INCLUDE "netcdf.inc"
+   ... 
+INTEGER STATUS   ! error status
+INTEGER NCID     ! netCDF ID
+INTEGER RHID     ! variable ID
+   ... 
+STATUS = NF_OPEN ("foo.nc", NF_NOWRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, "rh", RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+! rename attribute
+STATUS = NF_RENAME_ATT (NCID, RHID, "units", "Units")
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node NF_DEL_ATT,  , NF_RENAME_ATT, Attributes
+ at section NF_DEL_ATT 
+ at findex NF_DEL_ATT 
+
+The function NF_DEL_ATT deletes a netCDF attribute from an open netCDF
+dataset. The netCDF dataset must be in define mode.
+
+ at heading Usage 
+INTEGER FUNCTION NF_DEL_ATT (INTEGER NCID, INTEGER VARID,
+                             CHARACTER*(*) NAME)
+
+ at table @code
+ at item NCID
+NetCDF ID, from a previous call to NF_OPEN or NF_CREATE.
+ 
+ at item VARID
+ID of the attribute's variable, or NF_GLOBAL for a global attribute.
+ 
+ at item NAME
+The name of the attribute to be deleted.
+ at end table
+ 
+ at heading Errors 
+
+NF_DEL_ATT returns the value NF_NOERR if no errors
+occurred. Otherwise, the returned status indicates an error. Possible
+causes of errors include:
+
+ at itemize
+
+ at item
+The specified variable ID is not valid. 
+
+ at item
+The specified netCDF dataset is in data mode. 
+
+ at item
+The specified attribute does not exist. 
+
+ at item
+The specified netCDF ID does not refer to an open netCDF dataset.
+ at end itemize
+
+ at heading Example 
+
+Here is an example using NF_DEL_ATT to delete the variable attribute
+Units for a variable rh in an existing netCDF dataset named foo.nc:
+
+ at example
+INCLUDE 'netcdf.inc'
+   ... 
+INTEGER STATUS            ! error status
+INTEGER NCID              ! netCDF ID
+INTEGER RHID              ! variable ID
+   ... 
+STATUS = NF_OPEN ('foo.nc', NF_WRITE, NCID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+STATUS = NF_INQ_VARID (NCID, 'rh', RHID)
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+   ... 
+! delete attribute
+STATUS = NF_REDEF (NCID)  ! enter define mode
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_DEL_ATT (NCID, RHID, 'Units')
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+STATUS = NF_ENDDEF (NCID) ! leave define mode
+IF (STATUS .NE. NF_NOERR) CALL HANDLE_ERR(STATUS)
+ at end example
+
+ at node V2 FORTRAN Transition, Summary of FORTRAN 77 Interface, Attributes, Top
+ at appendix NetCDF 2 to NetCDF 3 Fortran 77 Transition Guide
+
+ at section Overview of FORTRAN interface changes
+
+NetCDF version 3 includes a complete rewrite of the netCDF
+library. It is about twice as fast as the previous version. The
+netCDF file format is unchanged, so files written with version 3 can
+be read with version 2 code and vice versa.
+
+The core library is now written in ANSI C. You must have an ANSI C
+compiler to compile this version. The FORTRAN interface is layered on
+top of the C interface using a different technique than was used in
+netCDF-2.
+
+Rewriting the library offered an opportunity to implement improved C
+and FORTRAN interfaces that provide some significant benefits:
+
+ at itemize
+
+ at item
+type safety, by eliminating the need to use type punning in arguments;
+
+ at item
+automatic type conversions, by eliminating the undesirable coupling
+between the language-independent external netCDF types (NF_BYTE, ...,
+NF_DOUBLE) and language-dependent internal data types (INT*1, ...,
+DOUBLE PRECISION);
+
+ at item
+support for future enhancements, by eliminating obstacles to the clean
+addition of support for packed data and multithreading;
+
+ at item
+more standard error behavior, by uniformly communicating an error
+status back to the calling program in the return value of each
+function.
+
+ at end itemize
+
+It is not necessary to rewrite programs that use the version 2
+FORTRAN interface, because the netCDF-3 library includes a backward
+compatibility interface that supports all the old functions, globals,
+and behavior. We are hoping that the benefits of the new interface
+will be an incentive to use it in new netCDF applications. It is
+possible to convert old applications to the new interface
+incrementally, replacing netCDF-2 calls with the corresponding
+netCDF-3 calls one at a time.
+
+Other changes in the implementation of netCDF result in improved
+portability, maintainability, and performance on most platforms. A
+clean separation between I/O and type layers facilitates
+platform-specific optimizations. The new library no longer uses a
+vendor-provided XDR library, which simplifies linking programs that
+use netCDF and speeds up data access significantly in most cases.
+
+ at section The New FORTRAN Interface
+
+First, here's an example of FORTRAN code that uses the netCDF-2
+interface:
+
+ at example
+! Use a buffer big enough for values of any type
+DOUBLE PRECISION DBUF(NDATA)
+REAL RBUF(NDATA)
+...
+EQUIVALENCE (RBUF, DBUF), ...
+INT XTYPE     ! to hold the actual type of the data
+INT STATUS    ! for error status
+! Get the actual data type
+CALL NCVINQ(NCID, VARID, ...,XTYPE, ...)
+...
+! Get the data
+CALL NCVGT(NCID, VARID, START, COUNT, DBUF, STATUS)
+IF(STATUS .NE. NCNOERR) THEN
+   PRINT *, 'Cannot get data, error code =', STATUS
+   ! Deal with error
+   ...
+ENDIF
+IF (XTYPE .EQ. NCDOUBLE) THEN
+   CALL DANALYZE(DBUF)
+ELSEIF (XTYPE .EQ. NCFLOAT) THEN
+   CALL RANALYZE(RBUF)
+...
+ENDIF
+ at end example
+
+Here's how you might handle this with the new netCDF-3 FORTRAN
+interface:
+
+ at example
+! I want to use doubles for my analysis
+DOUBLE PRECISION DBUF(NDATA)
+INT STATUS
+! So I use a function that gets the data as doubles.
+STATUS = NF_GET_VARA_DOUBLE(NCID, VARID, START, COUNT, DBUF)
+IF(STATUS .NE. NF_NOERR) THEN
+   PRINT *, 'Cannot get data, ', NF_STRERROR(STATUS)
+   ! Deal with error
+   ...
+ENDIF
+CALL DANALYZE(DBUF)
+ at end example
+
+The example above illustrates changes in function names, data type
+conversion, and error handling, discussed in detail in the sections
+below.
+
+ at section Function Naming Conventions
+
+The netCDF-3 Fortran 77 library employs a naming convention intended to
+make netCDF programs more readable. For example, the name of the
+function to rename a variable is now NF_RENAME_VAR instead of the
+previous NCVREN.
+
+All netCDF-3 FORTRAN function names begin with the NF_ prefix. The
+second part of the name is a verb, like GET, PUT, INQ (for inquire),
+or OPEN. The third part of the name is typically the object of the
+verb: for example DIM, VAR, or ATT for functions dealing with
+dimensions, variables, or attributes. To distinguish the various I/O
+operations for variables, a single character modifier is appended to
+VAR:
+
+ at itemize
+
+ at item
+VAR entire variable access
+
+ at item
+VAR1 single value access
+
+ at item
+VARA array or array section access
+
+ at item
+VARS strided access to a subsample of values
+
+ at item
+VARM mapped access to values not contiguous in memory 
+
+ at end itemize
+
+At the end of the name for variable and attribute functions, there is
+a component indicating the type of the final argument: TEXT, INT1,
+INT2, INT, REAL, or DOUBLE. This part of the function name indicates
+the type of the data container you are using in your program:
+character string, 1-byte integer, and so on.
+
+Also, all PARAMETER names in the public FORTRAN interface begin with
+the prefix NF_. For example, the PARAMETER which was formerly
+MAXNCNAM is now NF_MAX_NAME, and the former FILFLOAT is now
+NF_FILL_FLOAT.
+
+As previously mentioned, all the old names are still supported for
+backward compatibility.
+
+ at section Type Conversion
+
+With the new interface, users need not be aware of the external type
+of numeric variables, since automatic conversion to or from any
+desired numeric type is now available. You can use this feature to
+simplify code, by making it independent of external types. The
+elimination of type punning prevents some kinds of type errors that
+could occur with the previous interface. Programs may be made more
+robust with the new interface, because they need not be changed to
+accommodate a change to the external type of a variable.
+
+If conversion to or from an external numeric type is necessary, it is
+handled by the library. This automatic conversion and separation of
+external data representation from internal data types will become
+even more important in netCDF version 4, when new external types will
+be added for packed data for which there is no natural corresponding
+internal type, for example, arrays of 11-bit values.
+
+Converting from one numeric type to another may result in an error if
+the target type is not capable of representing the converted
+value. (In netCDF-2, such overflows can only happen in the XDR
+layer.) For example, a REAL may not be able to hold data stored
+externally as an NF_DOUBLE (an IEEE floating-point number). When
+accessing an array of values, an NF_ERANGE error is returned if one
+or more values are out of the range of representable values, but
+other values are converted properly.
+
+Note that mere loss of precision in type conversion does not return
+an error. Thus, if you read double precision values into an INTEGER,
+for example, no error results unless the magnitude of the double
+precision value exceeds the representable range of INTEGERs on your
+platform. Similarly, if you read a large integer into a REAL
+incapable of representing all the bits of the integer in its
+mantissa, this loss There are two new functions in netCDF-3 that
+don't correspond to any netCDF-2 functions: NF_INQ_LIBVERS and
+NF_STRERROR. The version ation
+The previous implementation returned an error when the same dimension
+was used more than once in specifying the shape of a variable in
+ncvardef. This restriction is relaxed in the netCDF-3 implementation,
+because an autocorrelation matrix is a good example where using the
+same dimension twice makes sense.
+
+In the new interface, units for the IMAP argument to the NF_PUT_VARM
+and NF_GET_VARM families of functions are now in terms of the number
+of data elements of the desired internal type, not in terms of bytes
+as in the netCDF version-2 mapped access interfaces.
+
+Following is a table of netCDF-2 function names and names of the
+corresponding netCDF-3 functions. For parameter lists of netCDF-2
+functions, see the netCDF-2 User's Guide.
+
+ at table @code
+
+ at item NCABOR
+NF_ABORT
+
+ at item NCACPY
+NF_COPY_ATT
+
+ at item NCADEL
+NF_DEL_ATT
+
+ at item NCAGT
+NF_GET_ATT_DOUBLE, NF_GET_ATT_REAL, NF_GET_ATT_INT, NF_GET_ATT_INT1,
+NF_GET_ATT_INT2
+
+ at item NCAGTC
+NF_GET_ATT_TEXT
+
+ at item NCAINQ
+NF_INQ_ATT, NF_INQ_ATTID, NF_INQ_ATTLEN, NF_INQ_ATTTYPE
+
+ at item NCANAM
+NF_INQ_ATTNAME
+
+ at item NCAPT
+NF_PUT_ATT_DOUBLE, NF_PUT_ATT_REAL, NF_PUT_ATT_INT,
+NF_PUT_ATT_INT1NF_PUT
+
+ at end table
+
+ at node Summary of FORTRAN 77 Interface, Combined Index, V2 FORTRAN Transition, Top
+ at appendix Summary of FORTRAN 77 Interface
+
+Input parameters are in upper case, output parameters are in lower
+case. The FORTRAN types of all the parameters are listed
+alphabetically by parameter name below the function declarations.
+
+ at example
+CHARACTER*80 FUNCTION  NF_INQ_LIBVERS()
+CHARACTER*80 FUNCTION  NF_STRERROR  (NCERR)
+INTEGER FUNCTION  NF_CREATE         (PATH, CMODE, ncid)
+INTEGER FUNCTION  NF_OPEN           (PATH, MODE, ncid)
+INTEGER FUNCTION  NF_SET_FILL       (NCID, FILLMODE, old_mode)
+INTEGER FUNCTION  NF_REDEF          (NCID)
+INTEGER FUNCTION  NF_ENDDEF         (NCID)
+INTEGER FUNCTION  NF_SYNC           (NCID)
+INTEGER FUNCTION  NF_ABORT          (NCID)
+INTEGER FUNCTION  NF_CLOSE          (NCID)
+INTEGER FUNCTION  NF_INQ            (NCID, ndims, nvars, ngatts,
+                                     unlimdimid)
+INTEGER FUNCTION  NF_INQ_NDIMS      (NCID, ndims)
+INTEGER FUNCTION  NF_INQ_NVARS      (NCID, nvars)
+INTEGER FUNCTION  NF_INQ_NATTS      (NCID, ngatts)
+INTEGER FUNCTION  NF_INQ_UNLIMDIM   (NCID, unlimdimid)
+INTEGER FUNCTION  NF_DEF_DIM        (NCID, NAME, LEN, dimid)
+INTEGER FUNCTION  NF_INQ_DIMID      (NCID, NAME, dimid)
+INTEGER FUNCTION  NF_INQ_DIM        (NCID, DIMID, name, len)
+INTEGER FUNCTION  NF_INQ_DIMNAME    (NCID, DIMID, name)
+INTEGER FUNCTION  NF_INQ_DIMLEN     (NCID, DIMID, len)
+INTEGER FUNCTION  NF_RENAME_DIM     (NCID, DIMID, NAME)
+
+INTEGER FUNCTION  NF_DEF_VAR        (NCID, NAME, XTYPE, NDIMS, DIMIDS, 
+                                     varid)
+INTEGER FUNCTION  NF_INQ_VAR        (NCID, VARID, name, xtype, ndims, 
+                                     dimids, natts)
+INTEGER FUNCTION  NF_INQ_VARID      (NCID, NAME, varid)
+INTEGER FUNCTION  NF_INQ_VARNAME    (NCID, VARID, name)
+INTEGER FUNCTION  NF_INQ_VARTYPE    (NCID, VARID, xtype)
+INTEGER FUNCTION  NF_INQ_VARNDIMS   (NCID, VARID, ndims)
+INTEGER FUNCTION  NF_INQ_VARDIMID   (NCID, VARID, DIMIDS)
+INTEGER FUNCTION  NF_INQ_VARNATTS   (NCID, VARID, natts)
+INTEGER FUNCTION  NF_RENAME_VAR     (NCID, VARID, NAME)
+INTEGER FUNCTION  NF_PUT_VAR_TEXT   (NCID, VARID, TEXT)
+INTEGER FUNCTION  NF_GET_VAR_TEXT   (NCID, VARID, text)
+INTEGER FUNCTION  NF_PUT_VAR_INT1   (NCID, VARID, I1VAL)
+INTEGER FUNCTION  NF_GET_VAR_INT1   (NCID, VARID, i1val)
+INTEGER FUNCTION  NF_PUT_VAR_INT2   (NCID, VARID, I2VAL)
+INTEGER FUNCTION  NF_GET_VAR_INT2   (NCID, VARID, i2val)
+INTEGER FUNCTION  NF_PUT_VAR_INT    (NCID, VARID, IVAL)
+INTEGER FUNCTION  NF_GET_VAR_INT    (NCID, VARID, ival)
+INTEGER FUNCTION  NF_PUT_VAR_REAL   (NCID, VARID, RVAL)
+INTEGER FUNCTION  NF_GET_VAR_REAL   (NCID, VARID, rval)
+INTEGER FUNCTION  NF_PUT_VAR_DOUBLE (NCID, VARID, DVAL)
+INTEGER FUNCTION  NF_GET_VAR_DOUBLE (NCID, VARID, dval)
+INTEGER FUNCTION  NF_PUT_VAR1_TEXT  (NCID, VARID, INDEX, TEXT)
+INTEGER FUNCTION  NF_GET_VAR1_TEXT  (NCID, VARID, INDEX, text)
+INTEGER FUNCTION  NF_PUT_VAR1_INT1  (NCID, VARID, INDEX, I1VAL)
+INTEGER FUNCTION  NF_GET_VAR1_INT1  (NCID, VARID, INDEX, i1val)
+INTEGER FUNCTION  NF_PUT_VAR1_INT2  (NCID, VARID, INDEX, I2VAL)
+INTEGER FUNCTION  NF_GET_VAR1_INT2  (NCID, VARID, INDEX, i2val)
+INTEGER FUNCTION  NF_PUT_VAR1_INT   (NCID, VARID, INDEX, IVAL)
+INTEGER FUNCTION  NF_GET_VAR1_INT   (NCID, VARID, INDEX, ival)
+INTEGER FUNCTION  NF_PUT_VAR1_REAL  (NCID, VARID, INDEX, RVAL)
+INTEGER FUNCTION  NF_GET_VAR1_REAL  (NCID, VARID, INDEX, rval)
+INTEGER FUNCTION  NF_PUT_VAR1_DOUBLE(NCID, VARID, INDEX, DVAL)
+INTEGER FUNCTION  NF_GET_VAR1_DOUBLE(NCID, VARID, INDEX, dval)
+INTEGER FUNCTION  NF_PUT_VARA_TEXT  (NCID, VARID, START, COUNT, TEXT)
+INTEGER FUNCTION  NF_GET_VARA_TEXT  (NCID, VARID, START, COUNT, text)
+INTEGER FUNCTION  NF_PUT_VARA_INT1  (NCID, VARID, START, COUNT, I1VALS)
+INTEGER FUNCTION  NF_GET_VARA_INT1  (NCID, VARID, START, COUNT, i1vals)
+INTEGER FUNCTION  NF_PUT_VARA_INT2  (NCID, VARID, START, COUNT, I2VALS)
+INTEGER FUNCTION  NF_GET_VARA_INT2  (NCID, VARID, START, COUNT, i2vals)
+INTEGER FUNCTION  NF_PUT_VARA_INT   (NCID, VARID, START, COUNT, IVALS)
+INTEGER FUNCTION  NF_GET_VARA_INT   (NCID, VARID, START, COUNT, ivals)
+INTEGER FUNCTION  NF_PUT_VARA_REAL  (NCID, VARID, START, COUNT, RVALS)
+INTEGER FUNCTION  NF_GET_VARA_REAL  (NCID, VARID, START, COUNT, rvals)
+INTEGER FUNCTION  NF_PUT_VARA_DOUBLE(NCID, VARID, START, COUNT, DVALS)
+INTEGER FUNCTION  NF_GET_VARA_DOUBLE(NCID, VARID, START, COUNT, dvals)
+INTEGER FUNCTION  NF_PUT_VARS_TEXT  (NCID, VARID, START, COUNT, STRIDE,
+                                     TEXT)
+INTEGER FUNCTION  NF_GET_VARS_TEXT  (NCID, VARID, START, COUNT, STRIDE,
+                                     text)
+INTEGER FUNCTION  NF_PUT_VARS_INT1  (NCID, VARID, START, COUNT, STRIDE,
+                                     I1VALS)
+INTEGER FUNCTION  NF_GET_VARS_INT1  (NCID, VARID, START, COUNT, STRIDE,
+                                     i1vals)
+INTEGER FUNCTION  NF_PUT_VARS_INT2  (NCID, VARID, START, COUNT, STRIDE,
+                                     I2VALS)
+INTEGER FUNCTION  NF_GET_VARS_INT2  (NCID, VARID, START, COUNT, STRIDE,
+                                     i2vals)
+INTEGER FUNCTION  NF_PUT_VARS_INT   (NCID, VARID, START, COUNT, STRIDE,
+                                     IVALS)
+INTEGER FUNCTION  NF_GET_VARS_INT   (NCID, VARID, START, COUNT, STRIDE,
+                                     ivals)
+INTEGER FUNCTION  NF_PUT_VARS_REAL  (NCID, VARID, START, COUNT, STRIDE,
+                                     RVALS)
+INTEGER FUNCTION  NF_GET_VARS_REAL  (NCID, VARID, START, COUNT, STRIDE,
+                                     rvals)
+INTEGER FUNCTION  NF_PUT_VARS_DOUBLE(NCID, VARID, START, COUNT, STRIDE,
+                                     DVALS)
+INTEGER FUNCTION  NF_GET_VARS_DOUBLE(NCID, VARID, START, COUNT, STRIDE,
+                                     dvals)
+INTEGER FUNCTION  NF_PUT_VARM_TEXT  (NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, TEXT)
+INTEGER FUNCTION  NF_GET_VARM_TEXT  (NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, text)
+INTEGER FUNCTION  NF_PUT_VARM_INT1  (NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, I1VALS)
+INTEGER FUNCTION  NF_GET_VARM_INT1  (NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, i1vals)
+INTEGER FUNCTION  NF_PUT_VARM_INT2  (NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, I2VALS)
+INTEGER FUNCTION  NF_GET_VARM_INT2  (NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, i2vals)
+INTEGER FUNCTION  NF_PUT_VARM_INT   (NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, IVALS)
+INTEGER FUNCTION  NF_GET_VARM_INT   (NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, ivals)
+INTEGER FUNCTION  NF_PUT_VARM_REAL  (NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, RVALS)
+INTEGER FUNCTION  NF_GET_VARM_REAL  (NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, rvals)
+INTEGER FUNCTION  NF_PUT_VARM_DOUBLE(NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, DVALS)
+INTEGER FUNCTION  NF_GET_VARM_DOUBLE(NCID, VARID, START, COUNT, STRIDE,
+                                     IMAP, dvals)
+
+INTEGER FUNCTION  NF_INQ_ATT        (NCID, VARID, NAME, xtype, len)
+INTEGER FUNCTION  NF_INQ_ATTID      (NCID, VARID, NAME, attnum)
+INTEGER FUNCTION  NF_INQ_ATTTYPE    (NCID, VARID, NAME, xtype)
+INTEGER FUNCTION  NF_INQ_ATTLEN     (NCID, VARID, NAME, len)
+INTEGER FUNCTION  NF_INQ_ATTNAME    (NCID, VARID, ATTNUM, name)
+INTEGER FUNCTION  NF_COPY_ATT       (NCID_IN, VARID_IN, NAME,
+                                     NCID_OUT, VARID_OUT)
+INTEGER FUNCTION  NF_RENAME_ATT     (NCID, VARID, CURNAME, NEWNAME)
+INTEGER FUNCTION  NF_DEL_ATT        (NCID, VARID, NAME)
+INTEGER FUNCTION  NF_PUT_ATT_TEXT   (NCID, VARID, NAME, LEN, TEXT)
+INTEGER FUNCTION  NF_GET_ATT_TEXT   (NCID, VARID, NAME, text)
+INTEGER FUNCTION  NF_PUT_ATT_INT1   (NCID, VARID, NAME, XTYPE, LEN,
+                                     I1VALS)
+INTEGER FUNCTION  NF_GET_ATT_INT1   (NCID, VARID, NAME, i1vals)
+INTEGER FUNCTION  NF_PUT_ATT_INT2   (NCID, VARID, NAME, XTYPE, LEN,
+                                     I2VALS)
+INTEGER FUNCTION  NF_GET_ATT_INT2   (NCID, VARID, NAME, i2vals)
+INTEGER FUNCTION  NF_PUT_ATT_INT    (NCID, VARID, NAME, XTYPE, LEN,
+                                     IVALS)
+INTEGER FUNCTION  NF_GET_ATT_INT    (NCID, VARID, NAME, ivals)
+INTEGER FUNCTION  NF_PUT_ATT_REAL   (NCID, VARID, NAME, XTYPE, LEN,
+                                     RVALS)
+INTEGER FUNCTION  NF_GET_ATT_REAL   (NCID, VARID, NAME, rvals)
+INTEGER FUNCTION  NF_PUT_ATT_DOUBLE (NCID, VARID, NAME, XTYPE, LEN,
+                                     DVALS)
+INTEGER FUNCTION  NF_GET_ATT_DOUBLE (NCID, VARID, NAME, dvals)
+
+INTEGER       ATTNUM       ! attribute number
+INTEGER       attnum       ! returned attribute number
+INTEGER       CMODE        ! NF_NOCLOBBER, NF_SHARE flags expression
+INTEGER       COUNT        ! array of edge lengths of block of values
+CHARACTER(*)  CURNAME      ! current name (before renaming)
+INTEGER       DIMID        ! dimension ID
+INTEGER       dimid        ! returned dimension ID
+INTEGER       DIMIDS       ! list of dimension IDs
+INTEGER       dimids       ! list of returned dimension IDs
+DOUBLEPRECISION  DVAL      ! single data value
+DOUBLEPRECISION  dval      ! returned single data value
+DOUBLEPRECISION  DVALS     ! array of data values
+DOUBLEPRECISION  dvals     ! array of returned data values
+INTEGER       FILLMODE     ! NF_NOFILL or NF_FILL, for setting fill mode
+INTEGER*1     I1VAL        ! single data value
+INTEGER*1     I1val        ! returned single data value
+INTEGER*1     I1VALS       ! array of data values
+INTEGER*1     i1vals       ! array of returned data values
+INTEGER*2     I2VAL        ! single data value
+INTEGER*2     i2val        ! returned single data value
+INTEGER*2     I2VALS       ! array of data values
+INTEGER*2     i2vals       ! array of returned data values
+INTEGER       IMAP         ! index mapping vector
+INTEGER       INDEX        ! variable array index vector
+INTEGER       IVAL         ! single data value
+INTEGER       ival         ! returned single data value
+INTEGER       IVALS        ! array of data values
+INTEGER       ivals        ! array of returned data values
+INTEGER       LEN          ! dimension or attribute length
+INTEGER       len          ! returned dimension or attribute length
+INTEGER       MODE         ! open mode, one of NF_WRITE or NF_NOWRITE
+CHARACTER(*)  NAME         ! dimension, variable, or attribute name
+CHARACTER(*)  name         ! returned dim, var, or att name
+INTEGER       natts        ! returned number of attributes
+INTEGER       NCERR        ! error returned from NF_xxx function call
+INTEGER       NCID         ! netCDF ID of an open netCDF dataset
+INTEGER       ncid         ! returned netCDF ID
+INTEGER       NCID_IN      ! netCDF ID of open source netCDF dataset
+INTEGER       NCID_OUT     ! netCDF ID of open destination netCDF dataset
+INTEGER       NDIMS        ! number of dimensions
+INTEGER       ndims        ! returned number of dimensions
+CHARACTER(*)  NEWNAME      ! new name for dim, var, or att
+INTEGER       ngatts       ! returned number of global attributes
+INTEGER       nvars        ! returned number of variables
+INTEGER       old_mode     ! previous fill mode, NF_NOFILL or NF_FILL,
+CHARACTER(*)  PATH         ! name of netCDF dataset
+REAL          RVAL         ! single data value
+REAL          rval         ! returned single data value
+REAL          RVALS        ! array of data values
+REAL          rvals        ! array of returned data values
+INTEGER       START        ! variable array indices of first value
+INTEGER       STRIDE       ! variable array dimensional strides
+CHARACTER(*)  TEXT         ! input text value
+CHARACTER(*)  text         ! returned text value
+INTEGER       unlimdimid   ! returned ID of unlimited dimension
+INTEGER       VARID        ! variable ID
+INTEGER       varid        ! returned variable ID
+INTEGER       VARID_IN     ! variable ID
+INTEGER       VARID_OUT    ! variable ID
+INTEGER       XTYPE        ! external type: NF_BYTE, NF_CHAR, ... , 
+INTEGER       xtype        ! returned external type
+ at end example
+
+ at node Combined Index,  , Summary of FORTRAN 77 Interface, Top
+ at unnumbered Index
+
+ at printindex cp
+
+ at bye
+End:
+
diff --git a/fortran/EightByteIntTest-2.f90 b/fortran/EightByteIntTest-2.f90
new file mode 100644
index 0000000..d7fdac8
--- /dev/null
+++ b/fortran/EightByteIntTest-2.f90
@@ -0,0 +1,16 @@
+program EightBytIntTest
+   use typeSizes
+   implicit none
+
+   integer (kind = EightByteInt) :: Eight
+   integer                       :: defaultInt
+
+   print *, "Kind parameter for EightByteInt is", EightByteInt
+   print *, "Bit size of eight byte int is",      bit_size(Eight)
+contains
+   subroutine EightByteIntProcedure(input)
+     integer (kind = EightByteInt), intent( in) :: input
+
+     print *, int(input)
+   end subroutine EightByteIntProcedure
+end program EightBytIntTest
diff --git a/fortran/EightByteIntTest.f90 b/fortran/EightByteIntTest.f90
new file mode 100644
index 0000000..228ccab
--- /dev/null
+++ b/fortran/EightByteIntTest.f90
@@ -0,0 +1,11 @@
+program EightBytIntTest
+   use typeSizes
+   implicit none
+
+   integer (kind = EightByteInt) :: Eight
+   integer                       :: defaultInt
+
+   print *, "Bit size of default int is",         bit_size(defaultInt)
+   print *, "Kind parameter for EightByteInt is", EightByteInt
+   print *, "Bit size of eight byte int is",      bit_size(Eight)
+end program EightBytIntTest
diff --git a/fortran/NOTES b/fortran/NOTES
new file mode 100644
index 0000000..76f072c
--- /dev/null
+++ b/fortran/NOTES
@@ -0,0 +1,37 @@
+Implemented with 4 files:
+
+ f90aux.m4  auxiliary m4 macro definitions used by nves.m4 and nvea.m4
+ nves.m4    to generate netcdf_vars_expand_single variations
+ nvea.m4    to generate netcdf_vars_expand_arrays variations
+ gen.m4     defines top-level NVES and NVEA macros and invokes them to
+            generate all variations 
+
+To generate all the 6*2 nves functions and 7*6*2 nvea functions:
+
+ m4 gen.m4 > netcdf_expanded.f90
+
+m4 uses common names for some built-in macros, e.g. "index", so
+f90aux.m4 renames a few of these to avoid clashes with source
+variables and functions.
+
+All the invocations of the "dnl" macro (delete to new line) in
+f90aux.m4 are just to avoid gratuitous blank lines in the output.
+
+m4 may be used for generating parameterized documentation and
+comments also.
+
+Another approach to generating all the f90 functions other than the
+definition and invocation of the top-level NVES and NVEA macros in
+gen.m4 would be to just invoke m4 for each function generation,
+something like:
+
+ m4 -D NUMDIMS=2 -D KINDVALUE=FourByteReal -D PUTORGET=put f90aux.m4 nvea.m4
+
+for the array functions, or
+
+ m4 -D NUMDIMS=0 -D KINDVALUE=FourByteReal -D PUTORGET=put f90aux.m4 nves.m4
+
+for the single value functions.
+
+
+
diff --git a/fortran/example_good.cdl b/fortran/example_good.cdl
new file mode 100644
index 0000000..e243666
--- /dev/null
+++ b/fortran/example_good.cdl
@@ -0,0 +1,51 @@
+netcdf example {
+dimensions:
+	lat = 4 ;
+	lon = 3 ;
+	frtime = UNLIMITED ; // (2 currently)
+	timelen = 20 ;
+variables:
+	float P(frtime, lat, lon) ;
+		P:long_name = "pressure at maximum wind" ;
+		P:units = "hectopascals" ;
+		P:valid_range = 0.f, 1500.f ;
+		P:_FillValue = -9999.f ;
+	float lat(lat) ;
+		lat:long_name = "latitude" ;
+		lat:units = "degrees_north" ;
+	float lon(lon) ;
+		lon:long_name = "longitude" ;
+		lon:units = "degrees_east" ;
+	int frtime(frtime) ;
+		frtime:long_name = "forecast time" ;
+		frtime:units = "hours" ;
+	char reftime(timelen) ;
+		reftime:long_name = "reference time" ;
+		reftime:units = "text_time" ;
+	float ScalarVariable ;
+
+// global attributes:
+		:history = "created by Unidata LDM from NPS broadcast" ;
+		:title = "NMC Global Product Set: Pressure at Maximum Wind" ;
+data:
+
+ P =
+  950, 951, 952,
+  953, 954, 955,
+  956, 957, 958,
+  959, 960, 961,
+  962, 963, 964,
+  965, 966, 967,
+  968, 969, 970,
+  971, 972, 973 ;
+
+ lat = -90, -87.5, -85, -82.5 ;
+
+ lon = -180, -175, -170 ;
+
+ frtime = 12, 18 ;
+
+ reftime = "1992-3-21 12:00" ;
+
+ ScalarVariable = 10 ;
+}
diff --git a/fortran/f90aux.m4 b/fortran/f90aux.m4
new file mode 100644
index 0000000..17d19ce
--- /dev/null
+++ b/fortran/f90aux.m4
@@ -0,0 +1,50 @@
+divert(-1)dnl
+ifdef(`NUMDIMS',,
+	`errprint(`****NUMDIMS should be defined as 0, 1, 2, 3, 4, 5, 6, 7, ...****')m4exit')dnl
+ifdef(`KINDVALUE',,
+	`errprint(`****KINDVALUE must be defined as  "text", "OneByteInt", "TwoBytInt", "FourByteInt", "EightByteInt", "FourByteReal", or "EightByteReal"****\n')m4exit')dnl
+ifdef(`PUTORGET',,
+	`errprint(`****PUTORGET must be defined as "put" or "get"****\n')m4exit')dnl
+dnl# NCOLONS(1) = ":", NCOLONS(2) = ":, :", etc.
+define(`NCOLONS',`ifelse($1, 1, `:', `:, '`NCOLONS(decr($1))')')
+define(`COLONS',`NCOLONS(NUMDIMS)')
+define(`NUMERIC_DECL',`$1 (kind = KINDVALUE)')
+define(`TEXT_DEFINES',
+	`define(`TYPE',`character (len = *)')define(`NCKIND',`text')')
+define(`INT1_DEFINES',
+	`define(`TYPE',`NUMERIC_DECL(integer)')define(`NCKIND',`int1')')
+define(`INT2_DEFINES',
+	`define(`TYPE',`NUMERIC_DECL(integer)')define(`NCKIND',`int2')')
+define(`INT4_DEFINES',
+	`define(`TYPE',`NUMERIC_DECL(integer)')define(`NCKIND',`int')')
+define(`INT8_DEFINES',
+	`define(`TYPE',`NUMERIC_DECL(integer)')define(`NCKIND',`int')')
+define(`FLT4_DEFINES',
+	`define(`TYPE',`NUMERIC_DECL(real)')define(`NCKIND',`real')')
+define(`FLT8_DEFINES',
+	`define(`TYPE',`NUMERIC_DECL(real)')define(`NCKIND',`double')')
+ifelse(KINDVALUE,text,`TEXT_DEFINES',
+       KINDVALUE,OneByteInt,`INT1_DEFINES',
+       KINDVALUE,TwoByteInt,`INT2_DEFINES',
+       KINDVALUE,FourByteInt,`INT4_DEFINES',
+       KINDVALUE,EightByteInt,`INT8_DEFINES',
+       KINDVALUE,FourByteReal,`FLT4_DEFINES',
+       KINDVALUE,EightByteReal,`FLT8_DEFINES',
+       
+	`errprint(`****KINDVALUE must be "text", "OneByteInt", "TwoBytInt", "FourByteInt", "EightByteInt", "FourByteReal", or "EightByteReal"****\n')')
+ifelse(PUTORGET,`put',`define(`IN_OR_OUT',` in')',
+       PUTORGET,`get',`define(`IN_OR_OUT',`out')',
+       
+	`errprint(`****PUTORGET must be "put" or "get"****')')
+define(`ND_KINDVALUE',NUMDIMS`'D_`'KINDVALUE)
+define(`NF90_AFUN',`nf90_'PUTORGET`_var_'ND_KINDVALUE)
+define(`NF90_1FUN',`nf90_'PUTORGET`_var_'KINDVALUE)
+define(`NF_MFUN',`nf_'PUTORGET`_varm_'NCKIND)
+define(`NF_SFUN',`nf_'PUTORGET`_vars_'NCKIND)
+define(`NF_AFUN',`nf_'PUTORGET`_vara_'NCKIND)
+define(`NF_1FUN',`nf_'PUTORGET`_var1_'NCKIND)
+define(`m4_rename',`ifdef(`$1',`define(`m4'_`$1',defn(`$1'))undefine(`$1')')')
+m4_rename(`index')
+m4_rename(`len')
+m4_rename(`shift')
+divert`'dnl
diff --git a/fortran/gen.m4 b/fortran/gen.m4
new file mode 100644
index 0000000..6fba64a
--- /dev/null
+++ b/fortran/gen.m4
@@ -0,0 +1,145 @@
+define(NVES, dnl
+`define(`NUMDIMS',0)dnl # not used, but permits sharing f90aux.m4 
+define(`KINDVALUE',$1)dnl
+define(`PUTORGET', $2)dnl
+include(f90aux.m4)dnl
+include(nves.m4)
+')dnl
+
+define(NVESPUT48, dnl
+`define(`NUMDIMS',0)dnl # not used, but permits sharing f90aux.m4 
+define(`KINDVALUE',$1)dnl
+define(`PUTORGET', $2)dnl
+include(f90aux.m4)dnl
+include(nvesput48.m4)
+')dnl
+
+define(NVESGET48, dnl
+`define(`NUMDIMS',0)dnl # not used, but permits sharing f90aux.m4 
+define(`KINDVALUE',$1)dnl
+define(`PUTORGET', $2)dnl
+include(f90aux.m4)dnl
+include(nvesget48.m4)
+')dnl
+
+define(NVEA, dnl
+`define(`NUMDIMS',$1)dnl
+define(`KINDVALUE',$2)dnl
+define(`PUTORGET', $3)dnl
+include(f90aux.m4)dnl
+include(nvea.m4)
+')dnl
+
+define(NVEAPUT48, dnl
+`define(`NUMDIMS',$1)dnl
+define(`KINDVALUE',$2)dnl
+define(`PUTORGET', $3)dnl
+include(f90aux.m4)dnl
+include(nveaput48.m4)
+')dnl
+
+define(NVEAGET48, dnl
+`define(`NUMDIMS',$1)dnl
+define(`KINDVALUE',$2)dnl
+define(`PUTORGET', $3)dnl
+include(f90aux.m4)dnl
+include(nveaget48.m4)
+')dnl
+
+NVES(OneByteInt, put)
+NVES(TwoByteInt, put)
+NVESPUT48(FourByteInt, put)
+NVESPUT48(EightByteInt, put)
+NVES(FourByteReal, put)
+NVES(EightByteReal, put)
+NVES(OneByteInt, get)
+NVES(TwoByteInt, get)
+NVESGET48(FourByteInt, get)
+NVESGET48(EightByteInt, get)
+NVES(FourByteReal, get)
+NVES(EightByteReal, get)
+
+NVEA(1, OneByteInt, put)
+NVEA(2, OneByteInt, put)
+NVEA(3, OneByteInt, put)
+NVEA(4, OneByteInt, put)
+NVEA(5, OneByteInt, put)
+NVEA(6, OneByteInt, put)
+NVEA(7, OneByteInt, put)
+NVEA(1, TwoByteInt, put)
+NVEA(2, TwoByteInt, put)
+NVEA(3, TwoByteInt, put)
+NVEA(4, TwoByteInt, put)
+NVEA(5, TwoByteInt, put)
+NVEA(6, TwoByteInt, put)
+NVEA(7, TwoByteInt, put)
+NVEAPUT48(1, FourByteInt, put)
+NVEAPUT48(2, FourByteInt, put)
+NVEAPUT48(3, FourByteInt, put)
+NVEAPUT48(4, FourByteInt, put)
+NVEAPUT48(5, FourByteInt, put)
+NVEAPUT48(6, FourByteInt, put)
+NVEAPUT48(7, FourByteInt, put)
+NVEAPUT48(1, EightByteInt, put)
+NVEAPUT48(2, EightByteInt, put)
+NVEAPUT48(3, EightByteInt, put)
+NVEAPUT48(4, EightByteInt, put)
+NVEAPUT48(5, EightByteInt, put)
+NVEAPUT48(6, EightByteInt, put)
+NVEAPUT48(7, EightByteInt, put)
+NVEA(1, FourByteReal, put)
+NVEA(2, FourByteReal, put)
+NVEA(3, FourByteReal, put)
+NVEA(4, FourByteReal, put)
+NVEA(5, FourByteReal, put)
+NVEA(6, FourByteReal, put)
+NVEA(7, FourByteReal, put)
+NVEA(1, EightByteReal, put)
+NVEA(2, EightByteReal, put)
+NVEA(3, EightByteReal, put)
+NVEA(4, EightByteReal, put)
+NVEA(5, EightByteReal, put)
+NVEA(6, EightByteReal, put)
+NVEA(7, EightByteReal, put)
+NVEA(1, OneByteInt, get)
+NVEA(2, OneByteInt, get)
+NVEA(3, OneByteInt, get)
+NVEA(4, OneByteInt, get)
+NVEA(5, OneByteInt, get)
+NVEA(6, OneByteInt, get)
+NVEA(7, OneByteInt, get)
+NVEA(1, TwoByteInt, get)
+NVEA(2, TwoByteInt, get)
+NVEA(3, TwoByteInt, get)
+NVEA(4, TwoByteInt, get)
+NVEA(5, TwoByteInt, get)
+NVEA(6, TwoByteInt, get)
+NVEA(7, TwoByteInt, get)
+NVEAGET48(1, FourByteInt, get)
+NVEAGET48(2, FourByteInt, get)
+NVEAGET48(3, FourByteInt, get)
+NVEAGET48(4, FourByteInt, get)
+NVEAGET48(5, FourByteInt, get)
+NVEAGET48(6, FourByteInt, get)
+NVEAGET48(7, FourByteInt, get)
+NVEAGET48(1, EightByteInt, get)
+NVEAGET48(2, EightByteInt, get)
+NVEAGET48(3, EightByteInt, get)
+NVEAGET48(4, EightByteInt, get)
+NVEAGET48(5, EightByteInt, get)
+NVEAGET48(6, EightByteInt, get)
+NVEAGET48(7, EightByteInt, get)
+NVEA(1, FourByteReal, get)
+NVEA(2, FourByteReal, get)
+NVEA(3, FourByteReal, get)
+NVEA(4, FourByteReal, get)
+NVEA(5, FourByteReal, get)
+NVEA(6, FourByteReal, get)
+NVEA(7, FourByteReal, get)
+NVEA(1, EightByteReal, get)
+NVEA(2, EightByteReal, get)
+NVEA(3, EightByteReal, get)
+NVEA(4, EightByteReal, get)
+NVEA(5, EightByteReal, get)
+NVEA(6, EightByteReal, get)
+NVEA(7, EightByteReal, get)
diff --git a/fortran/netcdf.inc b/fortran/netcdf.inc
deleted file mode 100644
index 1371bcb..0000000
--- a/fortran/netcdf.inc
+++ /dev/null
@@ -1,1740 +0,0 @@
-!     NetCDF-3.
-!
-! netcdf version 3 fortran interface:
-!
-
-!
-! external netcdf data types:
-!
-      integer nf_byte
-      integer nf_int1
-      integer nf_char
-      integer nf_short
-      integer nf_int2
-      integer nf_int
-      integer nf_float
-      integer nf_real
-      integer nf_double
-
-      parameter (nf_byte = 1)
-      parameter (nf_int1 = nf_byte)
-      parameter (nf_char = 2)
-      parameter (nf_short = 3)
-      parameter (nf_int2 = nf_short)
-      parameter (nf_int = 4)
-      parameter (nf_float = 5)
-      parameter (nf_real = nf_float)
-      parameter (nf_double = 6)
-
-!
-! default fill values:
-!
-      integer           nf_fill_byte
-      integer           nf_fill_int1
-      integer           nf_fill_char
-      integer           nf_fill_short
-      integer           nf_fill_int2
-      integer           nf_fill_int
-      real              nf_fill_float
-      real              nf_fill_real
-      doubleprecision   nf_fill_double
-
-      parameter (nf_fill_byte = -127)
-      parameter (nf_fill_int1 = nf_fill_byte)
-      parameter (nf_fill_char = 0)
-      parameter (nf_fill_short = -32767)
-      parameter (nf_fill_int2 = nf_fill_short)
-      parameter (nf_fill_int = -2147483647)
-      parameter (nf_fill_float = 9.9692099683868690e+36)
-      parameter (nf_fill_real = nf_fill_float)
-      parameter (nf_fill_double = 9.9692099683868690d+36)
-
-!
-! mode flags for opening and creating a netcdf dataset:
-!
-      integer nf_nowrite
-      integer nf_write
-      integer nf_clobber
-      integer nf_noclobber
-      integer nf_fill
-      integer nf_nofill
-      integer nf_lock
-      integer nf_share
-      integer nf_64bit_offset
-      integer nf_sizehint_default
-      integer nf_align_chunk
-      integer nf_format_classic
-      integer nf_format_64bit
-      integer nf_diskless
-      integer nf_mmap
-
-      parameter (nf_nowrite = 0)
-      parameter (nf_write = 1)
-      parameter (nf_clobber = 0)
-      parameter (nf_noclobber = 4)
-      parameter (nf_fill = 0)
-      parameter (nf_nofill = 256)
-      parameter (nf_lock = 1024)
-      parameter (nf_share = 2048)
-      parameter (nf_64bit_offset = 512)
-      parameter (nf_sizehint_default = 0)
-      parameter (nf_align_chunk = -1)
-      parameter (nf_format_classic = 1)
-      parameter (nf_format_64bit = 2)
-      parameter (nf_diskless = 8)
-      parameter (nf_mmap = 16)
-
-!
-! size argument for defining an unlimited dimension:
-!
-      integer nf_unlimited
-      parameter (nf_unlimited = 0)
-
-!
-! global attribute id:
-!
-      integer nf_global
-      parameter (nf_global = 0)
-
-!
-! implementation limits:
-!
-      integer nf_max_dims
-      integer nf_max_attrs
-      integer nf_max_vars
-      integer nf_max_name
-      integer nf_max_var_dims
-
-      parameter (nf_max_dims = 1024)
-      parameter (nf_max_attrs = 8192)
-      parameter (nf_max_vars = 8192)
-      parameter (nf_max_name = 256)
-      parameter (nf_max_var_dims = nf_max_dims)
-
-!
-! error codes:
-!
-      integer nf_noerr
-      integer nf_ebadid
-      integer nf_eexist
-      integer nf_einval
-      integer nf_eperm
-      integer nf_enotindefine
-      integer nf_eindefine
-      integer nf_einvalcoords
-      integer nf_emaxdims
-      integer nf_enameinuse
-      integer nf_enotatt
-      integer nf_emaxatts
-      integer nf_ebadtype
-      integer nf_ebaddim
-      integer nf_eunlimpos
-      integer nf_emaxvars
-      integer nf_enotvar
-      integer nf_eglobal
-      integer nf_enotnc
-      integer nf_ests
-      integer nf_emaxname
-      integer nf_eunlimit
-      integer nf_enorecvars
-      integer nf_echar
-      integer nf_eedge
-      integer nf_estride
-      integer nf_ebadname
-      integer nf_erange
-      integer nf_enomem
-      integer nf_evarsize
-      integer nf_edimsize
-      integer nf_etrunc
-
-      parameter (nf_noerr = 0)
-      parameter (nf_ebadid = -33)
-      parameter (nf_eexist = -35)
-      parameter (nf_einval = -36)
-      parameter (nf_eperm = -37)
-      parameter (nf_enotindefine = -38)
-      parameter (nf_eindefine = -39)
-      parameter (nf_einvalcoords = -40)
-      parameter (nf_emaxdims = -41)
-      parameter (nf_enameinuse = -42)
-      parameter (nf_enotatt = -43)
-      parameter (nf_emaxatts = -44)
-      parameter (nf_ebadtype = -45)
-      parameter (nf_ebaddim = -46)
-      parameter (nf_eunlimpos = -47)
-      parameter (nf_emaxvars = -48)
-      parameter (nf_enotvar = -49)
-      parameter (nf_eglobal = -50)
-      parameter (nf_enotnc = -51)
-      parameter (nf_ests = -52)
-      parameter (nf_emaxname = -53)
-      parameter (nf_eunlimit = -54)
-      parameter (nf_enorecvars = -55)
-      parameter (nf_echar = -56)
-      parameter (nf_eedge = -57)
-      parameter (nf_estride = -58)
-      parameter (nf_ebadname = -59)
-      parameter (nf_erange = -60)
-      parameter (nf_enomem = -61)
-      parameter (nf_evarsize = -62)
-      parameter (nf_edimsize = -63)
-      parameter (nf_etrunc = -64)
-!
-! error handling modes:
-!
-      integer  nf_fatal
-      integer nf_verbose
-
-      parameter (nf_fatal = 1)
-      parameter (nf_verbose = 2)
-
-!
-! miscellaneous routines:
-!
-      character*80   nf_inq_libvers
-      external       nf_inq_libvers
-
-      character*80   nf_strerror
-!                         (integer             ncerr)
-      external       nf_strerror
-
-      logical        nf_issyserr
-!                         (integer             ncerr)
-      external       nf_issyserr
-
-!
-! control routines:
-!
-      integer         nf_inq_base_pe
-!                         (integer             ncid,
-!                          integer             pe)
-      external        nf_inq_base_pe
-
-      integer         nf_set_base_pe
-!                         (integer             ncid,
-!                          integer             pe)
-      external        nf_set_base_pe
-
-      integer         nf_create
-!                         (character*(*)       path,
-!                          integer             cmode,
-!                          integer             ncid)
-      external        nf_create
-
-      integer         nf__create
-!                         (character*(*)       path,
-!                          integer             cmode,
-!                          integer             initialsz,
-!                          integer             chunksizehint,
-!                          integer             ncid)
-      external        nf__create
-
-      integer         nf__create_mp
-!                         (character*(*)       path,
-!                          integer             cmode,
-!                          integer             initialsz,
-!                          integer             basepe,
-!                          integer             chunksizehint,
-!                          integer             ncid)
-      external        nf__create_mp
-
-      integer         nf_open
-!                         (character*(*)       path,
-!                          integer             mode,
-!                          integer             ncid)
-      external        nf_open
-
-      integer         nf__open
-!                         (character*(*)       path,
-!                          integer             mode,
-!                          integer             chunksizehint,
-!                          integer             ncid)
-      external        nf__open
-
-      integer         nf__open_mp
-!                         (character*(*)       path,
-!                          integer             mode,
-!                          integer             basepe,
-!                          integer             chunksizehint,
-!                          integer             ncid)
-      external        nf__open_mp
-
-      integer         nf_set_fill
-!                         (integer             ncid,
-!                          integer             fillmode,
-!                          integer             old_mode)
-      external        nf_set_fill
-
-      integer         nf_set_default_format
-!                          (integer             format,
-!                          integer             old_format)
-      external        nf_set_default_format
-
-      integer         nf_redef
-!                         (integer             ncid)
-      external        nf_redef
-
-      integer         nf_enddef
-!                         (integer             ncid)
-      external        nf_enddef
-
-      integer         nf__enddef
-!                         (integer             ncid,
-!                          integer             h_minfree,
-!                          integer             v_align,
-!                          integer             v_minfree,
-!                          integer             r_align)
-      external        nf__enddef
-
-      integer         nf_sync
-!                         (integer             ncid)
-      external        nf_sync
-
-      integer         nf_abort
-!                         (integer             ncid)
-      external        nf_abort
-
-      integer         nf_close
-!                         (integer             ncid)
-      external        nf_close
-
-      integer         nf_delete
-!                         (character*(*)       ncid)
-      external        nf_delete
-
-!
-! general inquiry routines:
-!
-
-      integer         nf_inq
-!                         (integer             ncid,
-!                          integer             ndims,
-!                          integer             nvars,
-!                          integer             ngatts,
-!                          integer             unlimdimid)
-      external        nf_inq
-
-! new inquire path
-
-      integer nf_inq_path
-      external nf_inq_path
-
-      integer         nf_inq_ndims
-!                         (integer             ncid,
-!                          integer             ndims)
-      external        nf_inq_ndims
-
-      integer         nf_inq_nvars
-!                         (integer             ncid,
-!                          integer             nvars)
-      external        nf_inq_nvars
-
-      integer         nf_inq_natts
-!                         (integer             ncid,
-!                          integer             ngatts)
-      external        nf_inq_natts
-
-      integer         nf_inq_unlimdim
-!                         (integer             ncid,
-!                          integer             unlimdimid)
-      external        nf_inq_unlimdim
-
-      integer         nf_inq_format
-!                         (integer             ncid,
-!                          integer             format)
-      external        nf_inq_format
-
-!
-! dimension routines:
-!
-
-      integer         nf_def_dim
-!                         (integer             ncid,
-!                          character(*)        name,
-!                          integer             len,
-!                          integer             dimid)
-      external        nf_def_dim
-
-      integer         nf_inq_dimid
-!                         (integer             ncid,
-!                          character(*)        name,
-!                          integer             dimid)
-      external        nf_inq_dimid
-
-      integer         nf_inq_dim
-!                         (integer             ncid,
-!                          integer             dimid,
-!                          character(*)        name,
-!                          integer             len)
-      external        nf_inq_dim
-
-      integer         nf_inq_dimname
-!                         (integer             ncid,
-!                          integer             dimid,
-!                          character(*)        name)
-      external        nf_inq_dimname
-
-      integer         nf_inq_dimlen
-!                         (integer             ncid,
-!                          integer             dimid,
-!                          integer             len)
-      external        nf_inq_dimlen
-
-      integer         nf_rename_dim
-!                         (integer             ncid,
-!                          integer             dimid,
-!                          character(*)        name)
-      external        nf_rename_dim
-
-!
-! general attribute routines:
-!
-
-      integer         nf_inq_att
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        name,
-!                          integer             xtype,
-!                          integer             len)
-      external        nf_inq_att
-
-      integer         nf_inq_attid
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        name,
-!                          integer             attnum)
-      external        nf_inq_attid
-
-      integer         nf_inq_atttype
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        name,
-!                          integer             xtype)
-      external        nf_inq_atttype
-
-      integer         nf_inq_attlen
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        name,
-!                          integer             len)
-      external        nf_inq_attlen
-
-      integer         nf_inq_attname
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             attnum,
-!                          character(*)        name)
-      external        nf_inq_attname
-
-      integer         nf_copy_att
-!                         (integer             ncid_in,
-!                          integer             varid_in,
-!                          character(*)        name,
-!                          integer             ncid_out,
-!                          integer             varid_out)
-      external        nf_copy_att
-
-      integer         nf_rename_att
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        curname,
-!                          character(*)        newname)
-      external        nf_rename_att
-
-      integer         nf_del_att
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        name)
-      external        nf_del_att
-
-!
-! attribute put/get routines:
-!
-
-      integer         nf_put_att_text
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        name,
-!                          integer             len,
-!                          character(*)        text)
-      external        nf_put_att_text
-
-      integer         nf_get_att_text
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        name,
-!                          character(*)        text)
-      external        nf_get_att_text
-
-      integer         nf_put_att_int1
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        name,
-!                          integer             xtype,
-!                          integer             len,
-!                          nf_int1_t           i1vals(1))
-      external        nf_put_att_int1
-
-      integer         nf_get_att_int1
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        name,
-!                          nf_int1_t           i1vals(1))
-      external        nf_get_att_int1
-
-      integer         nf_put_att_int2
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        name,
-!                          integer             xtype,
-!                          integer             len,
-!                          nf_int2_t           i2vals(1))
-      external        nf_put_att_int2
-
-      integer         nf_get_att_int2
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        name,
-!                          nf_int2_t           i2vals(1))
-      external        nf_get_att_int2
-
-      integer         nf_put_att_int
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        name,
-!                          integer             xtype,
-!                          integer             len,
-!                          integer             ivals(1))
-      external        nf_put_att_int
-
-      integer         nf_get_att_int
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        name,
-!                          integer             ivals(1))
-      external        nf_get_att_int
-
-      integer         nf_put_att_real
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        name,
-!                          integer             xtype,
-!                          integer             len,
-!                          real                rvals(1))
-      external        nf_put_att_real
-
-      integer         nf_get_att_real
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        name,
-!                          real                rvals(1))
-      external        nf_get_att_real
-
-      integer         nf_put_att_double
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        name,
-!                          integer             xtype,
-!                          integer             len,
-!                          double              dvals(1))
-      external        nf_put_att_double
-
-      integer         nf_get_att_double
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        name,
-!                          double              dvals(1))
-      external        nf_get_att_double
-
-!
-! general variable routines:
-!
-
-      integer         nf_def_var
-!                         (integer             ncid,
-!                          character(*)        name,
-!                          integer             datatype,
-!                          integer             ndims,
-!                          integer             dimids(1),
-!                          integer             varid)
-      external        nf_def_var
-
-      integer         nf_inq_var
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        name,
-!                          integer             datatype,
-!                          integer             ndims,
-!                          integer             dimids(1),
-!                          integer             natts)
-      external        nf_inq_var
-
-      integer         nf_inq_varid
-!                         (integer             ncid,
-!                          character(*)        name,
-!                          integer             varid)
-      external        nf_inq_varid
-
-      integer         nf_inq_varname
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        name)
-      external        nf_inq_varname
-
-      integer         nf_inq_vartype
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             xtype)
-      external        nf_inq_vartype
-
-      integer         nf_inq_varndims
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             ndims)
-      external        nf_inq_varndims
-
-      integer         nf_inq_vardimid
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             dimids(1))
-      external        nf_inq_vardimid
-
-      integer         nf_inq_varnatts
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             natts)
-      external        nf_inq_varnatts
-
-      integer         nf_rename_var
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        name)
-      external        nf_rename_var
-
-      integer         nf_copy_var
-!                         (integer             ncid_in,
-!                          integer             varid,
-!                          integer             ncid_out)
-      external        nf_copy_var
-
-!
-! entire variable put/get routines:
-!
-
-      integer         nf_put_var_text
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        text)
-      external        nf_put_var_text
-
-      integer         nf_get_var_text
-!                         (integer             ncid,
-!                          integer             varid,
-!                          character(*)        text)
-      external        nf_get_var_text
-
-      integer         nf_put_var_int1
-!                         (integer             ncid,
-!                          integer             varid,
-!                          nf_int1_t           i1vals(1))
-      external        nf_put_var_int1
-
-      integer         nf_get_var_int1
-!                         (integer             ncid,
-!                          integer             varid,
-!                          nf_int1_t           i1vals(1))
-      external        nf_get_var_int1
-
-      integer         nf_put_var_int2
-!                         (integer             ncid,
-!                          integer             varid,
-!                          nf_int2_t           i2vals(1))
-      external        nf_put_var_int2
-
-      integer         nf_get_var_int2
-!                         (integer             ncid,
-!                          integer             varid,
-!                          nf_int2_t           i2vals(1))
-      external        nf_get_var_int2
-
-      integer         nf_put_var_int
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             ivals(1))
-      external        nf_put_var_int
-
-      integer         nf_get_var_int
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             ivals(1))
-      external        nf_get_var_int
-
-      integer         nf_put_var_real
-!                         (integer             ncid,
-!                          integer             varid,
-!                          real                rvals(1))
-      external        nf_put_var_real
-
-      integer         nf_get_var_real
-!                         (integer             ncid,
-!                          integer             varid,
-!                          real                rvals(1))
-      external        nf_get_var_real
-
-      integer         nf_put_var_double
-!                         (integer             ncid,
-!                          integer             varid,
-!                          doubleprecision     dvals(1))
-      external        nf_put_var_double
-
-      integer         nf_get_var_double
-!                         (integer             ncid,
-!                          integer             varid,
-!                          doubleprecision     dvals(1))
-      external        nf_get_var_double
-
-!
-! single variable put/get routines:
-!
-
-      integer         nf_put_var1_text
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             index(1),
-!                          character*1         text)
-      external        nf_put_var1_text
-
-      integer         nf_get_var1_text
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             index(1),
-!                          character*1         text)
-      external        nf_get_var1_text
-
-      integer         nf_put_var1_int1
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             index(1),
-!                          nf_int1_t           i1val)
-      external        nf_put_var1_int1
-
-      integer         nf_get_var1_int1
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             index(1),
-!                          nf_int1_t           i1val)
-      external        nf_get_var1_int1
-
-      integer         nf_put_var1_int2
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             index(1),
-!                          nf_int2_t           i2val)
-      external        nf_put_var1_int2
-
-      integer         nf_get_var1_int2
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             index(1),
-!                          nf_int2_t           i2val)
-      external        nf_get_var1_int2
-
-      integer         nf_put_var1_int
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             index(1),
-!                          integer             ival)
-      external        nf_put_var1_int
-
-      integer         nf_get_var1_int
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             index(1),
-!                          integer             ival)
-      external        nf_get_var1_int
-
-      integer         nf_put_var1_real
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             index(1),
-!                          real                rval)
-      external        nf_put_var1_real
-
-      integer         nf_get_var1_real
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             index(1),
-!                          real                rval)
-      external        nf_get_var1_real
-
-      integer         nf_put_var1_double
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             index(1),
-!                          doubleprecision     dval)
-      external        nf_put_var1_double
-
-      integer         nf_get_var1_double
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             index(1),
-!                          doubleprecision     dval)
-      external        nf_get_var1_double
-
-!
-! variable array put/get routines:
-!
-
-      integer         nf_put_vara_text
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          character(*)        text)
-      external        nf_put_vara_text
-
-      integer         nf_get_vara_text
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          character(*)        text)
-      external        nf_get_vara_text
-
-      integer         nf_put_vara_int1
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          nf_int1_t           i1vals(1))
-      external        nf_put_vara_int1
-
-      integer         nf_get_vara_int1
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          nf_int1_t           i1vals(1))
-      external        nf_get_vara_int1
-
-      integer         nf_put_vara_int2
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          nf_int2_t           i2vals(1))
-      external        nf_put_vara_int2
-
-      integer         nf_get_vara_int2
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          nf_int2_t           i2vals(1))
-      external        nf_get_vara_int2
-
-      integer         nf_put_vara_int
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             ivals(1))
-      external        nf_put_vara_int
-
-      integer         nf_get_vara_int
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             ivals(1))
-      external        nf_get_vara_int
-
-      integer         nf_put_vara_real
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          real                rvals(1))
-      external        nf_put_vara_real
-
-      integer         nf_get_vara_real
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          real                rvals(1))
-      external        nf_get_vara_real
-
-      integer         nf_put_vara_double
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          doubleprecision     dvals(1))
-      external        nf_put_vara_double
-
-      integer         nf_get_vara_double
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          doubleprecision     dvals(1))
-      external        nf_get_vara_double
-
-!
-! strided variable put/get routines:
-!
-
-      integer         nf_put_vars_text
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          character(*)        text)
-      external        nf_put_vars_text
-
-      integer         nf_get_vars_text
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          character(*)        text)
-      external        nf_get_vars_text
-
-      integer         nf_put_vars_int1
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          nf_int1_t           i1vals(1))
-      external        nf_put_vars_int1
-
-      integer         nf_get_vars_int1
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          nf_int1_t           i1vals(1))
-      external        nf_get_vars_int1
-
-      integer         nf_put_vars_int2
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          nf_int2_t           i2vals(1))
-      external        nf_put_vars_int2
-
-      integer         nf_get_vars_int2
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          nf_int2_t           i2vals(1))
-      external        nf_get_vars_int2
-
-      integer         nf_put_vars_int
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          integer             ivals(1))
-      external        nf_put_vars_int
-
-      integer         nf_get_vars_int
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          integer             ivals(1))
-      external        nf_get_vars_int
-
-      integer         nf_put_vars_real
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          real                rvals(1))
-      external        nf_put_vars_real
-
-      integer         nf_get_vars_real
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          real                rvals(1))
-      external        nf_get_vars_real
-
-      integer         nf_put_vars_double
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          doubleprecision     dvals(1))
-      external        nf_put_vars_double
-
-      integer         nf_get_vars_double
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          doubleprecision     dvals(1))
-      external        nf_get_vars_double
-
-!
-! mapped variable put/get routines:
-!
-
-      integer         nf_put_varm_text
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          integer             imap(1),
-!                          character(*)        text)
-      external        nf_put_varm_text
-
-      integer         nf_get_varm_text
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          integer             imap(1),
-!                          character(*)        text)
-      external        nf_get_varm_text
-
-      integer         nf_put_varm_int1
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          integer             imap(1),
-!                          nf_int1_t           i1vals(1))
-      external        nf_put_varm_int1
-
-      integer         nf_get_varm_int1
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          integer             imap(1),
-!                          nf_int1_t           i1vals(1))
-      external        nf_get_varm_int1
-
-      integer         nf_put_varm_int2
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          integer             imap(1),
-!                          nf_int2_t           i2vals(1))
-      external        nf_put_varm_int2
-
-      integer         nf_get_varm_int2
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          integer             imap(1),
-!                          nf_int2_t           i2vals(1))
-      external        nf_get_varm_int2
-
-      integer         nf_put_varm_int
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          integer             imap(1),
-!                          integer             ivals(1))
-      external        nf_put_varm_int
-
-      integer         nf_get_varm_int
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          integer             imap(1),
-!                          integer             ivals(1))
-      external        nf_get_varm_int
-
-      integer         nf_put_varm_real
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          integer             imap(1),
-!                          real                rvals(1))
-      external        nf_put_varm_real
-
-      integer         nf_get_varm_real
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          integer             imap(1),
-!                          real                rvals(1))
-      external        nf_get_varm_real
-
-      integer         nf_put_varm_double
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          integer             imap(1),
-!                          doubleprecision     dvals(1))
-      external        nf_put_varm_double
-
-      integer         nf_get_varm_double
-!                         (integer             ncid,
-!                          integer             varid,
-!                          integer             start(1),
-!                          integer             count(1),
-!                          integer             stride(1),
-!                          integer             imap(1),
-!                          doubleprecision     dvals(1))
-      external        nf_get_varm_double
-
-
-!     NetCDF-4.
-!     This is part of netCDF-4. Copyright 2006, UCAR, See COPYRIGHT
-!     file for distribution information.
-
-!     Netcdf version 4 fortran interface.
-
-!     $Id: netcdf4.inc,v 1.28 2010/05/25 13:53:02 ed Exp $
-
-!     New netCDF-4 types.
-      integer nf_ubyte
-      integer nf_ushort
-      integer nf_uint
-      integer nf_int64
-      integer nf_uint64
-      integer nf_string
-      integer nf_vlen
-      integer nf_opaque
-      integer nf_enum
-      integer nf_compound
-
-      parameter (nf_ubyte = 7)
-      parameter (nf_ushort = 8)
-      parameter (nf_uint = 9)
-      parameter (nf_int64 = 10)
-      parameter (nf_uint64 = 11)
-      parameter (nf_string = 12)
-      parameter (nf_vlen = 13)
-      parameter (nf_opaque = 14)
-      parameter (nf_enum = 15)
-      parameter (nf_compound = 16)
-
-!     New netCDF-4 fill values.
-      integer           nf_fill_ubyte
-      integer           nf_fill_ushort
-!      real              nf_fill_uint
-!      real              nf_fill_int64
-!      real              nf_fill_uint64
-      parameter (nf_fill_ubyte = 255)
-      parameter (nf_fill_ushort = 65535)
-
-!     New constants.
-      integer nf_format_netcdf4
-      parameter (nf_format_netcdf4 = 3)
-
-      integer nf_format_netcdf4_classic
-      parameter (nf_format_netcdf4_classic = 4)
-
-      integer nf_netcdf4
-      parameter (nf_netcdf4 = 4096)
-
-      integer nf_classic_model
-      parameter (nf_classic_model = 256)
-
-      integer nf_chunk_seq
-      parameter (nf_chunk_seq = 0)
-      integer nf_chunk_sub
-      parameter (nf_chunk_sub = 1)
-      integer nf_chunk_sizes
-      parameter (nf_chunk_sizes = 2)
-
-      integer nf_endian_native
-      parameter (nf_endian_native = 0)
-      integer nf_endian_little
-      parameter (nf_endian_little = 1)
-      integer nf_endian_big
-      parameter (nf_endian_big = 2)
-
-!     For NF_DEF_VAR_CHUNKING
-      integer nf_chunked
-      parameter (nf_chunked = 0)
-      integer nf_contiguous
-      parameter (nf_contiguous = 1)
-
-!     For NF_DEF_VAR_FLETCHER32
-      integer nf_nochecksum
-      parameter (nf_nochecksum = 0)
-      integer nf_fletcher32
-      parameter (nf_fletcher32 = 1)
-
-!     For NF_DEF_VAR_DEFLATE
-      integer nf_noshuffle
-      parameter (nf_noshuffle = 0)
-      integer nf_shuffle
-      parameter (nf_shuffle = 1)
-
-!     For NF_DEF_VAR_SZIP
-      integer nf_szip_ec_option_mask
-      parameter (nf_szip_ec_option_mask = 4)
-      integer nf_szip_nn_option_mask
-      parameter (nf_szip_nn_option_mask = 32)
-
-!     For parallel I/O.
-      integer nf_mpiio      
-      parameter (nf_mpiio = 8192)
-      integer nf_mpiposix
-      parameter (nf_mpiposix = 16384)
-      integer nf_pnetcdf
-      parameter (nf_pnetcdf = 32768)
-
-!     For NF_VAR_PAR_ACCESS.
-      integer nf_independent
-      parameter (nf_independent = 0)
-      integer nf_collective
-      parameter (nf_collective = 1)
-
-!     New error codes.
-      integer nf_ehdferr        ! Error at HDF5 layer. 
-      parameter (nf_ehdferr = -101)
-      integer nf_ecantread      ! Can't read. 
-      parameter (nf_ecantread = -102)
-      integer nf_ecantwrite     ! Can't write. 
-      parameter (nf_ecantwrite = -103)
-      integer nf_ecantcreate    ! Can't create. 
-      parameter (nf_ecantcreate = -104)
-      integer nf_efilemeta      ! Problem with file metadata. 
-      parameter (nf_efilemeta = -105)
-      integer nf_edimmeta       ! Problem with dimension metadata. 
-      parameter (nf_edimmeta = -106)
-      integer nf_eattmeta       ! Problem with attribute metadata. 
-      parameter (nf_eattmeta = -107)
-      integer nf_evarmeta       ! Problem with variable metadata. 
-      parameter (nf_evarmeta = -108)
-      integer nf_enocompound    ! Not a compound type. 
-      parameter (nf_enocompound = -109)
-      integer nf_eattexists     ! Attribute already exists. 
-      parameter (nf_eattexists = -110)
-      integer nf_enotnc4        ! Attempting netcdf-4 operation on netcdf-3 file.   
-      parameter (nf_enotnc4 = -111)
-      integer nf_estrictnc3     ! Attempting netcdf-4 operation on strict nc3 netcdf-4 file.   
-      parameter (nf_estrictnc3 = -112)
-      integer nf_enotnc3        ! Attempting netcdf-3 operation on netcdf-4 file.   
-      parameter (nf_enotnc3 = -113)
-      integer nf_enopar         ! Parallel operation on file opened for non-parallel access.   
-      parameter (nf_enopar = -114)
-      integer nf_eparinit       ! Error initializing for parallel access.   
-      parameter (nf_eparinit = -115)
-      integer nf_ebadgrpid      ! Bad group ID.   
-      parameter (nf_ebadgrpid = -116)
-      integer nf_ebadtypid      ! Bad type ID.   
-      parameter (nf_ebadtypid = -117)
-      integer nf_etypdefined    ! Type has already been defined and may not be edited. 
-      parameter (nf_etypdefined = -118)
-      integer nf_ebadfield      ! Bad field ID.   
-      parameter (nf_ebadfield = -119)
-      integer nf_ebadclass      ! Bad class.   
-      parameter (nf_ebadclass = -120)
-      integer nf_emaptype       ! Mapped access for atomic types only.   
-      parameter (nf_emaptype = -121)
-      integer nf_elatefill      ! Attempt to define fill value when data already exists. 
-      parameter (nf_elatefill = -122)
-      integer nf_elatedef       ! Attempt to define var properties, like deflate, after enddef. 
-      parameter (nf_elatedef = -123)
-      integer nf_edimscale      ! Probem with HDF5 dimscales. 
-      parameter (nf_edimscale = -124)
-      integer nf_enogrp       ! No group found.
-      parameter (nf_enogrp = -125)
-
-
-!     New functions.
-
-!     Parallel I/O.
-      integer nf_create_par
-      external nf_create_par
-
-      integer nf_open_par
-      external nf_open_par
-
-      integer nf_var_par_access
-      external nf_var_par_access
-
-!     Functions to handle groups.
-      integer nf_inq_ncid
-      external nf_inq_ncid
-
-      integer nf_inq_grps
-      external nf_inq_grps
-
-      integer nf_inq_grpname
-      external nf_inq_grpname
-
-      integer nf_inq_grpname_full
-      external nf_inq_grpname_full
-
-      integer nf_inq_grpname_len
-      external nf_inq_grpname_len
-
-      integer nf_inq_grp_parent
-      external nf_inq_grp_parent
-
-      integer nf_inq_grp_ncid
-      external nf_inq_grp_ncid
-
-      integer nf_inq_grp_full_ncid
-      external nf_inq_grp_full_ncid
-
-      integer nf_inq_varids
-      external nf_inq_varids
-
-      integer nf_inq_dimids
-      external nf_inq_dimids
-
-      integer nf_def_grp
-      external nf_def_grp
-
-!     New rename grp function
-
-      integer nf_rename_grp
-      external nf_rename_grp
-
-!     New options for netCDF variables.
-      integer nf_def_var_deflate
-      external nf_def_var_deflate
-
-      integer nf_inq_var_deflate
-      external nf_inq_var_deflate
-
-      integer nf_def_var_fletcher32
-      external nf_def_var_fletcher32
-
-      integer nf_inq_var_fletcher32
-      external nf_inq_var_fletcher32
-
-      integer nf_def_var_chunking
-      external nf_def_var_chunking
-
-      integer nf_inq_var_chunking
-      external nf_inq_var_chunking
-
-      integer nf_def_var_fill
-      external nf_def_var_fill
-
-      integer nf_inq_var_fill
-      external nf_inq_var_fill
-
-      integer nf_def_var_endian
-      external nf_def_var_endian
-
-      integer nf_inq_var_endian
-      external nf_inq_var_endian
-
-!     User defined types.
-      integer nf_inq_typeids
-      external nf_inq_typeids
-
-      integer nf_inq_typeid
-      external nf_inq_typeid
-
-      integer nf_inq_type
-      external nf_inq_type
-
-      integer nf_inq_user_type
-      external nf_inq_user_type
-
-!     User defined types - compound types.
-      integer nf_def_compound
-      external nf_def_compound
-
-      integer nf_insert_compound
-      external nf_insert_compound
-
-      integer nf_insert_array_compound
-      external nf_insert_array_compound
-
-      integer nf_inq_compound
-      external nf_inq_compound
-
-      integer nf_inq_compound_name
-      external nf_inq_compound_name
-
-      integer nf_inq_compound_size
-      external nf_inq_compound_size
-
-      integer nf_inq_compound_nfields
-      external nf_inq_compound_nfields
-
-      integer nf_inq_compound_field
-      external nf_inq_compound_field
-
-      integer nf_inq_compound_fieldname
-      external nf_inq_compound_fieldname
-
-      integer nf_inq_compound_fieldindex
-      external nf_inq_compound_fieldindex
-
-      integer nf_inq_compound_fieldoffset
-      external nf_inq_compound_fieldoffset
-
-      integer nf_inq_compound_fieldtype
-      external nf_inq_compound_fieldtype
-
-      integer nf_inq_compound_fieldndims
-      external nf_inq_compound_fieldndims
-
-      integer nf_inq_compound_fielddim_sizes
-      external nf_inq_compound_fielddim_sizes
-
-!     User defined types - variable length arrays.
-      integer nf_def_vlen
-      external nf_def_vlen
-
-      integer nf_inq_vlen
-      external nf_inq_vlen
-
-      integer nf_free_vlen
-      external nf_free_vlen
-
-!     User defined types - enums.
-      integer nf_def_enum
-      external nf_def_enum
-
-      integer nf_insert_enum
-      external nf_insert_enum
-
-      integer nf_inq_enum
-      external nf_inq_enum
-
-      integer nf_inq_enum_member
-      external nf_inq_enum_member
-
-      integer nf_inq_enum_ident
-      external nf_inq_enum_ident
-
-!     User defined types - opaque.
-      integer nf_def_opaque
-      external nf_def_opaque
-
-      integer nf_inq_opaque
-      external nf_inq_opaque
-
-!     Write and read attributes of any type, including user defined
-!     types.
-      integer nf_put_att
-      external nf_put_att
-      integer nf_get_att
-      external nf_get_att
-
-!     Write and read variables of any type, including user defined
-!     types.
-      integer nf_put_var
-      external nf_put_var
-      integer nf_put_var1
-      external nf_put_var1
-      integer nf_put_vara
-      external nf_put_vara
-      integer nf_put_vars
-      external nf_put_vars
-      integer nf_get_var
-      external nf_get_var
-      integer nf_get_var1
-      external nf_get_var1
-      integer nf_get_vara
-      external nf_get_vara
-      integer nf_get_vars
-      external nf_get_vars
-
-!     64-bit int functions.
-      integer nf_put_var1_int64
-      external nf_put_var1_int64
-      integer nf_put_vara_int64
-      external nf_put_vara_int64
-      integer nf_put_vars_int64
-      external nf_put_vars_int64
-      integer nf_put_varm_int64
-      external nf_put_varm_int64
-      integer nf_put_var_int64
-      external nf_put_var_int64
-      integer nf_get_var1_int64
-      external nf_get_var1_int64
-      integer nf_get_vara_int64
-      external nf_get_vara_int64
-      integer nf_get_vars_int64
-      external nf_get_vars_int64
-      integer nf_get_varm_int64
-      external nf_get_varm_int64
-      integer nf_get_var_int64
-      external nf_get_var_int64
-
-!     For helping F77 users with VLENs.
-      integer nf_get_vlen_element
-      external nf_get_vlen_element
-      integer nf_put_vlen_element
-      external nf_put_vlen_element
-
-!     For dealing with file level chunk cache.
-      integer nf_set_chunk_cache
-      external nf_set_chunk_cache
-      integer nf_get_chunk_cache
-      external nf_get_chunk_cache
-
-!     For dealing with per variable chunk cache.
-      integer nf_set_var_chunk_cache
-      external nf_set_var_chunk_cache
-      integer nf_get_var_chunk_cache
-      external nf_get_var_chunk_cache
-
-!     NetCDF-2.
-!ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
-! begin netcdf 2.4 backward compatibility:
-!
-
-!      
-! functions in the fortran interface
-!
-      integer nccre
-      integer ncopn
-      integer ncddef
-      integer ncdid
-      integer ncvdef
-      integer ncvid
-      integer nctlen
-      integer ncsfil
-
-      external nccre
-      external ncopn
-      external ncddef
-      external ncdid
-      external ncvdef
-      external ncvid
-      external nctlen
-      external ncsfil
-
-
-      integer ncrdwr
-      integer nccreat
-      integer ncexcl
-      integer ncindef
-      integer ncnsync
-      integer nchsync
-      integer ncndirty
-      integer nchdirty
-      integer nclink
-      integer ncnowrit
-      integer ncwrite
-      integer ncclob
-      integer ncnoclob
-      integer ncglobal
-      integer ncfill
-      integer ncnofill
-      integer maxncop
-      integer maxncdim
-      integer maxncatt
-      integer maxncvar
-      integer maxncnam
-      integer maxvdims
-      integer ncnoerr
-      integer ncebadid
-      integer ncenfile
-      integer nceexist
-      integer nceinval
-      integer nceperm
-      integer ncenotin
-      integer nceindef
-      integer ncecoord
-      integer ncemaxds
-      integer ncename
-      integer ncenoatt
-      integer ncemaxat
-      integer ncebadty
-      integer ncebadd
-      integer ncests
-      integer nceunlim
-      integer ncemaxvs
-      integer ncenotvr
-      integer nceglob
-      integer ncenotnc
-      integer ncfoobar
-      integer ncsyserr
-      integer ncfatal
-      integer ncverbos
-      integer ncentool
-
-
-!
-! netcdf data types:
-!
-      integer ncbyte
-      integer ncchar
-      integer ncshort
-      integer nclong
-      integer ncfloat
-      integer ncdouble
-
-      parameter(ncbyte = 1)
-      parameter(ncchar = 2)
-      parameter(ncshort = 3)
-      parameter(nclong = 4)
-      parameter(ncfloat = 5)
-      parameter(ncdouble = 6)
-
-!     
-!     masks for the struct nc flag field; passed in as 'mode' arg to
-!     nccreate and ncopen.
-!     
-
-!     read/write, 0 => readonly 
-      parameter(ncrdwr = 1)
-!     in create phase, cleared by ncendef 
-      parameter(nccreat = 2)
-!     on create destroy existing file 
-      parameter(ncexcl = 4)
-!     in define mode, cleared by ncendef 
-      parameter(ncindef = 8)
-!     synchronise numrecs on change (x'10')
-      parameter(ncnsync = 16)
-!     synchronise whole header on change (x'20')
-      parameter(nchsync = 32)
-!     numrecs has changed (x'40')
-      parameter(ncndirty = 64)  
-!     header info has changed (x'80')
-      parameter(nchdirty = 128)
-!     prefill vars on endef and increase of record, the default behavior
-      parameter(ncfill = 0)
-!     do not fill vars on endef and increase of record (x'100')
-      parameter(ncnofill = 256)
-!     isa link (x'8000')
-      parameter(nclink = 32768)
-
-!     
-!     'mode' arguments for nccreate and ncopen
-!     
-      parameter(ncnowrit = 0)
-      parameter(ncwrite = ncrdwr)
-      parameter(ncclob = nf_clobber)
-      parameter(ncnoclob = nf_noclobber)
-
-!     
-!     'size' argument to ncdimdef for an unlimited dimension
-!     
-      integer ncunlim
-      parameter(ncunlim = 0)
-
-!     
-!     attribute id to put/get a global attribute
-!     
-      parameter(ncglobal  = 0)
-
-!     
-!     advisory maximums:
-!     
-      parameter(maxncop = 64)
-      parameter(maxncdim = 1024)
-      parameter(maxncatt = 8192)
-      parameter(maxncvar = 8192)
-!     not enforced 
-      parameter(maxncnam = 256)
-      parameter(maxvdims = maxncdim)
-
-!     
-!     global netcdf error status variable
-!     initialized in error.c
-!     
-
-!     no error 
-      parameter(ncnoerr = nf_noerr)
-!     not a netcdf id 
-      parameter(ncebadid = nf_ebadid)
-!     too many netcdfs open 
-      parameter(ncenfile = -31)   ! nc_syserr
-!     netcdf file exists && ncnoclob
-      parameter(nceexist = nf_eexist)
-!     invalid argument 
-      parameter(nceinval = nf_einval)
-!     write to read only 
-      parameter(nceperm = nf_eperm)
-!     operation not allowed in data mode 
-      parameter(ncenotin = nf_enotindefine )   
-!     operation not allowed in define mode 
-      parameter(nceindef = nf_eindefine)   
-!     coordinates out of domain 
-      parameter(ncecoord = nf_einvalcoords)
-!     maxncdims exceeded 
-      parameter(ncemaxds = nf_emaxdims)
-!     string match to name in use 
-      parameter(ncename = nf_enameinuse)   
-!     attribute not found 
-      parameter(ncenoatt = nf_enotatt)
-!     maxncattrs exceeded 
-      parameter(ncemaxat = nf_emaxatts)
-!     not a netcdf data type 
-      parameter(ncebadty = nf_ebadtype)
-!     invalid dimension id 
-      parameter(ncebadd = nf_ebaddim)
-!     ncunlimited in the wrong index 
-      parameter(nceunlim = nf_eunlimpos)
-!     maxncvars exceeded 
-      parameter(ncemaxvs = nf_emaxvars)
-!     variable not found 
-      parameter(ncenotvr = nf_enotvar)
-!     action prohibited on ncglobal varid 
-      parameter(nceglob = nf_eglobal)
-!     not a netcdf file 
-      parameter(ncenotnc = nf_enotnc)
-      parameter(ncests = nf_ests)
-      parameter (ncentool = nf_emaxname) 
-      parameter(ncfoobar = 32)
-      parameter(ncsyserr = -31)
-
-!     
-!     global options variable. used to determine behavior of error handler.
-!     initialized in lerror.c
-!     
-      parameter(ncfatal = 1)
-      parameter(ncverbos = 2)
-
-!
-!     default fill values.  these must be the same as in the c interface.
-!
-      integer filbyte
-      integer filchar
-      integer filshort
-      integer fillong
-      real filfloat
-      doubleprecision fildoub
-
-      parameter (filbyte = -127)
-      parameter (filchar = 0)
-      parameter (filshort = -32767)
-      parameter (fillong = -2147483647)
-      parameter (filfloat = 9.9692099683868690e+36)
-      parameter (fildoub = 9.9692099683868690e+36)
diff --git a/libsrc/nfconfig.inc b/fortran/nfconfig.in
similarity index 82%
rename from libsrc/nfconfig.inc
rename to fortran/nfconfig.in
index 11ee4f8..4d3eeb8 100644
--- a/libsrc/nfconfig.inc
+++ b/fortran/nfconfig.in
@@ -21,8 +21,8 @@
     ostensibly corresponding to 8-bit and 16-bit integers, respectively.
     For example:
 
-	#define NF_INT1_T byte
-	#define NF_INT2_T integer*2
+	#define NF_INT1_T        byte
+	#define NF_INT2_T        integer*2
 
     These are the types of the relevant arguments in the NF_*_INT1() and
     NF_*_INT2() netCDF FORTRAN function calls.  The word "ostensibly"
@@ -32,8 +32,8 @@
     If your FORTRAN system does not have the respective supplementary
     datatype, then do not define the corresponding macro.
 #endif
-#define NF_INT1_T byte
-#define NF_INT2_T integer*2
+#undef NF_INT1_T
+#undef NF_INT2_T
 
 
 #if 0
@@ -43,18 +43,18 @@
    FORTRAN datatype, respectively.  If the respective FORTRAN datatype
    does not exist, then do not define the corresponding macro.
 #endif
-#define NF_INT1_IS_C_SIGNED_CHAR 1
+#undef NF_INT1_IS_C_SIGNED_CHAR
 #undef NF_INT1_IS_C_SHORT
 #undef NF_INT1_IS_C_INT
 #undef NF_INT1_IS_C_LONG
-#define NF_INT2_IS_C_SHORT 1
+#undef NF_INT2_IS_C_SHORT
 #undef NF_INT2_IS_C_INT
 #undef NF_INT2_IS_C_LONG
-#define NF_INT_IS_C_INT 1
+#undef NF_INT_IS_C_INT
 #undef NF_INT_IS_C_LONG
-#define NF_REAL_IS_C_FLOAT 1
+#undef NF_REAL_IS_C_FLOAT
 #undef NF_REAL_IS_C_DOUBLE
-#define NF_DOUBLEPRECISION_IS_C_DOUBLE 1
+#undef NF_DOUBLEPRECISION_IS_C_DOUBLE
 #undef NF_DOUBLEPRECISION_IS_C_FLOAT
 
 
@@ -75,8 +75,8 @@
     data types (e.g. INTEGER*1, INTEGER*2).  See file "ftest.F" for usage.
 #endif
 #if !defined(NO_NETCDF_2)
-#   define NCBYTE_T byte
-#   define NCSHORT_T integer*2
+#   undef NCBYTE_T
+#   undef NCSHORT_T
 #endif
 
 #if 0
@@ -91,13 +91,7 @@
 #if 0
   Set USE_NETCDF4 to defined - include netCDF4 code
 #endif
-#define USE_NETCDF4 1
-
-#if 0
-  Set HAVE_TS29113_SUPPORT to defined - TS29113 types (like CPTRDIFF_T) defined
-#endif
-#define HAVE_TS29113_SUPPORT 1
-#define SIZEOF_PTRDIFF_T 8
+#undef USE_NETCDF4
 
 #endif /*UD_NETCDF_CPP_INC*/
 
diff --git a/fortran/nvea.m4 b/fortran/nvea.m4
new file mode 100644
index 0000000..187e248
--- /dev/null
+++ b/fortran/nvea.m4
@@ -0,0 +1,33 @@
+   function NF90_AFUN`'(ncid, varid, values, start, count, stride, map)
+     integer,                         intent( in) :: ncid, varid
+     TYPE, dimension(COLONS), &
+                                      intent(IN_OR_OUT) :: values
+     integer, dimension(:), optional, intent( in) :: start, count, stride, map
+     integer                                      :: NF90_AFUN
+ 
+     integer, dimension(nf90_max_var_dims) :: localStart, localCount, localStride, localMap
+     integer                               :: numDims, counter
+ 
+     ! Set local arguments to default values
+     numDims                 = size(shape(values))
+     localStart (:         ) = 1
+     localCount (:numDims  ) = shape(values)
+     localCount (numDims+1:) = 1
+     localStride(:         ) = 1
+     localMap   (:numDims  ) = (/ 1, (product(localCount(:counter)), counter = 1, numDims - 1) /)
+ 
+     if(present(start))  localStart (:size(start) )  = start(:)
+     if(present(count))  localCount (:size(count) )  = count(:)
+     if(present(stride)) localStride(:size(stride)) = stride(:)
+     if(present(map))  then
+       localMap   (:size(map))    = map(:)
+       NF90_AFUN = &
+          NF_MFUN`'(ncid, varid, localStart, localCount, localStride, localMap, values)
+     else if(present(stride)) then
+       NF90_AFUN = &
+          NF_SFUN`'(ncid, varid, localStart, localCount, localStride, values)
+     else
+       NF90_AFUN = &
+          NF_AFUN`'(ncid, varid, localStart, localCount, values)
+     end if
+   end function NF90_AFUN
diff --git a/fortran/nveaget48.m4 b/fortran/nveaget48.m4
new file mode 100644
index 0000000..6e4df0e
--- /dev/null
+++ b/fortran/nveaget48.m4
@@ -0,0 +1,35 @@
+   function NF90_AFUN`'(ncid, varid, values, start, count, stride, map)
+     integer,                         intent( in) :: ncid, varid
+     TYPE, dimension(COLONS), &
+                                      intent(IN_OR_OUT) :: values
+     integer, dimension(:), optional, intent( in) :: start, count, stride, map
+     integer                                      :: NF90_AFUN
+ 
+     integer, dimension(nf90_max_var_dims) :: localStart, localCount, localStride, localMap
+     integer                               :: numDims, counter
+     integer, dimension(size(values))      :: defaultIntArray
+ 
+     ! Set local arguments to default values
+     numDims                 = size(shape(values))
+     localStart (:         ) = 1
+     localCount (:numDims  ) = shape(values)
+     localCount (numDims+1:) = 1
+     localStride(:         ) = 1
+     localMap   (:numDims  ) = (/ 1, (product(localCount(:counter)), counter = 1, numDims - 1) /)
+ 
+     if(present(start))  localStart (:size(start) )  = start(:)
+     if(present(count))  localCount (:size(count) )  = count(:)
+     if(present(stride)) localStride(:size(stride)) = stride(:)
+     if(present(map))  then
+       localMap   (:size(map))    = map(:)
+       NF90_AFUN = &
+          NF_MFUN`'(ncid, varid, localStart, localCount, localStride, localMap, defaultIntArray)
+     else if(present(stride)) then
+       NF90_AFUN = &
+          NF_SFUN`'(ncid, varid, localStart, localCount, localStride, defaultIntArray)
+     else
+       NF90_AFUN = &
+          NF_AFUN`'(ncid, varid, localStart, localCount, defaultIntArray)
+     end if
+     values(COLONS) = reshape(defaultIntArray(:), shape(values))
+   end function NF90_AFUN
diff --git a/fortran/nveaput48.m4 b/fortran/nveaput48.m4
new file mode 100644
index 0000000..e3077c7
--- /dev/null
+++ b/fortran/nveaput48.m4
@@ -0,0 +1,33 @@
+   function NF90_AFUN`'(ncid, varid, values, start, count, stride, map)
+     integer,                         intent( in) :: ncid, varid
+     TYPE, dimension(COLONS), &
+                                      intent(IN_OR_OUT) :: values
+     integer, dimension(:), optional, intent( in) :: start, count, stride, map
+     integer                                      :: NF90_AFUN
+ 
+     integer, dimension(nf90_max_var_dims) :: localStart, localCount, localStride, localMap
+     integer                               :: numDims, counter
+ 
+     ! Set local arguments to default values
+     numDims                 = size(shape(values))
+     localStart (:         ) = 1
+     localCount (:numDims  ) = shape(values)
+     localCount (numDims+1:) = 1
+     localStride(:         ) = 1
+     localMap   (:numDims  ) = (/ 1, (product(localCount(:counter)), counter = 1, numDims - 1) /)
+ 
+     if(present(start))  localStart (:size(start) )  = start(:)
+     if(present(count))  localCount (:size(count) )  = count(:)
+     if(present(stride)) localStride(:size(stride)) = stride(:)
+     if(present(map))  then
+       localMap   (:size(map))    = map(:)
+       NF90_AFUN = &
+          NF_MFUN`'(ncid, varid, localStart, localCount, localStride, localMap, int(values))
+     else if(present(stride)) then
+       NF90_AFUN = &
+          NF_SFUN`'(ncid, varid, localStart, localCount, localStride, int(values))
+     else
+       NF90_AFUN = &
+          NF_AFUN`'(ncid, varid, localStart, localCount, int(values))
+     end if
+   end function NF90_AFUN
diff --git a/fortran/nves.m4 b/fortran/nves.m4
new file mode 100644
index 0000000..1704144
--- /dev/null
+++ b/fortran/nves.m4
@@ -0,0 +1,15 @@
+   function NF90_1FUN`'(ncid, varid, values, start)
+     integer,                         intent( in) :: ncid, varid
+     TYPE, intent(IN_OR_OUT) :: values
+     integer, dimension(:), optional, intent( in) :: start
+     integer                                      :: NF90_1FUN
+ 
+     integer, dimension(nf90_max_var_dims) :: localIndex
+     integer                               :: counter
+ 
+     ! Set local arguments to default values
+     localIndex(:) = 1
+     if(present(start)) localIndex(:size(start)) = start(:)
+ 
+     NF90_1FUN = NF_1FUN`'(ncid, varid, localIndex, values)
+   end function NF90_1FUN
diff --git a/fortran/nvesget48.m4 b/fortran/nvesget48.m4
new file mode 100644
index 0000000..8878f86
--- /dev/null
+++ b/fortran/nvesget48.m4
@@ -0,0 +1,17 @@
+   function NF90_1FUN`'(ncid, varid, values, start)
+     integer,                         intent( in) :: ncid, varid
+     TYPE, intent(IN_OR_OUT) :: values
+     integer, dimension(:), optional, intent( in) :: start
+     integer                                      :: NF90_1FUN
+ 
+     integer, dimension(nf90_max_var_dims) :: localIndex
+     integer                               :: counter
+     integer                               :: defaultInteger
+     
+     ! Set local arguments to default values
+     localIndex(:) = 1
+     if(present(start)) localIndex(:size(start)) = start(:)
+ 
+     NF90_1FUN = NF_1FUN`'(ncid, varid, localIndex, defaultInteger)
+     values = defaultInteger
+   end function NF90_1FUN
diff --git a/fortran/nvesput48.m4 b/fortran/nvesput48.m4
new file mode 100644
index 0000000..f10ef53
--- /dev/null
+++ b/fortran/nvesput48.m4
@@ -0,0 +1,15 @@
+   function NF90_1FUN`'(ncid, varid, values, start)
+     integer,                         intent( in) :: ncid, varid
+     TYPE, intent(IN_OR_OUT) :: values
+     integer, dimension(:), optional, intent( in) :: start
+     integer                                      :: NF90_1FUN
+ 
+     integer, dimension(nf90_max_var_dims) :: localIndex
+     integer                               :: counter
+ 
+     ! Set local arguments to default values
+     localIndex(:) = 1
+     if(present(start)) localIndex(:size(start)) = start(:)
+ 
+     NF90_1FUN = NF_1FUN`'(ncid, varid, localIndex, int(values))
+   end function NF90_1FUN
diff --git a/fortran/testEightByteGet.f90 b/fortran/testEightByteGet.f90
new file mode 100644
index 0000000..c7fe6ff
--- /dev/null
+++ b/fortran/testEightByteGet.f90
@@ -0,0 +1,49 @@
+program testEightByteGet
+  use typeSizes
+  use netcdf
+  implicit none
+  
+  ! netcdf related variables
+  integer :: ncFileID, dimId, varId
+             
+  ! Local variables
+  integer, parameter :: numLats = 10
+  character (len = *), parameter :: fileName = "eightByteIntExample.nc"
+  integer            :: counter
+  !integer(kind = FourByteInt), dimension(numLats) :: lats  
+  integer(kind = EightByteInt), dimension(numLats) :: lats  
+
+! -----  
+  call check(nf90_create(path = trim(fileName), cmode = nf90_clobber, ncid = ncFileID))
+  
+  ! Define the dimensions
+  call check(nf90_def_dim(ncid = ncFileID, name = "lat", len = numLats, dimid = dimID))
+  ! Define the variable
+  call check(nf90_def_var(ncFileID, "lat", nf90_int, dimids = dimID, varID = varID) )
+  ! Leave define mode
+  call check(nf90_enddef(ncfileID))
+  ! Write the variable
+  lats(:) = (/ (counter, counter = 1, numLats) /)
+  print *, lats
+  call check(nf90_put_var(ncFileID, varId, lats ))
+  call check(nf90_close(ncFileID))
+
+  ! Now read it back in... 
+  lats(:) = 0
+  call check(nf90_open(path = trim(fileName), mode = nf90_nowrite, ncid = ncFileID))
+  call check(nf90_inq_varid(ncFileId, "lat", varId))
+  call check(nf90_get_var(ncFileID, varId, lats))
+  print *, lats
+  call check(nf90_close(ncFileID))  
+  
+contains
+  ! Internal subroutine - checks error status after each netcdf, prints out text message each time
+  !   an error code is returned. 
+  subroutine check(status)
+    integer, intent ( in) :: status
+    
+    if(status /= nf90_noerr) then 
+      print *, trim(nf90_strerror(status))
+    end if
+  end subroutine check  
+end program testEightByteGet
diff --git a/libsrc/cfortran.doc b/libsrc/cfortran.doc
new file mode 100644
index 0000000..c3bba9d
--- /dev/null
+++ b/libsrc/cfortran.doc
@@ -0,0 +1,2049 @@
+cfortran.doc  4.3
+http://www-zeus.desy.de/~burow/cfortran/
+Burkhard Burow  burow at desy.de                 1990 - 2001.
+
+              cfortran.h :  Interfacing C or C++ and FORTRAN
+
+Supports: Alpha and VAX VMS, Alpha OSF, DECstation and VAX Ultrix, IBM RS/6000, 
+          Silicon Graphics, Sun, CRAY, Apollo, HP9000, LynxOS, Convex, Absoft,
+          f2c, g77, NAG f90, PowerStation Fortran with Visual C++, NEC SX-4,
+          Portland Group.
+
+C and C++ are generally equivalent as far as cfortran.h is concerned.
+Unless explicitly noted otherwise, mention of C implicitly includes C++.
+C++ compilers tested include: 
+  SunOS> CC +p +w      # Clean compiles.
+  IRIX>  CC            # Clean compiles.
+  IRIX>  CC -fullwarn  # Still some warnings to be overcome.
+  GNU>   g++ -Wall     # Compiles are clean, other than warnings for unused
+                       #   cfortran.h static routines.
+
+N.B.: The best documentation on interfacing C or C++ and Fortran is in
+      the chapter named something like 'Interfacing C and Fortran'
+      to be found in the user's guide of almost every Fortran compiler.
+      Understanding this information for one or more Fortran compilers
+      greatly clarifies the aims and actions of cfortran.h.
+      Such a chapter generally also addresses issues orthogonal to cfortran.h,
+      for example the order of array indices, the index of the first element,
+      as well as compiling and linking issues.
+
+
+0 Short Summary of the Syntax Required to Create the Interface
+--------------------------------------------------------------
+
+e.g. Prototyping a FORTRAN subroutine for C:
+
+/* PROTOCCALLSFSUBn is optional for C, but mandatory for C++. */
+
+                 PROTOCCALLSFSUB2(SUB_NAME,sub_name,STRING,PINT)
+#define SUB_NAME(A,B) CCALLSFSUB2(SUB_NAME,sub_name,STRING,PINT, A,B)
+
+                                ^     -                                       -
+       number of arguments _____|    |   STRING   BYTE    PBYTE       BYTEV(..)|
+                                  /  |   STRINGV  DOUBLE  PDOUBLE   DOUBLEV(..)|
+                                 /   |  PSTRING   FLOAT   PFLOAT     FLOATV(..)|
+        types of arguments ____ /    | PNSTRING   INT     PINT         INTV(..)|
+                                \    | PPSTRING   LOGICAL PLOGICAL LOGICALV(..)|
+                                 \   |  PSTRINGV  LONG    PLONG       LONGV(..)|
+                                  \  |   ZTRINGV  SHORT   PSHORT     SHORTV(..)|
+                                     |  PZTRINGV  ROUTINE PVOID      SIMPLE    |
+                                      -                                       -
+
+
+e.g. Prototyping a FORTRAN function for C:
+/* PROTOCCALLSFFUNn is mandatory for both C and C++. */
+PROTOCCALLSFFUN1(INT,FUN_NAME,fun_name,STRING)
+#define FUN_NAME(A)  CCALLSFFUN1(FUN_NAME,fun_name,STRING, A)
+
+e.g. calling FUN_NAME from C:    {int a; a = FUN_NAME("hello");}
+
+
+e.g. Creating a FORTRAN-callable wrapper for
+     a C function returning void, with a 7 dimensional integer array argument:
+     [Not supported from C++.]
+FCALLSCSUB1(csub_name,CSUB_NAME,csub_name,INTVVVVVVV)
+
+
+e.g. Creating a FORTRAN-callable wrapper for other C functions:
+FCALLSCFUN1(STRING,cfun_name,CFUN_NAME,cfun_name,INT)
+           [ ^-- BYTE, DOUBLE, FLOAT, INT, LOGICAL, LONG, SHORT, VOID  
+             are other types returned by functions.       ]
+       
+
+e.g. COMMON BLOCKs:
+FORTRAN:                         common /fcb/  v,w,x
+                                 character *(13) v, w(4), x(3,2)
+C:
+typedef struct { char v[13],w[4][13],x[2][3][13]; } FCB_DEF;
+#define FCB COMMON_BLOCK(FCB,fcb)
+COMMON_BLOCK_DEF(FCB_DEF,FCB);
+FCB_DEF FCB;    /* Define, i.e. allocate memory, in exactly one *.c file. */
+
+e.g. accessing FCB in C:          printf("%.13s",FCB.v);
+
+
+
+I Introduction
+--------------
+
+cfortran.h is an easy-to-use powerful bridge between C and FORTRAN.
+It provides a completely transparent, machine independent interface between
+C and FORTRAN routines (= subroutines and/or functions) and global data,
+i.e. structures and COMMON blocks.
+
+The complete cfortran.h package consists of 4 files: the documentation in
+cfortran.doc, the engine cfortran.h, examples in cfortest.c and 
+cfortex.f/or. [cfortex.for under VMS, cfortex.f on other machines.]
+
+The cfortran.h package continues to be developed. The most recent version is
+available via www at http://www-zeus.desy.de/~burow/cfortran/
+
+The examples may be run using one of the following sets of instructions:
+
+N.B. Unlike earlier versions, cfortran.h 3.0 and later versions
+     automatically uses the correct ANSI ## or pre-ANSI /**/
+     preprocessor operator as required by the C compiler.
+
+N.B. As a general rule when trying to determine how to link C and Fortran,
+     link a trivial Fortran program using the Fortran compilers verbose option,
+     in order to see how the Fortran compiler drives the linker. e.g.
+       unix> cat f.f
+                END
+       unix> f77 -v f.f
+       .. lots of info. follows ...
+
+N.B. If using a C main(), i.e. Fortran PROGRAM is not entry of the executable,
+     and if the link bombs with a complaint about
+     a missing "MAIN" (e.g. MAIN__, MAIN_, f90_main or similar),
+     then Fortran has hijacked the entry point to the executable
+     and wishes to call the rest of the executable via "MAIN".
+     This can usually be satisfied by doing e.g. 'cc -Dmain=MAIN__ ...'
+     but often kills the command line arguments in argv and argc.
+     The f77 verbose option, usually -v, may point to a solution.
+     
+
+RS/6000> # Users are strongly urged to use f77 -qextname and cc -Dextname
+RS/6000> # Use -Dextname=extname if extname is a symbol used in the C code.
+RS/6000> xlf -c -qextname cfortex.f
+RS/6000> cc  -c -Dextname cfortest.c
+RS/6000> xlf -o cfortest cfortest.o cfortex.o && cfortest 
+
+DECFortran> #Only DECstations with DECFortran for Ultrix RISC Systems.
+DECFortran> cc -c -DDECFortran cfortest.c
+DECFortran> f77 -o cfortest cfortest.o cfortex.f  &&  cfortest
+
+IRIX xxxxxx 5.2 02282015 IP20 mips
+MIPS> # DECstations and Silicon Graphics using the MIPS compilers.
+MIPS> cc -o cfortest cfortest.c cfortex.f -lI77 -lU77 -lF77  &&  cfortest
+MIPS> # Can also let f77 drive linking, e.g.
+MIPS> cc -c cfortest.c
+MIPS> f77 -o cfortest cfortest.o cfortex.f  &&  cfortest
+
+Apollo> # Some 'C compiler 68K Rev6.8' break. [See Section II o) Notes: Apollo]
+Apollo> f77 -c cfortex.f && cc -o cfortest cfortest.c cfortex.o  &&  cfortest
+
+VMS> define lnk$library sys$library:vaxcrtl
+VMS> cc cfortest.c
+VMS> fortran cfortex.for
+VMS> link/exec=cfortest cfortest,cfortex
+VMS> run cfortest
+
+OSF1 xxxxxx V3.0 347 alpha
+Alpha/OSF> # Probably better to let cc drive linking, e.g.
+Alpha/OSF> f77 -c cfortex.f
+Alpha/OSF> cc  -o cfortest cfortest.c cfortex.o -lUfor -lfor -lFutil -lots -lm
+Alpha/OSF> cfortest
+Alpha/OSF> # Else may need 'cc -Dmain=MAIN__' to let f77 drive linking.
+
+Sun> # Some old cc(1) need a little help. [See Section II o) Notes: Sun]
+Sun> f77 -o cfortest cfortest.c cfortex.f -lc -lm  &&  cfortest
+Sun> # Some older f77 may require 'cc -Dmain=MAIN_'.
+
+CRAY> cft77 cfortex.f
+CRAY> cc -c cfortest.c
+CRAY> segldr -o cfortest.e cfortest.o cfortex.o
+CRAY> ./cfortest.e
+
+NEC> cc -c -Xa cfortest.c
+NEC> f77 -o cfortest cfortest.o cfortex.f  &&  cfortest
+
+VAX/Ultrix/cc> # For cc on VAX Ultrix only, do the following once to cfortran.h.
+VAX/Ultrix/cc> mv cfortran.h cftmp.h && grep -v "^#pragma" <cftmp.h >cfortran.h
+                                            
+VAX/Ultrix/f77> # In the following, 'CC' is either 'cc' or 'gcc -ansi'. NOT'vcc'
+VAX/Ultrix/f77> CC -c -Dmain=MAIN_ cfortest.c
+VAX/Ultrix/f77> f77 -o cfortest cfortex.f cfortest.o  &&  cfortest
+
+LynxOS> # In the following, 'CC' is either 'cc' or 'gcc -ansi'.
+LynxOS> # Unfortunately cc is easily overwhelmed by cfortran.h,
+LynxOS> #  and won't compile some of the cfortest.c demos.
+LynxOS> f2c -R cfortex.f
+LynxOS> CC -Dlynx -o cfortest cfortest.c cfortex.c -lf2c  &&  cfortest
+
+HP9000> # Tested with HP-UX 7.05 B 9000/380 and with A.08.07 A 9000/730
+HP9000> # CC may be either 'c89 -Aa' or 'cc -Aa'
+HP9000> #    Depending on the compiler version, you may need to include the
+HP9000> #    option '-tp,/lib/cpp' or worse, you'll have to stick to the K&R C.
+HP9000> #    [See Section II o) Notes: HP9000]
+HP9000> # Users are strongly urged to use f77 +ppu and cc -Dextname
+HP9000> # Use -Dextname=extname if extname is a symbol used in the C code.
+HP9000> CC  -Dextname -c cfortest.c
+HP9000> f77 +ppu         cfortex.f  -o cfortest cfortest.o && cfortest
+HP9000> # Older f77 may need
+HP9000> f77 -c cfortex.f
+HP9000> CC -o cfortest cfortest.c cfortex.o -lI77 -lF77 && cfortest
+
+HP0000> # If old-style f77 +800 compiled objects are required:
+HP9000> # #define hpuxFortran800
+HP9000> cc -c -Aa -DhpuxFortran800 cfortest.c
+HP9000> f77 +800 -o cfortest cfortest.o cfortex.f
+
+f2c> # In the following, 'CC' is any C compiler.
+f2c> f2c -R cfortex.f
+f2c> CC -o cfortest -Df2cFortran cfortest.c cfortex.c -lf2c  &&  cfortest
+
+Portland Group $ # Presumably other C compilers also work.
+Portland Group $ pgcc -DpgiFortran -c cfortest.c
+Portland Group $ pgf77 -o cfortest cfortex.f cfortest.o && cfortest
+
+NAGf90> # cfortex.f is distributed with Fortran 77 style comments.
+NAGf90> # To convert to f90 style comments do the following once to cfortex.f: 
+NAGf90> mv cfortex.f cf_temp.f && sed 's/^C/\!/g' cf_temp.f > cfortex.f
+NAGf90> # In the following, 'CC' is any C compiler.
+NAGf90> CC -c -DNAGf90Fortran cfortest.c
+NAGf90> f90 -o cfortest cfortest.o cfortex.f &&  cfortest
+
+PC> # On a PC with PowerStation Fortran and Visual_C++
+PC> cl /c cftest.c
+PC> fl32  cftest.obj cftex.for
+
+GNU> # GNU Fortran
+GNU> # See Section VI caveat on using 'gcc -traditional'.
+GNU> gcc -ansi -Wall -O -c -Df2cFortran cfortest.c
+GNU> g77 -ff2c -o cfortest cfortest.o cfortex.f &&  cfortest
+
+AbsoftUNIX> # Absoft Fortran for all UNIX based operating systems.
+AbsoftUNIX> # e.g. Linux or Next on Intel or Motorola68000.
+AbsoftUNIX> # Absoft f77 -k allows Fortran routines to be safely called from C.
+AbsoftUNIX> gcc -ansi -Wall -O -c -DAbsoftUNIXFortran cfortest.c
+AbsoftUNIX> f77 -k -o cfortest cfortest.o cfortex.f && cfortest
+
+AbsoftPro> # Absoft Pro Fortran for MacOS
+AbsoftPro> # Use #define AbsoftProFortran
+
+CLIPPER> # INTERGRAPH CLIX using CLIPPER C and Fortran compilers.
+CLIPPER> # N.B. - User, not cfortran.h, is responsible for
+CLIPPER> #        f77initio() and f77uninitio() if required.
+CLIPPER> #      - LOGICAL values are not mentioned in CLIPPER doc.s,
+CLIPPER> #        so they may not yet be correct in cfortran.h.
+CLIPPER> #      - K&R mode (-knr or Ac=knr) breaks FLOAT functions
+CLIPPER> #        (see CLIPPER doc.s) and cfortran.h does not fix it up.
+CLIPPER> #        [cfortran.h ok for old sun C which made the same mistake.]
+CLIPPER> acc cfortest.c -c -DCLIPPERFortran
+CLIPPER> af77 cfortex.f cfortest.o -o cfortest
+
+
+By changing the SELECTion ifdef of cfortest.c and recompiling one can try out
+a few dozen different few-line examples.
+
+
+
+The benefits of using cfortran.h include:
+1. Machine/OS/compiler independent mixing of C and FORTRAN.
+
+2. Identical (within syntax) calls across languages, e.g.
+C FORTRAN
+      CALL HBOOK1(1,'pT spectrum of pi+',100,0.,5.,0.)
+/* C*/
+           HBOOK1(1,"pT spectrum of pi+",100,0.,5.,0.);
+
+3. Each routine need only be set up once in its lifetime. e.g.
+/* Setting up a FORTRAN routine to be called by C.
+   ID,...,VMX are merely the names of arguments.
+   These tags must be unique w.r.t. each other but are otherwise arbitrary. */
+PROTOCCALLSFSUB6(HBOOK1,hbook1,INT,STRING,INT,FLOAT,FLOAT,FLOAT)
+#define HBOOK1(ID,CHTITLE,NX,XMI,XMA,VMX)                        \
+     CCALLSFSUB6(HBOOK1,hbook1,INT,STRING,INT,FLOAT,FLOAT,FLOAT, \
+               ID,CHTITLE,NX,XMI,XMA,VMX) 
+
+4. Source code is NOT required for the C routines exported to FORTRAN, nor for
+   the FORTRAN routines imported to C. In fact, routines are most easily
+   prototyped using the information in the routines' documentation.
+
+5. Routines, and the code calling them, can be coded naturally in the language
+   of choice. C routines may be coded with the natural assumption of being 
+   called only by C code. cfortran.h does all the required work for FORTRAN 
+   code to call C routines. Similarly it also does all the work required for C
+   to call FORTRAN routines. Therefore:
+     - C programmers need not embed FORTRAN argument passing mechanisms into 
+       their code.
+     - FORTRAN code need not be converted into C code. i.e. The honed and 
+       time-honored FORTRAN routines are called by C.
+
+6. cfortran.h is a single ~1700 line C include file; portable to most
+   remaining, if not all, platforms.
+
+7. STRINGS and VECTORS of STRINGS along with the usual simple arguments to 
+   routines are supported as are functions returning STRINGS or numbers. Arrays
+   of pointers to strings and values of structures as C arguments, will soon be
+   implemented. After learning the machinery of cfortran.h, users can expand 
+   it to create custom types of arguments. [This requires no modification to
+   cfortran.h, all the preprocessor directives required to implement the
+   custom types can be defined outside cfortran.h]
+
+8. cfortran.h requires each routine to be exported to be explicitly set up. 
+   While is usually only be done once in a header file it would be best if
+   applications were required to do no work at all in order to cross languages.
+   cfortran.h's simple syntax could be a convenient back-end for a program
+   which would export FORTRAN or C routines directly from the source code. 
+
+
+                                    -----
+
+Example 1 - cfortran.h has been used to make the C header file hbook.h, 
+            which then gives any C programmer, e.g. example.c, full and 
+            completely transparent access to CERN's HBOOK library of routines.
+            Each HBOOK routine required about 3 lines of simple code in
+            hbook.h. The example also demonstrates how FORTRAN common blocks
+            are defined and used.
+
+/* hbook.h */
+#include "cfortran.h"
+        :
+PROTOCCALLSFSUB6(HBOOK1,hbook1,INT,STRING,INT,FLOAT,FLOAT,FLOAT)
+#define HBOOK1(ID,CHTITLE,NX,XMI,XMA,VMX)                        \
+     CCALLSFSUB6(HBOOK1,hbook1,INT,STRING,INT,FLOAT,FLOAT,FLOAT, \
+               ID,CHTITLE,NX,XMI,XMA,VMX) 
+        :
+/* end hbook.h */
+
+/* example.c */
+#include "hbook.h"
+        :
+typedef struct {
+  int lines;  
+  int status[SIZE];
+  float p[SIZE];  /* momentum */
+} FAKE_DEF;
+#define FAKE COMMON_BLOCK(FAKE,fake)
+COMMON_BLOCK_DEF(FAKE_DEF,FAKE);
+        :
+main ()
+{
+        :
+           HBOOK1(1,"pT spectrum of pi+",100,0.,5.,0.);
+/* c.f. the call in FORTRAN:
+      CALL HBOOK1(1,'pT spectrum of pi+',100,0.,5.,0.)
+*/
+        :
+  FAKE.p[7]=1.0;
+	:
+}           
+
+N.B. i) The routine is language independent.
+    ii) hbook.h is machine independent.  
+   iii) Applications using routines via cfortran.h are machine independent.
+
+                                    -----
+
+Example 2 - Many VMS System calls are most easily called from FORTRAN, but
+            cfortran.h now gives that ease in C.
+
+#include "cfortran.h"
+
+PROTOCCALLSFSUB3(LIB$SPAWN,lib$spawn,STRING,STRING,STRING)
+#define LIB$SPAWN(command,input_file,output_file)          \
+     CCALLSFSUB3(LIB$SPAWN,lib$spawn,STRING,STRING,STRING, \
+                  command,input_file,output_file)
+
+main ()
+{
+LIB$SPAWN("set term/width=132","","");
+}
+
+Obviously the cfortran.h command above could be put into a header file along
+with the description of the other system calls, but as this example shows, it's
+not much hassle to set up cfortran.h for even a single call.
+
+                                    -----
+
+Example 3 - cfortran.h and the source cstring.c create the cstring.obj library 
+            which gives FORTRAN access to all the functions in C's system 
+            library described by the system's C header file string.h.
+
+C     EXAMPLE.FOR
+      PROGRAM EXAMPLE
+      DIMENSION I(20), J(30)
+        :
+      CALL MEMCPY(I,J,7)
+        :
+      END
+
+/* cstring.c */
+#include <string.h>             /* string.h prototypes memcpy() */
+#include "cfortran.h"
+
+        :
+FCALLSCSUB3(memcpy,MEMCPY,memcpy,PVOID,PVOID,INT)
+        :
+
+
+The simplicity exhibited in the above example exists for many but not all
+machines. Note 4. of Section II ii) details the limitations and describes tools
+which try to maintain the best possible interface when FORTRAN calls C
+routines.
+
+                                    -----
+
+
+II Using cfortran.h
+-------------------
+
+The user is asked to look at the source files cfortest.c and cfortex.f
+for clarification by example.
+
+o) Notes: 
+
+o Specifying the Fortran compiler
+  cfortran.h generates interfaces for the default Fortran compiler. The default
+can be overridden by defining, 
+     . in the code,              e.g.: #define    NAGf90Fortran
+  OR . in the compile directive, e.g.: unix> cc -DNAGf90Fortran
+one of the following before including cfortran.h:
+ NAGf90Fortran   f2cFortran  hpuxFortran  apolloFortran  sunFortran
+  IBMR2Fortran  CRAYFortran  mipsFortran     DECFortran  vmsFortran
+ CONVEXFortran       PowerStationFortran          AbsoftUNIXFortran
+     SXFortran   pgiFortran                        AbsoftProFortran
+This also allows crosscompilation.
+If wanted, NAGf90Fortran, f2cFortran, DECFortran, AbsoftUNIXFortran,
+AbsoftProFortran and pgiFortran must be requested by the user.
+
+o /**/
+  cfortran.h (ab)uses the comment kludge /**/ when the ANSI C preprocessor
+catenation operator ## doesn't exist. In at least MIPS C, this kludge is
+sensitive to  blanks surrounding arguments to macros.
+  Therefore, for applications using non-ANSI C compilers, the argtype_i,
+routine_name, routine_type and common_block_name arguments to the
+PROTOCCALLSFFUNn, CCALLSFSUB/FUNn, FCALLSCSUB/FUNn and COMMON_BLOCK macros 
+--- MUST NOT --- be followed by any white space characters such as
+blanks, tabs or newlines.
+
+o LOGICAL
+  FORTRAN LOGICAL values of .TRUE. and .FALSE. do not agree with the C
+representation of TRUE and FALSE on all machines. cfortran.h does the
+conversion for LOGICAL and PLOGICAL arguments and for functions returning
+LOGICAL. Users must convert arrays of LOGICALs from C to FORTRAN with the 
+C2FLOGICALV(array_name, elements_in_array); macro. Similarly, arrays of LOGICAL
+values may be converted from the FORTRAN into C representation by using
+F2CLOGICALV(array_name, elements_in_array);
+
+  When C passes or returns LOGICAL values to FORTRAN, by default cfortran.h 
+only makes the minimal changes required to the value. [e.g. Set/Unset the 
+single relevant bit or do nothing for FORTRAN compilers which use 0 as FALSE
+and treat all other values as TRUE.] Therefore cfortran.h will pass LOGICALs
+to FORTRAN which do not have an identical representation to .TRUE. or .FALSE.
+This is fine except for abuses of FORTRAN/77 in the style of:
+       logical l
+       if (l .eq. .TRUE.)     ! (1)
+instead of the correct:
+       if (l .eqv. .TRUE.)    ! (2)
+or:
+       if (l)                 ! (3)
+For FORTRAN code which treats LOGICALs from C in the method of (1),
+LOGICAL_STRICT must be defined before including cfortran.h, either in the
+code, "#define LOGICAL_STRICT", or compile with "cc -DLOGICAL_STRICT".
+There is no reason to use LOGICAL_STRICT for FORTRAN code which does not do (1).
+At least the IBM's xlf and the Apollo's f77 do not even allow code along the
+lines of (1).
+
+  DECstations' DECFortran and MIPS FORTRAN compilers use different internal
+representations for LOGICAL values. [Both compilers are usually called f77,
+although when both are installed on a single machine the MIPS' one is usually
+renamed. (e.g. f772.1 for version 2.10.)] cc doesn't know which FORTRAN
+compiler is present, so cfortran.h assumes MIPS f77. To use cc with DECFortran
+define the preprocessor constant 'DECFortran'.
+e.g.        i)  cc -DDECFortran -c the_code.c
+        or  ii) #define DECFortran  /* in the C code or add to cfortran.h. */
+
+  MIPS f77 [SGI and DECstations], f2c, and f77 on VAX Ultrix treat
+.eqv./.neqv. as .eq./.ne.. Therefore, for these compilers, LOGICAL_STRICT is
+defined by default in cfortran.h. [The Sun and HP compilers have not been
+tested, so they may also require LOGICAL_STRICT as the default.]
+
+o SHORT and BYTE 
+  They are irrelevant for the CRAY where FORTRAN has no equivalent to C's short.
+Similarly BYTE is irrelevant for f2c and for VAX Ultrix f77 and fort. The
+author has tested SHORT and BYTE with a modified cfortest.c/cfortex.f on all
+machines supported except for the HP9000 and the Sun.
+
+  BYTE is a signed 8-bit quantity, i.e. values are -128 to 127, on all machines
+except for the SGI [at least for MIPS Computer Systems 2.0.] On the SGI it is
+an unsigned 8-bit quantity, i.e. values are 0 to 255, although the SGI 'FORTRAN
+77 Programmers Guide' claims BYTE is signed. Perhaps MIPS 2.0 is dated, since
+the DECstations using MIPS 2.10 f77 have a signed BYTE.
+
+  To minimize the difficulties of signed and unsigned BYTE, cfortran.h creates
+the type 'INTEGER_BYTE' to agree with FORTRAN's BYTE. Users may define 
+SIGNED_BYTE or UNSIGNED_BYTE, before including cfortran.h, to specify FORTRAN's
+BYTE. If neither is defined, cfortran.h assumes SIGNED_BYTE.
+
+o CRAY
+  The type DOUBLE in cfortran.h corresponds to FORTRAN's DOUBLE PRECISION.
+  The type FLOAT  in cfortran.h corresponds to FORTRAN's REAL.
+
+On a classic CRAY [i.e. all models except for the t3e]:
+( 64 bit) C float       == C double == Fortran REAL
+(128 bit) C long double             == Fortran DOUBLE PRECISION
+Therefore when moving a mixed C and FORTRAN app. to/from a classic CRAY,
+either the C code will have to change,
+or the FORTRAN code and cfortran.h declarations will have to change.
+DOUBLE_PRECISION is a cfortran.h macro which provides the former option,
+i.e. the C code is automatically changed.
+DOUBLE_PRECISION is 'long double' on classic CRAY and 'double' elsewhere.
+DOUBLE_PRECISION thus corresponds to FORTRAN's DOUBLE PRECISION
+on all machines, including classic CRAY.
+
+On a classic CRAY with the fortran compiler flag '-dp':
+Fortran DOUBLE PRECISION thus is also the faster 64bit type.
+(This switch is often used since the application is usually satisfied by
+ 64 bit precision and the application needs the speed.)
+DOUBLE_PRECISION is thus not required in this case,
+since the classic CRAY behaves like all other machines.
+If DOUBLE_PRECISION is used nonetheless, then on the classic CRAY
+the default cfortran.h behavior must be overridden,
+for example by the C compiler option '-DDOUBLE_PRECISION=double'.
+
+On a CRAY t3e:
+(32 bit) C float                   == Fortran Unavailable
+(64 bit) C double == C long double == Fortran REAL == Fortran DOUBLE PRECISION
+Notes:
+- (32 bit) is available as Fortran REAL*4 and
+  (64 bit) is available as Fortran REAL*8.
+  Since cfortran.h is all about more portability, not about less portability,
+  the use of the nonstandard REAL*4 and REAL*8 is strongly discouraged.
+- Fortran DOUBLE PRECISION is folded to REAL with the following warning:
+    'DOUBLE PRECISION is not supported on this platform.  REAL will be used.'
+  Similarly, Fortran REAL*16 is mapped to REAL*8 with a warning.
+This behavior differs from that of other machines, including the classic CRAY.
+FORTRAN_REAL is thus introduced for the t3e,
+just as DOUBLE_PRECISION is introduced for the classic CRAY.
+FORTRAN_REAL is 'double' on t3e and 'float' elsewhere.
+FORTRAN_REAL thus corresponds to FORTRAN's REAL on all machines, including t3e.
+
+
+o f2c
+  f2c, by default promotes REAL functions to double. cfortran.h does not (yet)
+support this, so the f2c -R option must be used to turn this promotion off.
+
+o f2c
+[Thanks to Dario Autiero for pointing out the following.]
+f2c has a strange feature in that either one or two underscores are appended
+to a Fortran name of a routine or common block,
+depending on whether or not the original name contains an underscore.
+
+   S.I. Feldman et al., "A fortran to C converter",
+   Computing Science Technical Report No. 149.
+
+   page 2, chapter 2: INTERLANGUAGE conventions
+   ...........
+   To avoid conflict with the names of library routines and with names that
+   f2c generates,
+   Fortran names may have one or two underscores appended. Fortran names are
+   forced to lower case (unless the -U option described in Appendix B is in
+   effect); external names, i.e. the names of fortran procedures and common
+   blocks, have a single underscore appended if they do not contain any
+   underscore and have a pair of underscores appended if they do contain
+   underscores. Thus fortran subroutines names ABC, A_B_C and A_B_C_ result
+   in C functions named abc_, a_b_c__ and a_b_c___.
+   ...........
+
+cfortran.h is unable to change the naming convention on a name by name basis.
+Fortran routine and common block names which do not contain an underscore
+are unaffected by this feature.
+Names which do contain an underscore may use the following work-around:
+
+/* First 2 lines are a completely standard cfortran.h interface
+   to the Fortran routine E_ASY . */
+                  PROTOCCALLSFSUB2(E_ASY,e_asy, PINT, INT)
+#define E_ASY(A,B)     CCALLSFSUB2(E_ASY,e_asy, PINT, INT, A, B)
+#ifdef f2cFortran
+#define e_asy_ e_asy__
+#endif
+/* Last three lines are a work-around for the strange f2c naming feature. */
+
+o NAG f90
+  The Fortran 77 subset of Fortran 90 is supported. Extending cfortran.h to 
+interface C with all of Fortran 90 has not yet been examined.
+  The NAG f90 library hijacks the main() of any program and starts the user's 
+program with a call to: void f90_main(void);
+While this in itself is only a minor hassle, a major problem arises because
+NAG f90 provides no mechanism to access command line arguments.
+  At least version 'NAGWare f90 compiler Version 1.1(334)' appended _CB to
+common block names instead of the usual _. To fix, add this to cfortran.h:
+#ifdef old_NAG_f90_CB_COMMON
+#define COMMON_BLOCK                 CFC_  /* for all other Fortran compilers */
+#else
+#define COMMON_BLOCK(UN,LN)          _(LN,_CB)
+#endif
+
+o RS/6000
+  Using "xlf -qextname ...", which appends an underscore, '_', to all FORTRAN
+external references, requires "cc -Dextname ..." so that cfortran.h also
+generates these underscores.
+Use -Dextname=extname if extname is a symbol used in the C code.
+The use of "xlf -qextname" is STRONGLY ENCOURAGED, since it allows for
+transparent naming schemes when mixing C and Fortran.
+
+o HP9000
+  Using "f77 +ppu      ...", which appends an underscore, '_', to all FORTRAN
+external references, requires "cc -Dextname ..." so that cfortran.h also
+generates these underscores.
+Use -Dextname=extname if extname is a symbol used in the C code.
+The use of "f77 +ppu"      is STRONGLY ENCOURAGED, since it allows for
+transparent naming schemes when mixing C and Fortran.
+
+  At least one release of the HP /lib/cpp.ansi preprocessor is broken and will
+go into an infinite loop when trying to process cfortran.h with the
+## catenation operator. The K&R version of cfortran.h must then be used and the
+K&R preprocessor must be specified. e.g.
+                                         HP9000> cc -Aa -tp,/lib/cpp -c source.c
+The same problem with a similar solution exists on the Apollo.
+An irrelevant error message '0: extraneous name /usr/include' will appear for
+each source file due to another HP bug, and can be safely ignored.
+e.g. 'cc -v -c -Aa -tp,/lib/cpp cfortest.c' will show that the driver passes
+'-I /usr/include' instead of '-I/usr/include' to /lib/cpp
+
+On some machines the above error causes compilation to stop; one must then use
+K&R C, as with old HP compilers which don't support function prototyping.
+cfortran.h has to be informed that K&R C is to being used, e.g.
+HP9000> cc -D__CF__KnR -c source.c
+
+o AbsoftUNIXFortran
+By default, cfortran.h follows the default AbsoftUNIX/ProFortran and prepends _C
+to each COMMON BLOCK name. To override the cfortran.h behavior
+#define COMMON_BLOCK(UN,LN) before #including cfortran.h.
+[Search for COMMON_BLOCK in cfortran.h for examples.]
+
+o Apollo
+On at least one release, 'C compiler 68K Rev6.8(168)', the default C 
+preprocessor, from cc -A xansi or cc -A ansi, enters an infinite loop when 
+using cfortran.h. This Apollo bug can be circumvented by using:
+     . cc -DANSI_C_preprocessor=0 to force use of /**/, instead of '##'.
+ AND . The pre-ANSI preprocessor, i.e. use cc -Yp,/usr/lib
+The same problem with a similar solution exists on the HP.
+
+o Sun
+Old versions of cc(1), say <~1986, may require help for cfortran.h applications:
+ . #pragma may not be understood, hence cfortran.h and cfortest.c may require
+   sun> mv cfortran.h cftmp.h && grep -v "^#pragma" <cftmp.h >cfortran.h
+   sun> mv cfortest.c cftmp.c && grep -v "^#pragma" <cftmp.c >cfortest.c
+ . Old copies of math.h may not include the following from a newer math.h.
+   [For an ancient math.h on a 386 or sparc, get similar from a new math.h.]
+   #ifdef mc68000     /* 5 lines Copyright (c) 1988 by Sun Microsystems, Inc. */
+   #define FLOATFUNCTIONTYPE	int
+   #define RETURNFLOAT(x) 		return (*(int *)(&(x)))
+   #define ASSIGNFLOAT(x,y)	*(int *)(&x) = y
+   #endif
+
+o CRAY, Sun, Apollo [pre 6.8 cc], VAX Ultrix and HP9000
+  Only FORTRAN routines with less than 15 arguments can be prototyped for C,
+since these compilers don't allow more than 31 arguments to a C macro. This can
+be overcome, [see Section IV], with access to any C compiler without this
+limitation, e.g. gcc, on ANY machine.
+
+o VAX Ultrix
+  vcc (1) with f77 is not supported. Although: 
+VAXUltrix> f77 -c cfortex.f
+VAXUltrix> vcc -o cfortest cfortest.c cfortex.o -lI77 -lU77 -lF77  &&  cfortest
+will link and run. However, the FORTRAN standard I/O is NOT merged with the
+stdin and stdout of C, and instead uses the files fort.6 and fort.5. For vcc,
+f77 can't drive the linking, as for gcc and cc, since vcc objects must be
+linked using lk (1).  f77 -v doesn't tell much, and without VAX Ultrix manuals,
+the author can only wait for the info. required.
+
+  fort (1) is not supported. Without VAX Ultrix manuals the author cannot 
+convince vcc/gcc/cc and fort to generate names of routines and COMMON blocks
+that match at the linker, lk (1). i.e. vcc/gcc/cc prepend a single underscore
+to external references, e.g. NAME becomes _NAME, while fort does not modify the
+references. So ... either fort has prepend an underscore to external
+references, or vcc/gcc/cc have to generate unmodified names. man 1 fort
+mentions JBL, is JBL the only way?
+
+o VAX VMS C
+  The compiler 'easily' exhausts its table space and generates:
+%CC-F-BUGCHECK, Compiler bug check during parser phase    .
+                Submit an SPR with a problem description.
+                At line number 777 in DISK:[DIR]FILE.C;1.
+where the line given, '777', includes a call across C and FORTRAN via
+cfortran.h, usually with >7 arguments and/or very long argument expressions.
+This SPR can be staved off, with the simple modification to cfortran.h, such
+that the relevant CCALLSFSUBn (or CCALLSFFUNn or FCALLSCFUNn) is not
+cascaded up to CCALLSFSUB14, and instead has its own copy of the contents of 
+CCALLSFSUB14. [If these instructions are not obvious after examining cfortran.h
+please contact the author.]
+[Thanks go to Mark Kyprianou (kyp at stsci.edu) for this solution.]
+
+o Mips compilers
+  e.g. DECstations and SGI, require applications with a C main() and calls to
+GETARG(3F), i.e. FORTRAN routines returning the command line arguments, to use
+two macros as shown:
+        :
+CF_DECLARE_GETARG;              /* This must be external to all routines.     */
+        :
+main(int argc, char *argv[])
+{
+        :
+CF_SET_GETARG(argc,argv);       /* This must precede any calls to GETARG(3F). */
+        :
+}
+The macros are null and benign on all other systems. Sun's GETARG(3F) also
+doesn't work with a generic C main() and perhaps a workaround similar to the
+Mips' one exists.
+
+o Alpha/OSF
+Using the DEC Fortran and the DEC C compilers of DEC OSF/1 [RT] V1.2 (Rev. 10),
+Fortran, when called from C, has occasional trouble using a routine received as
+a dummy argument.
+
+e.g. In the following the Fortran routine 'e' will crash when it tries to use
+     the C routine 'c' or the Fortran routine 'f'.
+     The example works on other systems.
+
+C FORTRAN                           /* C */
+      integer function f()          #include <stdio.h>
+      f = 2                         int f_();
+      return                        int e_(int (*u)());
+      end
+                                    int c(){ return 1;}
+      integer function e(u)         int d (int (*u)()) { return u();}
+      integer u
+      external u                    main()
+      e=u()                         {         /* Calls to d  work.  */
+      return                        printf("d (c ) returns %d.\n",d (c ));
+      end                           printf("d (f_) returns %d.\n",d (f_));
+                                              /* Calls to e_ crash. */
+                                    printf("e_(c ) returns %d.\n",e_(c ));
+                                    printf("e_(f_) returns %d.\n",e_(f_));
+                                    }
+
+Solutions to the problem are welcomed!
+A kludge which allows the above example to work correctly, requires an extra
+argument to be given when calling the dummy argument function.
+i.e. Replacing 'e=u()' by 'e=u(1)' allows the above example to work.
+
+
+o The FORTRAN routines are called using macro expansions, therefore the usual
+caveats for expressions in arguments apply. The expressions to the routines may
+be evaluated more than once, leading to lower performance and in the worst case
+bizarre bugs.
+
+o For those who wish to use cfortran.h in large applications. [See Section IV.]
+This release is intended to make it easy to get applications up and running. 
+This implies that applications are not as efficient as they could be:
+- The current mechanism is inefficient if a single header file is used to
+  describe a large library of FORTRAN functions. Code for a static wrapper fn.
+  is generated in each piece of C source code for each FORTRAN function 
+  specified with the CCALLSFFUNn statement, irrespective of whether or not the
+  function is ever called. 
+- Code for several static utility routines internal to cfortran.h is placed 
+  into any source code which #includes cfortran.h. These routines should
+  probably be in a library.
+
+
+i) Calling FORTRAN routines from C:
+   --------------------------------
+
+The FORTRAN routines are defined by one of the following two instructions:
+
+for a SUBROUTINE:
+/* PROTOCCALLSFSUBn is optional for C, but mandatory for C++. */
+PROTOCCALLSFSUBn(ROUTINE_NAME,routine_name,argtype_1,...,argtype_n)
+#define     Routine_name(argname_1,..,argname_n)               \
+CCALLSFSUBn(ROUTINE_NAME,routine_name,argtype_1,...,argtype_n, \
+                         argname_1,..,argname_n) 
+
+for a FUNCTION:
+PROTOCCALLSFFUNn(routine_type,ROUTINE_NAME,routine_name,argtype_1,...,argtype_n)
+#define     Routine_name(argname_1,..,argname_n)               \
+CCALLSFFUNn(ROUTINE_NAME,routine_name,argtype_1,...,argtype_n, \
+                         argname_1,..,argname_n) 
+
+Where:
+'n' = 0->14 [SUBROUTINE's ->27] (easily expanded in cfortran.h to > 14 [27]) is 
+    the number of arguments to the routine.
+Routine_name = C       name of the routine (IN UPPER CASE LETTERS).[see 2.below]
+ROUTINE_NAME = FORTRAN name of the routine (IN UPPER CASE LETTERS).
+routine_name = FORTRAN name of the routine (IN lower case LETTERS).
+routine_type = the type of argument returned by FORTRAN functions.
+             = BYTE, DOUBLE, FLOAT, INT, LOGICAL, LONG, SHORT, STRING, VOID.
+               [Instead of VOID one would usually use CCALLSFSUBn.
+                VOID forces a wrapper function to be used.]
+argtype_i    = the type of argument passed to the FORTRAN routine and must be
+               consistent in the definition and prototyping of the routine s.a.
+             = BYTE, DOUBLE, FLOAT, INT, LOGICAL, LONG, SHORT, STRING.
+             For vectors, i.e. 1 dim. arrays use 
+             = BYTEV, DOUBLEV, FLOATV, INTV, LOGICALV, LONGV, SHORTV, 
+               STRINGV, ZTRINGV.
+             For vectors of vectors, i.e. 2 dim. arrays use
+             = BYTEVV, DOUBLEVV, FLOATVV, INTVV, LOGICALVV, LONGVV, SHORTVV.
+             For n-dim. arrays, 1<=n<=7 [7 is the maximum in Fortran 77],
+             = BYTEV..nV's..V, DOUBLEV..V, FLOATV..V, INTV..V, LOGICALV..V, 
+               LONGV..V, SHORTV..V.
+                N.B. Array dimensions and types are checked by the C compiler.
+             For routines changing the values of an argument, the keyword is 
+                  prepended by a 'P'.
+             = PBYTE, PDOUBLE, PFLOAT, PINT, PLOGICAL, PLONG, PSHORT,
+               PSTRING, PSTRINGV, PZTRINGV.
+             For EXTERNAL procedures passed as arguments use
+             = ROUTINE.
+             For exceptional arguments which require no massaging to fit the
+                  argument passing mechanisms use
+             = PVOID.
+                The argument is cast and passed as (void *).
+                Although PVOID could be used to describe all array arguments on
+                most (all?) machines , it shouldn't be because the C compiler
+                can no longer check the type and dimension of the array.
+argname_i    = any valid unique C tag, but must be consistent in the definition 
+               as shown.
+
+Notes:
+
+1. cfortran.h may be expanded to handle a more argument type. To suppport new
+arguments requiring complicated massaging when passed  between Fortran and C,
+the user will have to understand cfortran.h and follow its code and mechanisms.
+
+To define types requiring little or no massaging when passed between Fortran 
+and C, the pseudo argument type SIMPLE may be used.
+For a user defined type called 'newtype', the definitions required are:
+
+/* The following 7 lines are required verbatim.
+   'newtype' is the name of the new user defined argument type.
+*/
+#define newtype_cfV(  T,A,B,F)       SIMPLE_cfV(T,A,B,F)
+#define newtype_cfSEP(T,  B)         SIMPLE_cfSEP(T,B)
+#define newtype_cfINT(N,A,B,X,Y,Z)   SIMPLE_cfINT(N,A,B,X,Y,Z)
+#define newtype_cfSTR(N,T,A,B,C,D,E) SIMPLE_cfSTR(N,T,A,B,C,D,E)
+#define newtype_cfCC( T,A,B)         SIMPLE_cfCC(T,A,B)
+#define newtype_cfAA( T,A,B)         newtype_cfB(T,A) /* Argument B not used. */
+#define newtype_cfU(  T,A)           newtype_cfN(T,A)
+
+/* 'parameter_type(A)' is a declaration for 'A' and describes the type of the 
+parameter expected by the Fortran function.  This type will be used in the
+prototype for the function, if  using ANSI C, and to declare the argument used
+by the intermediate function if calling a Fortran FUNCTION.
+Valid 'parameter_type(A)' include: int A
+                                   void (*A)()
+                                   double A[17]
+*/
+#define newtype_cfN(  T,A)     parameter_type(A)      /* Argument T not used. */
+
+/* Before any argument of the new type is passed to the Fortran routine, it may
+be massaged as given by 'massage(A)'.
+*/
+#define newtype_cfB(  T,A)     massage(A)             /* Argument T not used. */
+
+An example of a simple user defined type is given cfortex.f and cfortest.c.
+Two uses of SIMPLE user defined types are [don't show the 7 verbatim #defines]:
+
+/* Pass the address of a structure, using a type called PSTRUCT */
+#define PSTRUCT_cfN(  T,A)        void *A
+#define PSTRUCT_cfB(  T,A)       (void *) &(A)
+
+/* Pass an integer by value, (not standard F77 ), using a type called INTVAL */
+#define INTVAL_cfN(   T,A)      int A
+#define INTVAL_cfB(   T,A)         (A)
+
+[If using VAX VMS, surrounding the #defines with "#pragma (no)standard" allows
+ the %CC-I-PARAMNOTUSED messages to be avoided.]
+
+Upgrades to cfortran.h try to be, and have been, backwards compatible. This
+compatibility cannot be offered to user defined types. SIMPLE user defined 
+types are less of a risk since they require so little effort in their creation.
+If a user defined type is required in more than one C header file of interfaces
+to libraries of Fortran routines, good programming practice, and ease of code
+maintenance, suggests keeping any user defined type within a single file which
+is #included as required. To date, changes to the SIMPLE macros were introduced
+in versions 2.6, 3.0 and 3.2 of cfortran.h.
+
+
+2. Routine_name is the name of the macro which the C programmer will use in
+order to call a FORTRAN routine. In theory Routine_name could be any valid and
+unique name, but in practice, the name of the FORTRAN routine in UPPER CASE
+works everywhere and would seem to be an obvious choice.
+
+
+3. <BYTE|DOUBLE|BYTE|DOUBLE|FLOAT|INT|LOGICAL|LONG|SHORT><V|VV|VVV|...>
+
+cfortran.h encourages the exact specification of the type and dimension of
+array parameters because it allows the C compiler to detect errors in the
+arguments when calling the routine.
+
+cfortran.h does not strictly require the exact specification since the argument 
+is merely the address of the array and is passed on to the calling routine.
+Any array parameter could be declared as PVOID, but this circumvents
+C's compiletime ability to check the correctness of arguments and is therefore
+discouraged.
+
+Passing the address of these arguments implies that PBYTEV, PFLOATV, ... ,
+PDOUBLEVV, ... don't exist in cfortran.h, since by default the routine and the
+calling code share the same array, i.e. the same values at the same memory
+location.
+
+These comments do NOT apply to arrays of (P)S/ZTRINGV. For these parameters,
+cfortran.h passes a massaged copy of the array to the routine. When the routine
+returns, S/ZTRINGV ignores the copy, while PS/ZTRINGV replaces the calling
+code's original array with copy, which may have been modified by the called
+routine.
+
+
+4. (P)STRING(V):
+- STRING - If the argument is a fixed length character array, e.g. char ar[8];,
+the string is blank, ' ', padded on the right to fill out the array before
+being passed to the FORTRAN routine. The useful size of the string is the same
+in both languages, e.g. ar[8] is passed as character*7. If the argument is a
+pointer, the string cannot be blank padded, so the length is passed as
+strlen(argument). On return from the FORTRAN routine, pointer arguments are not
+disturbed, but arrays have the terminating '\0' replaced to its original
+position. i.e. The padding blanks are never visible to the C code.
+
+- PSTRING - The argument is massaged as with STRING before being passed to the
+FORTRAN routine. On return, the argument has all trailing blanks removed,
+regardless of whether the argument was a pointer or an array.
+
+- (P)STRINGV - Passes a 1- or 2-dimensional char array. e.g. char a[7],b[6][8];
+STRINGV may thus also pass a string constant, e.g. "hiho".
+(P)STRINGV does NOT pass a pointer, e.g. char *, to either a 1- or a
+2-dimensional array, since it cannot determine the array dimensions.
+A pointer can only be passed using (P)ZTRINGV.
+N.B. If a C routine receives a character array argument, e.g. char a[2][3],
+     such an argument is actually a pointer and my thus not be passed by
+     (P)STRINGV. Instead (P)ZTRINGV must be used.
+
+- STRINGV - The elements of the argument are copied into space malloc'd, and
+each element is padded with blanks. The useful size of each element is the same
+in both languages. Therefore char bb[6][8]; is equivalent to character*7 bb(6).
+On return from the routine the malloc'd space is simply released.
+
+- PSTRINGV - Since FORTRAN has no trailing '\0', elements in an array of
+strings are contiguous. Therefore each element of the C array is padded with
+blanks and strip out C's trailing '\0'. After returning from the routine, the
+trailing '\0' is reinserted and kill the trailing blanks in each element.
+
+- SUMMARY: STRING(V) arguments are blank padded during the call to the FORTRAN
+routine, but remain original in the C code. (P)STRINGV arguments are blank
+padded for the FORTRAN call, and after returning from FORTRAN trailing blanks
+are stripped off.
+
+
+5. (P)ZTRINGV:
+- (P)ZTRINGV - is identical to (P)STRINGV,
+except that the dimensions of the array of strings is explicitly specified,
+which thus also allows a pointer to be passed.
+(P)ZTRINGV can thus pass a 1- or 2-dimensional char array, e.g. char b[6][8],
+or it can pass a pointer to such an array, e.g. char *p;.
+ZTRINGV may thus also pass a string constant, e.g. "hiho".
+If passing a 1-dimensional array, routine_name_ELEMS_j (see below) must be 1.
+[Users of (P)ZTRINGV should examine cfortest.c for examples.]:
+
+- (P)ZTRINGV must thus be used instead of (P)STRINGV whenever sizeof()
+can't be used to determine the dimensions of the array of string or strings.
+e.g. when calling FORTRAN from C with a char * received by C as an argument.
+
+- There is no (P)ZTRING type, since (P)ZTRINGV can pass a 1-dimensional
+array or a pointer to such an array, e.g. char a[7], *b;
+If passing a 1-dimensional array, routine_name_ELEMS_j (see below) must be 1.
+
+- To specify the numbers of elements,
+routine_name_ELEMS_j and routine_name_ELEMLEN_j must be defined as shown below
+before interfacing the routine with CCALLSFSUBn, PROTOCCALLSFFUNn, etc.
+
+#define routine_name_ELEMS_j   ZTRINGV_ARGS(k)       
+                                 [..ARGS for subroutines, ..ARGF for functions.]
+or
+#define routine_name_ELEMS_j   ZTRINGV_NUM(l)
+Where: routine_name is as above.
+       j            [1-n], is the argument being specifying.
+       k            [1-n], the value of the k'th argument is the dynamic number
+                    of elements for argument j. The k'th argument must be
+                    of type BYTE, DOUBLE, FLOAT, INT, LONG or SHORT.
+       l            the number of elements for argument j. This must be an
+                    integer constant available at compile time.
+                    i.e. it is static.
+
+- Similarly to specify the useful length, [i.e. don't count C's trailing '\0',]
+of each element:
+#define routine_name_ELEMLEN_j ZTRINGV_ARGS(m)
+                                 [..ARGS for subroutines, ..ARGF for functions.]
+or
+#define routine_name_ELEMLEN_j ZTRINGV_NUM(q)
+Where: m            [1-n], as for k but this is the length of each element. 
+       q            as for l but this is the length of each element. 
+
+
+6. ROUTINE
+The argument is an EXTERNAL procedure.
+
+When C passes a routine to Fortran, the language of the function must be
+specified as follows:  [The case of some_*_function must be given as shown.]
+
+When C passes a C routine to a Fortran: 
+    FORTRAN_ROUTINE(arg1, .... ,       
+                    C_FUNCTION(SOME_C_FUNCTION,some_c_function),
+                    ...., argn);
+
+and similarly when C passes a Fortran routine to Fortran:
+    FORTRAN_ROUTINE(arg1, .... ,
+                    FORTRAN_FUNCTION(SOME_FORT_FUNCTION,some_fort_function),
+                    ...., argn);
+
+If fcallsc has been redefined; the same definition of fcallsc used when creating
+the wrapper for 'some_c_function' must also be defined when C_FUNCTION is used.
+See ii) 4. of this section for when and how to redefine fcallsc.
+
+ROUTINE was introduced with cfortran.h version 2.6. Earlier versions of
+cfortran.h used PVOID to pass external procedures as arguments. Using PVOID for
+this purpose is no longer recommended since it won't work 'as is' for
+apolloFortran, hpuxFortran800, AbsoftUNIXFortran, AbsoftProFortran.
+
+7. CRAY only: 
+In a given piece of source code, where FFUNC is any FORTRAN routine,
+FORTRAN_FUNCTION(FFUNC,ffunc)
+disallows a previous 
+#define FFUNC(..) CCALLSFSUBn(FFUNC,ffunc,...) [ or CCALLSFFUNn]
+in order to make the UPPER CASE FFUNC callable from C.
+#define Ffunc(..) ... is OK though, as are obviously any other names.
+
+
+ii) Calling C routines from FORTRAN:
+    --------------------------------
+
+Each of the following two statements to export a C routine to FORTRAN create
+FORTRAN 'wrappers', written in C, which must be compiled and linked along with
+the original C routines and with the FORTRAN calling code.
+
+FORTRAN callable 'wrappers' may also be created for C macros. i.e. in this
+section, the term 'C function' may be replaced by 'C macro'.
+
+for C functions returning void:
+FCALLSCSUBn(             Routine_name,ROUTINE_NAME,routine_name,argtype_1,...,argtype_n)
+
+for all other C functions:
+FCALLSCFUNn(routine_type,Routine_name,ROUTINE_NAME,routine_name,argtype_1,...,argtype_n)
+
+Where:
+'n' = 0->27 (easily expanded to > 27) stands for the number of arguments to the 
+    routine.
+Routine_name = the C       name of the routine. [see 9. below]
+ROUTINE_NAME = the FORTRAN name of the routine (IN UPPER CASE LETTERS).
+routine_name = the FORTRAN name of the routine (IN lower case LETTERS).
+routine_type = the type of argument returned by C functions.
+             = BYTE, DOUBLE, FLOAT, INT, LOGICAL, LONG, SHORT, STRING, VOID.
+               [Instead of VOID, FCALLSCSUBn is recommended.]
+argtype_i    = the type of argument passed to the FORTRAN routine and must be
+               consistent in the definition and prototyping of the routine
+             = BYTE, DOUBLE, FLOAT, INT, LOGICAL, LONG, SHORT, STRING.
+             For vectors, i.e. 1 dim. arrays use 
+             = BYTEV, DOUBLEV, FLOATV, INTV, LOGICALV, LONGV, SHORTV, STRINGV.
+             For vectors of vectors, 2 dim. arrays use
+             = BYTEVV, DOUBLEVV, FLOATVV, INTVV, LOGICALVV, LONGVV, SHORTVV.
+             For n-dim. arrays use
+             = BYTEV..nV's..V, DOUBLEV..V, FLOATV..V, INTV..V, LOGICALV..V, 
+               LONGV..V, SHORTV..V.
+             For routines changing the values of an argument, the keyword is 
+                  prepended by a 'P'.
+             = PBYTE, PDOUBLE, PFLOAT, PINT, PLOGICAL, PLONG, PSHORT, 
+               PSTRING, PNSTRING, PPSTRING, PSTRINGV.
+             For EXTERNAL procedures passed as arguments use
+             = ROUTINE.
+             For exceptional arguments which require no massaging to fit the
+                  argument passing mechanisms use
+             = PVOID.
+                The argument is cast and passed as (void *).
+
+
+Notes:
+
+0. For Fortran calling C++ routines, C++ does NOT easily allow support for: 
+   STRINGV.
+   BYTEVV, DOUBLEVV, FLOATVV, INTVV, LOGICALVV, LONGVV, SHORTVV.
+   BYTEV..V, DOUBLEV..V, FLOATV..V, INTV..V, LOGICALV..V, LONGV..V, SHORTV..V.
+Though there are ways to get around this restriction,
+the restriction is not serious since these types are unlikely to be used as
+arguments for a C++ routine.
+
+1. FCALLSCSUB/FUNn expect that the routine to be 'wrapped' has been properly
+prototyped, or at least declared.
+
+
+2. cfortran.h may be expanded to handle a new argument type not already among
+the above. 
+
+
+3. <BYTE|DOUBLE|BYTE|DOUBLE|FLOAT|INT|LOGICAL|LONG|SHORT><V|VV|VVV|...>
+
+cfortran.h encourages the exact specification of the type and dimension of
+array parameters because it allows the C compiler to detect errors in the
+arguments when declaring the routine using FCALLSCSUB/FUNn, assuming the
+routine to be 'wrapped' has been properly prototyped.
+
+cfortran.h does not strictly require the exact specification since the argument 
+is merely the address of the array and is passed on to the calling routine.
+Any array parameter could be declared as PVOID, but this circumvents
+C's compiletime ability to check the correctness of arguments and is therefore
+discouraged.
+
+Passing the address of these arguments implies that PBYTEV, PFLOATV, ... ,
+PDOUBLEVV, ... don't exist in cfortran.h, since by default the routine and the
+calling code share the same array, i.e. the same values at the same memory
+location.
+
+These comments do NOT apply to arrays of (P)STRINGV. For these parameters,
+cfortran.h passes a massaged copy of the array to the routine. When the routine
+returns, STRINGV ignores the copy, while PSTRINGV replaces the calling
+code's original array with copy, which may have been modified by the called
+routine.
+
+
+4. (P(N))STRING arguments have any trailing blanks removed before being passed
+to C, the same holds true for each element in (P)STRINGV. Space is malloc'd in
+all cases big enough to hold the original string (elements) as well as C's
+terminating '\0'. i.e. The useful size of the string (elements) is the same in
+both languages. P(N)STRING(V) => the string (elements) will be copied from the
+malloc'd space back into the FORTRAN bytes. If one of the two escape mechanisms
+mentioned below for PNSTRING has been used, the copying back to FORTRAN is
+obviously not relevant.
+
+
+5. (PN)STRING's, [NOT PSTRING's nor (P)STRINGV's,] behavior may be overridden
+in two cases.  In both cases PNSTRING and STRING behave identically.
+
+a) If a (PN)STRING argument's first 4 bytes are all the NUL character,
+i.e. '\0\0\0\0' the NULL pointer is passed to the C routine.
+
+b) If the characters of a (PN)STRING argument contain at least one HEX-00, i.e.
+the NUL character, i.e. C strings' terminating '\0', the address of the string
+is simply passed to the C routine. i.e. The argument is treated in this case as
+it would be with PPSTRING, to which we refer the reader for more detail.
+
+Mechanism a) overrides b). Therefore, to use this mechanism to pass the NULL
+string, "", to C, the first character of the string must obviously be the NUL
+character, but of the first 4 characters in the string, at least one must not
+be HEX-00.
+
+Example:
+C FORTRAN                         /* C */
+      character*40 str            #include "cfortran.h"
+C Set up a NULL as :              void cs(char *s) {if (s) printf("%s.\n",s);}
+C    i)  4 NUL characters.        FCALLSCSUB1(cs,CS,cs,STRING)
+C    ii) NULL pointer.
+      character*4 NULL        
+      NULL = CHAR(0)//CHAR(0)//CHAR(0)//CHAR(0)
+
+      data str/'just some string'/
+
+C Passing the NULL pointer to cs.
+      call cs(NULL)
+C Passing a copy of 'str' to cs.
+      call cs(str)
+C Passing address of 'str' to cs. Trailing blanks NOT killed.
+      str(40:) = NULL
+      call cs(str)
+      end
+
+Strings passed from Fortran to C via (PN)STRING must not have undefined
+contents, otherwise undefined behavior will result, since one of the above two
+escape mechanisms may occur depending on the contents of the string.
+
+This is not be a problem for STRING arguments, which are read-only in the C
+routine and hence must have a well defined value when being passed in.
+
+PNSTRING arguments require special care. Even if they are write-only in the C
+routine, PNSTRING's above two escape mechanisms require that the value of the
+argument be well defined when being passed in from Fortran to C. Therefore,
+unless one or both of PNSTRING's escape mechanisms are required, PSTRING should
+be used instead of PNSTRING.
+Prior to version 2.8, PSTRING did have the above two escape mechanisms,
+but they were removed from PSTRING to allow strings with undefined contents to
+be passed in. PNSTRING behaves like the old PSTRING.
+[Thanks go to Paul Dubois (dubios at icf.llnl.gov) for pointing out that PSTRING
+ must allow for strings with undefined contents to be passed in.]
+
+Example:
+C FORTRAN                         /* C */
+      character*10 s,sn           #include "cfortran.h"
+                                  void ps(char *s) {strcpy(s,"hello");}
+C Can   call ps  with undef. s.   FCALLSCSUB1(ps,PS,ps,PSTRING)
+      call ps(s)                  FCALLSCSUB1(ps,PNS,pns,PNSTRING)
+      print *,s,'=s'
+                              
+C Can't call pns with undef. s.
+C e.g. If first 4 bytes of s were
+C      "\0\0\0\0", ps would try
+C      to copy to NULL because
+C      of PNSTRING mechanism.
+      sn = ""
+      call pns(sn)
+      print *,sn,'=sn'
+                                               
+      end
+
+
+6. PPSTRING
+The address of the string argument is simply passed to the C routine. Therefore
+the C routine and the FORTRAN calling code share the same string at the same
+memory location. If the C routine modifies the string, the string will also be
+modified for the FORTRAN calling code.
+The user is responsible for negociating the differences in representation of a
+string in Fortran and in C, i.e. the differences are not automatically resolved
+as they are for (P(N)STRING(V).
+This mechanism is provided for two reasons:
+   - Some C routines require the string to exist at the given memory location, 
+     after the C routine has exited. Recall that for the usual (P(N)STRING(V)
+     mechanism, a copy of the FORTRAN string is given to the C routine, and this
+     copy ceases to exist after returning to the FORTRAN calling code.
+   - This mechanism can save runtime CPU cycles over (P(N)STRING(V), since it
+     does not perform their malloc, copy and kill trailing blanks of the string
+     to be passed.
+     Only in a small minority of cases does the potential benefit of the saved
+     CPU cycles outweigh the programming effort required to manually resolve
+     the differences in representation of a string in Fortran and in C.
+
+For arguments passed via PPSTRING, the argument passed may also be an array of
+strings.
+
+
+7. ROUTINE
+ANSI C requires that the type of the value returned by the routine be known,
+For all ROUTINE arguments passed from Fortran to C, the type of ROUTINE is
+specified by defining a cast as follows:
+
+#undef  ROUTINE_j
+#define ROUTINE_j   (cast)
+where:
+       j            [1-n], is the argument being specifying.
+       (cast)       is a cast matching that of the argument expected by the C
+                    function protoytpe for which a wrapper is being defined.
+
+e.g. To create a Fortran wrapper for qsort(3C):
+#undef  ROUTINE_4
+#define ROUTINE_4 (int (*)(void *,void *))
+FCALLSCSUB4(qsort,FQSORT,fqsort,PVOID,INT,INT,ROUTINE)
+
+In order to maintain backward compatibility, cfortran.h defines a generic cast
+for ROUTINE_1, ROUTINE_2, ..., ROUTINE_27. The user's definition is therefore
+strictly required only for DEC C, which at the moment is the only compiler
+which insists on the correct cast for pointers to functions.
+
+When using the ROUTINE argument inside some Fortran code:
+- it is difficult to pass a C routine as the parameter,
+  since in many Fortran implementations,
+  Fortran has no access to the normal C namespace.
+  e.g. For most UNIX,
+       Fortran implicitly only has access to C routines ending in _.
+  If the calling Fortran code receives the routine as a parameter
+  it can of course easily pass it along.
+- if a Fortran routine is passed directly as the parameter,
+  the called C routine must call the parameter routine
+  using the Fortran argument passing conventions.
+- if a Fortran routine is to be passed as the parameter,
+  but if Fortran can be made to pass a C routine as the parameter,
+  then it may be best to pass a C-callable wrapper for the Fortran routine.
+  The called C routine is thus spared all Fortran argument passing conventions.
+  cfortran.h can be used to create such a C-callable wrapper
+  to the parameter Fortran routine.
+
+ONLY PowerStationFortran:
+This Fortran provides no easy way to pass a Fortran routine as an argument to a
+C routine. The problem arises because in Fortran the stack is cleared by the
+called routine, while in C/C++ it is cleared by the caller.
+The C/C++ stack clearing behavior can be changed to that of Fortran by using
+stdcall__ in the function prototype. The stdcall__ cannot be applied in this
+case since the called C routine expects the ROUTINE parameter to be a C routine
+and does not know that it should apply stdcall__.
+In principle the cfortran.h generated Fortran callable wrapper for the called C
+routine should be able to massage the ROUTINE argument such that stdcall__ is
+performed, but it is not yet known how this could be easily done.
+
+
+8. THE FOLLOWING INSTRUCTIONS ARE NOT REQUIRED FOR VAX VMS
+                                  ------------
+(P)STRINGV information [NOT required for VAX VMS]: cfortran.h cannot convert
+the FORTRAN vector of STRINGS to the required C vector of STRINGS without
+explicitly knowing the number of elements in the vector. The application must
+do one of the following for each (P)STRINGV argument in a routine before that
+routine's FCALLSCFUNn/SUBn is called:
+
+#define routine_name_STRV_Ai NUM_ELEMS(j)
+ or
+#define routine_name_STRV_Ai NUM_ELEM_ARG(k)
+ or
+#define routine_name_STRV_Ai TERM_CHARS(l,m)
+
+where: routine_name     is as above.
+       i [i=1->n.]      specifies the argument number of a STRING VECTOR.
+       j                would specify a fixed number of elements. 
+       k [k=1->n. k!=i] would specify an integer argument which specifies the
+                        number of elements.
+       l [char]         the terminating character at the beginning of an
+                        element, indicating to cfortran.h that the preceding
+                        elements in the vector are the valid ones.
+       m [m=1-...]      the number of terminating characters required to appear
+                        at the beginning of the terminating string element.
+                        The terminating element is NOT passed on to 
+                        the C routine.
+
+e.g.      #define ce_STRV_A1 TERM_CHARS(' ',2)
+          FCALLSCSUB1(ce,CE,ce,STRINGV)
+
+cfortran.h will pass on all elements, in the 1st and only argument to the C
+routine ce, of the STRING VECTOR until, but not including, the first string
+element beginning with 2 blank, ' ', characters.
+
+
+9. INSTRUCTIONS REQUIRED ONLY FOR FORTRAN COMPILERS WHICH GENERATE
+                -------------     
+   ROUTINE NAMES WHICH ARE UNDISTINGUISHABLE FROM C ROUTINE NAMES
+   i.e. VAX VMS
+        AbsoftUNIXFortran (AbsoftProFortran ok, since it uses Uppercase names.)
+        HP9000      if not using the +ppu      option of f77
+        IBM RS/6000 if not using the -qextname option of xlf
+   Call them the same_namespace compilers.
+
+FCALLSCSUBn(...) and FCALLSCFUNn(...), when compiled, are expanded into
+'wrapper' functions, so called because they wrap around the original C 
+functions and interface the format of the original C functions' arguments and
+return values with the format of the FORTRAN call.
+
+Ideally one wants to be able to call the C routine from FORTRAN using the same
+name as the original C name. This is not a problem for FORTRAN compilers which
+append an underscore, '_', to the names of routines, since the original C
+routine has the name 'name', and the FORTRAN wrapper is called 'name_'.
+Similarly, if the FORTRAN compiler generates upper case names for routines, the
+original C routine 'name' can have a wrapper called 'NAME', [Assuming the C
+routine name is not in upper case.] For these compilers, e.g. Mips, CRAY, IBM
+RS/6000 'xlf -qextname', HP-UX 'f77 +ppu', the naming of the wrappers is done
+automatically.
+
+For same_namespace compilers things are not as simple, but cfortran.h tries to
+provide tools and guidelines to minimize the costs involved in meeting their
+constraints. The following two options can provide same_namespace compilers
+with distinct names for the wrapper and the original C function.
+
+These compilers are flagged by cfortran.h with the CF_SAME_NAMESPACE  constant,
+so that the change in the C name occurs only when required.
+
+For the remainder of the discussion, routine names generated by FORTRAN
+compilers are referred to in lower case, these names should be read as upper
+case for the appropriate compilers.
+
+
+HP9000: (When f77 +ppu is not used.)
+f77 has a -U option which forces uppercase external names to be generated.
+Unfortunately, cc does not handle recursive macros. Hence, if one wished to use
+-U for separate C and FORTRAN namespaces, one would have to adopt a different
+convention of naming the macros which allow C to call FORTRAN subroutines.
+(Functions are not a problem.) The macros are currently the uppercase of the
+original FORTRAN name, and would have to be changed to lower case or mixed
+case, or to a different name. (Lower case would of course cause conflicts on
+many other machines.) Therefore, it is suggested that f77 -U  not be used, and
+instead that Option a) or Option b) outlined below be used.
+
+
+VAX/VMS:
+For the name used by FORTRAN in calling a C routine to be the same as that of
+the C routine, the source code of the C routine is required. A preprocessor
+directive can then force the C compiler to generate a different name for the C
+routine. 
+e.g.                #if defined(vms)
+                    #define name name_
+                    #endif
+                    void name() {printf("name: was called.\n");}
+                    FCALLSCSUB0(name,NAME,name)
+
+In the above, the C compiler generates the original routine with the name
+'name_' and a wrapper called 'NAME'. This assumes that the name of the routine,
+as seen by the C programmer, is not in upper case. The VAX VMS linker is not
+case sensitive, allowing cfortran.h to export the upper case name as the
+wrapper, which then doesn't conflict with the routine name in C. Since the IBM,
+HP and AbsoftUNIXFortran platforms have case sensitive linkers
+this technique is not available to them.
+
+The above technique is required even if the C name is in mixed case, see 
+Option a) for the other compilers, but is obviously not required when 
+Option b) is used.
+
+
+Option a) Mixed Case names for the C routines to be called by FORTRAN.
+
+If the original C routines have mixed case names, there are no name space
+conflicts.
+
+Nevertheless for VAX/VMS, the technique outlined above must also used.
+
+
+Option b) Modifying the names of C routines when used by FORTRAN:
+
+The more robust naming mechanism, which guarantees portability to all machines, 
+'renames' C routines when called by FORTRAN. Indeed, one must change the names
+on same_namespace compilers when FORTRAN calls C routines for which the source
+is unavailable. [Even when the source is available, renaming may be preferable
+to Option a) for large libraries of C routines.]
+
+Obviously, if done for a single type of machine, it must be done for all
+machines since the names of routines used in FORTRAN code cannot be easily
+redefined for different machines.
+
+The simplest way to achieve this end is to do explicitly give the modified
+FORTRAN name in the FCALLSCSUBn(...) and FCALLSCFUNn(...) declarations. e.g.
+
+FCALLSCSUB0(name,CFNAME,cfname)
+
+This allows FORTRAN to call the C routine 'name' as 'cfname'. Any name can of
+course be used for a given routine when it is called from FORTRAN, although
+this is discouraged due to the confusion it is sure to cause.  e.g. Bizarre,
+but valid and allowing C's 'call_back' routine to be called from FORTRAN as
+'abcd':
+
+FCALLSCSUB0(call_back,ABCD,abcd)
+
+
+cfortran.h also provides preprocessor directives for a systematic 'renaming' of
+the C routines when they are called from FORTRAN. This is done by redefining
+the fcallsc macro before the FCALLSCSUB/FUN/n declarations as follows:
+
+#undef  fcallsc
+#define fcallsc(UN,LN) preface_fcallsc(CF,cf,UN,LN)
+
+FCALLSCSUB0(hello,HELLO,hello)
+
+Will cause C's routine 'hello' to be known in FORTRAN as 'cfhello'. Similarly
+all subsequent FCALLSCSUB/FUN/n declarations will generate wrappers to allow
+FORTRAN to call C with the C routine's name prefaced by 'cf'. The following has
+the same effect, with subsequent FCALLSCSUB/FUN/n's appending the modifier to
+the original C routines name.
+
+#undef  fcallsc
+#define fcallsc(UN,LN) append_fcallsc(Y,y,UN,LN)
+
+FCALLSCSUB0(Xroutine,ROUTINE,routine)
+
+Hence, C's Xroutine is called from FORTRAN as:
+       CALL XROUTINEY()
+
+The original behavior of FCALLSCSUB/FUN/n, where FORTRAN routine names are left
+identical to those of C, is returned using:
+
+#undef  fcallsc
+#define fcallsc(UN,LN) orig_fcallsc(UN,LN)
+
+
+In C, when passing a C routine, i.e. its wrapper, as an argument to a FORTRAN
+routine, the FORTRAN name declared is used and the correct fcallsc must be in
+effect. E.g. Passing 'name' and 'routine' of the above examples to the FORTRAN
+routines, FT1 and FT2, respectively:
+
+/* This might not be needed if fcallsc is already orig_fcallsc. */
+#undef  fcallsc
+#define fcallsc(UN,LN) orig_fcallsc(UN,LN)
+FT1(C_FUNCTION(CFNAME,cfname));
+
+#undef  fcallsc
+#define fcallsc(UN,LN) append_fcallsc(Y,y,UN,LN)
+FT1(C_FUNCTION(XROUTINE,xroutine));
+
+If the names of C routines are modified when used by FORTRAN, fcallsc would
+usually be defined once in a header_file.h for the application. This definition
+would then be used and be valid for the entire application and fcallsc would at
+no point need to be redefined.
+
+
+ONCE AGAIN: THE DEFINITIONS, INSTRUCTIONS, DECLARATIONS AND DIFFICULTIES
+DESCRIBED HERE, NOTE 9. of II ii), 
+APPLY ONLY FOR VAX VMS,
+               IBM RS/6000 WITHOUT THE -qextname OPTION FOR xlf, OR
+               HP-UX       WITHOUT THE +ppu      OPTION FOR f77
+               AbsoftUNIXFortran
+AND APPLY ONLY WHEN CREATING WRAPPERS WHICH ENABLE FORTRAN TO CALL C ROUTINES.
+
+
+
+iii) Using C to manipulate FORTRAN COMMON BLOCKS:
+     -------------------------------------------------------
+
+FORTRAN common blocks are set up with the following three constructs:
+
+1.
+#define Common_block_name COMMON_BLOCK(COMMON_BLOCK_NAME,common_block_name)
+
+Common_block_name is in UPPER CASE. 
+COMMON_BLOCK_NAME is in UPPER CASE.
+common_block_name is in lower case. 
+[Common_block_name actually follows the same 'rules' as Routine_name in Note 2.
+ of II i).] This construct exists to ensure that C code accessing the common
+block is machine independent.
+
+2.
+COMMON_BLOCK_DEF(TYPEDEF_OF_STRUCT, Common_block_name);
+
+where 
+typedef { ... } TYPEDEF_OF_STRUCT;
+declares the structure which maps on to the common block. The #define of
+Common_block_name must come before the use of COMMON_BLOCK_DEF.
+
+3.
+In exactly one of the C source files, storage should be set aside for the
+common block with the definition: 
+
+TYPEDEF_OF_STRUCT  Common_block_name;
+
+The above definition may have to be omitted on some machines for a common block
+which is initialized by Fortran BLOCK DATA or is declared with a smaller size
+in the C routines than in the Fortran routines.
+
+The rules for common blocks are not well defined when linking/loading a mixture
+of C and Fortran, but the following information may help resolve problems.
+
+From the 2nd or ANSI ed. of K&R C, p.31, last paragraph:
+i)
+ An external variable must be defined, exactly once, outside of any function;
+ this sets aside storage for it.
+ii)
+ The variable must also be declared in each function that wants to access it;
+ ...
+ The declaration ... may be implicit from context.
+
+In Fortran, every routine says 'common /bar/ foo',
+i.e. part ii) of the above, but there's no part i) requirement.
+cc/ld on some machines don't require i) either.
+Therefore, when handling Fortran, and sometimes C,
+the loader/linker must automagically set aside storage for common blocks.
+
+Some loaders, including at least one for the CRAY, turn off the
+'automagically set aside storage' capability for Fortran common blocks,
+if any C object declares that common block.
+Therefore, C code should define, i.e. set aside storage,
+for the the common block as shown above.
+
+e.g.
+C Fortran
+      common /fcb/  v,w,x
+      character *(13) v, w(4), x(3,2)
+
+/* C */
+typedef struct { char v[13],w[4][13],x[2][3][13]; } FCB_DEF;
+#define Fcb COMMON_BLOCK(FCB,fcb)
+COMMON_BLOCK_DEF(FCB_DEF,Fcb);
+FCB_DEF Fcb;      /* Definition, which sets aside storage for Fcb, */
+                  /* may appear in at most one C source file.      */
+
+
+C programs can place a string (or a multidimensional array of strings) into a
+FORTRAN common block using the following call:
+
+C2FCBSTR( CSTR, FSTR,DIMENSIONS);
+
+where:
+
+CSTR is a pointer to the first element of C's copy of the string (array). 
+     The C code must use a duplicate of, not the original, common block string,
+     because the FORTRAN common block does not allocate space for C strings'
+     terminating '\0'.
+
+FSTR is a pointer to the first element of the string (array) in the common
+     block.
+
+DIMENSIONS is the number of dimensions of string array. 
+     e.g. char a[10]      has DIMENSIONS=0.
+          char aa[10][17] has DIMENSIONS=1.
+          etc...
+
+C2FCBSTR will copy the string (array) from CSTR to FSTR, padding with blanks, 
+' ', the trailing characters as required. C2FCBSTR uses DIMENSIONS and FSTR to
+determine the lengths of the individual string elements and the total number of
+elements in the string array.
+
+Note that:
+- the number of string elements in CSTR and FSTR are identical.
+- for arrays of strings, the useful lengths of strings in CSTR and FSTR must be
+  the same. i.e. CSTR elements each have 1 extra character to accommodate the
+  terminating '\0'.
+- On most non-ANSI compilers, the DIMENSION argument cannot be prepended by any
+  blanks.
+
+
+FCB2CSTR( FSTR, CSTR,DIMENSIONS)
+
+is the inverse of C2FCBSTR, and shares the same arguments and caveats.
+FCB2CSTR copies each string element of FSTR to CSTR, minus FORTRAN strings'
+trailing blanks.
+
+
+cfortran.h USERS ARE STRONGLY URGED TO EXAMINE THE COMMON BLOCK EXAMPLES IN
+cfortest.c AND cfortex.f. The use of strings in common blocks is
+demonstrated, along with a suggested way for C to imitate FORTRAN EQUIVALENCE'd
+variables.
+
+
+              ===> USERS OF CFORTRAN.H NEED READ NO FURTHER <===
+
+
+III Some Musings
+----------------
+
+cfortran.h is simple enough to be used by the most basic of applications, i.e.
+making a single C/FORTRAN routine available to the FORTRAN/C programmers. Yet
+cfortran.h is powerful enough to easily make entire C/FORTRAN libraries
+available to FORTRAN/C programmers. 
+
+
+cfortran.h is the ideal tool for FORTRAN libraries which are being (re)written
+in C, but are to (continue to) support FORTRAN users. It allows the routines to
+be written in 'natural C', without having to consider the FORTRAN argument
+passing mechanisms of any machine. It also allows C code accessing these
+rewritten routines, to use the C entry point. Without cfortran.h, one risks the
+perverse practice of C code calling a C function using FORTRAN argument passing
+mechanisms!
+
+
+Perhaps the philosophy and mechanisms of cfortran.h could be used and extended
+to create other language bridges such as ADAFORTRAN, CPASCAL, COCCAM, etc.
+
+
+The code generation machinery inside cfortran.h, i.e. the global structure is
+quite good, being clean and workable as seen by its ability to meet the needs
+and constraints of many different compilers. Though the individual instructions
+of the A..., C..., T..., R... and K... tables deserve to be cleaned up.
+
+
+
+IV  Getting Serious with cfortran.h
+-----------------------------------
+
+cfortran.h is set up to be as simple as possible for the casual user. While
+this ease of use will always be present, 'hooks', i.e. preprocessor directives,
+are required in cfortran.h so that some of the following 'inefficiencies' can
+be eliminated if they cause difficulties:
+
+o cfortran.h contains a few small routines for string manipulation. These
+routines are declared static and are included and compiled in all source code
+which uses cfortran.h. Hooks should be provided in cfortran.h to create an
+object file of these routines, allowing cfortran.h to merely prototypes
+these routines in the application source code. This is the only 'problem' which
+afflicts both halves of cfortran.h. The remaining discussion refers to the C
+calls FORTRAN half only.
+
+o Similar to the above routines, cfortran.h generates code for a 'wrapper'
+routine for each FUNCTION exported from FORTRAN. Again cfortran.h needs
+preprocessor directives to create a single object file of these routines,
+and to merely prototype them in the applications.
+
+o Libraries often contain hundreds of routines. While the preprocessor makes
+quick work of generating the required interface code from cfortran.h and the
+application.h's, it may be convenient for very large stable libraries to have
+final_application.h's which already contain the interface code, i.e. these
+final_application.h's would not require cfortran.h. [The convenience can be
+imagined for the VAX VMS CC compiler which has a fixed amount of memory for
+preprocessor directives. Not requiring cfortran.h, with its hundreds of
+directives, could help prevent this compiler from choking on its internal
+limits quite so often.]
+
+With a similar goal in mind, cfortran.h defines 100's of preprocessor
+directives. There is always the potential that these will clash with other tags
+in the users code, so final_applications.h, which don't require cfortran.h,
+also provide the solution.
+
+In the same vein, routines with more than 14 arguments can not be interfaced by
+cfortran.h with compilers which limit C macros to 31 arguments. To resolve this
+difficulty, final_application.h's can be created on a compiler without this
+limitation.
+
+Therefore, new machinery is required to do:
+
+application.h + cfortran.h => final_application.h
+
+The following example may help clarify the means and ends:
+
+If the following definition of the HBOOK1 routine, the /*commented_out_part*/,
+is passed through the preprocessor [perhaps #undefing and #defining preprocessor
+constants if creating an application.h for compiler other than that of the
+preprocessor being used, e.g. cpp -Umips -DCRAY ... ] :
+
+#include "cfortran.h"
+PROTOCCALLSFSUB6(HBOOK1,hbook1,INT,STRING,INT,FLOAT,FLOAT,FLOAT)
+/*#define HBOOK1(ID,CHTITLE,NX,XMI,XMA,VMX)                 \*/
+     CCALLSFSUB6(HBOOK1,hbook1,INT,STRING,INT,FLOAT,FLOAT,FLOAT, \
+                 ID,CHTITLE,NX,XMI,XMA,VMX) 
+
+A function prototype is produced by the PROTOCCALLSFSUB6(...).
+Interface code is produced, based on the 'variables', 
+ID,CHTITLE,NX,XMI,XMA,VMX, which will correctly massage a HBOOK1 call.
+Therefore, adding the #define line:
+
+'prototype code'
+#define HBOOK1(ID,CHTITLE,NX,XMI,XMA,VMX)                 \
+ 'interface code'(ID,CHTITLE,NX,XMI,XMA,VMX)
+
+which is placed into final_application.h.
+
+The only known limitation of the above method does not allow the 'variable'
+names to include B1,B2,...,B9,BA,BB,... 
+
+Obviously the machinery to automatically generate final_applications.h from
+cfortran.h and applications.h needs more than just some preprocessor
+directives, but a fairly simple unix shell script should be sufficient. Any
+takers?
+
+
+
+V Machine Dependencies of cfortran.h
+------------------------------------
+
+Porting cfortran.h applications, e.g. the hbook.h and cstring.c mentioned
+above, to other machines is trivial since they are machine independent. Porting
+cfortran.h requires a solid knowledge of the new machines C preprocessor, and
+its FORTRAN argument passing mechanisms. Logically cfortran.h exists as two
+halves, a "C CALLS FORTRAN" and a "FORTRAN CALLS C" utility. In some cases it
+may be perfectly reasonable to port only 'one half' of cfortran.h onto a new
+system.
+
+
+The lucky programmer porting cfortran.h to a new machine, must discover the
+FORTRAN argument passing mechanisms. A safe starting point is to assume that
+variables and arrays are simply passed by reference, but nothing is guaranteed.
+Strings, and n-dimensional arrays of strings are a different story. It is
+doubtful that any systems do it quite like VAX VMS does it, so that a UNIX or
+f2c versions may provide an easier starting point.
+
+
+cfortran.h uses and abuses the preprocessor's ## operator. Although the ##
+operator does not exist in many compilers, many kludges do. cfortran.h uses
+/**/ with no space allowed between the slashes, '/', and the macros or tags
+to be concatenated. e.g.
+#define concat(a,b) a/**/b   /* works*/
+main()
+{
+  concat(pri,ntf)("hello");           /* e.g. */
+}
+N.B. On some compilers without ##, /**/ may also not work. The author may be
+able to offer alternate kludges.
+
+
+
+VI Bugs in vendors C compilers and other curiosities
+----------------------------------------------------
+
+1. ULTRIX xxxxxx 4.3 1 RISC
+
+Condolences to long suffering ultrix users!
+DEC supplies a working C front end for alpha/OSF, but not for ultrix.
+
+From K&R ANSI C p. 231:
+   ultrix> cat cat.c
+   #define cat(x, y) x ## y
+   #define xcat(x,y) cat(x,y)
+   cat(cat(1,2),3)
+   xcat(xcat(1,2),3)
+   ultrix> cc -E cat.c
+   123                  <---- Should be: cat(1,2)3
+   123                  <---- Correct.
+   ultrix> 
+
+The problem for cfortran.h, preventing use of -std and -std1:
+   ultrix> cat c.c
+   #define cat(x, y) x ## y
+   #define xcat(x,y) cat(x,y)
+   #define AB(X) X+X
+   #define C(E,F,G)  cat(E,F)(G)
+   #define X(E,F,G) xcat(E,F)(G)
+   C(A,B,2)
+   X(A,B,2)
+   ultrix> cc -std1 -E c.c
+   2+2  
+   AB  (2)              <---- ?????????????
+   ultrix>
+   ultrix> cc -std0 -E c.c
+   2+2  
+   AB(2)                <---- ?????????????
+   ultrix>
+
+Due to further ultrix preprocessor problems,
+for all definitions of definitions with arguments,
+cfortran.h >= 3.0 includes the arguments and recommends the same,
+even though it is not required by ANSI C.
+e.g. Users are advised to do
+   #define fcallsc(UN,LN) orig_fcallsc(UN,LN)
+instead of
+   #define fcallsc        orig_fcallsc
+since ultrix fails to properly preprocess the latter example.
+CRAY used to (still does?) occasionally trip up on this problem.
+
+
+2. ConvexOS convex C210 11.0 convex
+
+In a program with a C main, output to LUN=6=* from Fortran goes into
+$pwd/fort.6 instead of stdout. Presumably, a magic incantation can be called
+from the C main in order to properly initialize the Fortran I/O.
+
+
+3. SunOS 5.3 Generic_101318-69 sun4m sparc
+
+The default data and code alignments produced by cc, gcc and f77 are compatible.
+If deviating from the defaults, consistent alignment options must be used
+across all objects compiled by cc and f77. [Does gcc provide such options?]
+
+
+4. SunOS 5.3 Generic_101318-69 sun4m sparc with cc: SC3.0.1 13 Jul 1994
+   or equivalently
+   ULTRIX 4.4 0 RISC using cc -oldc
+   are K&R C preprocessors that suffer from infinite loop macros, e.g.
+
+  zedy03> cat src.c
+  #include "cfortran.h"
+                            PROTOCCALLSFFUN1(INT,FREV,frev, INTV)
+  #define FREV(A1)               CCALLSFFUN1(    FREV,frev, INTV, A1)
+  /* To avoid the problem, deletete these ---^^^^--- spaces.    */
+  main() { static int a[] = {1,2}; FREV(a); return EXIT_SUCCESS; }
+
+  zedy03> cc -c -Xs -v -DMAX_PREPRO_ARGS=31 -D__CF__KnR src.c
+  "src.c", line 4: FREV: actuals too long
+  "src.c", line 4: FREV: actuals too long
+  .... 3427 more lines of the same message
+  "src.c", line 4: FREV: actuals too long
+  cc : Fatal error in /usr/ccs/lib/cpp
+  Segmentation fault (core dumped) 
+
+
+5. Older sun C compilers
+
+To link to f77 objects, older sun C compilers require the math.h macros:
+
+#define RETURNFLOAT(x)   { union {double _d; float _f; } _kluge; \
+                           _kluge._f = (x); return _kluge._d;   }
+#define ASSIGNFLOAT(x,y) { union {double _d; float _f; } _kluge; \
+                           _kluge._d = (y); x = _kluge._f;      }
+
+Unfortunately, in at least some copies of the sun math.h, the semi-colon
+for 'float _f;' is left out, leading to compiler warnings.
+
+The solution is to correct math.h, or to change cfortran.h to #define 
+RETURNFLOAT(x) and ASSIGNFLOAT(x,y) instead of including math.h.
+
+
+6. gcc version 2.6.3 and probably all other versions as well
+
+Unlike all other C compilers supported by cfortran.h,
+'gcc -traditional' promotes to double all functions returning float
+as demonstrated bu the following example.
+
+/* m.c */
+#include <stdio.h>
+int main() { FLOAT_FUNCTION d(); float f; f = d(); printf("%f\n",f); return 0; }
+
+/* d.c */
+float d() { return -123.124; }
+
+burow[29] gcc -c -traditional d.c
+burow[30] gcc -DFLOAT_FUNCTION=float m.c d.o && a.out
+0.000000
+burow[31] gcc -DFLOAT_FUNCTION=double m.c d.o && a.out
+-123.124001
+burow[32]
+
+Thus, 'gcc -traditional' is not supported by cfortran.h.
+Support would require the same RETURNFLOAT, etc. macro machinery
+present in old sun math.h, before sun gave up the same promotion.
+
+
+7. CRAY
+
+At least some versions of the t3e and t3d C preprocessor are broken
+in the fashion described below.
+At least some versions of the t90 C preprocessor do not have this problem.
+
+On the CRAY, all Fortran names are converted to uppercase.
+Generally the uppercase name is also used for the macro interface
+created by cfortran.h.
+
+For example, in the following interface,
+EASY is both the name of the macro in the original C code
+and EASY is the name of the resulting function to be called.
+
+#define EASY(A,B)      CCALLSFSUB2(EASY,easy, PINT, INTV, A, B)
+
+The fact that a macro called EASY() expands to a function called EASY()
+is not a problem for a working C preprocessor.
+From Kernighan and Ritchie, 2nd edition, p.230:
+
+    In both kinds of macro, the replacement token sequence is repeatedly
+  rescanned for more identifiers. However, once a given identifier has been
+  replaced in a given expansion, it is not replaced if it turns up again during
+  rescanning; instead it is left unchanged.
+
+Unfortunately, some CRAY preprocessors are broken and don't obey the above rule.
+A work-around is for the user to NOT use the uppercase name
+of the name of the macro interface provided by cfortran.h. For example:
+
+#define Easy(A,B)      CCALLSFSUB2(EASY,easy, PINT, INTV, A, B)
+
+Luckily, the above work-around is not required since the following
+work-around within cfortran.h also circumvents the bug:
+
+   /* (UN), not UN, is required in order to get around  CRAY preprocessor bug.*/
+   #define CFC_(UN,LN)            (UN)      /* Uppercase FORTRAN symbols.     */
+
+Aside: The Visual C++ compiler is happy with UN, but barfs on (UN),
+       so either (UN) causes nonstandard C/C++ or Visual C++ is broken.
+
+
+VII History and Acknowledgements
+--------------------------------
+
+1.0 - Supports VAX VMS using C 3.1 and FORTRAN 5.4.                    Oct. '90.
+1.0 - Supports Silicon Graphics w. Mips Computer 2.0 f77 and cc.       Feb. '91.
+          [Port of C calls FORTRAN half only.]
+1.1 - Supports Mips Computer System 2.0 f77 and cc.                    Mar. '91.
+          [Runs on at least: Silicon Graphics IRIX 3.3.1
+                             DECstations with Ultrix V4.1]
+1.2 - Internals made simpler, smaller, faster, stronger.               May  '91.
+    - Mips version works on IBM RS/6000, this is now called the unix version.
+1.3 - UNIX and VAX VMS versions are merged into a single cfortran.h.   July '91.
+    - C can help manipulate (arrays of) strings in FORTRAN common blocks.
+    - Dimensions of string arrays arguments can be explicit.
+    - Supports Apollo DomainOS 10.2 (sys5.3) with f77 10.7 and cc 6.7.
+
+2.0 - Improved code generation machinery creates K&R or ANSI C.        Aug. '91.
+    - Supports Sun, CRAY. f2c with vcc on VAX Ultrix.
+    - cfortran.h macros now require routine and COMMON block names in both 
+      upper and lower case. No changes required to applications though.
+    - PROTOCCALLSFSUBn is eliminated, with no loss to cfortran.h performance.
+    - Improved tools and guidelines for naming C routines called by FORTRAN.
+2.1 - LOGICAL correctly supported across all machines.                 Oct. '91.
+    - Improved support for DOUBLE PRECISION on the CRAY.
+    - HP9000 fully supported.
+    - VAX Ultrix cc or gcc with f77 now supported.
+2.2 - SHORT, i.e. INTEGER*2, and BYTE now supported.                   Dec. '91.
+    - LOGICAL_STRICT introduced. More compact and robust internal tables.
+    - typeV and typeVV for type = BYTE, DOUBLE, FLOAT, INT, LOGICAL, LONG,SHORT.
+    - FORTRAN passing strings and NULL pointer to C routines improved. 
+2.3 - Extraneous arguments removed from many internal tables.          May  '92.
+    - Introduce pseudo argument type SIMPLE for user defined types.
+    - LynxOS using f2c supported. (Tested with LynxOS 2.0 386/AT.)
+2.4 - Separation of internal C and Fortran compilation directives.     Oct. '92.
+    - f2c and NAG f90 supported on all machines.
+2.5 - Minor mod.s to source and/or doc for HP9000, f2c, and NAG f90.   Nov. '92.
+2.6 - Support external procedures as arguments with type ROUTINE.      Dec. '92.
+2.7 - Support Alpha VMS. Support HP9000 f77 +ppu                       Jan. '93.
+    - Support arrays with up to 7 dimensions.
+    - Minor mod. of Fortran NULL to C via (P)STRING.
+    - Specify the type of ROUTINE passed from Fortran to C [ANSI C requirement.]
+    - Macros never receive a null parameter [RS/6000 requirement.]
+2.8 - PSTRING for Fortran calls C no longer provides escape to pass    April'93.
+      NULL pointer nor to pass address of original string.
+      PNSTRING introduced with old PSTRING's behavior.
+      PPSTRING introduced to always pass original address of string.
+    - Support Alpha/OSF.
+    - Document that common blocks used in C should be declared AND defined.
+
+3.0 - Automagic handling of ANSI ## versus K&R /**/ preprocessor op.   March'95.
+    - Less chance of name space collisions between cfortran.h and other codes.
+    - SIMPLE macros, supporting user defined types, have changed names.
+3.1 - Internal macro name _INT not used. Conflicted with IRIX 5.3.     May  '95.
+    - SunOS, all versions, should work out of the box.
+    - ZTRINGV_ARGS|F(k) may no longer point to a PDOUBLE or PFLOAT argument.
+    - ConvexOS 11.0 supported.
+3.2 - __hpux no longer needs to be restricted to MAX_PREPRO_ARGS=31.   Oct. '95.
+    - PSTRING bug fixed.
+    - ZTRINGV_ARGS|F(k) may not point to a PBYTE,PINT,PLONG or PSHORT argument.
+    - (P)ZTRINGV machinery improved. Should lead to fewer compiler warnings.
+      (P)ZTRINGV no longer limits recursion or the nesting of routines.
+    - SIMPLE macros, supporting user defined types, have changed slightly.
+3.3 - Supports PowerStation Fortran with Visual C++.                   Nov. '95.
+    - g77 should work using f2cFortran, though no changes made for it.
+    - (PROTO)CCALLSFFUN10 extended to (PROTO)CCALLSFFUN14.
+    - FCALLSCFUN10 and SUB10 extended to FCALLSCFUN14 and SUB14.
+3.4 - C++ supported,                                                   Dec. '95.
+      but it required the reintroduction of PROTOCCALLSFSUBn for users.
+    - HP-UX f77 +800 supported.
+3.5 - Absoft UNIX Fortran supported.                                   Sept.'96.
+3.6 - Minor corrections to cfortran.doc.                               Oct. '96.
+    - Fixed bug for 15th argument. [Thanks to Tom Epperly at Aspen Tech.]
+    - For AbsoftUNIXFortran, obey default of prepending _C to COMMON BLOCK name.
+    - Fortran calling C with ROUTINE argument fixed and cleaned up.
+3.7 - Circumvent IBM and HP "null argument" preprocessor warning.      Oct. '96
+3.8 - (P)STRINGV and (P)ZTRINGV can pass a 1- or 2-dim. char array.    Feb. '97
+      (P)ZTRINGV thus effectively also provides (P)ZTRING.
+    - (P)ZTRINGV accepts a (char *) pointer.
+3.9 - Bug fixed for *VVVVV.                                            May  '97
+    - f2c: Work-around for strange underscore-dependent naming feature.
+    - NEC SX-4 supported.
+    - CRAY: LOGICAL conversion uses _btol and _ltob from CRAY's fortran.h.
+    - CRAY: Avoid bug of some versions of the C preprocessor.
+    - CRAY T3E: FORTRAN_REAL introduced.
+
+4.0 - new/delete now used for C++. malloc/free still used for C.       Jan. '98
+    - FALSE no longer is defined by cfortran.h .
+    - Absoft Pro Fortran for MacOS supported.
+4.1 - COMMA and COLON no longer are defined by cfortran.h .            April'98
+    - Bug fixed when 10th arg. or beyond is a string.
+      [Rob Lucchesi of NASA-Goddard pointed out this bug.]
+    - CCALLSFSUB/FUN extended from 14 to 27 arguments.
+    - Workaround SunOS CC 4.2 cast bug. [Thanks to Savrak SAR of CERN.]
+4.2 - Portland Group needs -DpgiFortran . [Thank George Lai of NASA.]  June '98
+4.3 - (PROTO)CCALLSFSUB extended from 20 to 27 arguments.              July '98
+
+
+['Support' implies these and more recent releases of the respective
+ OS/compilers/linkers can be used with cfortran.h. 
+ Earlier releases may also work.]
+
+
+Acknowledgements:
+- CERN very generously sponsored a week in 1994 for me to work on cfortran.h.
+- M.L.Luvisetto (Istituto Nazionale Fisica Nucleare - Centro Nazionale
+  Analisi Fotogrammi, Bologna, Italy) provided all the support for the port to
+  the CRAY. Marisa's encouragement and enthusiasm was also much appreciated.
+- J.Bunn (CERN) supported the port to PowerStation Fortran with Visual C++.
+- Paul Schenk (UC Riverside, CERN PPE/OPAL) in June 1993 extended cfortran.h 2.7
+  to have C++ call Fortran. This was the starting point for full C++ in 3.4.
+- Glenn P.Davis of University Corp. for Atmospheric Research (UCAR) / Unidata
+  supported the NEC SX-4 port and helped understand the CRAY.
+- Tony Goelz of Absoft Corporation ported cfortran.h to Absoft.
+- Though cfortran.h has been created in my 'copious' free time, I thank 
+  NSERC for their generous support of my grad. student and postdoc years.
+- Univ.Toronto, DESY, CERN and others have provided time on their computers.
+
+
+THIS PACKAGE, I.E. CFORTRAN.H, THIS DOCUMENT, AND THE CFORTRAN.H EXAMPLE
+PROGRAMS ARE PROPERTY OF THE AUTHOR WHO RESERVES ALL RIGHTS. THIS PACKAGE AND
+THE CODE IT PRODUCES MAY BE FREELY DISTRIBUTED WITHOUT FEES, SUBJECT TO THE
+FOLLOWING RESTRICTIONS:
+- YOU MUST ACCOMPANY ANY COPIES OR DISTRIBUTION WITH THIS (UNALTERED) NOTICE.
+- YOU MAY NOT RECEIVE MONEY FOR THE DISTRIBUTION OR FOR ITS MEDIA 
+  (E.G. TAPE, DISK, COMPUTER, PAPER.)
+- YOU MAY NOT PREVENT OTHERS FROM COPYING IT FREELY.
+- YOU MAY NOT DISTRIBUTE MODIFIED VERSIONS WITHOUT CLEARLY DOCUMENTING YOUR
+  CHANGES AND NOTIFYING THE AUTHOR.
+- YOU MAY NOT MISREPRESENTED THE ORIGIN OF THIS SOFTWARE, EITHER BY EXPLICIT
+  CLAIM OR BY OMISSION.
+
+THE INTENT OF THE ABOVE TERMS IS TO ENSURE THAT THE CFORTRAN.H PACKAGE NOT BE
+USED FOR PROFIT MAKING ACTIVITIES UNLESS SOME ROYALTY ARRANGEMENT IS ENTERED
+INTO WITH ITS AUTHOR.
+              
+THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
+EXPRESSED OR IMPLIED. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+SOFTWARE IS WITH YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST
+OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. THE AUTHOR IS NOT RESPONSIBLE
+FOR ANY SUPPORT OR SERVICE OF THE CFORTRAN.H PACKAGE.
+
+                                              Burkhard Burow 
+                                              burow at desy.de
+
+P.S. Your comments and questions are welcomed and usually promptly answered.
+
+VAX VMS and Ultrix, Alpha, OSF, Silicon Graphics (SGI), DECstation, Mips RISC,
+Sun, CRAY, Convex, IBM RS/6000, Apollo DomainOS, HP, LynxOS, f2c, NAG, Absoft,
+NEC SX-4, PowerStation and Visual C++ are registered trademarks of their
+respective owners.
+        
+/* end: cfortran.doc */
diff --git a/libsrc/makevms.com b/libsrc/makevms.com
new file mode 100644
index 0000000..6c59a54
--- /dev/null
+++ b/libsrc/makevms.com
@@ -0,0 +1,20 @@
+$! --------------------------------------------------------------------------
+$! For making FTEST.EXE on VMS
+$! --------------------------------------------------------------------------
+$!
+$! $Id: makevms.com,v 1.3 1996/02/27 22:56:05 steve Exp $
+$
+$ ccc := cc /opt/nodebug/nolist/include=([-.src])
+$
+$ ccc JACKETS.C
+$ fort FTEST.FOR
+$
+$ link/nodebug/notraceback/exec=FTEST.exe -
+    ftest.obj, -
+    jackets.obj, -
+    [---.lib]netcdf.olb/lib, -
+    sys$input/opt
+	sys$library:vaxcrtl.exe/share
+$
+$ run ftest
+$
diff --git a/libsrc/netcdf_f77.3 b/libsrc/netcdf_f77.3
deleted file mode 100644
index 24571cd..0000000
--- a/libsrc/netcdf_f77.3
+++ /dev/null
@@ -1,1370 +0,0 @@
-.nr yr \n(yr+1900
-.af mo 01
-.af dy 01
-.TH NETCDF 3 "1997-04-18" "Printed: \n(yr-\n(mo-\n(dy" "UNIDATA LIBRARY FUNCTIONS"
-.SH NAME
-netcdf \- Unidata's Network Common Data Form (netCDF) library interface
-.SH SYNOPSIS
-.ft B
-.na
-.nh
-include netcdf.inc
-.sp
-.SS Most Systems:
-f77 ...  -lnetcdf -lhdf5_hl -lhdf5 -lz -lm
-.sp
-.SS CRAY PVP Systems:
-f90 -dp -i64 ... -lnetcdf
-
-.ad
-.hy
-Complete documentation for the netCDF libraries can be found at the netCDF website: http://www.unidata.ucar.edu/software/netcdf/.
-.sp
-.SH "LIBRARY VERSION"
-.LP
-This document describes versions 3 and 4
-of Unidata netCDF data-access interface
-for the FORTRAN programming language.
-.HP
-\fBcharacter*80 nf_inq_libvers(void)\fR
-.sp
-Returns a string identifying the version of the netCDF library, and
-when it was built, like: "3.1a of Aug 22 1996 12:57:47 $".
-.LP
-The RCS \fBident(1)\fP command will find a string like
-"$\|Id: @\|(#) netcdf library version 3.1a of Sep  6 1996 15:56:26 $"
-in the library. The SCCS \fBwhat(1)\fP command will find a string like
-"netcdf library version 3.1a of Aug 23 1996 16:07:40 $".
-.SH "RETURN VALUES"
-.LP
-All netCDF functions (except
-\fBnf_inq_libvers(\|)\fR and \fBnf_strerror(\|)\fR) return an integer status.
-
-If this returned status value is not equal to
-\fBNF_NOERR\fR (zero), it
-indicates that an error occurred. The possible status values are defined in 
-netcdf.inc.
-.HP
-\fBcharacter*80 nf_strerror(integer \fIstatus\fP)\fR
-.sp
-Returns a string textual translation of the \fIstatus\fP
-value, like "Attribute or variable name contains illegal characters"
-or "No such file or directory".
-.sp
-.SH "FILE OPERATIONS"
-.LP
-.HP
-\fBinteger function nf_create(character*(*) \fIpath\fP, integer \fIcmode\fP, integer \fIncid\fP)\fR
-.sp
-Creates a new netCDF dataset at \fIpath\fP,
-returning a netCDF ID in \fIncid\fP.
-The argument \fIcmode\fP may include the bitwise-or
-of the following flags:
-\fBNF_NOCLOBBER\fR
-to protect existing datasets (default
-silently blows them away),
-\fBNF_SHARE\fR
-for synchronous dataset updates for classic format files
-(default is to buffer accesses),
-.sp
-When a netCDF dataset is created, is is opened
-\fBNF_WRITE\fR.
-The new netCDF dataset is in define mode.
-\fBNF_64BIT_OFFSET\fR.
-to create a file in the 64-bit offset format 
-(as opposed to classic format, the default). 
-\fBNF_TRUE\fR to create a netCDF-4/HDF5 file, 
-and \fBNF_CLASSIC_MODEL\fR to guarantee that netCDF-4/HDF5 files maintain compatibility 
-with the netCDF classic data model.
-.HP
-\fBinteger function nf__create(character*(*) \fIpath\fP, integer \fIcmode\fP, integer \fIinitialsize\fP, integer \fIchunksize\fP, integer \fIncid\fP)\fR
-.sp
-Like \fBnf_create(\|)\fR but has additional performance tuning parameters.
-.sp
-The argument \fIinitialsize\fP sets the initial size of the file at
-creation time.
-.sp
-See \fBnf__open(\|)\fR below for an explanation of the \fIchunksize\fP
-parameter.
-.HP
-\fBinteger function nf_open(character*(*) \fIpath\fP, integer \fImode\fP, integer \fIncid\fP)\fR
-.sp
-(Corresponds to \fBncopn(\|)\fR in version 2)
-.sp
-Opens a existing netCDF dataset at \fIpath\fP
-returning a netCDF ID
-in \fIncid\fP.
-The type of access is described by the \fImode\fP parameter,
-which may include the bitwise-or
-of the following flags:
-\fBNF_WRITE\fR
-for read-write access (default
-read-only),
-\fBNF_SHARE\fR
-for synchronous dataset updates (default is
-to buffer accesses), and
-\fBNF_LOCK\fR
-(not yet implemented).
-.sp
-As of NetCDF version 4.1, and if TRUE support was enabled
-when the NetCDF library was built, the path parameter
-may specify a TRUE URL. In this case, the access mode is
-forced to be read-only.
-.HP
-\fBinteger function nf__open(character*(*) \fIpath\fP, integer \fImode\fP, integer \fIchunksize\fP, integer \fIncid\fP)\fR
-.sp
-Like \fBnf_open(\|)\fR but has an additional performance tuning parameter.
-.sp
-The argument referenced by \fIchunksize\fP controls a space versus time
-tradeoff, memory allocated in the netcdf library versus number of system
-calls.
-Because of internal requirements, the value may not be set to exactly
-the value requested.
-The actual value chosen is returned by reference.
-Using the value \fBNF_SIZEHINT_DEFAULT\fR causes the library to choose a
-default.
-How the system choses the default depends on the system.
-On many systems, the "preferred I/O block size" is available from the 
-\fBstat()\fR system call, \fBstruct stat\fR member \fBst_blksize\fR.
-If this is available it is used. Lacking that, twice the system pagesize
-is used.
-Lacking a call to discover the system pagesize, we just set default
-chunksize to 8192.
-.sp
-The chunksize is a property of a given open netcdf descriptor
-\fIncid\fP, it is not a persistent property of the netcdf dataset.
-.sp
-As with \fBnf__open(\|)\fR, the path parameter
-may specify a TRUE URL, but the tuning parameters are ignored.
-.HP
-\fBinteger function nf_redef(integer \fIncid\fP)\fR
-.sp
-(Corresponds to \fBncredf(\|)\fR in version 2)
-.sp
-Puts an open netCDF dataset into define mode, 
-so dimensions, variables, and attributes can be added or renamed and 
-attributes can be deleted.
-.HP
-\fBinteger function nf_enddef(integer \fIncid\fP)\fR
-.sp
-(Corresponds to \fBncendf(\|)\fR in version 2)
-.sp
-Takes an open netCDF dataset out of define mode.
-The changes made to the netCDF dataset
-while it was in define mode are checked and committed to disk if no
-problems occurred.  Some data values may be written as well,
-see "VARIABLE PREFILLING" below.
-After a successful call, variable data can be read or written to the dataset.
-.HP
-\fBinteger function nf__enddef(integer \fIncid\fP, integer \fIh_minfree\fP, integer \fIv_align\fP, integer \fIv_minfree\fP, integer \fIr_align\fP)\fR
-.sp
-Like \fBnf_enddef(\|)\fR but has additional performance tuning parameters.
-.sp
-Caution: this function exposes internals of the netcdf version 1 file
-format.
-It may not be available on future netcdf implementations.
-.sp
-The current netcdf file format has three sections,
-the "header" section, the data section for fixed size variables, and
-the data section for variables which have an unlimited dimension (record
-variables).
-The header begins at the beginning of the file. The index
-(offset) of the beginning of the other two sections is contained in the
-header. Typically, there is no space between the sections. This causes
-copying overhead to accrue if one wishes to change the size of the
-sections,
-as may happen when changing names of things, text attribute values,
-adding
-attributes or adding variables. Also, for buffered i/o, there may be
-advantages
-to aligning sections in certain ways.
-.sp
-The minfree parameters allow one to control costs of future calls
-to \fBnf_redef(\|)\fR, \fBnf_enddef(\|)\fR by requesting that \fIminfree\fP bytes be
-available at the end of the section.
-The \fIh_minfree\fP parameter sets the pad
-at the end of the "header" section. The \fIv_minfree\fP parameter sets
-the pad at the end of the data section for fixed size variables.
-.sp
-The align parameters allow one to set the alignment of the beginning of
-the corresponding sections. The beginning of the section is rounded up
-to an index which is a multiple of the align parameter. The flag value
-\fBNF_ALIGN_CHUNK\fR tells the library to use the chunksize (see above)
-as the align parameter.
-The \fIv_align\fP parameter controls the alignment of the beginning of
-the data section for fixed size variables.
-The \fIr_align\fP parameter controls the alignment of the beginning of
-the data section for variables which have an unlimited dimension (record
-variables).
-.sp
-The file format requires mod 4 alignment, so the align parameters
-are silently rounded up to multiples of 4. The usual call,
-\fBnf_enddef(\fIncid\fP)\fR
-is equivalent to
-\fBnf__enddef(\fIncid\fP, 0, 4, 0, 4)\fR.
-.sp
-The file format does not contain a "record size" value, this is
-calculated from the sizes of the record variables. This unfortunate fact
-prevents us from providing minfree and alignment control of the
-"records"
-in a netcdf file. If you add a variable which has an unlimited
-dimension,
-the third section will always be copied with the new variable added.
-.HP
-\fBinteger function nf_sync(integer \fIncid\fP)\fR
-.sp
-(Corresponds to \fBncsnc(\|)\fR in version 2)
-.sp
-Unless the
-\fBNF_SHARE\fR
-bit is set in
-\fBnf_open(\|)\fR or \fBnf_create(\|)\fR,
-accesses to the underlying netCDF dataset are
-buffered by the library. This function synchronizes the state of
-the underlying dataset and the library.
-This is done automatically by
-\fBnf_close(\|)\fR and \fBnf_enddef(\|)\fR.
-.HP
-\fBinteger function nf_abort(integer \fIncid\fP)\fR
-.sp
-(Corresponds to \fBncabor(\|)\fR in version 2)
-.sp
-You don't need to call this function.
-This function is called automatically by
-\fBnf_close(\|)\fR
-if the netCDF was in define mode and something goes wrong with the commit.
-If the netCDF dataset isn't in define mode, then this function is equivalent to
-\fBnf_close(\|)\fR.
-If it is called after
-\fBnf_redef(\|)\fR,
-but before
-\fBnf_enddef(\|)\fR,
-the new definitions are not committed and the dataset is closed.
-If it is called after
-\fBnf_create(\|)\fR
-but before
-\fBnf_enddef(\|)\fR,
-the dataset disappears.
-.HP
-\fBinteger function nf_close(integer \fIncid\fP)\fR
-.sp
-(Corresponds to
-\fBncclos(\|)\fR in version 2)
-.sp
-Closes an open netCDF dataset.
-If the dataset is in define mode,
-\fBnf_enddef(\|)\fR
-will be called before closing.
-After a dataset is closed, its ID may be reassigned to another dataset.
-.HP
-\fBinteger function nf_inq(integer \fIncid\fP, integer \fIndims\fP, integer \fInvars\fP,
-integer \fInatts\fP, integer \fIunlimdimid\fP)\fR
-.HP
-\fBinteger function nf_inq_ndims(integer \fIncid\fP, integer \fIndims\fP)\fR
-.HP
-\fBinteger function nf_inq_nvars(integer \fIncid\fP, integer \fInvars\fP)\fR
-.HP
-\fBinteger function nf_inq_natts(integer \fIncid\fP, integer \fInatts\fP)\fR
-.HP
-\fBinteger function nf_inq_unlimdim(integer \fIncid\fP, integer \fIunlimdimid\fP)\fR
-.HP
-\fBinteger function nf_inq_format(integer \fIncid\fP, integer \fIformatn\fP)\fR
-.sp
-Use these functions to find out what is in a netCDF dataset.
-Upon successful return,
-\fIndims\fP will contain  the
-number of dimensions defined for this netCDF dataset,
-\fInvars\fP will contain the number of variables,
-\fInatts\fP will contain the number of attributes, and
-\fIunlimdimid\fP will contain the
-dimension ID of the unlimited dimension if one exists, or
-0 otherwise.
-\fIformatn\fP will contain the version number of the dataset <format>, one of
-\fBNF_FORMAT_CLASSIC\fR, \fBNF_FORMAT_64BIT\fR, \fBNF_FORMAT_NETCDF4\fR, or
-\fBNF_FORMAT_NETCDF4_CLASSIC\fR.
-
-.HP
-\fBinteger function nf_def_dim(integer \fIncid\fP, character*(*) \fIname\fP, integer \fIlen\fP, integer \fIdimid\fP)\fR
-.sp
-(Corresponds to \fBncddef(\|)\fR in version 2)
-.sp
-Adds a new dimension to an open netCDF dataset, which must be 
-in define mode.
-\fIname\fP is the dimension name.
-\fIdimid\fP will contain the dimension ID of the newly created dimension.
-
-.SH "USER DEFINED TYPES"
-.LP
-Users many define types for a netCDF-4/HDF5 file (unless the
-\fBNF_CLASSIC_MODEL\fR was used when the file was creates). Users may
-define compound types, variable length arrays, enumeration types, and
-opaque types.
-.sp
-
-.HP
-\fBinteger function nf_def_compound(integer \fIncid\fP, integer \fIsize\fP, character*(*) \fIname\fP, integer \fItypeidp\fP)\fR
-.sp
-Define a compound type.
-.HP
-\fBinteger function nf_insert_compound(integer \fIncid\fP, integer \fI\fP, character*(*) \fIname\fP, integer \fIoffset\fP, integer \fIfield_typeid\fP)\fR
-.sp
-Insert an element into a compound type. May not be done after type has been used, or after the type has been written by an enddef.
-.HP
-\fBinteger function nf_insert_array_compound(integer \fIncid\fP, integer \fI\fP, character*(*) \fIname\fP, integer \fIoffset\fP, integer \fIfield_typeid\fP, integer \fIndims\fP, integer \fIdim_sizes\fP(1))\fR
-.sp 
-Insert an array into a compound type.
-.HP
-\fBinteger function nf_inq_type(integer \fIncid\fP, integer \fI\fP, character*(*) \fIname\fP, integer \fIsizep\fP)\fR
-.sp
-Learn about a type.
-.HP
-\fBinteger function nf_inq_compound(integer \fIncid\fP, integer \fI\fP, character*(*) \fIname\fP, integer \fIsizep\fP, integer \fInfieldsp\fP)\fR
-.HP
-\fBinteger function nf_inq_compound_name(integer \fIncid\fP, integer \fI\fP, character*(*) \fIname\fP)\fR
-.HP
-\fBinteger function nf_inq_compound_size(integer \fIncid\fP, integer \fI\fP, integer \fIsizep\fP)\fR
-.HP
-\fBinteger function nf_inq_compound_nfields(integer \fIncid\fP, integer \fI\fP, integer \fInfieldsp\fP)\fR
-.HP
-\fBinteger function nf_inq_compound_fieldname(integer \fIncid\fP, integer \fI\fP, integer \fIfieldid\fP, character*(*) \fIname\fP)\fR
-.HP
-\fBinteger function nf_inq_compound_fieldindex(integer \fIncid\fP, integer \fI\fP, character*(*) \fIname\fP, integer \fIfieldidp\fP)\fR
-.HP
-\fBinteger function nf_inq_compound_fieldoffset(integer \fIncid\fP, integer \fI\fP, integer \fIfieldid\fP, integer \fIoffsetp\fP)\fR
-.HP
-\fBinteger function nf_inq_compound_fieldtype(integer \fIncid\fP, integer \fI\fP, integer \fIfieldid\fP, integer \fIfield_typeid\fP)\fR
-.HP
-\fBinteger function nf_inq_compound_fieldndims(integer \fIncid\fP, integer \fI\fP, integer \fIfieldid\fP, integer \fIndims\fP)\fR
-.HP
-\fBinteger function nf_inq_compound_fielddim_sizes(integer \fIncid\fP, integer \fI\fP, integer \fIfieldid\fP, integer \fIdim_sizes\fP(1))\fR
-.sp
-Learn about a compound type.
-.HP
-\fBinteger function nf_def_vlen(integer \fIncid\fP, character*(*) \fIname\fP, integer \fIbase_typeid\fP, integer \fIxtypep\fP)\fR
-.sp
-Create a varaible length array type.
-.HP
-\fBinteger function nf_inq_vlen(integer \fIncid\fP, integer \fI\fP, character*(*) \fIname\fP, integer \fIdatum_sizep\fP, integer \fIbase_nc_typep\fP)\fR
-.sp
-Learn about a varaible length array type.
-.HP
-\fBinteger function nf_free_vlen(nc_vlen_t *vl)\fR
-.sp
-Free memory comsumed by reading data of a varaible length array type.
-.HP
-\fBinteger function nf_put_vlen_element(integer \fIncid\fP, integer \fI\fP, void * \fIvlen_element\fP, integer \fIlen\fP, void * \fIdata\fP)\fR
-.sp
-Write one VLEN.
-.HP
-\fBinteger function nf_get_vlen_element(integer \fIncid\fP, integer \fI\fP, void * \fIvlen_element\fP, integer \fIlen\fP, void * \fIdata\fP)\fR
-.sp
-Read one VLEN.
-.HP
-\fBinteger function nf_free_string(integer \fIlen\fP, char **data)\fR
-.sp
-Free memory comsumed by reading data of a string type.
-.HP
-\fBinteger function nf_inq_user_type(integer \fIncid\fP, integer \fI\fP, character*(*) \fIname\fP, integer \fI\fP, integer \fI\fP, integer \fI\fP, integer \fI\fP)\fR
-.sp
-Learn about a user define type.
-.HP
-\fBinteger function nf_def_enum(integer \fIncid\fP, integer \fIbase_typeid\fP, character*(*) \fIname\fP, integer \fItypeidp\fP)\fR
-.sp
-Define an enumeration type.
-.HP
-\fBinteger function nf_insert_enum(integer \fIncid\fP, integer \fIbase_typeid\fP, character*(*) \fIname\fP, const void *value)\fR
-.sp
-Insert a name-value pair into enumeration type.
-.HP
-\fBinteger function nf_inq_enum_member(integer \fIncid\fP, integer \fIxtype\fP, integer \fIidx\fP, character*(*) \fIname\fP, void *value)\fR
-.HP
-\fBinteger function nf_inq_enum_ident(integer \fIncid\fP, integer \fIxtype\fP, integer \fIidx\fP, integer*8 \fIvalue\fP, character*(*) \fIidentifier\fP)\fR
-.sp
-Learn about a name-value pair into enumeration type.
-.HP
-\fBinteger function nf_def_opaque(integer \fIncid\fP, integer \fIsize\fP, character*(*) \fIname\fP, integer \fIxtypep\fP)\fR
-.sp
-Create an opaque type.
-.HP
-\fBinteger function nf_inq_opaque(integer \fIncid\fP, integer \fIxtype\fP, character*(*) \fIname\fP, integer \fIsizep\fP)\fR
-.sp
-Learn about opaque type.
-.HP
-.SH "GROUPS"
-.sp
-Users may organize data into hierarchical groups in netCDF-4/HDF5 files (unless \fBNF_CLASSIC_MODEL\fR was used when creating the file).
-.HP
-\fBinteger function nf_inq_grps(integer \fIncid\fP, integer \fInumgrps\fP, integer \fIncids\fP(1))\fR
-.sp
-Learn how many groups (and their ncids) are available from the group represented by ncid.
-.HP
-\fBinteger function nf_inq_grpname(integer \fIncid\fP, character*(*) \fIname\fP)\fR
-.HP
-\fBinteger function nf_inq_grpname_full(integer \fIncid\fP, integer \fIlen\fP, character*(*) \fIname\fP)\fR
-.HP
-\fBinteger function nf_inq_grpname_len(integer \fIncid\fP, integer \fIlen\fP)\fR
-.HP
-\fBinteger function nf_inq_grp_parent(integer \fIncid\fP, integer \fIncid\fP)\fR
-.HP
-\fBinteger function nf_inq_grp_ncid(integer \fIncid\fP, character*(*) \fIname\fP, integer \fIncid\fP)\fR
-.HP
-\fBinteger function nf_inq_full_ncid(integer \fIncid\fP, character*(*) \fIname\fP, integer \fIncid\fP)\fR
-.sp
-Learn about a group.
-.HP
-\fBinteger function nf_inq_varids(integer \fIncid\fP, integer \fInvars\fP, integer \fI\fP)\fR
-.sp
-Get the varids in a group.
-.HP
-\fBinteger function nf_inq_dimids(integer \fIncid\fP, integer \fIndims\fP, integer \fIdimids\fP, integer \fIinclude_parents\fP)\fR
-.sp
-Get the dimids in a group and (potentially) its parents.
-.HP
-\fBinteger function nf_inq_typeids(integer \fIncid\fP, integer \fIntypes\fP, integer \fItypeids\fP(1))\fR
-.sp
-Get the typeids of user-defined types in a group.
-.HP
-\fBinteger function nf_def_grp(integer \fIncid\fP, character*(*) \fIname\fP, integer \fIncid\fP)\fR
-.sp
-Create a group.
-.LP
-
-.SH "DIMENSIONS"
-.LP
-.HP
-\fBinteger function nf_inq_dimid(integer \fIncid\fP, character*(*) \fIname\fP, integer \fIdimid\fP)\fR
-.sp
-(Corresponds to \fBncdid(\|)\fR in version 2)
-.sp
-Given a dimension name, returns the ID of a netCDF dimension in \fIdimid\fP.
-.HP
-\fBinteger function nf_inq_dim(integer \fIncid\fP, integer \fIdimid\fP, character*(*) \fIname\fP, integer \fIlen\fP)\fR
-.HP
-\fBinteger function nf_inq_dimname(integer \fIncid\fP, integer \fIdimid\fP, character*(*) \fIname\fP)\fR
-.HP
-\fBinteger function nf_inq_dimlen(integer \fIncid\fP, integer \fIdimid\fP, integer \fIlen\fP)\fR
-.sp
-Use these functions to find out about a dimension.
-
-\fIname\fP should be  big enough (\fBNF_MAX_NAME\fR)
-to hold the dimension name as the name will be copied into your storage.
-The length return parameter, \fIlen\fP
-will contain the size of the dimension.
-For the unlimited dimension, the returned length is the current
-maximum value used for writing into any of the variables which use
-the dimension.
-.HP
-\fBinteger function nf_rename_dim(integer \fIncid\fP, integer \fIdimid\fP, character*(*) \fIname\fP)\fR
-.sp
-(Corresponds to \fBncdren(\|)\fR in version 2)
-.sp
-Renames an existing dimension in an open netCDF dataset.
-If the new name is longer than the old name, the netCDF dataset must be in 
-define mode.
-You cannot rename a dimension to have the same name as another dimension.
-.SH "VARIABLES"
-.LP
-.HP
-\fBinteger function nf_def_var(integer \fIncid\fP, character*(*) \fIname\fP, integer \fIxtype\fP, integer \fIndims\fP, integer \fIdimids\fP(1), integer \fIvarid\fP)\fR
-.sp
-(Corresponds to \fBncvdef(\|)\fR in version 2)
-.sp
-Adds a new variable to a netCDF dataset. The netCDF must be in define mode.
-\fIvarid\fP will be set to the netCDF variable ID.
-.HP
-\fBinteger function nf_inq_varid(integer \fIncid\fP, character*(*) \fIname\fP, integer \fIvarid\fP)\fR
-.sp
-(Corresponds to \fBncvid(\|)\fR in version 2)
-.sp
-Returns the ID of a netCDF variable in \fIvarid\fP given its name.
-.HP
-\fBinteger function nf_inq_var(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer \fIxtype\fP, integer \fIndims\fP, integer \fIdimids\fP(1),
-integer \fInatts\fP)\fR
-.HP
-\fBinteger function nf_inq_varname(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP)\fR
-.HP
-\fBinteger function nf_inq_vartype(integer \fIncid\fP, integer \fIvarid\fP, integer \fIxtype\fP)\fR
-.HP
-\fBinteger function nf_inq_varndims(integer \fIncid\fP, integer \fIvarid\fP, integer \fIndims\fP)\fR
-.HP
-\fBinteger function nf_inq_vardimid(integer \fIncid\fP, integer \fIvarid\fP, integer \fIdimids\fP(1))\fR
-.HP
-\fBinteger function nf_inq_varnatts(integer \fIncid\fP, integer \fIvarid\fP, integer \fInatts\fP)\fR
-.sp
-Returns information about a netCDF variable, given its ID.
-
-.HP
-\fBinteger function nf_rename_var(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP)\fR
-.sp
-(Corresponds to \fBncvren(\|)\fR in version 2)
-.sp
-Changes the name of a netCDF variable.
-If the new name is longer than the old name, the netCDF must be in define mode.
-You cannot rename a variable to have the name of any existing variable.
-
-.SH "VARIABLES \fIin\fP NETCDF-4 FILES"
-.LP
-The following functions may only be used on variables in a
-netCDF-4/HDF5 data file. These functions must be called after the
-variable is defined, but before an enddef call.
-.sp
-\fBinteger function nf_def_var_deflate(integer \fIncid\fP, integer \fIvarid\fP, integer \fIshuffle\fP, integer \fIdeflate\fP, integer \fIdeflate_level\fP)\fR
-.sp
-Turn on compression and/or shuffle filter. (Shuffle filter is only useful for integer data.)
-.HP
-\fBinteger function nf_inq_var_deflate(integer \fIncid\fP, integer \fIvarid\fP, integer \fIshufflep\fP, integer \fIdeflatep\fP, integer \fIdeflate_levelp\fP)\fR
-.sp
-Learn about a variable's deflate settings.
-.HP
-\fBinteger function nf_def_var_fletcher32(integer \fIncid\fP, integer \fIvarid\fP, integer \fIfletcher32\fP)\fR
-.sp
-Turn on checksumming for a variable.
-.HP
-\fBinteger function nf_inq_var_fletcher32(integer \fIncid\fP, integer \fIvarid\fP, integer \fIfletcher32\fP)\fR
-.sp
-Learn about checksumming for a variable.
-.HP
-\fBinteger function nf_def_var_chunking(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstorage\fP, integer \fIchunksizesp\fP(1))\fR
-.sp
-Set chunksizes for a variable.
-.HP
-\fBinteger function nf_inq_var_chunking(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstoragep\fP, integer \fIchunksizesp\fP(1))\fR
-.sp
-Learn about chunksizes for a variable.
-.HP
-\fBinteger function nf_def_var_fill(integer \fIncid\fP, integer \fIvarid\fP, integer \fIno_fill\fP, integer \fIchunksizesp\fP(1))\fR
-.sp
-Set a fill value for a variable.
-.HP
-\fBinteger function nf_inq_var_fill(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstoragep\fP, integer \fIchunksizesp\fP(1))\fR
-.sp
-Learn the fill value for a variable.
-.HP
-\fBinteger function nf_def_var_endian(integer \fIncid\fP, integer \fIvarid\fP, integer \fIendian\fP)\fR
-.sp
-Set endianness of variable.
-.HP
-\fBinteger function nf_inq_var_endian(integer \fIncid\fP, integer \fIvarid\fP, integer \fIendianp\fP)\fR
-.sp
-Learn the endianness of a variable.
-.HP
-
-.SH "WRITING AND READING WHOLE VARIABLES"
-.LP
-.HP
-\fBinteger function nf_put_var_text(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIout\fP)\fR
-
-.HP
-\fBinteger function nf_put_var_int1(integer \fIncid\fP, integer \fIvarid\fP, integer*1 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_var_int2(integer \fIncid\fP, integer \fIvarid\fP, integer*2 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_var_int(integer \fIncid\fP, integer \fIvarid\fP, integer \fIout\fP(1))\fR
-
-.HP
-\fBinteger function nf_put_var_real(integer \fIncid\fP, integer \fIvarid\fP, real \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_var_double(integer \fIncid\fP, integer \fIvarid\fP, doubleprecision \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_var_ubyte(integer \fIncid\fP, integer \fIvarid\fP, integer*1 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_var_ushort(integer \fIncid\fP, integer \fIvarid\fP, integer*2 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_var_uint(integer \fIncid\fP, integer \fIvarid\fP, integer*4 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_var_(integer \fIncid\fP, integer \fIvarid\fP, integer*8 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_var_uint64(integer \fIncid\fP, integer \fIvarid\fP, integer*8 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_var_string(integer \fIncid\fP, integer \fIvarid\fP, character* \fIout\fP(1))\fR
-
-
-.sp
-Writes an entire netCDF variable (i.e. all the values).  The netCDF
-dataset must be open and in data mode.  The type of the data is
-specified in the function name, and it is converted to the external
-type of the specified variable, if possible, otherwise an
-\fBNF_ERANGE\fR error is returned. Note that rounding is not performed
-during the conversion. Floating point numbers are truncated when
-converted to integers.
-.HP
-\fBinteger function nf_get_var_text(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIin\fP)\fR
-
-.HP
-\fBinteger function nf_get_var_int1(integer \fIncid\fP, integer \fIvarid\fP, integer*1 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_var_int2(integer \fIncid\fP, integer \fIvarid\fP, integer*2 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_var_int(integer \fIncid\fP, integer \fIvarid\fP, integer \fIin\fP(1))\fR
-
-.HP
-\fBinteger function nf_get_var_real(integer \fIncid\fP, integer \fIvarid\fP, real \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_var_double(integer \fIncid\fP, integer \fIvarid\fP, doubleprecision \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_var_ubyte(integer \fIncid\fP, integer \fIvarid\fP, integer*1 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_var_ushort(integer \fIncid\fP, integer \fIvarid\fP, integer*2 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_var_uint(integer \fIncid\fP, integer \fIvarid\fP, integer*4 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_var_(integer \fIncid\fP, integer \fIvarid\fP, integer*8 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_var_uint64(integer \fIncid\fP, integer \fIvarid\fP, integer*8 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_var_string(integer \fIncid\fP, integer \fIvarid\fP, character* \fIin\fP(1))\fR
-
-
-.sp
-Reads an entire netCDF variable (i.e. all the values).
-The netCDF dataset must be open and in data mode.  
-The data is converted from the external type of the specified variable,
-if necessary, to the type specified in the function name.  If conversion is
-not possible, an \fBNF_ERANGE\fR error is returned.
-.SH "WRITING AND READING ONE DATUM"
-.LP
-.HP
-\fBinteger function nf_put_var1_text(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), character*1 \fI*out\fP)\fR
-
-.HP
-\fBinteger function nf_put_var1_int1(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), integer*1 \fI*out\fP)\fR
-.HP
-\fBinteger function nf_put_var1_int2(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), integer*2 \fI*out\fP)\fR
-.HP
-\fBinteger function nf_put_var1_int(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), integer \fI*out\fP)\fR
-
-.HP
-\fBinteger function nf_put_var1_real(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), real \fI*out\fP)\fR
-.HP
-\fBinteger function nf_put_var1_double(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), doubleprecision \fI*out\fP)\fR
-.HP
-\fBinteger function nf_put_var1_ubyte(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), integer*1 \fI*out\fP)\fR
-.HP
-\fBinteger function nf_put_var1_ushort(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), integer*2 \fI*out\fP)\fR
-.HP
-\fBinteger function nf_put_var1_uint(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), integer*4 \fI*out\fP)\fR
-.HP
-\fBinteger function nf_put_var1_(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), integer*8 \fI*out\fP)\fR
-.HP
-\fBinteger function nf_put_var1_uint64(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), integer*8 \fI*out\fP)\fR
-.HP
-\fBinteger function nf_put_var1_string(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), character* \fI*out\fP)\fR
-
-
-.sp
-Puts a single data value into a variable at the position \fIindex\fP of an
-open netCDF dataset that is in data mode.  The type of the data is
-specified in the function name, and it is converted to the external type
-of the specified variable, if possible, otherwise an \fBNF_ERANGE\fR
-error is returned.
-.HP
-\fBinteger function nf_get_var1_text(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), character*1 \fIin\fP)\fR
-
-.HP
-\fBinteger function nf_get_var1_int1(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), integer*1 \fIin\fP)\fR
-.HP
-\fBinteger function nf_get_var1_int2(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), integer*2 \fIin\fP)\fR
-.HP
-\fBinteger function nf_get_var1_int(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), integer \fIin\fP)\fR
-
-.HP
-\fBinteger function nf_get_var1_real(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), real \fIin\fP)\fR
-.HP
-\fBinteger function nf_get_var1_double(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), doubleprecision \fIin\fP)\fR
-.HP
-\fBinteger function nf_get_var1_ubyte(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), integer*1 \fIin\fP)\fR
-.HP
-\fBinteger function nf_get_var1_ushort(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), integer*2 \fIin\fP)\fR
-.HP
-\fBinteger function nf_get_var1_uint(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), integer*4 \fIin\fP)\fR
-.HP
-\fBinteger function nf_get_var1_(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), integer*8 \fIin\fP)\fR
-.HP
-\fBinteger function nf_get_var1_uint64(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), integer*8 \fIin\fP)\fR
-.HP
-\fBinteger function nf_get_var1_string(integer \fIncid\fP, integer \fIvarid\fP, integer \fIindex\fP(1), character* \fIin\fP)\fR
-
-
-.sp
-Gets a single data value from a variable at the position \fIindex\fP
-of an open netCDF dataset that is in data mode.  
-The data is converted from the external type of the specified variable,
-if necessary, to the type specified in the function name.  If conversion is
-not possible, an \fBNF_ERANGE\fR error is returned.
-.SH "WRITING AND READING AN ARRAY"
-.LP
-.HP
-\fBinteger function nf_put_vara_text(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), character*(*) \fIout\fP)\fR
-
-.HP
-\fBinteger function nf_put_vara_int1(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer*1 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_vara_int2(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer*2 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_vara_int(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIout\fP(1))\fR
-
-.HP
-\fBinteger function nf_put_vara_real(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), real \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_vara_double(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), doubleprecision \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_vara_ubyte(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer*1 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_vara_ushort(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer*2 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_vara_uint(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer*4 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_vara_(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer*8 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_vara_uint64(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer*8 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_vara_string(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), character* \fIout\fP(1))\fR
-
-
-.sp
-Writes an array section of values into a netCDF variable of an open
-netCDF dataset, which must be in data mode.  The array section is specified
-by the \fIstart\fP and \fIcount\fP vectors, which give the starting index
-and count of values along each dimension of the specified variable.
-The type of the data is
-specified in the function name and is converted to the external type
-of the specified variable, if possible, otherwise an \fBNF_ERANGE\fR
-error is returned.
-.HP
-\fBinteger function nf_get_vara_text(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), character*(*) \fIin\fP)\fR
-
-.HP
-\fBinteger function nf_get_vara_int1(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer*1 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_vara_int2(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer*2 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_vara_int(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIin\fP(1))\fR
-
-.HP
-\fBinteger function nf_get_vara_real(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), real \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_vara_double(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), doubleprecision \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_vara_ubyte(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer*1 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_vara_ushort(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer*2 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_vara_uint(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer*4 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_vara_(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer*8 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_vara_uint64(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer*8 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_vara_string(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), character* \fIin\fP(1))\fR
-
-
-.sp
-Reads an array section of values from a netCDF variable of an open
-netCDF dataset, which must be in data mode.  The array section is specified
-by the \fIstart\fP and \fIcount\fP vectors, which give the starting index
-and count of values along each dimension of the specified variable.
-The data is converted from the external type of the specified variable,
-if necessary, to the type specified in the function name.  If conversion is
-not possible, an \fBNF_ERANGE\fR error is returned.
-.SH "WRITING AND READING A SLICED ARRAY"
-.LP
-.HP
-\fBinteger function nf_put_vars_text(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), character*(*) \fIout\fP)\fR
-
-.HP
-\fBinteger function nf_put_vars_int1(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), integer*1 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_vars_int2(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), integer*2 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_vars_int(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), integer \fIout\fP(1))\fR
-
-.HP
-\fBinteger function nf_put_vars_real(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), real \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_vars_double(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), doubleprecision \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_vars_ubyte(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), integer*1 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_vars_ushort(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), integer*2 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_vars_uint(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), integer*4 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_vars_(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), integer*8 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_vars_uint64(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), integer*8 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_vars_string(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), character* \fIout\fP(1))\fR
-
-
-.sp
-These functions are used for \fIstrided output\fP, which is like the
-array section output described above, except that
-the sampling stride (the interval between accessed values) is
-specified for each dimension.
-For an explanation of the sampling stride
-vector, see COMMON ARGUMENTS DESCRIPTIONS below.
-.HP
-\fBinteger function nf_get_vars_text(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), character*(*) \fIin\fP)\fR
-
-.HP
-\fBinteger function nf_get_vars_int1(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), integer*1 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_vars_int2(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), integer*2 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_vars_int(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), integer \fIin\fP(1))\fR
-
-.HP
-\fBinteger function nf_get_vars_real(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), real \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_vars_double(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), doubleprecision \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_vars_ubyte(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), integer*1 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_vars_ushort(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), integer*2 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_vars_uint(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), integer*4 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_vars_(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), integer*8 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_vars_uint64(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), integer*8 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_vars_string(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), character* \fIin\fP(1))\fR
-
-
-.sp
-These functions are used for \fIstrided input\fP, which is like the
-array section input described above, except that 
-the sampling stride (the interval between accessed values) is
-specified for each dimension.
-For an explanation of the sampling stride
-vector, see COMMON ARGUMENTS DESCRIPTIONS below.
-.SH "WRITING AND READING A MAPPED ARRAY"
-.LP
-.HP
-\fBinteger function nf_put_varm_text(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, character*(*) \fIout\fP)\fR
-
-.HP
-\fBinteger function nf_put_varm_int1(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, integer*1 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_varm_int2(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, integer*2 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_varm_int(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, integer \fIout\fP(1))\fR
-
-.HP
-\fBinteger function nf_put_varm_real(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, real \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_varm_double(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, doubleprecision \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_varm_ubyte(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, integer*1 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_varm_ushort(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, integer*2 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_varm_uint(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, integer*4 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_varm_(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, integer*8 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_varm_uint64(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, integer*8 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_varm_string(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, character* \fIout\fP(1))\fR
-
-
-.sp
-These functions are used for \fImapped output\fP, which is like
-strided output described above, except that an additional index mapping
-vector is provided to specify the in-memory arrangement of the data
-values.
-For an explanation of the index
-mapping vector, see COMMON ARGUMENTS DESCRIPTIONS below.
-.HP
-\fBinteger function nf_get_varm_text(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, character*(*) \fIin\fP)\fR
-
-.HP
-\fBinteger function nf_get_varm_int1(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, integer*1 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_varm_int2(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, integer*2 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_varm_int(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, integer \fIin\fP(1))\fR
-
-.HP
-\fBinteger function nf_get_varm_real(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, real \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_varm_double(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, doubleprecision \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_varm_ubyte(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, integer*1 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_varm_ushort(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, integer*2 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_varm_uint(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, integer*4 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_varm_(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, integer*8 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_varm_uint64(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, integer*8 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_varm_string(integer \fIncid\fP, integer \fIvarid\fP, integer \fIstart\fP(1), integer \fIcount\fP(1), integer \fIstride\fP(1), \fIimap\fP, character* \fIin\fP(1))\fR
-
-
-.sp
-These functions are used for \fImapped input\fP, which is like
-strided input described above, except that an additional index mapping
-vector is provided to specify the in-memory arrangement of the data
-values.
-For an explanation of the index
-mapping vector, see COMMON ARGUMENTS DESCRIPTIONS below.
-.SH "ATTRIBUTES"
-.LP
-.HP
-\fBinteger function nf_put_att_text(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer \fIxtype\fP, integer \fIlen\fP, character*(*) \fIout\fP)\fR
-
-.HP
-\fBinteger function nf_put_att_int1(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer \fIxtype\fP, integer \fIlen\fP, integer*1 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_att_int2(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer \fIxtype\fP, integer \fIlen\fP, integer*2 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_att_int(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer \fIxtype\fP, integer \fIlen\fP, integer \fIout\fP(1))\fR
-
-.HP
-\fBinteger function nf_put_att_real(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer \fIxtype\fP, integer \fIlen\fP, real \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_att_double(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer \fIxtype\fP, integer \fIlen\fP, doubleprecision \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_att_ubyte(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer \fIxtype\fP, integer \fIlen\fP, integer*1 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_att_ushort(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer \fIxtype\fP, integer \fIlen\fP, integer*2 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_att_uint(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer \fIxtype\fP, integer \fIlen\fP, integer*4 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_att_(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer \fIxtype\fP, integer \fIlen\fP, integer*8 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_att_uint64(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer \fIxtype\fP, integer \fIlen\fP, integer*8 \fIout\fP(1))\fR
-.HP
-\fBinteger function nf_put_att_string(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer \fIxtype\fP, integer \fIlen\fP, character* \fIout\fP(1))\fR
-
-
-.HP
-\fBinteger function nf_put_att(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer \fIxtype\fP, integer \fIlen\fP, void * \fIip\fP)\fR
-.HP
-\fBinteger function nf_get_att(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, void * \fIip\fP)\fR
-.sp
-Unlike variables, attributes do not have 
-separate functions for defining and writing values.
-This family of functions defines a new attribute with a value or changes
-the value of an existing attribute.
-If the attribute is new, or if the space required to
-store the attribute value is greater than before,
-the netCDF dataset must be in define mode.
-The parameter \fIlen\fP is the number of values from \fIout\fP to transfer.
-It is often one, except that for
-\fBnf_put_att_text(\|)\fR it will usually be
-\fBlen_trim(\fIout\fP)\fR.
-.sp
-For these functions, the type component of the function name refers to
-the in-memory type of the value, whereas the \fIxtype\fP argument refers to the
-external type for storing the value.  An \fBNF_ERANGE\fR
-error results if
-a conversion between these types is not possible.  In this case the value
-is represented with the appropriate fill-value for the associated 
-external type.
-.HP
-\fBinteger function nf_inq_attname(integer \fIncid\fP, integer \fIvarid\fP, integer \fIattnum\fP, character*(*) \fIname\fP)\fR
-.sp
-Gets the
-name of an attribute, given its variable ID and attribute number.
-This function is useful in generic applications that
-need to get the names of all the attributes associated with a variable,
-since attributes are accessed by name rather than number in all other
-attribute functions.  The number of an attribute is more volatile than
-the name, since it can change when other attributes of the same variable
-are deleted.  The attributes for each variable are numbered
-from 1 (the first attribute) to
-\fInvatts\fP,
-where \fInvatts\fP is
-the number of attributes for the variable, as returned from a call to
-\fBnf_inq_varnatts(\|)\fR.
-
-.HP
-\fBinteger function nf_inq_att(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer \fIxtype\fP, integer \fIlen\fP)\fR
-.HP
-\fBinteger function nf_inq_attid(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer \fIattnum\fP)\fR
-.HP
-\fBinteger function nf_inq_atttype(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer \fIxtype\fP)\fR
-.HP
-\fBinteger function nf_inq_attlen(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer \fIlen\fP)\fR
-.sp
-These functions return information about a netCDF attribute,
-given its variable ID and name.  The information returned is the
-external type in \fIxtype\fP
-and the number of elements in the attribute as \fIlen\fP.
-
-.HP
-\fBinteger function nf_copy_att(integer \fIncid\fP, integer \fIvarid_in\fP, character*(*) \fIname\fP, integer \fIncid_out\fP, integer \fIvarid_out\fP)\fR
-.sp
-Copies an
-attribute from one netCDF dataset to another.  It can also be used to
-copy an attribute from one variable to another within the same netCDF.
-\fIncid_in\fP is the netCDF ID of an input netCDF dataset from which the
-attribute will be copied.
-\fIvarid_in\fP
-is the ID of the variable in the input netCDF dataset from which the
-attribute will be copied, or \fBNF_GLOBAL\fR
-for a global attribute.
-\fIname\fP
-is the name of the attribute in the input netCDF dataset to be copied.
-\fIncid_out\fP
-is the netCDF ID of the output netCDF dataset to which the attribute will be 
-copied.
-It is permissible for the input and output netCDF ID's to be the same.  The
-output netCDF dataset should be in define mode if the attribute to be
-copied does not already exist for the target variable, or if it would
-cause an existing target attribute to grow.
-\fIvarid_out\fP
-is the ID of the variable in the output netCDF dataset to which the attribute will
-be copied, or \fBNF_GLOBAL\fR to copy to a global attribute.
-.HP
-\fBinteger function nf_rename_att(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, character*(*) \fInewname\fP)\fR
-.sp
-Changes the
-name of an attribute.  If the new name is longer than the original name,
-the netCDF must be in define mode.  You cannot rename an attribute to
-have the same name as another attribute of the same variable.
-\fIname\fP is the original attribute name.
-\fInewname\fP
-is the new name to be assigned to the specified attribute.  If the new name
-is longer than the old name, the netCDF dataset must be in define mode.
-.HP
-\fBinteger function nf_del_att(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP)\fR
-.sp
-Deletes an attribute from a netCDF dataset.  The dataset must be in
-define mode.
-.HP
-\fBinteger function nf_get_att_text(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, character*(*) \fIin\fP)\fR
-
-.HP
-\fBinteger function nf_get_att_int1(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer*1 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_att_int2(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer*2 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_att_int(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer \fIin\fP(1))\fR
-
-.HP
-\fBinteger function nf_get_att_real(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, real \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_att_double(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, doubleprecision \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_att_ubyte(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer*1 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_att_ushort(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer*2 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_att_uint(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer*4 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_att_(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer*8 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_att_uint64(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, integer*8 \fIin\fP(1))\fR
-.HP
-\fBinteger function nf_get_att_string(integer \fIncid\fP, integer \fIvarid\fP, character*(*) \fIname\fP, character* \fIin\fP(1))\fR
-
-
-.sp
-Gets the value(s) of a netCDF attribute, given its
-variable ID and name.  Converts from the external type to the type
-specified in
-the function name, if possible, otherwise returns an \fBNF_ERANGE\fR
-error.
-All elements of the vector of attribute
-values are returned, so you must allocate enough space to hold
-them.  If you don't know how much space to reserve, call
-\fBnf_inq_attlen(\|)\fR
-first to find out the length of the attribute.
-.SH "COMMON ARGUMENT DESCRIPTIONS"
-.LP
-In this section we define some common arguments which are used in the 
-"FUNCTION DESCRIPTIONS" section.
-.TP
-integer \fIncid\fP
-is the netCDF ID returned from a previous, successful call to
-\fBnf_open(\|)\fR or \fBnf_create(\|)\fR
-.TP
-character*(*) \fIname\fP
-is the name of a dimension, variable, or attribute. The names of 
-dimensions, variables and attributes consist of arbitrary
-sequences of alphanumeric characters (as well as underscore '_',
-period '.' and hyphen '-'), beginning with a letter or
-underscore. (However names commencing with underscore are reserved for
-system use.) Case is significant in netCDF names. A zero-length name
-is not allowed.
-
-The maximum allowable number of characters 
- is \fBNF_MAX_NAME\fR.
-.TP
-integer \fIxtype\fP
-specifies the external data type of a netCDF variable or attribute and
-is one of the following:
-\fBNF_BYTE\fR, \fBNF_CHAR\fR, \fBNF_SHORT\fR, \fBNF_INT\fR, 
-\fBNF_FLOAT\fR, or \fBNF_DOUBLE\fR.
-These are used to specify 8-bit integers,
-characters, 16-bit integers, 32-bit integers, 32-bit IEEE floating point
-numbers, and 64-bit IEEE floating-point numbers, respectively.
-
-.TP
-integer \fIdimids\fP(1)
-is a vector of dimension ID's and defines the shape of a netCDF variable.
-The size of the vector shall be greater than or equal to the
-rank (i.e. the number of dimensions) of the variable (\fIndims\fP).
-The vector shall be ordered by the speed with which a dimension varies:
-\fIdimids\fP(1)
-shall be the dimension ID of the most rapidly
-varying dimension and
-\fIdimids\fP(\fIndims\fP)
-shall be the dimension ID of the most slowly
-varying dimension.
-The maximum possible number of
-dimensions for a variable is given by the symbolic constant
-\fBNF_MAX_VAR_DIMS\fR.
-.TP
-integer \fIdimid\fP
-is the ID of a netCDF dimension.
-netCDF dimension ID's are allocated sequentially from the 
-positive
-integers beginning with 1.
-.TP
-integer \fIndims\fP
-is either the total number of dimensions in a netCDF dataset or the rank
-(i.e. the number of dimensions) of a netCDF variable.
-The value shall not be negative or greater than the symbolic constant 
-\fBNF_MAX_VAR_DIMS\fR.
-.TP
-integer \fIvarid\fP
-is the ID of a netCDF variable or (for the attribute-access functions) 
-the symbolic constant
-\fBNF_GLOBAL\fR,
-which is used to reference global attributes.
-netCDF variable ID's are allocated sequentially from the 
-positive
-integers beginning with 1.
-.TP
-integer \fInatts\fP
-is the number of global attributes in a netCDF dataset  for the
-\fBnf_inquire(\|)\fR
-function or the number
-of attributes associated with a netCDF variable for the
-\fBnf_varinq(\|)\fR
-function.
-.TP
-integer \fIindex\fP(1)
-specifies the indicial coordinates of the netCDF data value to be accessed.
-The indices start at 1;
-thus, for example, the first data value of a
-two-dimensional variable is (1,1).
-The size of the vector shall be at least the rank of the associated
-netCDF variable and its elements shall correspond, in order, to the
-variable's dimensions.
-.TP
-integer \fIstart\fP(1)
-specifies the starting point
-for accessing a netCDF variable's data values
-in terms of the indicial coordinates of 
-the corner of the array section.
-The indices start at 1;
-thus, the first data
-value of a variable is (1, 1, ..., 1).
-The size of the vector shall be at least the rank of the associated
-netCDF variable and its elements shall correspond, in order, to the
-variable's dimensions.
-.TP
-integer \fIcount\fP(1)
-specifies the number of indices selected along each dimension of the
-array section.
-Thus, to access a single value, for example, specify \fIcount\fP as
-(1, 1, ..., 1).
-Note that, for strided I/O, this argument must be adjusted
-to be compatible with the \fIstride\fP and \fIstart\fP arguments so that 
-the interaction of the
-three does not attempt to access an invalid data co-ordinate.
-The elements of the
-\fIcount\fP vector correspond, in order, to the variable's dimensions.
-.TP
-integer \fIstride\fP(1)
-specifies the sampling interval along each dimension of the netCDF
-variable.   The elements of the stride vector correspond, in order,
-to the netCDF variable's dimensions (\fIstride\fP(1))
-gives the sampling interval along the most rapidly 
-varying dimension of the netCDF variable).  Sampling intervals are
-specified in type-independent units of elements (a value of 1 selects
-consecutive elements of the netCDF variable along the corresponding
-dimension, a value of 2 selects every other element, etc.).
-
-.TP
-\fIimap\fP
-specifies the mapping between the dimensions of a netCDF variable and
-the in-memory structure of the internal data array.  The elements of
-the index mapping vector correspond, in order, to the netCDF variable's
-dimensions (\fIimap\fP(1) gives the distance
-between elements of the internal array corresponding to the most
-rapidly varying dimension of the netCDF variable).
-Distances between elements are specified in type-independent units of
-elements (the distance between internal elements that occupy adjacent
-memory locations is 1 and not the element's byte-length as in netCDF 2).
-
-.SH "VARIABLE PREFILLING"
-.LP
-By default, the netCDF interface sets the values of
-all newly-defined variables of finite length (i.e. those that do not have
-an unlimited, dimension) to the type-dependent fill-value associated with each 
-variable.  This is done when \fBnf_enddef(\|)\fR
-is called.  The
-fill-value for a variable may be changed from the default value by
-defining the attribute `\fB_FillValue\fR' for the variable.  This
-attribute must have the same type as the variable and be of length one.
-.LP
-Variables with an unlimited dimension are also prefilled, but on
-an `as needed' basis.  For example, if the first write of such a
-variable is to position 5, then
-positions
-1 through 4
-(and no others)
-would be set to the fill-value at the same time.
-.LP
-This default prefilling of data values may be disabled by
-or'ing the
-\fBNF_NOFILL\fR
-flag into the mode parameter of \fBnf_open(\|)\fR or \fBnf_create(\|)\fR,
-or, by calling the function \fBnf_set_fill(\|)\fR
-with the argument \fBNF_NOFILL\fR.
-For variables that do not use the unlimited dimension,
-this call must
-be made before
-\fBnf_enddef(\|)\fR.
-For variables that
-use the unlimited dimension, this call
-may be made at any time.
-.LP
-One can obtain increased performance of the netCDF interface by using 
-this feature, but only at the expense of requiring the application to set
-every single data value.  The performance
-enhancing behavior of this function is dependent on the particulars of
-the implementation and dataset format.
-The flag value controlled by \fBnf_set_fill(\|)\fR
-is per netCDF ID,
-not per variable or per write. 
-Allowing this to change affects the degree to which
-a program can be effectively parallelized.
-Given all of this, we state that the use
-of this feature may not be available (or even needed) in future
-releases. Programmers are cautioned against heavy reliance upon this
-feature.
-.HP
-\fBinteger function nf_setfill(integer \fIncid\fP, integer \fIfillmode\fP, integer \fIold_fillemode\fP)\fR
-
-.sp
-Determines whether or not variable prefilling will be done (see 
-above).
-The netCDF dataset shall be writable.
-\fIfillmode\fP is either \fBNF_FILL\fR
-to enable prefilling (the
-default) or \fBNF_NOFILL\fR
-to disable prefilling.
-This function returns the previous setting in \fIold_fillmode\fP.
-
-.HP
-.SH "MPP FUNCTION DESCRIPTIONS"
-.LP
-Additional functions for use on SGI/Cray MPP machines (_CRAYMPP).
-These are used to set and inquire which PE is the base for MPP
-for a particular netCDF. These are only relevant when
-using the SGI/Cray ``global''
-Flexible File I/O layer and desire to have
-only a subset of PEs to open the specific netCDF file.
-For technical reasons, these functions are available on all platforms.
-On a platform other than SGI/Cray MPP, it is as if
-only processor available were processor 0.
-.LP
-To use this feature, you need to specify a communicator group and call
-\fBglio_group_mpi(\|)\fR or \fBglio_group_shmem(\|)\fR prior to the netCDF
-\fBnf_open(\|)\fR and \fBnf_create(\|)\fR calls.
-.HP
-\fBinteger function nf__create_mp(character*(*) \fIpath\fP, integer \fIcmode\fP, integer \fIinitialsize\fP, integer \fIpe\fP, integer \fIchunksize\fP, integer \fIncid\fP)\fR
-.sp
-Like \fBnf__create(\|)\fR but allows the base PE to be set.
-.sp
-The argument \fIpe\fP sets the base PE at creation time. In the MPP
-environment, \fBnf__create(\|)\fR and \fBnf_create(\|)\fR set the base PE to processor
-zero by default.
-.HP
-\fBinteger function nf__open_mp(character*(*) \fIpath\fP, integer \fImode\fP, integer \fIpe\fP, integer \fIchunksize\fP, integer \fIncid\fP)\fR
-.sp
-Like \fBnf__open(\|)\fR but allows the base PE to be set.
-The argument \fIpe\fP sets the base PE at creation time. In the MPP
-environment, \fBnf__open(\|)\fR and \fBnf_open(\|)\fR set the base PE to processor
-zero by default.
-.HP
-\fBinteger function nf_inq_base_pe(integer \fIncid\fP, integer \fIpe\fP)\fR
-.sp
-Inquires of the netCDF dataset which PE is being used as the base for MPP use.
-This is safe to use at any time.
-.HP
-\fBinteger function nf_set_base_pe(integer \fIncid\fP, integer \fIpe\fP)\fR
-.sp
-Resets the base PE for the netCDF dataset.
-Only perform this operation when the affected communicator group
-synchronizes before and after the call.
-This operation is very risky and should only be contemplated
-under only the most extreme cases.
-.SH "ENVIRONMENT VARIABLES"
-.TP 4
-.B NETCDF_FFIOSPEC
-Specifies the Flexible File I/O buffers for netCDF I/O when executing
-under the UNICOS operating system (the variable is ignored on other
-operating systems).
-An appropriate specification can greatly increase the efficiency of 
-netCDF I/O -- to the extent that it can actually surpass FORTRAN binary 
-I/O.
-This environment variable has been made a little more generalized,
-such that other FFIO option specifications can now be added.
-The default specification is \fBbufa:336:2\fP,
-unless a current FFIO specification is in operation,
-which will be honored.
-See UNICOS Flexible File I/O for more information.
-.SH "MAILING-LISTS"
-.LP
-Both a mailing list and a digest are available for
-discussion of the netCDF interface and announcements about netCDF bugs,
-fixes, and enhancements.
-To begin or change your subscription to either the mailing-list or the
-digest, send one of the following in the body (not
-the subject line) of an email message to "majordomo at unidata.ucar.edu".
-Use your email address in place of \fIjdoe at host.inst.domain\fP.
-.sp
-To subscribe to the netCDF mailing list:
-.RS
-\fBsubscribe netcdfgroup \fIjdoe at host.inst.domain\fR
-.RE
-To unsubscribe from the netCDF mailing list:
-.RS
-\fBunsubscribe netcdfgroup \fIjdoe at host.inst.domain\fR
-.RE
-To subscribe to the netCDF digest:
-.RS
-\fBsubscribe netcdfdigest \fIjdoe at host.inst.domain\fR
-.RE
-To unsubscribe from the netCDF digest:
-.RS
-\fBunsubscribe netcdfdigest \fIjdoe at host.inst.domain\fR
-.RE
-To retrieve the general introductory information for the mailing list:
-.RS
-\fBinfo netcdfgroup\fR
-.RE
-To get a synopsis of other majordomo commands:
-.RS
-\fBhelp\fR
-.RE
-.SH "SEE ALSO"
-.LP
-.BR ncdump (1),
-.BR ncgen (1),
-.BR netcdf (3f).
-.LP
-\fInetCDF User's Guide\fP, published
-by the Unidata Program Center, University Corporation for Atmospheric
-Research, located in Boulder, Colorado.
-
-NetCDF home page at http:/www.unidata.ucar.edu/netcdf.
diff --git a/m4/dummy.txt b/m4/dummy.txt
new file mode 100644
index 0000000..0651e5f
--- /dev/null
+++ b/m4/dummy.txt
@@ -0,0 +1,2 @@
+This file exists just to make git put the m4/ parent directory in the
+repository, since git doesn't seem to like empty directories ...
diff --git a/nf03_test/README_NF03_TESTS b/nf03_test/README_NF03_TESTS
new file mode 100644
index 0000000..d7bbf2f
--- /dev/null
+++ b/nf03_test/README_NF03_TESTS
@@ -0,0 +1,4 @@
+ These test programs are modified versions of test programs from
+ a previous nf_test. There purpose is to test the use of the Fortran
+ 2003 modules supplied as replacements for the netcdf and netcdf4 include
+ files
diff --git a/nf_test/README_NF03_TESTS b/nf_test/README_NF03_TESTS
new file mode 100644
index 0000000..d7bbf2f
--- /dev/null
+++ b/nf_test/README_NF03_TESTS
@@ -0,0 +1,4 @@
+ These test programs are modified versions of test programs from
+ a previous nf_test. There purpose is to test the use of the Fortran
+ 2003 modules supplied as replacements for the netcdf and netcdf4 include
+ files
diff --git a/nf_test/f03test.F b/nf_test/f03test.F
new file mode 100755
index 0000000..5482db2
--- /dev/null
+++ b/nf_test/f03test.F
@@ -0,0 +1,1458 @@
+!********************************************************************
+!   Copyright 1993, UCAR/Unidata
+!   See netcdf/COPYRIGHT file for copying and redistribution conditions.
+!   $Id: ftest.F,v 1.11 2009/01/25 14:33:45 ed Exp $
+!********************************************************************
+
+#include "../fortran/nf03config.inc"
+
+!
+!     program to test the netCDF-2 Fortran API
+!
+      program ftest
+
+      use netcdf_f03
+
+!     name of first test cdf
+      character*31 name
+!     name of second test cdf
+      character*31 name2
+      
+!     Returned error code.
+      integer iret 
+!     netCDF ID
+      integer ncid
+!     ID of dimension lat
+      integer  latdim
+!     ID of dimension lon
+      integer londim
+!     ID of dimension level
+      integer leveldim
+!     ID of dimension time
+      integer timedim
+!     ID of dimension len
+      integer lendim
+
+!     Count the errors.
+      integer nfails
+
+!     variable used to control error-handling behavior
+      integer ncopts
+      integer dimsiz(MAXNCDIM)
+!      allowable roundoff 
+      common /dims/timedim, latdim, londim, leveldim, lendim,
+     + dimsiz
+      data name/'test.nc'/
+      data name2/'copy.nc'/
+
+      print *, ''
+      print *,'*** Testing netCDF-2 Fortran 77 API.'
+
+100   format(' *** testing ', a, ' ...')
+!     set error-handling to verbose and non-fatal
+      ncopts = NCVERBOS
+      call ncpopt(ncopts)
+
+!     This will be a count of how many failures we experience.
+      nfails = 0
+
+!     create a netCDF named 'test.nc'
+      write(*,100) 'nccre'
+      ncid = nccre(name, NCCLOB, iret)
+      if (ncid .eq. -1) then nfails = nfails + 1
+
+!     test ncddef
+      write(*,100) 'ncddef'
+      call tncddef(ncid, nfails)
+
+!     test ncvdef
+      write(*,100) 'ncvdef'
+      call tncvdef(ncid, nfails)
+
+!     test ncapt
+      write(*, 100) 'ncapt, ncaptc'
+      call tncapt(ncid, nfails)
+
+!     close 'test.nc'
+      write(*, 100) 'ncclos'
+      call ncclos(ncid, iret)
+      if (ncid .eq. -1) then nfails = nfails + 1
+
+!     test ncvpt1
+      write(*, 100) 'ncvpt1'
+      call tncvpt1(name, nfails)
+
+!     test ncvgt1
+      write(*, 100) 'ncvgt1'
+      call tncvgt1(name, nfails)
+
+!     test ncvpt
+      write(*, 100) 'ncvpt'
+      call tncvpt(name, nfails)
+
+!     test ncinq
+      write(*, 100) 'ncopn, ncinq, ncdinq, ncvinq, ncanam, ncainq'
+      call tncinq(name, nfails)
+
+!     test ncvgt
+      write(*, 100) 'ncvgt, ncvgtc'
+      call tncvgt(name, nfails)
+
+!     test ncagt
+      write(*, 100) 'ncagt, ncagtc'
+      call tncagt(name, nfails)
+
+!     test ncredf
+      write(*, 100) 'ncredf, ncdren, ncvren, ncaren, ncendf'
+      call tncredf(name, nfails)
+
+      call tncinq(name, nfails)
+
+!     test ncacpy
+      write(*, 100) 'ncacpy'
+      call tncacpy(name, name2, nfails)
+
+!     test ncadel
+      write(*, 100) 'ncadel'
+      call tncadel(name2, nfails)
+
+!     test fill values
+      write(*, 100) 'fill values'
+      call tfills(nfails)
+
+      print *,'Total number of failures: ', nfails
+      if (nfails .ne. 0) stop 2
+
+      print *,'*** SUCCESS!'
+
+      end
+!
+!     subroutine to test ncacpy
+!
+      subroutine tncacpy(iname, oname, nfails)
+      use netcdf_f03
+      character*31 iname, oname
+      integer ndims, nvars, natts, recdim, iret
+      character*31 vname, attnam
+      integer attype, attlen
+      integer vartyp, nvdims, vdims(MAXVDIMS), nvatts
+      integer lenstr
+!     existing netCDF id
+      integer incdf
+!     netCDF id of the output netCDF file to which the attribute
+!     will be copied
+      integer outcdf
+
+      integer mattlen
+      parameter (mattlen = 80)
+      character*80 charval
+      doubleprecision doubval(2)
+      real flval(2)
+      integer lngval(2)
+      NCSHORT_T shval(2)
+      integer i, j, k
+      character*31 varnam, attname(2,7), gattnam(2)
+      NCBYTE_T bytval(2)
+      common /atts/attname, gattnam
+      NCSHORT_T svalidrg(2)
+      real rvalidrg(2)
+      integer lvalidrg(2)
+      doubleprecision dvalidrg(2)
+      NCBYTE_T bvalidrg(2)
+      character*31 gavalue(2), cavalue(2)
+      real epsilon
+
+      data bvalidrg/-127,127/
+      data svalidrg/-100,100/
+      data lvalidrg/0,360/
+      data rvalidrg/0.0, 5000.0/
+      data dvalidrg/0D0,500D0/
+      data gavalue/'NWS', '88/10/25 12:00:00'/
+      data cavalue/'test string', 'a'/
+      data lenstr/80/   
+      data epsilon /.000001/
+
+      incdf = ncopn(iname, NCNOWRIT, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+      outcdf = nccre(oname, NCCLOB, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+      call tncddef(outcdf, nfails)
+      call tncvdef(outcdf, nfails)
+      call ncinq (incdf, ndims, nvars, natts, recdim, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      do 5 j = 1, natts
+         call ncanam (incdf, NCGLOBAL, j, attnam, iret)
+         if (iret .ne. 0) nfails = nfails + 1
+         call ncacpy (incdf, NCGLOBAL, attnam, outcdf, NCGLOBAL, iret)
+         if (iret .ne. 0) nfails = nfails + 1
+ 5    continue
+      do 10 i = 1, nvars
+         call ncvinq (incdf, i, vname, vartyp, nvdims,
+     +        vdims, nvatts, iret)
+         if (iret .ne. 0) nfails = nfails + 1
+         do 20 k = 1, nvatts
+            call ncanam (incdf, i, k, attnam, iret)
+            if (iret .ne. 0) nfails = nfails + 1
+            call ncacpy (incdf, i, attnam, outcdf, i, iret)
+            if (iret .ne. 0) nfails = nfails + 1
+ 20      continue
+ 10   continue
+!     
+!     get global attributes first
+!     
+      do 100 i = 1, natts
+         call ncanam (outcdf, NCGLOBAL, i, attnam, iret)
+         if (iret .ne. 0) nfails = nfails + 1
+         call ncainq (outcdf, NCGLOBAL, attnam, attype, attlen,
+     +        iret)
+         if (iret .ne. 0) nfails = nfails + 1
+         if (attlen .gt. mattlen) then
+            write (*,*) 'global attribute too big!', attlen, mattlen
+            stop 2
+         else if (attype .eq. NCBYTE) then
+            call ncagt (outcdf, NCBYTE, attnam, bytval, iret)
+            if (iret .ne. 0) nfails = nfails + 1
+         else if (attype .eq. NCCHAR) then
+            call ncagtc (outcdf, NCGLOBAL, attnam, charval, 
+     +           lenstr, iret)
+            if (iret .ne. 0) nfails = nfails + 1
+            if (attnam .ne. gattnam(i)) write(*,*) 'error in ncagt G'
+            if (charval .ne. gavalue(i))
+     + write(*,*) 'error in ncagt G2', lenstr, charval, gavalue(i)
+                  charval = ' '
+         else if (attype .eq. NCSHORT) then
+            call ncagt (outcdf, NCGLOBAL, attnam, shval, iret)
+            if (iret .ne. 0) nfails = nfails + 1
+         else if (attype .eq. NCLONG) then
+            call ncagt (outcdf, NCGLOBAL, attnam, lngval, iret)            
+            if (iret .ne. 0) nfails = nfails + 1
+         else if (attype .eq. NCFLOAT) then
+            call ncagt (outcdf, NCGLOBAL, attnam, flval, iret)
+            if (iret .ne. 0) nfails = nfails + 1
+         else 
+            call ncagt (outcdf, NCGLOBAL, attnam, doubval,iret)          
+            if (iret .ne. 0) nfails = nfails + 1
+         end if
+ 100   continue
+!
+!     get variable attributes
+!
+      do 200 i = 1, nvars
+         call ncvinq (outcdf, i, varnam, vartyp, nvdims, vdims,
+     +                nvatts, iret)
+         if (iret .ne. 0) nfails = nfails + 1
+         do 250 j = 1, nvatts
+            call ncanam (outcdf, i, j, attnam, iret)
+            if (iret .ne. 0) nfails = nfails + 1
+            call ncainq (outcdf, i, attnam, attype, attlen,
+     +                   iret)
+            if (iret .ne. 0) nfails = nfails + 1
+            if (attlen .gt. mattlen) then
+               write (*,*) 'variable ', i,  'attribute too big !'
+               stop 2
+            else 
+               if (attype .eq. NCBYTE) then
+                  call ncagt (outcdf, i, attnam, bytval, 
+     +                 iret)
+                  if (iret .ne. 0) nfails = nfails + 1
+                  if (attnam .ne. attname(j,i))
+     +               write(*,*) 'error in ncagt BYTE N'
+                  if (bytval(j) .ne. bvalidrg(j)) write(*,*)
+     + 'ncacpy: byte ', bytval(j), ' .ne. ', bvalidrg(j)
+               else if (attype .eq. NCCHAR) then
+                  call ncagtc (outcdf, i, attnam, charval, 
+     +                 lenstr, iret)
+                  if (iret .ne. 0) nfails = nfails + 1
+                  if (attnam .ne. attname(j,i)) 
+     +               write(*,*) 'error in ncagt CHAR N'
+                  if (charval .ne. cavalue(j)) 
+     +               write(*,*) 'error in ncagt'
+                  charval = ' '
+               else if (attype .eq. NCSHORT) then
+                  call ncagt (outcdf, i, attnam, shval, 
+     +                 iret)  
+                  if (iret .ne. 0) nfails = nfails + 1
+                  if (attnam .ne. attname(j,i)) 
+     +               write(*,*) 'error in ncagt SHORT N'
+                  if (shval(j) .ne. svalidrg(j)) then
+                     write(*,*) 'error in ncagt SHORT'
+                  end if
+               else if (attype .eq. NCLONG) then
+                  call ncagt (outcdf, i, attnam, lngval, 
+     +                 iret)
+                  if (iret .ne. 0) nfails = nfails + 1
+                  if (attnam .ne. attname(j,i)) 
+     +               write(*,*) 'error in ncagt LONG N'
+                  if (lngval(j) .ne. lvalidrg(j)) 
+     +               write(*,*) 'error in ncagt LONG'
+               else if (attype .eq. NCFLOAT) then
+                  call ncagt (outcdf, i, attnam, flval, 
+     +                 iret)            
+                  if (iret .ne. 0) nfails = nfails + 1
+                  if (attnam .ne. attname(j,i)) 
+     +               write(*,*) 'error in ncagt FLOAT N'
+                  if (flval(j) .ne. rvalidrg(j)) 
+     +               write(*,*) 'error in ncagt FLOAT'
+               else if (attype .eq. NCDOUBLE) then
+                  call ncagt (outcdf, i, attnam, doubval,
+     +                 iret)          
+                  if (iret .ne. 0) nfails = nfails + 1
+                  if (attnam .ne. attname(j,i)) 
+     +               write(*,*) 'error in ncagt DOUBLE N'
+                  if ( abs(doubval(j) - dvalidrg(j)) .gt. epsilon)
+     + write(*,*) 'error in ncagt DOUBLE'
+               end if
+            end if
+ 250     continue
+ 200   continue
+      call ncclos(incdf, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      call ncclos(outcdf, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      return
+      end
+
+
+      
+!     
+!     subroutine to test ncadel
+!
+      subroutine tncadel (cdfname, nfails)
+      use netcdf_f03
+      character*31 cdfname
+      
+      integer  bid, sid, lid, fid, did, cid, chid
+      common /vars/bid, sid, lid, fid, did, cid, chid
+      integer ncid, iret, i, j
+      integer ndims, nvars, natts, recdim
+      integer vartyp, nvdims, vdims(MAXVDIMS), nvatts
+      character*31 varnam, attnam
+
+      ncid = ncopn(cdfname, NCWRITE, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+!     put cdf in define mode
+      call ncredf (ncid,iret)
+      if (iret .ne. 0) nfails = nfails + 1
+!     get number of global attributes
+      call ncinq (ncid, ndims, nvars, natts, recdim, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      do 10 i = natts, 1, -1
+!     get name of global attribute
+         call ncanam (ncid, NCGLOBAL, i, attnam, iret)
+         if (iret .ne. 0) nfails = nfails + 1
+!     delete global attribute
+         call ncadel (ncid, NCGLOBAL, attnam, iret)
+         if (iret .ne. 0) nfails = nfails + 1
+ 10   continue
+
+      do 100 i = 1, nvars
+!     get number of variable attributes
+         call ncvinq (ncid, i, varnam, vartyp, nvdims, vdims,
+     +        nvatts, iret)
+         if (iret .ne. 0) nfails = nfails + 1
+         do 200 j = nvatts, 1, -1
+            call ncanam (ncid, i, j, attnam, iret)
+            if (iret .ne. 0) nfails = nfails + 1
+            call ncadel (ncid, i, attnam, iret)
+            if (iret .ne. 0) nfails = nfails + 1
+ 200     continue
+ 100  continue
+      call ncinq (ncid, ndims, nvars, natts, recdim, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      if (natts .ne. 0) write(*,*) 'error in ncadel'
+!     put netCDF into data mode
+      call ncendf (ncid, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      call ncclos (ncid, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      return
+      end
+
+!
+!     subroutine to test ncagt and ncagtc
+
+      subroutine tncagt(cdfname, nfails)
+      use netcdf_f03
+      character*31 cdfname
+            
+!     maximum length of an attribute
+      integer mattlen
+      parameter (mattlen = 80)
+      integer ncid, ndims, nvars, natts, recdim
+      integer bid, sid, lid, fid, did, cid, chid
+      common /vars/bid, sid, lid, fid, did, cid, chid
+      integer i, j
+      integer attype, attlen, lenstr, iret
+      character*31 attnam
+      character*80 charval
+      doubleprecision doubval(2)
+      real flval(2)
+      integer lngval(2)
+      NCSHORT_T shval(2)
+      NCBYTE_T bytval(2)
+      integer vartyp, nvdims, vdims(MAXVDIMS), nvatts
+
+      character*31 varnam, attname(2,7), gattnam(2)
+      common /atts/attname, gattnam
+      NCSHORT_T svalidrg(2)
+      real rvalidrg(2)
+      integer lvalidrg(2)
+      doubleprecision dvalidrg(2)
+      NCBYTE_T bvalidrg(2)
+      character*31 gavalue(2), cavalue(2)
+      real epsilon
+
+      data bvalidrg/-127,127/
+      data svalidrg/-100,100/
+      data lvalidrg/0,360/
+      data rvalidrg/0.0, 5000.0/
+      data dvalidrg/0D0,500D0/
+      data gavalue/'NWS', '88/10/25 12:00:00'/
+      data cavalue/'test string', 'a'/
+      data lenstr/80/   
+      data epsilon /.000001/
+      
+      ncid = ncopn (cdfname, NCNOWRIT, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      call ncinq (ncid, ndims, nvars, natts, recdim, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+!     
+!     get global attributes first
+!     
+      do 10 i = 1, natts
+!     get name of attribute
+         call ncanam (ncid, NCGLOBAL, i, attnam, iret)
+         if (iret .ne. 0) nfails = nfails + 1
+!     get attribute type and length
+         call ncainq (ncid, NCGLOBAL, attnam, attype, attlen,
+     +        iret)
+         if (iret .ne. 0) nfails = nfails + 1
+         if (attlen .gt. mattlen) then
+            write (*,*) 'global attribute too big!'
+            stop 2
+         else if (attype .eq. NCBYTE) then
+            call ncagt (ncid, NCBYTE, attnam, bytval, iret)
+            if (iret .ne. 0) nfails = nfails + 1
+         else if (attype .eq. NCCHAR) then
+            call ncagtc (ncid, NCGLOBAL, attnam, charval, 
+     +           lenstr, iret)
+            if (iret .ne. 0) nfails = nfails + 1
+            if (attnam .ne. gattnam(i)) write(*,*) 'error in ncagt'
+            if (charval .ne. gavalue(i)) write(*,*) 'error in ncagt'
+            charval = '                                        '
+         else if (attype .eq. NCSHORT) then
+            call ncagt (ncid, NCGLOBAL, attnam, shval, iret) 
+            if (iret .ne. 0) nfails = nfails + 1
+         else if (attype .eq. NCLONG) then
+            call ncagt (ncid, NCGLOBAL, attnam, lngval, iret)            
+            if (iret .ne. 0) nfails = nfails + 1
+         else if (attype .eq. NCFLOAT) then
+            call ncagt (ncid, NCGLOBAL, attnam, flval, iret)
+            if (iret .ne. 0) nfails = nfails + 1
+         else 
+            call ncagt (ncid, NCGLOBAL, attnam, doubval,iret)          
+            if (iret .ne. 0) nfails = nfails + 1
+         end if
+ 10   continue
+
+!
+!     get variable attributes
+!
+      do 20 i = 1, nvars
+         call ncvinq (ncid, i, varnam, vartyp, nvdims, vdims,
+     +                nvatts, iret)
+         if (iret .ne. 0) nfails = nfails + 1
+         do 25 j = 1, nvatts
+            call ncanam (ncid, i, j, attnam, iret)
+            if (iret .ne. 0) nfails = nfails + 1
+            call ncainq (ncid, i, attnam, attype, attlen,
+     +                   iret)
+            if (iret .ne. 0) nfails = nfails + 1
+            if (attlen .gt. mattlen) then
+               write (*,*) 'variable ', i,  'attribute too big !'
+               stop 2
+            else 
+               if (attype .eq. NCBYTE) then
+                  call ncagt (ncid, i, attnam, bytval, 
+     +                 iret)
+                  if (iret .ne. 0) nfails = nfails + 1
+                  if (attnam .ne. attname(j,i)) 
+     +               write(*,*) 'error in ncagt BYTE name'
+                  if (bytval(j) .ne. bvalidrg(j)) write(*,*)
+     + 'ncacpy: byte ', bytval(j), ' .ne. ', bvalidrg(j)
+               else if (attype .eq. NCCHAR) then
+                  call ncagtc (ncid, i, attnam, charval, 
+     +                 lenstr, iret)
+                  if (iret .ne. 0) nfails = nfails + 1
+                  if (attnam .ne. attname(j,i)) 
+     +               write(*,*) 'error in ncagt CHAR name'
+                  if (charval .ne. cavalue(j)) 
+     +               write(*,*) 'error in ncagt CHAR name'
+                 charval = '                                        '
+               else if (attype .eq. NCSHORT) then
+                  call ncagt (ncid, i, attnam, shval, 
+     +                 iret)  
+                  if (iret .ne. 0) nfails = nfails + 1
+                  if (attnam .ne. attname(j,i)) 
+     +               write(*,*) 'error in ncagt SHORT name'
+                  if (shval(j) .ne. svalidrg(j)) then
+                     write(*,*) 'error in ncagt SHORT'
+                  end if
+               else if (attype .eq. NCLONG) then
+                  call ncagt (ncid, i, attnam, lngval, 
+     +                 iret)
+                  if (iret .ne. 0) nfails = nfails + 1
+                  if (attnam .ne. attname(j,i)) 
+     +               write(*,*) 'error in ncagt LONG name'
+                  if (lngval(j) .ne. lvalidrg(j)) 
+     +               write(*,*) 'error in ncagt LONG'
+               else if (attype .eq. NCFLOAT) then
+                  call ncagt (ncid, i, attnam, flval, 
+     +                 iret)            
+                  if (iret .ne. 0) nfails = nfails + 1
+                  if (attnam .ne. attname(j,i)) 
+     +               write(*,*) 'error in ncagt FLOAT name'
+                  if (flval(j) .ne. rvalidrg(j)) 
+     +               write(*,*) 'error in ncagt FLOAT'
+               else if (attype .eq. NCDOUBLE) then
+                  call ncagt (ncid, i, attnam, doubval,
+     +                 iret)          
+                  if (iret .ne. 0) nfails = nfails + 1
+                  if (attnam .ne. attname(j,i)) 
+     +               write(*,*) 'error in ncagt DOUBLE name'
+                  if ( abs(doubval(j) - dvalidrg(j)) .gt. epsilon)
+     + write(*,*) 'error in ncagt DOUBLE'
+               end if
+            end if
+ 25      continue
+ 20   continue
+      call ncclos(ncid, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      return
+      end
+!
+!     subroutine to test ncapt
+!
+      subroutine tncapt (ncid, nfails)
+      use netcdf_f03
+      integer ncid, iret
+
+! attribute vectors
+      NCSHORT_T svalidrg(2)
+      real rvalidrg(2)
+      integer lvalidrg(2)
+      doubleprecision dvalidrg(2)
+      NCBYTE_T bvalidrg(2)
+
+!     variable ids
+      integer  bid, sid, lid, fid, did, cid, chid
+      common /vars/bid, sid, lid, fid, did, cid, chid
+
+! assign attributes
+      
+!
+!     byte
+!
+      
+      bvalidrg(1) = -127
+      bvalidrg(2) =  127
+      call ncapt (ncid, bid, 'validrange', NCBYTE, 2,
+     +bvalidrg, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+!
+!     short
+!
+
+      svalidrg(1) = -100
+      svalidrg(2) = 100
+      call ncapt (ncid, sid, 'validrange', NCSHORT, 2, 
+     +svalidrg, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+!
+!     long
+!
+
+      lvalidrg(1) = 0
+      lvalidrg(2) = 360
+      call ncapt (ncid, lid, 'validrange', NCLONG, 2,
+     +lvalidrg, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      
+!
+!     float
+!
+
+      rvalidrg(1) = 0.0
+      rvalidrg(2) = 5000.0
+      call ncapt (ncid, fid, 'validrange', NCFLOAT, 2,
+     +rvalidrg, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+!
+!     double
+!
+
+      dvalidrg(1) = 0D0
+      dvalidrg(2) = 500D0
+      call ncapt (ncid, did, 'validrange', NCDOUBLE, 2,
+     +dvalidrg, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+!
+!     global
+!
+
+      call ncaptc (ncid, NCGLOBAL, 'source', NCCHAR, 3, 
+     +'NWS', iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      call ncaptc (ncid, NCGLOBAL, 'basetime', NCCHAR, 17, 
+     +'88/10/25 12:00:00', iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+!
+!     char
+!
+
+      call ncaptc (ncid, chid, 'longname', NCCHAR, 11,
+     +'test string', iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+      call ncaptc (ncid, chid, 'id', NCCHAR, 1,
+     +'a', iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+      return
+      end
+
+!
+!     initialize variables in labelled common blocks
+!
+      block data
+      common /cdims/ dimnam
+      common /dims/timedim, latdim, londim, leveldim, lendim,
+     + dimsiz
+      common /varn/varnam
+      common /atts/attname, gattnam
+      integer  latdim, londim, leveldim, timedim, lendim
+
+!     should include 'netcdf.inc' for MAXNCDIM, but it has EXTERNAL
+!     declaration, which is not permitted in a BLOCK DATA unit.
+
+      integer dimsiz(1024)
+      character*31 dimnam(1024)
+      character*31 varnam(7)
+      character*31 attname(2,7)
+      character*31 gattnam(2)
+
+      data dimnam /'time', 'lat', 'lon', 'level',
+     + 'length', 1019*'0'/
+      data dimsiz /4, 5, 5, 4, 80, 1019*0/
+      data varnam/'bytev', 'shortv', 'longv', 'floatv', 'doublev', 
+     + 'chv', 'cv'/
+      
+      data attname/'validrange', '0', 'validrange', '0', 'validrange',
+     + '0', 'validrange', '0', 'validrange', '0', 'longname', 'id',
+     + '0', '0'/
+      data gattnam/'source','basetime'/
+      end
+
+
+!
+!     subroutine to test ncddef
+!
+
+      subroutine tncddef(ncid, nfails)
+      use netcdf_f03
+      integer ncid
+
+!     sizes of dimensions of 'test.nc' and 'copy.nc'
+      integer  ndims
+      parameter(ndims=5)
+! dimension ids
+      integer  latdim, londim, leveldim, timedim, lendim
+      integer iret
+!     function to define a netCDF dimension
+      integer dimsiz(MAXNCDIM)
+      character*31 dimnam(MAXNCDIM)
+      
+      common /dims/timedim, latdim, londim, leveldim, lendim,
+     + dimsiz
+      common /cdims/ dimnam
+
+! define dimensions
+      timedim = ncddef(ncid, dimnam(1), NCUNLIM, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      latdim = ncddef(ncid, dimnam(2), dimsiz(2), iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      londim = ncddef(ncid, dimnam(3), dimsiz(3), iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      leveldim = ncddef(ncid, dimnam(4), dimsiz(4), iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      lendim = ncddef(ncid, dimnam(5), dimsiz(5), iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      return
+      end
+!
+!     subroutine to test ncinq, ncdinq, ncdid, ncvinq, ncanam
+!     and ncainq
+!
+      subroutine tncinq(cdfname, nfails)
+      use netcdf_f03
+      character*31 cdfname
+
+!     netCDF id
+      integer ncid
+!     returned number of dimensions
+      integer ndims
+!     returned number of variables
+      integer nvars
+!     returned number of global attributes
+      integer natts
+!     returned id of the unlimited dimension
+      integer recdim
+!     returned error code
+      integer iret
+!     returned name of record dimension
+      character*31 recnam
+!     returned size of record dimension
+      integer recsiz
+!     loop control variables
+      integer i, j, k
+!     returned size of dimension
+      integer dsize
+!     returned dimension ID
+      integer dimid
+!     returned dimension name
+      character*31 dname
+!     returned variable name
+      character*31 vname
+!     returned attribute name
+      character*31 attnam
+!     returned netCDF datatype of variable
+      integer vartyp
+!     returned number of variable dimensions
+      integer nvdims
+!     returned number of variable attributes
+      integer nvatts
+!     returned vector of nvdims dimension IDS corresponding to the
+!     variable dimensions
+      integer vdims(MAXNCDIM)
+!     returned attribute length
+      integer attlen
+!     returned attribute type
+      integer attype
+      character*31 dimnam(MAXNCDIM)
+      character*31 varnam(7)
+      character*31 attname(2,7)
+      character*31 gattnam(2)
+      integer vdlist(5,7), vtyp(7), vndims(7), vnatts(7)
+      integer attyp(2,7),atlen(2,7),gattyp(2),gatlen(2)
+      integer timedim,latdim,londim,leveldim,lendim
+      integer dimsiz(MAXNCDIM)
+      common /dims/timedim, latdim, londim, leveldim, lendim,
+     + dimsiz
+      common /varn/varnam
+      common /atts/attname, gattnam
+      common /cdims/ dimnam
+
+      data vdlist/1,0,0,0,0,1,0,0,0,0,2,0,0,0,0,4,3,2,1,0,4,3,2,1,0,
+     + 5,1,0,0,0,1,0,0,0,0/
+      data vtyp/NCBYTE, NCSHORT, NCLONG, NCFLOAT, NCDOUBLE, NCCHAR,
+     + NCCHAR/
+      data vndims/1,1,1,4,4,2,1/
+      data vnatts/1,1,1,1,1,2,0/
+      data attyp/NCBYTE, 0, NCSHORT, 0, NCLONG, 0, NCFLOAT, 0,
+     + NCDOUBLE, 0, NCCHAR, NCCHAR, 0, 0/
+      data atlen/2,0,2,0,2,0,2,0,2,0,11,1, 0, 0/
+      data gattyp/NCCHAR,NCCHAR/
+      data gatlen/3,17/
+
+      ncid = ncopn (cdfname, NCNOWRIT, iret)
+      call ncinq (ncid, ndims, nvars, natts, recdim, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      if (ndims .ne. 5) write(*,*) 'error in ncinq or ncddef'
+      if (nvars .ne. 7) write(*,*) 'error in ncinq or ncvdef'
+      if (natts .ne. 2) write(*,*) 'error in ncinq or ncapt'
+      call ncdinq (ncid, recdim, recnam, recsiz, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      if (recnam .ne. 'time') write(*,*) 'error: bad recdim from ncinq'
+!
+!     dimensions
+!
+      do 10 i = 1, ndims
+         call ncdinq (ncid, i, dname, dsize, iret)
+         if (iret .ne. 0) nfails = nfails + 1
+         if (dname .ne. dimnam(i)) 
+     +      write(*,*) 'error in ncdinq or ncddef, dname=', dname
+         if (dsize .ne. dimsiz(i)) 
+     +      write(*,*) 'error in ncdinq or ncddef, dsize=',dsize
+         dimid = ncdid (ncid, dname, iret)
+         if (dimid .ne. i) write(*,*)
+     +      'error in ncdinq or ncddef, dimid=', dimid
+ 10   continue
+!
+!     variables
+!
+      do 30 i = 1, nvars
+         call ncvinq (ncid, i, vname, vartyp, nvdims,
+     +        vdims, nvatts, iret)
+         if (iret .ne. 0) nfails = nfails + 1
+         if (vname .ne. varnam(i)) 
+     +      write(*,*) 'error: from ncvinq, wrong name returned: ', 
+     +         vname, ' .ne. ', varnam(i)
+         if (vartyp .ne. vtyp(i)) 
+     +      write(*,*) 'error: from ncvinq, wrong type returned: ', 
+     +         vartyp, ' .ne. ', vtyp(i)
+         if (nvdims .ne. vndims(i)) 
+     +      write(*,*) 'error: from ncvinq, wrong num dims returned: ', 
+     +         vdims, ' .ne. ', vndims(i)
+         do 35 j = 1, nvdims
+            if (vdims(j) .ne. vdlist(j,i)) 
+     +         write(*,*) 'error: from ncvinq wrong dimids: ',
+     +            vdims(j), ' .ne. ', vdlist(j,i)
+ 35      continue
+         if (nvatts .ne. vnatts(i)) 
+     +      write(*,*) 'error in ncvinq or ncvdef'
+!
+!     attributes
+!
+         do 45 k = 1, nvatts
+            call ncanam (ncid, i, k, attnam, iret)
+            if (iret .ne. 0) nfails = nfails + 1
+            call ncainq (ncid, i, attnam, attype, attlen, iret)
+            if (iret .ne. 0) nfails = nfails + 1
+            if (attnam .ne. attname(k,i)) 
+     +         write(*,*) 'error in ncanam or ncapt'
+            if (attype .ne. attyp(k,i)) 
+     +         write(*,*) 'error in ncainq or ncapt'
+            if (attlen .ne. atlen(k,i)) 
+     +         write(*,*) 'error in ncainq or ncapt'
+ 45      continue
+ 30   continue
+      do 40 i = 1, natts
+         call ncanam (ncid, NCGLOBAL, i, attnam, iret)
+         if (iret .ne. 0) nfails = nfails + 1
+         call ncainq (ncid, NCGLOBAL, attnam, attype, attlen, iret)
+         if (iret .ne. 0) nfails = nfails + 1
+         if (attnam .ne. gattnam(i)) 
+     +      write(*,*) 'error in ncanam or ncapt'
+         if (attype .ne. gattyp(i)) 
+     +      write(*,*) 'error in ncainq or ncapt'
+         if (attlen .ne. gatlen(i)) 
+     +      write(*,*) 'error in ncainq or ncapt'
+ 40   continue
+      call ncclos(ncid, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      return
+      end
+      
+      
+      
+!     subroutine to test ncredf, ncdren, ncvren, ncaren, and 
+!     ncendf
+
+      subroutine tncredf(cdfname, nfails)
+      use netcdf_f03
+      character*31 cdfname
+      character*31 attname(2,7)
+      character*31 gattnam(2)
+      common /atts/attname, gattnam
+      common /cdims/ dimnam
+      character*31 dimnam(MAXNCDIM)
+      character*31 varnam(7)
+      common /varn/varnam
+      integer ncid, iret, latid, varid
+
+      dimnam(2) = 'latitude'
+      varnam(4) = 'realv'
+      attname(1,6) = 'stringname'
+      gattnam(1) = 'agency'
+      ncid = ncopn(cdfname, NCWRITE, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      call ncredf(ncid, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      latid = ncdid(ncid, 'lat', iret)
+      call ncdren(ncid, latid, 'latitude', iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      varid = ncvid(ncid, 'floatv', iret)
+      call ncvren(ncid, varid, 'realv', iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      varid = ncvid(ncid, 'chv', iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      call ncaren(ncid, varid, 'longname', 'stringname', iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      call ncaren(ncid, NCGLOBAL, 'source', 'agency', iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      call ncendf(ncid, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      call ncclos(ncid, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      return
+      end
+!     
+!     subroutine to test ncvdef
+!
+
+      subroutine tncvdef(ncid, nfails)
+      use netcdf_f03
+      integer ncid
+
+!     function to define a netCDF variable
+      integer dimsiz(MAXNCDIM)
+      integer  latdim, londim, leveldim, timedim, lendim
+      common /dims/timedim, latdim, londim, leveldim, lendim, 
+     + dimsiz
+
+! variable ids
+      integer  bid, sid, lid, fid, did, cid, chid
+      common /vars/bid, sid, lid, fid, did, cid, chid
+
+! variable shapes
+      integer  bdims(1), fdims(4), ddims(4), ldims(1), sdims(1) 
+      integer chdims(2), cdims(1)
+
+      integer iret
+!
+! define variables
+!
+!     byte
+! 
+      bdims(1) = timedim
+      bid = ncvdef(ncid, 'bytev', NCBYTE, 1, bdims, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+!
+!     short
+!
+      sdims(1) = timedim
+      sid = ncvdef (ncid, 'shortv', NCSHORT, 1, sdims, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+!
+!     long
+!
+      ldims(1) = latdim
+      lid = ncvdef (ncid, 'longv', NCLONG, 1, ldims, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+!
+!     float
+!
+      fdims(4) = timedim
+      fdims(1) = leveldim
+      fdims(2) = londim
+      fdims(3) = latdim
+      fid = ncvdef (ncid, 'floatv', NCFLOAT, 4, fdims, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+!
+!     double
+!
+      ddims(4) = timedim
+      ddims(1) = leveldim
+      ddims(2) = londim
+      ddims(3) = latdim
+      did = ncvdef (ncid, 'doublev', NCDOUBLE, 4, ddims, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+!
+!     char
+!
+      chdims(2) = timedim
+      chdims(1) = lendim
+      chid = ncvdef (ncid, 'chv', NCCHAR, 2, chdims, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+      cdims(1) = timedim
+      cid = ncvdef (ncid, 'cv', NCCHAR, 1, cdims, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+
+      return
+      end
+
+
+!    
+!     subroutine to test ncvgt and ncvgtc
+!
+      subroutine tncvgt(cdfname, nfails)
+      use netcdf_f03
+      character*31 cdfname
+
+      integer ndims, times, lats, lons, levels, lenstr
+      parameter (times=4, lats=5, lons=5, levels=4)
+
+      integer start(4), count(4)
+      integer ncid, iret, i, m
+      integer  latdim, londim, leveldim, timedim, lendim
+      integer dimsiz(MAXNCDIM)
+      common /dims/timedim, latdim, londim, leveldim, lendim,
+     + dimsiz
+
+      integer bid, sid, lid, fid, did, cid, chid
+      common /vars/bid, sid, lid, fid, did, cid, chid
+      integer itime, ilev, ilat, ilon
+
+!     arrays of data values to be read
+      NCBYTE_T barray(times), byval(times)
+      NCSHORT_T sarray(times), shval(times)
+      integer larray(lats)
+      real farray(levels, lats, lons, times)
+      doubleprecision darray(levels, lats, lons, times)
+!     character array of data values to be read
+      character*31 string
+      character*31 varnam
+      integer nvars, natts, recdim
+      integer vartyp, nvdims, vdims(MAXVDIMS), nvatts
+
+      data start/1,1,1,1/
+      data count/levels, lats, lons, times/
+      data byval /97, 98, 99, 100/
+      data shval /10, 11, 12, 13/
+
+      ncid = ncopn (cdfname, NCWRITE, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+!     get number of variables in netCDF
+      call ncinq (ncid, ndims, nvars, natts, recdim, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      do 5 m = 1, nvars-1
+!     get variable name, datatype, number of dimensions
+!     vector of dimension ids, and number of variable attributes
+         call ncvinq (ncid, m, varnam, vartyp, nvdims, vdims,
+     +                nvatts, iret)
+         if (iret .ne. 0) nfails = nfails + 1
+         if (vartyp .eq. NCBYTE) then
+!
+!     byte
+!
+            count(1) = times
+            call ncvgt (ncid, m, start, count, barray, iret)
+            if (iret .ne. 0) nfails = nfails + 1
+            do 10 i = 1, times
+               if (barray(i) .ne. byval(i)) then 
+                  write(*,*) 'ncvgt of bytes, got ', barray(i), ' .ne. '
+     +                       , byval(i)
+               end if
+ 10         continue
+         else if (vartyp .eq. NCSHORT) then
+!
+!     short
+!
+            count(1) = times
+            call ncvgt (ncid, m, start, count, sarray, iret)
+            if (iret .ne. 0) nfails = nfails + 1
+            do 20 i = 1, times
+               if (sarray(i) .ne. shval(i)) then 
+                  write(*,*) 'ncvgt of short, got ', sarray(i), ' .ne. '
+     +                       , shval(i)
+               end if
+ 20         continue
+         else if (vartyp .eq. NCLONG) then
+!     
+!     long
+!
+            count(1) = lats
+            call ncvgt (ncid, m, start, count, larray, iret)
+            if (iret .ne. 0) nfails = nfails + 1
+            do 30 i = 1, lats
+               if (larray(i) .ne. 1000) then 
+                  write(*,*) 'long error in ncvgt'
+               end if
+ 30         continue
+         else if (vartyp .eq. NCFLOAT) then
+!     
+!     float
+!
+            count(1) = levels
+            call ncvgt (ncid, m, start, count, farray, iret)
+            if (iret .ne. 0) nfails = nfails + 1
+            i = 0
+            do 40 itime = 1,times
+               do 41 ilon = 1, lons
+                  do 42 ilat = 1, lats
+                     do 43 ilev = 1, levels
+                        i = i + 1
+                        if (farray(ilev, ilat, ilon, itime) .ne.
+     + real(i)) then
+                           write (*,*) 'float error in ncvgt'
+                        end if
+ 43         continue
+ 42         continue
+ 41         continue
+ 40         continue
+         else if (vartyp .eq. NCDOUBLE) then
+!
+!     double
+!
+            count(1) = levels
+            call ncvgt (ncid, m, start, count, darray, iret)
+            if (iret .ne. 0) nfails = nfails + 1
+            i = 0
+            do 50 itime = 1, times
+               do 51 ilon = 1, lons
+                  do 52 ilat = 1, lats
+                     do 53 ilev = 1, levels
+                        i = i + 1
+                        if (darray(ilev, ilat, ilon, itime) .ne.
+     +                       real (i)) then
+                           write(*,*) 'double error in ncvgt:', i,
+     +              darray(ilev, ilat, ilon, itime), '.ne.', 
+     +              real (i)
+                        end if
+ 53         continue
+ 52         continue
+ 51         continue
+ 50         continue
+         else 
+!     
+!     char
+!
+            count(1) = 3
+            count(2) = 4
+            lenstr = 31
+            call ncvgtc (ncid, m, start, count, string, lenstr, iret)
+            if (iret .ne. 0) nfails = nfails + 1
+            if (string .ne. 'testhikin of') then 
+               write(*,*) 'error in ncvgt, returned string =', string
+            end if
+         end if
+ 5    continue
+      call ncclos(ncid, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      return
+      end
+
+      
+      subroutine tncvgt1(cdfname, nfails)
+      use netcdf_f03
+      character*31 cdfname
+
+      integer ncid, iret
+      integer  latdim, londim, leveldim, timedim, lendim
+      integer dimsiz(MAXNCDIM)
+      common /dims/timedim, latdim, londim, leveldim, lendim,
+     + dimsiz
+
+      integer bindx(1), sindx(1), lindx(1), findx(4), dindx(4), cindx(1)
+
+      integer bid, sid, lid, fid, did, cid, chid
+      common /vars/bid, sid, lid, fid, did, cid, chid
+
+      NCBYTE_T bvalue
+      NCSHORT_T svalue
+      integer lvalue
+      real fvalue
+      doubleprecision dvalue
+      character*1 c
+      real epsilon
+      doubleprecision onethird
+
+      data epsilon /.000001/
+      data lindx/1/, bindx/1/, sindx/1/, findx/1,1,1,1/
+     +dindx/1,1,1,1/, cindx/1/
+      data onethird/0.3333333333D0/
+      
+      ncid = ncopn (cdfname, NCNOWRIT, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+!
+!     test ncvgt1 for byte
+!
+      call ncvgt1 (ncid, bid, bindx, bvalue, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      if (bvalue .ne. ichar('z')) write(*,*) 'error in ncvgt1 byte:',
+     + bvalue, ' .ne.', ichar('z')
+!
+!     test ncvgt1 for short
+!
+      call ncvgt1 (ncid, sid, sindx, svalue, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      if (svalue .ne. 10) write(*,*) 'error in ncvgt1 short:',
+     + svalue, ' .ne.', 10
+!     
+!     test ncvgt1 for long
+!
+      call ncvgt1 (ncid, lid, lindx, lvalue, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      if (lvalue .ne. 1000) write(*,*) 'error in ncvgt1 long:',
+     + lvalue,  ' .ne.', 1000
+!
+!     test ncvgt1 for float
+!
+      call ncvgt1 (ncid, fid, findx, fvalue, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      if (abs(fvalue - 3.14159) .gt. epsilon) 
+     +   write(*,*) 'error in ncvgt 1 float:', fvalue, 
+     +      ' not close to', 3.14159
+!
+!     test ncvgt1 for double
+!
+      call ncvgt1 (ncid, did, dindx, dvalue, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      if (abs(dvalue - onethird) .gt. epsilon) write(*,*)
+     + 'error in ncvgt1 double:', dvalue, ' not close to',
+     +     onethird
+!
+!     test ncvg1c for char
+!
+      call ncvg1c (ncid, cid, cindx, c, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      if (c .ne. 'a') write(*,*) 'error in ncvg1c'
+      call ncclos(ncid, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+      return
+      end
+
+      
+      
+!
+!     subroutine to test ncvpt and ncvptc
+!
+      subroutine tncvpt(cdfname, nfails)
+      use netcdf_f03
+      character*31 cdfname
+
+!     size of dimensions
+      integer times, lats, lons, levels
+      parameter (times=4, lats=5, lons=5, levels=4)
+
+      integer ncid, iret
+!     loop control variables
+      integer itime, ilev, ilon, ilat, i
+      integer  latdim, londim, leveldim, timedim, lendim
+      integer dimsiz(MAXNCDIM)
+      common /dims/timedim, latdim, londim, leveldim, lendim,
+     + dimsiz
+      integer lenstr
+      integer bid, sid, lid, fid, did, cid, chid
+      common /vars/bid, sid, lid, fid, did, cid, chid
+
+!     vector of integers specifying the corner of the  hypercube
+!     where the first of the data values will be written
+      integer start(4)
+!     vector of integers specifying the edge lengths from the
+!     corner of the hypercube where the first of the data values
+!     will be written
+      integer count(4)
+
+!     arrays of data values to be written
+      NCBYTE_T barray(times)
+      NCSHORT_T sarray(times)
+      integer larray(lats)
+      real farray(levels, lats, lons, times)
+      doubleprecision darray(levels, lats, lons, times)
+      character*31 string
+
+      data start/1,1,1,1/
+      data count/levels, lats, lons, times/
+      data barray /97, 98, 99, 100/
+      data sarray /10, 11, 12, 13/
+
+      ncid = ncopn (cdfname, NCWRITE, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+!
+!     byte
+!
+      count(1) = times
+      call ncvpt (ncid, bid, start, count, barray, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+!
+!     short
+!
+      count(1) = times
+      call ncvpt (ncid, sid, start, count, sarray, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+!
+!     long
+!
+      do 30 i = 1,lats
+         larray(i) = 1000
+ 30   continue
+      count(1) = lats
+      call ncvpt (ncid, lid, start, count, larray, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+!
+!     float
+!
+      i = 0
+      do 40 itime = 1,times
+         do 41 ilon = 1, lons
+            do 42 ilat = 1, lats
+               do 43 ilev = 1, levels
+                  i = i + 1
+                  farray(ilev, ilat, ilon, itime) = real (i)
+ 43   continue
+ 42   continue
+ 41   continue
+ 40   continue
+      count(1) = levels
+      call ncvpt (ncid, fid, start, count, farray, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+!
+!     double
+!
+      i = 0
+      do 50 itime = 1, times
+         do 51 ilon = 1, lons
+            do 52 ilat = 1, lats
+               do 53 ilev = 1, levels
+                  i = i + 1
+                  darray(ilev, ilat, ilon, itime) = real (i)
+ 53   continue
+ 52   continue
+ 51   continue
+ 50   continue
+      count(1) = levels
+      call ncvpt (ncid, did, start, count, darray, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+!
+!     char
+!
+      start(1) = 1
+      start(2) = 1
+      count(1) = 4
+      count(2) = 4
+      lenstr = 31       
+      string = 'testthiskind of '
+      call ncvptc (ncid, chid,start, count, string, lenstr, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+      call ncclos(ncid, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+      return
+      end
+
+
+      subroutine tncvpt1(cdfname, nfails)
+      use netcdf_f03
+      character*31 cdfname
+
+
+      integer iret, ncid
+      integer  latdim, londim, leveldim, timedim, lendim
+      integer dimsiz(MAXNCDIM)
+      common /dims/timedim, latdim, londim, leveldim, lendim, 
+     + dimsiz
+
+      integer bindx(1), sindx(1), lindx(1), findx(4), dindx(4), cindx(1)
+
+      integer lvalue
+      NCSHORT_T svalue
+      NCBYTE_T bvalue
+      doubleprecision onethird
+      integer bid, sid, lid, fid, did, cid, chid
+      common /vars/bid, sid, lid, fid, did, cid, chid
+      data lindx/1/, bindx/1/, sindx/1/, findx/1,1,1,1/
+     +dindx/1,1,1,1/, cindx/1/
+      data lvalue /1000/
+      data svalue/10/
+      data onethird/0.3333333333D0/
+
+      bvalue = ichar('z')
+      
+      ncid = ncopn (cdfname, NCWRITE, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+!
+!     test ncvpt1 for byte
+!
+      call ncvpt1 (ncid, bid, bindx, bvalue, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+!
+!     test ncvpt1 for short
+!
+      call ncvpt1 (ncid, sid, sindx, svalue, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+!     
+!     test ncvpt1 for long
+!
+      call ncvpt1 (ncid, lid, lindx, lvalue, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+!
+!     test ncvpt1 for float
+!
+      call ncvpt1 (ncid, fid, findx, 3.14159, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+!
+!     test ncvpt1 for double
+!
+      call ncvpt1 (ncid, did, dindx, onethird, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+!
+!     test ncvp1c for char
+!
+      call ncvp1c (ncid, cid, cindx, 'a', iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+      call ncclos (ncid, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+      return
+      end
+
+!
+! subroutine to test default fill values
+!
+      subroutine tfills(nfails)
+      use netcdf_f03
+      integer ncid
+      integer bid, sid, lid, fid, did
+      integer ix(1)
+      integer l
+      NCSHORT_T s
+      doubleprecision d
+      real f
+      NCBYTE_T b
+
+      ncid = NCOPN('fills.nc', NCNOWRIT, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+      bid = ncvid(ncid, 'b', iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+      sid = ncvid(ncid, 's', iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+      lid = ncvid(ncid, 'l', iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+      fid = ncvid(ncid, 'f', iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+      did = ncvid(ncid, 'd', iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+
+      ix(1) = 2
+      call ncvgt1(ncid, bid, ix, b, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+      call ncvgt1(ncid, sid, ix, s, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+      call ncvgt1(ncid, lid, ix, l, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+      call ncvgt1(ncid, fid, ix, f, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+      call ncvgt1(ncid, did, ix, d, iret)
+      if (iret .ne. 0) nfails = nfails + 1
+
+
+      if (b .ne. FILBYTE) write(*,*) 'error in byte fill value'
+      if (d .ne. FILDOUB) write(*,*) 'error in double fill value'
+      if (f .ne. FILFLOAT) write(*,*) 'error in float fill value'
+      if (l .ne. FILLONG) write(*,*) 'error in long fill value'
+      if (s .ne. FILSHORT) write(*,*) 'error in short fill value'
+
+      return
+      end
diff --git a/nf_test/f03tst_groups.F b/nf_test/f03tst_groups.F
new file mode 100755
index 0000000..f522e8b
--- /dev/null
+++ b/nf_test/f03tst_groups.F
@@ -0,0 +1,152 @@
+C     This is part of the netCDF package.
+C     Copyright 2006 University Corporation for Atmospheric Research/Unidata.
+C     See COPYRIGHT file for conditions of use.
+
+C     This program tests netCDF-4 variable functions from fortran.
+
+C     $Id: ftst_groups.F,v 1.5 2009/01/25 14:33:44 ed Exp $
+
+      program ftst_groups
+      USE netcdf4_f03
+      implicit none
+
+C     This is the name of the data file we will create.
+      character*(*) file_name
+      parameter (file_name='ftst_groups.nc')
+
+C     Info about the groups we'll create.
+      character*(*) group_name, sub_group_name
+      parameter (group_name = 'grp', sub_group_name = 'sub')
+      character*80 name_in, name_in2
+      integer ngroups_in
+      integer full_name_len
+
+C     Dimensions and variables.
+      character*(*) dim1_name, dim2_name
+      parameter (dim1_name = 'd1', dim2_name = 'd2')
+      character*(*) var1_name, var2_name
+      parameter (var1_name = 'v1', var2_name = 'v2')
+      integer nvars, ndims
+
+C     NetCDF IDs.
+      integer ncid, grpid, sub_grpid, subgrp_in
+      integer grpids(1), grpid_in, dimids(2), varids(2)
+      integer varids_in(2), dimids_in(2)
+
+C     Error handling.
+      integer retval
+
+      print *, ''
+      print *,'*** Testing netCDF-4 groups from F77.'
+
+C     Create the netCDF file.
+      retval = nf_create(file_name, NF_NETCDF4, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Create a group and a subgroup.
+      retval = nf_def_grp(ncid, group_name, grpid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_def_grp(grpid, sub_group_name, sub_grpid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Create a two dims and two vars.
+      retval = nf_def_dim(sub_grpid, dim1_name, 0, dimids(1))
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_def_dim(sub_grpid, dim2_name, 0, dimids(2))
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_def_var(sub_grpid, var1_name, NF_UINT64, 2, dimids, 
+     &     varids(1))
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_def_var(sub_grpid, var2_name, NF_UINT64, 2, dimids, 
+     &     varids(2))
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Close the file. 
+      retval = nf_close(ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Reopen the file.
+      retval = nf_open(file_name, NF_NOWRITE, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      
+C     Check the name of the root group.
+      retval = nf_inq_grpname(ncid, name_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:1) .ne. '/') stop 2
+
+C     Check the full name of the root group (also "/").
+      retval = nf_inq_grpname_full(ncid, full_name_len, name_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (full_name_len .ne. 1 .or. name_in(1:1) .ne. '/') stop 2
+
+C     What groups are there from the root group?
+      retval = nf_inq_grps(ncid, ngroups_in, grpids)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (ngroups_in .ne. 1) stop 2
+
+C     Check the name of this group.
+      retval = nf_inq_grpname(grpids(1), name_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:len(group_name)) .ne. group_name) stop 2
+
+C     Check the length of the full name.
+      retval = nf_inq_grpname_len(grpids(1), full_name_len)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (full_name_len .ne. len(group_name) + 1) stop 2
+
+C     Check the full name.
+      retval = nf_inq_grpname_full(grpids(1), full_name_len, name_in2)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in2(1:1) .ne. '/' .or. 
+     &     name_in2(2:len(group_name)+1) .ne. group_name .or.
+     &     full_name_len .ne. len(group_name) + 1) stop 2
+
+C     Check getting the grpid by full name
+      retval = nf_inq_grp_full_ncid(ncid, name_in, grpid_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (grpid_in .ne. grpids(1)) stop 2
+
+C     Check the parent ncid.
+      retval = nf_inq_grp_parent(grpids(1), grpid_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (grpid_in .ne. ncid) stop 2
+
+C     Check getting the group by name
+      retval = nf_inq_ncid(ncid, group_name, grpid_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (grpid_in .ne. grpids(1)) stop 2
+
+C     Check getting the group by name
+      retval = nf_inq_ncid(ncid, group_name, grpid_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (grpid_in .ne. grpids(1)) stop 2
+
+C     Get the sub group id, using its name.
+      retval = nf_inq_ncid(grpid_in, sub_group_name, subgrp_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Check varids in subgroup.
+      retval = nf_inq_varids(subgrp_in, nvars, varids_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (nvars .ne. 2 .or. varids_in(1) .ne. varids(1) .or.
+     &     varids_in(2) .ne. varids(2)) stop 2
+
+C     Check dimids in subgroup.
+      retval = nf_inq_dimids(subgrp_in, ndims, dimids_in, 0)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (ndims .ne. 2 .or. dimids_in(1) .ne. dimids(1) .or.
+     &     dimids_in(2) .ne. dimids(2)) stop 2
+
+C     Check dimids including parents (will get same answers, since there
+C     are no dims in parent group.
+      retval = nf_inq_dimids(subgrp_in, ndims, dimids_in, 1)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (ndims .ne. 2 .or. dimids_in(1) .ne. dimids(1) .or.
+     &     dimids_in(2) .ne. dimids(2)) stop 2
+
+C     Close the file. 
+      retval = nf_close(ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+      print *,'*** SUCCESS!'
+      end
diff --git a/nf_test/f03tst_parallel.F b/nf_test/f03tst_parallel.F
new file mode 100755
index 0000000..0dbea53
--- /dev/null
+++ b/nf_test/f03tst_parallel.F
@@ -0,0 +1,135 @@
+!     This is part of the netCDF package.
+!     Copyright 2006 University Corporation for Atmospheric Research/Unidata.
+!     See COPYRIGHT file for conditions of use.
+
+!     This program tests netCDF-4 variable functions from fortran.
+
+!     $Id: ftst_parallel.F,v 1.3 2009/01/25 15:47:47 ed Exp $
+
+      program ftst_parallel
+      USE netcdf4_f03
+      implicit none
+      include 'mpif.h'
+      
+      character*(*) FILE_NAME
+      parameter (FILE_NAME = 'ftst_parallel.nc')
+
+      integer MAX_DIMS
+      parameter (MAX_DIMS = 2)
+      integer NX, NY
+      parameter (NX = 16)
+      parameter (NY = 16)
+      integer NUM_PROC
+      parameter (NUM_PROC = 4)
+      integer ncid, varid, dimids(MAX_DIMS)
+      integer x_dimid, y_dimid, contig
+      integer data_out(NY / 2, NX / 2), data_in(NY / 2, NX / 2)
+      integer mode_flag
+      integer nvars, ngatts, ndims, unlimdimid, file_format
+      integer x, y, retval
+      integer p, my_rank, ierr
+      integer start(MAX_DIMS), count(MAX_DIMS)
+
+      call MPI_Init(ierr)
+      call MPI_Comm_rank(MPI_COMM_WORLD, my_rank, ierr)
+      call MPI_Comm_size(MPI_COMM_WORLD, p, ierr)
+
+      if (my_rank .eq. 0) then
+         print *," "
+         print *, '*** Testing netCDF-4 parallel I/O from Fortran 77.'
+      endif
+
+!     There must be 4 procs for this test.
+      if (p .ne. 4) then
+         print *, 'This test program must be run on 4 processors.'
+         stop 2 
+      endif
+
+!     Create some pretend data.
+      do x = 1, NX / 2
+         do y = 1, NY / 2
+            data_out(y, x) = my_rank
+         end do
+      end do
+
+!     Create the netCDF file. 
+      mode_flag = IOR(nf_netcdf4, nf_classic_model) 
+      retval = nf_create_par(FILE_NAME, mode_flag, MPI_COMM_WORLD, 
+     $     MPI_INFO_NULL, ncid)
+      if (retval .ne. nf_noerr) stop 2
+
+!     Define the dimensions.
+      retval = nf_def_dim(ncid, "x", NX, x_dimid)
+      if (retval .ne. nf_noerr) stop 2
+      retval = nf_def_dim(ncid, "y", NY, y_dimid)
+      if (retval .ne. nf_noerr) stop 2
+      dimids(1) = y_dimid
+      dimids(2) = x_dimid
+
+!     Define the variable. 
+      retval = nf_def_var(ncid, "data", NF_INT, MAX_DIMS, dimids, varid)
+      if (retval .ne. nf_noerr) stop 2
+
+!     With classic model netCDF-4 file, enddef must be called.
+      retval = nf_enddef(ncid)
+      if (retval .ne. nf_noerr) stop 2
+
+!     Determine what part of the variable will be written for this
+!     processor. It's a checkerboard decomposition.
+      count(1) = NX / 2
+      count(2) = NY / 2
+      if (my_rank .eq. 0) then
+         start(1) = 1
+         start(2) = 1
+      else if (my_rank .eq. 1) then
+         start(1) = NX / 2 + 1
+         start(2) = 1
+      else if (my_rank .eq. 2) then
+         start(1) = 1
+         start(2) = NY / 2 + 1
+      else if (my_rank .eq. 3) then
+         start(1) = NX / 2 + 1
+         start(2) = NY / 2 + 1
+      endif
+
+!     Write this processor's data.
+      retval = nf_put_vara_int(ncid, varid, start, count, data_out)
+      if (retval .ne. nf_noerr) stop 2
+
+!     Close the file. 
+      retval = nf_close(ncid)
+      if (retval .ne. nf_noerr) stop 2
+
+!     Reopen the file.
+      retval = nf_open_par(FILE_NAME, nf_nowrite, MPI_COMM_WORLD, 
+     $     MPI_INFO_NULL, ncid)
+      if (retval .ne. nf_noerr) stop 2
+
+!     Set collective access on this variable. This will cause all
+!     reads/writes to happen together on every processor. Fairly
+!     pointless, in this contexct, but I want to at least call this
+!     function once in my testing.
+      retval = nf_var_par_access(ncid, varid, nf_collective)
+      if (retval .ne. nf_noerr) stop 2
+      
+!     Read this processor's data.
+      retval = nf_get_vara_int(ncid, varid, start, count, data_in)
+      if (retval .ne. nf_noerr) stop 2
+
+!     Check the data.
+      do x = 1, NX / 2
+         do y = 1, NY / 2
+            if (data_in(y, x) .ne. my_rank) stop 3
+         end do
+      end do
+
+!     Close the file. 
+      retval = nf_close(ncid)
+      if (retval .ne. nf_noerr) stop 2
+
+      call MPI_Finalize(ierr)
+
+      if (my_rank .eq. 0) print *,'*** SUCCESS!'
+
+      end program ftst_parallel
+
diff --git a/nf_test/f03tst_path.f90 b/nf_test/f03tst_path.f90
new file mode 100644
index 0000000..540f8ab
--- /dev/null
+++ b/nf_test/f03tst_path.f90
@@ -0,0 +1,87 @@
+program ftst_path
+
+! Tests new nf_inq_path function
+! Mimics tests in C tst_files5.c code
+
+  USE netcdf_f03
+
+  implicit NONE
+
+  character(len=*), parameter  :: FILE_NAME="f03tst_path.nc"
+
+  integer                      :: path_len, ncid
+  character(LEN=NF_MAX_NAME+1) :: path_in
+
+  path_in   = REPEAT(" ", LEN(path_in))
+  path_len  = 0
+
+  print *,''
+  print *,'*** Testing netcdf file functions.'
+  print *,'*** Checking the new inq_path function'
+
+! Test with classic mode nf90_create
+
+  call check(nf_create(FILE_NAME, nf_classic_model, ncid))
+  call check(nf_inq_path(ncid, path_len, path_in))
+
+  if ((path_len /= LEN(FILE_NAME)) .OR. (FILE_NAME /= TRIM(path_in)))  &
+    call check(-1)
+  call check(nf_close(ncid))
+
+  path_in=REPEAT(" ", LEN(path_in))
+  path_len=0
+
+! Test with classic mode nf_open
+
+  call check(nf_open(FILE_NAME, nf_classic_model, ncid))
+  call check(nf_inq_path(ncid, path_len, path_in))
+
+  if ((path_len /= LEN(FILE_NAME)) .OR. (FILE_NAME /= TRIM(path_in)))  &
+    call check(-1)
+  call check(nf_close(ncid))
+
+  path_in=REPEAT(" ", LEN(path_in))
+  path_len=0
+
+
+! Test with netcdf4 mode nf_create
+
+  call check(nf_create(FILE_NAME, nf_netcdf4, ncid))
+  call check(nf_inq_path(ncid, path_len, path_in))
+
+  if ((path_len /= LEN(FILE_NAME)) .OR. (FILE_NAME /= TRIM(path_in)))  &
+    call check(-1)
+  call check(nf_close(ncid))
+
+  path_in=REPEAT(" ", LEN(path_in))
+  path_len=0
+
+! Test with netcdf4 mode nf_open
+
+  call check(nf_open(FILE_NAME, nf_netcdf4, ncid))
+  call check(nf_inq_path(ncid, path_len, path_in))
+
+  if ((path_len /= LEN(FILE_NAME)) .OR. (FILE_NAME /= TRIM(path_in)))  &
+    call check(-1)
+  call check(nf_close(ncid))
+
+  path_in=REPEAT(" ", LEN(path_in))
+  path_len=0
+
+  Print *,'*** SUCCESS!'
+
+contains
+!     This subroutine handles errors by printing an error message and
+!     exiting with a non-zero status.
+  subroutine check(errcode)
+    use netcdf
+    implicit none
+    integer, intent(in) :: errcode
+
+    if(errcode /= nf_noerr) then
+       print *, 'Error: ', trim(nf_strerror(errcode))
+       stop 2
+    endif
+  end subroutine check
+
+end program ftst_path
diff --git a/nf_test/f03tst_types.F b/nf_test/f03tst_types.F
new file mode 100755
index 0000000..b584a47
--- /dev/null
+++ b/nf_test/f03tst_types.F
@@ -0,0 +1,178 @@
+C     This is part of the netCDF package.
+C     Copyright 2007 University Corporation for Atmospheric Research/Unidata.
+C     See COPYRIGHT file for conditions of use.
+
+C     This program tests netCDF-4 user defined types from fortran.
+
+C     $Id: ftst_types.F,v 1.6 2009/01/25 14:33:44 ed Exp $
+
+      program ftst_types
+      USE netcdf4_f03
+      implicit none
+
+C     This is the name of the data file we will create.
+      character*(*) FILE_NAME
+      parameter (FILE_NAME='ftst_types.nc')
+
+C     We are writing 2D data, a 6 x 12 grid. 
+      integer NDIMS
+      parameter (NDIMS=2)
+      integer NX, NY
+      parameter (NX = 6, NY = 12)
+
+C     NetCDF IDs.
+      integer ncid, varid, dimids(NDIMS)
+      integer wind_typeid
+      integer x_dimid, y_dimid
+      integer typeids(1)
+
+C     Info about the type we'll create.
+      integer size_in, base_type_in, nfields_in, class_in
+      character*80 name_in
+      character*(*) type_name, u_name, v_name
+      parameter (type_name = 'wind_t', u_name = 'U', v_name = 'V')
+      integer ntypes
+      integer WIND_T_SIZE
+      parameter (WIND_T_SIZE = 8)
+      integer offset_in, field_typeid_in, ndims_in, dim_sizes_in(1)
+
+C     This is the data array we will write, and a place to store it when
+C     we read it back in.
+      integer data_out(NY, NX), data_in(NY, NX)
+
+C     Loop indexes, and error handling.
+      integer x, y, retval
+
+C     Create some pretend data.
+      do x = 1, NX
+         do y = 1, NY
+            data_out(y, x) = (x - 1) * NY + (y - 1)
+         end do
+      end do
+
+      print *, ''
+      print *,'*** Testing netCDF-4 compound type from F77.'
+
+C     Create the netCDF file.
+      retval = nf_create(FILE_NAME, NF_NETCDF4, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define the dimensions.
+      retval = nf_def_dim(ncid, "x", NX, x_dimid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_def_dim(ncid, "y", NY, y_dimid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define a compound type.
+      retval = nf_def_compound(ncid, WIND_T_SIZE, type_name, 
+     &     wind_typeid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_insert_compound(ncid, wind_typeid, u_name, 0, NF_INT)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_insert_compound(ncid, wind_typeid, v_name, 4, NF_INT)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Check out my new type.
+      retval = nf_inq_typeids(ncid, ntypes, typeids)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (ntypes .ne. 1) stop 2
+      if (typeids(1) .ne. wind_typeid) stop 2
+
+C     Define the variable. 
+      dimids(2) = x_dimid
+      dimids(1) = y_dimid
+      retval = nf_def_var(ncid, "data", NF_INT, NDIMS, dimids, varid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Write the pretend data to the file.
+      retval = nf_put_var_int(ncid, varid, data_out)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Close the file. 
+      retval = nf_close(ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Reopen the file and check again.
+      retval = nf_open(FILE_NAME, NF_NOWRITE, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Find the type.
+      retval = nf_inq_typeids(ncid, ntypes, typeids)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (ntypes .ne. 1 .or. typeids(1) .ne. wind_typeid) stop 2
+      
+C     Check the type.
+      retval = nf_inq_user_type(ncid, typeids(1), name_in, size_in, 
+     &     base_type_in, nfields_in, class_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:len(type_name)) .ne. type_name .or. 
+     &     size_in .ne. WIND_T_SIZE .or. nfields_in .ne. 2 .or.
+     &     class_in .ne. NF_COMPOUND) stop 2
+
+C     Check it differently.
+      retval = nf_inq_compound(ncid, typeids(1), name_in, size_in, 
+     &     nfields_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:len(type_name)) .ne. type_name .or. 
+     &     size_in .ne. WIND_T_SIZE .or. nfields_in .ne. 2) stop 2
+
+C     Check it one piece at a time.
+      retval = nf_inq_compound_nfields(ncid, typeids(1), nfields_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (nfields_in .ne. 2) stop 2
+      retval = nf_inq_compound_size(ncid, typeids(1), size_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (size_in .ne. WIND_T_SIZE) stop 2
+      retval = nf_inq_compound_name(ncid, typeids(1), name_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:len(type_name)) .ne. type_name) stop 2
+
+C     Check the first field of the compound type.
+      retval = nf_inq_compound_field(ncid, typeids(1), 1, name_in, 
+     &     offset_in, field_typeid_in, ndims_in, dim_sizes_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:len(u_name)) .ne. u_name .or. offset_in .ne. 0 .or.
+     &     field_typeid_in .ne. NF_INT .or. ndims_in .ne. 0) stop 2
+      retval = nf_inq_compound_fieldname(ncid, typeids(1), 1, name_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:len(u_name)) .ne. u_name) stop 2
+      retval = nf_inq_compound_fieldoffset(ncid, typeids(1), 1, 
+     &     offset_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (offset_in .ne. 0) stop 2
+      retval = nf_inq_compound_fieldtype(ncid, typeids(1), 1, 
+     &     field_typeid_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (field_typeid_in .ne. NF_INT) stop 2
+      retval = nf_inq_compound_fieldndims(ncid, typeids(1), 1, 
+     &     ndims_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (ndims_in .ne. 0) stop 2
+      
+C     Check the second field of the compound type.
+      retval = nf_inq_compound_field(ncid, typeids(1), 2, name_in, 
+     &     offset_in, field_typeid_in, ndims_in, dim_sizes_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:len(v_name)) .ne. v_name .or. offset_in .ne. 4 .or.
+     &     field_typeid_in .ne. NF_INT .or. ndims_in .ne. 0) stop 2
+      
+C     Find our variable.
+      retval = nf_inq_varid(ncid, "data", varid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (varid .ne. 1) stop 2
+
+C     Read the data and check it.
+      retval = nf_get_var_int(ncid, varid, data_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      do x = 1, NX
+         do y = 1, NY
+            if (data_in(y, x) .ne. data_out(y, x)) stop 2
+         end do
+      end do
+
+C     Close the file. 
+      retval = nf_close(ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+      print *,'*** SUCCESS!'
+      end
diff --git a/nf_test/f03tst_types2.F b/nf_test/f03tst_types2.F
new file mode 100755
index 0000000..9be1ec7
--- /dev/null
+++ b/nf_test/f03tst_types2.F
@@ -0,0 +1,98 @@
+C     This is part of the netCDF package.
+C     Copyright 2007 University Corporation for Atmospheric Research/Unidata.
+C     See COPYRIGHT file for conditions of use.
+
+C     This program tests netCDF-4 user defined types from fortran.
+
+C     $Id: ftst_types2.F,v 1.5 2009/09/25 19:23:37 ed Exp $
+
+      program ftst_types2
+      USE netcdf4_f03
+      implicit none
+
+C     This is the name of the data file we will create.
+      character*(*) FILE_NAME
+      parameter (FILE_NAME='ftst_types2.nc')
+
+C     We are writing 2D data, a 3 x 2 grid. 
+      integer NDIMS
+      parameter (NDIMS = 2)
+      integer dim_sizes(NDIMS)
+      integer NX, NY
+      parameter (NX = 3, NY = 2)
+
+C     NetCDF IDs.
+      integer ncid, varid, dimids(NDIMS)
+      integer cmp_typeid
+      integer x_dimid, y_dimid
+      integer typeids(1)
+
+C     Info about the type we'll create.
+      integer size_in, base_type_in, nfields_in, class_in
+      character*80 name_in
+      character*(*) type_name, ary_name
+      parameter (type_name = 'cmp_w_ary', ary_name = 'A')
+      integer ntypes
+      integer cmp_size
+      parameter (cmp_size = 24)
+      integer offset_in, field_typeid_in, ndims_in, dim_sizes_in(NDIMS)
+
+C     Loop indexes, and error handling.
+      integer x, y, retval
+
+      print *, ''
+      print *,'*** Testing netCDF-4 compound types from F77 some more.'
+
+C     Create the netCDF file.
+      retval = nf_create(FILE_NAME, NF_NETCDF4, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define a compound type.
+      retval = nf_def_compound(ncid, cmp_size, type_name, 
+     &     cmp_typeid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Include an array.
+      dim_sizes(1) = NX
+      dim_sizes(2) = NY
+      retval = nf_insert_array_compound(ncid, cmp_typeid, ary_name, 0, 
+     &     NF_INT, NDIMS, dim_sizes)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Close the file. 
+      retval = nf_close(ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Reopen the file and check again.
+      retval = nf_open(FILE_NAME, NF_NOWRITE, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Find the type.
+      retval = nf_inq_typeids(ncid, ntypes, typeids)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (ntypes .ne. 1 .or. typeids(1) .ne. cmp_typeid) stop 2
+      
+C     Check the type.
+      retval = nf_inq_user_type(ncid, typeids(1), name_in, size_in, 
+     &     base_type_in, nfields_in, class_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:len(type_name)) .ne. type_name .or. 
+     &     size_in .ne. cmp_size .or. nfields_in .ne. 1 .or. 
+     &     class_in .ne. NF_COMPOUND) stop 2
+
+C     Check the first field of the compound type.
+      retval = nf_inq_compound_field(ncid, typeids(1), 1, name_in, 
+     &     offset_in, field_typeid_in, ndims_in, dim_sizes_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:len(ary_name)) .ne. ary_name .or. 
+     &     offset_in .ne. 0 .or. field_typeid_in .ne. NF_INT .or. 
+     &     ndims_in .ne. NDIMS .or. 
+     &     dim_sizes_in(1) .ne. dim_sizes(1) .or. 
+     &     dim_sizes_in(2) .ne. dim_sizes(2)) stop 2
+
+C     Close the file. 
+      retval = nf_close(ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+      print *,'*** SUCCESS!'
+      end
diff --git a/nf_test/f03tst_types3.F b/nf_test/f03tst_types3.F
new file mode 100755
index 0000000..871292b
--- /dev/null
+++ b/nf_test/f03tst_types3.F
@@ -0,0 +1,121 @@
+C     This is part of the netCDF package.
+C     Copyright 2007 University Corporation for Atmospheric Research/Unidata.
+C     See COPYRIGHT file for conditions of use.
+
+C     This program tests netCDF-4 user defined types from fortran.
+
+C     $Id: ftst_types3.F,v 1.2 2009/09/25 19:23:37 ed Exp $
+
+      program ftst_types3
+      USE netcdf4_f03
+      implicit none
+
+C     This is the name of the data file we will create.
+      character*(*) FILE_NAME
+      parameter (FILE_NAME='ftst_types3.nc')
+
+C     We are writing 2D data, a 3 x 2 grid. 
+      integer NDIMS
+      parameter (NDIMS = 2)
+      integer dim_sizes(NDIMS)
+      integer NX, NY
+      parameter (NX = 3, NY = 2)
+
+C     NetCDF IDs.
+      integer ncid, varid, dimids(NDIMS)
+      integer cmp_typeid, typeid_in
+      integer x_dimid, y_dimid
+      integer typeids(1)
+      integer grpid, sub_grpid
+
+C     Info about the groups we'll create.
+      character*(*) group_name, sub_group_name
+      parameter (group_name = 'you_drive_me_crazy')
+      parameter (sub_group_name = 'baby_Im_so_into_you')
+
+C     Info about the type we'll create.
+      integer size_in, base_type_in, nfields_in, class_in
+      character*80 name_in
+      character*(*) type_name, field_name
+      parameter (type_name = 'I_just_want_to_have_some_fun')
+      parameter (field_name = 'Ill_tell_it_to_the_world')
+      integer ntypes
+      integer cmp_size
+      parameter (cmp_size = 4)
+      integer offset_in, field_typeid_in, ndims_in, dim_sizes_in(NDIMS)
+
+C     Loop indexes, and error handling.
+      integer x, y, retval
+
+      print *, ''
+      print *,'*** Testing netCDF-4 user-defined types and groups.'
+
+C     Create the netCDF file.
+      retval = nf_create(FILE_NAME, NF_NETCDF4, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Create a group and a subgroup.
+      retval = nf_def_grp(ncid, group_name, grpid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_def_grp(grpid, sub_group_name, sub_grpid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define a compound type in the root group.
+      retval = nf_def_compound(ncid, cmp_size, type_name, 
+     &     cmp_typeid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Include a float.
+      retval = nf_insert_compound(ncid, cmp_typeid, field_name, 0, 
+     &     NF_FLOAT)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Close the file. 
+      retval = nf_close(ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Reopen the file and check again.
+      retval = nf_open(FILE_NAME, NF_NOWRITE, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Find the type.
+      retval = nf_inq_typeids(ncid, ntypes, typeids)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (ntypes .ne. 1 .or. typeids(1) .ne. cmp_typeid) stop 2
+      
+C     Check the type.
+      retval = nf_inq_user_type(ncid, typeids(1), name_in, size_in, 
+     &     base_type_in, nfields_in, class_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:len(type_name)) .ne. type_name .or. 
+     &     size_in .ne. cmp_size .or. nfields_in .ne. 1 .or. 
+     &     class_in .ne. NF_COMPOUND) stop 31
+
+C     Check the first field of the compound type.
+      retval = nf_inq_compound_field(ncid, typeids(1), 1, name_in, 
+     &     offset_in, field_typeid_in, ndims_in, dim_sizes_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:len(field_name)) .ne. field_name .or. 
+     &     offset_in .ne. 0 .or. field_typeid_in .ne. NF_FLOAT .or. 
+     &     ndims_in .ne. 0) stop 19
+
+C     Go to a child group and find the id of our type.
+      retval = nf_inq_grp_ncid(ncid, group_name, sub_grpid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_inq_typeid(sub_grpid, type_name, typeid_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_inq_user_type(sub_grpid, typeid_in, name_in, size_in, 
+     &     base_type_in, nfields_in, class_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (name_in(1:len(type_name)) .ne. type_name .or. 
+     &     size_in .ne. cmp_size .or. nfields_in .ne. 1 .or. 
+     &     class_in .ne. NF_COMPOUND) stop 22
+      
+
+
+C     Close the file. 
+      retval = nf_close(ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+      print *,'*** SUCCESS!'
+      end
diff --git a/nf_test/f03tst_v2.F b/nf_test/f03tst_v2.F
new file mode 100755
index 0000000..de35a02
--- /dev/null
+++ b/nf_test/f03tst_v2.F
@@ -0,0 +1,94 @@
+C     This is part of the netCDF package.
+C     Copyright 2009 University Corporation for Atmospheric Research/Unidata.
+C     See COPYRIGHT file for conditions of use.
+
+C     This program tests the fortran V2 API with netCDF-4.
+
+C     $Id: ftst_v2.F,v 1.1 2009/01/27 19:49:11 ed Exp $
+
+      program ftst_v2
+      use netcdf4_f03
+      implicit none
+
+C     This is the name of the data file we will create.
+      character*(*) FILE_NAME
+      parameter (FILE_NAME='ftst_v2.nc')
+
+      integer ncid, timedim, londim, latdim, lonid, latid
+      character*(3) lat_name
+      parameter (lat_name = 'lat')
+      character*(3) lon_name
+      parameter (lon_name = 'lon')
+      character*(4) time_name
+      parameter (time_name = 'time')
+      integer LON_LEN, LAT_LEN
+      parameter (LON_LEN = 3, LAT_LEN = 5)
+      integer NDIMS, NVARS
+      parameter (NDIMS = 3, NVARS = 2)
+      integer ndims_in, nvars_in, ngatts_in, recdim_in
+      integer dimsize_in, natts_in
+      integer xtype_in, dimids_in(NDIMS)
+      character*(128) name_in
+      integer rc
+
+      print *, ''
+      print *,'*** Testing v2 fortran API with netCDF-4.'
+
+C     Create the file.
+      ncid = nccre(FILE_NAME, NF_NETCDF4, rc)
+      timedim = ncddef(ncid, time_name, NCUNLIM, rc)
+      londim = ncddef(ncid, lon_name, LON_LEN, rc)
+      latdim = ncddef(ncid, lat_name, LAT_LEN, rc)
+      lonid = ncvdef(ncid, lon_name, NCFLOAT, 1, londim, rc)
+      latid = ncvdef(ncid, lat_name, NCFLOAT, 1, latdim, rc)
+
+C     Check the file.
+      call ncinq(ncid, ndims_in, nvars_in, ngatts_in, recdim_in, rc)
+      if (ndims_in .ne. NDIMS) stop 2
+      if (ndims_in .ne. NDIMS .or. nvars_in .ne. NVARS .or.
+     $     ngatts_in .ne. 0 .or. recdim_in .ne. timedim) stop 2
+      call ncdinq(ncid, timedim, name_in, dimsize_in, rc)
+      if (name_in .ne. time_name .or. dimsize_in .ne. 0) stop 2
+      call ncdinq(ncid, londim, name_in, dimsize_in, rc)
+      if (name_in .ne. lon_name .or. dimsize_in .ne. LON_LEN) stop 2
+      call ncdinq(ncid, latdim, name_in, dimsize_in, rc)
+      if (name_in .ne. lat_name .or. dimsize_in .ne. LAT_LEN) stop 2
+      call ncvinq(ncid, lonid, name_in, xtype_in, ndims_in, dimids_in, 
+     $     natts_in, rc)
+      if (name_in .ne. lon_name .or. xtype_in .ne. NCFLOAT .or.
+     $     ndims_in .ne. 1 .or. dimids_in(1) .ne. londim) stop 2
+      call ncvinq(ncid, latid, name_in, xtype_in, ndims_in, dimids_in, 
+     $     natts_in, rc)
+      if (name_in .ne. lat_name .or. xtype_in .ne. NCFLOAT .or.
+     $     ndims_in .ne. 1 .or. dimids_in(1) .ne. latdim) stop 2
+
+C     Close the file.
+      call ncclos(ncid, rc)
+
+C     Reopen, and check again.
+      ncid = ncopn(FILE_NAME, NCNOWRIT, rc)
+C     Check the file.
+      call ncinq(ncid, ndims_in, nvars_in, ngatts_in, recdim_in, rc)
+      if (ndims_in .ne. NDIMS) stop 2
+      if (ndims_in .ne. NDIMS .or. nvars_in .ne. NVARS .or.
+     $     ngatts_in .ne. 0 .or. recdim_in .ne. timedim) stop 2
+      call ncdinq(ncid, timedim, name_in, dimsize_in, rc)
+      if (name_in .ne. time_name .or. dimsize_in .ne. 0) stop 2
+      call ncdinq(ncid, londim, name_in, dimsize_in, rc)
+      if (name_in .ne. lon_name .or. dimsize_in .ne. LON_LEN) stop 2
+      call ncdinq(ncid, latdim, name_in, dimsize_in, rc)
+      if (name_in .ne. lat_name .or. dimsize_in .ne. LAT_LEN) stop 2
+      call ncvinq(ncid, lonid, name_in, xtype_in, ndims_in, dimids_in, 
+     $     natts_in, rc)
+      if (name_in .ne. lon_name .or. xtype_in .ne. NCFLOAT .or.
+     $     ndims_in .ne. 1 .or. dimids_in(1) .ne. londim) stop 2
+      call ncvinq(ncid, latid, name_in, xtype_in, ndims_in, dimids_in, 
+     $     natts_in, rc)
+      if (name_in .ne. lat_name .or. xtype_in .ne. NCFLOAT .or.
+     $     ndims_in .ne. 1 .or. dimids_in(1) .ne. latdim) stop 2
+
+      call ncclos(ncid, rc)
+
+      print *,'*** SUCCESS!'
+      end
+
diff --git a/nf_test/f03tst_vars.F b/nf_test/f03tst_vars.F
new file mode 100755
index 0000000..ff5bb46
--- /dev/null
+++ b/nf_test/f03tst_vars.F
@@ -0,0 +1,172 @@
+C     This is part of the netCDF package.
+C     Copyright 2006 University Corporation for Atmospheric Research/Unidata.
+C     See COPYRIGHT file for conditions of use.
+
+C     This program tests netCDF-4 variable functions from fortran.
+
+C     $Id: ftst_vars.F,v 1.19 2009/09/27 21:25:23 ed Exp $
+
+      program ftst_vars
+      USE netcdf4_f03
+      implicit none
+
+C     This is the name of the data file we will create.
+      character*(*) FILE_NAME
+      parameter (FILE_NAME='ftst_vars.nc')
+
+C     We are writing 2D data, a 6 x 12 grid. 
+      integer NDIMS
+      parameter (NDIMS=2)
+      integer NX, NY
+      parameter (NX = 6, NY = 12)
+
+C     NetCDF IDs.
+      integer ncid, varid, dimids(NDIMS)
+      integer x_dimid, y_dimid
+
+C     This is the data array we will write, and a place to store it when
+C     we read it back in.
+      integer data_out(NY, NX), data_in(NY, NX)
+
+C     For checking our data file to make sure it's correct.
+      integer chunks(NDIMS), chunks_in(NDIMS)
+      integer shuffle, deflate, deflate_level, checksum, contiguous
+      integer endianness
+
+C     Cache size stuff.
+      integer CACHE_SIZE, CACHE_NELEMS, CACHE_PREEMPTION
+      parameter (CACHE_SIZE = 8000, CACHE_NELEMS = 500)
+      parameter (CACHE_PREEMPTION = 50)
+      integer cache_size_in, cache_nelems_in, cache_preemption_in
+
+C     Loop indexes, and error handling.
+      integer x, y, retval
+
+C     Create some pretend data.
+      do x = 1, NX
+         do y = 1, NY
+            data_out(y, x) = 2147483646 + x * y
+         end do
+      end do
+
+      print *, ''
+      print *,'*** Testing definition of netCDF-4 vars from Fortran 77.'
+
+C     Change the cache size for the files created/opened in this program.
+      retval = nf_set_chunk_cache(CACHE_SIZE, CACHE_NELEMS, 
+     &     CACHE_PREEMPTION)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Check chunk cache sizes.
+      retval = nf_get_chunk_cache(cache_size_in, cache_nelems_in, 
+     &     cache_preemption_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (cache_size_in .ne. CACHE_SIZE .or. 
+     &     cache_nelems_in .ne. CACHE_NELEMS .or. 
+     &     cache_preemption_in .ne. CACHE_PREEMPTION) stop 4
+
+C     Create the netCDF file.
+      retval = nf_create(FILE_NAME, NF_NETCDF4, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define the dimensions.
+      retval = nf_def_dim(ncid, "x", NX, x_dimid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_def_dim(ncid, "y", NY, y_dimid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define the variable. 
+      dimids(1) = y_dimid
+      dimids(2) = x_dimid
+      retval = nf_def_var(ncid, "data", NF_INT64, NDIMS, dimids, varid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Turn on chunking.
+      chunks(1) = NY
+      chunks(2) = NX
+      retval = nf_def_var_chunking(ncid, varid, 0, chunks)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Set variable to big-endian (default is whatever is native to
+C     writing machine).
+      retval = nf_def_var_endian(ncid, varid, NF_ENDIAN_BIG)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Turn on deflate, fletcher32.
+      retval = nf_def_var_deflate(ncid, varid, 0, 1, 4)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_def_var_fletcher32(ncid, varid, NF_FLETCHER32)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Is everything set that is supposed to be?
+      retval = nf_inq_var_deflate(ncid, varid, shuffle, deflate, 
+     +     deflate_level)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (shuffle .ne. 0 .or. deflate .ne. 1 .or. 
+     +     deflate_level .ne. 4) stop 2
+      retval = nf_inq_var_fletcher32(ncid, varid, checksum)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (checksum .ne. NF_FLETCHER32) stop 2
+      retval = nf_inq_var_chunking(ncid, varid, contiguous, chunks_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (contiguous .ne. 0) stop 2
+      if (chunks(1) .ne. chunks_in(1) .or.
+     +     chunks(2) .ne. chunks_in(2)) stop 2
+      retval = nf_inq_var_endian(ncid, varid, endianness)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (endianness .ne. NF_ENDIAN_BIG) stop 2
+
+C     Since this is a classic model file, we must call enddef
+      retval = nf_enddef(ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Write the pretend data to the file.
+      retval = nf_put_var_int(ncid, varid, data_out)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Close the file. 
+      retval = nf_close(ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Reopen the file and check again.
+      retval = nf_open(FILE_NAME, NF_NOWRITE, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Find our variable.
+      retval = nf_inq_varid(ncid, "data", varid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (varid .ne. 1) stop 2
+
+C     Check the deflate, fletcher32, chunking, and endianness.
+      retval = nf_inq_var_deflate(ncid, varid, shuffle, deflate, 
+     +     deflate_level)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (shuffle .ne. 0 .or. deflate .ne. 1 .or. 
+     +     deflate_level .ne. 4) stop 2
+      retval = nf_inq_var_fletcher32(ncid, varid, checksum)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (checksum .ne. NF_FLETCHER32) stop 2
+      retval = nf_inq_var_chunking(ncid, varid, contiguous, chunks_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (contiguous .ne. 0) stop 2
+      if (chunks(1) .ne. chunks_in(1) .or.
+     +     chunks(2) .ne. chunks_in(2)) stop 2
+      retval = nf_inq_var_endian(ncid, varid, endianness)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (endianness .ne. NF_ENDIAN_BIG) stop 2
+
+C     Read the data and check it.
+      retval = nf_get_var_int(ncid, varid, data_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      do x = 1, NX
+         do y = 1, NY
+            if (data_in(y, x) .ne. data_out(y, x)) stop 2
+         end do
+      end do
+
+C     Close the file. 
+      retval = nf_close(ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+      print *,'*** SUCCESS!'
+      end
diff --git a/nf_test/f03tst_vars2.F b/nf_test/f03tst_vars2.F
new file mode 100755
index 0000000..f6bd9ba
--- /dev/null
+++ b/nf_test/f03tst_vars2.F
@@ -0,0 +1,137 @@
+C     This is part of the netCDF package.
+C     Copyright 2008 University Corporation for Atmospheric Research/Unidata.
+C     See COPYRIGHT file for conditions of use.
+
+C     This program tests netCDF-4 variable functions from fortran, even
+C     more.
+
+C     $Id: ftst_vars2.F,v 1.6 2010/01/20 15:21:46 ed Exp $
+
+      program ftst_vars2
+      USE netcdf4_f03
+      implicit none
+
+C     This is the name of the data file we will create.
+      character*(*) FILE_NAME
+      parameter (FILE_NAME='ftst_vars2.nc')
+
+C     We are writing 3D data, a 3 x 5 x 2 grid. Why do I use "x, y, z,"
+C     and then do everything in order "z, y, x?" Because I am a C
+C     programmer, and everything in Fortran seems backwards!
+      integer NDIMS, NTYPES
+      parameter (NDIMS = 3, NTYPES = 5)
+      integer NX, NY, NZ
+      parameter (NX = 3, NY = 5, NZ = 2)
+
+C     These will be used to set the per-variable chunk cache.
+      integer CACHE_SIZE, CACHE_NELEMS, CACHE_PREEMPTION
+      parameter (CACHE_SIZE = 8, CACHE_NELEMS = 571)
+      parameter (CACHE_PREEMPTION = 42)
+
+C     These will be used to check the setting of the per-variable chunk
+C     cache.
+      integer cache_size_in, cache_nelems_in, cache_preemption_in
+
+C     NetCDF IDs.
+      integer ncid, varid(NTYPES), dimids(NDIMS), typeid(NTYPES)
+
+C     Name of the variable is stored here.
+      character*80 var_name
+
+C     This is the data array we will write, and a place to store it when
+C     we read it back in. Z is the fastest varying dimension.
+      integer data_out(NZ, NY, NX), data_in(NZ, NY, NX)
+
+C     Loop indexes, and error handling.
+      integer i, x, y, z, retval
+
+C     Create some pretend data.
+      do x = 1, NX
+         do y = 1, NY
+            do z = 1, NZ
+               data_out(z, y, x) = (x-1) * NY * NZ + (y-1) * NZ + (z-1)
+            end do
+         end do
+      end do
+
+      print *, ''
+      print *,'*** Testing netCDF-4 vars from F77 with new types.'
+
+C     Create the netCDF file.
+      retval = nf_create(FILE_NAME, NF_NETCDF4, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Define the dimensions.
+      retval = nf_def_dim(ncid, "z", NZ, dimids(3))
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_def_dim(ncid, "y", NY, dimids(2))
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_def_dim(ncid, "x", NX, dimids(1))
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     These are the types of vars that will be written.
+      typeid(1) = NF_UBYTE
+      typeid(2) = NF_USHORT
+      typeid(3) = NF_UINT
+      typeid(4) = NF_INT64
+      typeid(5) = NF_UINT64
+
+C     Define the variables. 
+      do i = 1, NTYPES
+         write(var_name, 1001) i
+ 1001    format('var', I1)
+         retval = nf_def_var(ncid, var_name, typeid(i), NDIMS, 
+     &        dimids, varid(i))
+         if (retval .ne. nf_noerr) call handle_err(retval)
+
+C        Set variable caches.
+         retval = nf_set_var_chunk_cache(ncid, varid(i), CACHE_SIZE, 
+     &        CACHE_NELEMS, CACHE_PREEMPTION)
+         if (retval .ne. nf_noerr) call handle_err(retval)
+      end do
+
+C     Check the per-variable cache to make sure it is what we think it
+C     is.
+      do i = 1, NTYPES
+         retval = nf_get_var_chunk_cache(ncid, varid(i), cache_size_in, 
+     &        cache_nelems_in, cache_preemption_in)
+         if (retval .ne. nf_noerr) call handle_err(retval)
+         if (cache_size_in .ne. CACHE_SIZE .or. cache_nelems_in .ne. 
+     &        CACHE_NELEMS .or. cache_preemption .ne. CACHE_PREEMPTION)
+     &        stop 8
+         
+      end do
+
+C     Write the pretend data to the file.
+      do i = 1, NTYPES
+         retval = nf_put_var_int(ncid, varid(i), data_out)
+         if (retval .ne. nf_noerr) call handle_err(retval)
+      end do
+
+C     Close the file. 
+      retval = nf_close(ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Reopen the file and check again.
+      retval = nf_open(FILE_NAME, NF_NOWRITE, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Read the data and check it.
+      do i = 1, NTYPES
+         retval = nf_get_var_int(ncid, varid(i), data_in)
+         if (retval .ne. nf_noerr) call handle_err(retval)
+         do x = 1, NX
+            do y = 1, NY
+               do z = 1, NZ
+                  if (data_in(z, y, x) .ne. data_out(z, y, x)) stop 2
+               end do
+            end do
+         end do
+      end do
+
+C     Close the file. 
+      retval = nf_close(ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+      print *,'*** SUCCESS!'
+      end
diff --git a/nf_test/f03tst_vars3.F b/nf_test/f03tst_vars3.F
new file mode 100755
index 0000000..3bc98b7
--- /dev/null
+++ b/nf_test/f03tst_vars3.F
@@ -0,0 +1,189 @@
+C     This is part of the netCDF package.
+C     Copyright 2008 University Corporation for Atmospheric Research/Unidata.
+C     See COPYRIGHT file for conditions of use.
+
+C     This program tests netCDF-4 variable functions from fortran, even
+C     more, even more.
+
+C     $Id: ftst_vars3.F,v 1.11 2009/01/25 14:33:44 ed Exp $
+
+      program ftst_vars3
+      use netcdf4_f03
+      implicit none
+
+C     This is the name of the data file we will create.
+      character*(*) FILE_NAME
+      parameter (FILE_NAME='ftst_vars3.nc')
+
+C     We are writing an attribute, of length 3.
+      integer NDIMS
+      parameter (NDIMS = 1)
+      integer NX
+      parameter (NX = 3)
+
+C     NetCDF IDs.
+      integer ncid, varid, dimids(1)
+      integer enum_typeid, opaque_typeid
+
+C     This is the data array we will write as an enum attribute, and a
+C     place to store it when we read it back in. Z is the fastest
+C     varying dimension.
+      integer data_out(NX), data_in(NX)
+
+      integer max_types
+      parameter (max_types = 2)
+
+C     Need these to read type information.
+      integer num_types, typeids(max_types)
+      integer base_type, base_size, num_members, member_value
+      character*80 type_name, member_name
+      integer type_size, nfields, class
+
+C     Information for the enum type we will define.
+      character*(*) enum_type_name, one_name, zero_name
+      parameter (enum_type_name = 'enum_type')
+      parameter (zero_name = 'zero', one_name = 'one')
+      integer one, zero
+
+C     Information for the opaque type we will define.
+      character*(*) opaque_type_name
+      parameter (opaque_type_name = 'opaque_type')
+      integer opaque_size
+      parameter (opaque_size = 16)
+      character*(opaque_size) opaque_data, opaque_data_in
+      parameter (opaque_data = '0123456789012345')
+
+C     Loop indexes, and error handling.
+      integer x, retval, index(1)
+
+C     Create some pretend data.
+      do x = 1, NX
+         data_out(x) = 0
+      end do
+      data_out(1) = 1
+
+      print *, ''
+      print *,'*** Testing enum and opaque types.'
+
+C     Create the netCDF file.
+      retval = nf_create(FILE_NAME, NF_NETCDF4, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Create the enum type.
+      retval = nf_def_enum(ncid, NF_INT, enum_type_name, enum_typeid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      one = 1
+      zero = 0
+      retval = nf_insert_enum(ncid, enum_typeid, zero_name, zero)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_insert_enum(ncid, enum_typeid, one_name, one)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Create the opaque type.
+      retval = nf_def_opaque(ncid, opaque_size, opaque_type_name, 
+     &     opaque_typeid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Create a dimension.
+      retval = nf_def_dim(ncid, 'dim', 1, dimids(1))
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Create an opaque variable.
+      retval = nf_def_var(ncid, 'var', opaque_typeid, 1, dimids, varid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Write the opaque scalar var. (Could also use nf_put_var).
+      index(1) = 1
+      retval = nf_put_var1(ncid, varid, index, opaque_data)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Attach an enum attribute to the variable.
+      retval = nf_put_att(ncid, varid, 'att', enum_typeid, NX, 
+     &     data_out)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Close the file. 
+      retval = nf_close(ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Reopen the file.
+      retval = nf_open(FILE_NAME, NF_NOWRITE, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Get the typeids of all user defined types.
+      retval = nf_inq_typeids(ncid, num_types, typeids)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (num_types .ne. max_types) stop 2
+
+C     Use nf_inq_user_type to confirm this is an enum type.
+      retval = nf_inq_user_type(ncid, typeids(1), type_name, type_size, 
+     &     base_type, nfields, class)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (type_name(1:len(enum_type_name)) .ne. enum_type_name .or.
+     &     type_size .ne. 4 .or. base_type .ne. NF_INT .or. 
+     &     nfields .ne. 2 .or. class .ne. nf_enum) stop 2
+
+C     Use nf_inq_enum and make sure we get the same answers as we did
+C     with nf_inq_user_type.
+      retval = nf_inq_enum(ncid, typeids(1), type_name, base_type, 
+     &     base_size, num_members)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (type_name(1:len(enum_type_name)) .ne. enum_type_name .or.
+     &     base_type .ne. NF_INT .or. num_members .ne. 2) stop 2
+
+C     Check the members of the enum type.
+      retval = nf_inq_enum_member(ncid, typeids(1), 1, member_name, 
+     &     member_value)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (member_name(1:len(zero_name)) .ne. zero_name .or.
+     &     member_value .ne. 0) stop 2
+      retval = nf_inq_enum_member(ncid, typeids(1), 2, member_name, 
+     &     member_value)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (member_name(1:len(one_name)) .ne. one_name .or.
+     &     member_value .ne. 1) stop 2
+      retval = nf_inq_enum_ident(ncid, typeids(1), 0, member_name)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (member_name(1:len(zero_name)) .ne. zero_name) stop 2
+      retval = nf_inq_enum_ident(ncid, typeids(1), 1, member_name)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (member_name(1:len(one_name)) .ne. one_name) stop 2
+
+C     Use nf_inq_user_type to confirm that the second typeid is an
+C     opaque type.
+      retval = nf_inq_user_type(ncid, typeids(2), type_name, type_size, 
+     &     base_type, nfields, class)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (type_name(1:len(opaque_type_name)) .ne. opaque_type_name .or.
+     &     type_size .ne. opaque_size .or. base_type .ne. 0 .or. 
+     &     nfields .ne. 0 .or. class .ne. nf_opaque) stop 2
+
+C     Use nf_inq_opaque and make sure we get the same answers as we did
+C     with nf_inq_user_type.
+      retval = nf_inq_opaque(ncid, typeids(2), type_name, base_size)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (base_size .ne. opaque_size .or. 
+     &     type_name(1:len(opaque_type_name)) .ne. opaque_type_name) 
+     &     stop 2
+
+C     Read the variable.
+      index(1) = 1
+      retval = nf_get_var1(ncid, varid, index, opaque_data_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (opaque_data_in .ne. opaque_data) stop 2
+
+C     Read the attribute.
+      retval = nf_get_att(ncid, varid, 'att', data_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Check the values.
+      do x = 1, NX
+         if (data_in(x) .ne. data_out(x)) stop 2
+      end do
+
+C     Close the file. 
+      retval = nf_close(ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+      print *,'*** SUCCESS!'
+      end
diff --git a/nf_test/f03tst_vars4.F b/nf_test/f03tst_vars4.F
new file mode 100755
index 0000000..9001427
--- /dev/null
+++ b/nf_test/f03tst_vars4.F
@@ -0,0 +1,120 @@
+C     This is part of the netCDF package.
+C     Copyright 2008 University Corporation for Atmospheric Research/Unidata.
+C     See COPYRIGHT file for conditions of use.
+
+C     This program tests netCDF-4 variable functions from fortran, even
+C     more, even more.
+
+C     $Id: ftst_vars4.F,v 1.11 2009/10/24 10:03:39 ed Exp $
+
+      program ftst_vars4
+      USE netcdf4_f03
+      implicit none
+
+C     This is the name of the data file we will create.
+      character*(*) FILE_NAME
+      parameter (FILE_NAME='ftst_vars4.nc')
+
+C     NetCDF IDs.
+      integer ncid, vlen_typeid
+
+      integer max_types
+      parameter (max_types = 1)
+
+C     Need these to read type information.
+      integer num_types, typeids(max_types)
+      integer base_type, base_size, num_members, member_value
+      character*80 type_name, member_name
+      integer type_size, nfields, class
+
+C     Information for the vlen type we will define.
+      character*(*) vlen_type_name
+      parameter (vlen_type_name = 'vlen_type')
+
+C     Some data about and for the vlen.
+      integer vlen_len, vlen_len_in
+      parameter (vlen_len = 5)
+      integer data1(vlen_len), data1_in(vlen_len)
+
+C     These must be big enough to hold the stuct nc_vlen in netcdf.h.
+      integer vlen(10), vlen_in(10)
+
+C     Loop indexes, and error handling.
+      integer x, retval, index(1)
+
+      print *, ''
+      print *,'*** Testing VLEN types.'
+
+      do x = 1, vlen_len
+         data1(x) = x
+      end do
+
+C     Create the netCDF file.
+      retval = nf_create(FILE_NAME, NF_NETCDF4, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Create the vlen type.
+      retval = nf_def_vlen(ncid, vlen_type_name, nf_int, vlen_typeid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Set up the vlen with this helper function, since F77 can't deal
+C     with pointers.
+      retval = nf_put_vlen_element(ncid, vlen_typeid, vlen, 
+     &     vlen_len, data1)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Write the vlen attribute.
+      retval = nf_put_att(ncid, NF_GLOBAL, 'att1', vlen_typeid, 1, vlen)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Close the file. 
+      retval = nf_close(ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Reopen the file.
+      retval = nf_open(FILE_NAME, NF_NOWRITE, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Get the typeids of all user defined types.
+      retval = nf_inq_typeids(ncid, num_types, typeids)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (num_types .ne. max_types) stop 2
+
+C     Use nf_inq_user_type to confirm this is an vlen type, with base
+C     type NF_INT.
+      retval = nf_inq_user_type(ncid, typeids(1), type_name, type_size, 
+     &     base_type, nfields, class)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (type_name(1:len(vlen_type_name)) .ne. vlen_type_name .or.
+     &     base_type .ne. nf_int .or.
+     &     nfields .ne. 0 .or. class .ne. nf_vlen) stop 2
+
+C     Use nf_inq_vlen and make sure we get the same answers as we did
+C     with nf_inq_user_type.
+      retval = nf_inq_vlen(ncid, typeids(1), type_name, base_size, 
+     &     base_type)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (type_name(1:len(vlen_type_name)) .ne. vlen_type_name .or.
+     &     base_type .ne. nf_int) stop 2
+
+C     Read the vlen attribute.
+      retval = nf_get_att(ncid, NF_GLOBAL, 'att1', vlen_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Get the data from the vlen we just read.
+      retval = nf_get_vlen_element(ncid, vlen_typeid, vlen_in, 
+     &     vlen_len_in, data1_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (vlen_len_in .ne. vlen_len) stop 2
+
+C     Check the data
+      do x = 1, vlen_len
+         if (data1(x) .ne. data1_in(x)) stop 2
+      end do
+
+C     Close the file. 
+      retval = nf_close(ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+      print *,'*** SUCCESS!'
+      end
diff --git a/nf_test/f03tst_vars5.F b/nf_test/f03tst_vars5.F
new file mode 100755
index 0000000..a8669a3
--- /dev/null
+++ b/nf_test/f03tst_vars5.F
@@ -0,0 +1,117 @@
+C     This is part of the netCDF package.
+C     Copyright 2008 University Corporation for Atmospheric Research/Unidata.
+C     See COPYRIGHT file for conditions of use.
+
+C     This program tests netCDF-4 variable functions from fortran, even
+C     more, even more.
+
+C     $Id: ftst_vars5.F,v 1.4 2009/01/25 14:33:44 ed Exp $
+
+      program ftst_vars5
+      USE netcdf4_f03
+      implicit none
+
+C     This is the name of the data file we will create.
+      character*(*) FILE_NAME
+      parameter (FILE_NAME='ftst_vars5.nc')
+
+C     NetCDF IDs.
+      integer ncid, cmp_typeid
+
+      integer max_types
+      parameter (max_types = 1)
+
+C     Need these to read type information.
+      integer num_types, typeids(max_types)
+      integer base_type, type_size, num_members, member_value
+      character*80 type_name, member_name
+      integer nfields, class
+
+C     Information for the compound type we will define.
+      character*(*) cmp_type_name, int1_name, int2_name
+      parameter (cmp_type_name = 'compound_type')
+      parameter (int1_name = 'int1', int2_name = 'int2')
+      integer compound_len, compound_len_in
+      parameter (compound_len = 2)
+      integer data1(compound_len), data1_in(compound_len)
+      character*(4) att_name
+      parameter (att_name = 'att1')
+
+C     Loop indexes, and error handling.
+      integer x, retval, index(1)
+
+      print *, ''
+      print *,'*** Testing compound types.'
+
+C     Prepare some data to write.
+      do x = 1, compound_len
+         data1(x) = x
+      end do
+
+C     Create the netCDF file.
+      retval = nf_create(FILE_NAME, NF_NETCDF4, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Create the compound type.
+      retval = nf_def_compound(ncid, 8, cmp_type_name, 
+     &     cmp_typeid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Insert two integers.
+      retval = nf_insert_compound(ncid, cmp_typeid, int1_name, 
+     &     0, NF_INT)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      retval = nf_insert_compound(ncid, cmp_typeid, int2_name, 
+     &     4, NF_INT)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Write the compound attribute.
+      retval = nf_put_att(ncid, NF_GLOBAL, att_name, cmp_typeid, 
+     &     1, data1)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Close the file. 
+      retval = nf_close(ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Reopen the file.
+      retval = nf_open(FILE_NAME, NF_NOWRITE, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Get the typeids of all user defined types.
+      retval = nf_inq_typeids(ncid, num_types, typeids)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (num_types .ne. max_types) stop 2
+
+C     Use nf_inq_user_type to confirm this is an compound type
+      retval = nf_inq_user_type(ncid, typeids(1), type_name, type_size, 
+     &     base_type, nfields, class)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (type_name(1:len(cmp_type_name)) .ne. cmp_type_name .or.
+     &     type_size .ne. 8 .or. base_type .ne. 0 .or.
+     &     nfields .ne. 2 .or. class .ne. nf_compound) stop 2
+
+C     Use nf_inq_compound and make sure we get the same answers as we did
+C     with nf_inq_user_type.
+      retval = nf_inq_compound(ncid, typeids(1), type_name, type_size, 
+     &     nfields)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (type_name(1:len(cmp_type_name)) .ne. cmp_type_name .or.
+     &     base_type .ne. 0 .or. type_size .ne. 8 .or.
+     &     nfields .ne. 2) stop 2
+
+C     Read the compound attribute.
+      retval = nf_get_att(ncid, NF_GLOBAL, att_name, data1_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Check the data
+      do x = 1, compound_len
+         if (data1(x) .ne. data1_in(x)) stop 2
+      end do
+
+C     Close the file. 
+      retval = nf_close(ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+      print *,'*** SUCCESS!'
+      end
diff --git a/nf_test/f03tst_vars6.F b/nf_test/f03tst_vars6.F
new file mode 100755
index 0000000..064abda
--- /dev/null
+++ b/nf_test/f03tst_vars6.F
@@ -0,0 +1,204 @@
+C     This is part of the netCDF package.
+C     Copyright 2008 University Corporation for Atmospheric Research/Unidata.
+C     See COPYRIGHT file for conditions of use.
+
+C     This program tests netCDF-4 variable functions from fortran, even
+C     more, even more.
+
+C     $Id: ftst_vars6.F,v 1.7 2009/02/11 16:53:46 ed Exp $
+
+      program ftst_vars6
+      use netcdf4_f03
+      implicit none
+
+C     This is the name of the data file we will create.
+      character*(*) FILE_NAME
+      parameter (FILE_NAME='ftst_vars6.nc')
+      integer NDIMS
+      parameter (NDIMS = 1)
+      integer DIM_LEN
+      parameter (DIM_LEN = 22)
+      integer NVARS
+      parameter (NVARS = 3)
+      integer DATA_LEN
+      parameter (DATA_LEN = 2)
+      integer check_file
+
+      integer ncid, varid(NVARS), dimids(NDIMS)
+      integer data_len_in, offset
+      parameter (offset = 20)
+      integer data1(data_len), data1_in(data_len)
+      character*(4) var_name(NVARS)
+      character*(4) dim_name
+      parameter (dim_name = 'dim1')
+      integer NO_FILL, MY_FILL_VALUE
+      parameter (NO_FILL = 1)
+      parameter (MY_FILL_VALUE = 42)
+
+C     Loop index and error handling.
+      integer x, retval
+
+      print *, ''
+      print *,'*** Testing fill values.'
+
+C     Prepare some data to write.
+      do x = 1, data_len
+         data1(x) = x
+      end do
+
+C     Set up var names.
+      var_name(1) = 'var1'
+      var_name(2) = 'var2'
+      var_name(3) = 'var3'
+
+C     Create the netCDF file.
+      retval = nf_create(FILE_NAME, NF_NETCDF4, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Create a dimension.
+      retval = nf_def_dim(ncid, dim_name, DIM_LEN, dimids(1))
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Create a few integer variables.
+      do x = 1, NVARS      
+         retval = nf_def_var(ncid, var_name(x), NF_INT, NDIMS, dimids,
+     $        varid(x))
+         if (retval .ne. nf_noerr) call handle_err(retval)
+      end do
+
+C     Set no fill mode for the second variable.
+      retval = nf_def_var_fill(ncid, varid(2), NO_FILL, 88)
+      if (retval .ne. 0) stop 2
+
+C     Set an alternative fill value for the third variable.
+      retval = nf_def_var_fill(ncid, varid(3), 0, MY_FILL_VALUE)
+      if (retval .ne. 0) stop 3
+
+C     Check it out. 
+c      retval = check_file(ncid, var_name, dim_name)
+c      if (retval .ne. 0) stop 2
+
+C     Close the file. 
+      retval = nf_close(ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Reopen the file.
+      retval = nf_open(FILE_NAME, NF_NOWRITE, ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+C     Check it out. 
+      retval = check_file(ncid, var_name, dim_name)
+      if (retval .ne. 0) stop 4
+
+C     Close the file. 
+      retval = nf_close(ncid)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+
+      print *,'*** SUCCESS!'
+      end
+
+C     This function check the file to make sure everything is OK.
+      integer function check_file(ncid, var_name, dim_name)
+      use netcdf4_f03
+      implicit none
+
+C     I need these in both here and the main program.
+      integer NDIMS
+      parameter (NDIMS = 1)
+      integer DIM_LEN
+      parameter (DIM_LEN = 22)
+      integer NVARS
+      parameter (NVARS = 3)
+      integer DATA_LEN
+      parameter (DATA_LEN = 2)
+      integer MY_FILL_VALUE
+      parameter (MY_FILL_VALUE = 42)
+
+C     Parameters
+      integer ncid
+      character*(4) var_name(NVARS)
+      character*(4) dim_name
+
+C     Values that are read in, to check the file.
+      integer ndims_in, nvars_in, ngatts_in, unlimdimid_in
+      integer xtype_in, dimids_in(NDIMS), natts_in
+      integer varid_in(NVARS), dimid_in, no_fill_in, fill_value_in
+      character*(4) var_name_in
+      integer int_data_in(DIM_LEN)
+
+      integer x, retval
+
+C     Check it out.
+      retval = nf_inq(ncid, ndims_in, nvars_in, ngatts_in,
+     $     unlimdimid_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (ndims_in .ne. 1 .or. nvars_in .ne. NVARS .or. ngatts_in .ne. 0
+     $     .or. unlimdimid_in .ne. -1) stop 5
+
+C     Get the varids and the dimid.
+      do x = 1, NVARS      
+         retval = nf_inq_varid(ncid, var_name(x), varid_in(x))
+         if (retval .ne. nf_noerr) call handle_err(retval)
+         if (varid_in(x) .ne. x) stop 6
+      end do
+      retval = nf_inq_dimid(ncid, dim_name, dimid_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (dimid_in .ne. 1) stop 7
+
+C     These things are the same for all three variables, except
+C     natts_in..
+      do x = 1, NVARS      
+         retval = nf_inq_var(ncid, varid_in(x), var_name_in, xtype_in,
+     $        ndims_in, dimids_in, natts_in)
+         if (retval .ne. nf_noerr) call handle_err(retval)
+         if (ndims_in .ne. 1 .or. xtype_in .ne. NF_INT .or. dimids_in(1)
+     $        .ne. dimid_in) stop 8
+         if (x .eq. 3 .and. natts_in .ne. 1) stop 9
+         if (x .lt. 3 .and. natts_in .ne. 0) stop 10
+      end do
+
+C     Check the fill value for the first var. Nothing was set, so
+C     no_fill should be off, and fill_value should be the default fill
+C     value for this type.
+      retval = nf_inq_var_fill(ncid, varid_in(1), no_fill_in,
+     $     fill_value_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (no_fill_in .ne. 0 .or. fill_value_in .ne. nf_fill_int) stop 11
+
+C     Check that no_fill mode is on for the second variable.
+      retval = nf_inq_var_fill(ncid, varid_in(2), no_fill_in,
+     $     fill_value_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (no_fill_in .ne. 1 .or. fill_value_in .ne. nf_fill_int) stop 12
+
+C     Check that a non-default fill value is in use for the third variable.
+      retval = nf_inq_var_fill(ncid, varid_in(3), no_fill_in,
+     $     fill_value_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      if (no_fill_in .ne. 0 .or. fill_value_in .ne. MY_FILL_VALUE) stop
+     $     2
+
+C     Get the data in var1. It will be all the default fill value.
+      retval = nf_get_var_int(ncid, varid_in(1), int_data_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      do x = 1, DIM_LEN
+         if (int_data_in(x) .ne. nf_fill_int) stop 13
+      end do
+
+C     Get the data in var2. What will it be?
+      retval = nf_get_var_int(ncid, varid_in(2), int_data_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+C$$$      do x = 1, DIM_LEN
+C$$$         print *, int_data_in(x)
+C$$$      end do
+
+C     Get the data in var3. It will be all the default fill value.
+      retval = nf_get_var_int(ncid, varid_in(3), int_data_in)
+      if (retval .ne. nf_noerr) call handle_err(retval)
+      do x = 1, DIM_LEN
+C         print *, int_data_in(x)
+         if (int_data_in(x) .ne. MY_FILL_VALUE) stop 14
+      end do
+
+      check_file = 0
+      end 
diff --git a/nf_test/f90tst_parallel_fill.f90 b/nf_test/f90tst_parallel_fill.f90
new file mode 100644
index 0000000..2326d27
--- /dev/null
+++ b/nf_test/f90tst_parallel_fill.f90
@@ -0,0 +1,199 @@
+!     This is part of the netCDF package.
+!     Copyright 2006 University Corporation for Atmospheric Research/Unidata.
+!     See COPYRIGHT file for conditions of use.
+
+!     This program tests netCDF-4 fill values.
+
+!     $Id: f90tst_parallel_fill.f90,v 1.1 2009/12/10 16:44:51 ed Exp $
+
+program f90tst_parallel_fill
+  use typeSizes
+  use netcdf
+  implicit none
+  include 'mpif.h'
+  
+  ! This is the name of the data file we will create.
+  character (len = *), parameter :: FILE_NAME = "f90tst_parallel_fill.nc"
+  integer, parameter :: MAX_DIMS = 2
+  integer, parameter :: NX = 16, NY = 16
+  integer, parameter :: HALF_NX = NX / 2, HALF_NY = NY / 2
+  integer, parameter :: QUARTER_NX = NX / 4, QUARTER_NY = NY / 4
+  integer, parameter :: NUM_VARS = 8
+  character (len = *), parameter :: var_name(NUM_VARS) = &
+       (/ 'byte', 'short', 'int', 'float', 'double', 'ubyte', 'ushort', 'uint' /)
+  integer :: ncid, varid(NUM_VARS), dimids(MAX_DIMS)
+  integer :: var_type(NUM_VARS) = (/ nf90_byte, nf90_short, nf90_int, &
+       nf90_float, nf90_double, nf90_ubyte, nf90_ushort, nf90_uint /)
+  integer :: x_dimid, y_dimid
+  integer :: byte_out(QUARTER_NY, QUARTER_NX), byte_in(NY, NX)
+  integer :: short_out(QUARTER_NY, QUARTER_NX), short_in(NY, NX)
+  integer :: int_out(QUARTER_NY, QUARTER_NX), int_in(NY, NX)
+  real :: areal_out(QUARTER_NY, QUARTER_NX), areal_in(NY, NX)
+  real :: double_out(QUARTER_NY, QUARTER_NX), double_in(NY, NX)
+  integer :: ubyte_out(QUARTER_NY, QUARTER_NX), ubyte_in(NY, NX)
+  integer :: ushort_out(QUARTER_NY, QUARTER_NX), ushort_in(NY, NX)
+  integer (kind = EightByteInt) :: uint_out(QUARTER_NY, QUARTER_NX), uint_in(NY, NX)
+  integer :: nvars, ngatts, ndims, unlimdimid, file_format
+  integer :: x, y, v
+  integer :: start_out(MAX_DIMS), count_out(MAX_DIMS)
+  integer :: start_in(MAX_DIMS), count_in(MAX_DIMS)
+  integer :: p, my_rank, ierr
+
+  call MPI_Init(ierr)
+  call MPI_Comm_rank(MPI_COMM_WORLD, my_rank, ierr)
+  call MPI_Comm_size(MPI_COMM_WORLD, p, ierr)
+
+  if (my_rank .eq. 0) then
+     print *,
+     print *, '*** Testing fill values with unlimited dimension and parallel I/O.'
+  endif
+
+  ! There must be 4 procs for this test.
+  if (p .ne. 4) then
+     print *, 'Sorry, this test program must be run on four processors.'
+     stop 1
+  endif
+
+  ! Create some pretend data.
+  do x = 1, QUARTER_NX
+     do y = 1, QUARTER_NY
+        byte_out(y, x) = -1
+        short_out(y, x) =  -2
+        int_out(y, x) = -4
+        areal_out(y, x) = 2.5
+        double_out(y, x) = -4.5
+        ubyte_out(y, x) = 1
+        ushort_out(y, x) = 2
+        uint_out(y, x) = 4
+     end do
+  end do
+
+  ! Create the netCDF file. 
+  call check(nf90_create(FILE_NAME, nf90_netcdf4, ncid, comm = MPI_COMM_WORLD, &
+       info = MPI_INFO_NULL))
+
+  ! Define the dimensions.
+  call check(nf90_def_dim(ncid, "x", NX, x_dimid))
+  call check(nf90_def_dim(ncid, "y", NY, y_dimid))
+  dimids =  (/ y_dimid, x_dimid /)
+
+  ! Define the variables. 
+  do v = 1, NUM_VARS
+     call check(nf90_def_var(ncid, var_name(v), var_type(v), dimids, varid(v)))
+     call check(nf90_var_par_access(ncid, varid(v), nf90_collective))     
+  end do
+
+  ! This will be the last collective operation.
+  call check(nf90_enddef(ncid))
+
+  ! Determine what part of the variable will be written/read for this
+  ! processor. It's a checkerboard decomposition. Only the third
+  ! quadrant of data will be written, so each processor writes a
+  ! quarter of the quadrant, or 1/16th of the total array. (And
+  ! processor 0 doesn't write anyway.)
+  count_out = (/ QUARTER_NX, QUARTER_NY /)
+  if (my_rank .eq. 0) then 
+     start_out = (/ HALF_NX + 1, HALF_NY + 1 /)
+  else if (my_rank .eq. 1) then
+     start_out = (/ HALF_NX + 1, HALF_NY + 1 + QUARTER_NY /)
+  else if (my_rank .eq. 2) then
+     start_out = (/ HALF_NX + 1 + QUARTER_NX, HALF_NY + 1 /)
+  else if (my_rank .eq. 3) then
+     start_out = (/ HALF_NX + 1 + QUARTER_NX, HALF_NY + 1 + QUARTER_NY /)
+  endif
+  print *, my_rank, start_out, count_out
+
+  ! Write this processor's data, except for processor zero.
+  if (my_rank .ne. 0) then
+     call check(nf90_put_var(ncid, varid(1), byte_out, start = start_out, count = count_out))
+!      call check(nf90_put_var(ncid, varid(2), short_out, start = start_out, count = count_out))
+!      call check(nf90_put_var(ncid, varid(3), int_out, start = start_out, count = count_out))
+!      call check(nf90_put_var(ncid, varid(4), areal_out, start = start_out, count = count_out))
+!      call check(nf90_put_var(ncid, varid(5), double_out, start = start_out, count = count_out))
+!      call check(nf90_put_var(ncid, varid(6), ubyte_out, start = start_out, count = count_out))
+!      call check(nf90_put_var(ncid, varid(7), ushort_out, start = start_out, count = count_out))
+!      call check(nf90_put_var(ncid, varid(8), uint_out, start = start_out, count = count_out))
+  endif
+
+  ! Close the file. 
+  call check(nf90_close(ncid))
+
+  ! Reopen the file.
+!   call check(nf90_open(FILE_NAME, nf90_nowrite, ncid, comm = MPI_COMM_WORLD, &
+!        info = MPI_INFO_NULL))
+  
+!   ! Check some stuff out.
+!   call check(nf90_inquire(ncid, ndims, nvars, ngatts, unlimdimid, file_format))
+!   if (ndims /= 2 .or. nvars /= NUM_VARS .or. ngatts /= 0 .or. unlimdimid /= 1 .or. &
+!        file_format /= nf90_format_netcdf4) stop 2
+
+!   ! Now each processor will read one quarter of the whole array.
+!   count_in = (/ HALF_NX, HALF_NY /)
+!   if (my_rank .eq. 0) then 
+!      start_in = (/ 1, 1 /)
+!   else if (my_rank .eq. 1) then
+!      start_in = (/ HALF_NX + 1, 1 /)
+!   else if (my_rank .eq. 2) then
+!      start_in = (/ 1, HALF_NY + 1 /)
+!   else if (my_rank .eq. 3) then
+!      start_in = (/ HALF_NX + 1, HALF_NY + 1 /)
+!   endif
+
+!   ! Read this processor's data.
+!   call check(nf90_get_var(ncid, varid(1), byte_in, start = start_in, count = count_in))
+!   call check(nf90_get_var(ncid, varid(2), short_in, start = start_in, count = count_in))
+!   call check(nf90_get_var(ncid, varid(3), int_in, start = start_in, count = count_in))
+!   call check(nf90_get_var(ncid, varid(4), areal_in, start = start_in, count = count_in))
+!   call check(nf90_get_var(ncid, varid(5), double_in, start = start_in, count = count_in))
+!   call check(nf90_get_var(ncid, varid(6), ubyte_in, start = start_in, count = count_in))
+!   call check(nf90_get_var(ncid, varid(7), ushort_in, start = start_in, count = count_in))
+!   call check(nf90_get_var(ncid, varid(8), uint_in, start = start_in, count = count_in))
+
+!   ! Check the data. All the data from the processor zero are fill
+!   ! value.
+!   do x = 1, NX
+!      do y = 1, NY
+!         if (my_rank .eq. 0) then
+!            if (byte_in(y, x) .ne. -1) stop 13
+!            if (short_in(y, x) .ne. -2) stop 14
+!            if (int_in(y, x) .ne. -4) stop 15
+!            if (areal_in(y, x) .ne. 2.5) stop 16
+!            if (double_in(y, x) .ne. -4.5) stop 17
+!            if (ubyte_in(y, x) .ne. 1) stop 18
+!            if (ushort_in(y, x) .ne. 2) stop 19
+!            if (uint_in(y, x) .ne. 4) stop 20
+!         else 
+!            if (byte_in(y, x) .ne. nf90_fill_byte) stop 3
+!            if (short_in(y, x) .ne. nf90_fill_short) stop 4
+!            if (int_in(y, x) .ne. nf90_fill_int) stop 5
+!            if (areal_in(y, x) .ne. nf90_fill_real) stop 6
+!            if (double_in(y, x) .ne. nf90_fill_double) stop 7
+!            if (ubyte_in(y, x) .ne. nf90_fill_ubyte) stop 8
+!            if (ushort_in(y, x) .ne. nf90_fill_ushort) stop 9
+!            if (uint_in(y, x) .ne. nf90_fill_uint) stop 10
+!         endif
+!      end do
+!   end do
+
+!   ! Close the file. 
+!   call check(nf90_close(ncid))
+
+  call MPI_Finalize(ierr)
+
+  if (my_rank .eq. 0) print *,'*** SUCCESS!'
+
+contains
+!     This subroutine handles errors by printing an error message and
+!     exiting with a non-zero status.
+  subroutine check(errcode)
+    use netcdf
+    implicit none
+    integer, intent(in) :: errcode
+    
+    if(errcode /= nf90_noerr) then
+       print *, 'Error: ', trim(nf90_strerror(errcode))
+       stop 99
+    endif
+  end subroutine check
+end program f90tst_parallel_fill
+
diff --git a/nf_test/lib.F b/nf_test/lib.F
new file mode 100644
index 0000000..2cb010d
--- /dev/null
+++ b/nf_test/lib.F
@@ -0,0 +1,60 @@
+    / *Macros for accessing attribute test data */
+    /* varid is -1 for NF_GLOBAL so can do global atts in same loop */
+
+      FUNCTION VARID(VID)
+      IMPLICIT NONE
+      INTEGER VID
+#include "tests.inc"
+      IF (VID .LT. 0) THEN
+          VARID = NF_GLOBAL
+      ELSE
+          VARID = VID
+      ENDIF
+      end
+
+
+      FUNCTION NATTS(VID)
+      INTEGER VID
+#include "tests.inc"
+      IF (VID .LE. 0) THEN
+          NATTS = NGATTS
+      ELSE
+          NATTS = VAR_NATTS(VID)
+      ENDIF
+      END
+
+
+      FUNCTION ATT_NAME(J,VID)
+      INTEGER J
+      INTEGER VID
+#include "tests.inc"
+      IF (VID .LE. 0) THEN
+          ATT_NAME = GATT_NAME(J)
+      ELSE
+          ATT_NAME = ATTNAME(J,VID)
+      ENDIF
+      END
+
+
+      FUNCTION ATT_TYPE(J,VID)
+      INTEGER J
+      INTEGER VID
+#include "tests.inc"
+      IF (VID .LE. 0) THEN
+          ATT_TYPE = GATT_TYPE(J)
+      ELSE
+          ATT_TYPE = ATTTYPE(J,VID)
+      ENDIF
+      END
+
+
+      FUNCTION ATT_LEN(J,VID)
+      INTEGER J
+      INTEGER VID
+#include "tests.inc"
+      IF (VID .LE. 0) THEN
+          ATT_LEN = GATT_LEN(J)
+      ELSE
+          ATT_LEN = ATTLEN(J,VID)
+      ENDIF
+      END
diff --git a/nf_test/module_tests.F90 b/nf_test/module_tests.F90
new file mode 100755
index 0000000..9624eb2
--- /dev/null
+++ b/nf_test/module_tests.F90
@@ -0,0 +1,255 @@
+      Module tests
+!/*********************************************************************
+! *   Copyright 1996, UCAR/Unidata
+! *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
+! *   $Id: tests.inc,v 1.15 2007/01/19 16:08:47 ed Exp $
+! *********************************************************************/
+
+! Implementation of test.inc in a module
+! Modified by: Richard Weed,Ph.D
+!              Center for Advanced Vehicular Systems
+!              Mississippi State University
+!              rweed at cavs.msstate.edu
+
+!!!!
+! Do not tabify this unless you like hitting the 72 char limit !!!
+!!!
+#ifndef UD_TESTS_INC
+#define UD_TESTS_INC
+
+
+!/* The following prevents non-FORTRAN code from appearing in the output. */
+#if defined(__osf__)
+#   undef _POSIX_SOURCE
+#   define _POSIX_SOURCE
+#endif
+
+#if defined(NO_NETCDF_2)
+#  undef NO_NETCDF_2
+#  define NO_NETCDF_2 1
+#else
+#define NO_NETCDF_2 1
+#endif
+
+#include "nfconfig.inc"
+#ifdef USE_NETCDF4
+       USE netcdf4_f03
+#else
+       USE netcdf_f03
+#endif
+ 
+       Implicit NONE
+
+       SAVE
+!/* Parameters of test data */
+
+#ifdef  NF_INT1_T
+#   define NF_B 1
+#else
+#   define NF_B 0
+#endif
+#ifdef  NF_INT2_T
+#   define NF_S 1
+#else
+#   define NF_S 0
+#endif
+! Total number of FORTRAN types:
+       Integer, Parameter :: NUM_FORTRAN_TYPES = (3 + NF_S + NF_B)
+#undef NF_B
+#undef NF_S
+
+      Integer, Parameter :: NTYPES=6
+      Integer, Parameter :: NDIMS=5
+      Integer, Parameter :: NVARS=136
+      Integer, Parameter :: NRECS=2
+      Integer, Parameter :: NGATTS=NTYPES
+      Integer, Parameter :: RECDIM=1
+      Integer, Parameter :: MAX_RANK=3
+      Integer, Parameter :: MAX_NELS=64
+      Integer, Parameter :: MAX_DIM_LEN=4
+      Integer, Parameter :: MAX_NATTS=3
+
+
+!/*
+! * Limits of external types (based on those in ncx.h):
+! */
+      Integer, Parameter :: X_CHAR_MIN=0
+      Integer, Parameter :: X_CHAR_MAX=127
+      Integer, Parameter :: X_INT1_MIN=(-128)
+      Integer, Parameter :: X_INT1_MAX=127
+      Integer, Parameter :: X_INT2_MIN=(-32768)
+      Integer, Parameter :: X_INT2_MAX=32767
+      Integer, Parameter :: X_INT_MIN=(-2147483647-1)
+      Integer, Parameter :: X_INT_MAX=2147483647
+#if 0
+      Real(RK4), Parameter :: X_REAL_MAX=3.4028234663852886e+38
+#else
+      Real(RK4), Parameter :: X_REAL_MAX=3.4028234663852886e+37
+#endif
+      Real(RK4), Parameter :: X_REAL_MIN=(-X_REAL_MAX)
+#if 0
+      Real(RK8), Parameter :: X_DOUBLE_MAX=1.7976931348623157E+308
+#else
+      Real(RK8), Parameter :: X_DOUBLE_MAX=1.7976931348623157D+200
+#endif
+      Real(RK8), Parameter :: X_DOUBLE_MIN=(-X_DOUBLE_MAX)
+
+      Integer, Parameter :: X_BYTE_MIN=X_INT1_MIN
+      Integer, Parameter :: X_BYTE_MAX=X_INT1_MAX
+      Integer, Parameter :: X_SHORT_MIN=X_INT2_MIN
+      Integer, Parameter :: X_SHORT_MAX=X_INT2_MAX
+      Real(RK4), Parameter :: X_FLOAT_MIN=X_REAL_MIN
+      Real(RK4), Parameter :: X_FLOAT_MAX=X_REAL_MAX
+
+
+!/*
+! * Examples of invalid argument values:
+! */
+      Integer, Parameter :: BAD_ID=-1
+      Integer, Parameter :: BAD_DIMID=-1
+      Integer, Parameter :: BAD_VARID=-2
+      Integer, Parameter :: BAD_ATTNUM=-1
+      Integer, Parameter :: BAD_TYPE=0
+      Integer, Parameter :: BAD_FILLMODE=-1
+      Character*3, Parameter :: BAD_NAME='a/b'
+
+
+!/*
+! * Internal data types:
+! */
+      Integer, Parameter :: NFT_UNSPECIFIED=0
+      Integer, Parameter :: NFT_TEXT=16
+      Integer, Parameter :: NFT_CHAR=NFT_TEXT
+      Integer, Parameter :: NFT_INT1=17
+      Integer, Parameter :: NFT_INT2=18
+      Integer, Parameter :: NFT_INT=20
+      Integer, Parameter :: NFT_REAL=36
+      Integer, Parameter :: NFT_DOUBLE=40
+
+
+!/*
+! * Define a macro for trimming trailing blanks from character variables.
+! */
+#define TRIM(string) string(1:len_trim(string))
+
+
+!
+! FORTRAN GETARG() subroutine:
+!
+#ifdef __hpux
+#   define      getarg  getarg_
+#endif
+
+
+#endif /* UD_TESTS_INC */
+
+
+! #include "../fortran/netcdf.inc"
+
+
+!    /* Global variables - filenames */
+
+      CHARACTER(LEN=80) ::   testfile   !/* netCDF read-only test data */
+      CHARACTER(LEN=80) ::   scratch    !/* netCDF test file for writing */
+
+!    /* Global variables - command-line arguments */
+
+      LOGICAL :: CREATE_FILE
+      LOGICAL :: READONLY
+      LOGICAL :: VERBOSE
+      INTEGER :: NFAILS
+      INTEGER :: MAX_NMPT        !/* max num messages per test */
+
+!    /* Global variables - test data */
+
+      CHARACTER(LEN=2)            :: DIM_NAME(NDIMS)
+      INTEGER                     :: DIM_LEN(NDIMS)
+      CHARACTER(LEN=(2+MAX_RANK)) :: VAR_NAME(NVARS)
+      INTEGER                     :: VAR_TYPE(NVARS)
+      INTEGER                     :: VAR_RANK(NVARS)
+      INTEGER                     :: VAR_DIMID(MAX_RANK,NVARS)
+      INTEGER                     :: VAR_SHAPE(MAX_RANK,NVARS)
+      INTEGER                     :: VAR_NELS(NVARS)
+      INTEGER                     :: VAR_NATTS(NVARS)
+      CHARACTER(LEN=2)            :: ATTNAME(MAX_NATTS,NVARS)
+      CHARACTER(LEN=2)            :: GATT_NAME(NGATTS)
+      INTEGER                     :: ATTTYPE(NGATTS,NVARS)
+      INTEGER                     :: GATT_TYPE(NGATTS)
+      INTEGER                     :: ATTLEN(MAX_NATTS,NVARS)
+      INTEGER                     :: GATT_LEN(NGATTS)
+
+!    /* Miscellaneous global variables: */
+      CHARACTER(LEN=80) :: PROGNAME        !/* name of the program */
+      INTEGER           :: NFAILSTOTAL
+
+!    /* Common blocks for global variables: */
+
+!     COMMON    /LOGCOM/        CREATE_FILE,                            &
+!    &                          READONLY,                               & 
+!    &                          VERBOSE        
+
+!     COMMON    /TXTCOM/        TESTFILE,                               &
+!    &                          SCRATCH,                                &
+!    &                          DIM_NAME,                               &
+!    &                          VAR_NAME,                               &
+!    &                          ATTNAME,                                &
+!    &                          GATT_NAME,                              &
+!    &                          PROGNAME
+
+!     COMMON    /INTCOM/        NFAILS,                                 &  
+!    &                          DIM_LEN,                                &
+!    &                          VAR_TYPE,                               &
+!    &                          VAR_RANK,                               &
+!    &                          VAR_DIMID,                              &
+!    &                          VAR_SHAPE,                              &
+!    &                          VAR_NELS,                               &
+!    &                          VAR_NATTS,                              &
+!    &                          ATTTYPE,                                &
+!    &                          GATT_TYPE,                              &
+!    &                          ATTLEN,                                 &
+!    &                          GATT_LEN,                               &
+!    &                          MAX_NMPT,                               &
+!    &                          NFAILSTOTAL
+
+
+!    /* Functions for accessing attribute test data */
+!    /* varid is -1 for NC_GLOBAL so can do global atts in same loop */
+
+!/*      EXTERNAL       ATT_NAME */
+
+      INTEGER, EXTERNAL           :: VARID
+      INTEGER, EXTERNAL           :: NATTS
+      CHARACTER(LEN=2), EXTERNAL  :: ATT_NAME
+      INTEGER, EXTERNAL           :: ATT_TYPE
+      INTEGER, EXTERNAL           :: ATT_LEN
+
+
+      LOGICAL, EXTERNAL   :: INRANGE
+      LOGICAL, EXTERNAL   :: INRANGE_UCHAR
+      LOGICAL, EXTERNAL   :: INRANGE_FLOAT
+      LOGICAL, EXTERNAL   :: INRANGE3
+      LOGICAL, EXTERNAL   :: IN_INTERNAL_RANGE
+      LOGICAL, EXTERNAL   :: EQUAL
+      LOGICAL, EXTERNAL   :: INT_VEC_EQ
+
+      INTEGER, EXTERNAL   :: ROLL
+      INTEGER, EXTERNAL   :: INDEX2INDEXES
+      INTEGER, EXTERNAL   :: INDEX2NCINDEXES
+      INTEGER, EXTERNAL   :: INDEXES2INDEX
+      INTEGER, EXTERNAL   :: NC2DBL
+      INTEGER, EXTERNAL   :: DBL2NC
+!      INTEGER, EXTERNAL   :: LEN_TRIM
+      REAL(RK8), EXTERNAL :: HASH
+      REAL(RK8), EXTERNAL :: HASH4
+      REAL(RK8), EXTERNAL :: HASH_TEXT
+      REAL(RK8), EXTERNAL :: HASH_INT1
+      REAL(RK8), EXTERNAL :: HASH_INT2
+      REAL(RK8), EXTERNAL :: HASH_INT
+      REAL(RK8), EXTERNAL :: HASH_REAL
+      REAL(RK8), EXTERNAL :: HASH_DOUBLE
+      REAL(RK8), EXTERNAL :: INTERNAL_MIN
+      REAL(RK8), EXTERNAL :: INTERNAL_MAX
+      REAL(RK8), EXTERNAL :: EXTERNAL_MIN
+      REAL(RK8), EXTERNAL :: EXTERNAL_MAX
+
+      End Module tests
diff --git a/nf_test/nf03_error.F b/nf_test/nf03_error.F
new file mode 100755
index 0000000..e76bfde
--- /dev/null
+++ b/nf_test/nf03_error.F
@@ -0,0 +1,75 @@
+#if 0
+    Copyright 1996, UCAR/Unidata
+    See netcdf/COPYRIGHT file for copying and redistribution conditions.
+    $Id: nf_error.F,v 1.4 1997/06/03 22:26:09 steve Exp $
+#endif
+
+
+C
+C Use for logging error messages
+C
+        subroutine error(msg)
+        use tests
+        implicit        none
+        character*(*)   msg
+
+        nfails = nfails + 1
+        if (nfails .le. max_nmpt) print *, msg
+        end
+
+
+C
+C Use for logging error conditions
+C
+        subroutine errori(msg, i)
+        use tests
+        implicit        none
+        character*(*)   msg
+        integer         i
+
+        nfails = nfails + 1
+        if (nfails .le. max_nmpt) print *, msg, i
+        end
+
+
+C
+C Use for logging error conditions
+C
+        subroutine errord(msg, d)
+        use tests
+        implicit        none
+        character*(*)   msg
+        doubleprecision d
+
+        nfails = nfails + 1
+        if (nfails .le. max_nmpt) print *, msg, d
+        end
+
+
+C
+C Use for logging error conditions
+C
+        subroutine errorc(msg, string)
+        use tests
+        implicit        none
+        character*(*)   msg
+        character*(*)   string
+
+        nfails = nfails + 1
+        if (nfails .le. max_nmpt) print *, msg, 
+     +      string(1:len_trim(string))
+        end
+
+
+C
+C Use for logging error conditions
+C
+        subroutine errore(msg, err)
+        use tests
+        implicit        none
+        character*(*)   msg
+        integer         err
+
+        nfails = nfails + 1
+        call errorc(msg, nf_strerror(err))
+        end
diff --git a/nf_test/nf03_test.F b/nf_test/nf03_test.F
new file mode 100755
index 0000000..5178060
--- /dev/null
+++ b/nf_test/nf03_test.F
@@ -0,0 +1,388 @@
+#include "../fortran/nf03config.inc"
+
+C Copyright 1996-2006, UCAR/Unidata
+C See COPYRIGHT file for copying and redistribution conditions.
+
+C Test driver for netCDF-3 interface.  This program performs tests against
+C the netCDF-3 specification for all user-level functions in an
+C implementation of the netCDF library.
+
+C $Id: nf_test.F,v 1.28 2009/01/25 14:33:44 ed Exp $
+
+        subroutine test(name, func)
+        use tests
+        implicit        none
+        character*(*)   name
+        external        func
+
+        write(*, 1) name
+1       format(' *** testing ', a, ' ... ')
+        nfails = 0
+        call func()
+        nfailsTotal = nfailsTotal + nfails
+        if ( nfails .ne. 0) then
+            print *, ' '
+            print *, '  ### ', nfails, ' FAILURES TESTING ', name, 
+     +               '! ###'
+        end if
+        end
+
+        program nf_test
+        use tests
+        implicit        none
+
+
+        integer         status
+
+        external        test_nf_strerror
+        external        test_nf_open
+        external        test_nf_close
+        external        test_nf_inq
+        external        test_nf_inq_dimid
+        external        test_nf_inq_dim
+        external        test_nf_inq_dimlen
+        external        test_nf_inq_dimname
+        external        test_nf_inq_varid
+        external        test_nf_inq_var
+        external        test_nf_inq_natts
+        external        test_nf_inq_ndims
+        external        test_nf_inq_nvars
+        external        test_nf_inq_unlimdim
+        external        test_nf_inq_format
+        external        test_nf_inq_vardimid
+        external        test_nf_inq_varname
+        external        test_nf_inq_varnatts
+        external        test_nf_inq_varndims
+        external        test_nf_inq_vartype
+        external        test_nf_get_var1_text
+#if defined(NF_INT1_T)
+        external        test_nf_get_var1_int1
+#endif
+#if defined(NF_INT2_T)
+        external        test_nf_get_var1_int2
+#endif
+        external        test_nf_get_var1_int
+        external        test_nf_get_var1_real
+        external        test_nf_get_var1_double
+        external        test_nf_get_var_text
+#if defined(NF_INT1_T)
+        external        test_nf_get_var_int1
+#endif
+#if defined(NF_INT2_T)
+        external        test_nf_get_var_int2
+#endif
+        external        test_nf_get_var_int
+        external        test_nf_get_var_real
+        external        test_nf_get_var_double
+        external        test_nf_get_vara_text
+#if defined(NF_INT1_T)
+        external        test_nf_get_vara_int1
+#endif
+#if defined(NF_INT2_T)
+        external        test_nf_get_vara_int2
+#endif
+        external        test_nf_get_vara_int
+        external        test_nf_get_vara_real
+        external        test_nf_get_vara_double
+        external        test_nf_get_vars_text
+#if defined(NF_INT1_T)
+        external        test_nf_get_vars_int1
+#endif
+#if defined(NF_INT2_T)
+        external        test_nf_get_vars_int2
+#endif
+        external        test_nf_get_vars_int
+        external        test_nf_get_vars_real
+        external        test_nf_get_vars_double
+        external        test_nf_get_varm_text
+#if defined(NF_INT1_T)
+        external        test_nf_get_varm_int1
+#endif
+#if defined(NF_INT2_T)
+        external        test_nf_get_varm_int2
+#endif
+        external        test_nf_get_varm_int
+        external        test_nf_get_varm_real
+        external        test_nf_get_varm_double
+        external        test_nf_get_att_text
+#if defined(NF_INT1_T)
+        external        test_nf_get_att_int1
+#endif
+#if defined(NF_INT2_T)
+        external        test_nf_get_att_int2
+#endif
+        external        test_nf_get_att_int
+        external        test_nf_get_att_real
+        external        test_nf_get_att_double
+        external        test_nf_inq_att
+        external        test_nf_inq_attname
+        external        test_nf_inq_attid
+        external        test_nf_inq_attlen
+        external        test_nf_inq_atttype
+        external        test_nf_create
+        external        test_nf_redef
+        external        test_nf_enddef
+        external        test_nf_sync
+        external        test_nf_abort
+        external        test_nf_def_dim
+        external        test_nf_rename_dim
+        external        test_nf_def_var
+        external        test_nf_put_var1_text
+#if defined(NF_INT1_T)
+        external        test_nf_put_var1_int1
+#endif
+#if defined(NF_INT2_T)
+        external        test_nf_put_var1_int2
+#endif
+        external        test_nf_put_var1_int
+        external        test_nf_put_var1_real
+        external        test_nf_put_var1_double
+        external        test_nf_put_var_text
+#if defined(NF_INT1_T)
+        external        test_nf_put_var_int1
+#endif
+#if defined(NF_INT2_T)
+        external        test_nf_put_var_int2
+#endif
+        external        test_nf_put_var_int
+        external        test_nf_put_var_real
+        external        test_nf_put_var_double
+        external        test_nf_put_vara_text
+#if defined(NF_INT1_T)
+        external        test_nf_put_vara_int1
+#endif
+#if defined(NF_INT2_T)
+        external        test_nf_put_vara_int2
+#endif
+        external        test_nf_put_vara_int
+        external        test_nf_put_vara_real
+        external        test_nf_put_vara_double
+        external        test_nf_put_vars_text
+#if defined(NF_INT1_T)
+        external        test_nf_put_vars_int1
+#endif
+#if defined(NF_INT2_T)
+        external        test_nf_put_vars_int2
+#endif
+        external        test_nf_put_vars_int
+        external        test_nf_put_vars_real
+        external        test_nf_put_vars_double
+        external        test_nf_put_varm_text
+#if defined(NF_INT1_T)
+        external        test_nf_put_varm_int1
+#endif
+#if defined(NF_INT2_T)
+        external        test_nf_put_varm_int2
+#endif
+        external        test_nf_put_varm_int
+        external        test_nf_put_varm_real
+        external        test_nf_put_varm_double
+        external        test_nf_rename_var
+        external        test_nf_put_att_text
+#if defined(NF_INT1_T)
+        external        test_nf_put_att_int1
+#endif
+#if defined(NF_INT2_T)
+        external        test_nf_put_att_int2
+#endif
+        external        test_nf_put_att_int
+        external        test_nf_put_att_real
+        external        test_nf_put_att_double
+        external        test_nf_copy_att
+        external        test_nf_rename_att
+        external        test_nf_del_att
+        external        test_nf_set_fill
+        external        test_nf_set_default_format
+        external        ignorefpe
+
+        print *, ''
+        print *, '*** Testing netCDF-3 Fortran 77 API.'
+        call ignorefpe(1)
+
+        testfile = 'test.nc'
+        scratch = 'scratch.nc'
+
+        nfailsTotal = 0
+        progname = 'nf_test'
+        max_nmpt = 8
+
+        write(*, *) 'NetCDF version: ', nf_inq_libvers()
+
+C       /* Initialize global variables defining test file */
+        call init_gvars
+
+        call write_file(testfile)
+        if (nfailsTotal .gt. 0) call udexit(1)
+
+C       /* delete any existing scratch netCDF file */
+        status = nf_delete(scratch)
+
+C       /* Test read-only functions, using pregenerated test-file */
+        call test('nf_strerror', test_nf_strerror)
+        call test('nf_open', test_nf_open)
+        call test('nf_close', test_nf_close)
+        call test('nf_inq', test_nf_inq)
+        call test('nf_inq_dimid', test_nf_inq_dimid)
+        call test('nf_inq_dim', test_nf_inq_dim)
+        call test('nf_inq_dimlen', test_nf_inq_dimlen)
+        call test('nf_inq_dimname', test_nf_inq_dimname)
+        call test('nf_inq_varid', test_nf_inq_varid)
+        call test('nf_inq_var', test_nf_inq_var)
+        call test('nf_inq_natts', test_nf_inq_natts)
+        call test('nf_inq_ndims', test_nf_inq_ndims)
+        call test('nf_inq_nvars', test_nf_inq_nvars)
+        call test('nf_inq_unlimdim', test_nf_inq_unlimdim)
+        call test('nf_inq_format', test_nf_inq_format)
+        call test('nf_inq_vardimid', test_nf_inq_vardimid)
+        call test('nf_inq_varname', test_nf_inq_varname)
+        call test('nf_inq_varnatts', test_nf_inq_varnatts)
+        call test('nf_inq_varndims', test_nf_inq_varndims)
+        call test('nf_inq_vartype', test_nf_inq_vartype)
+        call test('nf_get_var1_text', test_nf_get_var1_text)
+#if defined(NF_INT1_T)
+        call test('nf_get_var1_int1', test_nf_get_var1_int1)
+#endif
+#if defined(NF_INT2_T)
+        call test('nf_get_var1_int2', test_nf_get_var1_int2)
+#endif
+        call test('nf_get_var1_int', test_nf_get_var1_int)
+        call test('nf_get_var1_real', test_nf_get_var1_real)
+        call test('nf_get_var1_double', test_nf_get_var1_double)
+        call test('nf_get_var_text', test_nf_get_var_text)
+#if defined(NF_INT1_T)
+        call test('nf_get_var_int1', test_nf_get_var_int1)
+#endif
+#if defined(NF_INT2_T)
+        call test('nf_get_var_int2', test_nf_get_var_int2)
+#endif
+        call test('nf_get_var_int', test_nf_get_var_int)
+        call test('nf_get_var_real', test_nf_get_var_real)
+        call test('nf_get_var_double', test_nf_get_var_double)
+        call test('nf_get_vara_text', test_nf_get_vara_text)
+#if defined(NF_INT1_T)
+        call test('nf_get_vara_int1', test_nf_get_vara_int1)
+#endif
+#if defined(NF_INT2_T)
+        call test('nf_get_vara_int2', test_nf_get_vara_int2)
+#endif
+        call test('nf_get_vara_int', test_nf_get_vara_int)
+        call test('nf_get_vara_real', test_nf_get_vara_real)
+        call test('nf_get_vara_double', test_nf_get_vara_double)
+        call test('nf_get_vars_text', test_nf_get_vars_text)
+#if defined(NF_INT1_T)
+        call test('nf_get_vars_int1', test_nf_get_vars_int1)
+#endif
+#if defined(NF_INT2_T)
+        call test('nf_get_vars_int2', test_nf_get_vars_int2)
+#endif
+        call test('nf_get_vars_int', test_nf_get_vars_int)
+        call test('nf_get_vars_real', test_nf_get_vars_real)
+        call test('nf_get_vars_double', test_nf_get_vars_double)
+        call test('nf_get_varm_text', test_nf_get_varm_text)
+#if defined(NF_INT1_T)
+        call test('nf_get_varm_int1', test_nf_get_varm_int1)
+#endif
+#if defined(NF_INT2_T)
+        call test('nf_get_varm_int2', test_nf_get_varm_int2)
+#endif
+        call test('nf_get_varm_int', test_nf_get_varm_int)
+        call test('nf_get_varm_real', test_nf_get_varm_real)
+        call test('nf_get_varm_double', test_nf_get_varm_double)
+        call test('nf_get_att_text', test_nf_get_att_text)
+#if defined(NF_INT1_T)
+        call test('nf_get_att_int1', test_nf_get_att_int1)
+#endif
+#if defined(NF_INT2_T)
+        call test('nf_get_att_int2', test_nf_get_att_int2)
+#endif
+        call test('nf_get_att_int', test_nf_get_att_int)
+        call test('nf_get_att_real', test_nf_get_att_real)
+        call test('nf_get_att_double', test_nf_get_att_double)
+        call test('nf_inq_att', test_nf_inq_att)
+        call test('nf_inq_attname', test_nf_inq_attname)
+        call test('nf_inq_attid', test_nf_inq_attid)
+        call test('nf_inq_attlen', test_nf_inq_attlen)
+        call test('nf_inq_atttype', test_nf_inq_atttype)
+
+C           /* Test write functions */
+        call test('nf_create', test_nf_create)
+        call test('nf_redef', test_nf_redef)
+        call test('nf_enddef', test_nf_enddef)
+        call test('nf_sync', test_nf_sync)
+        call test('nf_abort', test_nf_abort)
+        call test('nf_def_dim', test_nf_def_dim)
+        call test('nf_rename_dim', test_nf_rename_dim)
+        call test('nf_def_var', test_nf_def_var)
+        call test('nf_put_var1_text', test_nf_put_var1_text)
+#if defined(NF_INT1_T)
+        call test('nf_put_var1_int1', test_nf_put_var1_int1)
+#endif
+#if defined(NF_INT2_T)
+        call test('nf_put_var1_int2', test_nf_put_var1_int2)
+#endif
+        call test('nf_put_var1_int', test_nf_put_var1_int)
+        call test('nf_put_var1_real', test_nf_put_var1_real)
+        call test('nf_put_var1_double', test_nf_put_var1_double)
+        call test('nf_put_var_text', test_nf_put_var_text)
+#if defined(NF_INT1_T)
+        call test('nf_put_var_int1', test_nf_put_var_int1)
+#endif
+#if defined(NF_INT2_T)
+        call test('nf_put_var_int2', test_nf_put_var_int2)
+#endif
+        call test('nf_put_var_int', test_nf_put_var_int)
+        call test('nf_put_var_real', test_nf_put_var_real)
+        call test('nf_put_var_double', test_nf_put_var_double)
+        call test('nf_put_vara_text', test_nf_put_vara_text)
+#if defined(NF_INT1_T)
+        call test('nf_put_vara_int1', test_nf_put_vara_int1)
+#endif
+#if defined(NF_INT2_T)
+        call test('nf_put_vara_int2', test_nf_put_vara_int2)
+#endif
+        call test('nf_put_vara_int', test_nf_put_vara_int)
+        call test('nf_put_vara_real', test_nf_put_vara_real)
+        call test('nf_put_vara_double', test_nf_put_vara_double)
+        call test('nf_put_vars_text', test_nf_put_vars_text)
+#if defined(NF_INT1_T)
+        call test('nf_put_vars_int1', test_nf_put_vars_int1)
+#endif
+#if defined(NF_INT2_T)
+        call test('nf_put_vars_int2', test_nf_put_vars_int2)
+#endif
+        call test('nf_put_vars_int', test_nf_put_vars_int)
+        call test('nf_put_vars_real', test_nf_put_vars_real)
+        call test('nf_put_vars_double', test_nf_put_vars_double)
+        call test('nf_put_varm_text', test_nf_put_varm_text)
+#if defined(NF_INT1_T)
+        call test('nf_put_varm_int1', test_nf_put_varm_int1)
+#endif
+#if defined(NF_INT2_T)
+        call test('nf_put_varm_int2', test_nf_put_varm_int2)
+#endif
+        call test('nf_put_varm_int', test_nf_put_varm_int)
+        call test('nf_put_varm_real', test_nf_put_varm_real)
+        call test('nf_put_varm_double', test_nf_put_varm_double)
+        call test('nf_rename_var', test_nf_rename_var)
+        call test('nf_put_att_text', test_nf_put_att_text)
+#if defined(NF_INT1_T)
+        call test('nf_put_att_int1', test_nf_put_att_int1)
+#endif
+#if defined(NF_INT2_T)
+        call test('nf_put_att_int2', test_nf_put_att_int2)
+#endif
+        call test('nf_put_att_int', test_nf_put_att_int)
+        call test('nf_put_att_real', test_nf_put_att_real)
+        call test('nf_put_att_double', test_nf_put_att_double)
+        call test('nf_copy_att', test_nf_copy_att)
+        call test('nf_rename_att', test_nf_rename_att)
+        call test('nf_del_att', test_nf_del_att)
+        call test('nf_set_fill', test_nf_set_fill)
+        call test('nf_set_default_format', 
+     +       test_nf_set_default_format)
+
+        print *,'Total number of failures: ', nfailsTotal
+        if (nfailsTotal .ne. 0) stop 2
+        print *,'*** SUCCESS!'        
+
+        end
diff --git a/nf_test/test03_get.F b/nf_test/test03_get.F
new file mode 100755
index 0000000..5d72d68
--- /dev/null
+++ b/nf_test/test03_get.F
@@ -0,0 +1,5601 @@
+
+#include "../fortran/nf03config.inc"
+C Do not edit this file. It is produced from the corresponding .m4 source */
+
+C*********************************************************************
+C   Copyright 1996, UCAR/Unidata
+C   See netcdf/COPYRIGHT file for copying and redistribution conditions.
+C   $Id: test_get.m4,v 1.11 2008/04/30 16:50:46 ed Exp $
+C*********************************************************************
+
+        subroutine test_nf_get_var1_text()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        integer nok      
+        integer index(MAX_RANK)
+        doubleprecision expect
+        logical canConvert     
+        character    value
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_TEXT .eq. NFT_TEXT)
+            do 2, j = 1, var_rank(i)
+                index(j) = 1
+2           continue
+            err = nf_get_var1_text(BAD_ID, i, index, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_var1_text(ncid, BAD_VARID,
+     +                  index, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                index(j) = var_shape(j,i) + 1
+                err = nf_get_var1_text(ncid, i, index, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad index: ', err)
+                endif
+                index(j) = 1
+3           continue
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0)
+     +              call error('error in index2indexes 1')
+                expect = hash4( var_type(i), var_rank(i), index, 
+     +                          NFT_TEXT )
+                err = nf_get_var1_text(ncid, i, index,
+     +                          value)
+                if (canConvert) then
+                    if (inRange3(expect,var_type(i), 
+     +                           NFT_TEXT)) then
+                        if (in_internal_range(NFT_TEXT,
+     +                                        expect)) then
+                            if (err .ne. 0) then
+                                call errore('nf_get_var: ', err)
+                            else
+                                val = ichar(value)
+                                if (.not. equal(val, expect, 
+     +                                          var_type(i), 
+     +                                          NFT_TEXT)) then
+                                    call errord('unexpected: ', val)
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('Range error: ', err)
+                        end if
+                    else
+                        if (err .ne. 0  .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ', err)
+                    end if
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+4           continue
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ',  err)
+        call print_nok(nok)
+        end
+
+#ifdef NF_INT1_T
+        subroutine test_nf_get_var1_int1()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        integer nok      
+        integer index(MAX_RANK)
+        doubleprecision expect
+        logical canConvert     
+        NF_INT1_T    value
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT1 .eq. NFT_TEXT)
+            do 2, j = 1, var_rank(i)
+                index(j) = 1
+2           continue
+            err = nf_get_var1_int1(BAD_ID, i, index, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_var1_int1(ncid, BAD_VARID,
+     +                  index, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                index(j) = var_shape(j,i) + 1
+                err = nf_get_var1_int1(ncid, i, index, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad index: ', err)
+                endif
+                index(j) = 1
+3           continue
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0)
+     +              call error('error in index2indexes 1')
+                expect = hash4( var_type(i), var_rank(i), index, 
+     +                          NFT_INT1 )
+                err = nf_get_var1_int1(ncid, i, index,
+     +                          value)
+                if (canConvert) then
+                    if (inRange3(expect,var_type(i), 
+     +                           NFT_INT1)) then
+                        if (in_internal_range(NFT_INT1,
+     +                                        expect)) then
+                            if (err .ne. 0) then
+                                call errore('nf_get_var: ', err)
+                            else
+                                val = value
+                                if (.not. equal(val, expect, 
+     +                                          var_type(i), 
+     +                                          NFT_INT1)) then
+                                    call errord('unexpected: ', val)
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('Range error: ', err)
+                        end if
+                    else
+                        if (err .ne. 0  .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ', err)
+                    end if
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+4           continue
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ',  err)
+        call print_nok(nok)
+        end
+
+#endif
+#ifdef NF_INT2_T
+        subroutine test_nf_get_var1_int2()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        integer nok      
+        integer index(MAX_RANK)
+        doubleprecision expect
+        logical canConvert     
+        NF_INT2_T    value
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT2 .eq. NFT_TEXT)
+            do 2, j = 1, var_rank(i)
+                index(j) = 1
+2           continue
+            err = nf_get_var1_int2(BAD_ID, i, index, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_var1_int2(ncid, BAD_VARID,
+     +                  index, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                index(j) = var_shape(j,i) + 1
+                err = nf_get_var1_int2(ncid, i, index, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad index: ', err)
+                endif
+                index(j) = 1
+3           continue
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0)
+     +              call error('error in index2indexes 1')
+                expect = hash4( var_type(i), var_rank(i), index, 
+     +                          NFT_INT2 )
+                err = nf_get_var1_int2(ncid, i, index,
+     +                          value)
+                if (canConvert) then
+                    if (inRange3(expect,var_type(i), 
+     +                           NFT_INT2)) then
+                        if (in_internal_range(NFT_INT2,
+     +                                        expect)) then
+                            if (err .ne. 0) then
+                                call errore('nf_get_var: ', err)
+                            else
+                                val = value
+                                if (.not. equal(val, expect, 
+     +                                          var_type(i), 
+     +                                          NFT_INT2)) then
+                                    call errord('unexpected: ', val)
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('Range error: ', err)
+                        end if
+                    else
+                        if (err .ne. 0  .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ', err)
+                    end if
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+4           continue
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ',  err)
+        call print_nok(nok)
+        end
+
+#endif
+        subroutine test_nf_get_var1_int()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        integer nok      
+        integer index(MAX_RANK)
+        doubleprecision expect
+        logical canConvert     
+        integer    value
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT .eq. NFT_TEXT)
+            do 2, j = 1, var_rank(i)
+                index(j) = 1
+2           continue
+            err = nf_get_var1_int(BAD_ID, i, index, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_var1_int(ncid, BAD_VARID,
+     +                  index, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                index(j) = var_shape(j,i) + 1
+                err = nf_get_var1_int(ncid, i, index, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad index: ', err)
+                endif
+                index(j) = 1
+3           continue
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0)
+     +              call error('error in index2indexes 1')
+                expect = hash4( var_type(i), var_rank(i), index, 
+     +                          NFT_INT )
+                err = nf_get_var1_int(ncid, i, index,
+     +                          value)
+                if (canConvert) then
+                    if (inRange3(expect,var_type(i), 
+     +                           NFT_INT)) then
+                        if (in_internal_range(NFT_INT,
+     +                                        expect)) then
+                            if (err .ne. 0) then
+                                call errore('nf_get_var: ', err)
+                            else
+                                val = value
+                                if (.not. equal(val, expect, 
+     +                                          var_type(i), 
+     +                                          NFT_INT)) then
+                                    call errord('unexpected: ', val)
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('Range error: ', err)
+                        end if
+                    else
+                        if (err .ne. 0  .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ', err)
+                    end if
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+4           continue
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ',  err)
+        call print_nok(nok)
+        end
+
+        subroutine test_nf_get_var1_real()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        integer nok      
+        integer index(MAX_RANK)
+        doubleprecision expect
+        logical canConvert     
+        real    value
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_REAL .eq. NFT_TEXT)
+            do 2, j = 1, var_rank(i)
+                index(j) = 1
+2           continue
+            err = nf_get_var1_real(BAD_ID, i, index, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_var1_real(ncid, BAD_VARID,
+     +                  index, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                index(j) = var_shape(j,i) + 1
+                err = nf_get_var1_real(ncid, i, index, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad index: ', err)
+                endif
+                index(j) = 1
+3           continue
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0)
+     +              call error('error in index2indexes 1')
+                expect = hash4( var_type(i), var_rank(i), index, 
+     +                          NFT_REAL )
+                err = nf_get_var1_real(ncid, i, index,
+     +                          value)
+                if (canConvert) then
+                    if (inRange3(expect,var_type(i), 
+     +                           NFT_REAL)) then
+                        if (in_internal_range(NFT_REAL,
+     +                                        expect)) then
+                            if (err .ne. 0) then
+                                call errore('nf_get_var: ', err)
+                            else
+                                val = value
+                                if (.not. equal(val, expect, 
+     +                                          var_type(i), 
+     +                                          NFT_REAL)) then
+                                    call errord('unexpected: ', val)
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('Range error: ', err)
+                        end if
+                    else
+                        if (err .ne. 0  .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ', err)
+                    end if
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+4           continue
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ',  err)
+        call print_nok(nok)
+        end
+
+        subroutine test_nf_get_var1_double()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        integer nok      
+        integer index(MAX_RANK)
+        doubleprecision expect
+        logical canConvert     
+        doubleprecision    value
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_DOUBLE .eq. NFT_TEXT)
+            do 2, j = 1, var_rank(i)
+                index(j) = 1
+2           continue
+            err = nf_get_var1_double(BAD_ID, i, index, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_var1_double(ncid, BAD_VARID,
+     +                  index, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                index(j) = var_shape(j,i) + 1
+                err = nf_get_var1_double(ncid, i, index, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad index: ', err)
+                endif
+                index(j) = 1
+3           continue
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0)
+     +              call error('error in index2indexes 1')
+                expect = hash4( var_type(i), var_rank(i), index, 
+     +                          NFT_DOUBLE )
+                err = nf_get_var1_double(ncid, i, index,
+     +                          value)
+                if (canConvert) then
+                    if (inRange3(expect,var_type(i), 
+     +                           NFT_DOUBLE)) then
+                        if (in_internal_range(NFT_DOUBLE,
+     +                                        expect)) then
+                            if (err .ne. 0) then
+                                call errore('nf_get_var: ', err)
+                            else
+                                val = value
+                                if (.not. equal(val, expect, 
+     +                                          var_type(i), 
+     +                                          NFT_DOUBLE)) then
+                                    call errord('unexpected: ', val)
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('Range error: ', err)
+                        end if
+                    else
+                        if (err .ne. 0  .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ', err)
+                    end if
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+4           continue
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ',  err)
+        call print_nok(nok)
+        end
+
+
+        subroutine test_nf_get_var_text()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nok      
+        integer index(MAX_RANK)
+        doubleprecision expect(MAX_NELS)
+        logical canConvert     
+        character    value(MAX_NELS)
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_TEXT .eq. NFT_TEXT)
+            err = nf_get_var_text(BAD_ID, i, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_var_text(ncid, BAD_VARID, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            nels = 1
+            do 3, j = 1, var_rank(i)
+                nels = nels * var_shape(j,i)
+3           continue
+            allInExtRange = .true.
+            allInIntRange = .true.
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0)
+     +              call error('error in index2indexes 1')
+                expect(j) = hash4( var_type(i), var_rank(i), index, 
+     +                          NFT_TEXT )
+                if (inRange3(expect(j),var_type(i), NFT_TEXT)) then
+                    allInIntRange = allInIntRange .and.
+     +                  in_internal_range(NFT_TEXT, expect(j))
+                else
+                    allInExtRange = .false.
+                end if
+4           continue
+            err = nf_get_var_text(ncid, i, value)
+            if (canConvert) then
+                if (allInExtRange) then
+                    if (allInIntRange) then
+                        if (err .ne. 0) 
+     +                      call errore('nf_get_var: ', err)
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('Range error: ', err)
+                    endif
+                else
+                    if (err .ne. 0  .and. err .ne. NF_ERANGE)
+     +                  call errore('Range error: ', err)
+                endif
+                do 5, j = 1, var_nels(i)
+                    if (inRange3(expect(j),var_type(i),
+     +                           NFT_TEXT) .and.
+     +                  in_internal_range(NFT_TEXT,
+     +                                          expect(j))) then
+                        val = ichar(value(j))
+                        if (.not. equal(val, expect(j), 
+     +                                  var_type(i), 
+     +                                  NFT_TEXT)) then
+                            call errord('unexpected: ', val)
+                        else
+                            nok = nok + 1
+                        end if
+                    endif
+5               continue
+            else
+                if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+            end if
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ',  err)
+        call print_nok(nok)
+        end
+
+#ifdef NF_INT1_T
+        subroutine test_nf_get_var_int1()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nok      
+        integer index(MAX_RANK)
+        doubleprecision expect(MAX_NELS)
+        logical canConvert     
+        NF_INT1_T    value(MAX_NELS)
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT1 .eq. NFT_TEXT)
+            err = nf_get_var_int1(BAD_ID, i, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_var_int1(ncid, BAD_VARID, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            nels = 1
+            do 3, j = 1, var_rank(i)
+                nels = nels * var_shape(j,i)
+3           continue
+            allInExtRange = .true.
+            allInIntRange = .true.
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0)
+     +              call error('error in index2indexes 1')
+                expect(j) = hash4( var_type(i), var_rank(i), index, 
+     +                          NFT_INT1 )
+                if (inRange3(expect(j),var_type(i), NFT_INT1)) then
+                    allInIntRange = allInIntRange .and.
+     +                  in_internal_range(NFT_INT1, expect(j))
+                else
+                    allInExtRange = .false.
+                end if
+4           continue
+            err = nf_get_var_int1(ncid, i, value)
+            if (canConvert) then
+                if (allInExtRange) then
+                    if (allInIntRange) then
+                        if (err .ne. 0) 
+     +                      call errore('nf_get_var: ', err)
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('Range error: ', err)
+                    endif
+                else
+                    if (err .ne. 0  .and. err .ne. NF_ERANGE)
+     +                  call errore('Range error: ', err)
+                endif
+                do 5, j = 1, var_nels(i)
+                    if (inRange3(expect(j),var_type(i),
+     +                           NFT_INT1) .and.
+     +                  in_internal_range(NFT_INT1,
+     +                                          expect(j))) then
+                        val = value(j)
+                        if (.not. equal(val, expect(j), 
+     +                                  var_type(i), 
+     +                                  NFT_INT1)) then
+                            call errord('unexpected: ', val)
+                        else
+                            nok = nok + 1
+                        end if
+                    endif
+5               continue
+            else
+                if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+            end if
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ',  err)
+        call print_nok(nok)
+        end
+
+#endif
+#ifdef NF_INT2_T
+        subroutine test_nf_get_var_int2()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nok      
+        integer index(MAX_RANK)
+        doubleprecision expect(MAX_NELS)
+        logical canConvert     
+        NF_INT2_T    value(MAX_NELS)
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT2 .eq. NFT_TEXT)
+            err = nf_get_var_int2(BAD_ID, i, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_var_int2(ncid, BAD_VARID, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            nels = 1
+            do 3, j = 1, var_rank(i)
+                nels = nels * var_shape(j,i)
+3           continue
+            allInExtRange = .true.
+            allInIntRange = .true.
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0)
+     +              call error('error in index2indexes 1')
+                expect(j) = hash4( var_type(i), var_rank(i), index, 
+     +                          NFT_INT2 )
+                if (inRange3(expect(j),var_type(i), NFT_INT2)) then
+                    allInIntRange = allInIntRange .and.
+     +                  in_internal_range(NFT_INT2, expect(j))
+                else
+                    allInExtRange = .false.
+                end if
+4           continue
+            err = nf_get_var_int2(ncid, i, value)
+            if (canConvert) then
+                if (allInExtRange) then
+                    if (allInIntRange) then
+                        if (err .ne. 0) 
+     +                      call errore('nf_get_var: ', err)
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('Range error: ', err)
+                    endif
+                else
+                    if (err .ne. 0  .and. err .ne. NF_ERANGE)
+     +                  call errore('Range error: ', err)
+                endif
+                do 5, j = 1, var_nels(i)
+                    if (inRange3(expect(j),var_type(i),
+     +                           NFT_INT2) .and.
+     +                  in_internal_range(NFT_INT2,
+     +                                          expect(j))) then
+                        val = value(j)
+                        if (.not. equal(val, expect(j), 
+     +                                  var_type(i), 
+     +                                  NFT_INT2)) then
+                            call errord('unexpected: ', val)
+                        else
+                            nok = nok + 1
+                        end if
+                    endif
+5               continue
+            else
+                if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+            end if
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ',  err)
+        call print_nok(nok)
+        end
+
+#endif
+        subroutine test_nf_get_var_int()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nok      
+        integer index(MAX_RANK)
+        doubleprecision expect(MAX_NELS)
+        logical canConvert     
+        integer    value(MAX_NELS)
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT .eq. NFT_TEXT)
+            err = nf_get_var_int(BAD_ID, i, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_var_int(ncid, BAD_VARID, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            nels = 1
+            do 3, j = 1, var_rank(i)
+                nels = nels * var_shape(j,i)
+3           continue
+            allInExtRange = .true.
+            allInIntRange = .true.
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0)
+     +              call error('error in index2indexes 1')
+                expect(j) = hash4( var_type(i), var_rank(i), index, 
+     +                          NFT_INT )
+                if (inRange3(expect(j),var_type(i), NFT_INT)) then
+                    allInIntRange = allInIntRange .and.
+     +                  in_internal_range(NFT_INT, expect(j))
+                else
+                    allInExtRange = .false.
+                end if
+4           continue
+            err = nf_get_var_int(ncid, i, value)
+            if (canConvert) then
+                if (allInExtRange) then
+                    if (allInIntRange) then
+                        if (err .ne. 0) 
+     +                      call errore('nf_get_var: ', err)
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('Range error: ', err)
+                    endif
+                else
+                    if (err .ne. 0  .and. err .ne. NF_ERANGE)
+     +                  call errore('Range error: ', err)
+                endif
+                do 5, j = 1, var_nels(i)
+                    if (inRange3(expect(j),var_type(i),
+     +                           NFT_INT) .and.
+     +                  in_internal_range(NFT_INT,
+     +                                          expect(j))) then
+                        val = value(j)
+                        if (.not. equal(val, expect(j), 
+     +                                  var_type(i), 
+     +                                  NFT_INT)) then
+                            call errord('unexpected: ', val)
+                        else
+                            nok = nok + 1
+                        end if
+                    endif
+5               continue
+            else
+                if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+            end if
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ',  err)
+        call print_nok(nok)
+        end
+
+        subroutine test_nf_get_var_real()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nok      
+        integer index(MAX_RANK)
+        doubleprecision expect(MAX_NELS)
+        logical canConvert     
+        real    value(MAX_NELS)
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_REAL .eq. NFT_TEXT)
+            err = nf_get_var_real(BAD_ID, i, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_var_real(ncid, BAD_VARID, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            nels = 1
+            do 3, j = 1, var_rank(i)
+                nels = nels * var_shape(j,i)
+3           continue
+            allInExtRange = .true.
+            allInIntRange = .true.
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0)
+     +              call error('error in index2indexes 1')
+                expect(j) = hash4( var_type(i), var_rank(i), index, 
+     +                          NFT_REAL )
+                if (inRange3(expect(j),var_type(i), NFT_REAL)) then
+                    allInIntRange = allInIntRange .and.
+     +                  in_internal_range(NFT_REAL, expect(j))
+                else
+                    allInExtRange = .false.
+                end if
+4           continue
+            err = nf_get_var_real(ncid, i, value)
+            if (canConvert) then
+                if (allInExtRange) then
+                    if (allInIntRange) then
+                        if (err .ne. 0) 
+     +                      call errore('nf_get_var: ', err)
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('Range error: ', err)
+                    endif
+                else
+                    if (err .ne. 0  .and. err .ne. NF_ERANGE)
+     +                  call errore('Range error: ', err)
+                endif
+                do 5, j = 1, var_nels(i)
+                    if (inRange3(expect(j),var_type(i),
+     +                           NFT_REAL) .and.
+     +                  in_internal_range(NFT_REAL,
+     +                                          expect(j))) then
+                        val = value(j)
+                        if (.not. equal(val, expect(j), 
+     +                                  var_type(i), 
+     +                                  NFT_REAL)) then
+                            call errord('unexpected: ', val)
+                        else
+                            nok = nok + 1
+                        end if
+                    endif
+5               continue
+            else
+                if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+            end if
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ',  err)
+        call print_nok(nok)
+        end
+
+        subroutine test_nf_get_var_double()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nok      
+        integer index(MAX_RANK)
+        doubleprecision expect(MAX_NELS)
+        logical canConvert     
+        doubleprecision    value(MAX_NELS)
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_DOUBLE .eq. NFT_TEXT)
+            err = nf_get_var_double(BAD_ID, i, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_var_double(ncid, BAD_VARID, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            nels = 1
+            do 3, j = 1, var_rank(i)
+                nels = nels * var_shape(j,i)
+3           continue
+            allInExtRange = .true.
+            allInIntRange = .true.
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0)
+     +              call error('error in index2indexes 1')
+                expect(j) = hash4( var_type(i), var_rank(i), index, 
+     +                          NFT_DOUBLE )
+                if (inRange3(expect(j),var_type(i), NFT_DOUBLE)) then
+                    allInIntRange = allInIntRange .and.
+     +                  in_internal_range(NFT_DOUBLE, expect(j))
+                else
+                    allInExtRange = .false.
+                end if
+4           continue
+            err = nf_get_var_double(ncid, i, value)
+            if (canConvert) then
+                if (allInExtRange) then
+                    if (allInIntRange) then
+                        if (err .ne. 0) 
+     +                      call errore('nf_get_var: ', err)
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('Range error: ', err)
+                    endif
+                else
+                    if (err .ne. 0  .and. err .ne. NF_ERANGE)
+     +                  call errore('Range error: ', err)
+                endif
+                do 5, j = 1, var_nels(i)
+                    if (inRange3(expect(j),var_type(i),
+     +                           NFT_DOUBLE) .and.
+     +                  in_internal_range(NFT_DOUBLE,
+     +                                          expect(j))) then
+                        val = value(j)
+                        if (.not. equal(val, expect(j), 
+     +                                  var_type(i), 
+     +                                  NFT_DOUBLE)) then
+                            call errord('unexpected: ', val)
+                        else
+                            nok = nok + 1
+                        end if
+                    endif
+5               continue
+            else
+                if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+            end if
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ',  err)
+        call print_nok(nok)
+        end
+
+
+        subroutine test_nf_get_vara_text()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nslabs
+        integer nok      
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer mid(MAX_RANK)
+        logical canConvert     
+        character    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv. 
+     +                   (NFT_TEXT .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK)) stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS)) stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+2           continue
+            err = nf_get_vara_text(BAD_ID, i, start,
+     +                  edge, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_vara_text(ncid, BAD_VARID, start, 
+     +                           edge, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                start(j) = var_shape(j,i) + 1
+                err = nf_get_vara_text(ncid, i, start,
+     +                               edge, value)
+                if (canConvert .and. err .ne. NF_EINVALCOORDS)
+     +              call errore('bad index: ', err)
+                start(j) = 1
+                edge(j) = var_shape(j,i) + 1
+                err = nf_get_vara_text(ncid, i, start,
+     +                               edge, value)
+                if (canConvert .and. err .ne. NF_EEDGE)
+     +              call errore('bad edge: ', err)
+                edge(j) = 1
+3           continue
+
+C           /* Check non-scalars for correct error returned even when */
+C           /* there is nothing to get (edge(j).eq.0) */
+            if (var_rank(i) .gt. 0) then
+                do 10, j = 1, var_rank(i)
+                    edge(j) = 0
+10              continue
+                err = nf_get_vara_text(BAD_ID, i, start,
+     +                  edge, value)
+                if (err .ne. NF_EBADID) 
+     +              call errore('bad ncid: ', err)
+                err = nf_get_vara_text(ncid, BAD_VARID,
+     +                  start, edge, value)
+                if (err .ne. NF_ENOTVAR) 
+     +              call errore('bad var id: ', err)
+                do 11, j = 1, var_rank(i)
+                    if (var_dimid(j,i) .gt. 1) then     !/* skip record dim */
+                        start(j) = var_shape(j,i) + 1
+                        err = nf_get_vara_text(ncid, i,
+     +                          start, edge, value)
+                        if (canConvert .and. err .ne. NF_EINVALCOORDS)
+     +                      call errore('bad start: ', err)
+                        start(j) = 1
+                    endif
+11              continue
+                err = nf_get_vara_text(ncid, i, start,
+     +                          edge, value)
+                if (canConvert) then
+                    if (err .ne. 0) 
+     +                  call error(nf_strerror(err))
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                endif
+                do 12, j = 1, var_rank(i)
+                    edge(j) = 1
+12              continue
+            endif
+
+C           Choose a random point dividing each dim into 2 parts
+C           get 2^rank (nslabs) slabs so defined
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+C           bits of k determine whether to get lower or upper part of dim 
+            do 5, k = 1, nslabs
+                nels = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift((k-1), -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    nels = nels * edge(j)
+6               continue
+                allInIntRange = .true.
+                allInExtRange = .true.
+                do 7, j = 1, nels
+                    err = index2indexes(j, var_rank(i), edge, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes 1')
+                    do 8, d = 1, var_rank(i)
+                        index(d) = index(d) + start(d) - 1
+8                   continue
+                    expect(j) = hash4(var_type(i), var_rank(i), index, 
+     +                                NFT_TEXT)
+                    if (inRange3(expect(j),var_type(i), 
+     +                           NFT_TEXT)) then
+                        allInIntRange = 
+     +                      allInIntRange .and.
+     +                      in_internal_range(NFT_TEXT, expect(j))
+                    else
+                        allInExtRange = .false.
+                    end if
+7               continue
+                err = nf_get_vara_text(ncid, i, start,
+     +                          edge, value)
+                if (canConvert) then
+                    if (allInExtRange) then
+                        if (allInIntRange) then
+                            if (err .ne. 0)
+     +                          call errore('nf_get_vara_text:', err)
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('Range error: ', err)
+                        end if
+                    else
+                        if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ', err)
+                    end if
+                    do 9, j = 1, nels
+                        if (inRange3(expect(j),var_type(i),
+     +                               NFT_TEXT) .and.
+     +                      in_internal_range(NFT_TEXT, expect(j)))
+     +                          then
+                            val = ichar(value(j))
+                            if (.not.equal(val,expect(j),
+     +                                     var_type(i),NFT_TEXT)) 
+     +                              then
+                                call error(
+     +                              'value read not that expected')
+                                if (verbose) then
+                                    call error(' ')
+                                    call errori('varid: ', i)
+                                    call errorc('var_name: ',
+     +                                  var_name(i))
+                                    call errori('element number: %d ', 
+     +                                          j)
+                                    call errord('expect: ', expect(j))
+                                    call errord('got: ', val)
+                                end if
+                            else
+                                nok = nok + 1
+                            end if
+                        end if
+9                   continue
+                else
+                    if (nels .gt. 0  .and. err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+5           continue
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errorc('nf_close: ', nf_strerror(err))
+        call print_nok(nok)
+        end
+
+#ifdef NF_INT1_T
+        subroutine test_nf_get_vara_int1()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nslabs
+        integer nok      
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer mid(MAX_RANK)
+        logical canConvert     
+        NF_INT1_T    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv. 
+     +                   (NFT_INT1 .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK)) stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS)) stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+2           continue
+            err = nf_get_vara_int1(BAD_ID, i, start,
+     +                  edge, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_vara_int1(ncid, BAD_VARID, start, 
+     +                           edge, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                start(j) = var_shape(j,i) + 1
+                err = nf_get_vara_int1(ncid, i, start,
+     +                               edge, value)
+                if (canConvert .and. err .ne. NF_EINVALCOORDS)
+     +              call errore('bad index: ', err)
+                start(j) = 1
+                edge(j) = var_shape(j,i) + 1
+                err = nf_get_vara_int1(ncid, i, start,
+     +                               edge, value)
+                if (canConvert .and. err .ne. NF_EEDGE)
+     +              call errore('bad edge: ', err)
+                edge(j) = 1
+3           continue
+
+C           /* Check non-scalars for correct error returned even when */
+C           /* there is nothing to get (edge(j).eq.0) */
+            if (var_rank(i) .gt. 0) then
+                do 10, j = 1, var_rank(i)
+                    edge(j) = 0
+10              continue
+                err = nf_get_vara_int1(BAD_ID, i, start,
+     +                  edge, value)
+                if (err .ne. NF_EBADID) 
+     +              call errore('bad ncid: ', err)
+                err = nf_get_vara_int1(ncid, BAD_VARID,
+     +                  start, edge, value)
+                if (err .ne. NF_ENOTVAR) 
+     +              call errore('bad var id: ', err)
+                do 11, j = 1, var_rank(i)
+                    if (var_dimid(j,i) .gt. 1) then     !/* skip record dim */
+                        start(j) = var_shape(j,i) + 1
+                        err = nf_get_vara_int1(ncid, i,
+     +                          start, edge, value)
+                        if (canConvert .and. err .ne. NF_EINVALCOORDS)
+     +                      call errore('bad start: ', err)
+                        start(j) = 1
+                    endif
+11              continue
+                err = nf_get_vara_int1(ncid, i, start,
+     +                          edge, value)
+                if (canConvert) then
+                    if (err .ne. 0) 
+     +                  call error(nf_strerror(err))
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                endif
+                do 12, j = 1, var_rank(i)
+                    edge(j) = 1
+12              continue
+            endif
+
+C           Choose a random point dividing each dim into 2 parts
+C           get 2^rank (nslabs) slabs so defined
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+C           bits of k determine whether to get lower or upper part of dim 
+            do 5, k = 1, nslabs
+                nels = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift((k-1), -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    nels = nels * edge(j)
+6               continue
+                allInIntRange = .true.
+                allInExtRange = .true.
+                do 7, j = 1, nels
+                    err = index2indexes(j, var_rank(i), edge, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes 1')
+                    do 8, d = 1, var_rank(i)
+                        index(d) = index(d) + start(d) - 1
+8                   continue
+                    expect(j) = hash4(var_type(i), var_rank(i), index, 
+     +                                NFT_INT1)
+                    if (inRange3(expect(j),var_type(i), 
+     +                           NFT_INT1)) then
+                        allInIntRange = 
+     +                      allInIntRange .and.
+     +                      in_internal_range(NFT_INT1, expect(j))
+                    else
+                        allInExtRange = .false.
+                    end if
+7               continue
+                err = nf_get_vara_int1(ncid, i, start,
+     +                          edge, value)
+                if (canConvert) then
+                    if (allInExtRange) then
+                        if (allInIntRange) then
+                            if (err .ne. 0)
+     +                          call errore('nf_get_vara_int1:', err)
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('Range error: ', err)
+                        end if
+                    else
+                        if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ', err)
+                    end if
+                    do 9, j = 1, nels
+                        if (inRange3(expect(j),var_type(i),
+     +                               NFT_INT1) .and.
+     +                      in_internal_range(NFT_INT1, expect(j)))
+     +                          then
+                            val = value(j)
+                            if (.not.equal(val,expect(j),
+     +                                     var_type(i),NFT_INT1)) 
+     +                              then
+                                call error(
+     +                              'value read not that expected')
+                                if (verbose) then
+                                    call error(' ')
+                                    call errori('varid: ', i)
+                                    call errorc('var_name: ',
+     +                                  var_name(i))
+                                    call errori('element number: %d ', 
+     +                                          j)
+                                    call errord('expect: ', expect(j))
+                                    call errord('got: ', val)
+                                end if
+                            else
+                                nok = nok + 1
+                            end if
+                        end if
+9                   continue
+                else
+                    if (nels .gt. 0  .and. err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+5           continue
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errorc('nf_close: ', nf_strerror(err))
+        call print_nok(nok)
+        end
+
+#endif
+#ifdef NF_INT2_T
+        subroutine test_nf_get_vara_int2()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nslabs
+        integer nok      
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer mid(MAX_RANK)
+        logical canConvert     
+        NF_INT2_T    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv. 
+     +                   (NFT_INT2 .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK)) stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS)) stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+2           continue
+            err = nf_get_vara_int2(BAD_ID, i, start,
+     +                  edge, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_vara_int2(ncid, BAD_VARID, start, 
+     +                           edge, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                start(j) = var_shape(j,i) + 1
+                err = nf_get_vara_int2(ncid, i, start,
+     +                               edge, value)
+                if (canConvert .and. err .ne. NF_EINVALCOORDS)
+     +              call errore('bad index: ', err)
+                start(j) = 1
+                edge(j) = var_shape(j,i) + 1
+                err = nf_get_vara_int2(ncid, i, start,
+     +                               edge, value)
+                if (canConvert .and. err .ne. NF_EEDGE)
+     +              call errore('bad edge: ', err)
+                edge(j) = 1
+3           continue
+
+C           /* Check non-scalars for correct error returned even when */
+C           /* there is nothing to get (edge(j).eq.0) */
+            if (var_rank(i) .gt. 0) then
+                do 10, j = 1, var_rank(i)
+                    edge(j) = 0
+10              continue
+                err = nf_get_vara_int2(BAD_ID, i, start,
+     +                  edge, value)
+                if (err .ne. NF_EBADID) 
+     +              call errore('bad ncid: ', err)
+                err = nf_get_vara_int2(ncid, BAD_VARID,
+     +                  start, edge, value)
+                if (err .ne. NF_ENOTVAR) 
+     +              call errore('bad var id: ', err)
+                do 11, j = 1, var_rank(i)
+                    if (var_dimid(j,i) .gt. 1) then     !/* skip record dim */
+                        start(j) = var_shape(j,i) + 1
+                        err = nf_get_vara_int2(ncid, i,
+     +                          start, edge, value)
+                        if (canConvert .and. err .ne. NF_EINVALCOORDS)
+     +                      call errore('bad start: ', err)
+                        start(j) = 1
+                    endif
+11              continue
+                err = nf_get_vara_int2(ncid, i, start,
+     +                          edge, value)
+                if (canConvert) then
+                    if (err .ne. 0) 
+     +                  call error(nf_strerror(err))
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                endif
+                do 12, j = 1, var_rank(i)
+                    edge(j) = 1
+12              continue
+            endif
+
+C           Choose a random point dividing each dim into 2 parts
+C           get 2^rank (nslabs) slabs so defined
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+C           bits of k determine whether to get lower or upper part of dim 
+            do 5, k = 1, nslabs
+                nels = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift((k-1), -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    nels = nels * edge(j)
+6               continue
+                allInIntRange = .true.
+                allInExtRange = .true.
+                do 7, j = 1, nels
+                    err = index2indexes(j, var_rank(i), edge, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes 1')
+                    do 8, d = 1, var_rank(i)
+                        index(d) = index(d) + start(d) - 1
+8                   continue
+                    expect(j) = hash4(var_type(i), var_rank(i), index, 
+     +                                NFT_INT2)
+                    if (inRange3(expect(j),var_type(i), 
+     +                           NFT_INT2)) then
+                        allInIntRange = 
+     +                      allInIntRange .and.
+     +                      in_internal_range(NFT_INT2, expect(j))
+                    else
+                        allInExtRange = .false.
+                    end if
+7               continue
+                err = nf_get_vara_int2(ncid, i, start,
+     +                          edge, value)
+                if (canConvert) then
+                    if (allInExtRange) then
+                        if (allInIntRange) then
+                            if (err .ne. 0)
+     +                          call errore('nf_get_vara_int2:', err)
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('Range error: ', err)
+                        end if
+                    else
+                        if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ', err)
+                    end if
+                    do 9, j = 1, nels
+                        if (inRange3(expect(j),var_type(i),
+     +                               NFT_INT2) .and.
+     +                      in_internal_range(NFT_INT2, expect(j)))
+     +                          then
+                            val = value(j)
+                            if (.not.equal(val,expect(j),
+     +                                     var_type(i),NFT_INT2)) 
+     +                              then
+                                call error(
+     +                              'value read not that expected')
+                                if (verbose) then
+                                    call error(' ')
+                                    call errori('varid: ', i)
+                                    call errorc('var_name: ',
+     +                                  var_name(i))
+                                    call errori('element number: %d ', 
+     +                                          j)
+                                    call errord('expect: ', expect(j))
+                                    call errord('got: ', val)
+                                end if
+                            else
+                                nok = nok + 1
+                            end if
+                        end if
+9                   continue
+                else
+                    if (nels .gt. 0  .and. err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+5           continue
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errorc('nf_close: ', nf_strerror(err))
+        call print_nok(nok)
+        end
+
+#endif
+        subroutine test_nf_get_vara_int()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nslabs
+        integer nok      
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer mid(MAX_RANK)
+        logical canConvert     
+        integer    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv. 
+     +                   (NFT_INT .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK)) stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS)) stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+2           continue
+            err = nf_get_vara_int(BAD_ID, i, start,
+     +                  edge, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_vara_int(ncid, BAD_VARID, start, 
+     +                           edge, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                start(j) = var_shape(j,i) + 1
+                err = nf_get_vara_int(ncid, i, start,
+     +                               edge, value)
+                if (canConvert .and. err .ne. NF_EINVALCOORDS)
+     +              call errore('bad index: ', err)
+                start(j) = 1
+                edge(j) = var_shape(j,i) + 1
+                err = nf_get_vara_int(ncid, i, start,
+     +                               edge, value)
+                if (canConvert .and. err .ne. NF_EEDGE)
+     +              call errore('bad edge: ', err)
+                edge(j) = 1
+3           continue
+
+C           /* Check non-scalars for correct error returned even when */
+C           /* there is nothing to get (edge(j).eq.0) */
+            if (var_rank(i) .gt. 0) then
+                do 10, j = 1, var_rank(i)
+                    edge(j) = 0
+10              continue
+                err = nf_get_vara_int(BAD_ID, i, start,
+     +                  edge, value)
+                if (err .ne. NF_EBADID) 
+     +              call errore('bad ncid: ', err)
+                err = nf_get_vara_int(ncid, BAD_VARID,
+     +                  start, edge, value)
+                if (err .ne. NF_ENOTVAR) 
+     +              call errore('bad var id: ', err)
+                do 11, j = 1, var_rank(i)
+                    if (var_dimid(j,i) .gt. 1) then     !/* skip record dim */
+                        start(j) = var_shape(j,i) + 1
+                        err = nf_get_vara_int(ncid, i,
+     +                          start, edge, value)
+                        if (canConvert .and. err .ne. NF_EINVALCOORDS)
+     +                      call errore('bad start: ', err)
+                        start(j) = 1
+                    endif
+11              continue
+                err = nf_get_vara_int(ncid, i, start,
+     +                          edge, value)
+                if (canConvert) then
+                    if (err .ne. 0) 
+     +                  call error(nf_strerror(err))
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                endif
+                do 12, j = 1, var_rank(i)
+                    edge(j) = 1
+12              continue
+            endif
+
+C           Choose a random point dividing each dim into 2 parts
+C           get 2^rank (nslabs) slabs so defined
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+C           bits of k determine whether to get lower or upper part of dim 
+            do 5, k = 1, nslabs
+                nels = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift((k-1), -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    nels = nels * edge(j)
+6               continue
+                allInIntRange = .true.
+                allInExtRange = .true.
+                do 7, j = 1, nels
+                    err = index2indexes(j, var_rank(i), edge, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes 1')
+                    do 8, d = 1, var_rank(i)
+                        index(d) = index(d) + start(d) - 1
+8                   continue
+                    expect(j) = hash4(var_type(i), var_rank(i), index, 
+     +                                NFT_INT)
+                    if (inRange3(expect(j),var_type(i), 
+     +                           NFT_INT)) then
+                        allInIntRange = 
+     +                      allInIntRange .and.
+     +                      in_internal_range(NFT_INT, expect(j))
+                    else
+                        allInExtRange = .false.
+                    end if
+7               continue
+                err = nf_get_vara_int(ncid, i, start,
+     +                          edge, value)
+                if (canConvert) then
+                    if (allInExtRange) then
+                        if (allInIntRange) then
+                            if (err .ne. 0)
+     +                          call errore('nf_get_vara_int:', err)
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('Range error: ', err)
+                        end if
+                    else
+                        if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ', err)
+                    end if
+                    do 9, j = 1, nels
+                        if (inRange3(expect(j),var_type(i),
+     +                               NFT_INT) .and.
+     +                      in_internal_range(NFT_INT, expect(j)))
+     +                          then
+                            val = value(j)
+                            if (.not.equal(val,expect(j),
+     +                                     var_type(i),NFT_INT)) 
+     +                              then
+                                call error(
+     +                              'value read not that expected')
+                                if (verbose) then
+                                    call error(' ')
+                                    call errori('varid: ', i)
+                                    call errorc('var_name: ',
+     +                                  var_name(i))
+                                    call errori('element number: %d ', 
+     +                                          j)
+                                    call errord('expect: ', expect(j))
+                                    call errord('got: ', val)
+                                end if
+                            else
+                                nok = nok + 1
+                            end if
+                        end if
+9                   continue
+                else
+                    if (nels .gt. 0  .and. err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+5           continue
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errorc('nf_close: ', nf_strerror(err))
+        call print_nok(nok)
+        end
+
+        subroutine test_nf_get_vara_real()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nslabs
+        integer nok      
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer mid(MAX_RANK)
+        logical canConvert     
+        real    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv. 
+     +                   (NFT_REAL .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK)) stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS)) stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+2           continue
+            err = nf_get_vara_real(BAD_ID, i, start,
+     +                  edge, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_vara_real(ncid, BAD_VARID, start, 
+     +                           edge, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                start(j) = var_shape(j,i) + 1
+                err = nf_get_vara_real(ncid, i, start,
+     +                               edge, value)
+                if (canConvert .and. err .ne. NF_EINVALCOORDS)
+     +              call errore('bad index: ', err)
+                start(j) = 1
+                edge(j) = var_shape(j,i) + 1
+                err = nf_get_vara_real(ncid, i, start,
+     +                               edge, value)
+                if (canConvert .and. err .ne. NF_EEDGE)
+     +              call errore('bad edge: ', err)
+                edge(j) = 1
+3           continue
+
+C           /* Check non-scalars for correct error returned even when */
+C           /* there is nothing to get (edge(j).eq.0) */
+            if (var_rank(i) .gt. 0) then
+                do 10, j = 1, var_rank(i)
+                    edge(j) = 0
+10              continue
+                err = nf_get_vara_real(BAD_ID, i, start,
+     +                  edge, value)
+                if (err .ne. NF_EBADID) 
+     +              call errore('bad ncid: ', err)
+                err = nf_get_vara_real(ncid, BAD_VARID,
+     +                  start, edge, value)
+                if (err .ne. NF_ENOTVAR) 
+     +              call errore('bad var id: ', err)
+                do 11, j = 1, var_rank(i)
+                    if (var_dimid(j,i) .gt. 1) then     !/* skip record dim */
+                        start(j) = var_shape(j,i) + 1
+                        err = nf_get_vara_real(ncid, i,
+     +                          start, edge, value)
+                        if (canConvert .and. err .ne. NF_EINVALCOORDS)
+     +                      call errore('bad start: ', err)
+                        start(j) = 1
+                    endif
+11              continue
+                err = nf_get_vara_real(ncid, i, start,
+     +                          edge, value)
+                if (canConvert) then
+                    if (err .ne. 0) 
+     +                  call error(nf_strerror(err))
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                endif
+                do 12, j = 1, var_rank(i)
+                    edge(j) = 1
+12              continue
+            endif
+
+C           Choose a random point dividing each dim into 2 parts
+C           get 2^rank (nslabs) slabs so defined
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+C           bits of k determine whether to get lower or upper part of dim 
+            do 5, k = 1, nslabs
+                nels = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift((k-1), -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    nels = nels * edge(j)
+6               continue
+                allInIntRange = .true.
+                allInExtRange = .true.
+                do 7, j = 1, nels
+                    err = index2indexes(j, var_rank(i), edge, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes 1')
+                    do 8, d = 1, var_rank(i)
+                        index(d) = index(d) + start(d) - 1
+8                   continue
+                    expect(j) = hash4(var_type(i), var_rank(i), index, 
+     +                                NFT_REAL)
+                    if (inRange3(expect(j),var_type(i), 
+     +                           NFT_REAL)) then
+                        allInIntRange = 
+     +                      allInIntRange .and.
+     +                      in_internal_range(NFT_REAL, expect(j))
+                    else
+                        allInExtRange = .false.
+                    end if
+7               continue
+                err = nf_get_vara_real(ncid, i, start,
+     +                          edge, value)
+                if (canConvert) then
+                    if (allInExtRange) then
+                        if (allInIntRange) then
+                            if (err .ne. 0)
+     +                          call errore('nf_get_vara_real:', err)
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('Range error: ', err)
+                        end if
+                    else
+                        if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ', err)
+                    end if
+                    do 9, j = 1, nels
+                        if (inRange3(expect(j),var_type(i),
+     +                               NFT_REAL) .and.
+     +                      in_internal_range(NFT_REAL, expect(j)))
+     +                          then
+                            val = value(j)
+                            if (.not.equal(val,expect(j),
+     +                                     var_type(i),NFT_REAL)) 
+     +                              then
+                                call error(
+     +                              'value read not that expected')
+                                if (verbose) then
+                                    call error(' ')
+                                    call errori('varid: ', i)
+                                    call errorc('var_name: ',
+     +                                  var_name(i))
+                                    call errori('element number: %d ', 
+     +                                          j)
+                                    call errord('expect: ', expect(j))
+                                    call errord('got: ', val)
+                                end if
+                            else
+                                nok = nok + 1
+                            end if
+                        end if
+9                   continue
+                else
+                    if (nels .gt. 0  .and. err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+5           continue
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errorc('nf_close: ', nf_strerror(err))
+        call print_nok(nok)
+        end
+
+        subroutine test_nf_get_vara_double()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nslabs
+        integer nok      
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer mid(MAX_RANK)
+        logical canConvert     
+        doubleprecision    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv. 
+     +                   (NFT_DOUBLE .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK)) stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS)) stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+2           continue
+            err = nf_get_vara_double(BAD_ID, i, start,
+     +                  edge, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_vara_double(ncid, BAD_VARID, start, 
+     +                           edge, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                start(j) = var_shape(j,i) + 1
+                err = nf_get_vara_double(ncid, i, start,
+     +                               edge, value)
+                if (canConvert .and. err .ne. NF_EINVALCOORDS)
+     +              call errore('bad index: ', err)
+                start(j) = 1
+                edge(j) = var_shape(j,i) + 1
+                err = nf_get_vara_double(ncid, i, start,
+     +                               edge, value)
+                if (canConvert .and. err .ne. NF_EEDGE)
+     +              call errore('bad edge: ', err)
+                edge(j) = 1
+3           continue
+
+C           /* Check non-scalars for correct error returned even when */
+C           /* there is nothing to get (edge(j).eq.0) */
+            if (var_rank(i) .gt. 0) then
+                do 10, j = 1, var_rank(i)
+                    edge(j) = 0
+10              continue
+                err = nf_get_vara_double(BAD_ID, i, start,
+     +                  edge, value)
+                if (err .ne. NF_EBADID) 
+     +              call errore('bad ncid: ', err)
+                err = nf_get_vara_double(ncid, BAD_VARID,
+     +                  start, edge, value)
+                if (err .ne. NF_ENOTVAR) 
+     +              call errore('bad var id: ', err)
+                do 11, j = 1, var_rank(i)
+                    if (var_dimid(j,i) .gt. 1) then     !/* skip record dim */
+                        start(j) = var_shape(j,i) + 1
+                        err = nf_get_vara_double(ncid, i,
+     +                          start, edge, value)
+                        if (canConvert .and. err .ne. NF_EINVALCOORDS)
+     +                      call errore('bad start: ', err)
+                        start(j) = 1
+                    endif
+11              continue
+                err = nf_get_vara_double(ncid, i, start,
+     +                          edge, value)
+                if (canConvert) then
+                    if (err .ne. 0) 
+     +                  call error(nf_strerror(err))
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                endif
+                do 12, j = 1, var_rank(i)
+                    edge(j) = 1
+12              continue
+            endif
+
+C           Choose a random point dividing each dim into 2 parts
+C           get 2^rank (nslabs) slabs so defined
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+C           bits of k determine whether to get lower or upper part of dim 
+            do 5, k = 1, nslabs
+                nels = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift((k-1), -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    nels = nels * edge(j)
+6               continue
+                allInIntRange = .true.
+                allInExtRange = .true.
+                do 7, j = 1, nels
+                    err = index2indexes(j, var_rank(i), edge, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes 1')
+                    do 8, d = 1, var_rank(i)
+                        index(d) = index(d) + start(d) - 1
+8                   continue
+                    expect(j) = hash4(var_type(i), var_rank(i), index, 
+     +                                NFT_DOUBLE)
+                    if (inRange3(expect(j),var_type(i), 
+     +                           NFT_DOUBLE)) then
+                        allInIntRange = 
+     +                      allInIntRange .and.
+     +                      in_internal_range(NFT_DOUBLE, expect(j))
+                    else
+                        allInExtRange = .false.
+                    end if
+7               continue
+                err = nf_get_vara_double(ncid, i, start,
+     +                          edge, value)
+                if (canConvert) then
+                    if (allInExtRange) then
+                        if (allInIntRange) then
+                            if (err .ne. 0)
+     +                          call errore('nf_get_vara_double:', err)
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('Range error: ', err)
+                        end if
+                    else
+                        if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ', err)
+                    end if
+                    do 9, j = 1, nels
+                        if (inRange3(expect(j),var_type(i),
+     +                               NFT_DOUBLE) .and.
+     +                      in_internal_range(NFT_DOUBLE, expect(j)))
+     +                          then
+                            val = value(j)
+                            if (.not.equal(val,expect(j),
+     +                                     var_type(i),NFT_DOUBLE)) 
+     +                              then
+                                call error(
+     +                              'value read not that expected')
+                                if (verbose) then
+                                    call error(' ')
+                                    call errori('varid: ', i)
+                                    call errorc('var_name: ',
+     +                                  var_name(i))
+                                    call errori('element number: %d ', 
+     +                                          j)
+                                    call errord('expect: ', expect(j))
+                                    call errord('got: ', val)
+                                end if
+                            else
+                                nok = nok + 1
+                            end if
+                        end if
+9                   continue
+                else
+                    if (nels .gt. 0  .and. err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+5           continue
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errorc('nf_close: ', nf_strerror(err))
+        call print_nok(nok)
+        end
+
+
+        subroutine test_nf_get_vars_text()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nslabs
+        integer nstarts         
+        integer nok             
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        logical canConvert     
+        character    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv. 
+     +                   (NFT_TEXT .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK)) stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS)) stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+2           continue
+            err = nf_get_vars_text(BAD_ID, i, start,
+     +                  edge, stride, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_vars_text(ncid, BAD_VARID,
+     +                  start, edge, stride, 
+     +                           value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                start(j) = var_shape(j,i) + 1
+                err = nf_get_vars_text(ncid, i, start,
+     +                               edge, stride, 
+     +                               value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad index: ', err)
+                endif
+                start(j) = 1
+                edge(j) = var_shape(j,i) + 1
+                err = nf_get_vars_text(ncid, i, start,
+     +                               edge, stride, 
+     +                               value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EEDGE)
+     +                  call errore('bad edge: ', err)
+                endif
+                edge(j) = 1
+                stride(j) = 0
+                err = nf_get_vars_text(ncid, i, start,
+     +                               edge, stride, 
+     +                               value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_ESTRIDE)
+     +                  call errore('bad stride: ', err)
+                endif
+                stride(j) = 1
+3           continue
+C               Choose a random point dividing each dim into 2 parts
+C               get 2^rank (nslabs) slabs so defined
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+C               bits of k determine whether to get lower or upper part of dim
+C               choose random stride from 1 to edge
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, j-1), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        sstride(j) = 1 + roll(edge(j))
+                    else
+                        sstride(j) = 1
+                    end if
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, 
+     +                                  index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / 
+     +                                  stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+C                           Random choice of forward or backward 
+C    /* TODO
+C                   if ( roll(2) ) then
+C                       for (j = 0 j < var_rank(i) j++) {
+C                           index(j) += (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C                       }
+C                   end if
+C    */
+                    allInIntRange = .true.
+                    allInExtRange = .true.
+                    do 9, j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes() 1')
+                        do 10, d = 1, var_rank(i)
+                            index2(d) = index(d) + (index2(d)-1) * 
+     +                                  stride(d)
+10                      continue
+                        expect(j) = hash4(var_type(i), var_rank(i), 
+     +                                    index2, NFT_TEXT)
+                        if (inRange3(expect(j),var_type(i),
+     +                               NFT_TEXT)) then
+                            allInIntRange = 
+     +                          allInIntRange .and.
+     +                          in_internal_range(NFT_TEXT, 
+     +                                            expect(j))
+                        else
+                            allInExtRange = .false.
+                        end if
+9                   continue
+                    err = nf_get_vars_text(ncid, i, index,
+     +                                   count, stride,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (allInIntRange) then
+                                if (err .ne. 0)
+     +                              call error(nf_strerror(err))
+                            else
+                                if (err .ne. NF_ERANGE)
+     +                              call errore('Range error: ', err)
+                            end if
+                        else
+                            if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                          call errore('OK or Range error: ', err)
+                        end if
+                        do 11, j = 1, nels
+                            if (inRange3(expect(j),var_type(i),
+     +                          NFT_TEXT) .and.
+     +                          in_internal_range(NFT_TEXT, 
+     +                                            expect(j))) then
+                                val = ichar(value(j))
+                                if (.not.equal(val, expect(j),
+     +                              var_type(i), NFT_TEXT)) then
+                                    call error(
+     +                                  'value read not that expected')
+                                    if (verbose) then
+                                        call error(' ')
+                                        call errori('varid: ', i)
+                                        call errorc('var_name: ', 
+     +                                              var_name(i))
+                                        call errori('element number: ',
+     +                                              j)
+                                        call errord('expect: ', 
+     +                                              expect(j))
+                                        call errord('got: ', val)
+                                    end if
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+11                      continue
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        call print_nok(nok)
+        end
+
+#ifdef NF_INT1_T
+        subroutine test_nf_get_vars_int1()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nslabs
+        integer nstarts         
+        integer nok             
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        logical canConvert     
+        NF_INT1_T    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv. 
+     +                   (NFT_INT1 .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK)) stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS)) stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+2           continue
+            err = nf_get_vars_int1(BAD_ID, i, start,
+     +                  edge, stride, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_vars_int1(ncid, BAD_VARID,
+     +                  start, edge, stride, 
+     +                           value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                start(j) = var_shape(j,i) + 1
+                err = nf_get_vars_int1(ncid, i, start,
+     +                               edge, stride, 
+     +                               value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad index: ', err)
+                endif
+                start(j) = 1
+                edge(j) = var_shape(j,i) + 1
+                err = nf_get_vars_int1(ncid, i, start,
+     +                               edge, stride, 
+     +                               value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EEDGE)
+     +                  call errore('bad edge: ', err)
+                endif
+                edge(j) = 1
+                stride(j) = 0
+                err = nf_get_vars_int1(ncid, i, start,
+     +                               edge, stride, 
+     +                               value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_ESTRIDE)
+     +                  call errore('bad stride: ', err)
+                endif
+                stride(j) = 1
+3           continue
+C               Choose a random point dividing each dim into 2 parts
+C               get 2^rank (nslabs) slabs so defined
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+C               bits of k determine whether to get lower or upper part of dim
+C               choose random stride from 1 to edge
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, j-1), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        sstride(j) = 1 + roll(edge(j))
+                    else
+                        sstride(j) = 1
+                    end if
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, 
+     +                                  index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / 
+     +                                  stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+C                           Random choice of forward or backward 
+C    /* TODO
+C                   if ( roll(2) ) then
+C                       for (j = 0 j < var_rank(i) j++) {
+C                           index(j) += (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C                       }
+C                   end if
+C    */
+                    allInIntRange = .true.
+                    allInExtRange = .true.
+                    do 9, j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes() 1')
+                        do 10, d = 1, var_rank(i)
+                            index2(d) = index(d) + (index2(d)-1) * 
+     +                                  stride(d)
+10                      continue
+                        expect(j) = hash4(var_type(i), var_rank(i), 
+     +                                    index2, NFT_INT1)
+                        if (inRange3(expect(j),var_type(i),
+     +                               NFT_INT1)) then
+                            allInIntRange = 
+     +                          allInIntRange .and.
+     +                          in_internal_range(NFT_INT1, 
+     +                                            expect(j))
+                        else
+                            allInExtRange = .false.
+                        end if
+9                   continue
+                    err = nf_get_vars_int1(ncid, i, index,
+     +                                   count, stride,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (allInIntRange) then
+                                if (err .ne. 0)
+     +                              call error(nf_strerror(err))
+                            else
+                                if (err .ne. NF_ERANGE)
+     +                              call errore('Range error: ', err)
+                            end if
+                        else
+                            if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                          call errore('OK or Range error: ', err)
+                        end if
+                        do 11, j = 1, nels
+                            if (inRange3(expect(j),var_type(i),
+     +                          NFT_INT1) .and.
+     +                          in_internal_range(NFT_INT1, 
+     +                                            expect(j))) then
+                                val = value(j)
+                                if (.not.equal(val, expect(j),
+     +                              var_type(i), NFT_INT1)) then
+                                    call error(
+     +                                  'value read not that expected')
+                                    if (verbose) then
+                                        call error(' ')
+                                        call errori('varid: ', i)
+                                        call errorc('var_name: ', 
+     +                                              var_name(i))
+                                        call errori('element number: ',
+     +                                              j)
+                                        call errord('expect: ', 
+     +                                              expect(j))
+                                        call errord('got: ', val)
+                                    end if
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+11                      continue
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        call print_nok(nok)
+        end
+
+#endif
+#ifdef NF_INT2_T
+        subroutine test_nf_get_vars_int2()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nslabs
+        integer nstarts         
+        integer nok             
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        logical canConvert     
+        NF_INT2_T    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv. 
+     +                   (NFT_INT2 .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK)) stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS)) stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+2           continue
+            err = nf_get_vars_int2(BAD_ID, i, start,
+     +                  edge, stride, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_vars_int2(ncid, BAD_VARID,
+     +                  start, edge, stride, 
+     +                           value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                start(j) = var_shape(j,i) + 1
+                err = nf_get_vars_int2(ncid, i, start,
+     +                               edge, stride, 
+     +                               value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad index: ', err)
+                endif
+                start(j) = 1
+                edge(j) = var_shape(j,i) + 1
+                err = nf_get_vars_int2(ncid, i, start,
+     +                               edge, stride, 
+     +                               value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EEDGE)
+     +                  call errore('bad edge: ', err)
+                endif
+                edge(j) = 1
+                stride(j) = 0
+                err = nf_get_vars_int2(ncid, i, start,
+     +                               edge, stride, 
+     +                               value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_ESTRIDE)
+     +                  call errore('bad stride: ', err)
+                endif
+                stride(j) = 1
+3           continue
+C               Choose a random point dividing each dim into 2 parts
+C               get 2^rank (nslabs) slabs so defined
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+C               bits of k determine whether to get lower or upper part of dim
+C               choose random stride from 1 to edge
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, j-1), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        sstride(j) = 1 + roll(edge(j))
+                    else
+                        sstride(j) = 1
+                    end if
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, 
+     +                                  index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / 
+     +                                  stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+C                           Random choice of forward or backward 
+C    /* TODO
+C                   if ( roll(2) ) then
+C                       for (j = 0 j < var_rank(i) j++) {
+C                           index(j) += (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C                       }
+C                   end if
+C    */
+                    allInIntRange = .true.
+                    allInExtRange = .true.
+                    do 9, j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes() 1')
+                        do 10, d = 1, var_rank(i)
+                            index2(d) = index(d) + (index2(d)-1) * 
+     +                                  stride(d)
+10                      continue
+                        expect(j) = hash4(var_type(i), var_rank(i), 
+     +                                    index2, NFT_INT2)
+                        if (inRange3(expect(j),var_type(i),
+     +                               NFT_INT2)) then
+                            allInIntRange = 
+     +                          allInIntRange .and.
+     +                          in_internal_range(NFT_INT2, 
+     +                                            expect(j))
+                        else
+                            allInExtRange = .false.
+                        end if
+9                   continue
+                    err = nf_get_vars_int2(ncid, i, index,
+     +                                   count, stride,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (allInIntRange) then
+                                if (err .ne. 0)
+     +                              call error(nf_strerror(err))
+                            else
+                                if (err .ne. NF_ERANGE)
+     +                              call errore('Range error: ', err)
+                            end if
+                        else
+                            if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                          call errore('OK or Range error: ', err)
+                        end if
+                        do 11, j = 1, nels
+                            if (inRange3(expect(j),var_type(i),
+     +                          NFT_INT2) .and.
+     +                          in_internal_range(NFT_INT2, 
+     +                                            expect(j))) then
+                                val = value(j)
+                                if (.not.equal(val, expect(j),
+     +                              var_type(i), NFT_INT2)) then
+                                    call error(
+     +                                  'value read not that expected')
+                                    if (verbose) then
+                                        call error(' ')
+                                        call errori('varid: ', i)
+                                        call errorc('var_name: ', 
+     +                                              var_name(i))
+                                        call errori('element number: ',
+     +                                              j)
+                                        call errord('expect: ', 
+     +                                              expect(j))
+                                        call errord('got: ', val)
+                                    end if
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+11                      continue
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        call print_nok(nok)
+        end
+
+#endif
+        subroutine test_nf_get_vars_int()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nslabs
+        integer nstarts         
+        integer nok             
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        logical canConvert     
+        integer    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv. 
+     +                   (NFT_INT .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK)) stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS)) stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+2           continue
+            err = nf_get_vars_int(BAD_ID, i, start,
+     +                  edge, stride, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_vars_int(ncid, BAD_VARID,
+     +                  start, edge, stride, 
+     +                           value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                start(j) = var_shape(j,i) + 1
+                err = nf_get_vars_int(ncid, i, start,
+     +                               edge, stride, 
+     +                               value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad index: ', err)
+                endif
+                start(j) = 1
+                edge(j) = var_shape(j,i) + 1
+                err = nf_get_vars_int(ncid, i, start,
+     +                               edge, stride, 
+     +                               value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EEDGE)
+     +                  call errore('bad edge: ', err)
+                endif
+                edge(j) = 1
+                stride(j) = 0
+                err = nf_get_vars_int(ncid, i, start,
+     +                               edge, stride, 
+     +                               value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_ESTRIDE)
+     +                  call errore('bad stride: ', err)
+                endif
+                stride(j) = 1
+3           continue
+C               Choose a random point dividing each dim into 2 parts
+C               get 2^rank (nslabs) slabs so defined
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+C               bits of k determine whether to get lower or upper part of dim
+C               choose random stride from 1 to edge
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, j-1), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        sstride(j) = 1 + roll(edge(j))
+                    else
+                        sstride(j) = 1
+                    end if
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, 
+     +                                  index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / 
+     +                                  stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+C                           Random choice of forward or backward 
+C    /* TODO
+C                   if ( roll(2) ) then
+C                       for (j = 0 j < var_rank(i) j++) {
+C                           index(j) += (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C                       }
+C                   end if
+C    */
+                    allInIntRange = .true.
+                    allInExtRange = .true.
+                    do 9, j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes() 1')
+                        do 10, d = 1, var_rank(i)
+                            index2(d) = index(d) + (index2(d)-1) * 
+     +                                  stride(d)
+10                      continue
+                        expect(j) = hash4(var_type(i), var_rank(i), 
+     +                                    index2, NFT_INT)
+                        if (inRange3(expect(j),var_type(i),
+     +                               NFT_INT)) then
+                            allInIntRange = 
+     +                          allInIntRange .and.
+     +                          in_internal_range(NFT_INT, 
+     +                                            expect(j))
+                        else
+                            allInExtRange = .false.
+                        end if
+9                   continue
+                    err = nf_get_vars_int(ncid, i, index,
+     +                                   count, stride,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (allInIntRange) then
+                                if (err .ne. 0)
+     +                              call error(nf_strerror(err))
+                            else
+                                if (err .ne. NF_ERANGE)
+     +                              call errore('Range error: ', err)
+                            end if
+                        else
+                            if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                          call errore('OK or Range error: ', err)
+                        end if
+                        do 11, j = 1, nels
+                            if (inRange3(expect(j),var_type(i),
+     +                          NFT_INT) .and.
+     +                          in_internal_range(NFT_INT, 
+     +                                            expect(j))) then
+                                val = value(j)
+                                if (.not.equal(val, expect(j),
+     +                              var_type(i), NFT_INT)) then
+                                    call error(
+     +                                  'value read not that expected')
+                                    if (verbose) then
+                                        call error(' ')
+                                        call errori('varid: ', i)
+                                        call errorc('var_name: ', 
+     +                                              var_name(i))
+                                        call errori('element number: ',
+     +                                              j)
+                                        call errord('expect: ', 
+     +                                              expect(j))
+                                        call errord('got: ', val)
+                                    end if
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+11                      continue
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        call print_nok(nok)
+        end
+
+        subroutine test_nf_get_vars_real()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nslabs
+        integer nstarts         
+        integer nok             
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        logical canConvert     
+        real    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv. 
+     +                   (NFT_REAL .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK)) stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS)) stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+2           continue
+            err = nf_get_vars_real(BAD_ID, i, start,
+     +                  edge, stride, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_vars_real(ncid, BAD_VARID,
+     +                  start, edge, stride, 
+     +                           value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                start(j) = var_shape(j,i) + 1
+                err = nf_get_vars_real(ncid, i, start,
+     +                               edge, stride, 
+     +                               value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad index: ', err)
+                endif
+                start(j) = 1
+                edge(j) = var_shape(j,i) + 1
+                err = nf_get_vars_real(ncid, i, start,
+     +                               edge, stride, 
+     +                               value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EEDGE)
+     +                  call errore('bad edge: ', err)
+                endif
+                edge(j) = 1
+                stride(j) = 0
+                err = nf_get_vars_real(ncid, i, start,
+     +                               edge, stride, 
+     +                               value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_ESTRIDE)
+     +                  call errore('bad stride: ', err)
+                endif
+                stride(j) = 1
+3           continue
+C               Choose a random point dividing each dim into 2 parts
+C               get 2^rank (nslabs) slabs so defined
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+C               bits of k determine whether to get lower or upper part of dim
+C               choose random stride from 1 to edge
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, j-1), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        sstride(j) = 1 + roll(edge(j))
+                    else
+                        sstride(j) = 1
+                    end if
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, 
+     +                                  index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / 
+     +                                  stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+C                           Random choice of forward or backward 
+C    /* TODO
+C                   if ( roll(2) ) then
+C                       for (j = 0 j < var_rank(i) j++) {
+C                           index(j) += (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C                       }
+C                   end if
+C    */
+                    allInIntRange = .true.
+                    allInExtRange = .true.
+                    do 9, j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes() 1')
+                        do 10, d = 1, var_rank(i)
+                            index2(d) = index(d) + (index2(d)-1) * 
+     +                                  stride(d)
+10                      continue
+                        expect(j) = hash4(var_type(i), var_rank(i), 
+     +                                    index2, NFT_REAL)
+                        if (inRange3(expect(j),var_type(i),
+     +                               NFT_REAL)) then
+                            allInIntRange = 
+     +                          allInIntRange .and.
+     +                          in_internal_range(NFT_REAL, 
+     +                                            expect(j))
+                        else
+                            allInExtRange = .false.
+                        end if
+9                   continue
+                    err = nf_get_vars_real(ncid, i, index,
+     +                                   count, stride,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (allInIntRange) then
+                                if (err .ne. 0)
+     +                              call error(nf_strerror(err))
+                            else
+                                if (err .ne. NF_ERANGE)
+     +                              call errore('Range error: ', err)
+                            end if
+                        else
+                            if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                          call errore('OK or Range error: ', err)
+                        end if
+                        do 11, j = 1, nels
+                            if (inRange3(expect(j),var_type(i),
+     +                          NFT_REAL) .and.
+     +                          in_internal_range(NFT_REAL, 
+     +                                            expect(j))) then
+                                val = value(j)
+                                if (.not.equal(val, expect(j),
+     +                              var_type(i), NFT_REAL)) then
+                                    call error(
+     +                                  'value read not that expected')
+                                    if (verbose) then
+                                        call error(' ')
+                                        call errori('varid: ', i)
+                                        call errorc('var_name: ', 
+     +                                              var_name(i))
+                                        call errori('element number: ',
+     +                                              j)
+                                        call errord('expect: ', 
+     +                                              expect(j))
+                                        call errord('got: ', val)
+                                    end if
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+11                      continue
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        call print_nok(nok)
+        end
+
+        subroutine test_nf_get_vars_double()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nslabs
+        integer nstarts         
+        integer nok             
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        logical canConvert     
+        doubleprecision    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv. 
+     +                   (NFT_DOUBLE .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK)) stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS)) stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+2           continue
+            err = nf_get_vars_double(BAD_ID, i, start,
+     +                  edge, stride, value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_vars_double(ncid, BAD_VARID,
+     +                  start, edge, stride, 
+     +                           value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                start(j) = var_shape(j,i) + 1
+                err = nf_get_vars_double(ncid, i, start,
+     +                               edge, stride, 
+     +                               value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad index: ', err)
+                endif
+                start(j) = 1
+                edge(j) = var_shape(j,i) + 1
+                err = nf_get_vars_double(ncid, i, start,
+     +                               edge, stride, 
+     +                               value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EEDGE)
+     +                  call errore('bad edge: ', err)
+                endif
+                edge(j) = 1
+                stride(j) = 0
+                err = nf_get_vars_double(ncid, i, start,
+     +                               edge, stride, 
+     +                               value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_ESTRIDE)
+     +                  call errore('bad stride: ', err)
+                endif
+                stride(j) = 1
+3           continue
+C               Choose a random point dividing each dim into 2 parts
+C               get 2^rank (nslabs) slabs so defined
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+C               bits of k determine whether to get lower or upper part of dim
+C               choose random stride from 1 to edge
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, j-1), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        sstride(j) = 1 + roll(edge(j))
+                    else
+                        sstride(j) = 1
+                    end if
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, 
+     +                                  index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / 
+     +                                  stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+C                           Random choice of forward or backward 
+C    /* TODO
+C                   if ( roll(2) ) then
+C                       for (j = 0 j < var_rank(i) j++) {
+C                           index(j) += (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C                       }
+C                   end if
+C    */
+                    allInIntRange = .true.
+                    allInExtRange = .true.
+                    do 9, j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes() 1')
+                        do 10, d = 1, var_rank(i)
+                            index2(d) = index(d) + (index2(d)-1) * 
+     +                                  stride(d)
+10                      continue
+                        expect(j) = hash4(var_type(i), var_rank(i), 
+     +                                    index2, NFT_DOUBLE)
+                        if (inRange3(expect(j),var_type(i),
+     +                               NFT_DOUBLE)) then
+                            allInIntRange = 
+     +                          allInIntRange .and.
+     +                          in_internal_range(NFT_DOUBLE, 
+     +                                            expect(j))
+                        else
+                            allInExtRange = .false.
+                        end if
+9                   continue
+                    err = nf_get_vars_double(ncid, i, index,
+     +                                   count, stride,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (allInIntRange) then
+                                if (err .ne. 0)
+     +                              call error(nf_strerror(err))
+                            else
+                                if (err .ne. NF_ERANGE)
+     +                              call errore('Range error: ', err)
+                            end if
+                        else
+                            if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                          call errore('OK or Range error: ', err)
+                        end if
+                        do 11, j = 1, nels
+                            if (inRange3(expect(j),var_type(i),
+     +                          NFT_DOUBLE) .and.
+     +                          in_internal_range(NFT_DOUBLE, 
+     +                                            expect(j))) then
+                                val = value(j)
+                                if (.not.equal(val, expect(j),
+     +                              var_type(i), NFT_DOUBLE)) then
+                                    call error(
+     +                                  'value read not that expected')
+                                    if (verbose) then
+                                        call error(' ')
+                                        call errori('varid: ', i)
+                                        call errorc('var_name: ', 
+     +                                              var_name(i))
+                                        call errori('element number: ',
+     +                                              j)
+                                        call errord('expect: ', 
+     +                                              expect(j))
+                                        call errord('got: ', val)
+                                    end if
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+11                      continue
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        call print_nok(nok)
+        end
+
+
+        subroutine test_nf_get_varm_text()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nslabs
+        integer nstarts         
+        integer nok             
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        integer imap(MAX_RANK)
+        logical canConvert     
+        character    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv. 
+     +                   (NFT_TEXT .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK)) stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS)) stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+                imap(j) = 1
+2           continue
+            err = nf_get_varm_text(BAD_ID, i, start, edge,
+     +                           stride, imap, 
+     +                           value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_varm_text(ncid, BAD_VARID, start,
+     +                           edge, stride, 
+     +                           imap, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                start(j) = var_shape(j,i) + 1
+                err = nf_get_varm_text(ncid, i, start,
+     +                               edge, stride, 
+     +                               imap, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad index: ', err)
+                endif
+                start(j) = 1
+                edge(j) = var_shape(j,i) + 1
+                err = nf_get_varm_text(ncid, i, start,
+     +                               edge, stride, 
+     +                               imap, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EEDGE)
+     +                  call errore('bad edge: ', err)
+                endif
+                edge(j) = 1
+                stride(j) = 0
+                err = nf_get_varm_text(ncid, i, start,
+     +                               edge, stride, 
+     +                               imap, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_ESTRIDE)
+     +                  call errore('bad stride: ', err)
+                endif
+                stride(j) = 1
+3           continue
+C               Choose a random point dividing each dim into 2 parts 
+C               get 2^rank (nslabs) slabs so defined 
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+C               /* bits of k determine whether to get lower or upper part 
+C                * of dim
+C                * choose random stride from 1 to edge */
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift((k-1), -(j-1)), 2) .ne. 0) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        stride(j) = 1+roll(edge(j))
+                    else
+                        stride(j) = 1
+                    end if
+                    sstride(j) = stride(j)
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / 
+     +                                  stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+C                       Random choice of forward or backward 
+C    /* TODO
+C                   if ( roll(2) ) then
+C                       for (j = 0 j < var_rank(i) j++) {
+C                           index(j) += (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C                       }
+C                   end if
+C     */
+                    if (var_rank(i) .gt. 0) then
+                        imap(1) = 1
+                        do 9, j = 2, var_rank(i)
+                            imap(j) = imap(j-1) * count(j-1)
+9                       continue
+                    end if
+                    allInIntRange = .true.
+                    allInExtRange = .true.
+                    do 10, j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes 1')
+                        do 11, d = 1, var_rank(i)
+                            index2(d) = index(d) + (index2(d)-1) * 
+     +                                  stride(d)
+11                      continue
+                        expect(j) = hash4(var_type(i), var_rank(i), 
+     +                                    index2, NFT_TEXT)
+                        if (inRange3(expect(j),var_type(i),
+     +                               NFT_TEXT)) then
+                            allInIntRange = 
+     +                          allInIntRange .and.
+     +                          in_internal_range(NFT_TEXT,
+     +                                            expect(j))
+                        else
+                            allInExtRange = .false.
+                        end if
+10                  continue
+                    err = nf_get_varm_text(ncid,i,index,count,
+     +                                   stride,imap,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (allInIntRange) then
+                                if (err .ne. 0)
+     +                              call error(nf_strerror(err))
+                            else
+                                if (err .ne. NF_ERANGE)
+     +                              call errore('Range error: ', err)
+                            end if
+                        else
+                            if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                          call errore('OK or Range error: ', err)
+                        end if
+                        do 12, j = 1, nels
+                            if (inRange3(expect(j),var_type(i),
+     +                                   NFT_TEXT) .and.
+     +                          in_internal_range(NFT_TEXT,
+     +                                            expect(j))) then
+                                val = ichar(value(j))
+                                if (.not.equal(val, expect(j),
+     +                                         var_type(i), 
+     +                                         NFT_TEXT)) then
+                                    call error(
+     +                                  'value read not that expected')
+                                    if (verbose) then
+                                        call error(' ')
+                                        call errori('varid: ', i)
+                                        call errorc('var_name: ', 
+     +                                          var_name(i))
+                                        call errori('element number: ',
+     +                                              j)
+                                        call errord('expect: ', 
+     +                                              expect(j))
+                                        call errord('got: ', val)
+                                    end if
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+12                      continue
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ',  err)
+        call print_nok(nok)
+        end
+
+#ifdef NF_INT1_T
+        subroutine test_nf_get_varm_int1()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nslabs
+        integer nstarts         
+        integer nok             
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        integer imap(MAX_RANK)
+        logical canConvert     
+        NF_INT1_T    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv. 
+     +                   (NFT_INT1 .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK)) stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS)) stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+                imap(j) = 1
+2           continue
+            err = nf_get_varm_int1(BAD_ID, i, start, edge,
+     +                           stride, imap, 
+     +                           value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_varm_int1(ncid, BAD_VARID, start,
+     +                           edge, stride, 
+     +                           imap, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                start(j) = var_shape(j,i) + 1
+                err = nf_get_varm_int1(ncid, i, start,
+     +                               edge, stride, 
+     +                               imap, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad index: ', err)
+                endif
+                start(j) = 1
+                edge(j) = var_shape(j,i) + 1
+                err = nf_get_varm_int1(ncid, i, start,
+     +                               edge, stride, 
+     +                               imap, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EEDGE)
+     +                  call errore('bad edge: ', err)
+                endif
+                edge(j) = 1
+                stride(j) = 0
+                err = nf_get_varm_int1(ncid, i, start,
+     +                               edge, stride, 
+     +                               imap, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_ESTRIDE)
+     +                  call errore('bad stride: ', err)
+                endif
+                stride(j) = 1
+3           continue
+C               Choose a random point dividing each dim into 2 parts 
+C               get 2^rank (nslabs) slabs so defined 
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+C               /* bits of k determine whether to get lower or upper part 
+C                * of dim
+C                * choose random stride from 1 to edge */
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift((k-1), -(j-1)), 2) .ne. 0) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        stride(j) = 1+roll(edge(j))
+                    else
+                        stride(j) = 1
+                    end if
+                    sstride(j) = stride(j)
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / 
+     +                                  stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+C                       Random choice of forward or backward 
+C    /* TODO
+C                   if ( roll(2) ) then
+C                       for (j = 0 j < var_rank(i) j++) {
+C                           index(j) += (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C                       }
+C                   end if
+C     */
+                    if (var_rank(i) .gt. 0) then
+                        imap(1) = 1
+                        do 9, j = 2, var_rank(i)
+                            imap(j) = imap(j-1) * count(j-1)
+9                       continue
+                    end if
+                    allInIntRange = .true.
+                    allInExtRange = .true.
+                    do 10, j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes 1')
+                        do 11, d = 1, var_rank(i)
+                            index2(d) = index(d) + (index2(d)-1) * 
+     +                                  stride(d)
+11                      continue
+                        expect(j) = hash4(var_type(i), var_rank(i), 
+     +                                    index2, NFT_INT1)
+                        if (inRange3(expect(j),var_type(i),
+     +                               NFT_INT1)) then
+                            allInIntRange = 
+     +                          allInIntRange .and.
+     +                          in_internal_range(NFT_INT1,
+     +                                            expect(j))
+                        else
+                            allInExtRange = .false.
+                        end if
+10                  continue
+                    err = nf_get_varm_int1(ncid,i,index,count,
+     +                                   stride,imap,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (allInIntRange) then
+                                if (err .ne. 0)
+     +                              call error(nf_strerror(err))
+                            else
+                                if (err .ne. NF_ERANGE)
+     +                              call errore('Range error: ', err)
+                            end if
+                        else
+                            if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                          call errore('OK or Range error: ', err)
+                        end if
+                        do 12, j = 1, nels
+                            if (inRange3(expect(j),var_type(i),
+     +                                   NFT_INT1) .and.
+     +                          in_internal_range(NFT_INT1,
+     +                                            expect(j))) then
+                                val = value(j)
+                                if (.not.equal(val, expect(j),
+     +                                         var_type(i), 
+     +                                         NFT_INT1)) then
+                                    call error(
+     +                                  'value read not that expected')
+                                    if (verbose) then
+                                        call error(' ')
+                                        call errori('varid: ', i)
+                                        call errorc('var_name: ', 
+     +                                          var_name(i))
+                                        call errori('element number: ',
+     +                                              j)
+                                        call errord('expect: ', 
+     +                                              expect(j))
+                                        call errord('got: ', val)
+                                    end if
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+12                      continue
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ',  err)
+        call print_nok(nok)
+        end
+
+#endif
+#ifdef NF_INT2_T
+        subroutine test_nf_get_varm_int2()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nslabs
+        integer nstarts         
+        integer nok             
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        integer imap(MAX_RANK)
+        logical canConvert     
+        NF_INT2_T    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv. 
+     +                   (NFT_INT2 .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK)) stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS)) stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+                imap(j) = 1
+2           continue
+            err = nf_get_varm_int2(BAD_ID, i, start, edge,
+     +                           stride, imap, 
+     +                           value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_varm_int2(ncid, BAD_VARID, start,
+     +                           edge, stride, 
+     +                           imap, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                start(j) = var_shape(j,i) + 1
+                err = nf_get_varm_int2(ncid, i, start,
+     +                               edge, stride, 
+     +                               imap, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad index: ', err)
+                endif
+                start(j) = 1
+                edge(j) = var_shape(j,i) + 1
+                err = nf_get_varm_int2(ncid, i, start,
+     +                               edge, stride, 
+     +                               imap, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EEDGE)
+     +                  call errore('bad edge: ', err)
+                endif
+                edge(j) = 1
+                stride(j) = 0
+                err = nf_get_varm_int2(ncid, i, start,
+     +                               edge, stride, 
+     +                               imap, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_ESTRIDE)
+     +                  call errore('bad stride: ', err)
+                endif
+                stride(j) = 1
+3           continue
+C               Choose a random point dividing each dim into 2 parts 
+C               get 2^rank (nslabs) slabs so defined 
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+C               /* bits of k determine whether to get lower or upper part 
+C                * of dim
+C                * choose random stride from 1 to edge */
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift((k-1), -(j-1)), 2) .ne. 0) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        stride(j) = 1+roll(edge(j))
+                    else
+                        stride(j) = 1
+                    end if
+                    sstride(j) = stride(j)
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / 
+     +                                  stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+C                       Random choice of forward or backward 
+C    /* TODO
+C                   if ( roll(2) ) then
+C                       for (j = 0 j < var_rank(i) j++) {
+C                           index(j) += (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C                       }
+C                   end if
+C     */
+                    if (var_rank(i) .gt. 0) then
+                        imap(1) = 1
+                        do 9, j = 2, var_rank(i)
+                            imap(j) = imap(j-1) * count(j-1)
+9                       continue
+                    end if
+                    allInIntRange = .true.
+                    allInExtRange = .true.
+                    do 10, j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes 1')
+                        do 11, d = 1, var_rank(i)
+                            index2(d) = index(d) + (index2(d)-1) * 
+     +                                  stride(d)
+11                      continue
+                        expect(j) = hash4(var_type(i), var_rank(i), 
+     +                                    index2, NFT_INT2)
+                        if (inRange3(expect(j),var_type(i),
+     +                               NFT_INT2)) then
+                            allInIntRange = 
+     +                          allInIntRange .and.
+     +                          in_internal_range(NFT_INT2,
+     +                                            expect(j))
+                        else
+                            allInExtRange = .false.
+                        end if
+10                  continue
+                    err = nf_get_varm_int2(ncid,i,index,count,
+     +                                   stride,imap,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (allInIntRange) then
+                                if (err .ne. 0)
+     +                              call error(nf_strerror(err))
+                            else
+                                if (err .ne. NF_ERANGE)
+     +                              call errore('Range error: ', err)
+                            end if
+                        else
+                            if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                          call errore('OK or Range error: ', err)
+                        end if
+                        do 12, j = 1, nels
+                            if (inRange3(expect(j),var_type(i),
+     +                                   NFT_INT2) .and.
+     +                          in_internal_range(NFT_INT2,
+     +                                            expect(j))) then
+                                val = value(j)
+                                if (.not.equal(val, expect(j),
+     +                                         var_type(i), 
+     +                                         NFT_INT2)) then
+                                    call error(
+     +                                  'value read not that expected')
+                                    if (verbose) then
+                                        call error(' ')
+                                        call errori('varid: ', i)
+                                        call errorc('var_name: ', 
+     +                                          var_name(i))
+                                        call errori('element number: ',
+     +                                              j)
+                                        call errord('expect: ', 
+     +                                              expect(j))
+                                        call errord('got: ', val)
+                                    end if
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+12                      continue
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ',  err)
+        call print_nok(nok)
+        end
+
+#endif
+        subroutine test_nf_get_varm_int()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nslabs
+        integer nstarts         
+        integer nok             
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        integer imap(MAX_RANK)
+        logical canConvert     
+        integer    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv. 
+     +                   (NFT_INT .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK)) stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS)) stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+                imap(j) = 1
+2           continue
+            err = nf_get_varm_int(BAD_ID, i, start, edge,
+     +                           stride, imap, 
+     +                           value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_varm_int(ncid, BAD_VARID, start,
+     +                           edge, stride, 
+     +                           imap, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                start(j) = var_shape(j,i) + 1
+                err = nf_get_varm_int(ncid, i, start,
+     +                               edge, stride, 
+     +                               imap, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad index: ', err)
+                endif
+                start(j) = 1
+                edge(j) = var_shape(j,i) + 1
+                err = nf_get_varm_int(ncid, i, start,
+     +                               edge, stride, 
+     +                               imap, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EEDGE)
+     +                  call errore('bad edge: ', err)
+                endif
+                edge(j) = 1
+                stride(j) = 0
+                err = nf_get_varm_int(ncid, i, start,
+     +                               edge, stride, 
+     +                               imap, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_ESTRIDE)
+     +                  call errore('bad stride: ', err)
+                endif
+                stride(j) = 1
+3           continue
+C               Choose a random point dividing each dim into 2 parts 
+C               get 2^rank (nslabs) slabs so defined 
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+C               /* bits of k determine whether to get lower or upper part 
+C                * of dim
+C                * choose random stride from 1 to edge */
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift((k-1), -(j-1)), 2) .ne. 0) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        stride(j) = 1+roll(edge(j))
+                    else
+                        stride(j) = 1
+                    end if
+                    sstride(j) = stride(j)
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / 
+     +                                  stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+C                       Random choice of forward or backward 
+C    /* TODO
+C                   if ( roll(2) ) then
+C                       for (j = 0 j < var_rank(i) j++) {
+C                           index(j) += (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C                       }
+C                   end if
+C     */
+                    if (var_rank(i) .gt. 0) then
+                        imap(1) = 1
+                        do 9, j = 2, var_rank(i)
+                            imap(j) = imap(j-1) * count(j-1)
+9                       continue
+                    end if
+                    allInIntRange = .true.
+                    allInExtRange = .true.
+                    do 10, j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes 1')
+                        do 11, d = 1, var_rank(i)
+                            index2(d) = index(d) + (index2(d)-1) * 
+     +                                  stride(d)
+11                      continue
+                        expect(j) = hash4(var_type(i), var_rank(i), 
+     +                                    index2, NFT_INT)
+                        if (inRange3(expect(j),var_type(i),
+     +                               NFT_INT)) then
+                            allInIntRange = 
+     +                          allInIntRange .and.
+     +                          in_internal_range(NFT_INT,
+     +                                            expect(j))
+                        else
+                            allInExtRange = .false.
+                        end if
+10                  continue
+                    err = nf_get_varm_int(ncid,i,index,count,
+     +                                   stride,imap,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (allInIntRange) then
+                                if (err .ne. 0)
+     +                              call error(nf_strerror(err))
+                            else
+                                if (err .ne. NF_ERANGE)
+     +                              call errore('Range error: ', err)
+                            end if
+                        else
+                            if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                          call errore('OK or Range error: ', err)
+                        end if
+                        do 12, j = 1, nels
+                            if (inRange3(expect(j),var_type(i),
+     +                                   NFT_INT) .and.
+     +                          in_internal_range(NFT_INT,
+     +                                            expect(j))) then
+                                val = value(j)
+                                if (.not.equal(val, expect(j),
+     +                                         var_type(i), 
+     +                                         NFT_INT)) then
+                                    call error(
+     +                                  'value read not that expected')
+                                    if (verbose) then
+                                        call error(' ')
+                                        call errori('varid: ', i)
+                                        call errorc('var_name: ', 
+     +                                          var_name(i))
+                                        call errori('element number: ',
+     +                                              j)
+                                        call errord('expect: ', 
+     +                                              expect(j))
+                                        call errord('got: ', val)
+                                    end if
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+12                      continue
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ',  err)
+        call print_nok(nok)
+        end
+
+        subroutine test_nf_get_varm_real()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nslabs
+        integer nstarts         
+        integer nok             
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        integer imap(MAX_RANK)
+        logical canConvert     
+        real    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv. 
+     +                   (NFT_REAL .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK)) stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS)) stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+                imap(j) = 1
+2           continue
+            err = nf_get_varm_real(BAD_ID, i, start, edge,
+     +                           stride, imap, 
+     +                           value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_varm_real(ncid, BAD_VARID, start,
+     +                           edge, stride, 
+     +                           imap, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                start(j) = var_shape(j,i) + 1
+                err = nf_get_varm_real(ncid, i, start,
+     +                               edge, stride, 
+     +                               imap, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad index: ', err)
+                endif
+                start(j) = 1
+                edge(j) = var_shape(j,i) + 1
+                err = nf_get_varm_real(ncid, i, start,
+     +                               edge, stride, 
+     +                               imap, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EEDGE)
+     +                  call errore('bad edge: ', err)
+                endif
+                edge(j) = 1
+                stride(j) = 0
+                err = nf_get_varm_real(ncid, i, start,
+     +                               edge, stride, 
+     +                               imap, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_ESTRIDE)
+     +                  call errore('bad stride: ', err)
+                endif
+                stride(j) = 1
+3           continue
+C               Choose a random point dividing each dim into 2 parts 
+C               get 2^rank (nslabs) slabs so defined 
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+C               /* bits of k determine whether to get lower or upper part 
+C                * of dim
+C                * choose random stride from 1 to edge */
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift((k-1), -(j-1)), 2) .ne. 0) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        stride(j) = 1+roll(edge(j))
+                    else
+                        stride(j) = 1
+                    end if
+                    sstride(j) = stride(j)
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / 
+     +                                  stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+C                       Random choice of forward or backward 
+C    /* TODO
+C                   if ( roll(2) ) then
+C                       for (j = 0 j < var_rank(i) j++) {
+C                           index(j) += (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C                       }
+C                   end if
+C     */
+                    if (var_rank(i) .gt. 0) then
+                        imap(1) = 1
+                        do 9, j = 2, var_rank(i)
+                            imap(j) = imap(j-1) * count(j-1)
+9                       continue
+                    end if
+                    allInIntRange = .true.
+                    allInExtRange = .true.
+                    do 10, j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes 1')
+                        do 11, d = 1, var_rank(i)
+                            index2(d) = index(d) + (index2(d)-1) * 
+     +                                  stride(d)
+11                      continue
+                        expect(j) = hash4(var_type(i), var_rank(i), 
+     +                                    index2, NFT_REAL)
+                        if (inRange3(expect(j),var_type(i),
+     +                               NFT_REAL)) then
+                            allInIntRange = 
+     +                          allInIntRange .and.
+     +                          in_internal_range(NFT_REAL,
+     +                                            expect(j))
+                        else
+                            allInExtRange = .false.
+                        end if
+10                  continue
+                    err = nf_get_varm_real(ncid,i,index,count,
+     +                                   stride,imap,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (allInIntRange) then
+                                if (err .ne. 0)
+     +                              call error(nf_strerror(err))
+                            else
+                                if (err .ne. NF_ERANGE)
+     +                              call errore('Range error: ', err)
+                            end if
+                        else
+                            if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                          call errore('OK or Range error: ', err)
+                        end if
+                        do 12, j = 1, nels
+                            if (inRange3(expect(j),var_type(i),
+     +                                   NFT_REAL) .and.
+     +                          in_internal_range(NFT_REAL,
+     +                                            expect(j))) then
+                                val = value(j)
+                                if (.not.equal(val, expect(j),
+     +                                         var_type(i), 
+     +                                         NFT_REAL)) then
+                                    call error(
+     +                                  'value read not that expected')
+                                    if (verbose) then
+                                        call error(' ')
+                                        call errori('varid: ', i)
+                                        call errorc('var_name: ', 
+     +                                          var_name(i))
+                                        call errori('element number: ',
+     +                                              j)
+                                        call errord('expect: ', 
+     +                                              expect(j))
+                                        call errord('got: ', val)
+                                    end if
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+12                      continue
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ',  err)
+        call print_nok(nok)
+        end
+
+        subroutine test_nf_get_varm_double()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        logical allInExtRange   
+        logical allInIntRange   
+        integer nels
+        integer nslabs
+        integer nstarts         
+        integer nok             
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        integer imap(MAX_RANK)
+        logical canConvert     
+        doubleprecision    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv. 
+     +                   (NFT_DOUBLE .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK)) stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS)) stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+                imap(j) = 1
+2           continue
+            err = nf_get_varm_double(BAD_ID, i, start, edge,
+     +                           stride, imap, 
+     +                           value)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_get_varm_double(ncid, BAD_VARID, start,
+     +                           edge, stride, 
+     +                           imap, value)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                start(j) = var_shape(j,i) + 1
+                err = nf_get_varm_double(ncid, i, start,
+     +                               edge, stride, 
+     +                               imap, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad index: ', err)
+                endif
+                start(j) = 1
+                edge(j) = var_shape(j,i) + 1
+                err = nf_get_varm_double(ncid, i, start,
+     +                               edge, stride, 
+     +                               imap, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EEDGE)
+     +                  call errore('bad edge: ', err)
+                endif
+                edge(j) = 1
+                stride(j) = 0
+                err = nf_get_varm_double(ncid, i, start,
+     +                               edge, stride, 
+     +                               imap, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_ESTRIDE)
+     +                  call errore('bad stride: ', err)
+                endif
+                stride(j) = 1
+3           continue
+C               Choose a random point dividing each dim into 2 parts 
+C               get 2^rank (nslabs) slabs so defined 
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+C               /* bits of k determine whether to get lower or upper part 
+C                * of dim
+C                * choose random stride from 1 to edge */
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift((k-1), -(j-1)), 2) .ne. 0) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        stride(j) = 1+roll(edge(j))
+                    else
+                        stride(j) = 1
+                    end if
+                    sstride(j) = stride(j)
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / 
+     +                                  stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+C                       Random choice of forward or backward 
+C    /* TODO
+C                   if ( roll(2) ) then
+C                       for (j = 0 j < var_rank(i) j++) {
+C                           index(j) += (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C                       }
+C                   end if
+C     */
+                    if (var_rank(i) .gt. 0) then
+                        imap(1) = 1
+                        do 9, j = 2, var_rank(i)
+                            imap(j) = imap(j-1) * count(j-1)
+9                       continue
+                    end if
+                    allInIntRange = .true.
+                    allInExtRange = .true.
+                    do 10, j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes 1')
+                        do 11, d = 1, var_rank(i)
+                            index2(d) = index(d) + (index2(d)-1) * 
+     +                                  stride(d)
+11                      continue
+                        expect(j) = hash4(var_type(i), var_rank(i), 
+     +                                    index2, NFT_DOUBLE)
+                        if (inRange3(expect(j),var_type(i),
+     +                               NFT_DOUBLE)) then
+                            allInIntRange = 
+     +                          allInIntRange .and.
+     +                          in_internal_range(NFT_DOUBLE,
+     +                                            expect(j))
+                        else
+                            allInExtRange = .false.
+                        end if
+10                  continue
+                    err = nf_get_varm_double(ncid,i,index,count,
+     +                                   stride,imap,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (allInIntRange) then
+                                if (err .ne. 0)
+     +                              call error(nf_strerror(err))
+                            else
+                                if (err .ne. NF_ERANGE)
+     +                              call errore('Range error: ', err)
+                            end if
+                        else
+                            if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                          call errore('OK or Range error: ', err)
+                        end if
+                        do 12, j = 1, nels
+                            if (inRange3(expect(j),var_type(i),
+     +                                   NFT_DOUBLE) .and.
+     +                          in_internal_range(NFT_DOUBLE,
+     +                                            expect(j))) then
+                                val = value(j)
+                                if (.not.equal(val, expect(j),
+     +                                         var_type(i), 
+     +                                         NFT_DOUBLE)) then
+                                    call error(
+     +                                  'value read not that expected')
+                                    if (verbose) then
+                                        call error(' ')
+                                        call errori('varid: ', i)
+                                        call errorc('var_name: ', 
+     +                                          var_name(i))
+                                        call errori('element number: ',
+     +                                              j)
+                                        call errord('expect: ', 
+     +                                              expect(j))
+                                        call errord('got: ', val)
+                                    end if
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+12                      continue
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ',  err)
+        call print_nok(nok)
+        end
+
+
+        subroutine test_nf_get_att_text()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer k
+        integer err
+        integer ndx(1)
+        logical allInExtRange
+        logical allInIntRange
+        logical canConvert     
+        character    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        integer nok             
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_open: ', err)
+
+        do 1, i = 0, NVARS
+            do 2, j = 1, NATTS(i)
+                canConvert = (ATT_TYPE(j,i) .eq. NF_CHAR) .eqv.
+     +                       (NFT_TEXT .eq. NFT_TEXT)
+                err = nf_get_att_text(BAD_ID, i,
+     +                  ATT_NAME(j,i), 
+     +                  value)
+                if (err .ne. NF_EBADID) 
+     +              call errore('bad ncid: ', err)
+                err = nf_get_att_text(ncid, BAD_VARID, 
+     +                              ATT_NAME(j,i), 
+     +                              value)
+                if (err .ne. NF_ENOTVAR) 
+     +              call errore('bad var id: ', err)
+                err = nf_get_att_text(ncid, i, 'noSuch', value)
+                if (err .ne. NF_ENOTATT) 
+     +              call errore('Bad attribute name: ', err)
+                allInIntRange = .true.
+                allInExtRange = .true.
+                do 3, k = 1, ATT_LEN(j,i)
+                    ndx(1) = k
+                    expect(k) = hash4(ATT_TYPE(j,i), -1, ndx, 
+     +                                NFT_TEXT)
+                    if (inRange3(expect(k),ATT_TYPE(j,i),
+     +                           NFT_TEXT)) then
+                        allInIntRange = 
+     +                      allInIntRange .and.
+     +                      in_internal_range(NFT_TEXT, expect(k))
+                    else
+                        allInExtRange = .false.
+                    end if
+3               continue
+                err = nf_get_att_text(ncid, i, ATT_NAME(j,i), value)
+                if (canConvert .or. ATT_LEN(j,i) .eq. 0) then
+                    if (allInExtRange) then
+                        if (allInIntRange) then
+                            if (err .ne. 0)
+     +                          call errore('nf_get_att_text: ', err)
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('Range error: ', err)
+                        end if
+                    else
+                        if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ',
+     +                                  err)
+                    end if
+                    do 4, k = 1, ATT_LEN(j,i)
+                        if (inRange3(expect(k),ATT_TYPE(j,i),
+     +                               NFT_TEXT) .and.
+     +                      in_internal_range(NFT_TEXT,
+     +                                        expect(k))) then
+                            val = ichar(value(k))
+                            if (.not.equal(val, expect(k),
+     +                                     ATT_TYPE(j,i), 
+     +                                     NFT_TEXT))then
+                                call error(
+     +                              'value read not that expected')
+                                if (verbose) then
+                                    call error(' ')
+                                    call errori('varid: ', i)
+                                    call errorc('att_name: ', 
+     +                                  ATT_NAME(j,i))
+                                    call errori('element number: ', k)
+                                    call errord('expect: ', expect(k))
+                                    call errord('got: ', val)
+                                end if
+                            else
+                                nok = nok + 1
+                            end if
+                        end if
+4                   continue
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+2           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        call print_nok(nok)
+        end
+
+#ifdef NF_INT1_T
+        subroutine test_nf_get_att_int1()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer k
+        integer err
+        integer ndx(1)
+        logical allInExtRange
+        logical allInIntRange
+        logical canConvert     
+        NF_INT1_T    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        integer nok             
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_open: ', err)
+
+        do 1, i = 0, NVARS
+            do 2, j = 1, NATTS(i)
+                canConvert = (ATT_TYPE(j,i) .eq. NF_CHAR) .eqv.
+     +                       (NFT_INT1 .eq. NFT_TEXT)
+                err = nf_get_att_int1(BAD_ID, i,
+     +                  ATT_NAME(j,i), 
+     +                  value)
+                if (err .ne. NF_EBADID) 
+     +              call errore('bad ncid: ', err)
+                err = nf_get_att_int1(ncid, BAD_VARID, 
+     +                              ATT_NAME(j,i), 
+     +                              value)
+                if (err .ne. NF_ENOTVAR) 
+     +              call errore('bad var id: ', err)
+                err = nf_get_att_int1(ncid, i, 'noSuch', value)
+                if (err .ne. NF_ENOTATT) 
+     +              call errore('Bad attribute name: ', err)
+                allInIntRange = .true.
+                allInExtRange = .true.
+                do 3, k = 1, ATT_LEN(j,i)
+                    ndx(1) = k
+                    expect(k) = hash4(ATT_TYPE(j,i), -1, ndx, 
+     +                                NFT_INT1)
+                    if (inRange3(expect(k),ATT_TYPE(j,i),
+     +                           NFT_INT1)) then
+                        allInIntRange = 
+     +                      allInIntRange .and.
+     +                      in_internal_range(NFT_INT1, expect(k))
+                    else
+                        allInExtRange = .false.
+                    end if
+3               continue
+                err = nf_get_att_int1(ncid, i, ATT_NAME(j,i), value)
+                if (canConvert .or. ATT_LEN(j,i) .eq. 0) then
+                    if (allInExtRange) then
+                        if (allInIntRange) then
+                            if (err .ne. 0)
+     +                          call errore('nf_get_att_int1: ', err)
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('Range error: ', err)
+                        end if
+                    else
+                        if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ',
+     +                                  err)
+                    end if
+                    do 4, k = 1, ATT_LEN(j,i)
+                        if (inRange3(expect(k),ATT_TYPE(j,i),
+     +                               NFT_INT1) .and.
+     +                      in_internal_range(NFT_INT1,
+     +                                        expect(k))) then
+                            val = value(k)
+                            if (.not.equal(val, expect(k),
+     +                                     ATT_TYPE(j,i), 
+     +                                     NFT_INT1))then
+                                call error(
+     +                              'value read not that expected')
+                                if (verbose) then
+                                    call error(' ')
+                                    call errori('varid: ', i)
+                                    call errorc('att_name: ', 
+     +                                  ATT_NAME(j,i))
+                                    call errori('element number: ', k)
+                                    call errord('expect: ', expect(k))
+                                    call errord('got: ', val)
+                                end if
+                            else
+                                nok = nok + 1
+                            end if
+                        end if
+4                   continue
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+2           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        call print_nok(nok)
+        end
+
+#endif
+#ifdef NF_INT2_T
+        subroutine test_nf_get_att_int2()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer k
+        integer err
+        integer ndx(1)
+        logical allInExtRange
+        logical allInIntRange
+        logical canConvert     
+        NF_INT2_T    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        integer nok             
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_open: ', err)
+
+        do 1, i = 0, NVARS
+            do 2, j = 1, NATTS(i)
+                canConvert = (ATT_TYPE(j,i) .eq. NF_CHAR) .eqv.
+     +                       (NFT_INT2 .eq. NFT_TEXT)
+                err = nf_get_att_int2(BAD_ID, i,
+     +                  ATT_NAME(j,i), 
+     +                  value)
+                if (err .ne. NF_EBADID) 
+     +              call errore('bad ncid: ', err)
+                err = nf_get_att_int2(ncid, BAD_VARID, 
+     +                              ATT_NAME(j,i), 
+     +                              value)
+                if (err .ne. NF_ENOTVAR) 
+     +              call errore('bad var id: ', err)
+                err = nf_get_att_int2(ncid, i, 'noSuch', value)
+                if (err .ne. NF_ENOTATT) 
+     +              call errore('Bad attribute name: ', err)
+                allInIntRange = .true.
+                allInExtRange = .true.
+                do 3, k = 1, ATT_LEN(j,i)
+                    ndx(1) = k
+                    expect(k) = hash4(ATT_TYPE(j,i), -1, ndx, 
+     +                                NFT_INT2)
+                    if (inRange3(expect(k),ATT_TYPE(j,i),
+     +                           NFT_INT2)) then
+                        allInIntRange = 
+     +                      allInIntRange .and.
+     +                      in_internal_range(NFT_INT2, expect(k))
+                    else
+                        allInExtRange = .false.
+                    end if
+3               continue
+                err = nf_get_att_int2(ncid, i, ATT_NAME(j,i), value)
+                if (canConvert .or. ATT_LEN(j,i) .eq. 0) then
+                    if (allInExtRange) then
+                        if (allInIntRange) then
+                            if (err .ne. 0)
+     +                          call errore('nf_get_att_int2: ', err)
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('Range error: ', err)
+                        end if
+                    else
+                        if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ',
+     +                                  err)
+                    end if
+                    do 4, k = 1, ATT_LEN(j,i)
+                        if (inRange3(expect(k),ATT_TYPE(j,i),
+     +                               NFT_INT2) .and.
+     +                      in_internal_range(NFT_INT2,
+     +                                        expect(k))) then
+                            val = value(k)
+                            if (.not.equal(val, expect(k),
+     +                                     ATT_TYPE(j,i), 
+     +                                     NFT_INT2))then
+                                call error(
+     +                              'value read not that expected')
+                                if (verbose) then
+                                    call error(' ')
+                                    call errori('varid: ', i)
+                                    call errorc('att_name: ', 
+     +                                  ATT_NAME(j,i))
+                                    call errori('element number: ', k)
+                                    call errord('expect: ', expect(k))
+                                    call errord('got: ', val)
+                                end if
+                            else
+                                nok = nok + 1
+                            end if
+                        end if
+4                   continue
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+2           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        call print_nok(nok)
+        end
+
+#endif
+        subroutine test_nf_get_att_int()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer k
+        integer err
+        integer ndx(1)
+        logical allInExtRange
+        logical allInIntRange
+        logical canConvert     
+        integer    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        integer nok             
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_open: ', err)
+
+        do 1, i = 0, NVARS
+            do 2, j = 1, NATTS(i)
+                canConvert = (ATT_TYPE(j,i) .eq. NF_CHAR) .eqv.
+     +                       (NFT_INT .eq. NFT_TEXT)
+                err = nf_get_att_int(BAD_ID, i,
+     +                  ATT_NAME(j,i), 
+     +                  value)
+                if (err .ne. NF_EBADID) 
+     +              call errore('bad ncid: ', err)
+                err = nf_get_att_int(ncid, BAD_VARID, 
+     +                              ATT_NAME(j,i), 
+     +                              value)
+                if (err .ne. NF_ENOTVAR) 
+     +              call errore('bad var id: ', err)
+                err = nf_get_att_int(ncid, i, 'noSuch', value)
+                if (err .ne. NF_ENOTATT) 
+     +              call errore('Bad attribute name: ', err)
+                allInIntRange = .true.
+                allInExtRange = .true.
+                do 3, k = 1, ATT_LEN(j,i)
+                    ndx(1) = k
+                    expect(k) = hash4(ATT_TYPE(j,i), -1, ndx, 
+     +                                NFT_INT)
+                    if (inRange3(expect(k),ATT_TYPE(j,i),
+     +                           NFT_INT)) then
+                        allInIntRange = 
+     +                      allInIntRange .and.
+     +                      in_internal_range(NFT_INT, expect(k))
+                    else
+                        allInExtRange = .false.
+                    end if
+3               continue
+                err = nf_get_att_int(ncid, i, ATT_NAME(j,i), value)
+                if (canConvert .or. ATT_LEN(j,i) .eq. 0) then
+                    if (allInExtRange) then
+                        if (allInIntRange) then
+                            if (err .ne. 0)
+     +                          call errore('nf_get_att_int: ', err)
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('Range error: ', err)
+                        end if
+                    else
+                        if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ',
+     +                                  err)
+                    end if
+                    do 4, k = 1, ATT_LEN(j,i)
+                        if (inRange3(expect(k),ATT_TYPE(j,i),
+     +                               NFT_INT) .and.
+     +                      in_internal_range(NFT_INT,
+     +                                        expect(k))) then
+                            val = value(k)
+                            if (.not.equal(val, expect(k),
+     +                                     ATT_TYPE(j,i), 
+     +                                     NFT_INT))then
+                                call error(
+     +                              'value read not that expected')
+                                if (verbose) then
+                                    call error(' ')
+                                    call errori('varid: ', i)
+                                    call errorc('att_name: ', 
+     +                                  ATT_NAME(j,i))
+                                    call errori('element number: ', k)
+                                    call errord('expect: ', expect(k))
+                                    call errord('got: ', val)
+                                end if
+                            else
+                                nok = nok + 1
+                            end if
+                        end if
+4                   continue
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+2           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        call print_nok(nok)
+        end
+
+        subroutine test_nf_get_att_real()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer k
+        integer err
+        integer ndx(1)
+        logical allInExtRange
+        logical allInIntRange
+        logical canConvert     
+        real    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        integer nok             
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_open: ', err)
+
+        do 1, i = 0, NVARS
+            do 2, j = 1, NATTS(i)
+                canConvert = (ATT_TYPE(j,i) .eq. NF_CHAR) .eqv.
+     +                       (NFT_REAL .eq. NFT_TEXT)
+                err = nf_get_att_real(BAD_ID, i,
+     +                  ATT_NAME(j,i), 
+     +                  value)
+                if (err .ne. NF_EBADID) 
+     +              call errore('bad ncid: ', err)
+                err = nf_get_att_real(ncid, BAD_VARID, 
+     +                              ATT_NAME(j,i), 
+     +                              value)
+                if (err .ne. NF_ENOTVAR) 
+     +              call errore('bad var id: ', err)
+                err = nf_get_att_real(ncid, i, 'noSuch', value)
+                if (err .ne. NF_ENOTATT) 
+     +              call errore('Bad attribute name: ', err)
+                allInIntRange = .true.
+                allInExtRange = .true.
+                do 3, k = 1, ATT_LEN(j,i)
+                    ndx(1) = k
+                    expect(k) = hash4(ATT_TYPE(j,i), -1, ndx, 
+     +                                NFT_REAL)
+                    if (inRange3(expect(k),ATT_TYPE(j,i),
+     +                           NFT_REAL)) then
+                        allInIntRange = 
+     +                      allInIntRange .and.
+     +                      in_internal_range(NFT_REAL, expect(k))
+                    else
+                        allInExtRange = .false.
+                    end if
+3               continue
+                err = nf_get_att_real(ncid, i, ATT_NAME(j,i), value)
+                if (canConvert .or. ATT_LEN(j,i) .eq. 0) then
+                    if (allInExtRange) then
+                        if (allInIntRange) then
+                            if (err .ne. 0)
+     +                          call errore('nf_get_att_real: ', err)
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('Range error: ', err)
+                        end if
+                    else
+                        if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ',
+     +                                  err)
+                    end if
+                    do 4, k = 1, ATT_LEN(j,i)
+                        if (inRange3(expect(k),ATT_TYPE(j,i),
+     +                               NFT_REAL) .and.
+     +                      in_internal_range(NFT_REAL,
+     +                                        expect(k))) then
+                            val = value(k)
+                            if (.not.equal(val, expect(k),
+     +                                     ATT_TYPE(j,i), 
+     +                                     NFT_REAL))then
+                                call error(
+     +                              'value read not that expected')
+                                if (verbose) then
+                                    call error(' ')
+                                    call errori('varid: ', i)
+                                    call errorc('att_name: ', 
+     +                                  ATT_NAME(j,i))
+                                    call errori('element number: ', k)
+                                    call errord('expect: ', expect(k))
+                                    call errord('got: ', val)
+                                end if
+                            else
+                                nok = nok + 1
+                            end if
+                        end if
+4                   continue
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+2           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        call print_nok(nok)
+        end
+
+        subroutine test_nf_get_att_double()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer k
+        integer err
+        integer ndx(1)
+        logical allInExtRange
+        logical allInIntRange
+        logical canConvert     
+        doubleprecision    value(MAX_NELS)
+        doubleprecision expect(MAX_NELS)
+        integer nok             
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_open: ', err)
+
+        do 1, i = 0, NVARS
+            do 2, j = 1, NATTS(i)
+                canConvert = (ATT_TYPE(j,i) .eq. NF_CHAR) .eqv.
+     +                       (NFT_DOUBLE .eq. NFT_TEXT)
+                err = nf_get_att_double(BAD_ID, i,
+     +                  ATT_NAME(j,i), 
+     +                  value)
+                if (err .ne. NF_EBADID) 
+     +              call errore('bad ncid: ', err)
+                err = nf_get_att_double(ncid, BAD_VARID, 
+     +                              ATT_NAME(j,i), 
+     +                              value)
+                if (err .ne. NF_ENOTVAR) 
+     +              call errore('bad var id: ', err)
+                err = nf_get_att_double(ncid, i, 'noSuch', value)
+                if (err .ne. NF_ENOTATT) 
+     +              call errore('Bad attribute name: ', err)
+                allInIntRange = .true.
+                allInExtRange = .true.
+                do 3, k = 1, ATT_LEN(j,i)
+                    ndx(1) = k
+                    expect(k) = hash4(ATT_TYPE(j,i), -1, ndx, 
+     +                                NFT_DOUBLE)
+                    if (inRange3(expect(k),ATT_TYPE(j,i),
+     +                           NFT_DOUBLE)) then
+                        allInIntRange = 
+     +                      allInIntRange .and.
+     +                      in_internal_range(NFT_DOUBLE, expect(k))
+                    else
+                        allInExtRange = .false.
+                    end if
+3               continue
+                err = nf_get_att_double(ncid, i, ATT_NAME(j,i), value)
+                if (canConvert .or. ATT_LEN(j,i) .eq. 0) then
+                    if (allInExtRange) then
+                        if (allInIntRange) then
+                            if (err .ne. 0)
+     +                          call errore('nf_get_att_double: ', err)
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('Range error: ', err)
+                        end if
+                    else
+                        if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ',
+     +                                  err)
+                    end if
+                    do 4, k = 1, ATT_LEN(j,i)
+                        if (inRange3(expect(k),ATT_TYPE(j,i),
+     +                               NFT_DOUBLE) .and.
+     +                      in_internal_range(NFT_DOUBLE,
+     +                                        expect(k))) then
+                            val = value(k)
+                            if (.not.equal(val, expect(k),
+     +                                     ATT_TYPE(j,i), 
+     +                                     NFT_DOUBLE))then
+                                call error(
+     +                              'value read not that expected')
+                                if (verbose) then
+                                    call error(' ')
+                                    call errori('varid: ', i)
+                                    call errorc('att_name: ', 
+     +                                  ATT_NAME(j,i))
+                                    call errori('element number: ', k)
+                                    call errord('expect: ', expect(k))
+                                    call errord('got: ', val)
+                                end if
+                            else
+                                nok = nok + 1
+                            end if
+                        end if
+4                   continue
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+2           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        call print_nok(nok)
+        end
+
diff --git a/nf_test/test03_put.F b/nf_test/test03_put.F
new file mode 100755
index 0000000..678cec3
--- /dev/null
+++ b/nf_test/test03_put.F
@@ -0,0 +1,6647 @@
+#include "../fortran/nf03config.inc"
+C Do not edit this file. It is produced from the corresponding .m4 source */
+
+C********************************************************************
+C   Copyright 1996, UCAR/Unidata
+C   See netcdf/COPYRIGHT file for copying and redistribution conditions.
+C   $Id: test_put.m4,v 1.16 2008/04/30 16:50:45 ed Exp $
+C********************************************************************
+
+C
+C ensure hash value within range for internal TYPE
+C
+        function hash_text(type, rank, index, itype)
+        use tests, ONLY: internal_min, internal_max, RK8, hash4
+        implicit        none
+        integer type
+        integer rank
+        integer index(1)
+        integer itype
+        doubleprecision minimum
+        doubleprecision maximum
+        real(RK8) hash_text
+        minimum = internal_min(itype)
+        maximum = internal_max(itype)
+
+        hash_text = max(minimum, min(maximum, hash4( type, rank,
+     +      index, itype)))
+        end
+
+#ifdef NF_INT1_T
+C
+C ensure hash value within range for internal TYPE
+C
+        function hash_int1(type, rank, index, itype)
+        use tests, ONLY: internal_min, internal_max, RK8, hash4
+        implicit        none
+        integer type
+        integer rank
+        integer index(1)
+        integer itype
+        real(RK8) hash_int1
+        doubleprecision minimum
+        doubleprecision maximum
+
+        minimum = internal_min(itype)
+        maximum = internal_max(itype)
+
+        hash_int1 = max(minimum, min(maximum, hash4( type, rank,
+     +      index, itype)))
+        end
+
+#endif
+#ifdef NF_INT2_T
+C
+C ensure hash value within range for internal TYPE
+C
+        function hash_int2(type, rank, index, itype)
+        use tests, ONLY: internal_min, internal_max, RK8, hash4
+        implicit        none
+        integer type
+        integer rank
+        integer index(1)
+        integer itype
+        doubleprecision minimum
+        doubleprecision maximum
+        real(RK8) hash_int2
+        minimum = internal_min(itype)
+        maximum = internal_max(itype)
+
+        hash_int2 = max(minimum, min(maximum, hash4( type, rank,
+     +      index, itype)))
+        end
+
+#endif
+C
+C ensure hash value within range for internal TYPE
+C
+        function hash_int(type, rank, index, itype)
+        use tests, ONLY: internal_min, internal_max, RK8, hash4
+        implicit        none
+        integer type
+        integer rank
+        integer index(1)
+        integer itype
+        real(RK8) hash_int
+        doubleprecision minimum
+        doubleprecision maximum
+
+        minimum = internal_min(itype)
+        maximum = internal_max(itype)
+
+        hash_int = max(minimum, min(maximum, hash4( type, rank,
+     +      index, itype)))
+        end
+
+C
+C ensure hash value within range for internal TYPE
+C
+        function hash_real(type, rank, index, itype)
+        use tests, ONLY: internal_min, internal_max, RK8, hash4
+        implicit        none
+        integer type
+        integer rank
+        integer index(1)
+        integer itype
+        real(RK8) hash_real
+        doubleprecision minimum
+        doubleprecision maximum
+
+        minimum = internal_min(itype)
+        maximum = internal_max(itype)
+
+        hash_real = max(minimum, min(maximum, hash4( type, rank,
+     +      index, itype)))
+        end
+
+C
+C ensure hash value within range for internal TYPE
+C
+        function hash_double(type, rank, index, itype)
+        use tests, ONLY: internal_min, internal_max, RK8, hash4
+        implicit        none
+        integer type
+        integer rank
+        integer index(1)
+        integer itype
+        real(RK8) hash_double
+        doubleprecision minimum
+        doubleprecision maximum
+
+        minimum = internal_min(itype)
+        maximum = internal_max(itype)
+
+        hash_double = max(minimum, min(maximum, hash4( type, rank,
+     +      index, itype)))
+        end
+
+
+C
+C check all vars in file which are (text/numeric) compatible with TYPE
+C
+        subroutine check_vars_text(filename)
+        use tests, NDIMSG=>NDIMS, NGATTSG=>NGATTS
+        implicit        none
+        character*(*)   filename
+        integer  ncid          !/* netCDF id */
+        integer index(MAX_RANK)
+        integer  err           !/* status */
+        integer  d
+        integer  i
+        integer  j
+        character    value
+        integer datatype
+        integer ndims
+        integer dimids(MAX_RANK)
+        integer ngatts
+        doubleprecision expect
+        character*(NF_MAX_NAME) name
+        integer length
+        logical canConvert      !/* Both text or both numeric */
+        integer nok             !/* count of valid comparisons */
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(filename, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_TEXT .eq. NFT_TEXT)
+            if (canConvert)  then
+                err = nf_inq_var(ncid, i, name, datatype, ndims, dimids,
+     +                           ngatts)
+                if (err .ne. 0)
+     +              call errore('nf_inq_var: ', err)
+                if (name .ne. var_name(i))
+     +              call error('Unexpected var_name')
+                if (datatype .ne. var_type(i))
+     +              call error('Unexpected type')
+                if (ndims .ne. var_rank(i))
+     +              call error('Unexpected rank')
+                do 2, j = 1, ndims
+                    err = nf_inq_dim(ncid, dimids(j), name, length)
+                    if (err .ne. 0)
+     +                  call errore('nf_inq_dim: ', err)
+                    if (length .ne. var_shape(j,i))
+     +                  call error('Unexpected shape')
+2               continue
+                do 3, j = 1, var_nels(i)
+                    err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                                  index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes()')
+                    expect = hash4( var_type(i), var_rank(i), index, 
+     +                             NFT_TEXT)
+                    err = nf_get_var1_text(ncid, i, index, value)
+                    if (inRange3(expect,datatype,NFT_TEXT))  then
+                        if (in_internal_range(NFT_TEXT, 
+     +                                        expect)) then
+                            if (err .ne. 0)  then
+                                call errore('nf_get_var1_text: ', err)
+                            else
+                                val = ichar(value)
+                                if (.not.equal(
+     +                              val,
+     +                              expect,var_type(i),
+     +                              NFT_TEXT))  then
+                                    call error(
+     +                          'Var value read not that expected')
+                                    if (verbose)  then
+                                        call error(' ')
+                                        call errori('varid: %d', i)
+                                        call errorc('var_name: ', 
+     +                                          var_name(i))
+                                        call error('index:')
+                                        do 4, d = 1, var_rank(i)
+                                            call errori(' ', index(d))
+4                                       continue
+                                        call errord('expect: ', expect)
+                                        call errord('got: ',  val)
+                                    end if
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+                        end if
+                    end if
+3               continue
+            end if
+1       continue
+        err = nf_close (ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        call print_nok(nok)
+        end
+
+#ifdef NF_INT1_T
+C
+C check all vars in file which are (text/numeric) compatible with TYPE
+C
+        subroutine check_vars_int1(filename)
+        use tests, NDIMSG=>NDIMS, NGATTSG=>NGATTS
+        implicit        none
+        character*(*)   filename
+        integer  ncid          !/* netCDF id */
+        integer index(MAX_RANK)
+        integer  err           !/* status */
+        integer  d
+        integer  i
+        integer  j
+        NF_INT1_T    value
+        integer datatype
+        integer ndims
+        integer dimids(MAX_RANK)
+        integer ngatts
+        doubleprecision expect
+        character*(NF_MAX_NAME) name
+        integer length
+        logical canConvert      !/* Both text or both numeric */
+        integer nok             !/* count of valid comparisons */
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(filename, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT1 .eq. NFT_TEXT)
+            if (canConvert)  then
+                err = nf_inq_var(ncid, i, name, datatype, ndims, dimids,
+     +                           ngatts)
+                if (err .ne. 0)
+     +              call errore('nf_inq_var: ', err)
+                if (name .ne. var_name(i))
+     +              call error('Unexpected var_name')
+                if (datatype .ne. var_type(i))
+     +              call error('Unexpected type')
+                if (ndims .ne. var_rank(i))
+     +              call error('Unexpected rank')
+                do 2, j = 1, ndims
+                    err = nf_inq_dim(ncid, dimids(j), name, length)
+                    if (err .ne. 0)
+     +                  call errore('nf_inq_dim: ', err)
+                    if (length .ne. var_shape(j,i))
+     +                  call error('Unexpected shape')
+2               continue
+                do 3, j = 1, var_nels(i)
+                    err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                                  index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes()')
+                    expect = hash4( var_type(i), var_rank(i), index, 
+     +                             NFT_INT1)
+                    err = nf_get_var1_int1(ncid, i, index, value)
+                    if (inRange3(expect,datatype,NFT_INT1))  then
+                        if (in_internal_range(NFT_INT1, 
+     +                                        expect)) then
+                            if (err .ne. 0)  then
+                                call errore('nf_get_var1_int1: ', err)
+                            else
+                                val = value
+                                if (.not.equal(
+     +                              val,
+     +                              expect,var_type(i),
+     +                              NFT_INT1))  then
+                                    call error(
+     +                          'Var value read not that expected')
+                                    if (verbose)  then
+                                        call error(' ')
+                                        call errori('varid: %d', i)
+                                        call errorc('var_name: ', 
+     +                                          var_name(i))
+                                        call error('index:')
+                                        do 4, d = 1, var_rank(i)
+                                            call errori(' ', index(d))
+4                                       continue
+                                        call errord('expect: ', expect)
+                                        call errord('got: ',  val)
+                                    end if
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+                        end if
+                    end if
+3               continue
+            end if
+1       continue
+        err = nf_close (ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        call print_nok(nok)
+        end
+
+#endif
+#ifdef NF_INT2_T
+C
+C check all vars in file which are (text/numeric) compatible with TYPE
+C
+        subroutine check_vars_int2(filename)
+        use tests, NDIMSG=>NDIMS, NGATTSG=>NGATTS
+        implicit        none
+        character*(*)   filename
+        integer  ncid          !/* netCDF id */
+        integer index(MAX_RANK)
+        integer  err           !/* status */
+        integer  d
+        integer  i
+        integer  j
+        NF_INT2_T    value
+        integer datatype
+        integer ndims
+        integer dimids(MAX_RANK)
+        integer ngatts
+        doubleprecision expect
+        character*(NF_MAX_NAME) name
+        integer length
+        logical canConvert      !/* Both text or both numeric */
+        integer nok             !/* count of valid comparisons */
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(filename, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT2 .eq. NFT_TEXT)
+            if (canConvert)  then
+                err = nf_inq_var(ncid, i, name, datatype, ndims, dimids,
+     +                           ngatts)
+                if (err .ne. 0)
+     +              call errore('nf_inq_var: ', err)
+                if (name .ne. var_name(i))
+     +              call error('Unexpected var_name')
+                if (datatype .ne. var_type(i))
+     +              call error('Unexpected type')
+                if (ndims .ne. var_rank(i))
+     +              call error('Unexpected rank')
+                do 2, j = 1, ndims
+                    err = nf_inq_dim(ncid, dimids(j), name, length)
+                    if (err .ne. 0)
+     +                  call errore('nf_inq_dim: ', err)
+                    if (length .ne. var_shape(j,i))
+     +                  call error('Unexpected shape')
+2               continue
+                do 3, j = 1, var_nels(i)
+                    err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                                  index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes()')
+                    expect = hash4( var_type(i), var_rank(i), index, 
+     +                             NFT_INT2)
+                    err = nf_get_var1_int2(ncid, i, index, value)
+                    if (inRange3(expect,datatype,NFT_INT2))  then
+                        if (in_internal_range(NFT_INT2, 
+     +                                        expect)) then
+                            if (err .ne. 0)  then
+                                call errore('nf_get_var1_int2: ', err)
+                            else
+                                val = value
+                                if (.not.equal(
+     +                              val,
+     +                              expect,var_type(i),
+     +                              NFT_INT2))  then
+                                    call error(
+     +                          'Var value read not that expected')
+                                    if (verbose)  then
+                                        call error(' ')
+                                        call errori('varid: %d', i)
+                                        call errorc('var_name: ', 
+     +                                          var_name(i))
+                                        call error('index:')
+                                        do 4, d = 1, var_rank(i)
+                                            call errori(' ', index(d))
+4                                       continue
+                                        call errord('expect: ', expect)
+                                        call errord('got: ',  val)
+                                    end if
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+                        end if
+                    end if
+3               continue
+            end if
+1       continue
+        err = nf_close (ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        call print_nok(nok)
+        end
+
+#endif
+C
+C check all vars in file which are (text/numeric) compatible with TYPE
+C
+        subroutine check_vars_int(filename)
+        use tests, NDIMSG=>NDIMS, NGATTSG=>NGATTS
+        implicit        none
+        character*(*)   filename
+        integer  ncid          !/* netCDF id */
+        integer index(MAX_RANK)
+        integer  err           !/* status */
+        integer  d
+        integer  i
+        integer  j
+        integer    value
+        integer datatype
+        integer ndims
+        integer dimids(MAX_RANK)
+        integer ngatts
+        doubleprecision expect
+        character*(NF_MAX_NAME) name
+        integer length
+        logical canConvert      !/* Both text or both numeric */
+        integer nok             !/* count of valid comparisons */
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(filename, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT .eq. NFT_TEXT)
+            if (canConvert)  then
+                err = nf_inq_var(ncid, i, name, datatype, ndims, dimids,
+     +                           ngatts)
+                if (err .ne. 0)
+     +              call errore('nf_inq_var: ', err)
+                if (name .ne. var_name(i))
+     +              call error('Unexpected var_name')
+                if (datatype .ne. var_type(i))
+     +              call error('Unexpected type')
+                if (ndims .ne. var_rank(i))
+     +              call error('Unexpected rank')
+                do 2, j = 1, ndims
+                    err = nf_inq_dim(ncid, dimids(j), name, length)
+                    if (err .ne. 0)
+     +                  call errore('nf_inq_dim: ', err)
+                    if (length .ne. var_shape(j,i))
+     +                  call error('Unexpected shape')
+2               continue
+                do 3, j = 1, var_nels(i)
+                    err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                                  index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes()')
+                    expect = hash4( var_type(i), var_rank(i), index, 
+     +                             NFT_INT)
+                    err = nf_get_var1_int(ncid, i, index, value)
+                    if (inRange3(expect,datatype,NFT_INT))  then
+                        if (in_internal_range(NFT_INT, 
+     +                                        expect)) then
+                            if (err .ne. 0)  then
+                                call errore('nf_get_var1_int: ', err)
+                            else
+                                val = value
+                                if (.not.equal(
+     +                              val,
+     +                              expect,var_type(i),
+     +                              NFT_INT))  then
+                                    call error(
+     +                          'Var value read not that expected')
+                                    if (verbose)  then
+                                        call error(' ')
+                                        call errori('varid: %d', i)
+                                        call errorc('var_name: ', 
+     +                                          var_name(i))
+                                        call error('index:')
+                                        do 4, d = 1, var_rank(i)
+                                            call errori(' ', index(d))
+4                                       continue
+                                        call errord('expect: ', expect)
+                                        call errord('got: ',  val)
+                                    end if
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+                        end if
+                    end if
+3               continue
+            end if
+1       continue
+        err = nf_close (ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        call print_nok(nok)
+        end
+
+C
+C check all vars in file which are (text/numeric) compatible with TYPE
+C
+        subroutine check_vars_real(filename)
+        use tests, NDIMSG=>NDIMS, NGATTSG=>NGATTS
+        use tests
+        implicit        none
+        character*(*)   filename
+        integer  ncid          !/* netCDF id */
+        integer index(MAX_RANK)
+        integer  err           !/* status */
+        integer  d
+        integer  i
+        integer  j
+        real    value
+        integer datatype
+        integer ndims
+        integer dimids(MAX_RANK)
+        integer ngatts
+        doubleprecision expect
+        character*(NF_MAX_NAME) name
+        integer length
+        logical canConvert      !/* Both text or both numeric */
+        integer nok             !/* count of valid comparisons */
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(filename, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_REAL .eq. NFT_TEXT)
+            if (canConvert)  then
+                err = nf_inq_var(ncid, i, name, datatype, ndims, dimids,
+     +                           ngatts)
+                if (err .ne. 0)
+     +              call errore('nf_inq_var: ', err)
+                if (name .ne. var_name(i))
+     +              call error('Unexpected var_name')
+                if (datatype .ne. var_type(i))
+     +              call error('Unexpected type')
+                if (ndims .ne. var_rank(i))
+     +              call error('Unexpected rank')
+                do 2, j = 1, ndims
+                    err = nf_inq_dim(ncid, dimids(j), name, length)
+                    if (err .ne. 0)
+     +                  call errore('nf_inq_dim: ', err)
+                    if (length .ne. var_shape(j,i))
+     +                  call error('Unexpected shape')
+2               continue
+                do 3, j = 1, var_nels(i)
+                    err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                                  index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes()')
+                    expect = hash4( var_type(i), var_rank(i), index, 
+     +                             NFT_REAL)
+                    err = nf_get_var1_real(ncid, i, index, value)
+                    if (inRange3(expect,datatype,NFT_REAL))  then
+                        if (in_internal_range(NFT_REAL, 
+     +                                        expect)) then
+                            if (err .ne. 0)  then
+                                call errore('nf_get_var1_real: ', err)
+                            else
+                                val = value
+                                if (.not.equal(
+     +                              val,
+     +                              expect,var_type(i),
+     +                              NFT_REAL))  then
+                                    call error(
+     +                          'Var value read not that expected')
+                                    if (verbose)  then
+                                        call error(' ')
+                                        call errori('varid: %d', i)
+                                        call errorc('var_name: ', 
+     +                                          var_name(i))
+                                        call error('index:')
+                                        do 4, d = 1, var_rank(i)
+                                            call errori(' ', index(d))
+4                                       continue
+                                        call errord('expect: ', expect)
+                                        call errord('got: ',  val)
+                                    end if
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+                        end if
+                    end if
+3               continue
+            end if
+1       continue
+        err = nf_close (ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        call print_nok(nok)
+        end
+
+C
+C check all vars in file which are (text/numeric) compatible with TYPE
+C
+        subroutine check_vars_double(filename)
+        use tests, NDIMSG=>NDIMS, NGATTSG=>NGATTS
+        implicit        none
+        character*(*)   filename
+        integer  ncid          !/* netCDF id */
+        integer index(MAX_RANK)
+        integer  err           !/* status */
+        integer  d
+        integer  i
+        integer  j
+        doubleprecision    value
+        integer datatype
+        integer ndims
+        integer dimids(MAX_RANK)
+        integer ngatts
+        doubleprecision expect
+        character*(NF_MAX_NAME) name
+        integer length
+        logical canConvert      !/* Both text or both numeric */
+        integer nok             !/* count of valid comparisons */
+        doubleprecision val
+
+        nok = 0
+
+        err = nf_open(filename, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_DOUBLE .eq. NFT_TEXT)
+            if (canConvert)  then
+                err = nf_inq_var(ncid, i, name, datatype, ndims, dimids,
+     +                           ngatts)
+                if (err .ne. 0)
+     +              call errore('nf_inq_var: ', err)
+                if (name .ne. var_name(i))
+     +              call error('Unexpected var_name')
+                if (datatype .ne. var_type(i))
+     +              call error('Unexpected type')
+                if (ndims .ne. var_rank(i))
+     +              call error('Unexpected rank')
+                do 2, j = 1, ndims
+                    err = nf_inq_dim(ncid, dimids(j), name, length)
+                    if (err .ne. 0)
+     +                  call errore('nf_inq_dim: ', err)
+                    if (length .ne. var_shape(j,i))
+     +                  call error('Unexpected shape')
+2               continue
+                do 3, j = 1, var_nels(i)
+                    err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                                  index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes()')
+                    expect = hash4( var_type(i), var_rank(i), index, 
+     +                             NFT_DOUBLE)
+                    err = nf_get_var1_double(ncid, i, index, value)
+                    if (inRange3(expect,datatype,NFT_DOUBLE))  then
+                        if (in_internal_range(NFT_DOUBLE, 
+     +                                        expect)) then
+                            if (err .ne. 0)  then
+                                call errore('nf_get_var1_double: ', err)
+                            else
+                                val = value
+                                if (.not.equal(
+     +                              val,
+     +                              expect,var_type(i),
+     +                              NFT_DOUBLE))  then
+                                    call error(
+     +                          'Var value read not that expected')
+                                    if (verbose)  then
+                                        call error(' ')
+                                        call errori('varid: %d', i)
+                                        call errorc('var_name: ', 
+     +                                          var_name(i))
+                                        call error('index:')
+                                        do 4, d = 1, var_rank(i)
+                                            call errori(' ', index(d))
+4                                       continue
+                                        call errord('expect: ', expect)
+                                        call errord('got: ',  val)
+                                    end if
+                                else
+                                    nok = nok + 1
+                                end if
+                            end if
+                        end if
+                    end if
+3               continue
+            end if
+1       continue
+        err = nf_close (ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        call print_nok(nok)
+        end
+
+
+C/* 
+C *  check all attributes in file which are (text/numeric) compatible with TYPE
+C *  ignore any attributes containing values outside range of TYPE
+C */
+        subroutine check_atts_text(ncid)
+        use tests
+        implicit        none
+        integer ncid
+        integer  err           !/* status */
+        integer  i
+        integer  j
+        integer  k
+        integer ndx(1)
+        character    value(MAX_NELS)
+        integer datatype
+        doubleprecision expect(MAX_NELS)
+        integer length
+        integer nInExtRange     !/* number values within external range */
+        integer nInIntRange     !/* number values within internal range */
+        logical canConvert      !/* Both text or both numeric */
+        integer nok             !/* count of valid comparisons */
+        doubleprecision val
+
+        nok = 0
+
+        do 1, i = 0, NVARS
+            do 2, j = 1, NATTS(i)
+                canConvert = (ATT_TYPE(j,i) .eq. NF_CHAR) .eqv.
+     +                       (NFT_TEXT .eq. NFT_TEXT)
+                if (canConvert) then
+                    err = nf_inq_att(ncid, i, ATT_NAME(j,i), datatype, 
+     +                               length)
+                    if (err .ne. 0)
+     +                  call errore('nf_inq_att: ', err)
+                    if (datatype .ne. ATT_TYPE(j,i))
+     +                  call error('nf_inq_att: unexpected type')
+                    if (length .ne. ATT_LEN(j,i))
+     +                  call error('nf_inq_att: unexpected length')
+                    if (.not.(length .le. MAX_NELS))
+     +                  stop 2
+                    nInIntRange = 0
+                    nInExtRange = 0
+                    do 4, k = 1, length
+                        ndx(1) = k
+                        expect(k) = hash4( datatype, -1, ndx, 
+     +                                    NFT_TEXT)
+                        if (inRange3(expect(k), datatype, 
+     +                               NFT_TEXT)) then
+                            nInExtRange = nInExtRange + 1
+                            if (in_internal_range(NFT_TEXT,
+     +                                            expect(k)))
+     +                          nInIntRange = nInIntRange + 1
+                        end if
+4                   continue
+                    err = nf_get_att_text(ncid, i, 
+     +                                  ATT_NAME(j,i), value)
+                    if (nInExtRange .eq. length .and. 
+     +                  nInIntRange .eq. length) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ', err)
+                    end if
+                    do 3, k = 1, length
+                        if (inRange3(expect(k),datatype,NFT_TEXT)
+     +                          .and. 
+     +                          in_internal_range(NFT_TEXT, 
+     +                                            expect(k))) then
+                            val = ichar(value(k))
+                            if (.not.equal(
+     +                          val,
+     +                          expect(k),datatype,
+     +                          NFT_TEXT)) then
+                                call error(
+     +                              'att. value read not that expected')
+                                if (verbose) then
+                                    call error(' ')
+                                    call errori('varid: ', i)
+                                    call errorc('att_name: ', 
+     +                                  ATT_NAME(j,i))
+                                    call errori('element number: ', k)
+                                    call errord('expect: ', expect(k))
+                                    call errord('got: ',  val)
+                                end if
+                            else
+                                nok = nok + 1
+                            end if
+                        end if
+3                   continue
+                end if                                               
+2           continue
+1       continue
+
+        call print_nok(nok)
+        end
+
+#ifdef NF_INT1_T
+C/* 
+C *  check all attributes in file which are (text/numeric) compatible with TYPE
+C *  ignore any attributes containing values outside range of TYPE
+C */
+        subroutine check_atts_int1(ncid)
+        use tests
+        implicit        none
+        integer ncid
+        integer  err           !/* status */
+        integer  i
+        integer  j
+        integer  k
+        integer ndx(1)
+        NF_INT1_T    value(MAX_NELS)
+        integer datatype
+        doubleprecision expect(MAX_NELS)
+        integer length
+        integer nInExtRange     !/* number values within external range */
+        integer nInIntRange     !/* number values within internal range */
+        logical canConvert      !/* Both text or both numeric */
+        integer nok             !/* count of valid comparisons */
+        doubleprecision val
+
+        nok = 0
+
+        do 1, i = 0, NVARS
+            do 2, j = 1, NATTS(i)
+                canConvert = (ATT_TYPE(j,i) .eq. NF_CHAR) .eqv.
+     +                       (NFT_INT1 .eq. NFT_TEXT)
+                if (canConvert) then
+                    err = nf_inq_att(ncid, i, ATT_NAME(j,i), datatype, 
+     +                               length)
+                    if (err .ne. 0)
+     +                  call errore('nf_inq_att: ', err)
+                    if (datatype .ne. ATT_TYPE(j,i))
+     +                  call error('nf_inq_att: unexpected type')
+                    if (length .ne. ATT_LEN(j,i))
+     +                  call error('nf_inq_att: unexpected length')
+                    if (.not.(length .le. MAX_NELS))
+     +                  stop 2
+                    nInIntRange = 0
+                    nInExtRange = 0
+                    do 4, k = 1, length
+                        ndx(1) = k
+                        expect(k) = hash4( datatype, -1, ndx, 
+     +                                    NFT_INT1)
+                        if (inRange3(expect(k), datatype, 
+     +                               NFT_INT1)) then
+                            nInExtRange = nInExtRange + 1
+                            if (in_internal_range(NFT_INT1,
+     +                                            expect(k)))
+     +                          nInIntRange = nInIntRange + 1
+                        end if
+4                   continue
+                    err = nf_get_att_int1(ncid, i, 
+     +                                  ATT_NAME(j,i), value)
+                    if (nInExtRange .eq. length .and. 
+     +                  nInIntRange .eq. length) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ', err)
+                    end if
+                    do 3, k = 1, length
+                        if (inRange3(expect(k),datatype,NFT_INT1)
+     +                          .and. 
+     +                          in_internal_range(NFT_INT1, 
+     +                                            expect(k))) then
+                            val = value(k)
+                            if (.not.equal(
+     +                          val,
+     +                          expect(k),datatype,
+     +                          NFT_INT1)) then
+                                call error(
+     +                              'att. value read not that expected')
+                                if (verbose) then
+                                    call error(' ')
+                                    call errori('varid: ', i)
+                                    call errorc('att_name: ', 
+     +                                  ATT_NAME(j,i))
+                                    call errori('element number: ', k)
+                                    call errord('expect: ', expect(k))
+                                    call errord('got: ',  val)
+                                end if
+                            else
+                                nok = nok + 1
+                            end if
+                        end if
+3                   continue
+                end if                                               
+2           continue
+1       continue
+
+        call print_nok(nok)
+        end
+
+#endif
+#ifdef NF_INT2_T
+C/* 
+C *  check all attributes in file which are (text/numeric) compatible with TYPE
+C *  ignore any attributes containing values outside range of TYPE
+C */
+        subroutine check_atts_int2(ncid)
+        use tests
+        implicit        none
+        integer ncid
+        integer  err           !/* status */
+        integer  i
+        integer  j
+        integer  k
+        integer ndx(1)
+        NF_INT2_T    value(MAX_NELS)
+        integer datatype
+        doubleprecision expect(MAX_NELS)
+        integer length
+        integer nInExtRange     !/* number values within external range */
+        integer nInIntRange     !/* number values within internal range */
+        logical canConvert      !/* Both text or both numeric */
+        integer nok             !/* count of valid comparisons */
+        doubleprecision val
+
+        nok = 0
+
+        do 1, i = 0, NVARS
+            do 2, j = 1, NATTS(i)
+                canConvert = (ATT_TYPE(j,i) .eq. NF_CHAR) .eqv.
+     +                       (NFT_INT2 .eq. NFT_TEXT)
+                if (canConvert) then
+                    err = nf_inq_att(ncid, i, ATT_NAME(j,i), datatype, 
+     +                               length)
+                    if (err .ne. 0)
+     +                  call errore('nf_inq_att: ', err)
+                    if (datatype .ne. ATT_TYPE(j,i))
+     +                  call error('nf_inq_att: unexpected type')
+                    if (length .ne. ATT_LEN(j,i))
+     +                  call error('nf_inq_att: unexpected length')
+                    if (.not.(length .le. MAX_NELS))
+     +                  stop 2
+                    nInIntRange = 0
+                    nInExtRange = 0
+                    do 4, k = 1, length
+                        ndx(1) = k
+                        expect(k) = hash4( datatype, -1, ndx, 
+     +                                    NFT_INT2)
+                        if (inRange3(expect(k), datatype, 
+     +                               NFT_INT2)) then
+                            nInExtRange = nInExtRange + 1
+                            if (in_internal_range(NFT_INT2,
+     +                                            expect(k)))
+     +                          nInIntRange = nInIntRange + 1
+                        end if
+4                   continue
+                    err = nf_get_att_int2(ncid, i, 
+     +                                  ATT_NAME(j,i), value)
+                    if (nInExtRange .eq. length .and. 
+     +                  nInIntRange .eq. length) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ', err)
+                    end if
+                    do 3, k = 1, length
+                        if (inRange3(expect(k),datatype,NFT_INT2)
+     +                          .and. 
+     +                          in_internal_range(NFT_INT2, 
+     +                                            expect(k))) then
+                            val = value(k)
+                            if (.not.equal(
+     +                          val,
+     +                          expect(k),datatype,
+     +                          NFT_INT2)) then
+                                call error(
+     +                              'att. value read not that expected')
+                                if (verbose) then
+                                    call error(' ')
+                                    call errori('varid: ', i)
+                                    call errorc('att_name: ', 
+     +                                  ATT_NAME(j,i))
+                                    call errori('element number: ', k)
+                                    call errord('expect: ', expect(k))
+                                    call errord('got: ',  val)
+                                end if
+                            else
+                                nok = nok + 1
+                            end if
+                        end if
+3                   continue
+                end if                                               
+2           continue
+1       continue
+
+        call print_nok(nok)
+        end
+
+#endif
+C/* 
+C *  check all attributes in file which are (text/numeric) compatible with TYPE
+C *  ignore any attributes containing values outside range of TYPE
+C */
+        subroutine check_atts_int(ncid)
+        use tests
+        implicit        none
+        integer ncid
+        integer  err           !/* status */
+        integer  i
+        integer  j
+        integer  k
+        integer ndx(1)
+        integer    value(MAX_NELS)
+        integer datatype
+        doubleprecision expect(MAX_NELS)
+        integer length
+        integer nInExtRange     !/* number values within external range */
+        integer nInIntRange     !/* number values within internal range */
+        logical canConvert      !/* Both text or both numeric */
+        integer nok             !/* count of valid comparisons */
+        doubleprecision val
+
+        nok = 0
+
+        do 1, i = 0, NVARS
+            do 2, j = 1, NATTS(i)
+                canConvert = (ATT_TYPE(j,i) .eq. NF_CHAR) .eqv.
+     +                       (NFT_INT .eq. NFT_TEXT)
+                if (canConvert) then
+                    err = nf_inq_att(ncid, i, ATT_NAME(j,i), datatype, 
+     +                               length)
+                    if (err .ne. 0)
+     +                  call errore('nf_inq_att: ', err)
+                    if (datatype .ne. ATT_TYPE(j,i))
+     +                  call error('nf_inq_att: unexpected type')
+                    if (length .ne. ATT_LEN(j,i))
+     +                  call error('nf_inq_att: unexpected length')
+                    if (.not.(length .le. MAX_NELS))
+     +                  stop 2
+                    nInIntRange = 0
+                    nInExtRange = 0
+                    do 4, k = 1, length
+                        ndx(1) = k
+                        expect(k) = hash4( datatype, -1, ndx, 
+     +                                    NFT_INT)
+                        if (inRange3(expect(k), datatype, 
+     +                               NFT_INT)) then
+                            nInExtRange = nInExtRange + 1
+                            if (in_internal_range(NFT_INT,
+     +                                            expect(k)))
+     +                          nInIntRange = nInIntRange + 1
+                        end if
+4                   continue
+                    err = nf_get_att_int(ncid, i, 
+     +                                  ATT_NAME(j,i), value)
+                    if (nInExtRange .eq. length .and. 
+     +                  nInIntRange .eq. length) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ', err)
+                    end if
+                    do 3, k = 1, length
+                        if (inRange3(expect(k),datatype,NFT_INT)
+     +                          .and. 
+     +                          in_internal_range(NFT_INT, 
+     +                                            expect(k))) then
+                            val = value(k)
+                            if (.not.equal(
+     +                          val,
+     +                          expect(k),datatype,
+     +                          NFT_INT)) then
+                                call error(
+     +                              'att. value read not that expected')
+                                if (verbose) then
+                                    call error(' ')
+                                    call errori('varid: ', i)
+                                    call errorc('att_name: ', 
+     +                                  ATT_NAME(j,i))
+                                    call errori('element number: ', k)
+                                    call errord('expect: ', expect(k))
+                                    call errord('got: ',  val)
+                                end if
+                            else
+                                nok = nok + 1
+                            end if
+                        end if
+3                   continue
+                end if                                               
+2           continue
+1       continue
+
+        call print_nok(nok)
+        end
+
+C/* 
+C *  check all attributes in file which are (text/numeric) compatible with TYPE
+C *  ignore any attributes containing values outside range of TYPE
+C */
+        subroutine check_atts_real(ncid)
+        use tests
+        implicit        none
+        integer ncid
+        integer  err           !/* status */
+        integer  i
+        integer  j
+        integer  k
+        integer ndx(1)
+        real    value(MAX_NELS)
+        integer datatype
+        doubleprecision expect(MAX_NELS)
+        integer length
+        integer nInExtRange     !/* number values within external range */
+        integer nInIntRange     !/* number values within internal range */
+        logical canConvert      !/* Both text or both numeric */
+        integer nok             !/* count of valid comparisons */
+        doubleprecision val
+
+        nok = 0
+
+        do 1, i = 0, NVARS
+            do 2, j = 1, NATTS(i)
+                canConvert = (ATT_TYPE(j,i) .eq. NF_CHAR) .eqv.
+     +                       (NFT_REAL .eq. NFT_TEXT)
+                if (canConvert) then
+                    err = nf_inq_att(ncid, i, ATT_NAME(j,i), datatype, 
+     +                               length)
+                    if (err .ne. 0)
+     +                  call errore('nf_inq_att: ', err)
+                    if (datatype .ne. ATT_TYPE(j,i))
+     +                  call error('nf_inq_att: unexpected type')
+                    if (length .ne. ATT_LEN(j,i))
+     +                  call error('nf_inq_att: unexpected length')
+                    if (.not.(length .le. MAX_NELS))
+     +                  stop 2
+                    nInIntRange = 0
+                    nInExtRange = 0
+                    do 4, k = 1, length
+                        ndx(1) = k
+                        expect(k) = hash4( datatype, -1, ndx, 
+     +                                    NFT_REAL)
+                        if (inRange3(expect(k), datatype, 
+     +                               NFT_REAL)) then
+                            nInExtRange = nInExtRange + 1
+                            if (in_internal_range(NFT_REAL,
+     +                                            expect(k)))
+     +                          nInIntRange = nInIntRange + 1
+                        end if
+4                   continue
+                    err = nf_get_att_real(ncid, i, 
+     +                                  ATT_NAME(j,i), value)
+                    if (nInExtRange .eq. length .and. 
+     +                  nInIntRange .eq. length) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ', err)
+                    end if
+                    do 3, k = 1, length
+                        if (inRange3(expect(k),datatype,NFT_REAL)
+     +                          .and. 
+     +                          in_internal_range(NFT_REAL, 
+     +                                            expect(k))) then
+                            val = value(k)
+                            if (.not.equal(
+     +                          val,
+     +                          expect(k),datatype,
+     +                          NFT_REAL)) then
+                                call error(
+     +                              'att. value read not that expected')
+                                if (verbose) then
+                                    call error(' ')
+                                    call errori('varid: ', i)
+                                    call errorc('att_name: ', 
+     +                                  ATT_NAME(j,i))
+                                    call errori('element number: ', k)
+                                    call errord('expect: ', expect(k))
+                                    call errord('got: ',  val)
+                                end if
+                            else
+                                nok = nok + 1
+                            end if
+                        end if
+3                   continue
+                end if                                               
+2           continue
+1       continue
+
+        call print_nok(nok)
+        end
+
+C/* 
+C *  check all attributes in file which are (text/numeric) compatible with TYPE
+C *  ignore any attributes containing values outside range of TYPE
+C */
+        subroutine check_atts_double(ncid)
+        use tests
+        implicit        none
+        integer ncid
+        integer  err           !/* status */
+        integer  i
+        integer  j
+        integer  k
+        integer ndx(1)
+        doubleprecision    value(MAX_NELS)
+        integer datatype
+        doubleprecision expect(MAX_NELS)
+        integer length
+        integer nInExtRange     !/* number values within external range */
+        integer nInIntRange     !/* number values within internal range */
+        logical canConvert      !/* Both text or both numeric */
+        integer nok             !/* count of valid comparisons */
+        doubleprecision val
+
+        nok = 0
+
+        do 1, i = 0, NVARS
+            do 2, j = 1, NATTS(i)
+                canConvert = (ATT_TYPE(j,i) .eq. NF_CHAR) .eqv.
+     +                       (NFT_DOUBLE .eq. NFT_TEXT)
+                if (canConvert) then
+                    err = nf_inq_att(ncid, i, ATT_NAME(j,i), datatype, 
+     +                               length)
+                    if (err .ne. 0)
+     +                  call errore('nf_inq_att: ', err)
+                    if (datatype .ne. ATT_TYPE(j,i))
+     +                  call error('nf_inq_att: unexpected type')
+                    if (length .ne. ATT_LEN(j,i))
+     +                  call error('nf_inq_att: unexpected length')
+                    if (.not.(length .le. MAX_NELS))
+     +                  stop 2
+                    nInIntRange = 0
+                    nInExtRange = 0
+                    do 4, k = 1, length
+                        ndx(1) = k
+                        expect(k) = hash4( datatype, -1, ndx, 
+     +                                    NFT_DOUBLE)
+                        if (inRange3(expect(k), datatype, 
+     +                               NFT_DOUBLE)) then
+                            nInExtRange = nInExtRange + 1
+                            if (in_internal_range(NFT_DOUBLE,
+     +                                            expect(k)))
+     +                          nInIntRange = nInIntRange + 1
+                        end if
+4                   continue
+                    err = nf_get_att_double(ncid, i, 
+     +                                  ATT_NAME(j,i), value)
+                    if (nInExtRange .eq. length .and. 
+     +                  nInIntRange .eq. length) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. 0 .and. err .ne. NF_ERANGE)
+     +                      call errore('OK or Range error: ', err)
+                    end if
+                    do 3, k = 1, length
+                        if (inRange3(expect(k),datatype,NFT_DOUBLE)
+     +                          .and. 
+     +                          in_internal_range(NFT_DOUBLE, 
+     +                                            expect(k))) then
+                            val = value(k)
+                            if (.not.equal(
+     +                          val,
+     +                          expect(k),datatype,
+     +                          NFT_DOUBLE)) then
+                                call error(
+     +                              'att. value read not that expected')
+                                if (verbose) then
+                                    call error(' ')
+                                    call errori('varid: ', i)
+                                    call errorc('att_name: ', 
+     +                                  ATT_NAME(j,i))
+                                    call errori('element number: ', k)
+                                    call errord('expect: ', expect(k))
+                                    call errord('got: ',  val)
+                                end if
+                            else
+                                nok = nok + 1
+                            end if
+                        end if
+3                   continue
+                end if                                               
+2           continue
+1       continue
+
+        call print_nok(nok)
+        end
+
+
+        subroutine test_nf_put_var1_text()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        integer index(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        character    value
+        doubleprecision val
+
+        value = char(int(5))!/* any value would do - only for error cases */
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_TEXT .eq. NFT_TEXT)
+            do 2, j = 1, var_rank(i)
+                index(j) = 1
+2           continue
+            err = nf_put_var1_text(BAD_ID, i, index, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_var1_text(ncid, BAD_VARID,
+     +                           index, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .gt. 1) then         !/* skip record dim */
+                    index(j) = var_shape(j,i) + 1
+                    err = nf_put_var1_text(ncid, i,
+     +                                   index, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                        else
+                            if (err .ne. NF_EINVALCOORDS)
+     +                          call errore('bad index: ', err)
+                        endif
+                    index(j) = 0
+                end if
+3           continue
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0) 
+     +              call error('error in index2indexes 1')
+                value = char(int(hash_text(var_type(i),var_rank(i),
+     +                            index, NFT_TEXT)))
+                err = nf_put_var1_text(ncid, i, index, value)
+                if (canConvert) then
+                    val = ichar(value)
+                    if (inRange3(val, var_type(i), NFT_TEXT)) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('Range error: ', err)
+                    end if
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+4           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_text(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed: ', 
+     +                  scratch)
+        end
+
+#ifdef NF_INT1_T
+        subroutine test_nf_put_var1_int1()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        integer index(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        NF_INT1_T    value
+        doubleprecision val
+
+        value = 5!/* any value would do - only for error cases */
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT1 .eq. NFT_TEXT)
+            do 2, j = 1, var_rank(i)
+                index(j) = 1
+2           continue
+            err = nf_put_var1_int1(BAD_ID, i, index, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_var1_int1(ncid, BAD_VARID,
+     +                           index, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .gt. 1) then         !/* skip record dim */
+                    index(j) = var_shape(j,i) + 1
+                    err = nf_put_var1_int1(ncid, i,
+     +                                   index, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                        else
+                            if (err .ne. NF_EINVALCOORDS)
+     +                          call errore('bad index: ', err)
+                        endif
+                    index(j) = 0
+                end if
+3           continue
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0) 
+     +              call error('error in index2indexes 1')
+                value = hash_int1(var_type(i),var_rank(i),
+     +                            index, NFT_INT1)
+                err = nf_put_var1_int1(ncid, i, index, value)
+                if (canConvert) then
+                    val = value
+                    if (inRange3(val, var_type(i), NFT_INT1)) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('Range error: ', err)
+                    end if
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+4           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_int1(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed: ', 
+     +                  scratch)
+        end
+
+#endif
+#ifdef NF_INT2_T
+        subroutine test_nf_put_var1_int2()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        integer index(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        NF_INT2_T    value
+        doubleprecision val
+
+        value = 5!/* any value would do - only for error cases */
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT2 .eq. NFT_TEXT)
+            do 2, j = 1, var_rank(i)
+                index(j) = 1
+2           continue
+            err = nf_put_var1_int2(BAD_ID, i, index, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_var1_int2(ncid, BAD_VARID,
+     +                           index, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .gt. 1) then         !/* skip record dim */
+                    index(j) = var_shape(j,i) + 1
+                    err = nf_put_var1_int2(ncid, i,
+     +                                   index, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                        else
+                            if (err .ne. NF_EINVALCOORDS)
+     +                          call errore('bad index: ', err)
+                        endif
+                    index(j) = 0
+                end if
+3           continue
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0) 
+     +              call error('error in index2indexes 1')
+                value = hash_int2(var_type(i),var_rank(i),
+     +                            index, NFT_INT2)
+                err = nf_put_var1_int2(ncid, i, index, value)
+                if (canConvert) then
+                    val = value
+                    if (inRange3(val, var_type(i), NFT_INT2)) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('Range error: ', err)
+                    end if
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+4           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_int2(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed: ', 
+     +                  scratch)
+        end
+
+#endif
+        subroutine test_nf_put_var1_int()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        integer index(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        integer    value
+        doubleprecision val
+
+        value = 5!/* any value would do - only for error cases */
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT .eq. NFT_TEXT)
+            do 2, j = 1, var_rank(i)
+                index(j) = 1
+2           continue
+            err = nf_put_var1_int(BAD_ID, i, index, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_var1_int(ncid, BAD_VARID,
+     +                           index, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .gt. 1) then         !/* skip record dim */
+                    index(j) = var_shape(j,i) + 1
+                    err = nf_put_var1_int(ncid, i,
+     +                                   index, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                        else
+                            if (err .ne. NF_EINVALCOORDS)
+     +                          call errore('bad index: ', err)
+                        endif
+                    index(j) = 0
+                end if
+3           continue
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0) 
+     +              call error('error in index2indexes 1')
+                value = hash_int(var_type(i),var_rank(i),
+     +                            index, NFT_INT)
+                err = nf_put_var1_int(ncid, i, index, value)
+                if (canConvert) then
+                    val = value
+                    if (inRange3(val, var_type(i), NFT_INT)) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('Range error: ', err)
+                    end if
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+4           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_int(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed: ', 
+     +                  scratch)
+        end
+
+        subroutine test_nf_put_var1_real()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        integer index(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        real    value
+        doubleprecision val
+
+        value = 5!/* any value would do - only for error cases */
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_REAL .eq. NFT_TEXT)
+            do 2, j = 1, var_rank(i)
+                index(j) = 1
+2           continue
+            err = nf_put_var1_real(BAD_ID, i, index, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_var1_real(ncid, BAD_VARID,
+     +                           index, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .gt. 1) then         !/* skip record dim */
+                    index(j) = var_shape(j,i) + 1
+                    err = nf_put_var1_real(ncid, i,
+     +                                   index, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                        else
+                            if (err .ne. NF_EINVALCOORDS)
+     +                          call errore('bad index: ', err)
+                        endif
+                    index(j) = 0
+                end if
+3           continue
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0) 
+     +              call error('error in index2indexes 1')
+                value = hash_real(var_type(i),var_rank(i),
+     +                            index, NFT_REAL)
+                err = nf_put_var1_real(ncid, i, index, value)
+                if (canConvert) then
+                    val = value
+                    if (inRange3(val, var_type(i), NFT_REAL)) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('Range error: ', err)
+                    end if
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+4           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_real(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed: ', 
+     +                  scratch)
+        end
+
+        subroutine test_nf_put_var1_double()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        integer index(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        doubleprecision    value
+        doubleprecision val
+
+        value = 5!/* any value would do - only for error cases */
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_DOUBLE .eq. NFT_TEXT)
+            do 2, j = 1, var_rank(i)
+                index(j) = 1
+2           continue
+            err = nf_put_var1_double(BAD_ID, i, index, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_var1_double(ncid, BAD_VARID,
+     +                           index, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .gt. 1) then         !/* skip record dim */
+                    index(j) = var_shape(j,i) + 1
+                    err = nf_put_var1_double(ncid, i,
+     +                                   index, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                        else
+                            if (err .ne. NF_EINVALCOORDS)
+     +                          call errore('bad index: ', err)
+                        endif
+                    index(j) = 0
+                end if
+3           continue
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0) 
+     +              call error('error in index2indexes 1')
+                value = hash_double(var_type(i),var_rank(i),
+     +                            index, NFT_DOUBLE)
+                err = nf_put_var1_double(ncid, i, index, value)
+                if (canConvert) then
+                    val = value
+                    if (inRange3(val, var_type(i), NFT_DOUBLE)) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('Range error: ', err)
+                    end if
+                else
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+4           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_double(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed: ', 
+     +                  scratch)
+        end
+
+
+        subroutine test_nf_put_var_text()
+        use tests
+        implicit        none
+        integer ncid
+        integer vid
+        integer i
+        integer j
+        integer err
+        integer nels
+        integer index(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* All values within external range?*/
+        character    value(MAX_NELS)
+        doubleprecision val
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_TEXT .eq. NFT_TEXT)
+            err = nf_put_var_text(BAD_ID, i, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_var_text(ncid, BAD_VARID, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            nels = 1
+            do 3, j = 1, var_rank(i)
+                nels = nels * var_shape(j,i)
+3           continue
+            allInExtRange = .true.
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0) 
+     +              call error('error in index2indexes 1')
+                value(j) = char(int(hash_text(var_type(i), 
+     +              var_rank(i),
+     +              index, NFT_TEXT)))
+                val = ichar(value(j))
+                allInExtRange = allInExtRange .and.
+     +              inRange3(val, var_type(i), NFT_TEXT)
+4           continue
+            err = nf_put_var_text(ncid, i, value)
+            if (canConvert) then
+                if (allInExtRange) then
+                    if (err .ne. 0)
+     +                  call error(nf_strerror(err))
+                else
+                    if (err .ne. NF_ERANGE .and.
+     +                      var_dimid(var_rank(i),i) .ne. RECDIM)
+     +                  call errore('Range error: ', err)
+                endif
+            else
+                if (err .ne. NF_ECHAR)
+     +              call errore('wrong type: ', err)
+            endif
+1       continue
+
+C       The preceeding has written nothing for record variables, now try
+C       again with more than 0 records.
+
+C       Write record number NRECS to force writing of preceding records.
+C       Assumes variable cr is char vector with UNLIMITED dimension.
+
+        err = nf_inq_varid(ncid, "cr", vid)
+        if (err .ne. 0)
+     +      call errore('nf_inq_varid: ', err)
+        index(1) = NRECS
+        err = nf_put_var1_text(ncid, vid, index, 'x')
+        if (err .ne. 0)
+     +      call errore('nf_put_var1_text: ', err)
+
+        do 5 i = 1, NVARS
+C           Only test record variables here
+            if (var_rank(i) .ge. 1 .and.
+     +          var_dimid(var_rank(i),i) .eq. RECDIM) then
+                canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_TEXT .eq. NFT_TEXT)
+                if (var_rank(i) .gt. MAX_RANK)
+     +              stop 2
+                if (var_nels(i) .gt. MAX_NELS)
+     +              stop 2
+                err = nf_put_var_text(BAD_ID, i, value)
+
+                nels = 1
+                do 6 j = 1, var_rank(i)
+                    nels = nels * var_shape(j,i)
+6               continue
+                allInExtRange = .true.
+                do 7, j = 1, nels
+                    err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                    if (err .ne. 0) 
+     +                  call error('error in index2indexes()')
+                    value(j) = char(int(hash_text(var_type(i), 
+     +                  var_rank(i),
+     +                  index, NFT_TEXT)))
+                    val = ichar(value(j))
+                    allInExtRange = allInExtRange .and.
+     +                  inRange3(val, var_type(i), NFT_TEXT)
+7               continue
+                err = nf_put_var_text(ncid, i, value)
+                if (canConvert) then
+                    if (allInExtRange) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('range error: ', err)
+                    endif
+                else
+                    if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                endif
+            endif
+5       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_text(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed: ', 
+     +                  scratch)
+        end
+
+#ifdef NF_INT1_T
+        subroutine test_nf_put_var_int1()
+        use tests
+        implicit        none
+        integer ncid
+        integer vid
+        integer i
+        integer j
+        integer err
+        integer nels
+        integer index(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* All values within external range?*/
+        NF_INT1_T    value(MAX_NELS)
+        doubleprecision val
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT1 .eq. NFT_TEXT)
+            err = nf_put_var_int1(BAD_ID, i, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_var_int1(ncid, BAD_VARID, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            nels = 1
+            do 3, j = 1, var_rank(i)
+                nels = nels * var_shape(j,i)
+3           continue
+            allInExtRange = .true.
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0) 
+     +              call error('error in index2indexes 1')
+                value(j) = hash_int1(var_type(i), 
+     +              var_rank(i),
+     +              index, NFT_INT1)
+                val = value(j)
+                allInExtRange = allInExtRange .and.
+     +              inRange3(val, var_type(i), NFT_INT1)
+4           continue
+            err = nf_put_var_int1(ncid, i, value)
+            if (canConvert) then
+                if (allInExtRange) then
+                    if (err .ne. 0)
+     +                  call error(nf_strerror(err))
+                else
+                    if (err .ne. NF_ERANGE .and.
+     +                      var_dimid(var_rank(i),i) .ne. RECDIM)
+     +                  call errore('Range error: ', err)
+                endif
+            else
+                if (err .ne. NF_ECHAR)
+     +              call errore('wrong type: ', err)
+            endif
+1       continue
+
+C       The preceeding has written nothing for record variables, now try
+C       again with more than 0 records.
+
+C       Write record number NRECS to force writing of preceding records.
+C       Assumes variable cr is char vector with UNLIMITED dimension.
+
+        err = nf_inq_varid(ncid, "cr", vid)
+        if (err .ne. 0)
+     +      call errore('nf_inq_varid: ', err)
+        index(1) = NRECS
+        err = nf_put_var1_text(ncid, vid, index, 'x')
+        if (err .ne. 0)
+     +      call errore('nf_put_var1_text: ', err)
+
+        do 5 i = 1, NVARS
+C           Only test record variables here
+            if (var_rank(i) .ge. 1 .and.
+     +          var_dimid(var_rank(i),i) .eq. RECDIM) then
+                canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT1 .eq. NFT_TEXT)
+                if (var_rank(i) .gt. MAX_RANK)
+     +              stop 2
+                if (var_nels(i) .gt. MAX_NELS)
+     +              stop 2
+                err = nf_put_var_int1(BAD_ID, i, value)
+
+                nels = 1
+                do 6 j = 1, var_rank(i)
+                    nels = nels * var_shape(j,i)
+6               continue
+                allInExtRange = .true.
+                do 7, j = 1, nels
+                    err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                    if (err .ne. 0) 
+     +                  call error('error in index2indexes()')
+                    value(j) = hash_int1(var_type(i), 
+     +                  var_rank(i),
+     +                  index, NFT_INT1)
+                    val = value(j)
+                    allInExtRange = allInExtRange .and.
+     +                  inRange3(val, var_type(i), NFT_INT1)
+7               continue
+                err = nf_put_var_int1(ncid, i, value)
+                if (canConvert) then
+                    if (allInExtRange) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('range error: ', err)
+                    endif
+                else
+                    if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                endif
+            endif
+5       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_int1(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed: ', 
+     +                  scratch)
+        end
+
+#endif
+#ifdef NF_INT2_T
+        subroutine test_nf_put_var_int2()
+        use tests
+        implicit        none
+        integer ncid
+        integer vid
+        integer i
+        integer j
+        integer err
+        integer nels
+        integer index(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* All values within external range?*/
+        NF_INT2_T    value(MAX_NELS)
+        doubleprecision val
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT2 .eq. NFT_TEXT)
+            err = nf_put_var_int2(BAD_ID, i, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_var_int2(ncid, BAD_VARID, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            nels = 1
+            do 3, j = 1, var_rank(i)
+                nels = nels * var_shape(j,i)
+3           continue
+            allInExtRange = .true.
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0) 
+     +              call error('error in index2indexes 1')
+                value(j) = hash_int2(var_type(i), 
+     +              var_rank(i),
+     +              index, NFT_INT2)
+                val = value(j)
+                allInExtRange = allInExtRange .and.
+     +              inRange3(val, var_type(i), NFT_INT2)
+4           continue
+            err = nf_put_var_int2(ncid, i, value)
+            if (canConvert) then
+                if (allInExtRange) then
+                    if (err .ne. 0)
+     +                  call error(nf_strerror(err))
+                else
+                    if (err .ne. NF_ERANGE .and.
+     +                      var_dimid(var_rank(i),i) .ne. RECDIM)
+     +                  call errore('Range error: ', err)
+                endif
+            else
+                if (err .ne. NF_ECHAR)
+     +              call errore('wrong type: ', err)
+            endif
+1       continue
+
+C       The preceeding has written nothing for record variables, now try
+C       again with more than 0 records.
+
+C       Write record number NRECS to force writing of preceding records.
+C       Assumes variable cr is char vector with UNLIMITED dimension.
+
+        err = nf_inq_varid(ncid, "cr", vid)
+        if (err .ne. 0)
+     +      call errore('nf_inq_varid: ', err)
+        index(1) = NRECS
+        err = nf_put_var1_text(ncid, vid, index, 'x')
+        if (err .ne. 0)
+     +      call errore('nf_put_var1_text: ', err)
+
+        do 5 i = 1, NVARS
+C           Only test record variables here
+            if (var_rank(i) .ge. 1 .and.
+     +          var_dimid(var_rank(i),i) .eq. RECDIM) then
+                canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT2 .eq. NFT_TEXT)
+                if (var_rank(i) .gt. MAX_RANK)
+     +              stop 2
+                if (var_nels(i) .gt. MAX_NELS)
+     +              stop 2
+                err = nf_put_var_int2(BAD_ID, i, value)
+
+                nels = 1
+                do 6 j = 1, var_rank(i)
+                    nels = nels * var_shape(j,i)
+6               continue
+                allInExtRange = .true.
+                do 7, j = 1, nels
+                    err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                    if (err .ne. 0) 
+     +                  call error('error in index2indexes()')
+                    value(j) = hash_int2(var_type(i), 
+     +                  var_rank(i),
+     +                  index, NFT_INT2)
+                    val = value(j)
+                    allInExtRange = allInExtRange .and.
+     +                  inRange3(val, var_type(i), NFT_INT2)
+7               continue
+                err = nf_put_var_int2(ncid, i, value)
+                if (canConvert) then
+                    if (allInExtRange) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('range error: ', err)
+                    endif
+                else
+                    if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                endif
+            endif
+5       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_int2(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed: ', 
+     +                  scratch)
+        end
+
+#endif
+        subroutine test_nf_put_var_int()
+        use tests
+        implicit        none
+        integer ncid
+        integer vid
+        integer i
+        integer j
+        integer err
+        integer nels
+        integer index(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* All values within external range?*/
+        integer    value(MAX_NELS)
+        doubleprecision val
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT .eq. NFT_TEXT)
+            err = nf_put_var_int(BAD_ID, i, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_var_int(ncid, BAD_VARID, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            nels = 1
+            do 3, j = 1, var_rank(i)
+                nels = nels * var_shape(j,i)
+3           continue
+            allInExtRange = .true.
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0) 
+     +              call error('error in index2indexes 1')
+                value(j) = hash_int(var_type(i), 
+     +              var_rank(i),
+     +              index, NFT_INT)
+                val = value(j)
+                allInExtRange = allInExtRange .and.
+     +              inRange3(val, var_type(i), NFT_INT)
+4           continue
+            err = nf_put_var_int(ncid, i, value)
+            if (canConvert) then
+                if (allInExtRange) then
+                    if (err .ne. 0)
+     +                  call error(nf_strerror(err))
+                else
+                    if (err .ne. NF_ERANGE .and.
+     +                      var_dimid(var_rank(i),i) .ne. RECDIM)
+     +                  call errore('Range error: ', err)
+                endif
+            else
+                if (err .ne. NF_ECHAR)
+     +              call errore('wrong type: ', err)
+            endif
+1       continue
+
+C       The preceeding has written nothing for record variables, now try
+C       again with more than 0 records.
+
+C       Write record number NRECS to force writing of preceding records.
+C       Assumes variable cr is char vector with UNLIMITED dimension.
+
+        err = nf_inq_varid(ncid, "cr", vid)
+        if (err .ne. 0)
+     +      call errore('nf_inq_varid: ', err)
+        index(1) = NRECS
+        err = nf_put_var1_text(ncid, vid, index, 'x')
+        if (err .ne. 0)
+     +      call errore('nf_put_var1_text: ', err)
+
+        do 5 i = 1, NVARS
+C           Only test record variables here
+            if (var_rank(i) .ge. 1 .and.
+     +          var_dimid(var_rank(i),i) .eq. RECDIM) then
+                canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT .eq. NFT_TEXT)
+                if (var_rank(i) .gt. MAX_RANK)
+     +              stop 2
+                if (var_nels(i) .gt. MAX_NELS)
+     +              stop 2
+                err = nf_put_var_int(BAD_ID, i, value)
+
+                nels = 1
+                do 6 j = 1, var_rank(i)
+                    nels = nels * var_shape(j,i)
+6               continue
+                allInExtRange = .true.
+                do 7, j = 1, nels
+                    err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                    if (err .ne. 0) 
+     +                  call error('error in index2indexes()')
+                    value(j) = hash_int(var_type(i), 
+     +                  var_rank(i),
+     +                  index, NFT_INT)
+                    val = value(j)
+                    allInExtRange = allInExtRange .and.
+     +                  inRange3(val, var_type(i), NFT_INT)
+7               continue
+                err = nf_put_var_int(ncid, i, value)
+                if (canConvert) then
+                    if (allInExtRange) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('range error: ', err)
+                    endif
+                else
+                    if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                endif
+            endif
+5       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_int(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed: ', 
+     +                  scratch)
+        end
+
+        subroutine test_nf_put_var_real()
+        use tests
+        implicit        none
+        integer ncid
+        integer vid
+        integer i
+        integer j
+        integer err
+        integer nels
+        integer index(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* All values within external range?*/
+        real    value(MAX_NELS)
+        doubleprecision val
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_REAL .eq. NFT_TEXT)
+            err = nf_put_var_real(BAD_ID, i, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_var_real(ncid, BAD_VARID, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            nels = 1
+            do 3, j = 1, var_rank(i)
+                nels = nels * var_shape(j,i)
+3           continue
+            allInExtRange = .true.
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0) 
+     +              call error('error in index2indexes 1')
+                value(j) = hash_real(var_type(i), 
+     +              var_rank(i),
+     +              index, NFT_REAL)
+                val = value(j)
+                allInExtRange = allInExtRange .and.
+     +              inRange3(val, var_type(i), NFT_REAL)
+4           continue
+            err = nf_put_var_real(ncid, i, value)
+            if (canConvert) then
+                if (allInExtRange) then
+                    if (err .ne. 0)
+     +                  call error(nf_strerror(err))
+                else
+                    if (err .ne. NF_ERANGE .and.
+     +                      var_dimid(var_rank(i),i) .ne. RECDIM)
+     +                  call errore('Range error: ', err)
+                endif
+            else
+                if (err .ne. NF_ECHAR)
+     +              call errore('wrong type: ', err)
+            endif
+1       continue
+
+C       The preceeding has written nothing for record variables, now try
+C       again with more than 0 records.
+
+C       Write record number NRECS to force writing of preceding records.
+C       Assumes variable cr is char vector with UNLIMITED dimension.
+
+        err = nf_inq_varid(ncid, "cr", vid)
+        if (err .ne. 0)
+     +      call errore('nf_inq_varid: ', err)
+        index(1) = NRECS
+        err = nf_put_var1_text(ncid, vid, index, 'x')
+        if (err .ne. 0)
+     +      call errore('nf_put_var1_text: ', err)
+
+        do 5 i = 1, NVARS
+C           Only test record variables here
+            if (var_rank(i) .ge. 1 .and.
+     +          var_dimid(var_rank(i),i) .eq. RECDIM) then
+                canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_REAL .eq. NFT_TEXT)
+                if (var_rank(i) .gt. MAX_RANK)
+     +              stop 2
+                if (var_nels(i) .gt. MAX_NELS)
+     +              stop 2
+                err = nf_put_var_real(BAD_ID, i, value)
+
+                nels = 1
+                do 6 j = 1, var_rank(i)
+                    nels = nels * var_shape(j,i)
+6               continue
+                allInExtRange = .true.
+                do 7, j = 1, nels
+                    err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                    if (err .ne. 0) 
+     +                  call error('error in index2indexes()')
+                    value(j) = hash_real(var_type(i), 
+     +                  var_rank(i),
+     +                  index, NFT_REAL)
+                    val = value(j)
+                    allInExtRange = allInExtRange .and.
+     +                  inRange3(val, var_type(i), NFT_REAL)
+7               continue
+                err = nf_put_var_real(ncid, i, value)
+                if (canConvert) then
+                    if (allInExtRange) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('range error: ', err)
+                    endif
+                else
+                    if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                endif
+            endif
+5       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_real(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed: ', 
+     +                  scratch)
+        end
+
+        subroutine test_nf_put_var_double()
+        use tests
+        implicit        none
+        integer ncid
+        integer vid
+        integer i
+        integer j
+        integer err
+        integer nels
+        integer index(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* All values within external range?*/
+        doubleprecision    value(MAX_NELS)
+        doubleprecision val
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_DOUBLE .eq. NFT_TEXT)
+            err = nf_put_var_double(BAD_ID, i, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_var_double(ncid, BAD_VARID, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            nels = 1
+            do 3, j = 1, var_rank(i)
+                nels = nels * var_shape(j,i)
+3           continue
+            allInExtRange = .true.
+            do 4, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0) 
+     +              call error('error in index2indexes 1')
+                value(j) = hash_double(var_type(i), 
+     +              var_rank(i),
+     +              index, NFT_DOUBLE)
+                val = value(j)
+                allInExtRange = allInExtRange .and.
+     +              inRange3(val, var_type(i), NFT_DOUBLE)
+4           continue
+            err = nf_put_var_double(ncid, i, value)
+            if (canConvert) then
+                if (allInExtRange) then
+                    if (err .ne. 0)
+     +                  call error(nf_strerror(err))
+                else
+                    if (err .ne. NF_ERANGE .and.
+     +                      var_dimid(var_rank(i),i) .ne. RECDIM)
+     +                  call errore('Range error: ', err)
+                endif
+            else
+                if (err .ne. NF_ECHAR)
+     +              call errore('wrong type: ', err)
+            endif
+1       continue
+
+C       The preceeding has written nothing for record variables, now try
+C       again with more than 0 records.
+
+C       Write record number NRECS to force writing of preceding records.
+C       Assumes variable cr is char vector with UNLIMITED dimension.
+
+        err = nf_inq_varid(ncid, "cr", vid)
+        if (err .ne. 0)
+     +      call errore('nf_inq_varid: ', err)
+        index(1) = NRECS
+        err = nf_put_var1_text(ncid, vid, index, 'x')
+        if (err .ne. 0)
+     +      call errore('nf_put_var1_text: ', err)
+
+        do 5 i = 1, NVARS
+C           Only test record variables here
+            if (var_rank(i) .ge. 1 .and.
+     +          var_dimid(var_rank(i),i) .eq. RECDIM) then
+                canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_DOUBLE .eq. NFT_TEXT)
+                if (var_rank(i) .gt. MAX_RANK)
+     +              stop 2
+                if (var_nels(i) .gt. MAX_NELS)
+     +              stop 2
+                err = nf_put_var_double(BAD_ID, i, value)
+
+                nels = 1
+                do 6 j = 1, var_rank(i)
+                    nels = nels * var_shape(j,i)
+6               continue
+                allInExtRange = .true.
+                do 7, j = 1, nels
+                    err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                    if (err .ne. 0) 
+     +                  call error('error in index2indexes()')
+                    value(j) = hash_double(var_type(i), 
+     +                  var_rank(i),
+     +                  index, NFT_DOUBLE)
+                    val = value(j)
+                    allInExtRange = allInExtRange .and.
+     +                  inRange3(val, var_type(i), NFT_DOUBLE)
+7               continue
+                err = nf_put_var_double(ncid, i, value)
+                if (canConvert) then
+                    if (allInExtRange) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('range error: ', err)
+                    endif
+                else
+                    if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                endif
+            endif
+5       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_double(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed: ', 
+     +                  scratch)
+        end
+
+
+        subroutine test_nf_put_vara_text()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer k
+        integer d
+        integer err
+        integer nslabs
+        integer nels
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer index(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* all values within external range? */
+        character    value(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_TEXT .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK))
+     +          stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS))
+     +          stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+2           continue
+            err = nf_put_vara_text(BAD_ID, i, start,
+     +                  edge, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_vara_text(ncid, BAD_VARID,
+     +                  start, edge, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .ne. RECDIM) then    !/* skip record dim */
+                    start(j) = var_shape(j,i) + 1
+                    err = nf_put_vara_text(ncid, i, start, 
+     +                                   edge, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EINVALCOORDS)
+     +                      call errore('bad start: ', err)
+                    endif
+                    start(j) = 1
+                    edge(j) = var_shape(j,i) + 1
+                    err = nf_put_vara_text(ncid, i, start, 
+     +                                   edge, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EEDGE)
+     +                      call errore('bad edge: ', err)
+                    endif
+                    edge(j) = 1
+                end if
+3           continue
+
+C       /* Check correct error returned even when nothing to put */
+        do 20, j = 1, var_rank(i)
+              edge(j) = 0
+20      continue
+        err = nf_put_vara_text(BAD_ID, i, start,
+     +          edge, value)
+        if (err .ne. NF_EBADID) 
+     +      call errore('bad ncid: ', err)
+        err = nf_put_vara_text(ncid, BAD_VARID,
+     +          start, edge, value)
+        if (err .ne. NF_ENOTVAR) 
+     +      call errore('bad var id: ', err)
+        do 21, j = 1, var_rank(i)
+            if (var_dimid(j,i) .gt. 1) then     ! skip record dim
+                start(j) = var_shape(j,i) + 2
+                err = nf_put_vara_text(ncid, i, start,
+     +                  edge, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad start: ', err)
+                endif
+                start(j) = 1
+            endif
+21      continue
+        err = nf_put_vara_text(ncid, i, start, edge, value)
+        if (canConvert) then
+            if (err .ne. 0) 
+     +          call error(nf_strerror(err))
+        else
+            if (err .ne. NF_ECHAR)
+     +          call errore('wrong type: ', err)
+        endif
+        do 22, j = 1, var_rank(i)
+              edge(j) = 1
+22      continue
+
+
+                !/* Choose a random point dividing each dim into 2 parts */
+                !/* Put 2^rank (nslabs) slabs so defined */
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+                !/* bits of k determine whether to put lower or upper part of dim */
+            do 5, k = 1, nslabs
+                nels = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    nels = nels * edge(j)
+6               continue
+                allInExtRange = .true.
+                do 7, j = 1, nels
+                    err = index2indexes(j, var_rank(i), edge, index)
+                    if (err .ne. 0) 
+     +                  call error('error in index2indexes 1')
+                    do 8, d = 1, var_rank(i)
+                        index(d) = index(d) + start(d) - 1
+8                   continue
+                    value(j)= char(int(hash_text(var_type(i), 
+     +                                  var_rank(i), index, 
+     +                                  NFT_TEXT)))
+                    val = ichar(value(j))
+                    allInExtRange = allInExtRange .and.
+     +                  inRange3(val, var_type(i), NFT_TEXT)
+7               continue
+                err = nf_put_vara_text(ncid, i, start,
+     +                  edge, value)
+                if (canConvert) then
+                    if (allInExtRange) then
+                        if (err .ne. 0) 
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('range error: ', err)
+                    end if
+                else
+                    if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+5           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_text(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed: ', 
+     +          scratch)
+        end
+
+#ifdef NF_INT1_T
+        subroutine test_nf_put_vara_int1()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer k
+        integer d
+        integer err
+        integer nslabs
+        integer nels
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer index(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* all values within external range? */
+        NF_INT1_T    value(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT1 .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK))
+     +          stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS))
+     +          stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+2           continue
+            err = nf_put_vara_int1(BAD_ID, i, start,
+     +                  edge, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_vara_int1(ncid, BAD_VARID,
+     +                  start, edge, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .ne. RECDIM) then    !/* skip record dim */
+                    start(j) = var_shape(j,i) + 1
+                    err = nf_put_vara_int1(ncid, i, start, 
+     +                                   edge, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EINVALCOORDS)
+     +                      call errore('bad start: ', err)
+                    endif
+                    start(j) = 1
+                    edge(j) = var_shape(j,i) + 1
+                    err = nf_put_vara_int1(ncid, i, start, 
+     +                                   edge, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EEDGE)
+     +                      call errore('bad edge: ', err)
+                    endif
+                    edge(j) = 1
+                end if
+3           continue
+
+C       /* Check correct error returned even when nothing to put */
+        do 20, j = 1, var_rank(i)
+              edge(j) = 0
+20      continue
+        err = nf_put_vara_int1(BAD_ID, i, start,
+     +          edge, value)
+        if (err .ne. NF_EBADID) 
+     +      call errore('bad ncid: ', err)
+        err = nf_put_vara_int1(ncid, BAD_VARID,
+     +          start, edge, value)
+        if (err .ne. NF_ENOTVAR) 
+     +      call errore('bad var id: ', err)
+        do 21, j = 1, var_rank(i)
+            if (var_dimid(j,i) .gt. 1) then     ! skip record dim
+                start(j) = var_shape(j,i) + 2
+                err = nf_put_vara_int1(ncid, i, start,
+     +                  edge, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad start: ', err)
+                endif
+                start(j) = 1
+            endif
+21      continue
+        err = nf_put_vara_int1(ncid, i, start, edge, value)
+        if (canConvert) then
+            if (err .ne. 0) 
+     +          call error(nf_strerror(err))
+        else
+            if (err .ne. NF_ECHAR)
+     +          call errore('wrong type: ', err)
+        endif
+        do 22, j = 1, var_rank(i)
+              edge(j) = 1
+22      continue
+
+
+                !/* Choose a random point dividing each dim into 2 parts */
+                !/* Put 2^rank (nslabs) slabs so defined */
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+                !/* bits of k determine whether to put lower or upper part of dim */
+            do 5, k = 1, nslabs
+                nels = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    nels = nels * edge(j)
+6               continue
+                allInExtRange = .true.
+                do 7, j = 1, nels
+                    err = index2indexes(j, var_rank(i), edge, index)
+                    if (err .ne. 0) 
+     +                  call error('error in index2indexes 1')
+                    do 8, d = 1, var_rank(i)
+                        index(d) = index(d) + start(d) - 1
+8                   continue
+                    value(j)= hash_int1(var_type(i), 
+     +                                  var_rank(i), index, 
+     +                                  NFT_INT1)
+                    val = value(j)
+                    allInExtRange = allInExtRange .and.
+     +                  inRange3(val, var_type(i), NFT_INT1)
+7               continue
+                err = nf_put_vara_int1(ncid, i, start,
+     +                  edge, value)
+                if (canConvert) then
+                    if (allInExtRange) then
+                        if (err .ne. 0) 
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('range error: ', err)
+                    end if
+                else
+                    if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+5           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_int1(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed: ', 
+     +          scratch)
+        end
+
+#endif
+#ifdef NF_INT2_T
+        subroutine test_nf_put_vara_int2()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer k
+        integer d
+        integer err
+        integer nslabs
+        integer nels
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer index(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* all values within external range? */
+        NF_INT2_T    value(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT2 .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK))
+     +          stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS))
+     +          stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+2           continue
+            err = nf_put_vara_int2(BAD_ID, i, start,
+     +                  edge, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_vara_int2(ncid, BAD_VARID,
+     +                  start, edge, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .ne. RECDIM) then    !/* skip record dim */
+                    start(j) = var_shape(j,i) + 1
+                    err = nf_put_vara_int2(ncid, i, start, 
+     +                                   edge, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EINVALCOORDS)
+     +                      call errore('bad start: ', err)
+                    endif
+                    start(j) = 1
+                    edge(j) = var_shape(j,i) + 1
+                    err = nf_put_vara_int2(ncid, i, start, 
+     +                                   edge, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EEDGE)
+     +                      call errore('bad edge: ', err)
+                    endif
+                    edge(j) = 1
+                end if
+3           continue
+
+C       /* Check correct error returned even when nothing to put */
+        do 20, j = 1, var_rank(i)
+              edge(j) = 0
+20      continue
+        err = nf_put_vara_int2(BAD_ID, i, start,
+     +          edge, value)
+        if (err .ne. NF_EBADID) 
+     +      call errore('bad ncid: ', err)
+        err = nf_put_vara_int2(ncid, BAD_VARID,
+     +          start, edge, value)
+        if (err .ne. NF_ENOTVAR) 
+     +      call errore('bad var id: ', err)
+        do 21, j = 1, var_rank(i)
+            if (var_dimid(j,i) .gt. 1) then     ! skip record dim
+                start(j) = var_shape(j,i) + 2
+                err = nf_put_vara_int2(ncid, i, start,
+     +                  edge, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad start: ', err)
+                endif
+                start(j) = 1
+            endif
+21      continue
+        err = nf_put_vara_int2(ncid, i, start, edge, value)
+        if (canConvert) then
+            if (err .ne. 0) 
+     +          call error(nf_strerror(err))
+        else
+            if (err .ne. NF_ECHAR)
+     +          call errore('wrong type: ', err)
+        endif
+        do 22, j = 1, var_rank(i)
+              edge(j) = 1
+22      continue
+
+
+                !/* Choose a random point dividing each dim into 2 parts */
+                !/* Put 2^rank (nslabs) slabs so defined */
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+                !/* bits of k determine whether to put lower or upper part of dim */
+            do 5, k = 1, nslabs
+                nels = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    nels = nels * edge(j)
+6               continue
+                allInExtRange = .true.
+                do 7, j = 1, nels
+                    err = index2indexes(j, var_rank(i), edge, index)
+                    if (err .ne. 0) 
+     +                  call error('error in index2indexes 1')
+                    do 8, d = 1, var_rank(i)
+                        index(d) = index(d) + start(d) - 1
+8                   continue
+                    value(j)= hash_int2(var_type(i), 
+     +                                  var_rank(i), index, 
+     +                                  NFT_INT2)
+                    val = value(j)
+                    allInExtRange = allInExtRange .and.
+     +                  inRange3(val, var_type(i), NFT_INT2)
+7               continue
+                err = nf_put_vara_int2(ncid, i, start,
+     +                  edge, value)
+                if (canConvert) then
+                    if (allInExtRange) then
+                        if (err .ne. 0) 
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('range error: ', err)
+                    end if
+                else
+                    if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+5           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_int2(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed: ', 
+     +          scratch)
+        end
+
+#endif
+        subroutine test_nf_put_vara_int()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer k
+        integer d
+        integer err
+        integer nslabs
+        integer nels
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer index(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* all values within external range? */
+        integer    value(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK))
+     +          stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS))
+     +          stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+2           continue
+            err = nf_put_vara_int(BAD_ID, i, start,
+     +                  edge, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_vara_int(ncid, BAD_VARID,
+     +                  start, edge, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .ne. RECDIM) then    !/* skip record dim */
+                    start(j) = var_shape(j,i) + 1
+                    err = nf_put_vara_int(ncid, i, start, 
+     +                                   edge, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EINVALCOORDS)
+     +                      call errore('bad start: ', err)
+                    endif
+                    start(j) = 1
+                    edge(j) = var_shape(j,i) + 1
+                    err = nf_put_vara_int(ncid, i, start, 
+     +                                   edge, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EEDGE)
+     +                      call errore('bad edge: ', err)
+                    endif
+                    edge(j) = 1
+                end if
+3           continue
+
+C       /* Check correct error returned even when nothing to put */
+        do 20, j = 1, var_rank(i)
+              edge(j) = 0
+20      continue
+        err = nf_put_vara_int(BAD_ID, i, start,
+     +          edge, value)
+        if (err .ne. NF_EBADID) 
+     +      call errore('bad ncid: ', err)
+        err = nf_put_vara_int(ncid, BAD_VARID,
+     +          start, edge, value)
+        if (err .ne. NF_ENOTVAR) 
+     +      call errore('bad var id: ', err)
+        do 21, j = 1, var_rank(i)
+            if (var_dimid(j,i) .gt. 1) then     ! skip record dim
+                start(j) = var_shape(j,i) + 2
+                err = nf_put_vara_int(ncid, i, start,
+     +                  edge, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad start: ', err)
+                endif
+                start(j) = 1
+            endif
+21      continue
+        err = nf_put_vara_int(ncid, i, start, edge, value)
+        if (canConvert) then
+            if (err .ne. 0) 
+     +          call error(nf_strerror(err))
+        else
+            if (err .ne. NF_ECHAR)
+     +          call errore('wrong type: ', err)
+        endif
+        do 22, j = 1, var_rank(i)
+              edge(j) = 1
+22      continue
+
+
+                !/* Choose a random point dividing each dim into 2 parts */
+                !/* Put 2^rank (nslabs) slabs so defined */
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+                !/* bits of k determine whether to put lower or upper part of dim */
+            do 5, k = 1, nslabs
+                nels = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    nels = nels * edge(j)
+6               continue
+                allInExtRange = .true.
+                do 7, j = 1, nels
+                    err = index2indexes(j, var_rank(i), edge, index)
+                    if (err .ne. 0) 
+     +                  call error('error in index2indexes 1')
+                    do 8, d = 1, var_rank(i)
+                        index(d) = index(d) + start(d) - 1
+8                   continue
+                    value(j)= hash_int(var_type(i), 
+     +                                  var_rank(i), index, 
+     +                                  NFT_INT)
+                    val = value(j)
+                    allInExtRange = allInExtRange .and.
+     +                  inRange3(val, var_type(i), NFT_INT)
+7               continue
+                err = nf_put_vara_int(ncid, i, start,
+     +                  edge, value)
+                if (canConvert) then
+                    if (allInExtRange) then
+                        if (err .ne. 0) 
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('range error: ', err)
+                    end if
+                else
+                    if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+5           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_int(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed: ', 
+     +          scratch)
+        end
+
+        subroutine test_nf_put_vara_real()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer k
+        integer d
+        integer err
+        integer nslabs
+        integer nels
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer index(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* all values within external range? */
+        real    value(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_REAL .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK))
+     +          stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS))
+     +          stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+2           continue
+            err = nf_put_vara_real(BAD_ID, i, start,
+     +                  edge, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_vara_real(ncid, BAD_VARID,
+     +                  start, edge, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .ne. RECDIM) then    !/* skip record dim */
+                    start(j) = var_shape(j,i) + 1
+                    err = nf_put_vara_real(ncid, i, start, 
+     +                                   edge, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EINVALCOORDS)
+     +                      call errore('bad start: ', err)
+                    endif
+                    start(j) = 1
+                    edge(j) = var_shape(j,i) + 1
+                    err = nf_put_vara_real(ncid, i, start, 
+     +                                   edge, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EEDGE)
+     +                      call errore('bad edge: ', err)
+                    endif
+                    edge(j) = 1
+                end if
+3           continue
+
+C       /* Check correct error returned even when nothing to put */
+        do 20, j = 1, var_rank(i)
+              edge(j) = 0
+20      continue
+        err = nf_put_vara_real(BAD_ID, i, start,
+     +          edge, value)
+        if (err .ne. NF_EBADID) 
+     +      call errore('bad ncid: ', err)
+        err = nf_put_vara_real(ncid, BAD_VARID,
+     +          start, edge, value)
+        if (err .ne. NF_ENOTVAR) 
+     +      call errore('bad var id: ', err)
+        do 21, j = 1, var_rank(i)
+            if (var_dimid(j,i) .gt. 1) then     ! skip record dim
+                start(j) = var_shape(j,i) + 2
+                err = nf_put_vara_real(ncid, i, start,
+     +                  edge, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad start: ', err)
+                endif
+                start(j) = 1
+            endif
+21      continue
+        err = nf_put_vara_real(ncid, i, start, edge, value)
+        if (canConvert) then
+            if (err .ne. 0) 
+     +          call error(nf_strerror(err))
+        else
+            if (err .ne. NF_ECHAR)
+     +          call errore('wrong type: ', err)
+        endif
+        do 22, j = 1, var_rank(i)
+              edge(j) = 1
+22      continue
+
+
+                !/* Choose a random point dividing each dim into 2 parts */
+                !/* Put 2^rank (nslabs) slabs so defined */
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+                !/* bits of k determine whether to put lower or upper part of dim */
+            do 5, k = 1, nslabs
+                nels = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    nels = nels * edge(j)
+6               continue
+                allInExtRange = .true.
+                do 7, j = 1, nels
+                    err = index2indexes(j, var_rank(i), edge, index)
+                    if (err .ne. 0) 
+     +                  call error('error in index2indexes 1')
+                    do 8, d = 1, var_rank(i)
+                        index(d) = index(d) + start(d) - 1
+8                   continue
+                    value(j)= hash_real(var_type(i), 
+     +                                  var_rank(i), index, 
+     +                                  NFT_REAL)
+                    val = value(j)
+                    allInExtRange = allInExtRange .and.
+     +                  inRange3(val, var_type(i), NFT_REAL)
+7               continue
+                err = nf_put_vara_real(ncid, i, start,
+     +                  edge, value)
+                if (canConvert) then
+                    if (allInExtRange) then
+                        if (err .ne. 0) 
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('range error: ', err)
+                    end if
+                else
+                    if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+5           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_real(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed: ', 
+     +          scratch)
+        end
+
+        subroutine test_nf_put_vara_double()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer k
+        integer d
+        integer err
+        integer nslabs
+        integer nels
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer index(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* all values within external range? */
+        doubleprecision    value(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_DOUBLE .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK))
+     +          stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS))
+     +          stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+2           continue
+            err = nf_put_vara_double(BAD_ID, i, start,
+     +                  edge, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_vara_double(ncid, BAD_VARID,
+     +                  start, edge, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .ne. RECDIM) then    !/* skip record dim */
+                    start(j) = var_shape(j,i) + 1
+                    err = nf_put_vara_double(ncid, i, start, 
+     +                                   edge, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EINVALCOORDS)
+     +                      call errore('bad start: ', err)
+                    endif
+                    start(j) = 1
+                    edge(j) = var_shape(j,i) + 1
+                    err = nf_put_vara_double(ncid, i, start, 
+     +                                   edge, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EEDGE)
+     +                      call errore('bad edge: ', err)
+                    endif
+                    edge(j) = 1
+                end if
+3           continue
+
+C       /* Check correct error returned even when nothing to put */
+        do 20, j = 1, var_rank(i)
+              edge(j) = 0
+20      continue
+        err = nf_put_vara_double(BAD_ID, i, start,
+     +          edge, value)
+        if (err .ne. NF_EBADID) 
+     +      call errore('bad ncid: ', err)
+        err = nf_put_vara_double(ncid, BAD_VARID,
+     +          start, edge, value)
+        if (err .ne. NF_ENOTVAR) 
+     +      call errore('bad var id: ', err)
+        do 21, j = 1, var_rank(i)
+            if (var_dimid(j,i) .gt. 1) then     ! skip record dim
+                start(j) = var_shape(j,i) + 2
+                err = nf_put_vara_double(ncid, i, start,
+     +                  edge, value)
+                if (.not. canConvert) then
+                    if (err .ne. NF_ECHAR)
+     +                  call errore('conversion: ', err)
+                else
+                    if (err .ne. NF_EINVALCOORDS)
+     +                  call errore('bad start: ', err)
+                endif
+                start(j) = 1
+            endif
+21      continue
+        err = nf_put_vara_double(ncid, i, start, edge, value)
+        if (canConvert) then
+            if (err .ne. 0) 
+     +          call error(nf_strerror(err))
+        else
+            if (err .ne. NF_ECHAR)
+     +          call errore('wrong type: ', err)
+        endif
+        do 22, j = 1, var_rank(i)
+              edge(j) = 1
+22      continue
+
+
+                !/* Choose a random point dividing each dim into 2 parts */
+                !/* Put 2^rank (nslabs) slabs so defined */
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+                !/* bits of k determine whether to put lower or upper part of dim */
+            do 5, k = 1, nslabs
+                nels = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    nels = nels * edge(j)
+6               continue
+                allInExtRange = .true.
+                do 7, j = 1, nels
+                    err = index2indexes(j, var_rank(i), edge, index)
+                    if (err .ne. 0) 
+     +                  call error('error in index2indexes 1')
+                    do 8, d = 1, var_rank(i)
+                        index(d) = index(d) + start(d) - 1
+8                   continue
+                    value(j)= hash_double(var_type(i), 
+     +                                  var_rank(i), index, 
+     +                                  NFT_DOUBLE)
+                    val = value(j)
+                    allInExtRange = allInExtRange .and.
+     +                  inRange3(val, var_type(i), NFT_DOUBLE)
+7               continue
+                err = nf_put_vara_double(ncid, i, start,
+     +                  edge, value)
+                if (canConvert) then
+                    if (allInExtRange) then
+                        if (err .ne. 0) 
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('range error: ', err)
+                    end if
+                else
+                    if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                  call errore('wrong type: ', err)
+                end if
+5           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_double(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed: ', 
+     +          scratch)
+        end
+
+
+        subroutine test_nf_put_vars_text()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        integer nels
+        integer nslabs
+        integer nstarts        !/* number of different starts */
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* all values within external range? */
+        character    value(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_TEXT .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK))
+     +          stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS))
+     +          stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+2           continue
+            err = nf_put_vars_text(BAD_ID, i, start,
+     +                  edge, stride, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_vars_text(ncid, BAD_VARID, start,
+     +                           edge, stride, 
+     +                           value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .ne. RECDIM) then    ! skip record dim
+                    start(j) = var_shape(j,i) + 2
+                    err = nf_put_vars_text(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EINVALCOORDS)
+     +                          call errore('bad start: ', err)
+                    endif
+                    start(j) = 1
+                    edge(j) = var_shape(j,i) + 1
+                    err = nf_put_vars_text(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EEDGE)
+     +                      call errore('bad edge: ', err)
+                    endif
+                    edge(j) = 1
+                    stride(j) = 0
+                    err = nf_put_vars_text(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_ESTRIDE)
+     +                      call errore('bad stride: ', err)
+                    endif
+                    stride(j) = 1
+                end if
+3           continue
+                !/* Choose a random point dividing each dim into 2 parts */
+                !/* Put 2^rank (nslabs) slabs so defined */
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+                !/* bits of k determine whether to put lower or upper part of dim */
+                !/* choose random stride from 1 to edge */
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        stride(j) = 1+roll(edge(j))
+                    else
+                        stride(j) = 1
+                    end if
+                    sstride(j) = stride(j)
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+                        !/* Random choice of forward or backward */
+C/* TODO
+C                   if ( roll(2) ) {
+C                       for (j = 1 j .lt. var_rank(i) j++) {
+C                           index(j) += (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C                       }
+C                   }
+C*/
+                    allInExtRange = .true.
+                    do 9, j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes')
+                        do 10, d = 1, var_rank(i)
+                            index2(d) = index(d) + 
+     +                                  (index2(d)-1) * stride(d)
+10                      continue
+                        value(j) = char(int(hash_text(var_type(i), 
+     +                     var_rank(i), 
+     +                     index2, NFT_TEXT)))
+                        val = ichar(value(j))
+                        allInExtRange = allInExtRange .and.
+     +                      inRange3(val, var_type(i), 
+     +                               NFT_TEXT)
+9                   continue
+                    err = nf_put_vars_text(ncid, i, index,
+     +                                   count, stride,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (err .ne. 0) 
+     +                          call error(nf_strerror(err))
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('range error: ', err)
+                        end if
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_text(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed:', 
+     +          scratch)
+        end
+
+#ifdef NF_INT1_T
+        subroutine test_nf_put_vars_int1()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        integer nels
+        integer nslabs
+        integer nstarts        !/* number of different starts */
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* all values within external range? */
+        NF_INT1_T    value(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT1 .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK))
+     +          stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS))
+     +          stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+2           continue
+            err = nf_put_vars_int1(BAD_ID, i, start,
+     +                  edge, stride, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_vars_int1(ncid, BAD_VARID, start,
+     +                           edge, stride, 
+     +                           value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .ne. RECDIM) then    ! skip record dim
+                    start(j) = var_shape(j,i) + 2
+                    err = nf_put_vars_int1(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EINVALCOORDS)
+     +                          call errore('bad start: ', err)
+                    endif
+                    start(j) = 1
+                    edge(j) = var_shape(j,i) + 1
+                    err = nf_put_vars_int1(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EEDGE)
+     +                      call errore('bad edge: ', err)
+                    endif
+                    edge(j) = 1
+                    stride(j) = 0
+                    err = nf_put_vars_int1(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_ESTRIDE)
+     +                      call errore('bad stride: ', err)
+                    endif
+                    stride(j) = 1
+                end if
+3           continue
+                !/* Choose a random point dividing each dim into 2 parts */
+                !/* Put 2^rank (nslabs) slabs so defined */
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+                !/* bits of k determine whether to put lower or upper part of dim */
+                !/* choose random stride from 1 to edge */
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        stride(j) = 1+roll(edge(j))
+                    else
+                        stride(j) = 1
+                    end if
+                    sstride(j) = stride(j)
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+                        !/* Random choice of forward or backward */
+C/* TODO
+C                   if ( roll(2) ) {
+C                       for (j = 1 j .lt. var_rank(i) j++) {
+C                           index(j) += (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C                       }
+C                   }
+C*/
+                    allInExtRange = .true.
+                    do 9, j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes')
+                        do 10, d = 1, var_rank(i)
+                            index2(d) = index(d) + 
+     +                                  (index2(d)-1) * stride(d)
+10                      continue
+                        value(j) = hash_int1(var_type(i), 
+     +                     var_rank(i), 
+     +                     index2, NFT_INT1)
+                        val = value(j)
+                        allInExtRange = allInExtRange .and.
+     +                      inRange3(val, var_type(i), 
+     +                               NFT_INT1)
+9                   continue
+                    err = nf_put_vars_int1(ncid, i, index,
+     +                                   count, stride,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (err .ne. 0) 
+     +                          call error(nf_strerror(err))
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('range error: ', err)
+                        end if
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_int1(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed:', 
+     +          scratch)
+        end
+
+#endif
+#ifdef NF_INT2_T
+        subroutine test_nf_put_vars_int2()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        integer nels
+        integer nslabs
+        integer nstarts        !/* number of different starts */
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* all values within external range? */
+        NF_INT2_T    value(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT2 .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK))
+     +          stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS))
+     +          stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+2           continue
+            err = nf_put_vars_int2(BAD_ID, i, start,
+     +                  edge, stride, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_vars_int2(ncid, BAD_VARID, start,
+     +                           edge, stride, 
+     +                           value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .ne. RECDIM) then    ! skip record dim
+                    start(j) = var_shape(j,i) + 2
+                    err = nf_put_vars_int2(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EINVALCOORDS)
+     +                          call errore('bad start: ', err)
+                    endif
+                    start(j) = 1
+                    edge(j) = var_shape(j,i) + 1
+                    err = nf_put_vars_int2(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EEDGE)
+     +                      call errore('bad edge: ', err)
+                    endif
+                    edge(j) = 1
+                    stride(j) = 0
+                    err = nf_put_vars_int2(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_ESTRIDE)
+     +                      call errore('bad stride: ', err)
+                    endif
+                    stride(j) = 1
+                end if
+3           continue
+                !/* Choose a random point dividing each dim into 2 parts */
+                !/* Put 2^rank (nslabs) slabs so defined */
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+                !/* bits of k determine whether to put lower or upper part of dim */
+                !/* choose random stride from 1 to edge */
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        stride(j) = 1+roll(edge(j))
+                    else
+                        stride(j) = 1
+                    end if
+                    sstride(j) = stride(j)
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+                        !/* Random choice of forward or backward */
+C/* TODO
+C                   if ( roll(2) ) {
+C                       for (j = 1 j .lt. var_rank(i) j++) {
+C                           index(j) += (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C                       }
+C                   }
+C*/
+                    allInExtRange = .true.
+                    do 9, j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes')
+                        do 10, d = 1, var_rank(i)
+                            index2(d) = index(d) + 
+     +                                  (index2(d)-1) * stride(d)
+10                      continue
+                        value(j) = hash_int2(var_type(i), 
+     +                     var_rank(i), 
+     +                     index2, NFT_INT2)
+                        val = value(j)
+                        allInExtRange = allInExtRange .and.
+     +                      inRange3(val, var_type(i), 
+     +                               NFT_INT2)
+9                   continue
+                    err = nf_put_vars_int2(ncid, i, index,
+     +                                   count, stride,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (err .ne. 0) 
+     +                          call error(nf_strerror(err))
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('range error: ', err)
+                        end if
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_int2(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed:', 
+     +          scratch)
+        end
+
+#endif
+        subroutine test_nf_put_vars_int()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        integer nels
+        integer nslabs
+        integer nstarts        !/* number of different starts */
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* all values within external range? */
+        integer    value(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK))
+     +          stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS))
+     +          stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+2           continue
+            err = nf_put_vars_int(BAD_ID, i, start,
+     +                  edge, stride, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_vars_int(ncid, BAD_VARID, start,
+     +                           edge, stride, 
+     +                           value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .ne. RECDIM) then    ! skip record dim
+                    start(j) = var_shape(j,i) + 2
+                    err = nf_put_vars_int(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EINVALCOORDS)
+     +                          call errore('bad start: ', err)
+                    endif
+                    start(j) = 1
+                    edge(j) = var_shape(j,i) + 1
+                    err = nf_put_vars_int(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EEDGE)
+     +                      call errore('bad edge: ', err)
+                    endif
+                    edge(j) = 1
+                    stride(j) = 0
+                    err = nf_put_vars_int(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_ESTRIDE)
+     +                      call errore('bad stride: ', err)
+                    endif
+                    stride(j) = 1
+                end if
+3           continue
+                !/* Choose a random point dividing each dim into 2 parts */
+                !/* Put 2^rank (nslabs) slabs so defined */
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+                !/* bits of k determine whether to put lower or upper part of dim */
+                !/* choose random stride from 1 to edge */
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        stride(j) = 1+roll(edge(j))
+                    else
+                        stride(j) = 1
+                    end if
+                    sstride(j) = stride(j)
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+                        !/* Random choice of forward or backward */
+C/* TODO
+C                   if ( roll(2) ) {
+C                       for (j = 1 j .lt. var_rank(i) j++) {
+C                           index(j) += (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C                       }
+C                   }
+C*/
+                    allInExtRange = .true.
+                    do 9, j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes')
+                        do 10, d = 1, var_rank(i)
+                            index2(d) = index(d) + 
+     +                                  (index2(d)-1) * stride(d)
+10                      continue
+                        value(j) = hash_int(var_type(i), 
+     +                     var_rank(i), 
+     +                     index2, NFT_INT)
+                        val = value(j)
+                        allInExtRange = allInExtRange .and.
+     +                      inRange3(val, var_type(i), 
+     +                               NFT_INT)
+9                   continue
+                    err = nf_put_vars_int(ncid, i, index,
+     +                                   count, stride,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (err .ne. 0) 
+     +                          call error(nf_strerror(err))
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('range error: ', err)
+                        end if
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_int(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed:', 
+     +          scratch)
+        end
+
+        subroutine test_nf_put_vars_real()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        integer nels
+        integer nslabs
+        integer nstarts        !/* number of different starts */
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* all values within external range? */
+        real    value(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_REAL .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK))
+     +          stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS))
+     +          stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+2           continue
+            err = nf_put_vars_real(BAD_ID, i, start,
+     +                  edge, stride, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_vars_real(ncid, BAD_VARID, start,
+     +                           edge, stride, 
+     +                           value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .ne. RECDIM) then    ! skip record dim
+                    start(j) = var_shape(j,i) + 2
+                    err = nf_put_vars_real(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EINVALCOORDS)
+     +                          call errore('bad start: ', err)
+                    endif
+                    start(j) = 1
+                    edge(j) = var_shape(j,i) + 1
+                    err = nf_put_vars_real(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EEDGE)
+     +                      call errore('bad edge: ', err)
+                    endif
+                    edge(j) = 1
+                    stride(j) = 0
+                    err = nf_put_vars_real(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_ESTRIDE)
+     +                      call errore('bad stride: ', err)
+                    endif
+                    stride(j) = 1
+                end if
+3           continue
+                !/* Choose a random point dividing each dim into 2 parts */
+                !/* Put 2^rank (nslabs) slabs so defined */
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+                !/* bits of k determine whether to put lower or upper part of dim */
+                !/* choose random stride from 1 to edge */
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        stride(j) = 1+roll(edge(j))
+                    else
+                        stride(j) = 1
+                    end if
+                    sstride(j) = stride(j)
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+                        !/* Random choice of forward or backward */
+C/* TODO
+C                   if ( roll(2) ) {
+C                       for (j = 1 j .lt. var_rank(i) j++) {
+C                           index(j) += (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C                       }
+C                   }
+C*/
+                    allInExtRange = .true.
+                    do 9, j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes')
+                        do 10, d = 1, var_rank(i)
+                            index2(d) = index(d) + 
+     +                                  (index2(d)-1) * stride(d)
+10                      continue
+                        value(j) = hash_real(var_type(i), 
+     +                     var_rank(i), 
+     +                     index2, NFT_REAL)
+                        val = value(j)
+                        allInExtRange = allInExtRange .and.
+     +                      inRange3(val, var_type(i), 
+     +                               NFT_REAL)
+9                   continue
+                    err = nf_put_vars_real(ncid, i, index,
+     +                                   count, stride,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (err .ne. 0) 
+     +                          call error(nf_strerror(err))
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('range error: ', err)
+                        end if
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_real(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed:', 
+     +          scratch)
+        end
+
+        subroutine test_nf_put_vars_double()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        integer nels
+        integer nslabs
+        integer nstarts        !/* number of different starts */
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* all values within external range? */
+        doubleprecision    value(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_DOUBLE .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK))
+     +          stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS))
+     +          stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+2           continue
+            err = nf_put_vars_double(BAD_ID, i, start,
+     +                  edge, stride, value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_vars_double(ncid, BAD_VARID, start,
+     +                           edge, stride, 
+     +                           value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .ne. RECDIM) then    ! skip record dim
+                    start(j) = var_shape(j,i) + 2
+                    err = nf_put_vars_double(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EINVALCOORDS)
+     +                          call errore('bad start: ', err)
+                    endif
+                    start(j) = 1
+                    edge(j) = var_shape(j,i) + 1
+                    err = nf_put_vars_double(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EEDGE)
+     +                      call errore('bad edge: ', err)
+                    endif
+                    edge(j) = 1
+                    stride(j) = 0
+                    err = nf_put_vars_double(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_ESTRIDE)
+     +                      call errore('bad stride: ', err)
+                    endif
+                    stride(j) = 1
+                end if
+3           continue
+                !/* Choose a random point dividing each dim into 2 parts */
+                !/* Put 2^rank (nslabs) slabs so defined */
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+                !/* bits of k determine whether to put lower or upper part of dim */
+                !/* choose random stride from 1 to edge */
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        stride(j) = 1+roll(edge(j))
+                    else
+                        stride(j) = 1
+                    end if
+                    sstride(j) = stride(j)
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+                        !/* Random choice of forward or backward */
+C/* TODO
+C                   if ( roll(2) ) {
+C                       for (j = 1 j .lt. var_rank(i) j++) {
+C                           index(j) += (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C                       }
+C                   }
+C*/
+                    allInExtRange = .true.
+                    do 9, j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes')
+                        do 10, d = 1, var_rank(i)
+                            index2(d) = index(d) + 
+     +                                  (index2(d)-1) * stride(d)
+10                      continue
+                        value(j) = hash_double(var_type(i), 
+     +                     var_rank(i), 
+     +                     index2, NFT_DOUBLE)
+                        val = value(j)
+                        allInExtRange = allInExtRange .and.
+     +                      inRange3(val, var_type(i), 
+     +                               NFT_DOUBLE)
+9                   continue
+                    err = nf_put_vars_double(ncid, i, index,
+     +                                   count, stride,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (err .ne. 0) 
+     +                          call error(nf_strerror(err))
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('range error: ', err)
+                        end if
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_double(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed:', 
+     +          scratch)
+        end
+
+
+        subroutine test_nf_put_varm_text()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        integer nels
+        integer nslabs
+        integer nstarts        !/* number of different starts */
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        integer imap(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* all values within external range? */
+        character value(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_TEXT .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK))
+     +          stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS))
+     +          stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+                imap(j) = 1
+2           continue
+            err = nf_put_varm_text(BAD_ID, i, start,
+     +                           edge, stride, imap, 
+     +                           value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_varm_text(ncid, BAD_VARID, start,
+     +                           edge, stride, 
+     +                           imap, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .ne. RECDIM) then    !/* skip record dim */
+                    start(j) = var_shape(j,i) + 2
+                    err = nf_put_varm_text(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   imap, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EINVALCOORDS)
+     +                      call errore('bad start: ', err)
+                    endif
+                    start(j) = 1
+                    edge(j) = var_shape(j,i) + 1
+                    err = nf_put_varm_text(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   imap, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EEDGE)
+     +                      call errore('bad edge: ', err)
+                    endif
+                    edge(j) = 1
+                    stride(j) = 0
+                    err = nf_put_varm_text(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   imap, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_ESTRIDE)
+     +                      call errore('bad stride: ', err)
+                    endif
+                    stride(j) = 1
+                end if
+3           continue
+                !/* Choose a random point dividing each dim into 2 parts */
+                !/* Put 2^rank (nslabs) slabs so defined */
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+                !/* bits of k determine whether to put lower or upper part of dim */
+                !/* choose random stride from 1 to edge */
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        stride(j) = 1+roll(edge(j))
+                    else
+                        stride(j) = 1
+                    end if
+                    sstride(j) = stride(j)
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+                        !/* Random choice of forward or backward */
+C/* TODO
+C                   if ( roll(2) ) then
+C                       do 9, j = 1, var_rank(i)
+C                           index(j) = index(j) + 
+C     +                         (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C9                      continue
+C                   end if
+C*/
+                    if (var_rank(i) .gt. 0) then
+                        imap(1) = 1
+                        do 10, j = 2, var_rank(i)
+                            imap(j) = imap(j-1) * count(j-1)
+10                      continue
+                    end if
+                    allInExtRange = .true.
+                    do 11 j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes')
+                        do 12, d = 1, var_rank(i)
+                            index2(d) = index(d) + 
+     +                          (index2(d)-1) * stride(d)
+12                      continue
+                        value(j) = char(int(hash_text(var_type(i),
+     +                                       var_rank(i), 
+     +                                       index2, NFT_TEXT)))
+                        val = ichar(value(j))
+                        allInExtRange = allInExtRange .and.
+     +                      inRange3(val, var_type(i), 
+     +                               NFT_TEXT)
+11                  continue
+                    err = nf_put_varm_text(ncid,i,index,count,
+     +                                   stride,imap,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (err .ne. 0)
+     +                          call error(nf_strerror(err))
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('range error: ', err)
+                        end if
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_text(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed:', 
+     +          scratch)
+        end
+
+#ifdef NF_INT1_T
+        subroutine test_nf_put_varm_int1()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        integer nels
+        integer nslabs
+        integer nstarts        !/* number of different starts */
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        integer imap(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* all values within external range? */
+        NF_INT1_T value(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT1 .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK))
+     +          stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS))
+     +          stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+                imap(j) = 1
+2           continue
+            err = nf_put_varm_int1(BAD_ID, i, start,
+     +                           edge, stride, imap, 
+     +                           value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_varm_int1(ncid, BAD_VARID, start,
+     +                           edge, stride, 
+     +                           imap, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .ne. RECDIM) then    !/* skip record dim */
+                    start(j) = var_shape(j,i) + 2
+                    err = nf_put_varm_int1(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   imap, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EINVALCOORDS)
+     +                      call errore('bad start: ', err)
+                    endif
+                    start(j) = 1
+                    edge(j) = var_shape(j,i) + 1
+                    err = nf_put_varm_int1(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   imap, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EEDGE)
+     +                      call errore('bad edge: ', err)
+                    endif
+                    edge(j) = 1
+                    stride(j) = 0
+                    err = nf_put_varm_int1(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   imap, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_ESTRIDE)
+     +                      call errore('bad stride: ', err)
+                    endif
+                    stride(j) = 1
+                end if
+3           continue
+                !/* Choose a random point dividing each dim into 2 parts */
+                !/* Put 2^rank (nslabs) slabs so defined */
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+                !/* bits of k determine whether to put lower or upper part of dim */
+                !/* choose random stride from 1 to edge */
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        stride(j) = 1+roll(edge(j))
+                    else
+                        stride(j) = 1
+                    end if
+                    sstride(j) = stride(j)
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+                        !/* Random choice of forward or backward */
+C/* TODO
+C                   if ( roll(2) ) then
+C                       do 9, j = 1, var_rank(i)
+C                           index(j) = index(j) + 
+C     +                         (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C9                      continue
+C                   end if
+C*/
+                    if (var_rank(i) .gt. 0) then
+                        imap(1) = 1
+                        do 10, j = 2, var_rank(i)
+                            imap(j) = imap(j-1) * count(j-1)
+10                      continue
+                    end if
+                    allInExtRange = .true.
+                    do 11 j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes')
+                        do 12, d = 1, var_rank(i)
+                            index2(d) = index(d) + 
+     +                          (index2(d)-1) * stride(d)
+12                      continue
+                        value(j) = hash_int1(var_type(i),
+     +                                       var_rank(i), 
+     +                                       index2, NFT_INT1)
+                        val = value(j)
+                        allInExtRange = allInExtRange .and.
+     +                      inRange3(val, var_type(i), 
+     +                               NFT_INT1)
+11                  continue
+                    err = nf_put_varm_int1(ncid,i,index,count,
+     +                                   stride,imap,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (err .ne. 0)
+     +                          call error(nf_strerror(err))
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('range error: ', err)
+                        end if
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_int1(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed:', 
+     +          scratch)
+        end
+
+#endif
+#ifdef NF_INT2_T
+        subroutine test_nf_put_varm_int2()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        integer nels
+        integer nslabs
+        integer nstarts        !/* number of different starts */
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        integer imap(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* all values within external range? */
+        NF_INT2_T value(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT2 .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK))
+     +          stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS))
+     +          stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+                imap(j) = 1
+2           continue
+            err = nf_put_varm_int2(BAD_ID, i, start,
+     +                           edge, stride, imap, 
+     +                           value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_varm_int2(ncid, BAD_VARID, start,
+     +                           edge, stride, 
+     +                           imap, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .ne. RECDIM) then    !/* skip record dim */
+                    start(j) = var_shape(j,i) + 2
+                    err = nf_put_varm_int2(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   imap, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EINVALCOORDS)
+     +                      call errore('bad start: ', err)
+                    endif
+                    start(j) = 1
+                    edge(j) = var_shape(j,i) + 1
+                    err = nf_put_varm_int2(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   imap, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EEDGE)
+     +                      call errore('bad edge: ', err)
+                    endif
+                    edge(j) = 1
+                    stride(j) = 0
+                    err = nf_put_varm_int2(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   imap, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_ESTRIDE)
+     +                      call errore('bad stride: ', err)
+                    endif
+                    stride(j) = 1
+                end if
+3           continue
+                !/* Choose a random point dividing each dim into 2 parts */
+                !/* Put 2^rank (nslabs) slabs so defined */
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+                !/* bits of k determine whether to put lower or upper part of dim */
+                !/* choose random stride from 1 to edge */
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        stride(j) = 1+roll(edge(j))
+                    else
+                        stride(j) = 1
+                    end if
+                    sstride(j) = stride(j)
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+                        !/* Random choice of forward or backward */
+C/* TODO
+C                   if ( roll(2) ) then
+C                       do 9, j = 1, var_rank(i)
+C                           index(j) = index(j) + 
+C     +                         (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C9                      continue
+C                   end if
+C*/
+                    if (var_rank(i) .gt. 0) then
+                        imap(1) = 1
+                        do 10, j = 2, var_rank(i)
+                            imap(j) = imap(j-1) * count(j-1)
+10                      continue
+                    end if
+                    allInExtRange = .true.
+                    do 11 j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes')
+                        do 12, d = 1, var_rank(i)
+                            index2(d) = index(d) + 
+     +                          (index2(d)-1) * stride(d)
+12                      continue
+                        value(j) = hash_int2(var_type(i),
+     +                                       var_rank(i), 
+     +                                       index2, NFT_INT2)
+                        val = value(j)
+                        allInExtRange = allInExtRange .and.
+     +                      inRange3(val, var_type(i), 
+     +                               NFT_INT2)
+11                  continue
+                    err = nf_put_varm_int2(ncid,i,index,count,
+     +                                   stride,imap,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (err .ne. 0)
+     +                          call error(nf_strerror(err))
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('range error: ', err)
+                        end if
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_int2(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed:', 
+     +          scratch)
+        end
+
+#endif
+        subroutine test_nf_put_varm_int()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        integer nels
+        integer nslabs
+        integer nstarts        !/* number of different starts */
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        integer imap(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* all values within external range? */
+        integer value(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_INT .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK))
+     +          stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS))
+     +          stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+                imap(j) = 1
+2           continue
+            err = nf_put_varm_int(BAD_ID, i, start,
+     +                           edge, stride, imap, 
+     +                           value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_varm_int(ncid, BAD_VARID, start,
+     +                           edge, stride, 
+     +                           imap, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .ne. RECDIM) then    !/* skip record dim */
+                    start(j) = var_shape(j,i) + 2
+                    err = nf_put_varm_int(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   imap, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EINVALCOORDS)
+     +                      call errore('bad start: ', err)
+                    endif
+                    start(j) = 1
+                    edge(j) = var_shape(j,i) + 1
+                    err = nf_put_varm_int(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   imap, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EEDGE)
+     +                      call errore('bad edge: ', err)
+                    endif
+                    edge(j) = 1
+                    stride(j) = 0
+                    err = nf_put_varm_int(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   imap, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_ESTRIDE)
+     +                      call errore('bad stride: ', err)
+                    endif
+                    stride(j) = 1
+                end if
+3           continue
+                !/* Choose a random point dividing each dim into 2 parts */
+                !/* Put 2^rank (nslabs) slabs so defined */
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+                !/* bits of k determine whether to put lower or upper part of dim */
+                !/* choose random stride from 1 to edge */
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        stride(j) = 1+roll(edge(j))
+                    else
+                        stride(j) = 1
+                    end if
+                    sstride(j) = stride(j)
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+                        !/* Random choice of forward or backward */
+C/* TODO
+C                   if ( roll(2) ) then
+C                       do 9, j = 1, var_rank(i)
+C                           index(j) = index(j) + 
+C     +                         (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C9                      continue
+C                   end if
+C*/
+                    if (var_rank(i) .gt. 0) then
+                        imap(1) = 1
+                        do 10, j = 2, var_rank(i)
+                            imap(j) = imap(j-1) * count(j-1)
+10                      continue
+                    end if
+                    allInExtRange = .true.
+                    do 11 j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes')
+                        do 12, d = 1, var_rank(i)
+                            index2(d) = index(d) + 
+     +                          (index2(d)-1) * stride(d)
+12                      continue
+                        value(j) = hash_int(var_type(i),
+     +                                       var_rank(i), 
+     +                                       index2, NFT_INT)
+                        val = value(j)
+                        allInExtRange = allInExtRange .and.
+     +                      inRange3(val, var_type(i), 
+     +                               NFT_INT)
+11                  continue
+                    err = nf_put_varm_int(ncid,i,index,count,
+     +                                   stride,imap,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (err .ne. 0)
+     +                          call error(nf_strerror(err))
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('range error: ', err)
+                        end if
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_int(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed:', 
+     +          scratch)
+        end
+
+        subroutine test_nf_put_varm_real()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        integer nels
+        integer nslabs
+        integer nstarts        !/* number of different starts */
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        integer imap(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* all values within external range? */
+        real value(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_REAL .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK))
+     +          stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS))
+     +          stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+                imap(j) = 1
+2           continue
+            err = nf_put_varm_real(BAD_ID, i, start,
+     +                           edge, stride, imap, 
+     +                           value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_varm_real(ncid, BAD_VARID, start,
+     +                           edge, stride, 
+     +                           imap, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .ne. RECDIM) then    !/* skip record dim */
+                    start(j) = var_shape(j,i) + 2
+                    err = nf_put_varm_real(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   imap, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EINVALCOORDS)
+     +                      call errore('bad start: ', err)
+                    endif
+                    start(j) = 1
+                    edge(j) = var_shape(j,i) + 1
+                    err = nf_put_varm_real(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   imap, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EEDGE)
+     +                      call errore('bad edge: ', err)
+                    endif
+                    edge(j) = 1
+                    stride(j) = 0
+                    err = nf_put_varm_real(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   imap, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_ESTRIDE)
+     +                      call errore('bad stride: ', err)
+                    endif
+                    stride(j) = 1
+                end if
+3           continue
+                !/* Choose a random point dividing each dim into 2 parts */
+                !/* Put 2^rank (nslabs) slabs so defined */
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+                !/* bits of k determine whether to put lower or upper part of dim */
+                !/* choose random stride from 1 to edge */
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        stride(j) = 1+roll(edge(j))
+                    else
+                        stride(j) = 1
+                    end if
+                    sstride(j) = stride(j)
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+                        !/* Random choice of forward or backward */
+C/* TODO
+C                   if ( roll(2) ) then
+C                       do 9, j = 1, var_rank(i)
+C                           index(j) = index(j) + 
+C     +                         (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C9                      continue
+C                   end if
+C*/
+                    if (var_rank(i) .gt. 0) then
+                        imap(1) = 1
+                        do 10, j = 2, var_rank(i)
+                            imap(j) = imap(j-1) * count(j-1)
+10                      continue
+                    end if
+                    allInExtRange = .true.
+                    do 11 j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes')
+                        do 12, d = 1, var_rank(i)
+                            index2(d) = index(d) + 
+     +                          (index2(d)-1) * stride(d)
+12                      continue
+                        value(j) = hash_real(var_type(i),
+     +                                       var_rank(i), 
+     +                                       index2, NFT_REAL)
+                        val = value(j)
+                        allInExtRange = allInExtRange .and.
+     +                      inRange3(val, var_type(i), 
+     +                               NFT_REAL)
+11                  continue
+                    err = nf_put_varm_real(ncid,i,index,count,
+     +                                   stride,imap,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (err .ne. 0)
+     +                          call error(nf_strerror(err))
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('range error: ', err)
+                        end if
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_real(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed:', 
+     +          scratch)
+        end
+
+        subroutine test_nf_put_varm_double()
+        use tests
+        implicit        none
+        integer ncid
+        integer d
+        integer i
+        integer j
+        integer k
+        integer m
+        integer err
+        integer nels
+        integer nslabs
+        integer nstarts        !/* number of different starts */
+        integer start(MAX_RANK)
+        integer edge(MAX_RANK)
+        integer index(MAX_RANK)
+        integer index2(MAX_RANK)
+        integer mid(MAX_RANK)
+        integer count(MAX_RANK)
+        integer sstride(MAX_RANK)
+        integer stride(MAX_RANK)
+        integer imap(MAX_RANK)
+        logical canConvert      !/* Both text or both numeric */
+        logical allInExtRange   !/* all values within external range? */
+        doubleprecision value(MAX_NELS)
+        doubleprecision val
+        integer udshift
+
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 1, i = 1, NVARS
+            canConvert = (var_type(i) .eq. NF_CHAR) .eqv.
+     +                   (NFT_DOUBLE .eq. NFT_TEXT)
+            if (.not.(var_rank(i) .le. MAX_RANK))
+     +          stop 2
+            if (.not.(var_nels(i) .le. MAX_NELS))
+     +          stop 2
+            do 2, j = 1, var_rank(i)
+                start(j) = 1
+                edge(j) = 1
+                stride(j) = 1
+                imap(j) = 1
+2           continue
+            err = nf_put_varm_double(BAD_ID, i, start,
+     +                           edge, stride, imap, 
+     +                           value)
+            if (err .ne. NF_EBADID) 
+     +          call errore('bad ncid: ', err)
+            err = nf_put_varm_double(ncid, BAD_VARID, start,
+     +                           edge, stride, 
+     +                           imap, value)
+            if (err .ne. NF_ENOTVAR) 
+     +          call errore('bad var id: ', err)
+            do 3, j = 1, var_rank(i)
+                if (var_dimid(j,i) .ne. RECDIM) then    !/* skip record dim */
+                    start(j) = var_shape(j,i) + 2
+                    err = nf_put_varm_double(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   imap, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EINVALCOORDS)
+     +                      call errore('bad start: ', err)
+                    endif
+                    start(j) = 1
+                    edge(j) = var_shape(j,i) + 1
+                    err = nf_put_varm_double(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   imap, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_EEDGE)
+     +                      call errore('bad edge: ', err)
+                    endif
+                    edge(j) = 1
+                    stride(j) = 0
+                    err = nf_put_varm_double(ncid, i, start,
+     +                                   edge, stride, 
+     +                                   imap, value)
+                    if (.not. canConvert) then
+                        if (err .ne. NF_ECHAR)
+     +                      call errore('conversion: ', err)
+                    else
+                        if (err .ne. NF_ESTRIDE)
+     +                      call errore('bad stride: ', err)
+                    endif
+                    stride(j) = 1
+                end if
+3           continue
+                !/* Choose a random point dividing each dim into 2 parts */
+                !/* Put 2^rank (nslabs) slabs so defined */
+            nslabs = 1
+            do 4, j = 1, var_rank(i)
+                mid(j) = roll( var_shape(j,i) )
+                nslabs = nslabs * 2
+4           continue
+                !/* bits of k determine whether to put lower or upper part of dim */
+                !/* choose random stride from 1 to edge */
+            do 5, k = 1, nslabs
+                nstarts = 1
+                do 6, j = 1, var_rank(i)
+                    if (mod(udshift(k-1, -(j-1)), 2) .eq. 1) then
+                        start(j) = 1
+                        edge(j) = mid(j)
+                    else
+                        start(j) = 1 + mid(j)
+                        edge(j) = var_shape(j,i) - mid(j)
+                    end if
+                    if (edge(j) .gt. 0) then
+                        stride(j) = 1+roll(edge(j))
+                    else
+                        stride(j) = 1
+                    end if
+                    sstride(j) = stride(j)
+                    nstarts = nstarts * stride(j)
+6               continue
+                do 7, m = 1, nstarts
+                    err = index2indexes(m, var_rank(i), sstride, index)
+                    if (err .ne. 0)
+     +                  call error('error in index2indexes')
+                    nels = 1
+                    do 8, j = 1, var_rank(i)
+                        count(j) = 1 + (edge(j) - index(j)) / stride(j)
+                        nels = nels * count(j)
+                        index(j) = index(j) + start(j) - 1
+8                   continue
+                        !/* Random choice of forward or backward */
+C/* TODO
+C                   if ( roll(2) ) then
+C                       do 9, j = 1, var_rank(i)
+C                           index(j) = index(j) + 
+C     +                         (count(j) - 1) * stride(j)
+C                           stride(j) = -stride(j)
+C9                      continue
+C                   end if
+C*/
+                    if (var_rank(i) .gt. 0) then
+                        imap(1) = 1
+                        do 10, j = 2, var_rank(i)
+                            imap(j) = imap(j-1) * count(j-1)
+10                      continue
+                    end if
+                    allInExtRange = .true.
+                    do 11 j = 1, nels
+                        err = index2indexes(j, var_rank(i), count, 
+     +                                      index2)
+                        if (err .ne. 0)
+     +                      call error('error in index2indexes')
+                        do 12, d = 1, var_rank(i)
+                            index2(d) = index(d) + 
+     +                          (index2(d)-1) * stride(d)
+12                      continue
+                        value(j) = hash_double(var_type(i),
+     +                                       var_rank(i), 
+     +                                       index2, NFT_DOUBLE)
+                        val = value(j)
+                        allInExtRange = allInExtRange .and.
+     +                      inRange3(val, var_type(i), 
+     +                               NFT_DOUBLE)
+11                  continue
+                    err = nf_put_varm_double(ncid,i,index,count,
+     +                                   stride,imap,
+     +                                   value)
+                    if (canConvert) then
+                        if (allInExtRange) then
+                            if (err .ne. 0)
+     +                          call error(nf_strerror(err))
+                        else
+                            if (err .ne. NF_ERANGE)
+     +                          call errore('range error: ', err)
+                        end if
+                    else
+                        if (nels .gt. 0 .and. err .ne. NF_ECHAR)
+     +                      call errore('wrong type: ', err)
+                    end if
+7               continue
+5           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+        call check_vars_double(scratch)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed:', 
+     +          scratch)
+        end
+
+
+        subroutine test_nf_put_att_text()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer k
+        integer err
+        character       value(MAX_NELS)
+
+        err = nf_create(scratch, NF_NOCLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('NF_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+
+        do 1, i = 0, NVARS
+            do 2, j = 1, NATTS(i)
+                if (ATT_TYPE(j,i) .eq. NF_CHAR) then
+                    if (.not.(ATT_LEN(j,i) .le. MAX_NELS))
+     +                  stop 2
+                    err = nf_put_att_text(BAD_ID, i,
+     +                  ATT_NAME(j,i), ATT_LEN(j,i), value)
+                    if (err .ne. NF_EBADID)
+     +                  call errore('bad ncid: ', err)
+                    err = nf_put_att_text(ncid, BAD_VARID, 
+     +                                    ATT_NAME(j,i), 
+     +                                    ATT_LEN(j,i), value)
+                    if (err .ne. NF_ENOTVAR)
+     +                  call errore('bad var id: ', err)
+                    do 3, k = 1, ATT_LEN(j,i)
+                        value(k) = char(int(hash(ATT_TYPE(j,i), -1, k)))
+3                   continue
+                    err = nf_put_att_text(ncid, i, ATT_NAME(j,i), 
+     +                  ATT_LEN(j,i), value)
+                    if (err .ne. 0)
+     +                  call error(NF_strerror(err))
+                end if
+2           continue
+1       continue
+
+        call check_atts_text(ncid)
+        err = NF_close(ncid)
+        if (err .ne. 0)
+     +      call errore('NF_close: ', err)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed:', 
+     +          scratch)
+        end
+
+#ifdef NF_INT1_T
+        subroutine test_nf_put_att_int1()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer k
+        integer ndx(1)
+        integer err
+        NF_INT1_T value(MAX_NELS)
+        logical allInExtRange  !/* all values within external range? */
+        doubleprecision val
+
+        err = nf_create(scratch, NF_NOCLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+
+        do 1, i = 0, NVARS
+            do 2, j = 1, NATTS(i)
+                if (.not.(ATT_TYPE(j,i) .eq. NF_CHAR)) then
+                    if (.not.((ATT_LEN(j,i) .le. MAX_NELS)))
+     +                  stop 2
+                    err = nf_put_att_int1(BAD_ID, i,
+     +                                  ATT_NAME(j,i), 
+     +                                  ATT_TYPE(j,i), 
+     +                                  ATT_LEN(j,i), value)
+                    if (err .ne. NF_EBADID)
+     +                  call errore('bad ncid: ', err)
+                    err = nf_put_att_int1(ncid, BAD_VARID,
+     +                  ATT_NAME(j,i), 
+     +                  ATT_TYPE(j,i), ATT_LEN(j,i), value)
+                    if (err .ne. NF_ENOTVAR)
+     +                  call errore('bad var id: ', err)
+                    err = nf_put_att_int1(ncid, i,
+     +                  ATT_NAME(j,i), BAD_TYPE, 
+     +                  ATT_LEN(j,i), value)
+                    if (err .ne. NF_EBADTYPE)
+     +                  call errore('bad type: ', err)
+                    allInExtRange = .true.
+                    do 3, k = 1, ATT_LEN(j,i)
+                        ndx(1) = k
+                        value(k) = hash_int1(ATT_TYPE(j,i), -1, ndx, 
+     +                                     NFT_INT1)
+                        val = value(k)
+                        allInExtRange = allInExtRange .and.
+     +                      inRange3(val, ATT_TYPE(j,i), 
+     +                               NFT_INT1)
+3                   continue
+                    err = nf_put_att_int1(ncid, i, ATT_NAME(j,i), 
+     +                                  ATT_TYPE(j,i), ATT_LEN(j,i), 
+     +                                  value)
+                    if (allInExtRange) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('range error: ', err)
+                    end if
+                end if
+2           continue
+1       continue
+
+        call check_atts_int1(ncid)
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed:', 
+     +          scratch)
+        end
+
+#endif
+#ifdef NF_INT2_T
+        subroutine test_nf_put_att_int2()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer k
+        integer ndx(1)
+        integer err
+        NF_INT2_T value(MAX_NELS)
+        logical allInExtRange  !/* all values within external range? */
+        doubleprecision val
+
+        err = nf_create(scratch, NF_NOCLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+
+        do 1, i = 0, NVARS
+            do 2, j = 1, NATTS(i)
+                if (.not.(ATT_TYPE(j,i) .eq. NF_CHAR)) then
+                    if (.not.((ATT_LEN(j,i) .le. MAX_NELS)))
+     +                  stop 2
+                    err = nf_put_att_int2(BAD_ID, i,
+     +                                  ATT_NAME(j,i), 
+     +                                  ATT_TYPE(j,i), 
+     +                                  ATT_LEN(j,i), value)
+                    if (err .ne. NF_EBADID)
+     +                  call errore('bad ncid: ', err)
+                    err = nf_put_att_int2(ncid, BAD_VARID,
+     +                  ATT_NAME(j,i), 
+     +                  ATT_TYPE(j,i), ATT_LEN(j,i), value)
+                    if (err .ne. NF_ENOTVAR)
+     +                  call errore('bad var id: ', err)
+                    err = nf_put_att_int2(ncid, i,
+     +                  ATT_NAME(j,i), BAD_TYPE, 
+     +                  ATT_LEN(j,i), value)
+                    if (err .ne. NF_EBADTYPE)
+     +                  call errore('bad type: ', err)
+                    allInExtRange = .true.
+                    do 3, k = 1, ATT_LEN(j,i)
+                        ndx(1) = k
+                        value(k) = hash_int2(ATT_TYPE(j,i), -1, ndx, 
+     +                                     NFT_INT2)
+                        val = value(k)
+                        allInExtRange = allInExtRange .and.
+     +                      inRange3(val, ATT_TYPE(j,i), 
+     +                               NFT_INT2)
+3                   continue
+                    err = nf_put_att_int2(ncid, i, ATT_NAME(j,i), 
+     +                                  ATT_TYPE(j,i), ATT_LEN(j,i), 
+     +                                  value)
+                    if (allInExtRange) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('range error: ', err)
+                    end if
+                end if
+2           continue
+1       continue
+
+        call check_atts_int2(ncid)
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed:', 
+     +          scratch)
+        end
+
+#endif
+        subroutine test_nf_put_att_int()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer k
+        integer ndx(1)
+        integer err
+        integer value(MAX_NELS)
+        logical allInExtRange  !/* all values within external range? */
+        doubleprecision val
+
+        err = nf_create(scratch, NF_NOCLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+
+        do 1, i = 0, NVARS
+            do 2, j = 1, NATTS(i)
+                if (.not.(ATT_TYPE(j,i) .eq. NF_CHAR)) then
+                    if (.not.((ATT_LEN(j,i) .le. MAX_NELS)))
+     +                  stop 2
+                    err = nf_put_att_int(BAD_ID, i,
+     +                                  ATT_NAME(j,i), 
+     +                                  ATT_TYPE(j,i), 
+     +                                  ATT_LEN(j,i), value)
+                    if (err .ne. NF_EBADID)
+     +                  call errore('bad ncid: ', err)
+                    err = nf_put_att_int(ncid, BAD_VARID,
+     +                  ATT_NAME(j,i), 
+     +                  ATT_TYPE(j,i), ATT_LEN(j,i), value)
+                    if (err .ne. NF_ENOTVAR)
+     +                  call errore('bad var id: ', err)
+                    err = nf_put_att_int(ncid, i,
+     +                  ATT_NAME(j,i), BAD_TYPE, 
+     +                  ATT_LEN(j,i), value)
+                    if (err .ne. NF_EBADTYPE)
+     +                  call errore('bad type: ', err)
+                    allInExtRange = .true.
+                    do 3, k = 1, ATT_LEN(j,i)
+                        ndx(1) = k
+                        value(k) = hash_int(ATT_TYPE(j,i), -1, ndx, 
+     +                                     NFT_INT)
+                        val = value(k)
+                        allInExtRange = allInExtRange .and.
+     +                      inRange3(val, ATT_TYPE(j,i), 
+     +                               NFT_INT)
+3                   continue
+                    err = nf_put_att_int(ncid, i, ATT_NAME(j,i), 
+     +                                  ATT_TYPE(j,i), ATT_LEN(j,i), 
+     +                                  value)
+                    if (allInExtRange) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('range error: ', err)
+                    end if
+                end if
+2           continue
+1       continue
+
+        call check_atts_int(ncid)
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed:', 
+     +          scratch)
+        end
+
+        subroutine test_nf_put_att_real()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer k
+        integer ndx(1)
+        integer err
+        real value(MAX_NELS)
+        logical allInExtRange  !/* all values within external range? */
+        doubleprecision val
+
+        err = nf_create(scratch, NF_NOCLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+
+        do 1, i = 0, NVARS
+            do 2, j = 1, NATTS(i)
+                if (.not.(ATT_TYPE(j,i) .eq. NF_CHAR)) then
+                    if (.not.((ATT_LEN(j,i) .le. MAX_NELS)))
+     +                  stop 2
+                    err = nf_put_att_real(BAD_ID, i,
+     +                                  ATT_NAME(j,i), 
+     +                                  ATT_TYPE(j,i), 
+     +                                  ATT_LEN(j,i), value)
+                    if (err .ne. NF_EBADID)
+     +                  call errore('bad ncid: ', err)
+                    err = nf_put_att_real(ncid, BAD_VARID,
+     +                  ATT_NAME(j,i), 
+     +                  ATT_TYPE(j,i), ATT_LEN(j,i), value)
+                    if (err .ne. NF_ENOTVAR)
+     +                  call errore('bad var id: ', err)
+                    err = nf_put_att_real(ncid, i,
+     +                  ATT_NAME(j,i), BAD_TYPE, 
+     +                  ATT_LEN(j,i), value)
+                    if (err .ne. NF_EBADTYPE)
+     +                  call errore('bad type: ', err)
+                    allInExtRange = .true.
+                    do 3, k = 1, ATT_LEN(j,i)
+                        ndx(1) = k
+                        value(k) = hash_real(ATT_TYPE(j,i), -1, ndx, 
+     +                                     NFT_REAL)
+                        val = value(k)
+                        allInExtRange = allInExtRange .and.
+     +                      inRange3(val, ATT_TYPE(j,i), 
+     +                               NFT_REAL)
+3                   continue
+                    err = nf_put_att_real(ncid, i, ATT_NAME(j,i), 
+     +                                  ATT_TYPE(j,i), ATT_LEN(j,i), 
+     +                                  value)
+                    if (allInExtRange) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('range error: ', err)
+                    end if
+                end if
+2           continue
+1       continue
+
+        call check_atts_real(ncid)
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed:', 
+     +          scratch)
+        end
+
+        subroutine test_nf_put_att_double()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer k
+        integer ndx(1)
+        integer err
+        doubleprecision value(MAX_NELS)
+        logical allInExtRange  !/* all values within external range? */
+        doubleprecision val
+
+        err = nf_create(scratch, NF_NOCLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+
+        do 1, i = 0, NVARS
+            do 2, j = 1, NATTS(i)
+                if (.not.(ATT_TYPE(j,i) .eq. NF_CHAR)) then
+                    if (.not.((ATT_LEN(j,i) .le. MAX_NELS)))
+     +                  stop 2
+                    err = nf_put_att_double(BAD_ID, i,
+     +                                  ATT_NAME(j,i), 
+     +                                  ATT_TYPE(j,i), 
+     +                                  ATT_LEN(j,i), value)
+                    if (err .ne. NF_EBADID)
+     +                  call errore('bad ncid: ', err)
+                    err = nf_put_att_double(ncid, BAD_VARID,
+     +                  ATT_NAME(j,i), 
+     +                  ATT_TYPE(j,i), ATT_LEN(j,i), value)
+                    if (err .ne. NF_ENOTVAR)
+     +                  call errore('bad var id: ', err)
+                    err = nf_put_att_double(ncid, i,
+     +                  ATT_NAME(j,i), BAD_TYPE, 
+     +                  ATT_LEN(j,i), value)
+                    if (err .ne. NF_EBADTYPE)
+     +                  call errore('bad type: ', err)
+                    allInExtRange = .true.
+                    do 3, k = 1, ATT_LEN(j,i)
+                        ndx(1) = k
+                        value(k) = hash_double(ATT_TYPE(j,i), -1, ndx, 
+     +                                     NFT_DOUBLE)
+                        val = value(k)
+                        allInExtRange = allInExtRange .and.
+     +                      inRange3(val, ATT_TYPE(j,i), 
+     +                               NFT_DOUBLE)
+3                   continue
+                    err = nf_put_att_double(ncid, i, ATT_NAME(j,i), 
+     +                                  ATT_TYPE(j,i), ATT_LEN(j,i), 
+     +                                  value)
+                    if (allInExtRange) then
+                        if (err .ne. 0)
+     +                      call error(nf_strerror(err))
+                    else
+                        if (err .ne. NF_ERANGE)
+     +                      call errore('range error: ', err)
+                    end if
+                end if
+2           continue
+1       continue
+
+        call check_atts_double(ncid)
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed:', 
+     +          scratch)
+        end
+
diff --git a/nf_test/test03_read.F b/nf_test/test03_read.F
new file mode 100755
index 0000000..152694d
--- /dev/null
+++ b/nf_test/test03_read.F
@@ -0,0 +1,1069 @@
+C*********************************************************************
+C   Copyright 1996, UCAR/Unidata
+C   See netcdf/COPYRIGHT file for copying and redistribution conditions.
+C   $Id: test_read.F,v 1.13 2006/09/25 20:09:26 ed Exp $
+C*********************************************************************
+
+C Test nf_strerror.
+C    Try on a bad error status.
+C    Test for each defined error status.
+C
+        subroutine test_nf_strerror()
+        use tests
+        implicit        none
+        integer         number_of_messages
+        parameter       (number_of_messages = 27)
+
+        integer         i
+        integer         status(number_of_messages)
+        character*80    message
+        character*80    msg(number_of_messages)
+
+        data    status(1)  / NF_NOERR/
+        data    status(2)  / NF_EBADID /
+        data    status(3)  / NF_EEXIST /
+        data    status(4)  / NF_EINVAL /
+        data    status(5)  / NF_EPERM /
+        data    status(6)  / NF_ENOTINDEFINE /
+        data    status(7)  / NF_EINDEFINE /
+        data    status(8)  / NF_EINVALCOORDS /
+        data    status(9)  / NF_EMAXDIMS /
+        data    status(10) / NF_ENAMEINUSE /
+        data    status(11) / NF_ENOTATT /
+        data    status(12) / NF_EMAXATTS /
+        data    status(13) / NF_EBADTYPE /
+        data    status(14) / NF_EBADDIM /
+        data    status(15) / NF_EUNLIMPOS /
+        data    status(16) / NF_EMAXVARS /
+        data    status(17) / NF_ENOTVAR /
+        data    status(18) / NF_EGLOBAL /
+        data    status(19) / NF_ENOTNC /
+        data    status(20) / NF_ESTS /
+        data    status(21) / NF_EMAXNAME /
+        data    status(22) / NF_EUNLIMIT /
+        data    status(23) / NF_ENORECVARS /
+        data    status(24) / NF_ECHAR /
+        data    status(25) / NF_EEDGE /
+        data    status(26) / NF_ESTRIDE /
+        data    status(27) / NF_EBADNAME /
+
+        data msg(1)  / 'No error' /
+        data msg(2)  / 'NetCDF: Not a valid ID' /
+        data msg(3)  / 'NetCDF: File exists && NC_NOCLOBBER' /
+        data msg(4)  / 'NetCDF: Invalid argument' /
+        data msg(5)  / 'NetCDF: Write to read only' /
+        data msg(6)  / 'NetCDF: Operation not allowed in data mode' /
+        data msg(7)  / 'NetCDF: Operation not allowed in define mode' /
+        data msg(8)  / 'NetCDF: Index exceeds dimension bound' /
+        data msg(9)  / 'NetCDF: NC_MAX_DIMS exceeded' /
+        data msg(10) / 'NetCDF: String match to name in use' /
+        data msg(11) / 'NetCDF: Attribute not found' /
+        data msg(12) / 'NetCDF: NC_MAX_ATTRS exceeded' /
+        data msg(13)
+     +  / 'NetCDF: Not a valid data type or _FillValue type mismatch' /
+        data msg(14) / 'NetCDF: Invalid dimension ID or name' /
+        data msg(15) / 'NetCDF: NC_UNLIMITED in the wrong index' /
+        data msg(16) / 'NetCDF: NC_MAX_VARS exceeded' /
+        data msg(17) / 'NetCDF: Variable not found' /
+        data msg(18) / 'NetCDF: Action prohibited on NC_GLOBAL varid' /
+        data msg(19) / 'NetCDF: Unknown file format' /
+        data msg(20) / 'NetCDF: In Fortran, string too short' /
+        data msg(21) / 'NetCDF: NC_MAX_NAME exceeded' /
+        data msg(22) / 'NetCDF: NC_UNLIMITED size already in use' /
+        data msg(23) 
+     +  / 'NetCDF: nc_rec op when there are no record vars' /
+        data msg(24) 
+     +  /'NetCDF: Attempt to convert between text & numbers'/
+        data msg(25) / 'NetCDF: Start+count exceeds dimension bound' /
+        data msg(26) / 'NetCDF: Illegal stride' /
+        data msg(27) / 'NetCDF: Name contains illegal characters' /
+
+C       /* Try on a bad error status */
+        message = nf_strerror(-666)!/* should fail */
+        if (message .ne. 'Unknown Error')
+     +      call errorc('nf_strerror on bad error status returned: ',
+     +          message)
+
+C       /* Try on each legitimate error status */
+        do 1, i=1, number_of_messages
+            message = nf_strerror(status(i))
+            if (message .ne. msg(i))
+     +          call error('nf_strerror() should return "' // msg(i) //
+     +                     '"')
+1       continue
+        end
+
+
+C Test nf_open.
+C If in read-only section of tests,
+C    Try to open a non-existent netCDF file, check error return.
+C    Open a file that is not a netCDF file, check error return.
+C    Open a netCDF file with a bad mode argument, check error return.
+C    Open a netCDF file with NF_NOWRITE mode, try to write, check error.
+C    Try to open a netcdf twice, check whether returned netcdf ids different.
+C If in writable section of tests,
+C    Open a netCDF file with NF_WRITE mode, write something, close it.
+C On exit, any open netCDF files are closed.
+        subroutine test_nf_open()
+        use tests
+        implicit        none
+        integer err
+        integer ncid
+        integer ncid2
+        character TEMPFILE*8
+        integer unit51
+C       /* Create a non-netCDF file named 'temp.tmp' */
+        unit51 = 51
+        TEMPFILE = 'temp.tmp'
+        OPEN(unit51, FILE=TEMPFILE)
+        WRITE(51,*) 'text'
+        CLOSE(51)
+
+C       /* Try to open a nonexistent file */
+        err = nf_open('tooth-fairy.nc', NF_NOWRITE, ncid)!/* should fail */
+        if (err .eq. NF_NOERR)
+     +      call error('nf_open of nonexistent file should have failed')
+        if (.not. NF_ISSYSERR(err))
+     +      call error(
+     +  'nf_open of nonexistent file should have returned system error')
+
+C       /* Open a file that is not a netCDF file. */
+        err = nf_open(TEMPFILE, NF_NOWRITE, ncid)!/* should fail */
+        if (err .ne. NF_ENOTNC)
+     +      call errore('nf_open of non-netCDF file: ', err)
+
+C       /* Open a netCDF file in read-only mode, check that write fails */
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        err = nf_redef(ncid)    !/* should fail */
+        if (err .ne. NF_EPERM)
+     +      call error('nf_redef of read-only file should fail')
+C       /* Opened OK, see if can open again and get a different netCDF ID */
+        err = nf_open(testfile, NF_NOWRITE, ncid2)
+        if (err .ne. 0) then
+            call errore('nf_open: ', err)
+        else
+            err = nf_close(ncid2)
+        end if
+        if (ncid2 .eq. ncid)
+     +      call error(
+     +  'netCDF IDs for first and second nf_open calls should differ')
+
+        if (.not. readonly) then        !/* tests using netCDF scratch file */
+            err = nf_create(scratch, NF_NOCLOBBER, ncid2)
+            if (err .ne. 0) then
+                call errore('nf_create: ', err)
+            else 
+                err = nf_close(ncid2)
+            end if
+            err = nf_open(scratch, NF_WRITE, ncid2)
+            if (err .ne. 0) then
+                call errore('nf_open: ', err)
+            else 
+                err = nf_close(ncid2)
+            end if
+            err = nf_delete(scratch)
+            if (err .ne. 0) 
+     +          call errorc('delete of scratch file failed', scratch)
+        end if
+
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
+
+
+C 
+C Test nf_close.
+C    Try to close a netCDF file twice, check whether second close fails.
+C    Try on bad handle, check error return.
+C    Try in define mode and data mode.
+C/
+        subroutine test_nf_close()
+        use tests
+        implicit        none
+        integer ncid
+        integer err
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+
+C       /* Close a netCDF file twice, second time should fail */
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close failed: ', err)
+        err = nf_close(ncid)
+        if (err .ne. NF_EBADID)
+     +      call error('nf_close of closed file should have failed')
+        
+C       /* Try with a bad netCDF ID */
+        err = nf_close(BAD_ID)!/* should fail */
+        if (err .ne. NF_EBADID)
+     +      call errore(
+     +          'nf_close with bad netCDF ID returned wrong error: ', 
+     +          err)
+
+C       /* Close in data mode */
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close in data mode failed: ', err)
+
+        if (.not. readonly) then        !/* tests using netCDF scratch file */
+            err = nf_create(scratch, NF_NOCLOBBER, ncid)
+            if (err .ne. 0) 
+     +          call errore('nf_create: ', err)
+            err = nf_close(ncid)
+            if (err .ne. 0)
+     +          call errore('nf_close in define mode: ', err)
+            err = nf_delete(scratch)
+            if (err .ne. 0)
+     +          call errorc('delete of scratch file failed: ', 
+     +              scratch)
+        end if
+        end
+
+
+C Test nf_inq.
+C    Try on bad handle, check error return.
+C    Try in data mode, check returned values.
+C    Try asking for subsets of info.
+C If in writable section of tests,
+C    Try in define mode, after adding an unlimited dimension, variable.
+C On exit, any open netCDF files are closed.
+        subroutine test_nf_inq()
+        use tests, NDIMSG=>NDIMS, NGATTSG=>NGATTS, NVARSG=>NVARS,       &
+     &             RECDIMG=>RECDIM
+        implicit        none
+        integer ncid
+        integer ncid2                   !/* for scratch netCDF dataset */
+        integer ndims                   !/* number of dimensions */
+        integer nvars                   !/* number of variables */
+        integer ngatts                  !/* number of global attributes */
+        integer recdim                  !/* id of unlimited dimension */
+        integer err
+        integer ndims0
+        integer nvars0
+        integer ngatts0
+        integer recdim0
+        integer did
+        integer vid
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        
+C       /* Try on bad handle */
+        err = nf_inq(BAD_ID, ndims, nvars, ngatts, recdim)
+        if (err .ne. NF_EBADID)
+     +      call errore('bad ncid: ', err)
+        
+        err = nf_inq(ncid, ndims, nvars, ngatts, recdim)
+        if (err .ne. 0) then
+            call errore('nf_inq: ', err)
+        else if (ndims .ne. NDIMS) then
+            call errori('nf_inq: wrong number of dimensions returned: ',
+     +                  ndims)
+        else if (nvars .ne. NVARS) then
+            call errori('nf_inq: wrong number of variables returned: ',
+     +                  nvars)
+        else if (ngatts .ne. NGATTS) then
+            call errori(
+     +          'nf_inq: wrong number of global atts returned: ',
+     +          ngatts)
+        else if (recdim .ne. RECDIM) then
+            call errori('nf_inq: wrong record dimension ID returned: ',
+     +                  recdim)
+        end if
+
+        if (.not. readonly) then        !/* tests using netCDF scratch file */
+            err = nf_create(scratch, NF_NOCLOBBER, ncid2)
+            if (err .ne. 0) then
+                call errore('nf_create: ', err)
+            else                !/* add dim, var, gatt, check inq */
+                err = nf_enddef(ncid2) !/* enter data mode */
+                err = nf_inq(ncid2, ndims0, nvars0, ngatts0, recdim0)
+                if (err .ne. 0)
+     +              call errore('nf_inq: ', err)
+                err = nf_redef(ncid2) !/* enter define mode */
+C               /* Check that inquire still works in define mode */
+                err = nf_inq(ncid2, ndims, nvars, ngatts, recdim)
+                if (err .ne. 0) then
+                    call errore('nf_inq in define mode: ', err)
+                else if (ndims .ne. ndims0) then
+                    call errori('nf_inq in define mode: ndims wrong, ',
+     +                          ndims)
+                else if (nvars .ne. nvars0) then
+                    call errori('nf_inq in define mode: nvars wrong, ',
+     +                          nvars)
+                else if (ngatts .ne. ngatts0) then
+                    call errori(
+     +                  'nf_inq in define mode: ngatts wrong, ', ngatts)
+                else if (recdim .ne. recdim0) then
+                    call errori('nf_inq in define mode: recdim wrong, ',
+     +                          recdim)
+                end if
+
+C               /* Add dim, var, global att */
+                err = nf_def_dim(ncid2, 'inqd', 1, did)
+                if (err .ne. 0)
+     +              call errore('nf_def_dim: ', err)
+                err = nf_def_var(ncid2, 'inqv', NF_FLOAT, 0, (/0/), vid)
+                if (err .ne. 0)
+     +              call errore('nf_def_var: ', err)
+
+                err = nf_put_att_text(ncid2, NF_GLOBAL, 'inqa', 
+     +                                len('stuff'), 'stuff')
+                if (err .ne. 0)
+     +              call errore('nf_put_att_text: ', err)
+
+C               /* Make sure nf_inq sees the additions while in define mode */
+                err = nf_inq(ncid2, ndims, nvars, ngatts, recdim)
+                if (err .ne. 0) then
+                    call errore('nf_inq in define mode: ', err)
+                else if (ndims .ne. ndims0 + 1) then
+                    call errori('nf_inq in define mode: ndims wrong, ',
+     +                          ndims)
+                else if (nvars .ne. nvars0 + 1) then
+                    call errori('nf_inq in define mode: nvars wrong, ',
+     +                          nvars)
+                else if (ngatts .ne. ngatts0 + 1) then
+                    call errori('nf_inq in define mode: ngatts wrong, ',
+     +                          ngatts)
+                end if
+                err = nf_enddef(ncid2)
+                if (err .ne. 0)
+     +              call errore('nf_enddef: ', err)
+
+C               /* Make sure nf_inq stills sees additions in data mode */
+                err = nf_inq(ncid2, ndims, nvars, ngatts, recdim)
+                if (err .ne. 0) then
+                    call errore('nf_inq failed in data mode: ',err)
+                else if (ndims .ne. ndims0 + 1) then
+                    call errori('nf_inq in define mode: ndims wrong, ',
+     +                          ndims)
+                else if (nvars .ne. nvars0 + 1) then
+                    call errori('nf_inq in define mode: nvars wrong, ',
+     +                          nvars)
+                else if (ngatts .ne. ngatts0 + 1) then
+                    call errori('nf_inq in define mode: ngatts wrong, ',
+     +                          ngatts)
+                end if
+                err = nf_close(ncid2)
+                err = nf_delete(scratch)
+                if (err .ne. 0)
+     +              call errorc('delete of scratch file failed:', 
+     +                  scratch)
+            end if
+        end if
+
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
+
+
+        subroutine test_nf_inq_natts()
+        use tests, NDIMSG=>NDIMS, NGATTSG=>NGATTS
+        implicit        none
+        integer ncid
+        integer ngatts                  !/* number of global attributes */
+        integer err
+
+        err = nf_inq_natts(BAD_ID, ngatts)
+        if (err .ne. NF_EBADID)
+     +      call errore('bad ncid: ', err)
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        err = nf_inq_natts(ncid, ngatts)
+        if (err .ne. 0) then
+            call errore('nf_inq_natts: ', err)
+        else if (ngatts .ne. NGATTS) then
+            call errori(
+     +          'nf_inq_natts: wrong number of global atts returned, ',
+     +          ngatts)
+        end if
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
+
+
+        subroutine test_nf_inq_ndims()
+        use tests, NDIMSG=>NDIMS, NGATTSG=>NGATTS
+        implicit        none
+        integer ncid
+        integer ndims
+        integer err
+
+        err = nf_inq_ndims(BAD_ID, ndims)
+        if (err .ne. NF_EBADID)
+     +      call errore('bad ncid: ', err)
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        err = nf_inq_ndims(ncid, ndims)
+        if (err .ne. 0) then
+            call errore('nf_inq_ndims: ', err)
+        else if (ndims .ne. NDIMS) then
+            call errori('nf_inq_ndims: wrong number returned, ', ndims)
+        end if
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
+
+
+        subroutine test_nf_inq_nvars()
+        use tests, NVARSG=>NVARS
+        implicit        none
+        integer ncid
+        integer nvars
+        integer err
+
+        err = nf_inq_nvars(BAD_ID, nvars)
+        if (err .ne. NF_EBADID)
+     +      call errore('bad ncid: ', err)
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        err = nf_inq_nvars(ncid, nvars)
+        if (err .ne. 0) then
+            call errore('nf_inq_nvars: ', err)
+        else if (nvars .ne. NVARS) then
+            call errori('nf_inq_nvars: wrong number returned, ', nvars)
+        end if
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
+
+
+        subroutine test_nf_inq_unlimdim()
+        use tests
+        implicit        none
+        integer ncid
+        integer unlimdim
+        integer err
+
+        err = nf_inq_unlimdim(BAD_ID, unlimdim)
+        if (err .ne. NF_EBADID)
+     +      call errore('bad ncid: ', err)
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        err = nf_inq_unlimdim(ncid, unlimdim)
+        if (err .ne. 0) then
+            call errore('nf_inq_unlimdim: ', err)
+        else if (unlimdim .ne. RECDIM) then
+            call errori('nf_inq_unlimdim: wrong number returned, ', 
+     +                  unlimdim)
+        end if
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
+
+
+        subroutine test_nf_inq_format()
+        use tests
+        implicit        none
+        integer ncid
+        integer nformat
+        integer err
+
+        err = nf_inq_format(BAD_ID, nformat)
+        if (err .ne. NF_EBADID)
+     +      call errore('bad ncid: ', err)
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        err = nf_inq_format(ncid, nformat)
+        if (err .ne. 0) then
+            call errore('nf_inq_format: ', err)
+        else if (nformat .ne. nf_format_classic .and.
+     +           nformat .ne. nf_format_64bit) then
+            call errori('nf_inq_format: wrong format number returned, ', 
+     +                  nformat)
+        end if
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
+
+
+        subroutine test_nf_inq_dimid()
+        use tests
+        implicit        none
+        integer ncid
+        integer dimid
+        integer i
+        integer err
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        err = nf_inq_dimid(ncid, 'noSuch', dimid)
+        if (err .ne. NF_EBADDIM)
+     +      call errore('bad dim name: ', err)
+        do 1, i = 1, NDIMS
+            err = nf_inq_dimid(BAD_ID, dim_name(i), dimid)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_inq_dimid(ncid, dim_name(i), dimid)
+            if (err .ne. 0) then
+                call errore('nf_inq_dimid: ', err)
+            else if (dimid .ne. i) then
+                call errori('expected ', i)
+                call errori('got ', dimid)
+            end if
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
+
+
+        subroutine test_nf_inq_dim()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer err
+        character*(NF_MAX_NAME) name
+        integer length
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NDIMS
+            err = nf_inq_dim(BAD_ID, i, name, length)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_inq_dim(ncid, BAD_DIMID, name, length)
+            if (err .ne. NF_EBADDIM)
+     +          call errore('bad dimid: ', err)
+            err = nf_inq_dim(ncid, i, name, length)
+            if (err .ne. 0) then
+                call errore('nf_inq_dim: ', err)
+            else if (dim_name(i) .ne. name)  then
+                call errorc('name unexpected: ', name)
+            else if (dim_len(i) .ne. length) then
+                call errori('size unexpected: ', length)
+            end if
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
+
+
+        subroutine test_nf_inq_dimlen()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer err
+        integer length
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NDIMS
+            err = nf_inq_dimlen(BAD_ID, i, length)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_inq_dimlen(ncid, BAD_DIMID, length)
+            if (err .ne. NF_EBADDIM)
+     +          call errore('bad dimid: ', err)
+            err = nf_inq_dimlen(ncid, i, length)
+            if (err .ne. 0) then
+                call errore('nf_inq_dimlen: ', err)
+            else if (dim_len(i) .ne. length) then
+                call errori('size unexpected: ', length)
+            end if
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
+
+
+        subroutine test_nf_inq_dimname()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer err
+        character*(NF_MAX_NAME)  name
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NDIMS
+            err = nf_inq_dimname(BAD_ID, i, name)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_inq_dimname(ncid, BAD_DIMID, name)
+            if (err .ne. NF_EBADDIM)
+     +          call errore('bad dimid: ', err)
+            err = nf_inq_dimname(ncid, i, name)
+            if (err .ne. 0) then
+                call errore('nf_inq_dimname: ', err)
+            else if (dim_name(i) .ne. name)  then
+                call errorc('name unexpected: ', name)
+            end if
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
+
+
+        subroutine test_nf_inq_varid()
+        use tests
+        implicit        none
+        integer ncid
+        integer vid
+        integer i
+        integer err
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+
+        err = nf_inq_varid(ncid, 'noSuch', vid)
+        if (err .ne. NF_ENOTVAR)
+     +      call errore('bad ncid: ', err)
+
+        do 1, i = 1, NVARS
+            err = nf_inq_varid(BAD_ID, var_name(i), vid)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_inq_varid(ncid, var_name(i), vid)
+            if (err .ne. 0) then
+                call errore('nf_inq_varid: ', err)
+            else if (vid .ne. i) then
+                call errori('varid unexpected: ', vid)
+            endif
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
+
+
+        subroutine test_nf_inq_var()
+        use tests, NDIMSG=>NDIMS
+        implicit        none
+        integer ncid
+        integer i
+        integer err
+        character*(NF_MAX_NAME) name
+        integer datatype
+        integer ndims
+        integer dimids(MAX_RANK)
+        integer na
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            err = nf_inq_var(BAD_ID, i, name, datatype, ndims, dimids, 
+     +                       na)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_inq_var(ncid,BAD_VARID,name,datatype,ndims,dimids,
+     +                       na)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            err = nf_inq_var(ncid, i, name, datatype, ndims, dimids, 
+     +                       na)
+            if (err .ne. 0) then
+                call errore('nf_inq_var: ', err)
+            else if (var_name(i) .ne. name)  then
+                call errorc('name unexpected: ', name)
+            else if (var_type(i) .ne. datatype) then
+                call errori('type unexpected: ', datatype)
+            else if (var_rank(i) .ne. ndims) then
+                call errori('ndims expected: ', ndims)
+            else if (.not.int_vec_eq(var_dimid(1,i),dimids,ndims)) then
+                call error('unexpected dimid')
+            else if (var_natts(i) .ne. na) then
+                call errori('natts unexpected: ', na)
+            end if
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
+
+
+        subroutine test_nf_inq_vardimid()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer err
+        integer dimids(MAX_RANK)
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            err = nf_inq_vardimid(BAD_ID, i, dimids)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_inq_vardimid(ncid, BAD_VARID, dimids)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            err = nf_inq_vardimid(ncid, i, dimids)
+            if (err .ne. 0) then
+                call errore('nf_inq_vardimid: ', err)
+            else if (.not.int_vec_eq(var_dimid(1,i), dimids, 
+     +               var_rank(i))) then
+                call error('unexpected dimid')
+            end if
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
+
+
+        subroutine test_nf_inq_varname()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer err
+        character*(NF_MAX_NAME) name
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            err = nf_inq_varname(BAD_ID, i, name)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_inq_varname(ncid, BAD_VARID, name)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            err = nf_inq_varname(ncid, i, name)
+            if (err .ne. 0) then
+                call errore('nf_inq_varname: ', err)
+            else if (var_name(i) .ne. name)  then
+                call errorc('name unexpected: ', name)
+            end if
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
+
+
+        subroutine test_nf_inq_varnatts()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer err
+        integer na
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 0, NVARS	! start with global attributes
+            err = nf_inq_varnatts(BAD_ID, i, na)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_inq_varnatts(ncid, BAD_VARID, na)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            err = nf_inq_varnatts(ncid, VARID(i), na)
+            if (err .ne. 0) then
+                call errore('nf_inq_varnatts: ', err)
+            else if (NATTS(i) .ne. na) then	! works for global attributes
+                call errori('natts unexpected: ', na)
+            end if
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
+
+
+        subroutine test_nf_inq_varndims()
+        use tests, NDIMSG=>NDIMS
+        implicit        none
+        integer ncid
+        integer i
+        integer err
+        integer ndims
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            err = nf_inq_varndims(BAD_ID, i, ndims)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_inq_varndims(ncid, BAD_VARID, ndims)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            err = nf_inq_varndims(ncid, i, ndims)
+            if (err .ne. 0) then
+                call errore('nf_inq_varndims: ', err)
+            else if (var_rank(i) .ne. ndims) then
+                call errori('ndims unexpected: ', ndims)
+            end if
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
+
+
+        subroutine test_nf_inq_vartype()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer err
+        integer datatype
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 1, i = 1, NVARS
+            err = nf_inq_vartype(BAD_ID, i, datatype)
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_inq_vartype(ncid, BAD_VARID, datatype)
+            if (err .ne. NF_ENOTVAR)
+     +          call errore('bad var id: ', err)
+            err = nf_inq_vartype(ncid, i, datatype)
+            if (err .ne. 0) then
+                call errore('nf_inq_vartype: ', err)
+            else if (var_type(i) .ne. datatype) then
+                call errori('type unexpected: ', datatype)
+            end if
+1       continue
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
+
+
+        subroutine test_nf_inq_att()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        integer t
+        integer n
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_open: ', err)
+
+        do 1, i = 0, NVARS
+            do 2, j = 1, NATTS(i)
+                err = nf_inq_att(BAD_ID, i, ATT_NAME(j,i), t, n)
+                if (err .ne. NF_EBADID) 
+     +              call errore('bad ncid: ', err)
+                err = nf_inq_att(ncid, BAD_VARID, ATT_NAME(j,i), t, n)
+                if (err .ne. NF_ENOTVAR) 
+     +              call errore('bad var id: ', err)
+                err = nf_inq_att(ncid, i, 'noSuch', t, n)
+                if (err .ne. NF_ENOTATT) 
+     +              call errore('Bad attribute name: ', err)
+                err = nf_inq_att(ncid, i, ATT_NAME(j,i), t, n)
+                if (err .ne. 0) then
+                    call error(nf_strerror(err))
+                else
+                    if (t .ne. ATT_TYPE(j,i))
+     +                  call error('type not that expected')
+                    if (n .ne. ATT_LEN(j,i)) 
+     +                  call error('length not that expected')
+                end if
+2           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
+
+
+        subroutine test_nf_inq_attlen()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        integer len
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+
+        do 1, i = 0, NVARS
+            err = nf_inq_attlen(ncid, i, 'noSuch', len)
+            if (err .ne. NF_ENOTATT)
+     +          call errore('Bad attribute name: ', err)
+            do 2, j = 1, NATTS(i)
+                err = nf_inq_attlen(BAD_ID, i, ATT_NAME(j,i), len)
+                if (err .ne. NF_EBADID)
+     +              call errore('bad ncid: ', err)
+                err = nf_inq_attlen(ncid, BAD_VARID, ATT_NAME(j,i), len)
+                if (err .ne. NF_ENOTVAR)
+     +              call errore('bad varid: ', err)
+                err = nf_inq_attlen(ncid, i, ATT_NAME(j,i), len)
+                if (err .ne. 0) then
+                    call error(nf_strerror(err))
+                else
+                    if (len .ne. ATT_LEN(j,i))
+     +                  call error('len not that expected')
+                end if
+2           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
+
+
+        subroutine test_nf_inq_atttype()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        integer datatype
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+
+        do 1, i = 0, NVARS
+            err = nf_inq_atttype(ncid, i, 'noSuch', datatype)
+            if (err .ne. NF_ENOTATT)
+     +          call errore('Bad attribute name: ', err)
+            do 2, j = 1, NATTS(i)
+                err = nf_inq_atttype(BAD_ID, i, ATT_NAME(j,i), datatype)
+                if (err .ne. NF_EBADID)
+     +              call errore('bad ncid: ', err)
+                err = nf_inq_atttype(ncid, BAD_VARID, ATT_NAME(j,i), 
+     +                               datatype)
+                if (err .ne. NF_ENOTVAR)
+     +              call errore('bad varid: ', err)
+                err = nf_inq_atttype(ncid, i, ATT_NAME(j,i), datatype)
+                if (err .ne. 0) then
+                    call error(nf_strerror(err))
+                else
+                    if (datatype .ne. ATT_TYPE(j,i))
+     +                  call error('type not that expected')
+                end if
+2           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
+
+
+        subroutine test_nf_inq_attname()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        character*(NF_MAX_NAME) name
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+
+        do 1, i = 0, NVARS
+            err = nf_inq_attname(ncid, i, BAD_ATTNUM, name)
+            if (err .ne. NF_ENOTATT)
+     +          call errore('Bad attribute number: ', err)
+            err = nf_inq_attname(ncid, i, NATTS(i)+1, name)
+            if (err .ne. NF_ENOTATT)
+     +          call errore('Bad attribute number: ', err)
+            do 2, j = 1, NATTS(i)
+                err = nf_inq_attname(BAD_ID, i, j, name)
+                if (err .ne. NF_EBADID)
+     +              call errore('bad ncid: ', err)
+                err = nf_inq_attname(ncid, BAD_VARID, j, name)
+                if (err .ne. NF_ENOTVAR)
+     +              call errore('bad var id: ', err)
+                err = nf_inq_attname(ncid, i, j, name)
+                if (err .ne. 0) then
+                    call error(nf_strerror(err))
+                else
+                    if (ATT_NAME(j,i) .ne. name)
+     +                  call error('name not that expected')
+                end if
+2           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
+
+
+        subroutine test_nf_inq_attid()
+        use tests
+        implicit        none
+        integer ncid
+        integer i
+        integer j
+        integer err
+        integer attnum
+
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+
+        do 1, i = 0, NVARS
+            err = nf_inq_attid(ncid, i, 'noSuch', attnum)
+            if (err .ne. NF_ENOTATT)
+     +          call errore('Bad attribute name: ', err)
+            do 2, j = 1, NATTS(i)
+                err = nf_inq_attid(BAD_ID, i, ATT_NAME(j,i), attnum)
+                if (err .ne. NF_EBADID)
+     +              call errore('bad ncid: ', err)
+                err = nf_inq_attid(ncid, BAD_VARID, ATT_NAME(j,i), 
+     +                             attnum)
+                if (err .ne. NF_ENOTVAR)
+     +              call errore('bad varid: ', err)
+                err = nf_inq_attid(ncid, i, ATT_NAME(j,i), attnum)
+                if (err .ne. 0) then
+                    call error(nf_strerror(err))
+                else
+                    if (attnum .ne. j)
+     +                  call error('attnum not that expected')
+                end if
+2           continue
+1       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        end
diff --git a/nf_test/test03_write.F b/nf_test/test03_write.F
new file mode 100755
index 0000000..42542a3
--- /dev/null
+++ b/nf_test/test03_write.F
@@ -0,0 +1,1436 @@
+C********************************************************************
+C   Copyright 1996, UCAR/Unidata
+C   See netcdf/COPYRIGHT file for copying and redistribution conditions.
+C   $Id: test_write.F,v 1.15 2008/04/30 16:50:45 ed Exp $
+C********************************************************************
+
+
+C Test nf_create
+C    For mode in NF_NOCLOBBER, NF_CLOBBER do:
+C       create netcdf file 'scratch.nc' with no data, close it
+C       test that it can be opened, do nf_inq to check nvars = 0, etc.
+C    Try again in NF_NOCLOBBER mode, check error return
+C On exit, delete this file
+        subroutine test_nf_create()
+        use tests, NDIMSG=>NDIMS, NVARSG=>NVARS, NGATTSG=>NGATTS,       &
+     &             RECDIMG=>RECDIM
+        implicit        none
+
+        integer clobber         !/* 0 for NF_NOCLOBBER, 1 for NF_CLOBBER */
+        integer err
+        integer ncid
+        integer ndims           !/* number of dimensions */
+        integer nvars           !/* number of variables */
+        integer ngatts          !/* number of global attributes */
+        integer recdim          !/* id of unlimited dimension */
+        integer flags
+
+        flags = NF_NOCLOBBER
+        do 1, clobber = 0, 1
+            err = nf_create(scratch, flags, ncid)
+            if (err .ne. 0) then
+                call errore('nf_create: ', err)
+            end if
+            err = nf_close(ncid)
+            if (err .ne. 0) then
+                call errore('nf_close: ', err)
+            end if
+            err = nf_open(scratch, NF_NOWRITE, ncid)
+            if (err .ne. 0) then
+                call errore('nf_open: ', err)
+            end if
+            err = nf_inq(ncid, ndims, nvars, ngatts, recdim)
+            if (err .ne. 0) then
+                call errore('nf_inq: ', err)
+            else if (ndims .ne. 0) then
+                call errori(
+     +              'nf_inq: wrong number of dimensions returned, ',
+     +              ndims)
+            else if (nvars .ne. 0) then
+                call errori(
+     +              'nf_inq: wrong number of variables returned, ',
+     +              nvars)
+            else if (ngatts .ne. 0) then
+                call errori(
+     +              'nf_inq: wrong number of global atts returned, ',
+     +              ngatts)
+            else if (recdim .ge. 1) then
+                call errori(
+     +              'nf_inq: wrong record dimension ID returned, ',
+     +              recdim)
+            end if
+            err = nf_close(ncid)
+            if (err .ne. 0) then
+                call errore('nf_close: ', err)
+            end if
+
+            flags = NF_CLOBBER
+1       continue
+
+        err = nf_create(scratch, NF_NOCLOBBER, ncid)
+        if (err .ne. NF_EEXIST) then
+            call errore('attempt to overwrite file: ', err)
+        end if
+        err = nf_delete(scratch)
+        if (err .ne. 0) then
+            call errori('delete of scratch file failed: ', err)
+        end if
+        end
+
+
+C Test nf_redef 
+C (In fact also tests nf_enddef - called from test_nf_enddef)
+C    BAD_ID
+C    attempt redef (error) & enddef on read-only file
+C    create file, define dims & vars. 
+C    attempt put var (error)
+C    attempt redef (error) & enddef.
+C    put vars
+C    attempt def new dims (error)
+C    redef
+C    def new dims, vars.
+C    put atts
+C    enddef
+C    put vars
+C    close
+C    check file: vars & atts
+        subroutine test_nf_redef()
+        use tests
+        implicit        none
+        integer         title_len
+        parameter       (title_len = 9)
+
+        integer                 ncid            !/* netcdf id */
+        integer                 dimid           !/* dimension id */
+        integer                 vid             !/* variable id */
+        integer                 err
+        character*(title_len)   title
+        doubleprecision         var
+        character*(NF_MAX_NAME) name
+        integer                 length
+
+        title = 'Not funny'
+
+C           /* BAD_ID tests */
+        err = nf_redef(BAD_ID)
+        if (err .ne. NF_EBADID)
+     +      call errore('bad ncid: ', err)
+        err = nf_enddef(BAD_ID)
+        if (err .ne. NF_EBADID)
+     +      call errore('bad ncid: ', err)
+
+C           /* read-only tests */
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        err = nf_redef(ncid)
+        if (err .ne. NF_EPERM)
+     +      call errore('nf_redef in NF_NOWRITE mode: ', err)
+        err = nf_enddef(ncid)
+        if (err .ne. NF_ENOTINDEFINE)
+     +      call errore('nf_redef in NF_NOWRITE mode: ', err)
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+C           /* tests using scratch file */
+        err = nf_create(scratch, NF_NOCLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        call put_atts(ncid)
+        err = nf_inq_varid(ncid, 'd', vid)
+        if (err .ne. 0) 
+     +      call errore('nf_inq_varid: ', err)
+        var = 1.0
+        err = nf_put_var1_double(ncid, vid, (/0/), var)
+        if (err .ne. NF_EINDEFINE)
+     +      call errore('nf_put_var... in define mode: ', err)
+        err = nf_redef(ncid)
+        if (err .ne. NF_EINDEFINE)
+     +      call errore('nf_redef in define mode: ', err)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+        call put_vars(ncid)
+        err = nf_def_dim(ncid, 'abc', 8, dimid)
+        if (err .ne. NF_ENOTINDEFINE)
+     +      call errore('nf_def_dim in define mode: ', err)
+        err = nf_redef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_redef: ', err)
+        err = nf_def_dim(ncid, 'abc', 8, dimid)
+        if (err .ne. 0)
+     +      call errore('nf_def_dim: ', err)
+        err = nf_def_var(ncid, 'abc', NF_INT, 0, (/0/), vid)
+        if (err .ne. 0)
+     +      call errore('nf_def_var: ', err)
+        err = nf_put_att_text(ncid, NF_GLOBAL, 'title', len(title), 
+     +                        title)
+        if (err .ne .0)
+     +      call errore('nf_put_att_text: ', err)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+        var = 1.0
+        err = nf_put_var1_double(ncid, vid, (/0/), var)
+        if (err .ne. 0)
+     +      call errore('nf_put_var1_double: ', err)
+        err = nf_close(ncid)
+        if (err .ne. 0) 
+     +      call errore('nf_close: ', err)
+
+C           /* check scratch file written as expected */
+        call check_file(scratch)
+        err = nf_open(scratch, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        err = nf_inq_dim(ncid, dimid, name, length)
+        if (err .ne. 0) 
+     +      call errore('nf_inq_dim: ', err)
+        if (name .ne. "abc")
+     +      call errori('Unexpected dim name in netCDF ', ncid)
+        if (length .ne. 8) 
+     +      call errori('Unexpected dim length: ', length)
+        err = nf_get_var1_double(ncid, vid, (/0/), var)
+        if (err .ne. 0)
+     +      call errore('nf_get_var1_double: ', err)
+        if (var .ne. 1.0)
+     +      call errori(
+     +          'nf_get_var1_double: unexpected value in netCDF ', ncid)
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errori('delete failed for netCDF: ', err)
+        end
+
+C Test nf_enddef 
+C Simply calls test_nf_redef which tests both nf_redef & nf_enddef
+
+        subroutine test_nf_enddef()
+        use tests
+        implicit        none
+
+        call test_nf_redef
+        end
+
+
+C Test nf_sync
+C    try with bad handle, check error
+C    try in define mode, check error
+C    try writing with one handle, reading with another on same netCDF
+        subroutine test_nf_sync()
+        use tests
+        implicit        none
+
+        integer ncidw         !/* netcdf id for writing */
+        integer ncidr         !/* netcdf id for reading */
+        integer err
+
+C           /* BAD_ID test */
+        err = nf_sync(BAD_ID)
+        if (err .ne. NF_EBADID)
+     +      call errore('bad ncid: ', err)
+
+C           /* create scratch file & try nf_sync in define mode */
+        err = nf_create(scratch, NF_NOCLOBBER, ncidw)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        err = nf_sync(ncidw)
+        if (err .ne. NF_EINDEFINE)
+     +      call errore('nf_sync called in define mode: ', err)
+
+C           /* write using same handle */
+        call def_dims(ncidw)
+        call def_vars(ncidw)
+        call put_atts(ncidw)
+        err = nf_enddef(ncidw)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+        call put_vars(ncidw)
+        err = nf_sync(ncidw)
+        if (err .ne. 0)
+     +      call errore('nf_sync of ncidw failed: ', err)
+
+C           /* open another handle, nf_sync, read (check) */
+        err = nf_open(scratch, NF_NOWRITE, ncidr)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        err = nf_sync(ncidr)
+        if (err .ne. 0)
+     +      call errore('nf_sync of ncidr failed: ', err)
+        call check_dims(ncidr)
+        call check_atts(ncidr)
+        call check_vars(ncidr)
+
+C           /* close both handles */
+        err = nf_close(ncidr)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        err = nf_close(ncidw)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errori('delete of scratch file failed: ', err)
+        end
+
+
+C Test nf_abort
+C    try with bad handle, check error
+C    try in define mode before anything written, check that file was deleted
+C    try after nf_enddef, nf_redef, define new dims, vars, atts
+C    try after writing variable
+        subroutine test_nf_abort()
+        use tests, NDIMSG=>NDIMS, NVARSG=>NVARS, NGATTSG=>NGATTS,       &
+     &             RECDIMG=>RECDIM
+        implicit        none
+
+        integer ncid          !/* netcdf id */
+        integer err
+        integer ndims
+        integer nvars
+        integer ngatts
+        integer recdim
+
+C           /* BAD_ID test */
+        err = nf_abort(BAD_ID)
+        if (err .ne. NF_EBADID)
+     +      call errore('bad ncid: status = ', err)
+
+C           /* create scratch file & try nf_abort in define mode */
+        err = nf_create(scratch, NF_NOCLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        call put_atts(ncid)
+        err = nf_abort(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_abort of ncid failed: ', err)
+        err = nf_close(ncid)    !/* should already be closed */
+        if (err .ne. NF_EBADID)
+     +      call errore('bad ncid: ', err)
+        err = nf_delete(scratch)        !/* should already be deleted */
+        if (err .eq. 0)
+     +      call errori('scratch file should not exist: ', err)
+
+C            create scratch file
+C            do nf_enddef & nf_redef
+C            define new dims, vars, atts
+C            try nf_abort: should restore previous state (no dims, vars, atts)
+        err = nf_create(scratch, NF_NOCLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+        err = nf_redef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_redef: ', err)
+        call def_dims(ncid)
+        call def_vars(ncid)
+        call put_atts(ncid)
+        err = nf_abort(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_abort of ncid failed: ', err)
+        err = nf_close(ncid)    !/* should already be closed */
+        if (err .ne. NF_EBADID)
+     +      call errore('bad ncid: ', err)
+        err = nf_open(scratch, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        err = nf_inq (ncid, ndims, nvars, ngatts, recdim)
+        if (err .ne. 0)
+     +      call errore('nf_inq: ', err)
+        if (ndims .ne. 0)
+     +      call errori('ndims should be ', 0)
+        if (nvars .ne. 0)
+     +      call errori('nvars should be ', 0)
+        if (ngatts .ne. 0)
+     +      call errori('ngatts should be ', 0)
+        err = nf_close (ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+
+C           /* try nf_abort in data mode - should just close */
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+        call put_atts(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+        call put_vars(ncid)
+        err = nf_abort(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_abort of ncid failed: ', err)
+        err = nf_close(ncid)       !/* should already be closed */
+        if (err .ne. NF_EBADID)
+     +      call errore('bad ncid: ', err)
+        call check_file(scratch)
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errori('delete of scratch file failed: ', err)
+        end
+
+
+C Test nf_def_dim
+C    try with bad netCDF handle, check error
+C    try in data mode, check error
+C    check that returned id is one more than previous id
+C    try adding same dimension twice, check error
+C    try with illegal sizes, check error
+C    make sure unlimited size works, shows up in nf_inq_unlimdim
+C    try to define a second unlimited dimension, check error
+        subroutine test_nf_def_dim()
+        use tests
+        implicit        none
+
+        integer ncid
+        integer err             !/* status */
+        integer i
+        integer dimid         !/* dimension id */
+        integer length
+
+C           /* BAD_ID test */
+        err = nf_def_dim(BAD_ID, 'abc', 8, dimid)
+        if (err .ne. NF_EBADID)
+     +      call errore('bad ncid: ', err)
+
+C           /* data mode test */
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+        err = nf_def_dim(ncid, 'abc', 8, dimid)
+        if (err .ne. NF_ENOTINDEFINE)
+     +      call errore('bad ncid: ', err)
+
+C           /* define-mode tests: unlimited dim */
+        err = nf_redef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_redef: ', err)
+        err = nf_def_dim(ncid, dim_name(1), NF_UNLIMITED, dimid)
+        if (err .ne. 0) 
+     +      call errore('nf_def_dim: ', err)
+        if (dimid .ne. 1) 
+     +      call errori('Unexpected dimid: ', dimid)
+        err = nf_inq_unlimdim(ncid, dimid)
+        if (err .ne. 0) 
+     +      call errore('nf_inq_unlimdim: ', err)
+        if (dimid .ne. RECDIM) 
+     +      call error('Unexpected recdim: ')
+        err = nf_inq_dimlen(ncid, dimid, length)
+        if (length .ne. 0) 
+     +      call errori('Unexpected length: ', 0)
+        err = nf_def_dim(ncid, 'abc', NF_UNLIMITED, dimid)
+        if (err .ne. NF_EUNLIMIT)
+     +      call errore('2nd unlimited dimension: ', err)
+
+C           /* define-mode tests: remaining dims */
+        do 1, i = 2, NDIMS
+            err = nf_def_dim(ncid, dim_name(i-1), dim_len(i), 
+     +                       dimid)
+            if (err .ne. NF_ENAMEINUSE)
+     +          call errore('duplicate name: ', err)
+            err = nf_def_dim(ncid, BAD_NAME, dim_len(i), dimid)
+            if (err .ne. NF_EBADNAME)
+     +          call errore('bad name: ', err)
+            err = nf_def_dim(ncid, dim_name(i), NF_UNLIMITED-1, 
+     +                       dimid)
+            if (err .ne. NF_EDIMSIZE)
+     +          call errore('bad size: ', err)
+            err = nf_def_dim(ncid, dim_name(i), dim_len(i), dimid)
+            if (err .ne. 0) 
+     +          call errore('nf_def_dim: ', err)
+            if (dimid .ne. i) 
+     +          call errori('Unexpected dimid: ', 0)
+1       continue
+
+C           /* Following just to expand unlimited dim */
+        call def_vars(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+        call put_vars(ncid)
+
+C           /* Check all dims */
+        call check_dims(ncid)
+
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errori('delete of scratch file failed: ', err)
+        end
+
+
+C Test nf_rename_dim
+C    try with bad netCDF handle, check error
+C    check that proper rename worked with nf_inq_dim
+C    try renaming to existing dimension name, check error
+C    try with bad dimension handle, check error
+        subroutine test_nf_rename_dim()
+        use tests
+        implicit        none
+
+        integer ncid
+        integer err             !/* status */
+        character*(NF_MAX_NAME) name
+
+C           /* BAD_ID test */
+        err = nf_rename_dim(BAD_ID, 1, 'abc')
+        if (err .ne. NF_EBADID)
+     +      call errore('bad ncid: ', err)
+
+C           /* main tests */
+        err = nf_create(scratch, NF_NOCLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        err = nf_rename_dim(ncid, BAD_DIMID, 'abc')
+        if (err .ne. NF_EBADDIM)
+     +      call errore('bad dimid: ', err)
+        err = nf_rename_dim(ncid, 3, 'abc')
+        if (err .ne. 0)
+     +      call errore('nf_rename_dim: ', err)
+        err = nf_inq_dimname(ncid, 3, name)
+        if (name .ne. 'abc')
+     +      call errorc('Unexpected name: ', name)
+        err = nf_rename_dim(ncid, 1, 'abc')
+        if (err .ne. NF_ENAMEINUSE)
+     +      call errore('duplicate name: ', err)
+
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errori('delete of scratch file failed: ', err)
+        end
+
+
+C Test nf_def_var
+C    try with bad netCDF handle, check error
+C    try with bad name, check error
+C    scalar tests:
+C      check that proper define worked with nf_inq_var
+C      try redefining an existing variable, check error
+C      try with bad datatype, check error
+C      try with bad number of dimensions, check error
+C      try in data mode, check error
+C    check that returned id is one more than previous id
+C    try with bad dimension ids, check error
+        subroutine test_nf_def_var()
+        use tests, NDIMSG=>NDIMS
+        implicit        none
+
+        integer ncid
+        integer vid
+        integer err             !/* status */
+        integer i
+        integer ndims
+        integer na
+        character*(NF_MAX_NAME) name
+        integer dimids(MAX_RANK)
+        integer datatype
+
+C           /* BAD_ID test */
+        err = nf_def_var(BAD_ID, 'abc', NF_SHORT, 0, dimids, vid)
+        if (err .ne. NF_EBADID)
+     +      call errore('bad ncid: status = ', err)
+
+C           /* scalar tests */
+        err = nf_create(scratch, NF_NOCLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        err = nf_def_var(ncid, 'abc', NF_SHORT, 0, dimids, vid)
+        if (err .ne. 0)
+     +      call errore('nf_def_var: ', err)
+        err = nf_inq_var(ncid, vid, name, datatype, ndims, dimids, 
+     +                   na)
+        if (err .ne. 0)
+     +      call errore('nf_inq_var: ', err)
+        if (name .ne. 'abc')
+     +      call errorc('Unexpected name: ', name)
+        if (datatype .ne. NF_SHORT)
+     +      call error('Unexpected datatype')
+        if (ndims .ne. 0)
+     +      call error('Unexpected rank')
+        err = nf_def_var(ncid, BAD_NAME, NF_SHORT, 0, dimids, vid)
+        if (err .ne. NF_EBADNAME)
+     +      call errore('bad name: ', err)
+        err = nf_def_var(ncid, 'abc', NF_SHORT, 0, dimids, vid)
+        if (err .ne. NF_ENAMEINUSE)
+     +      call errore('duplicate name: ', err)
+        err = nf_def_var(ncid, 'ABC', BAD_TYPE, -1, dimids, vid)
+        if (err .ne. NF_EBADTYPE)
+     +      call errore('bad type: ', err)
+        err = nf_def_var(ncid, 'ABC', NF_SHORT, -1, dimids, vid)
+        if (err .ne. NF_EINVAL)
+     +      call errore('bad rank: ', err)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+        err = nf_def_var(ncid, 'ABC', NF_SHORT, 0, dimids, vid)
+        if (err .ne. NF_ENOTINDEFINE)
+     +      call errore('nf_def_var called in data mode: ', err)
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed: ', scratch)
+
+C           /* general tests using global vars */
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        do 1, i = 1, NVARS
+            err = nf_def_var(ncid, var_name(i), var_type(i), 
+     +                       var_rank(i), var_dimid(1,i), vid)
+            if (err .ne. 0) 
+     +          call errore('nf_def_var: ', err)
+            if (vid .ne. i)
+     +          call error('Unexpected varid')
+1       continue
+
+C           /* try bad dim ids */
+        dimids(1) = BAD_DIMID
+        err = nf_def_var(ncid, 'abc', NF_SHORT, 1, dimids, vid)
+        if (err .ne. NF_EBADDIM)
+     +      call errore('bad dim ids: ', err)
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed: ', scratch)
+        end
+
+
+C Test nf_rename_var
+C    try with bad netCDF handle, check error
+C    try with bad variable handle, check error
+C    try renaming to existing variable name, check error
+C    check that proper rename worked with nf_inq_varid
+C    try in data mode, check error
+        subroutine test_nf_rename_var()
+        use tests
+        implicit        none
+
+        integer ncid
+        integer vid
+        integer err
+        integer i
+        character*(NF_MAX_NAME) name
+
+        err = nf_create(scratch, NF_NOCLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        err = nf_rename_var(ncid, BAD_VARID, 'newName')
+        if (err .ne. NF_ENOTVAR)
+     +      call errore('bad var id: ', err)
+        call def_dims(ncid)
+        call def_vars(ncid)
+
+C           /* Prefix "new_" to each name */
+        do 1, i = 1, NVARS
+            err = nf_rename_var(BAD_ID, i, 'newName')
+            if (err .ne. NF_EBADID)
+     +          call errore('bad ncid: ', err)
+            err = nf_rename_var(ncid, i, var_name(NVARS))
+            if (err .ne. NF_ENAMEINUSE)
+     +          call errore('duplicate name: ', err)
+            name = 'new_' // var_name(i)
+            err = nf_rename_var(ncid, i, name)
+            if (err .ne. 0)
+     +          call errore('nf_rename_var: ', err)
+            err = nf_inq_varid(ncid, name, vid)
+            if (err .ne. 0)
+     +          call errore('nf_inq_varid: ', err)
+            if (vid .ne. i)
+     +          call error('Unexpected varid')
+1       continue
+
+C           /* Change to data mode */
+C           /* Try making names even longer. Then restore original names */
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+        do 2, i = 1, NVARS
+            name = 'even_longer_' // var_name(i)
+            err = nf_rename_var(ncid, i, name)
+            if (err .ne. NF_ENOTINDEFINE)
+     +          call errore('longer name in data mode: ', err)
+            err = nf_rename_var(ncid, i, var_name(i))
+            if (err .ne. 0)
+     +          call errore('nf_rename_var: ', err)
+            err = nf_inq_varid(ncid, var_name(i), vid)
+            if (err .ne. 0)
+     +          call errore('nf_inq_varid: ', err)
+            if (vid .ne. i)
+     +          call error('Unexpected varid')
+2       continue
+
+        call put_vars(ncid)
+        call check_vars(ncid)
+
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed: ', scratch)
+        end
+
+
+C Test nf_copy_att
+C    try with bad source or target netCDF handles, check error
+C    try with bad source or target variable handle, check error
+C    try with nonexisting attribute, check error
+C    check that NF_GLOBAL variable for source or target works
+C    check that new attribute put works with target in define mode
+C    check that old attribute put works with target in data mode
+C    check that changing type and length of an attribute work OK
+C    try with same ncid for source and target, different variables
+C    try with same ncid for source and target, same variable
+        subroutine test_nf_copy_att()
+        use tests
+        implicit        none
+
+        integer ncid_in
+        integer ncid_out
+        integer vid
+        integer err
+        integer i
+        integer j
+        character*(NF_MAX_NAME) name    !/* of att */
+        integer datatype                !/* of att */
+        integer length                  !/* of att */
+        character*1     value
+
+        err = nf_open(testfile, NF_NOWRITE, ncid_in)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        err = nf_create(scratch, NF_NOCLOBBER, ncid_out)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid_out)
+        call def_vars(ncid_out)
+
+        do 1, i = 0, NVARS
+            vid = VARID(i)
+            do 2, j = 1, NATTS(i)
+                name = ATT_NAME(j,i)
+                err = nf_copy_att(ncid_in, BAD_VARID, name, ncid_out, 
+     +                            vid)
+                if (err .ne. NF_ENOTVAR)
+     +              call errore('bad var id: ', err)
+                err = nf_copy_att(ncid_in, vid, name, ncid_out, 
+     +                            BAD_VARID)
+                if (err .ne. NF_ENOTVAR)
+     +              call errore('bad var id: ', err)
+                err = nf_copy_att(BAD_ID, vid, name, ncid_out, vid)
+                if (err .ne. NF_EBADID)
+     +              call errore('bad ncid: ', err)
+                err = nf_copy_att(ncid_in, vid, name, BAD_ID, vid)
+                if (err .ne. NF_EBADID)
+     +              call errore('bad ncid: ', err)
+                err = nf_copy_att(ncid_in, vid, 'noSuch', ncid_out, vid)
+                if (err .ne. NF_ENOTATT)
+     +              call errore('bad attname: ', err)
+                err = nf_copy_att(ncid_in, vid, name, ncid_out, vid)
+                if (err .ne. 0)
+     +              call errore('nf_copy_att: ', err)
+                err = nf_copy_att(ncid_out, vid, name, ncid_out, vid)
+                if (err .ne. 0)
+     +              call errore('source = target: ', err)
+2           continue
+1       continue
+
+        err = nf_close(ncid_in)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+
+C           /* Close scratch. Reopen & check attributes */
+        err = nf_close(ncid_out)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        err = nf_open(scratch, NF_WRITE, ncid_out)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        call check_atts(ncid_out)
+
+C           change to define mode
+C           define single char. global att. ':a' with value 'A'
+C           This will be used as source for following copies
+        err = nf_redef(ncid_out)
+        if (err .ne. 0)
+     +      call errore('nf_redef: ', err)
+        err = nf_put_att_text(ncid_out, NF_GLOBAL, 'a', 1, 'A')
+        if (err .ne. 0)
+     +      call errore('nf_put_att_text: ', err)
+
+C           change to data mode
+C           Use scratch as both source & dest.
+C           try copy to existing att. change type & decrease length
+C           rename 1st existing att of each var (if any) 'a'
+C           if this att. exists them copy ':a' to it
+        err = nf_enddef(ncid_out)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+        do 3, i = 1, NVARS
+            if (NATTS(i) .gt. 0 .and. ATT_LEN(1,i) .gt. 0) then
+                err = nf_rename_att(ncid_out, i, att_name(1,i), 'a')
+                if (err .ne. 0)
+     +              call errore('nf_rename_att: ', err)
+                err = nf_copy_att(ncid_out, NF_GLOBAL, 'a', ncid_out, 
+     +                            i)
+                if (err .ne. 0)
+     +              call errore('nf_copy_att: ', err)
+            end if
+3       continue
+        err = nf_close(ncid_out)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+
+C           /* Reopen & check */
+        err = nf_open(scratch, NF_WRITE, ncid_out)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        do 4, i = 1, NVARS
+            if (NATTS(i) .gt. 0 .and. ATT_LEN(1,i) .gt. 0) then
+                err = nf_inq_att(ncid_out, i, 'a', datatype, length)
+                if (err .ne. 0)
+     +              call errore('nf_inq_att: ', err)
+                if (datatype .ne. NF_CHAR)
+     +              call error('Unexpected type')
+                if (length .ne. 1)
+     +              call error('Unexpected length')
+                err = nf_get_att_text(ncid_out, i, 'a', value)
+                if (err .ne. 0)
+     +              call errore('nf_get_att_text: ', err)
+                if (value .ne. 'A')
+     +              call error('Unexpected value')
+            end if                                                   
+4       continue                                                   
+
+        err = nf_close(ncid_out)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errorc('delete of scratch file failed', scratch)
+        end
+
+
+C Test nf_rename_att
+C    try with bad netCDF handle, check error
+C    try with bad variable handle, check error
+C    try with nonexisting att name, check error
+C    try renaming to existing att name, check error
+C    check that proper rename worked with nf_inq_attid
+C    try in data mode, check error
+        subroutine test_nf_rename_att()
+        use tests
+        implicit        none
+
+        integer ncid
+        integer vid
+        integer err
+        integer i
+        integer j
+        integer  k
+        integer attnum
+        character*(NF_MAX_NAME) atnam
+        character*(NF_MAX_NAME) name
+        character*(NF_MAX_NAME) oldname
+        character*(NF_MAX_NAME) newname
+        integer nok             !/* count of valid comparisons */
+        integer datatype
+        integer attyp
+        integer length
+        integer attlength
+        integer ndx(1)
+        character*(MAX_NELS)    text
+        doubleprecision value(MAX_NELS)
+        doubleprecision expect
+
+        nok = 0
+
+        err = nf_create(scratch, NF_NOCLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        err = nf_rename_att(ncid, BAD_VARID, 'abc', 'newName')
+        if (err .ne. NF_ENOTVAR)
+     +      call errore('bad var id: ', err)
+        call def_dims(ncid)
+        call def_vars(ncid)
+        call put_atts(ncid)
+
+        do 1, i = 0, NVARS
+            vid = VARID(i)
+            do 2, j = 1, NATTS(i)
+                atnam = ATT_NAME(j,i)
+                err = nf_rename_att(BAD_ID, vid, atnam, 'newName')
+                if (err .ne. NF_EBADID)
+     +              call errore('bad ncid: ', err)
+                err = nf_rename_att(ncid, vid, 'noSuch', 'newName')
+                if (err .ne. NF_ENOTATT)
+     +              call errore('bad attname: ', err)
+                newname = 'new_' // atnam
+                err = nf_rename_att(ncid, vid, atnam, newname)
+                if (err .ne. 0)
+     +              call errore('nf_rename_att: ', err)
+                err = nf_inq_attid(ncid, vid, newname, attnum)
+                if (err .ne. 0)
+     +              call errore('nf_inq_attid: ', err)
+                if (attnum .ne. j)
+     +              call error('Unexpected attnum')
+2           continue
+1       continue
+
+C           /* Close. Reopen & check */
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        err = nf_open(scratch, NF_WRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+
+        do 3, i = 0, NVARS
+            vid = VARID(i)
+            do 4, j = 1, NATTS(i)
+                atnam = ATT_NAME(j,i)
+                attyp = ATT_TYPE(j,i)
+                attlength = ATT_LEN(j,i)
+                newname = 'new_' // atnam
+                err = nf_inq_attname(ncid, vid, j, name)
+                if (err .ne. 0)
+     +              call errore('nf_inq_attname: ', err)
+                if (name .ne. newname)
+     +              call error('nf_inq_attname: unexpected name')
+                err = nf_inq_att(ncid, vid, name, datatype, length)
+                if (err .ne. 0)
+     +              call errore('nf_inq_att: ', err)
+                if (datatype .ne. attyp)
+     +              call error('nf_inq_att: unexpected type')
+                if (length .ne. attlength)
+     +              call error('nf_inq_att: unexpected length')
+                if (datatype .eq. NF_CHAR) then
+                    err = nf_get_att_text(ncid, vid, name, text)
+                    if (err .ne. 0)
+     +                  call errore('nf_get_att_text: ', err)
+                    do 5, k = 1, attlength
+                        ndx(1) = k
+                        expect = hash(datatype, -1, ndx)
+                        if (ichar(text(k:k)) .ne. expect) then
+                            call error(
+     +                          'nf_get_att_text: unexpected value')
+                        else
+                            nok = nok + 1
+                        end if
+5                   continue
+                else
+                    err = nf_get_att_double(ncid, vid, name, value)
+                    if (err .ne. 0)
+     +                  call errore('nf_get_att_double: ', err)
+                    do 6, k = 1, attlength
+                        ndx(1) = k
+                        expect = hash(datatype, -1, ndx)
+                        if (inRange(expect, datatype)) then
+                            if (.not. equal(value(k),expect,datatype,
+     +                                      NF_DOUBLE)) then
+                                call error(
+     +                          'nf_get_att_double: unexpected value')
+                            else
+                                nok = nok + 1
+                            end if
+                        end if
+6                   continue
+                end if
+4           continue
+3       continue
+        call print_nok(nok)
+
+C           /* Now in data mode */
+C           /* Try making names even longer. Then restore original names */
+
+        do 7, i = 0, NVARS
+            vid = VARID(i)
+            do 8, j = 1, NATTS(i)
+                atnam = ATT_NAME(j,i)
+                oldname = 'new_' // atnam
+                newname = 'even_longer_' // atnam
+                err = nf_rename_att(ncid, vid, oldname, newname)
+                if (err .ne. NF_ENOTINDEFINE)
+     +              call errore('longer name in data mode: ', err)
+                err = nf_rename_att(ncid, vid, oldname, atnam)
+                if (err .ne. 0)
+     +              call errore('nf_rename_att: ', err)
+                err = nf_inq_attid(ncid, vid, atnam, attnum)
+                if (err .ne. 0)
+     +              call errore('nf_inq_attid: ', err)
+                if (attnum .ne. j)
+     +              call error('Unexpected attnum')
+8           continue
+7       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errori('delete of scratch file failed: ', err)
+        end
+
+
+C Test nf_del_att
+C    try with bad netCDF handle, check error
+C    try with bad variable handle, check error
+C    try with nonexisting att name, check error
+C    check that proper delete worked using:
+C      nf_inq_attid, nf_inq_natts, nf_inq_varnatts
+        subroutine test_nf_del_att()
+        use tests
+        implicit        none
+
+        integer ncid
+        integer err
+        integer i
+        integer j
+        integer attnum
+        integer na
+        integer numatts
+        integer vid
+        character*(NF_MAX_NAME)  name           !/* of att */
+
+        err = nf_create(scratch, NF_NOCLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        err = nf_del_att(ncid, BAD_VARID, 'abc')
+        if (err .ne. NF_ENOTVAR)
+     +      call errore('bad var id: ', err)
+        call def_dims(ncid)
+        call def_vars(ncid)
+        call put_atts(ncid)
+
+        do 1, i = 0, NVARS
+            vid = VARID(i)
+            numatts = NATTS(i)
+            do 2, j = 1, numatts
+                name = ATT_NAME(j,i)
+                err = nf_del_att(BAD_ID, vid, name)
+                if (err .ne. NF_EBADID)
+     +              call errore('bad ncid: ', err)
+                err = nf_del_att(ncid, vid, 'noSuch')
+                if (err .ne. NF_ENOTATT)
+     +              call errore('bad attname: ', err)
+                err = nf_del_att(ncid, vid, name)
+                if (err .ne. 0)
+     +              call errore('nf_del_att: ', err)
+                err = nf_inq_attid(ncid, vid, name, attnum)
+                if (err .ne. NF_ENOTATT)
+     +              call errore('bad attname: ', err)
+                if (i .lt. 1) then
+                    err = nf_inq_natts(ncid, na)
+                    if (err .ne. 0)
+     +                  call errore('nf_inq_natts: ', err)
+		    if (na .ne. numatts-j) then
+			call errori('natts: expected: ', numatts-j)
+			call errori('natts: got:      ', na)
+		    end if
+		end if
+		err = nf_inq_varnatts(ncid, vid, na)
+		if (err .ne. 0)
+     +              call errore('nf_inq_natts: ', err)
+                if (na .ne. numatts-j) then
+                    call errori('natts: expected: ', numatts-j)
+                    call errori('natts: got:      ', na)
+                end if
+2           continue
+1       continue
+
+C           /* Close. Reopen & check no attributes left */
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        err = nf_open(scratch, NF_WRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        err = nf_inq_natts(ncid, na)
+        if (err .ne. 0)
+     +      call errore('nf_inq_natts: ', err)
+        if (na .ne. 0)
+     +      call errori('natts: expected 0, got ', na)
+        do 3, i = 0, NVARS
+            vid = VARID(i)
+            err = nf_inq_varnatts(ncid, vid, na)
+            if (err .ne. 0)
+     +          call errore('nf_inq_natts: ', err)
+            if (na .ne. 0)
+     +          call errori('natts: expected 0, got ', na)
+3       continue
+
+C           /* restore attributes. change to data mode. try to delete */
+        err = nf_redef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_redef: ', err)
+        call put_atts(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+
+        do 4, i = 0, NVARS
+            vid = VARID(i)
+            numatts = NATTS(i)
+            do 5, j = 1, numatts
+                name = ATT_NAME(j,i)
+                err = nf_del_att(ncid, vid, name)
+                if (err .ne. NF_ENOTINDEFINE)
+     +              call errore('in data mode: ', err)
+5           continue
+4       continue
+
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errori('delete of scratch file failed: ', err)
+        end
+
+
+C Test nf_set_fill
+C    try with bad netCDF handle, check error
+C    try in read-only mode, check error
+C    try with bad new_fillmode, check error
+C    try in data mode, check error
+C    check that proper set to NF_FILL works for record & non-record variables
+C    (note that it is not possible to test NF_NOFILL mode!)
+C    close file & create again for test using attribute _FillValue
+        subroutine test_nf_set_fill()
+        use tests
+        implicit none
+
+        integer ncid
+        integer vid
+        integer err
+        integer i
+        integer j
+        integer old_fillmode
+        integer nok             !/* count of valid comparisons */
+        character*1 text
+        doubleprecision value
+        doubleprecision fill
+        integer index(MAX_RANK)
+
+        nok = 0
+        value = 0
+
+C           /* bad ncid */
+        err = nf_set_fill(BAD_ID, NF_NOFILL, old_fillmode)
+        if (err .ne. NF_EBADID)
+     +      call errore('bad ncid: ', err)
+
+C           /* try in read-only mode */
+        err = nf_open(testfile, NF_NOWRITE, ncid)
+        if (err .ne. 0)
+     +      call errore('nf_open: ', err)
+        err = nf_set_fill(ncid, NF_NOFILL, old_fillmode)
+        if (err .ne. NF_EPERM)
+     +      call errore('read-only: ', err)
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+
+C           /* create scratch */
+        err = nf_create(scratch, NF_NOCLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+
+C           /* BAD_FILLMODE */
+        err = nf_set_fill(ncid, BAD_FILLMODE, old_fillmode)
+        if (err .ne. NF_EINVAL)
+     +      call errore('bad fillmode: ', err)
+
+C           /* proper calls */
+        err = nf_set_fill(ncid, NF_NOFILL, old_fillmode)
+        if (err .ne. 0)
+     +      call errore('nf_set_fill: ', err)
+        if (old_fillmode .ne. NF_FILL)
+     +      call errori('Unexpected old fill mode: ', old_fillmode)
+        err = nf_set_fill(ncid, NF_FILL, old_fillmode)
+        if (err .ne. 0)
+     +      call errore('nf_set_fill: ', err)
+        if (old_fillmode .ne. NF_NOFILL)
+     +      call errori('Unexpected old fill mode: ', old_fillmode)
+
+C           /* define dims & vars */
+        call def_dims(ncid)
+        call def_vars(ncid)
+
+C           /* Change to data mode. Set fillmode again */
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+        err = nf_set_fill(ncid, NF_FILL, old_fillmode)
+        if (err .ne. 0)
+     +      call errore('nf_set_fill: ', err)
+        if (old_fillmode .ne. NF_FILL)
+     +      call errori('Unexpected old fill mode: ', old_fillmode)
+
+C       /* Write record number NRECS to force writing of preceding records */
+C       /* Assumes variable cr is char vector with UNLIMITED dimension */
+        err = nf_inq_varid(ncid, 'cr', vid)
+        if (err .ne. 0)
+     +      call errore('nf_inq_varid: ', err)
+        index(1) = NRECS
+        text = char(NF_FILL_CHAR)
+        err = nf_put_var1_text(ncid, vid, index, text)
+        if (err .ne. 0)
+     +      call errore('nf_put_var1_text: ', err)
+
+C           /* get all variables & check all values equal default fill */
+        do 1, i = 1, NVARS
+            if (var_type(i) .eq. NF_CHAR) then
+                fill = NF_FILL_CHAR
+            else if (var_type(i) .eq. NF_BYTE) then
+                fill = NF_FILL_BYTE
+            else if (var_type(i) .eq. NF_SHORT) then
+                fill = NF_FILL_SHORT
+            else if (var_type(i) .eq. NF_INT) then
+                fill = NF_FILL_INT
+            else if (var_type(i) .eq. NF_FLOAT) then
+                fill = NF_FILL_FLOAT
+            else if (var_type(i) .eq. NF_DOUBLE) then
+                fill = NF_FILL_DOUBLE
+            else
+                stop 2
+            end if
+
+            do 2, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0)
+     +              call error('error in index2indexes()')
+                if (var_type(i) .eq. NF_CHAR) then
+                    err = nf_get_var1_text(ncid, i, index, text)
+                    if (err .ne. 0)
+     +                  call errore('nf_get_var1_text failed: ',err)
+                    value = ichar(text)
+                else
+                    err = nf_get_var1_double(ncid, i, index, value)
+                    if (err .ne. 0)
+     +                  call errore('nf_get_var1_double failed: ',err)
+                end if
+                if (value .ne. fill .and. 
+     +              abs((fill - value)/fill) .gt. 1.0e-9) then
+                    call errord('Unexpected fill value: ', value)
+                else
+                    nok = nok + 1
+                end if
+2           continue
+1       continue
+
+C       /* close scratch & create again for test using attribute _FillValue */
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        err = nf_create(scratch, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+            return
+        end if
+        call def_dims(ncid)
+        call def_vars(ncid)
+
+C           /* set _FillValue = 42 for all vars */
+        fill = 42
+        text = char(int(fill))
+        do 3, i = 1, NVARS
+            if (var_type(i) .eq. NF_CHAR) then
+                err = nf_put_att_text(ncid, i, '_FillValue', 1, text)
+                if (err .ne. 0)
+     +              call errore('nf_put_att_text: ', err)
+            else
+                err = nf_put_att_double(ncid, i, '_FillValue',
+     +                                  var_type(i),1,(/fill/))
+                if (err .ne. 0)
+     +              call errore('nf_put_att_double: ', err)
+            end if
+3       continue
+
+C           /* data mode. write records */
+        err = nf_enddef(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_enddef: ', err)
+        index(1) = NRECS
+        err = nf_put_var1_text(ncid, vid, index, text)
+        if (err .ne. 0)
+     +      call errore('nf_put_var1_text: ', err)
+
+C           /* get all variables & check all values equal 42 */
+        do 4, i = 1, NVARS
+            do 5, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0)
+     +              call error('error in index2indexes')
+                if (var_type(i) .eq. NF_CHAR) then
+                    err = nf_get_var1_text(ncid, i, index, text)
+                    if (err .ne. 0)
+     +                  call errore('nf_get_var1_text failed: ',err)
+                    value = ichar(text)
+                else
+                    err = nf_get_var1_double(ncid, i, index, value)
+                    if (err .ne. 0)
+     +                  call errore('nf_get_var1_double failed: ', err)
+                end if
+                if (value .ne. fill) then
+                    call errord(' Value expected: ', fill)
+                    call errord(' Value read:     ', value)
+                else
+                    nok = nok + 1
+                end if
+5           continue
+4       continue
+        call print_nok(nok)
+
+        err = nf_close(ncid)
+        if (err .ne. 0)
+     +      call errore('nf_close: ', err)
+        err = nf_delete(scratch)
+        if (err .ne. 0)
+     +      call errori('delete of scratch file failed: ', err)
+        end
+
+C * Test nc_set_default_format
+C *    try with bad default format
+C *    try with NULL old_formatp
+C *    try in data mode, check error
+C *    check that proper set to NC_FILL works for record & non-record variables
+C *    (note that it is not possible to test NC_NOFILL mode!)
+C *    close file & create again for test using attribute _FillValue
+      subroutine test_nf_set_default_format()
+      use tests
+      implicit none
+      
+      integer ncid
+      integer err
+      integer i
+      integer version
+      integer old_format
+      integer nf_get_file_version
+      
+C     /* bad format */
+      err = nf_set_default_format(5, old_format)
+      IF (err .ne. NF_EINVAL)
+     +     call errore("bad default format: status = %d", err)
+     
+C     /* Cycle through available formats. (actually netcdf-4 formats are
+C     ignored for the moment - ed 5/15/5) */
+      do 1 i=1, 2
+         err = nf_set_default_format(i, old_format)
+         if (err .ne. 0) 
+     +         call errore("setting classic format: status = %d", err)
+         err = nf_create(scratch, NF_CLOBBER, ncid)
+         if (err .ne. 0) call errore("bad nf_create: status = %d", err)
+         err = nf_put_att_text(ncid, NF_GLOBAL, "testatt", 
+     +        4, "blah")
+         if (err .ne. 0) call errore("bad put_att: status = %d", err)
+         err = nf_close(ncid)
+         if (err .ne. 0) call errore("bad close: status = %d", err)
+         err = nf_get_file_version(scratch, version)
+         if (err .ne. 0) call errore("bad file version = %d", err)
+         if (version .ne. i)
+     +        call errore("bad file version = %d", err)
+ 1    continue
+
+C    /* Remove the left-over file. */
+C      err = nf_delete(scratch)
+      if (err .ne. 0) call errore("remove failed", err)
+      end
+      
+C     This function looks in a file for the netCDF magic number.
+      integer function nf_get_file_version(path, version)
+      use tests
+      implicit none
+      
+      character*(*) path
+      integer version, iosnum
+      character magic*4
+      integer ver
+      integer f
+      parameter (f = 10)
+
+      open(f, file=path, status='OLD', form='UNFORMATTED',
+     +     access='DIRECT', recl=4)
+
+C     Assume this is not a netcdf file.
+      nf_get_file_version = NF_ENOTNC
+      version = 0
+
+C     Read the magic number, the first 4 bytes of the file.
+      read(f, rec=1, err = 1) magic
+
+C     If the first three characters are not "CDF" we're done.
+      if (index(magic, 'CDF') .eq. 1) then
+         ver = ichar(magic(4:4))
+         if (ver .eq. 1) then
+            version = 1
+            nf_get_file_version = NF_NOERR
+         elseif (ver .eq. 2) then
+            version = 2
+            nf_get_file_version = NF_NOERR
+         endif
+      endif
+
+ 1    close(f)
+      return
+      end
+
diff --git a/nf_test/tst03_f77_v2.F b/nf_test/tst03_f77_v2.F
new file mode 100755
index 0000000..7abf6fb
--- /dev/null
+++ b/nf_test/tst03_f77_v2.F
@@ -0,0 +1,73 @@
+C     This is part of netCDF, Copyright 2006, UCAR
+
+C     This test program uses the fortran 77 v2 API to create a simple
+C     data file with some phoney data in it. This program is heavily
+C     based on one contributed by Jeremy Kepner,
+C     jvkepner at astro.Princeton.EDU.
+
+C     This program will bail out in the event of a netcdf error.
+
+C     $Id: tst_f77_v2.F,v 1.2 2009/01/25 14:33:44 ed Exp $
+
+      PROGRAM tst_f77_v2
+      use tests      
+      IMPLICIT NONE
+
+
+      INTEGER n_dim,x_dim,y_dim,z_dim
+      PARAMETER(n_dim = 3, x_dim = 20, y_dim = 10, z_dim = 5)
+      INTEGER dim_array(n_dim)
+      INTEGER start(n_dim),count(n_dim)
+
+      INTEGER ncid, errcode
+      INTEGER x_id,y_id,z_id,arr_id
+      REAL array(x_dim,y_dim,z_dim)
+      INTEGER i,j,k
+
+C     Put something into the array.
+      DO i=1,x_dim
+         DO j=1,y_dim
+            DO k=1,z_dim
+               array(i,j,k) = (i-1) + x_dim*(j-1) + x_dim*y_dim*(k-1)
+            ENDDO
+         ENDDO
+      ENDDO
+
+      print *, ''
+      print *, ' *** Testing netCDF v2 api for F77.'
+
+C     Create file.
+      ncid = NCCRE('tst_f77_v2.nc', NCCLOB, errcode)
+
+C     Create Dimensions.
+      x_id = NCDDEF(ncid, 'X', x_dim, errcode)
+      y_id = NCDDEF(ncid, 'Y', y_dim, errcode)
+      z_id = NCDDEF(ncid, 'Z', z_dim, errcode)
+
+C     Create a variable.
+C     Assign dimensions to array.
+      dim_array(1) = z_id
+      dim_array(2) = y_id
+      dim_array(3) = x_id
+      arr_id = NCVDEF(ncid,'array',NCFLOAT,n_dim,dim_array,errcode)
+
+C     Skip attributes.
+
+C     Leave definitions.
+      CALL NCENDF(ncid, errcode)
+
+C     Write variable to file.
+      start(1) = 1
+      start(2) = 1
+      start(3) = 1
+      count(1) = z_dim
+      count(2) = y_dim
+      count(3) = x_dim
+      CALL NCVPT(ncid,arr_id,start,count,array,errcode)
+
+C     Close the file.
+      CALL NCCLOS(ncid, errcode)
+
+      print *, ' *** SUCCESS!'
+
+      END
diff --git a/nf_test/util03.F b/nf_test/util03.F
new file mode 100755
index 0000000..5d2a9e7
--- /dev/null
+++ b/nf_test/util03.F
@@ -0,0 +1,1496 @@
+#include "../fortran/nf03config.inc"
+!*********************************************************************
+!   Copyright 1996, UCAR/Unidata
+!   See netcdf/COPYRIGHT file for copying and redistribution conditions.
+!   $Id: util.F,v 1.16 2008/12/31 17:54:10 ed Exp $
+!********************************************************************/
+
+! Implementation of util.F for F03 interfaces
+
+      SUBROUTINE PRINT_NOK(NOK)
+      use tests, ONLY: NFAILS, VERBOSE
+      IMPLICIT  NONE
+      INTEGER   NOK
+
+      IF (VERBOSE .OR. NFAILS .GT. 0) PRINT *, ' '
+      IF (VERBOSE) PRINT *, NOK, ' good comparisons.'
+      END
+
+
+! Is value within external type range? */
+      FUNCTION INRANGE(VALUE, DATATYPE)
+      use tests, ONLY: NF_CHAR, NF_BYTE, NF_SHORT, NF_INT, NF_FLOAT,    &
+     &                 NF_DOUBLE, X_CHAR_MIN, X_CHAR_MAX, X_BYTE_MIN,   &
+     &                 X_BYTE_MAX, X_SHORT_MIN, X_SHORT_MAX, X_INT_MIN, &
+     &                 X_INT_MAX, X_FLOAT_MIN, X_FLOAT_MAX,             &
+     &                 X_DOUBLE_MIN, X_DOUBLE_MAX
+
+      IMPLICIT  NONE
+      DOUBLEPRECISION   VALUE
+      INTEGER           DATATYPE
+      LOGICAL           INRANGE
+
+      DOUBLEPRECISION   MIN
+      DOUBLEPRECISION   MAX
+
+      IF (DATATYPE .EQ. NF_CHAR) THEN
+          MIN = X_CHAR_MIN
+          MAX = X_CHAR_MAX
+      ELSE IF (DATATYPE .EQ. NF_BYTE) THEN
+          MIN = X_BYTE_MIN
+          MAX = X_BYTE_MAX
+      ELSE IF (DATATYPE .EQ. NF_SHORT) THEN
+          MIN = X_SHORT_MIN
+          MAX = X_SHORT_MAX
+      ELSE IF (DATATYPE .EQ. NF_INT) THEN
+          MIN = X_INT_MIN
+          MAX = X_INT_MAX
+      ELSE IF (DATATYPE .EQ. NF_FLOAT) THEN
+          MIN = X_FLOAT_MIN
+          MAX = X_FLOAT_MAX
+      ELSE IF (DATATYPE .EQ. NF_DOUBLE) THEN
+          MIN = X_DOUBLE_MIN
+          MAX = X_DOUBLE_MAX
+      ELSE
+          CALL UDABORT
+      END IF
+
+      INRANGE = (VALUE .GE. MIN) .AND. (VALUE .LE. MAX)
+      END
+
+
+      FUNCTION INRANGE_UCHAR(VALUE, DATATYPE)
+      use tests, ONLY: NF_BYTE, INRANGE
+      IMPLICIT  NONE
+      DOUBLEPRECISION   VALUE
+      INTEGER           DATATYPE
+      LOGICAL INRANGE_UCHAR
+
+      IF (DATATYPE .EQ. NF_BYTE) THEN
+          INRANGE_UCHAR = (VALUE .GE. 0) .AND. (VALUE .LE. 255)
+      ELSE
+          INRANGE_UCHAR = INRANGE(VALUE, DATATYPE)
+      END IF
+      END
+
+
+      FUNCTION INRANGE_FLOAT(VALUE, DATATYPE)
+      use tests, ONLY: NF_CHAR, NF_BYTE, NF_SHORT, NF_INT, NF_FLOAT,    &
+     &                 NF_DOUBLE, X_CHAR_MIN, X_CHAR_MAX, X_BYTE_MIN,   &
+     &                 X_BYTE_MAX, X_SHORT_MIN, X_SHORT_MAX, X_INT_MIN, &
+     &                 X_INT_MAX, X_FLOAT_MIN, X_FLOAT_MAX, NFT_REAL,   &
+     &                 X_DOUBLE_MIN, X_DOUBLE_MAX, internal_max
+      IMPLICIT  NONE
+      DOUBLEPRECISION   VALUE
+      INTEGER           DATATYPE
+      LOGICAL INRANGE_FLOAT
+
+      DOUBLEPRECISION   MIN
+      DOUBLEPRECISION   MAX
+      REAL              FVALUE
+
+      IF (DATATYPE .EQ. NF_CHAR) THEN
+          MIN = X_CHAR_MIN
+          MAX = X_CHAR_MAX
+      ELSE IF (DATATYPE .EQ. NF_BYTE) THEN
+          MIN = X_BYTE_MIN
+          MAX = X_BYTE_MAX
+      ELSE IF (DATATYPE .EQ. NF_SHORT) THEN
+          MIN = X_SHORT_MIN
+          MAX = X_SHORT_MAX
+      ELSE IF (DATATYPE .EQ. NF_INT) THEN
+          MIN = X_INT_MIN
+          MAX = X_INT_MAX
+      ELSE IF (DATATYPE .EQ. NF_FLOAT) THEN
+          IF (internal_max(NFT_REAL) .LT. X_FLOAT_MAX) THEN
+              MIN = -internal_max(NFT_REAL)
+              MAX = internal_max(NFT_REAL)
+          ELSE
+              MIN = X_FLOAT_MIN
+              MAX = X_FLOAT_MAX
+          END IF
+      ELSE IF (DATATYPE .EQ. NF_DOUBLE) THEN
+          IF (internal_max(NFT_REAL) .LT. X_DOUBLE_MAX) THEN
+              MIN = -internal_max(NFT_REAL)
+              MAX = internal_max(NFT_REAL)
+          ELSE
+              MIN = X_DOUBLE_MIN
+              MAX = X_DOUBLE_MAX
+          END IF
+      ELSE
+          CALL UDABORT
+      END IF
+
+      IF (.NOT.((VALUE .GE. MIN) .AND. (VALUE .LE. MAX))) THEN
+          INRANGE_FLOAT = .FALSE.
+      ELSE
+          FVALUE = VALUE
+          INRANGE_FLOAT = (FVALUE .GE. MIN) .AND. (FVALUE .LE. MAX)
+      END IF
+      END
+
+
+! wrapper for inrange to handle special NF_BYTE/uchar adjustment */
+      function inrange3(value, datatype, itype)
+      use tests, ONLY: NFT_REAL, inrange, inrange_float
+      implicit          none
+      doubleprecision   value
+      integer           datatype
+      integer           itype
+      logical inrange3
+
+      if (itype .eq. NFT_REAL) then
+          inrange3 = inrange_float(value, datatype)
+      else
+          inrange3 = inrange(value, datatype)
+      end if
+      end
+
+
+!
+!  Does x == y, where one is internal and other external (netCDF)?  
+!  Use tolerant comparison based on IEEE FLT_EPSILON or DBL_EPSILON.
+!
+      function equal(x, y, extType, itype)
+      use tests, ONLY: NF_REAL, NFT_REAL
+      implicit  none
+      doubleprecision   x
+      doubleprecision   y
+      integer           extType         !!/* external data type */
+      integer           itype
+      logical equal
+      doubleprecision   epsilon
+
+      if ((extType .eq. NF_REAL) .or. (itype .eq. NFT_REAL)) then
+          epsilon = 1.19209290E-07
+      else
+          epsilon = 2.2204460492503131E-16
+      end if
+      equal = abs(x-y) .le. epsilon * max( abs(x), abs(y))
+      end
+
+
+! Test whether two int vectors are equal. If so return 1, else 0  */
+        function int_vec_eq(v1, v2, n)
+!        use tests
+        implicit        none
+        integer n
+        integer v1(n)
+        integer v2(n)
+
+        integer i
+        logical int_vec_eq
+
+        int_vec_eq = .true.
+
+        if (n .le. 0)
+     +      return
+
+        do 1, i=1, n
+            if (v1(i) .ne. v2(i)) then
+                int_vec_eq = .false.
+                return
+            end if
+1       continue
+        end
+
+
+!
+!  Generate random integer from 0 through n-1
+!  Like throwing an n-sided dice marked 0, 1, 2, ..., n-1
+!
+      function roll(n)
+!      use tests
+      implicit  none
+      integer   n
+      integer roll
+      doubleprecision   udrand
+      external          udrand
+      
+1     roll = (udrand(0) * (n-1)) + 0.5
+      if (roll .ge. n) goto 1
+      end
+
+
+!
+!      Convert an origin-1 cumulative index to a netCDF index vector.
+!       Grosset dimension first; finest dimension last.
+!
+!      Authors: Harvey Davies, Unidata/UCAR, Boulder, Colorado
+!                Steve Emmerson, (same place)
+!
+        function index2ncindexes(index, rank, base, indexes)
+!        use tests
+        implicit        none
+        integer         index           !!/* index to be converted */
+        integer         rank            !/* number of dimensions */
+        integer         base(rank)      !/* base(rank) ignored */
+        integer         indexes(rank)   !/* returned FORTRAN indexes */
+
+        integer i
+        integer offset
+        integer index2ncindexes
+
+        if (rank .gt. 0) then
+            offset = index - 1
+            do 1, i = rank, 1, -1
+                if (base(i) .eq. 0) then
+                    index2ncindexes = 1
+                    return
+                end if
+                indexes(i) = 1 + mod(offset, base(i))
+                offset = offset / base(i)
+1           continue
+        end if
+        index2ncindexes = 0
+        end
+
+
+!
+!      Convert an origin-1 cumulative index to a FORTRAN index vector.
+!       Finest dimension first; grossest dimension last.
+!
+!      Authors: Harvey Davies, Unidata/UCAR, Boulder, Colorado
+!                Steve Emmerson, (same place)
+!
+        function index2indexes(index, rank, base, indexes)
+!        use tests
+        implicit        none
+        integer         index           !/* index to be converted */
+        integer         rank            !/* number of dimensions */
+        integer         base(rank)      !/* base(rank) ignored */
+        integer         indexes(rank)   !/* returned FORTRAN indexes */
+        integer         index2indexes
+        integer i
+        integer offset
+
+        if (rank .gt. 0) then
+            offset = index - 1
+            do 1, i = 1, rank
+                if (base(i) .eq. 0) then
+                    index2indexes = 1
+                    return
+                end if
+                indexes(i) = 1 + mod(offset, base(i))
+                offset = offset / base(i)
+1           continue
+        end if
+        index2indexes = 0
+        end
+
+
+!
+!      Convert a FORTRAN index vector to an origin-1 cumulative index.
+!       Finest dimension first; grossest dimension last.
+!
+!      Authors: Harvey Davies, Unidata/UCAR, Boulder, Colorado
+!                Steve Emmerson, (same place)
+!
+        function indexes2index(rank, indexes, base)
+!        use tests
+        implicit        none
+        integer         rank            !/* number of dimensions */
+        integer         indexes(rank)   !/* FORTRAN indexes */
+        integer         base(rank)      !/* base(rank) ignored */
+        integer  indexes2index
+        integer i
+
+        indexes2index = 0
+        if (rank .gt. 0) then
+            do 1, i = rank, 1, -1
+                indexes2index = (indexes2index-1) * base(i) + indexes(i)
+1           continue
+        end if
+        end
+
+
+#ifdef USE_EXTREME_NUMBERS
+! Generate data values as function of type, rank (-1 for attribute), index */
+      function hash(type, rank, index) 
+      use tests, ONLY: NF_CHAR, NF_BYTE, NF_SHORT, NF_INT, NF_FLOAT,    &
+     &                 NF_DOUBLE, X_CHAR_MIN, X_CHAR_MAX, X_BYTE_MIN,   &
+     &                 X_BYTE_MAX, X_SHORT_MIN, X_SHORT_MAX, X_INT_MIN, &
+     &                 X_INT_MAX, X_FLOAT_MIN, X_FLOAT_MAX,             &
+     &                 X_DOUBLE_MIN, X_DOUBLE_MAX, RK8
+      implicit  none
+      integer   type
+      integer   rank
+      integer   index(*)
+      real(RK8) hash
+
+      doubleprecision   base
+      doubleprecision   result
+      integer           d       !/* index of dimension */
+
+        !/* If vector then elements 1 & 2 are min & max. Elements 3 & 4 are */
+        !/* just < min & > max (except for NF_CHAR & NF_DOUBLE) */
+      if (abs(rank) .eq. 1 .and. index(1) .le. 4) then
+          if (index(1) .eq. 1) then
+              if (type .eq. NF_CHAR) then
+                  hash = X_CHAR_MIN
+              else if (type .eq. NF_BYTE) then
+                  hash = X_BYTE_MIN
+              else if (type .eq. NF_SHORT) then
+                  hash = X_SHORT_MIN
+              else if (type .eq. NF_INT) then
+                  hash = X_INT_MIN
+              else if (type .eq. NF_FLOAT) then
+                  hash = X_FLOAT_MIN
+              else if (type .eq. NF_DOUBLE) then
+                  hash = X_DOUBLE_MIN
+              else
+                  call udabort
+              end if
+          else if (index(1) .eq. 2) then
+              if (type .eq. NF_CHAR) then
+                  hash = X_CHAR_MAX
+              else if (type .eq. NF_BYTE) then
+                  hash = X_BYTE_MAX
+              else if (type .eq. NF_SHORT) then
+                  hash = X_SHORT_MAX
+              else if (type .eq. NF_INT) then
+                  hash = X_INT_MAX
+              else if (type .eq. NF_FLOAT) then
+                  hash = X_FLOAT_MAX
+              else if (type .eq. NF_DOUBLE) then
+                  hash = X_DOUBLE_MAX
+              else
+                  call udabort
+              end if
+          else if (index(1) .eq. 3) then
+              if (type .eq. NF_CHAR) then
+                  hash = ichar('A')
+              else if (type .eq. NF_BYTE) then
+                  hash = X_BYTE_MIN-1.0
+              else if (type .eq. NF_SHORT) then
+                  hash = X_SHORT_MIN-1.0
+              else if (type .eq. NF_INT) then
+                  hash = X_INT_MIN
+              else if (type .eq. NF_FLOAT) then
+                  hash = X_FLOAT_MIN
+              else if (type .eq. NF_DOUBLE) then
+                  hash = -1.0
+              else
+                  call udabort
+              end if
+          else if (index(1) .eq. 4) then
+              if (type .eq. NF_CHAR) then
+                  hash = ichar('Z')
+              else if (type .eq. NF_BYTE) then
+                  hash = X_BYTE_MAX+1.0
+              else if (type .eq. NF_SHORT) then
+                  hash = X_SHORT_MAX+1.0
+              else if (type .eq. NF_INT) then
+                  hash = X_INT_MAX+1.0
+              else if (type .eq. NF_FLOAT) then
+                  hash = X_FLOAT_MAX
+              else if (type .eq. NF_DOUBLE) then
+                  hash = 1.0
+              else
+                  call udabort
+              end if
+          end if
+      else
+          if (type .eq. NF_CHAR) then
+              base = 2
+          else if (type .eq. NF_BYTE) then
+              base = -2
+          else if (type .eq. NF_SHORT) then
+              base = -5
+          else if (type .eq. NF_INT) then
+              base = -20
+          else if (type .eq. NF_FLOAT) then
+              base = -9
+          else if (type .eq. NF_DOUBLE) then
+              base = -10
+          else
+              stop 2
+          end if
+
+          if (rank .lt. 0) then
+              result = base * 7
+          else
+              result = base * (rank + 1)
+          end if
+
+!         /*
+!          * NB: Finest netCDF dimension assumed first.
+!          */
+          do 1, d = abs(rank), 1, -1
+              result = base * (result + index(d) - 1)
+1         continue
+          hash = result
+      end if
+      end
+#else /* USE_EXTREME_NUMBERS */
+#define SANE_SHORT 3333
+#define SANE_INT 2222
+#define SANE_FLOAT 300.0
+#define SANE_DOUBLE 1000.0
+
+! Generate data values as function of type, rank (-1 for attribute), index */
+      function hash(type, rank, index) 
+      use tests, ONLY: NF_CHAR, NF_BYTE, NF_SHORT, NF_INT, NF_FLOAT,    &
+     &                 NF_DOUBLE, X_CHAR_MIN, X_CHAR_MAX, X_BYTE_MIN,   &
+     &                 X_BYTE_MAX, X_SHORT_MIN, X_SHORT_MAX, X_INT_MIN, &
+     &                 X_INT_MAX, X_FLOAT_MIN, X_FLOAT_MAX,             &
+     &                 X_DOUBLE_MIN, X_DOUBLE_MAX, RK8
+      implicit  none
+      integer   type
+      integer   rank
+      integer   index(*)
+
+      real(RK8) hash
+      doubleprecision   base
+      doubleprecision   result
+      integer           d       !/* index of dimension */
+
+        !/* If vector then elements 1 & 2 are min & max. Elements 3 & 4 are */
+        !/* just < min & > max (except for NF_CHAR & NF_DOUBLE) */
+      if (abs(rank) .eq. 1 .and. index(1) .le. 4) then
+          if (index(1) .eq. 1) then
+              if (type .eq. NF_CHAR) then
+                  hash = X_CHAR_MIN
+              else if (type .eq. NF_BYTE) then
+                  hash = X_BYTE_MIN
+              else if (type .eq. NF_SHORT) then
+                  hash = SANE_SHORT
+              else if (type .eq. NF_INT) then
+                  hash = SANE_INT
+              else if (type .eq. NF_FLOAT) then
+                  hash = SANE_FLOAT
+              else if (type .eq. NF_DOUBLE) then
+                  hash = SANE_DOUBLE
+              else
+                  call udabort
+              end if
+          else if (index(1) .eq. 2) then
+              if (type .eq. NF_CHAR) then
+                  hash = X_CHAR_MAX
+              else if (type .eq. NF_BYTE) then
+                  hash = X_BYTE_MAX
+              else if (type .eq. NF_SHORT) then
+                  hash = SANE_SHORT
+              else if (type .eq. NF_INT) then
+                  hash = SANE_INT
+              else if (type .eq. NF_FLOAT) then
+                  hash = SANE_FLOAT
+              else if (type .eq. NF_DOUBLE) then
+                  hash = SANE_DOUBLE
+              else
+                  call udabort
+              end if
+          else if (index(1) .eq. 3) then
+              if (type .eq. NF_CHAR) then
+                  hash = ichar('A')
+              else if (type .eq. NF_BYTE) then
+                  hash = X_BYTE_MIN-1.0
+              else if (type .eq. NF_SHORT) then
+                  hash = SANE_SHORT-1.0
+              else if (type .eq. NF_INT) then
+                  hash = SANE_INT
+              else if (type .eq. NF_FLOAT) then
+                  hash = SANE_FLOAT
+              else if (type .eq. NF_DOUBLE) then
+                  hash = -1.0
+              else
+                  call udabort
+              end if
+          else if (index(1) .eq. 4) then
+              if (type .eq. NF_CHAR) then
+                  hash = ichar('Z')
+              else if (type .eq. NF_BYTE) then
+                  hash = X_BYTE_MAX+1.0
+              else if (type .eq. NF_SHORT) then
+                  hash = SANE_SHORT+1.0
+              else if (type .eq. NF_INT) then
+                  hash = SANE_INT+1.0
+              else if (type .eq. NF_FLOAT) then
+                  hash = SANE_FLOAT
+              else if (type .eq. NF_DOUBLE) then
+                  hash = 1.0
+              else
+                  call udabort
+              end if
+          end if
+      else
+          if (type .eq. NF_CHAR) then
+              base = 2
+          else if (type .eq. NF_BYTE) then
+              base = -2
+          else if (type .eq. NF_SHORT) then
+              base = -5
+          else if (type .eq. NF_INT) then
+              base = -20
+          else if (type .eq. NF_FLOAT) then
+              base = -9
+          else if (type .eq. NF_DOUBLE) then
+              base = -10
+          else
+              stop 2
+          end if
+
+          if (rank .lt. 0) then
+              result = base * 7
+          else
+              result = base * (rank + 1)
+          end if
+
+!         /*
+!          * NB: Finest netCDF dimension assumed first.
+!          */
+          do 1, d = abs(rank), 1, -1
+              result = base * (result + index(d) - 1)
+1         continue
+          hash = result
+      end if
+      end
+#endif
+
+! wrapper for hash to handle special NC_BYTE/uchar adjustment */
+      function hash4(type, rank, index, itype)
+      use tests, ONLY: NFT_CHAR, NF_BYTE, RK8, hash
+      implicit  none
+      integer   type
+      integer   rank
+      integer   index(*)
+      integer   itype
+      real(RK8) hash4
+
+      hash4 = hash( type, rank, index )
+      if ((itype .eq. NFT_CHAR) .and. (type .eq. NF_BYTE) .and. 
+     +    (hash4 .ge. -128) .and. (hash4 .lt. 0)) hash4 = hash4 + 256
+      end
+
+
+      integer function char2type(letter)
+      use tests, ONLY: NF_CHAR, NF_SHORT, NF_BYTE, NF_INT, NF_FLOAT,    &
+     &                 NF_DOUBLE
+      implicit          none
+      character*1       letter
+
+      if (letter .eq. 'c') then
+          char2type = NF_CHAR
+      else if (letter .eq. 'b') then
+          char2type = NF_BYTE
+      else if (letter .eq. 's') then
+          char2type = NF_SHORT
+      else if (letter .eq. 'i') then
+          char2type = NF_INT
+      else if (letter .eq. 'f') then
+          char2type = NF_FLOAT
+      else if (letter .eq. 'd') then
+          char2type = NF_DOUBLE
+      else
+        stop 2
+      end if
+      end
+
+
+      subroutine init_dims(digit)
+      use tests, ONLY: NDIMS, RECDIM, NRECS, DIM_LEN, DIM_NAME
+      implicit          none
+      character*1       digit(NDIMS)
+
+      integer   dimid                   !/* index of dimension */
+      do 1, dimid = 1, NDIMS
+          if (dimid .eq. RECDIM) then
+              dim_len(dimid) = NRECS
+          else
+              dim_len(dimid) = dimid - 1
+          endif
+          dim_name(dimid) = 'D' // digit(dimid)
+1     continue
+      end
+
+
+      subroutine init_gatts(type_letter)
+      use tests, ONLY: NTYPES, gatt_name, gatt_len, gatt_type
+      implicit          none
+      character*1       type_letter(NTYPES)
+
+      integer   attid
+      integer   char2type
+
+      do 1, attid = 1, NTYPES
+          gatt_name(attid) = 'G' // type_letter(attid)
+          gatt_len(attid) = attid
+          gatt_type(attid) = char2type(type_letter(attid))
+1     continue
+      end
+
+
+      integer function prod(nn, sp)
+      use tests, ONLY: MAX_RANK
+      implicit  none
+      integer   nn
+      integer   sp(MAX_RANK)
+
+      integer   i
+
+      prod = 1
+      do 1, i = 1, nn
+          prod = prod * sp(i)
+1     continue
+      end
+
+
+!
+!   define global variables:
+!   dim_name, dim_len, 
+!   var_name, var_type, var_rank, var_shape, var_natts, var_dimid, var_nels
+!   att_name, gatt_name, att_type, gatt_type, att_len, gatt_len
+!
+        subroutine init_gvars 
+        use tests, NTYPESP=>NTYPES, MAX_DIM_LENP=>MAX_DIM_LEN,          &
+     &             NVARSP=>NVARS
+        implicit        none
+
+        integer         max_dim_len(MAX_RANK)
+        character*1     type_letter(NTYPESP)
+        character*1     digit(10)
+
+        integer rank
+        integer vn              !/* var number */
+        integer xtype           !/* index of type */
+        integer an              !/* origin-0 cumulative attribute index */
+        integer nvars
+        integer jj
+        integer ntypes
+        integer tc
+        integer tmp(MAX_RANK)
+        integer ac              !/* attribute index */
+        integer dn              !/* dimension number */
+        integer prod            !/* function */
+        integer char2type       !/* function */
+        integer err
+
+        data    max_dim_len     /0, MAX_DIM_LENP, MAX_DIM_LENP/
+        data    type_letter     /'c', 'b', 's', 'i', 'f', 'd'/
+        data    digit           /'r', '1', '2', '3', '4', '5',
+     +                           '6', '7', '8', '9'/
+
+        max_dim_len(1) = MAX_DIM_LENP + 1
+
+        call init_dims(digit)
+
+        vn = 1
+        xtype = 1
+        an = 0
+
+!       /* Loop over variable ranks */
+        do 1, rank = 0, MAX_RANK
+            nvars = prod(rank, max_dim_len)
+
+            !/* Loop over variable shape vectors */
+            do 2, jj = 1, nvars                         !/* 1, 5, 20, 80 */
+                !/* number types of this shape */
+                if (rank .lt. 2) then
+                    ntypes = NTYPESP                     !/* 6 */
+                else
+                    ntypes = 1
+                end if
+
+                !/* Loop over external data types */
+                do 3, tc = 1, ntypes                    !/* 6, 1 */
+                    var_name(vn) = type_letter(xtype)
+                    var_type(vn) = char2type(type_letter(xtype))
+                    var_rank(vn) = rank
+                    if (rank .eq. 0) then
+                        var_natts(vn) = mod(vn - 1, MAX_NATTS + 1)
+                    else
+                        var_natts(vn) = 0
+                    end if
+
+                    do 4, ac = 1, var_natts(vn)
+                        attname(ac,vn) = 
+     +                      type_letter(1+mod(an, NTYPESP))
+                        attlen(ac,vn) = an
+                        atttype(ac,vn) =
+     +                      char2type(type_letter(1+mod(an, NTYPESP)))
+                        an = an + 1
+4                   continue
+
+                    !/* Construct initial shape vector */
+                    err = index2ncindexes(jj, rank, max_dim_len, tmp)
+                    do 5, dn = 1, rank
+                        var_dimid(dn,vn) = tmp(1+rank-dn)
+5                   continue
+
+                    var_nels(vn) = 1
+                    do 6, dn = 1, rank
+                        if (dn .lt. rank) then
+                            var_dimid(dn,vn) = var_dimid(dn,vn) + 1
+                        end if
+                        if (var_dimid(dn,vn) .gt. 9) then
+                            stop 2
+                        end if
+                        var_name(vn)(rank+2-dn:rank+2-dn) = 
+     +                      digit(var_dimid(dn,vn))
+                        if (var_dimid(dn,vn) .ne. RECDIM) then
+                            var_shape(dn,vn) = var_dimid(dn,vn) - 1
+                        else
+                            var_shape(dn,vn) = NRECS
+                        end if
+                        var_nels(vn) = var_nels(vn) * var_shape(dn,vn)
+6                   continue
+
+                    vn = vn + 1
+                    xtype = 1 + mod(xtype, NTYPESP)
+3               continue
+2           continue
+1       continue
+
+        call init_gatts(type_letter)
+        end
+
+
+! define dims defined by global variables */
+        subroutine def_dims(ncid)
+        use tests
+        implicit        none
+        integer         ncid
+
+        integer         err             !/* status */
+        integer         i
+        integer         dimid           !/* dimension id */
+
+        do 1, i = 1, NDIMS
+            if (i .eq. RECDIM) then
+                err = nf_def_dim(ncid, dim_name(i), NF_UNLIMITED,
+     +                           dimid)
+            else
+                err = nf_def_dim(ncid, dim_name(i), dim_len(i),
+     +                           dimid)
+            end if
+            if (err .ne. 0) then
+                call errore('nf_def_dim: ', err)
+            end if
+1       continue
+        end
+
+
+! define vars defined by global variables */
+        subroutine def_vars(ncid)
+        use tests
+        implicit        none
+        integer         ncid
+
+        integer         err             !/* status */
+        integer         i
+        integer         var_id
+
+        do 1, i = 1, NVARS
+            err = nf_def_var(ncid, var_name(i), var_type(i), 
+     +                       var_rank(i), var_dimid(1,i), var_id)
+            if (err .ne. 0) then
+                call errore('nf_def_var: ', err)
+            end if
+1       continue
+        end
+
+
+! put attributes defined by global variables */
+        subroutine put_atts(ncid)
+        use tests
+        implicit        none
+        integer         ncid
+
+        integer                 err             !/* netCDF status */
+        integer                 i               !/* variable index (0 => global 
+                                                ! * attribute */
+        integer                 k               !/* attribute index */
+        integer                 j               !/* index of attribute */
+        integer                 ndx(1)
+        logical                 allInRange
+
+        doubleprecision         att(MAX_NELS)
+        character*(MAX_NELS+2)  catt
+
+        do 1, i = 0, NVARS      !/* var 0 => NF_GLOBAL attributes */
+            do 2, j = 1, NATTS(i)
+                if (NF_CHAR .eq. ATT_TYPE(j,i)) then
+                    catt = ' '
+                    do 3, k = 1, ATT_LEN(j,i)
+                        ndx(1) = k
+                        catt(k:k) = char(int(hash(ATT_TYPE(j,i), -1, 
+     +                                   ndx)))
+3                   continue
+!                   /*
+!                    * The following ensures that the text buffer doesn't
+!                    * start with 4 zeros (which is a CFORTRAN NULL pointer
+!                    * indicator) yet contains a zero (which causes the
+!                    * CFORTRAN interface to pass the address of the
+!                    * actual text buffer).
+!                    */
+                    catt(ATT_LEN(j,i)+1:ATT_LEN(j,i)+1) = char(1)
+                    catt(ATT_LEN(j,i)+2:ATT_LEN(j,i)+2) = char(0)
+
+                    err = nf_put_att_text(ncid, varid(i), 
+     +                                    ATT_NAME(j,i),
+     +                                    ATT_LEN(j,i), catt)
+                    if (err .ne. 0) then
+                        call errore('nf_put_att_text: ', err)
+                    end if
+                else
+                    allInRange = .true.
+                    do 4, k = 1, ATT_LEN(j,i)
+                        ndx(1) = k
+                        att(k) = hash(ATT_TYPE(j,i), -1, ndx)
+                        allInRange = allInRange .and.
+     +                               inRange(att(k), ATT_TYPE(j,i))
+4                   continue
+                    err = nf_put_att_double(ncid, varid(i),
+     +                                      ATT_NAME(j,i),
+     +                                      ATT_TYPE(j,i),
+     +                                      ATT_LEN(j,i), att)
+                    if (allInRange) then
+                        if (err .ne. 0) then
+                            call errore('nf_put_att_double: ', err)
+                        end if
+                    else
+                        if (err .ne. NF_ERANGE) then
+                            call errore(
+     +                  'type-conversion range error: status = ',
+     +                          err)
+                        end if
+                    end if
+                end if
+2           continue
+1       continue
+        end
+
+
+! put variables defined by global variables */
+        subroutine put_vars(ncid)
+        use tests
+        implicit        none
+        integer                 ncid
+
+        integer                 start(MAX_RANK)
+        integer                 index(MAX_RANK)
+        integer                 err             !/* netCDF status */
+        integer                 i
+        integer                 j
+        doubleprecision         value(MAX_NELS)
+        character*(MAX_NELS+2)  text
+        logical                 allInRange
+
+        do 1, j = 1, MAX_RANK
+            start(j) = 1
+1       continue
+
+        do 2, i = 1, NVARS
+            allInRange = .true.
+            do 3, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                              index)
+                if (err .ne. 0) then
+                    call errori(
+     +                  'Error calling index2indexes() for var ', j)
+                end if
+                if (var_name(i)(1:1) .eq. 'c') then
+                    text(j:j) = 
+     +                  char(int(hash(var_type(i), var_rank(i), index)))
+                else
+                    value(j)  = hash(var_type(i), var_rank(i), index)
+                    allInRange = allInRange .and.
+     +                  inRange(value(j), var_type(i))
+                end if
+3           continue
+            if (var_name(i)(1:1) .eq. 'c') then
+!               /*
+!                * The following statement ensures that the first 4
+!                * characters in 'text' are not all zeros (which is
+!                * a cfortran.h NULL indicator) and that the string
+!                * contains a zero (which will cause the address of the
+!                * actual string buffer to be passed).
+!                */
+                text(var_nels(i)+1:var_nels(i)+1) = char(1)
+                text(var_nels(i)+2:var_nels(i)+2) = char(0)
+                err = nf_put_vara_text(ncid, i, start, var_shape(1:,i), & 
+     &                                 text)
+                if (err .ne. 0) then
+                    call errore('nf_put_vara_text: ', err)
+                end if
+            else
+                err = nf_put_vara_double(ncid, i, start,var_shape(1:,i),&
+     &                                   value)
+                if (allInRange) then
+                    if (err .ne. 0) then
+                        call errore('nf_put_vara_double: ', err)
+                    end if
+                else
+                    if (err .ne. NF_ERANGE) then                        &
+                        call errore(                                    & 
+     &                      'type-conversion range error: status = ',   & 
+     &                      err)
+                    end if
+                end if
+            end if
+2       continue
+        end
+
+
+! Create & write all of specified file using global variables */
+        subroutine write_file(filename) 
+        use tests
+        implicit        none
+        character*(*)   filename
+
+        integer ncid            !/* netCDF id */
+        integer err             !/* netCDF status */
+
+        err = nf_create(filename, NF_CLOBBER, ncid)
+        if (err .ne. 0) then
+            call errore('nf_create: ', err)
+        end if
+
+        call def_dims(ncid)
+        call def_vars(ncid)
+        call put_atts(ncid)
+        err = nf_enddef(ncid)
+        if (err .ne. 0) then
+            call errore('nf_enddef: ', err)
+        end if
+        call put_vars(ncid)
+
+        err = nf_close(ncid)
+        if (err .ne. 0) then
+            call errore('nf_close: ', err)
+        end if
+        end
+
+
+!
+! check dimensions of specified file have expected name & length
+!
+        subroutine check_dims(ncid)
+        use tests
+        implicit        none
+        integer         ncid
+
+        character*(NF_MAX_NAME) name
+        integer                 length
+        integer                 i
+        integer                 err           !/* netCDF status */
+
+        do 1, i = 1, NDIMS
+            err = nf_inq_dim(ncid, i, name, length)
+            if (err .ne. 0) then
+                call errore('nf_inq_dim: ', err)
+            end if
+            if (name .ne. dim_name(i)) then
+                call errori('Unexpected name of dimension ', i)
+            end if
+            if (length .ne. dim_len(i)) then
+                call errori('Unexpected length of dimension ', i)
+            end if
+1       continue
+        end
+
+
+!
+! check variables of specified file have expected name, type, shape & values
+!
+        subroutine check_vars(ncid)
+        use tests, NDIMSP=>NDIMS
+        implicit        none
+        integer         ncid
+
+        integer                 index(MAX_RANK)
+        integer                 err             !/* netCDF status */
+        integer                 i
+        integer                 j
+        character*1             text
+        doubleprecision         value
+        integer                 datatype
+        integer                 ndims
+        integer                 natt
+        integer                 dimids(MAX_RANK)
+        logical                 isChar
+        doubleprecision         expect
+        character*(NF_MAX_NAME) name
+        integer                 length
+        integer                 nok             !/* count of valid comparisons */
+
+        nok = 0
+
+        do 1, i = 1, NVARS
+            isChar = var_type(i) .eq. NF_CHAR
+            err = nf_inq_var(ncid, i, name, datatype, ndims, dimids, 
+     +          natt)
+            if (err .ne. 0) then
+                call errore('nf_inq_var: ', err)
+            end if
+            if (name .ne. var_name(i)) then
+                call errori('Unexpected var_name for variable ', i)
+            end if
+            if (datatype .ne. var_type(i))  then
+                call errori('Unexpected type for variable ', i)
+            end if
+            if (ndims .ne. var_rank(i))  then
+                call errori('Unexpected rank for variable ', i)
+            end if
+            do 2, j = 1, ndims
+                err = nf_inq_dim(ncid, dimids(j), name, length)
+                if (err .ne. 0) then
+                    call errore('nf_inq_dim: ', err)
+                end if
+                if (length .ne. var_shape(j,i))  then
+                    call errori('Unexpected shape for variable ', i)
+                end if
+2           continue
+            do 3, j = 1, var_nels(i)
+                err = index2indexes(j, var_rank(i), var_shape(1,i), 
+     +                  index)
+                if (err .ne. 0)  then
+                    call errori('error in index2indexes() 2, variable ',
+     +                          i)
+                end if
+                expect = hash(var_type(i), var_rank(i), index )
+                if (isChar) then
+                    err = nf_get_var1_text(ncid, i, index, text)
+                    if (err .ne. 0) then
+                        call errore('nf_get_var1_text: ', err)
+                    end if
+                    if (ichar(text) .ne. expect) then
+                        call errori(
+     +              'Var value read not that expected for variable ', i)
+                    else
+                        nok = nok + 1
+                    end if
+                else
+                    err = nf_get_var1_double(ncid, i, index, value)
+                    if (inRange(expect,var_type(i))) then
+                        if (err .ne. 0) then
+                            call errore('nf_get_var1_double: ', err)
+                        else
+                            if (.not. equal(value,expect,var_type(i),
+     +                          NFT_DOUBLE)) then
+                                call errori(
+     +              'Var value read not that expected for variable ', i)
+                            else
+                                nok = nok + 1
+                            end if
+                        end if
+                    end if
+                end if
+3           continue
+1       continue
+        call print_nok(nok)
+        end
+
+
+!
+! check attributes of specified file have expected name, type, length & values
+!
+        subroutine check_atts(ncid) 
+        use tests
+        implicit        none
+        integer         ncid
+
+        integer                 err             !/* netCDF status */
+        integer                 i
+        integer                 j
+        integer                 k
+        integer                 vid             !/* "variable" ID */
+        integer                 datatype
+        integer                 ndx(1)
+        character*(NF_MAX_NAME) name
+        integer                 length
+        character*(MAX_NELS)    text
+        doubleprecision         value(MAX_NELS)
+        doubleprecision         expect
+        integer                 nok             !/* count of valid comparisons */
+
+        nok = 0
+
+        do 1, vid = 0, NVARS
+            i = varid(vid)
+
+            do 2, j = 1, NATTS(i)
+                err = nf_inq_attname(ncid, i, j, name)
+                if (err .ne. 0) then
+                    call errore('nf_inq_attname: ', err)
+                end if
+                if (name .ne. ATT_NAME(j,i)) then
+                    call errori(
+     +                  'nf_inq_attname: unexpected name for var ', i)
+                end if
+                err = nf_inq_att(ncid, i, name, datatype, length)
+                if (err .ne. 0) then
+                    call errore('nf_inq_att: ', err)
+                end if
+                if (datatype .ne. ATT_TYPE(j,i)) then
+                    call errori('nf_inq_att: unexpected type for var ',
+     +                         i)
+                end if
+                if (length .ne. ATT_LEN(j,i)) then
+                    call errori(
+     +                  'nf_inq_att: unexpected length for var ', i)
+                end if
+                if (datatype .eq. NF_CHAR) then
+                    err = nf_get_att_text(ncid, i, name, text)
+                    if (err .ne. 0) then
+                        call errore('nf_get_att_text: ', err)
+                    end if
+                    do 3, k = 1, ATT_LEN(j,i)
+                        ndx(1) = k
+                        if (ichar(text(k:k)) .ne. hash(datatype, -1, 
+     +                                                 ndx))
+     +                  then
+                            call errori(
+     +          'nf_get_att_text: unexpected value for var ', i)
+                        else
+                            nok = nok + 1
+                        end if
+3                   continue
+                else
+                    err = nf_get_att_double(ncid, i, name, value)
+                    do 4, k = 1, ATT_LEN(j,i)
+                        ndx(1) = k
+                        expect = hash(datatype, -1, ndx)
+                        if (inRange(expect,ATT_TYPE(j,i))) then
+                            if (err .ne. 0) then
+                                call errore('nf_get_att_double: ', err)
+                            end if
+                            if (.not. equal(value(k), expect,
+     +                          ATT_TYPE(j,i), NFT_DOUBLE)) then
+                                call errori(
+     +                  'Att value read not that expected for var ', i)
+                            else
+                                nok = nok + 1
+                            end if
+                        end if
+4                   continue
+                end if
+2           continue
+1       continue
+        call print_nok(nok)
+        end
+
+
+! Check file (dims, vars, atts) corresponds to global variables */
+        subroutine check_file(filename) 
+        use tests
+        implicit        none
+        character*(*)   filename
+
+        integer ncid            !/* netCDF id */
+        integer err             !/* netCDF status */
+
+        err = nf_open(filename, NF_NOWRITE, ncid)
+        if (err .ne. 0) then
+            call errore('nf_open: ', err)
+        else
+            call check_dims(ncid)
+            call check_vars(ncid)
+            call check_atts(ncid)
+            err = nf_close (ncid)
+            if (err .ne. 0) then
+                call errore('nf_close: ', err)
+            end if
+        end if
+        end
+
+
+!
+! Functions for accessing attribute test data.
+!
+! NB: 'varid' is 0 for global attributes; thus, global attributes can
+! be handled in the same loop as variable attributes.
+!
+
+      FUNCTION VARID(VID)
+      use tests, ONLY: NF_GLOBAL 
+      IMPLICIT NONE
+      INTEGER VID
+      INTEGER VARID
+      IF (VID .LT. 1) THEN
+          VARID = NF_GLOBAL
+      ELSE
+          VARID = VID
+      ENDIF
+      end
+
+
+      FUNCTION NATTS(VID)
+      use tests, ONLY: NGATTS, VAR_NATTS
+      IMPLICIT  NONE
+      INTEGER VID
+      Integer NATTS
+
+      IF (VID .LT. 1) THEN
+          NATTS = NGATTS
+      ELSE
+          NATTS = VAR_NATTS(VID)
+      ENDIF
+      END
+
+
+      FUNCTION ATT_NAME(J,VID)
+      use tests, ONLY: GATT_NAME, ATTNAME
+      IMPLICIT  NONE
+      INTEGER J
+      INTEGER VID
+      CHARACTER*2 ATT_NAME
+      IF (VID .LT. 1) THEN
+          ATT_NAME = GATT_NAME(J)
+      ELSE
+          ATT_NAME = ATTNAME(J,VID)
+      ENDIF
+      END
+
+
+      FUNCTION ATT_TYPE(J,VID)
+      use tests, ONLY :GATT_TYPE, ATTTYPE
+      IMPLICIT  NONE
+      INTEGER J
+      INTEGER VID
+      INTEGER ATT_TYPE
+      IF (VID .LT. 1) THEN
+          ATT_TYPE = GATT_TYPE(J)
+      ELSE
+          ATT_TYPE = ATTTYPE(J,VID)
+      ENDIF
+      END
+
+
+      FUNCTION ATT_LEN(J,VID)
+      use tests, ONLY: GATT_LEN, ATTLEN
+      IMPLICIT  NONE
+      INTEGER J
+      INTEGER VID
+      INTEGER ATT_LEN
+      IF (VID .LT. 1) THEN
+          ATT_LEN = GATT_LEN(J)
+      ELSE
+          ATT_LEN = ATTLEN(J,VID)
+      ENDIF
+      END
+
+
+!
+! Return the minimum value of an internal type.
+!
+        function internal_min(type)
+        use tests, ONLY: RK8, NFT_CHAR, NFT_INT1, NFT_INT2, NFT_INT,    &
+     &                   NFT_REAL, NFT_DOUBLE
+        implicit        none
+        integer         type
+        real(RK8) internal_min
+        doubleprecision min_schar
+        doubleprecision min_short
+        doubleprecision min_int
+        doubleprecision min_long
+        doubleprecision max_float
+        doubleprecision max_double
+        if (type .eq. NFT_CHAR) then
+            internal_min = 0
+        else if (type .eq. NFT_INT1) then
+#if NF_INT1_IS_C_SIGNED_CHAR
+            internal_min = min_schar()
+#endif
+#if NF_INT1_IS_C_SHORT
+            internal_min = min_short()
+#endif
+#if NF_INT1_IS_C_INT
+            internal_min = min_int()
+#endif
+#if NF_INT1_IS_C_LONG
+            internal_min = min_long()
+#endif
+        else if (type .eq. NFT_INT2) then
+#if NF_INT2_IS_C_SHORT
+            internal_min = min_short()
+#endif            
+#if NF_INT2_IS_C_INT
+            internal_min = min_int()
+#endif            
+#if NF_INT2_IS_C_LONG
+            internal_min = min_long()
+#endif
+        else if (type .eq. NFT_INT) then
+#if NF_INT_IS_C_INT
+            internal_min = min_int()
+#endif            
+#if NF_INT_IS_C_LONG
+            internal_min = min_long()
+#endif
+        else if (type .eq. NFT_REAL) then
+#if NF_REAL_IS_C_FLOAT
+            internal_min = -max_float()
+#endif
+#if NF_REAL_IS_C_DOUBLE
+            internal_min = -max_double()
+#endif
+        else if (type .eq. NFT_DOUBLE) then
+#if NF_DOUBLEPRECISION_IS_C_DOUBLE
+            internal_min = -max_double()
+#endif
+#if NF_DOUBLEPRECISION_IS_C_FLOAT
+            internal_min = -max_float()
+#endif
+        else
+            stop 2
+        end if
+        end
+
+
+!
+! Return the maximum value of an internal type.
+!
+        function internal_max(type)
+        use tests, ONLY: RK8, NFT_CHAR, NFT_INT1, NFT_INT2, NFT_INT,    &
+     &                   NFT_REAL, NFT_DOUBLE
+        implicit        none
+        integer         type
+        doubleprecision max_schar
+        doubleprecision max_short
+        doubleprecision max_int
+        doubleprecision max_long
+        doubleprecision max_float
+        doubleprecision max_double
+        real(RK8) internal_max
+        if (type .eq. NFT_CHAR) then
+            internal_max = 255
+        else if (type .eq. NFT_INT1) then
+#if NF_INT1_IS_C_SIGNED_CHAR
+            internal_max = max_schar()
+#endif
+#if NF_INT1_IS_C_SHORT
+            internal_max = max_short()
+#endif
+#if NF_INT1_IS_C_INT
+            internal_max = max_int()
+#endif
+#if NF_INT1_IS_C_LONG
+            internal_max = max_long()
+#endif
+        else if (type .eq. NFT_INT2) then
+#if NF_INT2_IS_C_SHORT
+            internal_max = max_short()
+#endif
+#if NF_INT2_IS_C_INT
+            internal_max = max_int()
+#endif
+#if NF_INT2_IS_C_LONG
+            internal_max = max_long()
+#endif
+        else if (type .eq. NFT_INT) then
+#if NF_INT_IS_C_INT
+            internal_max = max_int()
+#endif
+#if NF_INT_IS_C_LONG
+            internal_max = max_long()
+#endif
+        else if (type .eq. NFT_REAL) then
+#if NF_REAL_IS_C_FLOAT
+            internal_max = max_float()
+#endif
+#if NF_REAL_IS_C_DOUBLE
+            internal_max = max_double()
+#endif
+        else if (type .eq. NFT_DOUBLE) then
+#if NF_DOUBLEPRECISION_IS_C_DOUBLE
+            internal_max = max_double()
+#endif            
+#if NF_DOUBLEPRECISION_IS_C_FLOAT
+            internal_max = max_float()
+#endif
+        else
+            stop 2
+        end if
+        end
+
+
+!
+! Return the minimum value of an external type.
+!
+        function external_min(type)
+        use tests, ONLY: RK8, NF_CHAR, NF_SHORT, NF_INT, NF_FLOAT,      &
+     &                   NF_DOUBLE, X_BYTE_MIN, X_CHAR_MIN, X_SHORT_MIN,&
+     &                   X_INT_MIN, X_FLOAT_MIN, X_DOUBLE_MIN , NF_BYTE
+        implicit        none
+        integer         type
+        real(rk8) external_min
+
+        if (type .eq. NF_BYTE) then
+            external_min = X_BYTE_MIN
+        else if (type .eq. NF_CHAR) then
+            external_min = X_CHAR_MIN
+        else if (type .eq. NF_SHORT) then
+            external_min = X_SHORT_MIN
+        else if (type .eq. NF_INT) then
+            external_min = X_INT_MIN
+        else if (type .eq. NF_FLOAT) then
+            external_min = X_FLOAT_MIN
+        else if (type .eq. NF_DOUBLE) then
+            external_min = X_DOUBLE_MIN
+        else
+            stop 2
+        end if
+        end
+
+
+!
+! Return the maximum value of an internal type.
+!
+        function external_max(type)
+        use tests, ONLY: RK8, NF_CHAR, NF_SHORT, NF_INT, NF_FLOAT,      &
+     &                   NF_DOUBLE, X_BYTE_MAX, X_CHAR_MAX, X_SHORT_MAX,&
+     &                   X_INT_MAX, X_FLOAT_MAX, X_DOUBLE_MAX, NF_BYTE
+        implicit        none
+        integer         type
+        real(RK8) external_max
+        if (type .eq. NF_BYTE) then
+            external_max = X_BYTE_MAX
+        else if (type .eq. NF_CHAR) then
+            external_max = X_CHAR_MAX
+        else if (type .eq. NF_SHORT) then
+            external_max = X_SHORT_MAX
+        else if (type .eq. NF_INT) then
+            external_max = X_INT_MAX
+        else if (type .eq. NF_FLOAT) then
+            external_max = X_FLOAT_MAX
+        else if (type .eq. NF_DOUBLE) then
+            external_max = X_DOUBLE_MAX
+        else
+            stop 2
+        end if
+        end
+
+
+!
+! Indicate whether or not a value lies in the range of an internal type.
+!
+        function in_internal_range(itype, value)
+        use tests, ONLY: RK8
+        implicit        none
+        integer         itype
+        doubleprecision value
+        logical in_internal_range
+        real(rk8), external :: internal_min, internal_max
+
+        in_internal_range = value .ge. internal_min(itype) .and.
+     +                      value .le. internal_max(itype)
+        end
+
+
+!
+! Return the length of a character variable minus any trailing blanks.
+!  not needed for Fortran 90/95/2003 which have an intrinsic LEN_TRIM
+!
+!        function len_trim(string)
+!        use tests
+!        implicit        none
+!        character*(*)   string
+
+!        do 1, len_trim = len(string), 1, -1
+!            if (string(len_trim:len_trim) .ne. ' ')
+!     +          goto 2
+!1       continue
+
+!2       return
+!        end

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/netcdf-fortran.git



More information about the Pkg-grass-devel mailing list