diff --git a/Makefile.am b/Makefile.am index 4c0b8269e3..0a88c72966 100644 --- a/Makefile.am +++ b/Makefile.am @@ -10,13 +10,12 @@ ACLOCAL_AMFLAGS = -I m4 # These files get added to the distribution. -EXTRA_DIST = README.md COPYRIGHT INSTALL.md test_prog.c \ - lib_flags.am cmake CMakeLists.txt COMPILE.cmake.txt \ - config.h.cmake.in cmake_uninstall.cmake.in \ - FixBundle.cmake.in \ - nc-config.cmake.in RELEASE_NOTES.md CTestCustom.cmake \ - CTestConfig.cmake.in libnetcdf.settings.in netCDFConfig.cmake.in \ - CMakeInstallation.cmake test-driver-verbose test_common.in +EXTRA_DIST = README.md COPYRIGHT INSTALL.md test_prog.c lib_flags.am \ +cmake CMakeLists.txt COMPILE.cmake.txt config.h.cmake.in \ +cmake_uninstall.cmake.in FixBundle.cmake.in nc-config.cmake.in \ +RELEASE_NOTES.md CTestCustom.cmake CTestConfig.cmake.in \ +libnetcdf.settings.in netCDFConfig.cmake.in CMakeInstallation.cmake \ +test-driver-verbose test_common.in pkgconfigdir=$(libdir)/pkgconfig pkgconfig_DATA = netcdf.pc @@ -77,7 +76,7 @@ endif # depend on it. SUBDIRS = include $(H5_TEST_DIR) libdispatch libsrc $(LIBSRC4_DIR) \ $(LIBSRCP) $(OCLIB) $(DAP2) ${DAP4} liblib $(NCGEN3) $(NCGEN) \ -$(NCDUMP) $(TESTDIRS) docs $(EXAMPLES) $(UDUNITS) $(LIBCF) +$(NCDUMP) $(TESTDIRS) docs $(EXAMPLES) # Remove these generated files, for a distclean. DISTCLEANFILES = VERSION comps.txt test_prog libnetcdf.settings \ @@ -101,14 +100,6 @@ ${prefix}/bin/ncgen$(EXEEXT) ${prefix}/bin/ncdump$(EXEEXT) \ ${prefix}/share/man/man1/ncgen.1 ${prefix}/share/man/man1/ncdump.1 endif -if BUILD_DLL -BINFILES += bin/libnetcdf-7.dll lib/libnetcdf.dll.a lib/libnetcdf.a \ -lib/libnetcdf.la lib/netcdfdll.def -ZIPBINFILES += ${prefix}/bin/libnetcdf-7.dll \ -${prefix}/lib/libnetcdf.dll.a ${prefix}/lib/libnetcdf.a \ -${prefix}/lib/libnetcdf.la ${prefix}/lib/netcdfdll.def -endif # BUILD_DLL - # install libnetcdf.settings in lib directory. settingsdir = $(libdir) settings_DATA = libnetcdf.settings @@ -154,29 +145,12 @@ install-netcdf-fortran: endif -# At Unidata, package up binaries. -ftpbin: install - echo "Getting binaries from ${prefix}" - ls -l ${prefix} - echo "These are the binaries for netCDF @PACKAGE_VERSION@." > ${prefix}/README_BINARIES.txt - echo "For this build: CC=$(CC) CXX=$(CXX)" >> ${prefix}/README_BINARIES.txt - echo "CFLAGS=$(CFLAGS) CXXFLAGS=$(CXXFLAGS)" >> ${prefix}/README_BINARIES.txt - echo "FCFLAGS=$(FCFLAGS) F77FLAGS=$(F77FLAGS) $F90FLAGS=$(F90FLAGS)" >> ${prefix}/README_BINARIES.txt - which tar - echo "PATH: $(PATH)" - tar cf @BINFILE_NAME@ -C ${prefix} ${BINFILES} - gzip -f @BINFILE_NAME@ - zip -j netcdf_${VERSION}.zip ${ZIPBINFILES} - check_nc_config: $(CC) `./nc-config --cflags` test_prog.c -o test_prog `./nc-config --libs` ./test_prog install-data-hook: -if BUILD_DLL - cp liblib/netcdfdll.def $(DESTDIR)${prefix}/bin -endif # BUILD_DLL @echo '' @echo '+-------------------------------------------------------------+' @echo '| Congratulations! You have successfully installed netCDF! |' diff --git a/configure.ac b/configure.ac index 12a221ef6e..82e505a75b 100644 --- a/configure.ac +++ b/configure.ac @@ -83,20 +83,6 @@ AC_CONFIG_SRCDIR([include/netcdf.h]) AC_MSG_NOTICE([checking user options]) -# If --enable-dll is specified the DLL will be built. This only works -# on mingw. -AC_MSG_CHECKING([whether a win32 DLL is desired]) -AC_ARG_ENABLE([dll], - [AS_HELP_STRING([--enable-dll], - [build a win32 DLL (only works on mingw)])]) -test "x$enable_dll" = xyes || enable_dll=no -AC_MSG_RESULT([$enable_dll]) -if test "x$enable_dll" = xyes; then - AC_DEFINE(DLL_NETCDF, 1, [set this only when building a DLL under MinGW]) - AC_DEFINE(DLL_EXPORT, 1, [set this only when building a DLL under MinGW]) -fi -AM_CONDITIONAL(BUILD_DLL, [test x$enable_dll = xyes]) - # Did the user specify a default minimum blocksize (NCIO_MINBLOCKSIZE) for posixio? AC_MSG_CHECKING([whether a NCIO_MINBLOCKSIZE was specified]) AC_ARG_WITH([minblocksize], @@ -348,13 +334,8 @@ fi # See if the user provided us with a curl library # Do an initial lib test for curl, but suppress the default action AC_CHECK_LIB([curl],[curl_easy_setopt],[found_curl=yes],[found_curl=no]) -#AC_CHECK_LIB([curl.dll],[curl_easy_setopt]) # If curl is required but there is no curl, then complain if test $require_curl = yes ; then - # Removed. Why assume no curl if we are building DLL? - #if test $enable_dll = yes ; then - # AC_MSG_NOTICE([libcurl not found; continuing]) - #elif test $found_curl = no ; then if test $found_curl = no ; then AC_MSG_NOTICE([libcurl not found; disabling remote protocol(s) support]) enable_dap=no @@ -712,7 +693,7 @@ CFLAGS="$SAVECFLAGS" # Set up libtool. AC_MSG_NOTICE([setting up libtool]) LT_PREREQ([2.2]) -LT_INIT(win32-dll) +LT_INIT() # Valgrind tests don't work with shared builds because of some libtool # weirdness. @@ -1236,33 +1217,6 @@ if test "x$enable_logging" = xyes; then AC_DEFINE([LOGGING], 1, [If true, turn on logging.]) fi - -# Like other libraries, udunits and libcf -# are no long part of the netcdf distribution. - -#AC_MSG_CHECKING([whether udunits is to be built]) -#AC_ARG_WITH([udunits], -# [AS_HELP_STRING([--with-udunits], -# [Build udunits2 package.])]) -#test "x$with_udunits" = xyes || with_udunits=no -#AC_MSG_RESULT($with_udunits) -#AM_CONDITIONAL(BUILD_UDUNITS, [test "x$with_udunits" = xyes]) - - -# Does the user want to also build the libcf library? -#AC_MSG_CHECKING([whether libcf is to be built]) -#AC_ARG_WITH([libcf], -# [AS_HELP_STRING([--with-libcf], -# [build and install libcf library, a library for \ -# handling data in conformance with the Climate and \ -# Forecast conventions. (Requires netCDF-4 and HDF5)])]) -#test "x$with_libcf" = xyes || with_libcf=no -#AC_MSG_RESULT($with_libcf) -#AM_CONDITIONAL(BUILD_LIBCF, [test "x$with_libcf" = xyes]) - -#AC_CONFIG_SUBDIRS([udunits libcf]) - - # Automake conditionals need to be called, whether the answer is yes # or no. AM_CONDITIONAL(BUILD_PARALLEL, [test x$enable_parallel = xyes]) diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in index 36b230f257..eaf65f93b4 100644 --- a/docs/Doxyfile.in +++ b/docs/Doxyfile.in @@ -788,7 +788,18 @@ INPUT = \ @abs_top_srcdir@/libdispatch/dparallel.c \ @abs_top_srcdir@/libdispatch/derror.c \ @abs_top_srcdir@/libdispatch/dv2i.c \ + @abs_top_srcdir@/libdispatch/dcopy.c \ @abs_top_srcdir@/libsrc4/nc4file.c \ + @abs_top_srcdir@/libsrc4/nc4var.c \ + @abs_top_srcdir@/libsrc4/nc4hdf.c \ + @abs_top_srcdir@/libsrc4/nc4internal.c \ + @abs_top_srcdir@/libsrc4/nc4type.c \ + @abs_top_srcdir@/libsrc4/nc4grp.c \ + @abs_top_srcdir@/libsrc4/ncfunc.c \ + @abs_top_srcdir@/libsrc4/nc4dim.c \ + @abs_top_srcdir@/libsrc4/nc4attr.c \ + @abs_top_srcdir@/libsrc4/nc4info.c \ + @abs_top_srcdir@/libsrc4/nc4dispatch.c \ @abs_top_srcdir@/examples/C/simple_xy_wr.c \ @abs_top_srcdir@/examples/C/simple_xy_rd.c \ @abs_top_srcdir@/examples/C/sfc_pres_temp_wr.c \ diff --git a/h5_test/Makefile.am b/h5_test/Makefile.am index 6d2339495d..18e168b1f4 100644 --- a/h5_test/Makefile.am +++ b/h5_test/Makefile.am @@ -19,7 +19,7 @@ tst_h_atts3 tst_h_atts4 tst_h_vars tst_h_vars2 tst_h_vars3 tst_h_grps \ tst_h_compounds tst_h_compounds2 tst_h_wrt_cmp tst_h_vl tst_h_opaques \ tst_h_strings tst_h_strings1 tst_h_strings2 tst_h_ints \ tst_h_dimscales tst_h_dimscales1 tst_h_dimscales2 tst_h_dimscales3 \ -tst_h_enums tst_h_dimscales4 #tst_h_filters +tst_h_enums tst_h_dimscales4 # If benchmarks were turned on, build and run a bunch more tests. if BUILD_BENCHMARKS diff --git a/h5_test/tst_h_filters.c b/h5_test/tst_h_filters.c deleted file mode 100644 index cccee447c4..0000000000 --- a/h5_test/tst_h_filters.c +++ /dev/null @@ -1,107 +0,0 @@ -#include "err_macros.h" -#include -#include - -#define FILE_NAME "tst_h_filters.h5" -#define DIM_LEN 10 -#define NDIMS 1 -#define VAR1_NAME "very_important_data" -#define FILTER_NAME "ed_compress_2000" -#define FILTER_ID (H5Z_FILTER_RESERVED + 1) -#define NUM_FILTER_PARAM 2 - -size_t -ed_compress_2000_filter(unsigned int flags, size_t cd_nelmts, const unsigned int cd_values[], - size_t nbytes, size_t *buf_size, void **buf) -{ - char *new_buf; - char *old_buf = (char *)*buf; - int i; - -/* printf("ed_compress_2000_filter called: type 0x%x bits %d nbytes %d buf_size %d\n", - cd_values[0], cd_values[1], nbytes, *buf_size);*/ - if (flags & H5Z_FLAG_REVERSE) - { -/* printf("reading\n");*/ - if (!(new_buf = malloc(*buf_size * 2))) ERR; - for (i = 0; i < *buf_size * 2; i++) - new_buf[i] = old_buf[i/2]; - free(*buf); - *buf = new_buf; - *buf_size *= 2; - } - else - { -/* printf("writing\n");*/ - if (!(new_buf = malloc(*buf_size/2))) ERR; - for (i = 0; i < *buf_size/2; i++) - new_buf[i] = old_buf[i*2]; - free(*buf); - *buf = new_buf; - *buf_size /= 2; - } - /* Return number of bytes in buf for success, 0 for failure. */ - return *buf_size; -} - -int -main() -{ - printf("\n*** Checking HDF5 filter.\n"); - printf("*** Checking EDPEG2000 compression filter..."); - { - hid_t fileid, grpid, spaceid, var1_id, create_propid; - hsize_t dims[NDIMS] = {DIM_LEN}, chunksize = 1; - int data_out[DIM_LEN], data_in[DIM_LEN]; - H5Z_class2_t fclass; - unsigned int filter_param[NUM_FILTER_PARAM] = {H5T_NATIVE_INT32, 12}; - int i; - - /* Initialize some data. */ - for (i = 0; i < DIM_LEN; i++) - data_out[i] = i; - - /* Create file. */ - if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT, - H5P_DEFAULT)) < 0) ERR; - if ((grpid = H5Gopen2(fileid, "/", H5P_DEFAULT)) < 0) ERR; - - /* Register filter. */ - fclass.version = H5Z_CLASS_T_VERS; - fclass.id = FILTER_ID; - fclass.encoder_present = 1; - fclass.decoder_present = 1; - fclass.can_apply = NULL; - fclass.set_local = NULL; - fclass.filter = &ed_compress_2000_filter; - if (H5Zregister(&fclass) < 0) ERR; - - /* Create dataset. */ - if ((spaceid = H5Screate_simple(NDIMS, dims, dims)) < 0) ERR; - if ((create_propid = H5Pcreate(H5P_DATASET_CREATE)) < 0) ERR; - if (H5Pset_chunk(create_propid, NDIMS, &chunksize) < 0) ERR; - if (H5Pset_filter(create_propid, FILTER_ID, H5Z_FLAG_OPTIONAL, - NUM_FILTER_PARAM, filter_param) < 0) ERR; - if ((var1_id = H5Dcreate2(grpid, VAR1_NAME, H5T_NATIVE_INT32, spaceid, - H5P_DEFAULT, create_propid, H5P_DEFAULT)) < 0) ERR; - if (H5Dwrite(var1_id, H5T_NATIVE_INT32, H5S_ALL, H5S_ALL, H5P_DEFAULT, data_out) < 0) ERR; - if (H5Sclose(spaceid) < 0) ERR; - if (H5Dclose(var1_id) < 0) ERR; - if (H5Gclose(grpid) < 0) ERR; - if (H5Fclose(fileid) < 0) ERR; - - /* Read file. */ - if ((fileid = H5Fopen(FILE_NAME, H5F_ACC_RDWR, H5P_DEFAULT)) < 0) ERR; - if ((grpid = H5Gopen2(fileid, "/", H5P_DEFAULT)) < 0) ERR; - if ((var1_id = H5Dopen2(grpid, VAR1_NAME, H5P_DEFAULT)) < 0) ERR; - if (H5Dread(var1_id, H5T_NATIVE_INT32, H5S_ALL, H5S_ALL, H5P_DEFAULT, data_in) < 0) ERR; - /*for (i = 0; i < DIM_LEN; i++) */ - /*printf("new data[%d]=%d\n", i, data_in[i]);*/ - - if (H5Dclose(var1_id) < 0) ERR; - if (H5Gclose(grpid) < 0) ERR; - if (H5Fclose(fileid) < 0) ERR; - } - SUMMARIZE_ERR; - FINAL_RESULTS; -} diff --git a/include/nc_tests.h b/include/nc_tests.h index a51fce7668..613298e05d 100644 --- a/include/nc_tests.h +++ b/include/nc_tests.h @@ -36,6 +36,8 @@ for conditions of use. #define THIRTY_TWO_MEG (SIXTEEN_MEG * 2) #define SIXTY_FOUR_MEG (SIXTEEN_MEG * 4) #define ONE_TWENTY_EIGHT_MEG (SIXTEEN_MEG * 8) +#define TEST_VAL_42 42 +#define BAD_NAME "dd//d/ " /** \} */ #ifdef USE_PNETCDF diff --git a/include/netcdf.h b/include/netcdf.h index 4b131fa433..fac6f63d8e 100644 --- a/include/netcdf.h +++ b/include/netcdf.h @@ -45,7 +45,7 @@ extern "C" { #define NC_UINT64 11 /**< unsigned 8-byte int */ #define NC_STRING 12 /**< string */ -#define NC_MAX_ATOMIC_TYPE NC_STRING +#define NC_MAX_ATOMIC_TYPE NC_STRING /**< @internal Largest atomic type. */ /* The following are use internally in support of user-defines * types. They are also the class returned by nc_inq_user_type. */ @@ -54,7 +54,8 @@ extern "C" { #define NC_ENUM 15 /**< enum types */ #define NC_COMPOUND 16 /**< compound types */ -/* Define the first user defined type id (leave some room) */ +/** @internal Define the first user defined type id (leave some + * room) */ #define NC_FIRSTUSERTYPEID 32 /** Default fill value. This is used unless _FillValue attribute @@ -299,6 +300,9 @@ there. */ #define NC_SHUFFLE 1 /**@}*/ +#define NC_MIN_DEFLATE_LEVEL 0 /**< Minimum deflate level. */ +#define NC_MAX_DEFLATE_LEVEL 9 /**< Maximum deflate level. */ + /** The netcdf version 3 functions all return integer error status. * These are the possible values, in addition to certain values from * the system errno.h. @@ -346,7 +350,7 @@ ::NC_CLASSIC_MODEL on. */ #define NC_ENAMEINUSE (-42) /**< String match to name in use */ #define NC_ENOTATT (-43) /**< Attribute not found */ -#define NC_EMAXATTS (-44) /**< NC_MAX_ATTRS exceeded */ /* not enforced after 4.5.0 */ +#define NC_EMAXATTS (-44) /**< NC_MAX_ATTRS exceeded - not enforced after 4.5.0 */ #define NC_EBADTYPE (-45) /**< Not a netcdf data type */ #define NC_EBADDIM (-46) /**< Invalid dimension id or name */ #define NC_EUNLIMPOS (-47) /**< NC_UNLIMITED in the wrong index */ @@ -415,7 +419,7 @@ by the desired type. */ /* The following was added in support of netcdf-4. Make all netcdf-4 error codes < -100 so that errors can be added to netcdf-3 if needed. */ -#define NC4_FIRST_ERROR (-100) +#define NC4_FIRST_ERROR (-100) /**< @internal All HDF5 errors < this. */ #define NC_EHDFERR (-101) /**< Error at HDF5 layer. */ #define NC_ECANTREAD (-102) /**< Can't read. */ #define NC_ECANTWRITE (-103) /**< Can't write. */ @@ -451,20 +455,20 @@ by the desired type. */ #define NC_EFILTER (-132) /**< Filter operation failed. */ #define NC_ERCFILE (-133) /**< RC file failure */ #define NC_ENULLPAD (-134) /**< Header Bytes not Null-Byte padded */ -#define NC4_LAST_ERROR (-135) +#define NC4_LAST_ERROR (-135) /**< @internal All netCDF errors > this. */ -/* This is used in netCDF-4 files for dimensions without coordinate - * vars. */ +/** @internal This is used in netCDF-4 files for dimensions without + * coordinate vars. */ #define DIM_WITHOUT_VARIABLE "This is a netCDF dimension but not a netCDF variable." -/* This is here at the request of the NCO team to support our - * mistake of having chunksizes be first ints, then size_t. Doh! */ +/** @internal This is here at the request of the NCO team to support + * our mistake of having chunksizes be first ints, then + * size_t. Doh! */ #define NC_HAVE_NEW_CHUNKING_API 1 -/*Errors for all remote access methods(e.g. DAP and CDMREMOTE)*/ -#define NC_EURL (NC_EDAPURL) /* Malformed URL */ -#define NC_ECONSTRAINT (NC_EDAPCONSTRAINT) /* Malformed Constraint*/ - +/* Errors for all remote access methods(e.g. DAP and CDMREMOTE)*/ +#define NC_EURL (NC_EDAPURL) /**< Malformed URL */ +#define NC_ECONSTRAINT (NC_EDAPCONSTRAINT) /**< Malformed Constraint*/ /* * The Interface @@ -479,10 +483,10 @@ by the desired type. */ # endif # include #else -# define MSC_EXTRA +#define MSC_EXTRA /**< Needed for DLL build. */ #endif /* defined(DLL_NETCDF) */ -# define EXTERNL MSC_EXTRA extern +#define EXTERNL MSC_EXTRA extern /**< Needed for DLL build. */ #if defined(DLL_NETCDF) /* define when library is a DLL */ EXTERNL int ncerr; @@ -1730,7 +1734,7 @@ nc_set_log_level(int new_level); #else /* not LOGGING */ -#define nc_set_log_level(e) +#define nc_set_log_level(e) /**< Get rid of these calls. */ #endif /* LOGGING */ @@ -1810,27 +1814,27 @@ nctypelen(nc_type datatype); */ EXTERNL int ncerr; -#define NC_ENTOOL NC_EMAXNAME /* Backward compatibility */ -#define NC_EXDR (-32) /* */ -#define NC_SYSERR (-31) +#define NC_ENTOOL NC_EMAXNAME /**< Backward compatibility */ +#define NC_EXDR (-32) /**< V2 API error. */ +#define NC_SYSERR (-31) /**< V2 API system error. */ /* * Global options variable. * Used to determine behavior of error handler. */ -#define NC_FATAL 1 -#define NC_VERBOSE 2 +#define NC_FATAL 1 /**< For V2 API, exit on error. */ +#define NC_VERBOSE 2 /**< For V2 API, be verbose on error. */ -EXTERNL int ncopts; /* default is (NC_FATAL | NC_VERBOSE) */ +/** V2 API error handling. Default is (NC_FATAL | NC_VERBOSE). */ +EXTERNL int ncopts; EXTERNL void nc_advise(const char *cdf_routine_name, int err, const char *fmt,...); -/* - * C data type corresponding to a netCDF NC_LONG argument, - * a signed 32 bit object. - * - * This is the only thing in this file which architecture dependent. +/** + * C data type corresponding to a netCDF NC_LONG argument, a signed 32 + * bit object. This is the only thing in this file which architecture + * dependent. */ typedef int nclong; @@ -1949,7 +1953,8 @@ ncrecget(int ncid, long recnum, void **datap); EXTERNL int ncrecput(int ncid, long recnum, void *const *datap); -EXTERNL int nc_finalize(); +EXTERNL int +nc_finalize(); /* End v2.4 backward compatibility */ #endif /*!NO_NETCDF_2*/ @@ -1958,11 +1963,6 @@ EXTERNL int nc_finalize(); } #endif -/* Temporary hack to shut up warnings */ -#ifndef __MINGW32_VERSION -#define END_OF_MAIN() -#endif - /* Define two hard-coded functionality-related macros, but this is not going to be standard practice. */ @@ -1974,6 +1974,4 @@ EXTERNL int nc_finalize(); #define NC_HAVE_INQ_FORMAT_EXTENDED /*!< inq_format_extended() support. */ #endif -#define NC_HAVE_META_H - #endif /* _NETCDF_ */ diff --git a/lib_flags.am b/lib_flags.am index 71b249df25..a157a82b2e 100644 --- a/lib_flags.am +++ b/lib_flags.am @@ -13,11 +13,6 @@ if USE_DAP AM_CPPFLAGS += -I${top_srcdir}/oc2 endif -# This turns on declspec magic in netcdf.h for windows DLLs. -if BUILD_DLL -AM_CPPFLAGS += -DDLL_NETCDF -endif - AM_TESTS_ENVIRONMENT = export DTOPSRCDIR=${abs_top_srcdir}; export DTOPBUILDDIR=${abs_top_builddir}; diff --git a/libdap2/ncd2dispatch.c b/libdap2/ncd2dispatch.c index 5b027aafce..eb8a2b7cff 100644 --- a/libdap2/ncd2dispatch.c +++ b/libdap2/ncd2dispatch.c @@ -184,8 +184,6 @@ NCD2_get_var_chunk_cache, NC_Dispatch* NCD2_dispatch_table = NULL; /* moved here from ddispatch.c */ -static NC_Dispatch NCD2_dispatcher; - int NCD2_initialize(void) { diff --git a/libdap4/d4file.c b/libdap4/d4file.c index f8089937c1..6574efe0eb 100644 --- a/libdap4/d4file.c +++ b/libdap4/d4file.c @@ -369,7 +369,6 @@ set_curl_properties(NCD4INFO* d4info) if(d4info->auth.curlflags.cookiejar == NULL) { /* If no cookie file was defined, define a default */ - int ok; char* path = NULL; char* newpath = NULL; int len; diff --git a/libdap4/d4meta.c b/libdap4/d4meta.c index 185fcf021e..6d615e5057 100644 --- a/libdap4/d4meta.c +++ b/libdap4/d4meta.c @@ -733,7 +733,7 @@ compileAttrValues(NCD4meta* builder, NCD4node* basetype, NClist* values, void** if(!ISTYPE(truebase->sort) || (truebase->meta.id > NC_MAX_ATOMIC_TYPE)) FAIL(NC_EBADTYPE,"Illegal attribute type: %s",basetype->name); size = NCD4_typesize(truebase->meta.id); - if((memory = (char*)d4alloc(count*size))==NULL) + if((memory = (unsigned char*)d4alloc(count*size))==NULL) return THROW(NC_ENOMEM); p = memory; for(i=0;ii64) != 1) return THROW(NC_ERANGE); + if(sscanf(s,"%lld",&converter->i64[0]) != 1) return THROW(NC_ERANGE); break; case NC_UBYTE: case NC_USHORT: case NC_UINT: case NC_UINT64: - if(sscanf(s,"%llu",&converter->u64) != 1) return THROW(NC_ERANGE); + if(sscanf(s,"%llu",&converter->u64[0]) != 1) return THROW(NC_ERANGE); break; case NC_FLOAT: case NC_DOUBLE: - if(sscanf(s,"%lf",&converter->f64) != 1) return THROW(NC_ERANGE); + if(sscanf(s,"%lf",&converter->f64[0]) != 1) return THROW(NC_ERANGE); break; case NC_CHAR: converter->i8[0] = s[0]; diff --git a/libdap4/d4read.c b/libdap4/d4read.c index dae6ff7c2d..b3d87b5a10 100644 --- a/libdap4/d4read.c +++ b/libdap4/d4read.c @@ -150,7 +150,6 @@ static int readfile(const NCURI* uri, const char* suffix, NCbytes* packet) { int stat = NC_NOERR; - char buf[1024]; NCbytes* tmp = ncbytesnew(); char* filename = NULL; diff --git a/libdap4/d4varx.c b/libdap4/d4varx.c index d944f7d4fb..2bbd28b6d7 100644 --- a/libdap4/d4varx.c +++ b/libdap4/d4varx.c @@ -21,7 +21,7 @@ NCD4_get_vara(int ncid, int varid, { int ret; /* TODO: optimize since we know stride is 1 */ - ret = NCD4_get_vars(ncid,varid,start,edges,nc_sizevector1,value,memtype); + ret = NCD4_get_vars(ncid,varid,start,edges,(ptrdiff_t *)nc_sizevector1,value,memtype); return ret; } diff --git a/libdispatch/Makefile.am b/libdispatch/Makefile.am index 08866d53f4..a1e900863e 100644 --- a/libdispatch/Makefile.am +++ b/libdispatch/Makefile.am @@ -31,11 +31,6 @@ libdispatch_la_SOURCES += dgroup.c dvlen.c dcompound.c dtype.c denum.c \ dopaque.c dfilter.c ncaux.c endif # USE_NETCDF4 -# Turn on pre-processor flag when building a DLL for windows. -if BUILD_DLL -libdispatch_la_CPPFLAGS += -DDLL_EXPORT -endif # BUILD_DLL - # Add V2 API convenience library if needed. if BUILD_V2 noinst_LTLIBRARIES += libnetcdf2.la diff --git a/libdispatch/dcopy.c b/libdispatch/dcopy.c index ebf32fdadf..0c73c40bd1 100644 --- a/libdispatch/dcopy.c +++ b/libdispatch/dcopy.c @@ -1,17 +1,30 @@ -/* Copyright 2010 University Corporation for Atmospheric - Research/Unidata. See COPYRIGHT file for more info. - - This file has the var and att copy functions. - - "$Id: copy.c,v 1.1 2010/06/01 15:46:49 ed Exp $" +/** + * @file + * Copyright 2010 University Corporation for Atmospheric + * Research/Unidata. See COPYRIGHT file for more info. + * + * This file has the var and att copy functions. + * + * @author Dennis Heimbigner */ - #include "ncdispatch.h" #include "nc_logging.h" #ifdef USE_NETCDF4 -/* Compare two netcdf types for equality. Must have the ncids as well, - to find user-defined types. */ +/** + * @internal Compare two netcdf types for equality. Must have the + * ncids as well, to find user-defined types. + * + * @param ncid1 File ID. + * @param typeid1 Type ID. + * @param ncid2 File ID. + * @param typeid2 Type ID. + * @param equalp Pointer that gets 1 of the types are equal, 0 + * otherwise. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett +*/ static int NC_compare_nc_types(int ncid1, int typeid1, int ncid2, int typeid2, int *equalp) @@ -137,8 +150,18 @@ NC_compare_nc_types(int ncid1, int typeid1, int ncid2, int typeid2, return ret; } -/* Recursively hunt for a netCDF type id. (Code from nc4internal.c); - Return matching typeid or 0 if not found. */ +/** + * @internal Recursively hunt for a netCDF type id. (Code from + * nc4internal.c); Return matching typeid or 0 if not found. + * + * @param ncid1 File ID. + * @param tid1 Type ID. + * @param ncid2 File ID. + * @param tid2 Pointer that gets type ID of equal type. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett +*/ static int NC_rec_find_nc_type(int ncid1, nc_type tid1, int ncid2, nc_type* tid2) { @@ -201,8 +224,18 @@ NC_rec_find_nc_type(int ncid1, nc_type tid1, int ncid2, nc_type* tid2) return NC_EBADTYPE; /* not found */ } -/* Given a type in one file, find its equal (if any) in another - * file. It sounds so simple, but it's a real pain! */ +/** + * @internal Given a type in one file, find its equal (if any) in + * another file. It sounds so simple, but it's a real pain! + * + * @param ncid1 File ID. + * @param xtype1 Type ID. + * @param ncid2 File ID. + * @param xtype2 Pointer that gets type ID of equal type. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett +*/ static int NC_find_equal_type(int ncid1, nc_type xtype1, int ncid2, nc_type *xtype2) { @@ -229,25 +262,33 @@ NC_find_equal_type(int ncid1, nc_type xtype1, int ncid2, nc_type *xtype2) #endif /* USE_NETCDF4 */ -/* This will copy a variable that is an array of primitive type and - its attributes from one file to another, assuming dimensions in the - output file are already defined and have same dimension IDs and - length. However it doesn't work for copying netCDF-4 variables of - type string or a user-defined type. - - This function works even if the files are different formats, - (for example, one netcdf classic, the other netcdf-4). - - If you're copying into a classic-model file, from a netcdf-4 file, - you must be copying a variable of one of the six classic-model - types, and similarly for the attributes. - - For large netCDF-3 files, this can be a very inefficient way to - copy data from one file to another, because adding a new variable - to the target file may require more space in the header and thus - result in moving data for other variables in the target file. This - is not a problem for netCDF-4 files, which support efficient - addition of variables without moving data for other variables. +/** + * This will copy a variable that is an array of primitive type and + * its attributes from one file to another, assuming dimensions in the + * output file are already defined and have same dimension IDs and + * length. However it doesn't work for copying netCDF-4 variables of + * type string or a user-defined type. + * + * This function works even if the files are different formats, + * (for example, one netcdf classic, the other netcdf-4). + * + * If you're copying into a classic-model file, from a netcdf-4 file, + * you must be copying a variable of one of the six classic-model + * types, and similarly for the attributes. + * + * For large netCDF-3 files, this can be a very inefficient way to + * copy data from one file to another, because adding a new variable + * to the target file may require more space in the header and thus + * result in moving data for other variables in the target file. This + * is not a problem for netCDF-4 files, which support efficient + * addition of variables without moving data for other variables. + * + * @param ncid_in File ID to copy from. + * @param varid_in Variable ID to copy. + * @param ncid_out File ID to copy to. + * + * @return ::NC_NOERR No error. + * @author Glenn Davis, Ed Hartnett, Dennis Heimbigner */ int nc_copy_var(int ncid_in, int varid_in, int ncid_out) @@ -477,6 +518,19 @@ nc_copy_var(int ncid_in, int varid_in, int ncid_out) return retval; } +/** + * Copy an attribute from one open file to another. This is called by + * nc_copy_att(). + * + * @param ncid_in File ID to copy from. + * @param varid_in Variable ID to copy from. + * @param name Name of attribute to copy. + * @param ncid_out File ID to copy to. + * @param varid_out Variable ID to copy to. + * + * @return ::NC_NOERR No error. + * @author Glenn Davis, Ed Hartnett, Dennis Heimbigner +*/ static int NC_copy_att(int ncid_in, int varid_in, const char *name, int ncid_out, int varid_out) @@ -576,16 +630,26 @@ NC_copy_att(int ncid_in, int varid_in, const char *name, return res; } -/* Copy an attribute from one open file to another. - - Special programming challenge: this function must work even if one - of the other of the files is a netcdf version 1.0 file (i.e. not - HDF5). So only use top level netcdf api functions. - - From the netcdf-3 docs: 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. +/** + * Copy an attribute from one open file to another. + * + * Special programming challenge: this function must work even if one + * of the other of the files is a netcdf version 1.0 file (i.e. not + * HDF5). So only use top level netcdf api functions. + * + * From the netcdf-3 docs: 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. + * + * @param ncid_in File ID to copy from. + * @param varid_in Variable ID to copy from. + * @param name Name of attribute to copy. + * @param ncid_out File ID to copy to. + * @param varid_out Variable ID to copy to. + * + * @return ::NC_NOERR No error. + * @author Glenn Davis, Ed Hartnett, Dennis Heimbigner */ int nc_copy_att(int ncid_in, int varid_in, const char *name, diff --git a/libdispatch/derror.c b/libdispatch/derror.c index 733fbf27e1..68cede30c6 100644 --- a/libdispatch/derror.c +++ b/libdispatch/derror.c @@ -12,13 +12,14 @@ Research/Unidata. See COPYRIGHT file for more info. #include /* for ncmpi_strerror() */ #endif -/* Tell the user the version of netCDF. */ +/** @internal The version string for the library, used by + * nc_inq_libvers(). */ static const char nc_libvers[] = PACKAGE_VERSION " of "__DATE__" "__TIME__" $"; /** - Return the library version. +Return the library version. - \returns short string that contains the version information for the +\returns short string that contains the version information for the library. */ const char * diff --git a/libdispatch/dfile.c b/libdispatch/dfile.c index 1a4e8eba39..9bed742c94 100644 --- a/libdispatch/dfile.c +++ b/libdispatch/dfile.c @@ -1,12 +1,13 @@ -/** \file dfile.c - -File create and open functions - -These functions end up calling functions in one of the dispatch layers -(netCDF-4, dap server, etc). - -Copyright 2010 University Corporation for Atmospheric -Research/Unidata. See COPYRIGHT file for more info. +/** + * @file + * + * File create and open functions + * + * These functions end up calling functions in one of the dispatch + * layers (netCDF-4, dap server, etc). + * + * Copyright 2010 University Corporation for Atmospheric + * Research/Unidata. See COPYRIGHT file for more info. */ #include "config.h" @@ -52,10 +53,10 @@ static int closemagic(struct MagicFile* file); static void printmagic(const char* tag, char* magic,struct MagicFile*); #endif -extern int NC_initialized; -extern int NC_finalized; +extern int NC_initialized; /**< True when dispatch table is initialized. */ -/* To be consistent with H5Fis_hdf5, use the complete HDF5 magic number */ +/** @internal Magic number for HDF5 files. To be consistent with + * H5Fis_hdf5, use the complete HDF5 magic number */ static char HDF5_SIGNATURE[MAGIC_NUMBER_LEN] = "\211HDF\r\n\032\n"; /** \defgroup datasets NetCDF File and Data I/O @@ -158,11 +159,20 @@ NC_interpret_magic_number(char* magic, int* model, int* version) return status; } -/*! -Given an existing file, figure out its format -and return that format value (NC_FORMATX_XXX) -in model arg. Assume any path conversion was -already performed at a higher level. +/** + * @internal Given an existing file, figure out its format and return + * that format value (NC_FORMATX_XXX) in model arg. Assume any path + * conversion was already performed at a higher level. + * + * @param path File name. + * @param flags + * @param parameters + * @param model Pointer that gets the model to use for the dispatch + * table. + * @param version Pointer that gets version of the file. + * + * @return ::NC_NOERR No error. + * @author Dennis Heimbigner */ int NC_check_file_type(const char *path, int flags, void *parameters, @@ -445,63 +455,57 @@ nc_create(const char *path, int cmode, int *ncidp) return nc__create(path,cmode,NC_SIZEHINT_DEFAULT,NULL,ncidp); } -/*! -Create a netCDF file with some extra parameters controlling classic -file cacheing. - -Like nc_create(), this function creates a netCDF file. - -\param path The file name of the new netCDF dataset. - -\param cmode The creation mode flag, the same as in nc_create(). - -\param initialsz On some systems, and with custom I/O layers, it may -be advantageous to set the size of the output file at creation -time. This parameter sets the initial size of the file at creation -time. This only applies to classic and 64-bit offset files. -The special value NC_SIZEHINT_DEFAULT (which is the value 0), -lets the netcdf library choose a suitable initial size. - -\param chunksizehintp A pointer to the chunk size hint, -which 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 a NULL pointer or -having the pointer point to the value NC_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. This only -applies to classic and 64-bit offset files. - -\param ncidp Pointer to location where returned netCDF ID is to be -stored. - -\note This function uses the same return codes as the nc_create() -function. - -\returns ::NC_NOERR No error. -\returns ::NC_ENOMEM System out of memory. -\returns ::NC_EHDFERR HDF5 error (netCDF-4 files only). -\returns ::NC_EFILEMETA Error writing netCDF-4 file-level metadata in -HDF5 file. (netCDF-4 files only). -\returns ::NC_EDISKLESS if there was an error in creating the -in-memory file. - -

Examples

- -In this example we create a netCDF dataset named foo_large.nc; we want -the dataset to be created in the current directory only if a dataset -with that name does not already exist. We also specify that bufrsize -and initial size for the file. - -\code +/** + * Create a netCDF file with some extra parameters controlling classic + * file cacheing. + * + * Like nc_create(), this function creates a netCDF file. + * + * @param path The file name of the new netCDF dataset. + * @param cmode The creation mode flag, the same as in nc_create(). + * @param initialsz On some systems, and with custom I/O layers, it + * may be advantageous to set the size of the output file at creation + * time. This parameter sets the initial size of the file at creation + * time. This only applies to classic and 64-bit offset files. The + * special value NC_SIZEHINT_DEFAULT (which is the value 0), lets the + * netcdf library choose a suitable initial size. + * @param chunksizehintp A pointer to the chunk size hint, which + * 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 + * a NULL pointer or having the pointer point to the value + * NC_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. This only applies to classic and 64-bit offset files. + * @param ncidp Pointer to location where returned netCDF ID is to be + * stored. + * + * @note This function uses the same return codes as the nc_create() + * function. + * + * @returns ::NC_NOERR No error. + * @returns ::NC_ENOMEM System out of memory. + * @returns ::NC_EHDFERR HDF5 error (netCDF-4 files only). + * @returns ::NC_EFILEMETA Error writing netCDF-4 file-level metadata in + * HDF5 file. (netCDF-4 files only). + * @returns ::NC_EDISKLESS if there was an error in creating the + * in-memory file. + * + *

Examples

+ * + * In this example we create a netCDF dataset named foo_large.nc; we + * want the dataset to be created in the current directory only if a + * dataset with that name does not already exist. We also specify that + * bufrsize and initial size for the file. + * + * @code #include ... int status = NC_NOERR; @@ -512,10 +516,10 @@ and initial size for the file. *bufrsize = 1024; status = nc__create("foo.nc", NC_NOCLOBBER, initialsz, bufrsize, &ncid); if (status != NC_NOERR) handle_error(status); -\endcode - -\ingroup datasets -\author Glenn Davis, Russ Rew, Dennis Heimbigner +@endcode + * + * @ingroup datasets + * @author Glenn Davis */ int nc__create(const char *path, int cmode, size_t initialsz, @@ -526,12 +530,23 @@ nc__create(const char *path, int cmode, size_t initialsz, } /** -\internal - -\deprecated This function was used in the old days with the Cray at -NCAR. The Cray is long gone, and this call is supported only for -backward compatibility. - + * @internal Create a file with special (deprecated) Cray settings. + * + * @deprecated This function was used in the old days with the Cray at + * NCAR. The Cray is long gone, and this call is supported only for + * backward compatibility. Use nc_create() instead. + * + * @param path File name. + * @param cmode Create mode. + * @param initialsz Initial size of metadata region for classic files, + * ignored for other files. + * @param basepe Deprecated parameter from the Cray days. + * @param chunksizehintp A pointer to the chunk size hint. This only + * applies to classic and 64-bit offset files. + * @param ncidp Pointer that gets ncid. + * + * @return ::NC_NOERR No error. + * @author Glenn Davis */ int nc__create_mp(const char *path, int cmode, size_t initialsz, @@ -541,119 +556,116 @@ nc__create_mp(const char *path, int cmode, size_t initialsz, chunksizehintp, 0, NULL, ncidp); } -/** \ingroup datasets -Open an existing netCDF file. - -This function opens an existing netCDF dataset for access. It -determines the underlying file format automatically. Use the same call -to open a netCDF classic, 64-bit offset, or netCDF-4 file. - -\param path File name for netCDF dataset to be opened. When DAP -support is enabled, then the path may be an OPeNDAP URL rather than a -file path. - -\param mode The mode flag may include NC_WRITE (for read/write -access) and NC_SHARE (see below) and NC_DISKLESS (see below). - -\param ncidp Pointer to location where returned netCDF ID is to be -stored. - -

Open Mode

- -A zero value (or ::NC_NOWRITE) specifies the default behavior: open the -dataset with read-only access, buffering and caching accesses for -efficiency. - -Otherwise, the open mode is ::NC_WRITE, ::NC_SHARE, or -::NC_WRITE|::NC_SHARE. Setting the ::NC_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 NC_SHARE flag is only used for netCDF classic and 64-bit offset -files. It 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 NC_SHARE flag. - -This procedure may also be invoked with the NC_DISKLESS flag -set in the mode argument if the file to be opened is a -classic format file. For nc_open(), this flag applies only -to files in classic format. If the file is of type -NC_NETCDF4, then the NC_DISKLESS flag will be ignored. - -If NC_DISKLESS is specified, then the whole file is read completely into -memory. In effect this creates an in-memory cache of the file. -If the mode flag also specifies NC_WRITE, then the in-memory cache -will be re-written to the disk file when nc_close() is called. -For some kinds of manipulations, having the in-memory cache can -speed up file processing. But in simple cases, non-cached -processing may actually be faster than using cached processing. -You will need to experiment to determine if the in-memory caching -is worthwhile for your application. - -Normally, NC_DISKLESS allocates space in the heap for -storing the in-memory file. If, however, the ./configure -flags --enable-mmap is used, and the additional mode flag -NC_MMAP is specified, then the file will be opened using -the operating system MMAP facility. -This flag only applies to files in classic format. Extended -format (netcdf-4) files will ignore the NC_MMAP flag. - -In most cases, using MMAP provides no advantage -for just NC_DISKLESS. The one case where using MMAP is an -advantage is when a file is to be opened and only a small portion -of its data is to be read and/or written. -In this scenario, MMAP will cause only the accessed data to be -retrieved from disk. Without MMAP, NC_DISKLESS will read the whole -file into memory on nc_open. Thus, MMAP will provide some performance -improvement in this case. - -It is not necessary to pass any information about the format of the -file being opened. The file type will be detected automatically by the -netCDF library. - -If a the path is a DAP URL, then the open mode is read-only. -Setting NC_WRITE will be ignored. - -As of version 4.3.1.2, multiple calls to nc_open with the same -path will return the same ncid value. - -\note When opening a netCDF-4 file HDF5 error reporting is turned off, -if it is on. This doesn't stop the HDF5 error stack from recording the -errors, it simply stops their display to the user through stderr. - -nc_open()returns the value NC_NOERR if no errors occurred. Otherwise, -the returned status indicates an error. Possible causes of errors -include: - -Note that nc_open(path,cmode,ncidp) is equivalent to the invocation of -nc__open(path,cmode,NC_SIZEHINT_DEFAULT,NULL,ncidp). - -\returns ::NC_NOERR No error. - -\returns ::NC_ENOMEM Out of memory. - -\returns ::NC_EHDFERR HDF5 error. (NetCDF-4 files only.) - -\returns ::NC_EDIMMETA Error in netCDF-4 dimension metadata. (NetCDF-4 files only.) - -

Examples

- -Here is an example using nc_open()to open an existing netCDF dataset -named foo.nc for read-only, non-shared access: - -@code -#include - ... -int status = NC_NOERR; -int ncid; - ... -status = nc_open("foo.nc", 0, &ncid); -if (status != NC_NOERR) handle_error(status); -@endcode +/** + * Open an existing netCDF file. + * + * This function opens an existing netCDF dataset for access. It + * determines the underlying file format automatically. Use the same + * call to open a netCDF classic, 64-bit offset, or netCDF-4 file. + * + * @param path File name for netCDF dataset to be opened. When DAP + * support is enabled, then the path may be an OPeNDAP URL rather than + * a file path. + * @param mode The mode flag may include NC_WRITE (for read/write + * access) and NC_SHARE (see below) and NC_DISKLESS (see below). + * @param ncidp Pointer to location where returned netCDF ID is to be + * stored. + * + *

Open Mode

+ * + * A zero value (or ::NC_NOWRITE) specifies the default behavior: open + * the dataset with read-only access, buffering and caching accesses + * for efficiency. + * + * Otherwise, the open mode is ::NC_WRITE, ::NC_SHARE, or + * ::NC_WRITE|::NC_SHARE. Setting the ::NC_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 NC_SHARE flag is only used for netCDF classic and 64-bit offset + * files. It 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 NC_SHARE flag. + * + * This procedure may also be invoked with the NC_DISKLESS flag set in + * the mode argument if the file to be opened is a classic format + * file. For nc_open(), this flag applies only to files in classic + * format. If the file is of type NC_NETCDF4, then the NC_DISKLESS + * flag will be ignored. + * + * If NC_DISKLESS is specified, then the whole file is read completely + * into memory. In effect this creates an in-memory cache of the file. + * If the mode flag also specifies NC_WRITE, then the in-memory cache + * will be re-written to the disk file when nc_close() is called. For + * some kinds of manipulations, having the in-memory cache can speed + * up file processing. But in simple cases, non-cached processing may + * actually be faster than using cached processing. You will need to + * experiment to determine if the in-memory caching is worthwhile for + * your application. + * + * Normally, NC_DISKLESS allocates space in the heap for storing the + * in-memory file. If, however, the ./configure flags --enable-mmap is + * used, and the additional mode flag NC_MMAP is specified, then the + * file will be opened using the operating system MMAP facility. This + * flag only applies to files in classic format. Extended format + * (netcdf-4) files will ignore the NC_MMAP flag. + * + * In most cases, using MMAP provides no advantage for just + * NC_DISKLESS. The one case where using MMAP is an advantage is when + * a file is to be opened and only a small portion of its data is to + * be read and/or written. In this scenario, MMAP will cause only the + * accessed data to be retrieved from disk. Without MMAP, NC_DISKLESS + * will read the whole file into memory on nc_open. Thus, MMAP will + * provide some performance improvement in this case. + * + * It is not necessary to pass any information about the format of the + * file being opened. The file type will be detected automatically by + * the netCDF library. + * + * If a the path is a DAP URL, then the open mode is read-only. + * Setting NC_WRITE will be ignored. + * + * As of version 4.3.1.2, multiple calls to nc_open with the same + * path will return the same ncid value. + * + * @note When opening a netCDF-4 file HDF5 error reporting is turned + * off, if it is on. This doesn't stop the HDF5 error stack from + * recording the errors, it simply stops their display to the user + * through stderr. + * + * nc_open()returns the value NC_NOERR if no errors + * occurred. Otherwise, the returned status indicates an + * error. Possible causes of errors include: + * + * Note that nc_open(path,cmode,ncidp) is equivalent to the invocation + * of nc__open(path,cmode,NC_SIZEHINT_DEFAULT,NULL,ncidp). + * + * @returns ::NC_NOERR No error. + * @returns ::NC_ENOMEM Out of memory. + * @returns ::NC_EHDFERR HDF5 error. (NetCDF-4 files only.) + * @returns ::NC_EDIMMETA Error in netCDF-4 dimension metadata. (NetCDF-4 files only.) + * + *

Examples

+ * + * Here is an example using nc_open()to open an existing netCDF dataset + * named foo.nc for read-only, non-shared access: + * + * @code + * #include + * ... + * int status = NC_NOERR; + * int ncid; + * ... + * status = nc_open("foo.nc", 0, &ncid); + * if (status != NC_NOERR) handle_error(status); + * @endcode + * @ingroup datasets + * @author Glenn Davis, Ed Hartnett, Dennis Heimbigner */ int nc_open(const char *path, int mode, int *ncidp) @@ -790,12 +802,22 @@ nc_open_mem(const char* path, int mode, size_t size, void* memory, int* ncidp) } /** -\internal - -\deprecated This function was used in the old days with the Cray at -NCAR. The Cray is long gone, and this call is supported only for -backward compatibility. - + * @internal Open a netCDF file with extra parameters for Cray. + * + * @deprecated This function was used in the old days with the Cray at + * NCAR. The Cray is long gone, and this call is supported only for + * backward compatibility. Use nc_open() instead. + * + * @param path The file name of the new netCDF dataset. + * @param mode Open mode. + * @param basepe Deprecated parameter from the Cray days. + * @param chunksizehintp A pointer to the chunk size hint. This only + * applies to classic and 64-bit offset files. + * @param ncidp Pointer to location where returned netCDF ID is to be + * stored. + * + * @return ::NC_NOERR + * @author Glenn Davis */ int nc__open_mp(const char *path, int mode, int basepe, @@ -1362,15 +1384,18 @@ nc_set_fill(int ncid, int fillmode, int *old_modep) } /** -\internal - -\deprecated This function was used in the old days with the Cray at -NCAR. The Cray is long gone, and this call is supported only for -backward compatibility. - -\returns ::NC_NOERR No error. - -\returns ::NC_EBADID Invalid ncid passed. + * @internal Learn base PE. + * + * @deprecated This function was used in the old days with the Cray at + * NCAR. The Cray is long gone, and this call is supported only for + * backward compatibility. + * + * @param ncid File and group ID. + * @param pe Pointer for base PE. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Invalid ncid passed. + * @author Glenn Davis */ int nc_inq_base_pe(int ncid, int *pe) @@ -1382,15 +1407,18 @@ nc_inq_base_pe(int ncid, int *pe) } /** -\internal - -\deprecated This function was used in the old days with the Cray at -NCAR. The Cray is long gone, and this call is supported only for -backward compatibility. - -\returns ::NC_NOERR No error. - -\returns ::NC_EBADID Invalid ncid passed. + * @internal Sets base processing element (ignored). + * + * @deprecated This function was used in the old days with the Cray at + * NCAR. The Cray is long gone, and this call is supported only for + * backward compatibility. + * + * @param ncid File ID. + * @param pe Base PE. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Invalid ncid passed. + * @author Glenn Davis */ int nc_set_base_pe(int ncid, int pe) @@ -1516,6 +1544,16 @@ nc_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp) return ncp->dispatch->inq(ncid,ndimsp,nvarsp,nattsp,unlimdimidp); } +/** + * Learn the number of variables in a file or group. + * + * @param ncid File and group ID. + * @param nvarsp Pointer that gets number of variables. Ignored if NULL. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Glenn Davis, Ed Hartnett, Dennis Heimbigner + */ int nc_inq_nvars(int ncid, int *nvarsp) { @@ -1615,37 +1653,95 @@ nc_inq_type(int ncid, nc_type xtype, char *name, size_t *size) } /** -\internal -\ingroup dispatch - -Create a file, calling the appropriate dispatch create call. - -For create, we have the following pieces of information to use to -determine the dispatch table: -- path -- cmode - -\param path0 The file name of the new netCDF dataset. +Check the create mode parameter for sanity. -\param cmode The creation mode flag, the same as in nc_create(). +Some create flags cannot be used if corresponding library features are +enabled during the build. This function does a pre-check of the mode +flag before calling the dispatch layer nc_create functions. -\param initialsz This parameter sets the initial size of the file at creation -time. This only applies to classic and 64-bit offset files. +\param cmode The creation mode flag. -\param basepe Deprecated parameter from the Cray days. - -\param chunksizehintp A pointer to the chunk size hint. This only -applies to classic and 64-bit offset files. +\returns ::NC_NOERR No error. +\returns ::NC_ENOTBUILT Requested feature not built into library +\returns ::NC_NINVAL Invalid combination of modes. +\internal +\ingroup dispatch +\author Ed Hartnett +*/ +static int +check_create_mode(int mode) +{ + int mode_format; -\param useparallel Non-zero if parallel I/O is to be used on this -file. + /* This is a clever check to see if more than one format bit is + * set. */ + mode_format = (mode & NC_NETCDF4) | (mode & NC_64BIT_OFFSET) | + (mode & NC_CDF5); + if (mode_format && (mode_format & (mode_format - 1))) + return NC_EINVAL; + + /* Can't use both NC_MPIIO and NC_MPIPOSIX. Make up your damn + * mind! */ + if (mode & NC_MPIIO && mode & NC_MPIPOSIX) + return NC_EINVAL; + + /* Can't use both parallel and diskless. */ + if ((mode & NC_MPIIO && mode & NC_DISKLESS) || + (mode & NC_MPIPOSIX && mode & NC_DISKLESS)) + return NC_EINVAL; -\param parameters Pointer to MPI comm and info. +#ifndef USE_DISKLESS + /* If diskless is requested, but not built, return error. */ + if (mode & NC_DISKLESS) + return NC_ENOTBUILT; + if (mode & NC_INMEMORY) + return NC_ENOTBUILT; +#endif + +#ifndef USE_NETCDF4 + /* If the user asks for a netCDF-4 file, and the library was built + * without netCDF-4, then return an error.*/ + if (mode & NC_NETCDF4) + return NC_ENOTBUILT; +#endif /* USE_NETCDF4 undefined */ + +#ifndef USE_PARALLEL + /* If parallel support is not included, these mode flags won't + * work. */ + if (mode & NC_PNETCDF || mode & NC_MPIPOSIX) + return NC_ENOTBUILT; +#endif /* USE_PARALLEL */ -\param ncidp Pointer to location where returned netCDF ID is to be -stored. + /* Well I guess there is some sanity in the world after all. */ + return NC_NOERR; +} -\returns ::NC_NOERR No error. +/** + * @internal Create a file, calling the appropriate dispatch create + * call. + * + * For create, we have the following pieces of information to use to + * determine the dispatch table: + * - path + * - cmode + * + * @param path0 The file name of the new netCDF dataset. + * @param cmode The creation mode flag, the same as in nc_create(). + * @param initialsz This parameter sets the initial size of the file + * at creation time. This only applies to classic and 64-bit offset + * files. + * @param basepe Deprecated parameter from the Cray days. + * @param chunksizehintp A pointer to the chunk size hint. This only + * applies to classic and 64-bit offset files. + * @param useparallel Non-zero if parallel I/O is to be used on this + * file. + * @param parameters Pointer to MPI comm and info. + * @param ncidp Pointer to location where returned netCDF ID is to be + * stored. + * + * @returns ::NC_NOERR No error. + * @ingroup dispatch + * @author Dennis Heimbigner, Ed Hartnett, Ward Fisher */ int NC_create(const char *path0, int cmode, size_t initialsz, @@ -1664,6 +1760,11 @@ NC_create(const char *path0, int cmode, size_t initialsz, TRACE(nc_create); if(path0 == NULL) return NC_EINVAL; + + /* Check mode flag for sanity. */ + if ((stat = check_create_mode(cmode))) + return stat; + /* Initialize the dispatch table. The function pointers in the * dispatch table will depend on how netCDF was built * (with/without netCDF-4, DAP, CDMREMOTE). */ @@ -1813,25 +1914,31 @@ NC_create(const char *path0, int cmode, size_t initialsz, } /** -\internal -\ingroup dispatch - -Open a netCDF file (or remote dataset) calling the appropriate -dispatch function. - -For open, we have the following pieces of information to use to determine the dispatch table. -- table specified by override -- path -- cmode -- the contents of the file (if it exists), basically checking its magic number. - -\returns ::NC_NOERR No error. + * @internal Open a netCDF file (or remote dataset) calling the + * appropriate dispatch function. + * + * For open, we have the following pieces of information to use to + * determine the dispatch table. + * - table specified by override + * - path + * - cmode + * - the contents of the file (if it exists), basically checking its magic number. + * + * @param path0 Path to the file to open. + * @param cmode Open mode. + * @param basepe Base processing element (ignored). + * @param chunksizehintp Size hint for classic files. + * @param useparallel If true use parallel I/O. + * @param parameters Extra parameters for the open. + * @param ncidp Pointer that gets ncid. + * + * @returns ::NC_NOERR No error. + * @ingroup dispatch + * @author Dennis Heimbigner */ int -NC_open(const char *path0, int cmode, - int basepe, size_t *chunksizehintp, - int useparallel, void* parameters, - int *ncidp) +NC_open(const char *path0, int cmode, int basepe, size_t *chunksizehintp, + int useparallel, void* parameters, int *ncidp) { int stat = NC_NOERR; NC* ncp = NULL; @@ -2022,11 +2129,15 @@ NC_open(const char *path0, int cmode, for systems that are not file based (e.g. dap, memio). */ -/* Static counter for pseudo file descriptors (incremented) */ +/** @internal Static counter for pseudo file descriptors (incremented) */ static int pseudofd = 0; -/* Create a pseudo file descriptor that does not - overlap real file descriptors +/** + * @internal Create a pseudo file descriptor that does not + * overlap real file descriptors + * + * @return pseudo file number + * @author Dennis Heimbigner */ int nc__pseudofd(void) @@ -2166,6 +2277,15 @@ readmagic(struct MagicFile* file, long pos, char* magic) return status; } +/** + * Close the file opened to check for magic number. + * + * @param file pointer to the MagicFile struct for this open file. + * @returns NC_NOERR for success + * @returns NC_EPARINIT if there was a problem closing file with MPI + * (parallel builds only). + * @author Dennis Heimbigner + */ static int closemagic(struct MagicFile* file) { diff --git a/libdispatch/dv2i.c b/libdispatch/dv2i.c index 2ba621433f..5d41238034 100644 --- a/libdispatch/dv2i.c +++ b/libdispatch/dv2i.c @@ -30,10 +30,11 @@ documentation. The V2 API is tested in test directory nctest. */ -/* The subroutines in error.c emit no messages unless NC_VERBOSE bit +/** The subroutines in error.c emit no messages unless NC_VERBOSE bit * is on. They call exit() when NC_FATAL bit is on. */ int ncopts = (NC_FATAL | NC_VERBOSE) ; -int ncerr = NC_NOERR ; + +int ncerr = NC_NOERR ; /**< V2 API error code. */ #if SIZEOF_LONG == SIZEOF_SIZE_T /* @@ -41,13 +42,15 @@ int ncerr = NC_NOERR ; * to 'size_t' or 'ptrdiff_t'. Use dummy macros. */ -# define NDIMS_DECL +# define NDIMS_DECL /**< NDIMS declaration */ + +/** @internal Declaration. */ # define A_DECL(name, type, ndims, rhs) \ const type *const name = ((const type *)(rhs)) -# define A_FREE(name) +# define A_FREE(name) /**< Free a variable. */ -# define A_INIT(lhs, type, ndims, rhs) +# define A_INIT(lhs, type, ndims, rhs) /**< Init a variable */ #else /* @@ -115,11 +118,19 @@ static void* nvmalloc(off_t size) { #endif -typedef signed char schar; +typedef signed char schar; /**< Signed character type. */ -/* +/** * Computes number of record variables in an open netCDF file, and an array of * the record variable ids, if the array parameter is non-null. + * + * @param ncid File ID. + * @param nrecvarsp Pointer that gets number of record variables. + * @param recvarids Pointer that gets array of record variable IDs. + * + * @return ::NC_NOERR No error. + * @return -1 on error. + * @author Russ Rew */ static int numrecvars(int ncid, int* nrecvarsp, int *recvarids) @@ -163,9 +174,15 @@ numrecvars(int ncid, int* nrecvarsp, int *recvarids) } -/* +/** * Computes record size (in bytes) of the record variable with a specified * variable id. Returns size as 0 if not a record variable. + * + * @param ncid File ID. + * @param varid Variable ID. + * @param recsizep Pointer that gets record size. + * + * @return size, or 0 if not a record variable */ static int ncrecsize(int ncid, int varid, size_t *recsizep) @@ -207,9 +224,17 @@ ncrecsize(int ncid, int varid, size_t *recsizep) } -/* +/** * Retrieves the dimension sizes of a variable with a specified variable id in - * an open netCDF file. Returns -1 on error. + * an open netCDF file. + * + * @param ncid File ID. + * @param varid Variable ID. + * @param sizes Pointer that gets sizes. + * + * @return ::NC_NOERR No error. + * @return -1 on error. + * @author Russ Rew */ static int dimsizes(int ncid, int varid, size_t *sizes) diff --git a/libdispatch/dvar.c b/libdispatch/dvar.c index 9d2cd0ce2e..11bc55903c 100644 --- a/libdispatch/dvar.c +++ b/libdispatch/dvar.c @@ -8,7 +8,8 @@ Research/Unidata. See COPYRIGHT file for more info. #include "ncdispatch.h" #include "netcdf_f.h" -/** \defgroup variables Variables +/** +\defgroup variables Variables Variables hold multi-dimensional arrays of data. @@ -121,14 +122,15 @@ classic or 64-bit offset format files, or in netCDF-4 files if they are created with the NC_CLASSIC_MODEL flags. */ -/** \name Defining Variables +/** +@name Defining Variables Use these functions to define variables. */ /*! \{ */ /** -\ingroup variables +@ingroup variables Define a new variable. This function adds a new variable to an open netCDF dataset or group. @@ -136,45 +138,45 @@ 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. -\param ncid NetCDF or group ID, from a previous call to nc_open(), +@param ncid NetCDF or group ID, from a previous call to nc_open(), nc_create(), nc_def_grp(), or associated inquiry functions such as nc_inq_ncid(). -\param name Variable \ref object_name. +@param name Variable \ref object_name. -\param xtype \ref data_type of the variable. +@param xtype \ref data_type of the variable. -\param ndims Number of dimensions for the variable. For example, 2 +@param ndims 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 ::NC_MAX_VAR_DIMS. -\param dimidsp Vector of ndims dimension IDs corresponding to the +@param dimidsp Vector of ndims dimension IDs corresponding to the variable dimensions. For classic model netCDF files, 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. -\param varidp Pointer to location for the returned variable ID. +@param varidp Pointer to location for the returned variable ID. -\returns ::NC_NOERR No error. -\returns ::NC_EBADID Bad ncid. -\returns ::NC_ENOTINDEFINE Not in define mode. -\returns ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3 netcdf-4 file. -\returns ::NC_EMAXVARS NC_MAX_VARS exceeded [Not enforced after 4.5.0] -\returns ::NC_EBADTYPE Bad type. -\returns ::NC_EINVAL Invalid input. -\returns ::NC_ENAMEINUSE Name already in use. -\returns ::NC_EPERM Attempt to create object in read-only file. +@returns ::NC_NOERR No error. +@returns ::NC_EBADID Bad ncid. +@returns ::NC_ENOTINDEFINE Not in define mode. +@returns ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3 netcdf-4 file. +@returns ::NC_EMAXVARS NC_MAX_VARS exceeded [Not enforced after 4.5.0] +@returns ::NC_EBADTYPE Bad type. +@returns ::NC_EINVAL Invalid input. +@returns ::NC_ENAMEINUSE Name already in use. +@returns ::NC_EPERM Attempt to create object in read-only file. -\section nc_def_var_example Example +@section nc_def_var_example Example Here is an example using nc_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: -\code +@code #include ... int status; @@ -200,8 +202,8 @@ dataset named foo.nc: rh_dimids[2] = lon_dim; status = nc_def_var (ncid, "rh", NC_DOUBLE, 3, rh_dimids, &rh_id); if (status != NC_NOERR) handle_error(status); -\endcode - +@endcode +@author Glenn Davis, Ed Hartnett, Dennis Heimbigner */ int nc_def_var(int ncid, const char *name, nc_type xtype, @@ -218,14 +220,16 @@ nc_def_var(int ncid, const char *name, nc_type xtype, } /*! \} */ -/** \name Rename a Variable +/** +@name Rename a Variable Rename a variable. */ /*! \{ */ -/** Rename a variable. -\ingroup variables +/** +Rename a variable. +@ingroup variables This function changes the name of a netCDF variable in an open netCDF file or group. You cannot rename a variable to have the name of any existing @@ -235,28 +239,28 @@ For classic format, 64-bit offset format, and netCDF-4/HDF5 with classic mode, if the new name is longer than the old name, the netCDF dataset must be in define mode. -\param ncid NetCDF or group ID, from a previous call to nc_open(), +@param ncid NetCDF or group ID, from a previous call to nc_open(), nc_create(), nc_def_grp(), or associated inquiry functions such as nc_inq_ncid(). -\param varid Variable ID +@param varid Variable ID -\param name New name of the variable. +@param name New name of the variable. -\returns ::NC_NOERR No error. -\returns ::NC_EBADID Bad ncid. -\returns ::NC_ENOTVAR Invalid variable ID. -\returns ::NC_EBADNAME Bad name. -\returns ::NC_EMAXNAME Name is too long. -\returns ::NC_ENAMEINUSE Name in use. -\returns ::NC_ENOMEM Out of memory. +@returns ::NC_NOERR No error. +@returns ::NC_EBADID Bad ncid. +@returns ::NC_ENOTVAR Invalid variable ID. +@returns ::NC_EBADNAME Bad name. +@returns ::NC_EMAXNAME Name is too long. +@returns ::NC_ENAMEINUSE Name in use. +@returns ::NC_ENOMEM Out of memory. -\section nc_rename_var_example Example +@section nc_rename_var_example Example Here is an example using nc_rename_var to rename the variable rh to rel_hum in an existing netCDF dataset named foo.nc: -\code +@code #include ... int status; @@ -274,7 +278,7 @@ rel_hum in an existing netCDF dataset named foo.nc: if (status != NC_NOERR) handle_error(status); status = nc_enddef(ncid); if (status != NC_NOERR) handle_error(status); -\endcode +@endcode */ int @@ -288,8 +292,15 @@ nc_rename_var(int ncid, int varid, const char *name) } /*! \} */ -/** \internal -\ingroup variables +/** +@ingroup variables +@internal Does a variable have a record dimension? + +@param ncid File ID. +@param varid Variable ID. +@param nrecs Pointer that gets number of records. + +@returns 0 if not a record var, 1 if it is. */ int NC_is_recvar(int ncid, int varid, size_t* nrecs) @@ -311,21 +322,31 @@ NC_is_recvar(int ncid, int varid, size_t* nrecs) return (dimset[0] == unlimid ? 1: 0); } -/** \internal -\ingroup variables -Get the number of record dimensions for a variable and an array that -identifies which of a variable's dimensions are record dimensions. -Intended to be used instead of NC_is_recvar, which doesn't work for -netCDF-4 variables which have multiple unlimited dimensions or an -unlimited dimension that is not the first of a variable's dimensions. +/** +@ingroup variables +@internal Get the number of record dimensions for a variable and an +array that identifies which of a variable's dimensions are record +dimensions. Intended to be used instead of NC_is_recvar(), which +doesn't work for netCDF-4 variables which have multiple unlimited +dimensions or an unlimited dimension that is not the first of a +variable's dimensions. + +@param ncid File ID. +@param varid Variable ID. +@param nrecdimsp Pointer that gets number of record dims. +@param is_recdim Pointer that gets 1 if there is one or more record +dimensions, 0 if not. + +@returns 0 if not a record var, 1 if it is. + Example use: -\code +@code int nrecdims; int is_recdim[NC_MAX_VAR_DIMS]; ... status = NC_inq_recvar(ncid,varid,&nrecdims,is_recdim); isrecvar = (nrecdims > 0); -\endcode +@endcode */ int NC_inq_recvar(int ncid, int varid, int* nrecdimsp, int *is_recdim) @@ -651,43 +672,49 @@ nc_free_string(size_t len, char **data) return NC_NOERR; } -/** \ingroup variables - -Set the compression settings for a netCDF-4/HDF5 variable. - -This function must be called after nc_def_var and before nc_enddef or -any functions which writes data to the file. - -\param ncid NetCDF or group ID, from a previous call to nc_open(), -nc_create(), nc_def_grp(), or associated inquiry functions such as -nc_inq_ncid(). - -\param varid Variable ID - -\param shuffle True to turn on the shuffle filter. - -\param deflate True to turn on deflation for this variable. - -\param deflate_level A number between 0 (no compression) and 9 -(maximum compression). - -\returns ::NC_NOERR No error. -\returns ::NC_EBADID Bad ncid. -\returns ::NC_ENOTVAR Invalid variable ID. -\returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is -not netCDF-4/HDF5. -\returns ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3 -netcdf-4 file. -\returns ::NC_ELATEDEF Too late to change settings for this variable. -\returns ::NC_EINVAL Invalid input - -\section nc_def_var_deflate_example Example +/** + * @ingroup variables + * + * Set the compression settings for a netCDF-4/HDF5 variable. + * + * This function must be called after nc_def_var and before nc_enddef + * or any functions which writes data to the file. + * + * @param ncid NetCDF or group ID, from a previous call to nc_open(), + * nc_create(), nc_def_grp(), or associated inquiry functions such as + * nc_inq_ncid(). + * @param varid Variable ID + * @param shuffle True to turn on the shuffle filter. + * @param deflate True to turn on deflation for this variable. + * @param deflate_level A number between 0 (no compression) and 9 + * (maximum compression). + * + * @returns ::NC_NOERR No error. + * @returns ::NC_EBADID Bad ncid. + * @returns ::NC_ENOTVAR Invalid variable ID. + * @returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is + * not netCDF-4/HDF5. + * @returns ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3 + * netcdf-4 file. + * @returns ::NC_ELATEDEF Too late to change settings for this variable. + * @returns ::NC_ENOTINDEFINE Not in define mode. + * @returns ::NC_EPERM File is read only. + * @returns ::NC_EMAXDIMS Classic model file exceeds ::NC_MAX_VAR_DIMS. + * @returns ::NC_ESTRICTNC3 Attempting to create netCDF-4 type var in +classic model file + * @returns ::NC_EBADTYPE Bad type. + * @returns ::NC_ENOMEM Out of memory. + * @returns ::NC_EHDFERR Error returned by HDF5 layer. + * @returns ::NC_EINVAL Invalid input. Deflate can't be set unless +variable storage is NC_CHUNK. + +@section nc_def_var_deflate_example Example Here is an example from /examples/C/simple_xy_nc4_wr.c using nc_def_var_deflate to create a variable and then turn on the shuffle filter and compression. -\code +@code #include #define NDIMS 2 #define NX 6 @@ -724,7 +751,7 @@ filter and compression. deflate_level))) ERR(retval); ... -\endcode +@endcode */ int nc_def_var_deflate(int ncid, int varid, int shuffle, int deflate, int deflate_level) @@ -735,31 +762,30 @@ nc_def_var_deflate(int ncid, int varid, int shuffle, int deflate, int deflate_le return ncp->dispatch->def_var_deflate(ncid,varid,shuffle,deflate,deflate_level); } -/** \ingroup variables - -Set checksum for a var. - -This function must be called after nc_def_var and before nc_enddef or -any functions which writes data to the file. - -\param ncid NetCDF or group ID, from a previous call to nc_open(), -nc_create(), nc_def_grp(), or associated inquiry functions such as -nc_inq_ncid(). - -\param varid Variable ID - -\param fletcher32 True to turn on Fletcher32 checksums for this -variable. - -\returns ::NC_NOERR No error. -\returns ::NC_EBADID Bad ncid. -\returns ::NC_ENOTVAR Invalid variable ID. -\returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is +/** + * @ingroup variables + * + * Set checksum for a var. + * + * This function must be called after nc_def_var and before nc_enddef + * or any functions which writes data to the file. + * + * @param ncid NetCDF or group ID, from a previous call to nc_open(), + * nc_create(), nc_def_grp(), or associated inquiry functions such as + * nc_inq_ncid(). + * @param varid Variable ID + * @param fletcher32 True to turn on Fletcher32 checksums for this + * variable. + * + * @returns ::NC_NOERR No error. + * @returns ::NC_EBADID Bad ncid. + * @returns ::NC_ENOTVAR Invalid variable ID. + * @returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is not netCDF-4/HDF5. -\returns ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3 + * @returns ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3 netcdf-4 file. -\returns ::NC_ELATEDEF Too late to change settings for this variable. -\returns ::NC_EINVAL Invalid input + * @returns ::NC_ELATEDEF Too late to change settings for this variable. + * @returns ::NC_EINVAL Invalid input */ int nc_def_var_fletcher32(int ncid, int varid, int fletcher32) @@ -807,19 +833,19 @@ array must have one chunksize for each dimension of the variable. If ::NC_CONTIGUOUS storage is set, then the chunksizes parameter is ignored. -\returns ::NC_NOERR No error. -\returns ::NC_EBADID Bad ID. -\returns ::NC_ENOTNC4 Not a netCDF-4 file. -\returns ::NC_ELATEDEF This variable has already been the subject of a + * @returns ::NC_NOERR No error. + * @returns ::NC_EBADID Bad ID. + * @returns ::NC_ENOTNC4 Not a netCDF-4 file. + * @returns ::NC_ELATEDEF This variable has already been the subject of a nc_enddef call. In netCDF-4 files nc_enddef will be called automatically for any data read or write. Once nc_enddef has been called after the nc_def_var call for a variable, it is impossible to set the chunking for that variable. -\returns ::NC_ENOTINDEFINE Not in define mode. This is returned for + * @returns ::NC_ENOTINDEFINE Not in define mode. This is returned for netCDF classic or 64-bit offset files, or for netCDF-4 files, when they wwere created with NC_STRICT_NC3 flag. See \ref nc_create. -\returns ::NC_EPERM Attempt to create object in read-only file. -\returns ::NC_EBADCHUNK Retunrs if the chunk size specified for a + * @returns ::NC_EPERM Attempt to create object in read-only file. + * @returns ::NC_EBADCHUNK Retunrs if the chunk size specified for a variable is larger than the length of the dimensions associated with variable. @@ -892,13 +918,13 @@ to hold one element of the data type of the variable. (For example, an NC_INT will require 4 bytes for it's fill value, which is also an NC_INT.) -\returns ::NC_NOERR No error. -\returns ::NC_EBADID Bad ID. -\returns ::NC_ENOTNC4 Not a netCDF-4 file. -\returns ::NC_ENOTINDEFINE Not in define mode. This is returned for + * @returns ::NC_NOERR No error. + * @returns ::NC_EBADID Bad ID. + * @returns ::NC_ENOTNC4 Not a netCDF-4 file. + * @returns ::NC_ENOTINDEFINE Not in define mode. This is returned for netCDF classic or 64-bit offset files, or for netCDF-4 files, when they wwere created with NC_STRICT_NC3 flag. See \ref nc_create. -\returns ::NC_EPERM Attempt to create object in read-only file. + * @returns ::NC_EPERM Attempt to create object in read-only file. \section nc_def_var_fill_example Example @@ -947,9 +973,10 @@ nc_def_var_fill(int ncid, int varid, int no_fill, const void *fill_value) return ncp->dispatch->def_var_fill(ncid,varid,no_fill,fill_value); } -/*! Define endianness of a variable. +/** +@ingroup variables -\ingroup variables +Define endianness of a variable. With this function the endianness (i.e. order of bits in integers) can be changed on a per-variable basis. By default, the endianness is the @@ -960,34 +987,34 @@ variable. This function may only be called after the variable is defined, but before nc_enddef is called. -\param[in] ncid NetCDF ID, from a previous call to nc_open or +@param[in] ncid NetCDF ID, from a previous call to nc_open or nc_create. -\param[in] varid Variable ID. +@param[in] varid Variable ID. -\param[in] endian NC_ENDIAN_NATIVE to select the native endianness of +@param[in] endian NC_ENDIAN_NATIVE to select the native endianness of the platform (the default), NC_ENDIAN_LITTLE to use little-endian, NC_ENDIAN_BIG to use big-endian. -\returns ::NC_NOERR No error. -\returns ::NC_EBADID Bad ID. -\returns ::NC_ENOTNC4 Not a netCDF-4 file. -\returns ::NC_ELATEDEF This variable has already been the subject of a +@returns ::NC_NOERR No error. +@returns ::NC_EBADID Bad ID. +@returns ::NC_ENOTNC4 Not a netCDF-4 file. +@returns ::NC_ELATEDEF This variable has already been the subject of a nc_enddef call. In netCDF-4 files nc_enddef will be called automatically for any data read or write. Once nc_enddef has been called after the nc_def_var call for a variable, it is impossible to set the chunking for that variable. -\returns ::NC_ENOTINDEFINE Not in define mode. This is returned for +@returns ::NC_ENOTINDEFINE Not in define mode. This is returned for netCDF classic or 64-bit offset files, or for netCDF-4 files, when they wwere created with NC_STRICT_NC3 flag. See \ref nc_create. -\returns ::NC_EPERM Attempt to create object in read-only file. +@returns ::NC_EPERM Attempt to create object in read-only file. -\section nc_def_var_endian_example Example +@section nc_def_var_endian_example Example In this example from libsrc4/tst_vars2.c, a variable is created, and the endianness set to NC_ENDIAN_BIG. -\code +@code #define NDIMS4 1 #define DIM4_NAME "Joe" #define VAR_NAME4 "Ed" @@ -1010,7 +1037,8 @@ the endianness set to NC_ENDIAN_BIG. if (dimids[0] != 0) ERR; if (nc_def_var(ncid, VAR_NAME4, NC_INT, NDIMS4, dimids, &varid)) ERR; if (nc_def_var_endian(ncid, varid, NC_ENDIAN_BIG)) ERR; -\endcode +@endcode +@author Ed Hartnett */ int nc_def_var_endian(int ncid, int varid, int endian) @@ -1021,6 +1049,18 @@ nc_def_var_endian(int ncid, int varid, int endian) return ncp->dispatch->def_var_endian(ncid,varid,endian); } +/** + * Define a new variable filter. + * + * @param ncid File and group ID. + * @param varid Variable ID. + * @param id + * @param nparams Number of filter parameters. + * @param parms Filter parameters. + * + * @return ::NC_NOERR No error. + * @author Dennis Heimbigner + */ int nc_def_var_filter(int ncid, int varid, unsigned int id, size_t nparams, const unsigned int* parms) { diff --git a/libdispatch/dvarget.c b/libdispatch/dvarget.c index cd5634f8d2..e11cb61d10 100644 --- a/libdispatch/dvarget.c +++ b/libdispatch/dvarget.c @@ -25,13 +25,19 @@ struct GETodometer { }; -/** \internal - +/** + * @internal Initialize odometer. + * + * @param odom Pointer to odometer. + * @param rank + * @param start Start indicies. + * @param edges Counts. + * @param stride Strides. + * */ static void -odom_init(struct GETodometer* odom, - int rank, - const size_t* start, const size_t* edges, const ptrdiff_t* stride) +odom_init(struct GETodometer* odom, int rank, const size_t* start, + const size_t* edges, const ptrdiff_t* stride) { int i; memset(odom,0,sizeof(struct GETodometer)); @@ -46,8 +52,12 @@ odom_init(struct GETodometer* odom, } } -/** \internal - +/** + * @internal Return true if there is more. + * + * @param odom Pointer to odometer. + * + * @return True if there is more, 0 otherwise. */ static int odom_more(struct GETodometer* odom) @@ -55,8 +65,12 @@ odom_more(struct GETodometer* odom) return (odom->index[0] < odom->stop[0]); } -/** \internal - +/** + * @internal Move odometer. + * + * @param odom Pointer to odometer. + * + * @return 0 or 1 */ static int odom_next(struct GETodometer* odom) diff --git a/libdispatch/dvarput.c b/libdispatch/dvarput.c index 7b29d09e96..c7e1fc8638 100644 --- a/libdispatch/dvarput.c +++ b/libdispatch/dvarput.c @@ -18,10 +18,19 @@ struct PUTodometer { size_t stop[NC_MAX_VAR_DIMS]; }; +/** + * @internal Initialize odometer. + * + * @param odom Pointer to odometer. + * @param rank + * @param start Start indicies. + * @param edges Counts. + * @param stride Strides. + * + */ static void -odom_init(struct PUTodometer* odom, - int rank, - const size_t* start, const size_t* edges, const ptrdiff_t* stride) +odom_init(struct PUTodometer* odom, int rank, const size_t* start, + const size_t* edges, const ptrdiff_t* stride) { int i; memset(odom,0,sizeof(struct PUTodometer)); @@ -36,12 +45,26 @@ odom_init(struct PUTodometer* odom, } } +/** + * @internal Return true if there is more. + * + * @param odom Pointer to odometer. + * + * @return True if there is more, 0 otherwise. + */ static int odom_more(struct PUTodometer* odom) { return (odom->index[0] < odom->stop[0]); } +/** + * @internal Return true if there is more. + * + * @param odom Pointer to odometer. + * + * @return True if there is more, 0 otherwise. + */ static int odom_next(struct PUTodometer* odom) { diff --git a/liblib/Makefile.am b/liblib/Makefile.am index e895af67f3..2fb5fdadd3 100644 --- a/liblib/Makefile.am +++ b/liblib/Makefile.am @@ -24,12 +24,6 @@ libnetcdf_la_CPPFLAGS = ${AM_CPPFLAGS} libnetcdf_la_LIBADD = CLEANFILES = -# Turn on some extra stuff when building a DLL for windows. -if BUILD_DLL -libnetcdf_la_LDFLAGS += -no-undefined -Wl,--output-def,netcdfdll.def -libnetcdf_la_CPPFLAGS += -DDLL_EXPORT -endif # BUILD_DLL - # The v2 API... if BUILD_V2 libnetcdf_la_LIBADD += ${top_builddir}/libdispatch/libnetcdf2.la diff --git a/libsrc/Makefile.am b/libsrc/Makefile.am index ce48785f4a..56727431d4 100644 --- a/libsrc/Makefile.am +++ b/libsrc/Makefile.am @@ -8,11 +8,6 @@ include $(top_srcdir)/lib_flags.am libnetcdf3_la_CPPFLAGS = ${AM_CPPFLAGS} -# Turn on a pre-processor flag when building a DLL for windows. -if BUILD_DLL -libnetcdf3_la_CPPFLAGS += -DDLL_EXPORT -endif # BUILD_DLL - # These files comprise the netCDF-3 classic library code. libnetcdf3_la_SOURCES = v1hpg.c \ putget.c attr.c nc3dispatch.c nc3internal.c var.c dim.c ncx.c nc_hashmap.c \ diff --git a/libsrc/v1hpg.c b/libsrc/v1hpg.c index 0e834a71d8..a69150386d 100644 --- a/libsrc/v1hpg.c +++ b/libsrc/v1hpg.c @@ -304,8 +304,11 @@ static int v1h_get_NC_string(v1hs *gsp, NC_string **ncstrpp) { int status = 0; - size_t padding = 0, nchars = 0; + size_t nchars = 0; NC_string *ncstrp = NULL; +#if USE_STRICT_NULL_BYTE_HEADER_PADDING + size_t padding = 0; +#endif /* USE_STRICT_NULL_BYTE_HEADER_PADDING */ status = v1h_get_size_t(gsp, &nchars); if(status != NC_NOERR) @@ -333,10 +336,10 @@ v1h_get_NC_string(v1hs *gsp, NC_string **ncstrpp) if(status != NC_NOERR) goto unwind_alloc; +#if USE_STRICT_NULL_BYTE_HEADER_PADDING padding = _RNDUP(X_SIZEOF_CHAR * ncstrp->nchars, X_ALIGN) - X_SIZEOF_CHAR * ncstrp->nchars; -#if USE_STRICT_NULL_BYTE_HEADER_PADDING if (padding > 0) { /* CDF specification: Header padding uses null (\x00) bytes. */ char pad[X_ALIGN-1]; @@ -692,7 +695,10 @@ v1h_get_NC_attrV(v1hs *gsp, NC_attr *attrp) const size_t perchunk = gsp->extent; size_t remaining = attrp->xsz; void *value = attrp->xvalue; - size_t nget, padding; + size_t nget; +#if USE_STRICT_NULL_BYTE_HEADER_PADDING + size_t padding; +#endif /* USE_STRICT_NULL_BYTE_HEADER_PADDING */ do { nget = MIN(perchunk, remaining); @@ -710,9 +716,8 @@ v1h_get_NC_attrV(v1hs *gsp, NC_attr *attrp) } while(remaining != 0); - padding = attrp->xsz - ncmpix_len_nctype(attrp->type) * attrp->nelems; - #if USE_STRICT_NULL_BYTE_HEADER_PADDING + padding = attrp->xsz - ncmpix_len_nctype(attrp->type) * attrp->nelems; if (padding > 0) { /* CDF specification: Header padding uses null (\x00) bytes. */ char pad[X_ALIGN-1]; diff --git a/libsrc4/Makefile.am b/libsrc4/Makefile.am index b064eb2859..80bdd8767a 100644 --- a/libsrc4/Makefile.am +++ b/libsrc4/Makefile.am @@ -2,23 +2,19 @@ # the COPYRIGHT file for more information. # This automake file generates the Makefile to build netCDF-4. +# Ed Hartnett include $(top_srcdir)/lib_flags.am libnetcdf4_la_CPPFLAGS = ${AM_CPPFLAGS} -# This turns on declspec magic in netcdf.h for windows DLLs. -if BUILD_DLL -libnetcdf4_la_CPPFLAGS += -DDLL_EXPORT -endif - # This is our output. The netCDF-4 convenience library. noinst_LTLIBRARIES = libnetcdf4.la -libnetcdf4_la_SOURCES = nc4dispatch.c nc4attr.c nc4dim.c \ -nc4file.c nc4grp.c nc4hdf.c nc4internal.c nc4type.c nc4var.c ncfunc.c error4.c \ +libnetcdf4_la_SOURCES = nc4dispatch.c nc4attr.c nc4dim.c nc4file.c \ +nc4grp.c nc4hdf.c nc4internal.c nc4type.c nc4var.c ncfunc.c error4.c \ nc4info.c nc4printer.c -EXTRA_DIST=CMakeLists.txt +EXTRA_DIST = CMakeLists.txt diff --git a/libsrc4/nc3stub.c b/libsrc4/nc3stub.c deleted file mode 100644 index 15fd4cdac3..0000000000 --- a/libsrc4/nc3stub.c +++ /dev/null @@ -1,997 +0,0 @@ -/* - * Copyright 1993-2011 University Corporation for Atmospheric - * Research/Unidata - * - */ - -#include "config.h" -#include -#include "nc.h" - -#ifndef MPI_INCLUDED -typedef int MPI_Comm; -typedef int MPI_Info; -#endif - -int -nc3_create(const char *path, int cmode, size_t initialsz, int basepe, - size_t *chunksizehintp, - MPI_Comm comm, MPI_Info info, - NC** ncp) {abort();} - -int -nc3_open(const char *path, int mode, int basepe, size_t *chunksizehintp, - int use_parallel, MPI_Comm comm, MPI_Info info, - NC** ncp) {abort();} - -int -nc3_redef(int ncid) {abort();} - -int -nc3__enddef(int ncid, size_t h_minfree, size_t v_align, - size_t v_minfree, size_t r_align) {abort();} - -int -nc3_sync(int ncid) {abort();} - -int -nc3_abort(int ncid) {abort();} - -int -nc3_close(int ncid) {abort();} - -int -nc3_set_fill(int ncid, int fillmode, int *old_modep) {abort();} - -int -nc3_set_base_pe(int ncid, int pe) {abort();} - -int -nc3_inq_base_pe(int ncid, int *pe) {abort();} - -int -nc3_inq_format(int ncid, int *formatp) {abort();} - -int -nc3_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp) {abort();} - -int -nc3_inq_type(int ncid, nc_type xtype,char* name,size_t* sizep) {abort();} - -/* Begin _dim */ - -int -nc3_def_dim(int ncid, const char *name, size_t len, int *idp) {abort();} - -int -nc3_inq_dimid(int ncid, const char *name, int *idp) {abort();} - -int -nc3_inq_dim(int ncid, int dimid, char *name, size_t *lenp) {abort();} - -int -nc3_rename_dim(int ncid, int dimid, const char *name) {abort();} - -/* End _dim */ -/* Begin _att */ - -int -nc3_inq_att(int ncid, int varid, const char *name, - nc_type *xtypep, size_t *lenp) {abort();} - -int -nc3_inq_attid(int ncid, int varid, const char *name, int *idp) {abort();} - -int -nc3_inq_attname(int ncid, int varid, int attnum, char *name) {abort();} - -int -nc3_rename_att(int ncid, int varid, const char *name, const char *newname) {abort();} - -int -nc3_del_att(int ncid, int varid, const char* name) {abort();} - -/* End _att */ -/* Begin {put,get}_att */ - -int -nc3_get_att(int ncid, int varid, const char *name, void *value, nc_type xtype) {abort();} - -int -nc3_put_att(int ncid, int varid, const char *name, nc_type datatype, - size_t len, const void *value, nc_type xtype) {abort();} - -/* End {put,get}_att */ -/* Begin _var */ - -int -nc3_def_var(int ncid, const char *name, - nc_type xtype, int ndims, const int *dimidsp, int *varidp) {abort();} - -int -nc3_inq_var(int ncid, int varid, char *name, - nc_type *xtypep, int *ndimsp, int *dimidsp, int *nattsp) {abort();} - -int -nc3_inq_varid(int ncid, const char *name, int *varidp) {abort();} - -int -nc3_rename_var(int ncid, int varid, const char *name) {abort();} - -int -nc3_put_vara(int ncid, int varid, - const size_t *start, const size_t *count, - const void *value, nc_type xtype) {abort();} - -int -nc3_get_vara(int ncid, int varid, - const size_t *start, const size_t *count, - void *value, nc_type xtype) {abort();} - -int -nc3_put_var(int ncid, int varid, const void *op) {abort();} - -int -nc3_get_var(int ncid, int varid, void *ip) {abort();} - -int -nc3_put_var1(int ncid, int varid, const size_t *indexp, - const void *op) {abort();} - -int -nc3_get_var1(int ncid, int varid, const size_t *indexp, void *ip) {abort();} - -int -nc3_put_vars(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const void *op) {abort();} - -int -nc3_get_vars(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - void *ip) {abort();} - -int -nc3_put_varm(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t *imapp, const void *op) {abort();} - -int -nc3_get_varm(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t *imapp, void *ip) {abort();} - -/* End _var */ - -/* netCDF4 API only */ -int -nc3_var_par_access(int ncid,int varid,int pint) {abort();} - -int -nc3_inq_ncid(int ncid,const char* pnm,int* pintp) {abort();} - -int -nc3_inq_grps(int ncid,int* pintp,int* pintp2) {abort();} - -int -nc3_inq_grpname(int ncid,char* pcharp) {abort();} - -int -nc3_inq_grpname_full(int ncid,size_t* psize_tp,char* pcharp) {abort();} - -int -nc3_inq_grp_parent(int ncid,int* pintp) {abort();} - -int -nc3_inq_grp_full_ncid(int ncid,const char* pnm,int* pintp) {abort();} - -int -nc3_inq_varids(int ncid,int* nvars,int* pintp) {abort();} - -int -nc3_inq_dimids(int ncid,int* ndims,int* pintp,int pint) {abort();} - -int -nc3_inq_typeids(int ncid,int* ntypes,int* pintp) {abort();} - -int -nc3_inq_type_equal(int ncid,nc_type pnc_type,int pint,nc_type pnc_type2,int* pintp) {abort();} - -int -nc3_def_grp(int ncid,const char* pnm,int* pintp) {abort();} - -int -nc3_inq_user_type(int ncid,nc_type pnc_type,char* pnm,size_t* psize_tp,nc_type* pnc_typep,size_t* psize_tp2,int* pintp) {abort();} - - -int -nc3_def_compound(int ncid,size_t psize_t,const char* pnm,nc_type* pnc_typep) {abort();} - -int -nc3_insert_compound(int ncid,nc_type pnc_type,const char* pnm,size_t psize_t,nc_type pnc_type2) {abort();} - -int -nc3_insert_array_compound(int ncid,nc_type pnc_type,const char* pnm,size_t psize_t,nc_type pnc_type2,int pint,const int* pintp) {abort();} - -int -nc3_inq_typeid(int ncid,const char* pnm,nc_type* pnc_typep) {abort();} - -int -nc3_inq_compound_field(int ncid,nc_type pnc_type,int pint,char* pnm,size_t* psize_tp,nc_type* pnc_typep,int* pintp,int* pintp2) {abort();} - -int -nc3_inq_compound_fieldindex(int ncid,nc_type pnc_type,const char* pnm,int* pintp) {abort();} - -int -nc3_def_vlen(int ncid,const char* pnm,nc_type base_typeid,nc_type* pnc_typep) {abort();} - -int -nc3_put_vlen_element(int ncid,int varid,void* pvoidp,size_t psize_t,const void* voidp) {abort();} - -int -nc3_get_vlen_element(int ncid,int varid,const void* pvoidp,size_t* psize_tp,void* pvoidp2) {abort();} - -int -nc3_def_enum(int ncid,nc_type pnc_type,const char* pnm,nc_type* pnc_typep) {abort();} - -int -nc3_insert_enum(int ncid,nc_type pnc_type,const char* pnm,const void* voidp) {abort();} - -int -nc3_inq_enum_member(int ncid,nc_type pnc_type,int pint,char* pnm,void* pvoidp) {abort();} - -int -nc3_inq_enum_ident(int ncid,nc_type pnc_type,long long plonglong,char* pcharp) {abort();} - -int -nc3_def_opaque(int ncid,size_t psize_t,const char* pnm,nc_type* pnc_typep) {abort();} - -int -nc3_def_var_deflate(int ncid,int varid,int pint,int pint2,int pint3) {abort();} - -int -nc3_inq_var_deflate(int ncid,int varid,int* pintp,int* pintp2,int* pintp3) {abort();} - -int -nc3_inq_var_szip(int ncid,int varid,int* pintp,int* pintp2) {abort();} - -int -nc3_def_var_fletcher32(int ncid,int varid,int pint) {abort();} - -int -nc3_inq_var_fletcher32(int ncid,int varid,int* pintp) {abort();} - -int -nc3_def_var_chunking(int ncid,int varid,int pint,const size_t* size_tp) {abort();} - -int -nc3_inq_var_chunking(int ncid,int varid,int* pintp,size_t* psize_tp) {abort();} - -int -nc3_def_var_fill(int ncid,int varid,int pint,const void* pvoidp) {abort();} - -int -nc3_inq_var_fill(int ncid,int varid,int* pintp,void* pvoidp) {abort();} - -int -nc3_def_var_endian(int ncid,int varid,int pint) {abort();} - -int -nc3_inq_var_endian(int ncid,int varid,int* pintp) {abort();} - -int -nc3_set_var_chunk_cache(int ncid,int varid,size_t psize_t,size_t psize_t2,float pfloat) {abort();} - -int -nc3_get_var_chunk_cache(int ncid,int varid,size_t* psize_tp,size_t* psize_tp2, size_t* psize_tp3, float* pfloatp) {abort();} - -int -nc3_inq_unlimdims(int ncid ,int* nump,int* dimsp) {abort();} - -int -nc3_inq_unlimdim(int ncid, int *unlimdimidp) {abort();} - -int -nc3_show_metadata(int ncid) {abort();} - -int -nc3_put_att_text(int ncid, int varid, const char *name, - size_t len, const char *op) {abort();} - -int -nc3_get_att_text(int ncid, int varid, const char *name, char *ip) {abort();} - -int -nc3_put_att_uchar(int ncid, int varid, const char *name, nc_type xtype, - size_t len, const unsigned char *op) {abort();} - -int -nc3_get_att_uchar(int ncid, int varid, const char *name, unsigned char *ip) {abort();} - -int -nc3_put_att_schar(int ncid, int varid, const char *name, nc_type xtype, - size_t len, const signed char *op) {abort();} - -int -nc3_get_att_schar(int ncid, int varid, const char *name, signed char *ip) {abort();} - -int -nc3_put_att_short(int ncid, int varid, const char *name, nc_type xtype, - size_t len, const short *op) {abort();} - -int -nc3_get_att_short(int ncid, int varid, const char *name, short *ip) {abort();} - -int -nc3_put_att_int(int ncid, int varid, const char *name, nc_type xtype, - size_t len, const int *op) {abort();} - -int -nc3_get_att_int(int ncid, int varid, const char *name, int *ip) {abort();} - -int -nc3_put_att_long(int ncid, int varid, const char *name, nc_type xtype, - size_t len, const long *op) {abort();} - -int -nc3_get_att_long(int ncid, int varid, const char *name, long *ip) {abort();} - -int -nc3_put_att_float(int ncid, int varid, const char *name, nc_type xtype, - size_t len, const float *op) {abort();} - -int -nc3_get_att_float(int ncid, int varid, const char *name, float *ip) {abort();} - -int -nc3_put_att_double(int ncid, int varid, const char *name, nc_type xtype, - size_t len, const double *op) {abort();} - -int -nc3_get_att_double(int ncid, int varid, const char *name, double *ip) {abort();} - -int -nc3_put_att_ubyte(int ncid, int varid, const char *name, nc_type xtype, - size_t len, const unsigned char *op) {abort();} - -int -nc3_get_att_ubyte(int ncid, int varid, const char *name, - unsigned char *ip) {abort();} - -int -nc3_put_att_ushort(int ncid, int varid, const char *name, nc_type xtype, - size_t len, const unsigned short *op) {abort();} - -int -nc3_get_att_ushort(int ncid, int varid, const char *name, unsigned short *ip) {abort();} - -int -nc3_put_att_uint(int ncid, int varid, const char *name, nc_type xtype, - size_t len, const unsigned int *op) {abort();} - -int -nc3_get_att_uint(int ncid, int varid, const char *name, unsigned int *ip) {abort();} - -int -nc3_put_att_longlong(int ncid, int varid, const char *name, nc_type xtype, - size_t len, const long long *op) {abort();} - -int -nc3_get_att_longlong(int ncid, int varid, const char *name, long long *ip) {abort();} - -int -nc3_put_att_ulonglong(int ncid, int varid, const char *name, nc_type xtype, - size_t len, const unsigned long long *op) {abort();} - -int -nc3_get_att_ulonglong(int ncid, int varid, const char *name, - unsigned long long *ip) {abort();} - -int -nc3_put_att_string(int ncid, int varid, const char *name, - size_t len, const char **op) {abort();} - -int -nc3_get_att_string(int ncid, int varid, const char *name, char **ip) {abort();} - - -int -nc3_put_var1_text(int ncid, int varid, const size_t *indexp, const char *op) {abort();} - -int -nc3_get_var1_text(int ncid, int varid, const size_t *indexp, char *ip) {abort();} - -int -nc3_put_var1_uchar(int ncid, int varid, const size_t *indexp, - const unsigned char *op) {abort();} - -int -nc3_get_var1_uchar(int ncid, int varid, const size_t *indexp, - unsigned char *ip) {abort();} - -int -nc3_put_var1_schar(int ncid, int varid, const size_t *indexp, - const signed char *op) {abort();} - -int -nc3_get_var1_schar(int ncid, int varid, const size_t *indexp, - signed char *ip) {abort();} - -int -nc3_put_var1_short(int ncid, int varid, const size_t *indexp, - const short *op) {abort();} - -int -nc3_get_var1_short(int ncid, int varid, const size_t *indexp, - short *ip) {abort();} - -int -nc3_put_var1_int(int ncid, int varid, const size_t *indexp, const int *op) {abort();} - -int -nc3_get_var1_int(int ncid, int varid, const size_t *indexp, int *ip) {abort();} - -int -nc3_put_var1_long(int ncid, int varid, const size_t *indexp, const long *op) {abort();} - -int -nc3_get_var1_long(int ncid, int varid, const size_t *indexp, long *ip) {abort();} - -int -nc3_put_var1_float(int ncid, int varid, const size_t *indexp, const float *op) {abort();} - -int -nc3_get_var1_float(int ncid, int varid, const size_t *indexp, float *ip) {abort();} - -int -nc3_put_var1_double(int ncid, int varid, const size_t *indexp, const double *op) {abort();} - -int -nc3_get_var1_double(int ncid, int varid, const size_t *indexp, double *ip) {abort();} - -int -nc3_put_var1_ubyte(int ncid, int varid, const size_t *indexp, - const unsigned char *op) {abort();} - -int -nc3_get_var1_ubyte(int ncid, int varid, const size_t *indexp, - unsigned char *ip) {abort();} - -int -nc3_put_var1_ushort(int ncid, int varid, const size_t *indexp, - const unsigned short *op) {abort();} - -int -nc3_get_var1_ushort(int ncid, int varid, const size_t *indexp, - unsigned short *ip) {abort();} - -int -nc3_put_var1_uint(int ncid, int varid, const size_t *indexp, - const unsigned int *op) {abort();} - -int -nc3_get_var1_uint(int ncid, int varid, const size_t *indexp, - unsigned int *ip) {abort();} - -int -nc3_put_var1_longlong(int ncid, int varid, const size_t *indexp, - const long long *op) {abort();} - -int -nc3_get_var1_longlong(int ncid, int varid, const size_t *indexp, - long long *ip) {abort();} - -int -nc3_put_var1_ulonglong(int ncid, int varid, const size_t *indexp, - const unsigned long long *op) {abort();} - -int -nc3_get_var1_ulonglong(int ncid, int varid, const size_t *indexp, - unsigned long long *ip) {abort();} - -int -nc3_put_var1_string(int ncid, int varid, const size_t *indexp, - const char **op) {abort();} - -int -nc3_get_var1_string(int ncid, int varid, const size_t *indexp, - char **ip) {abort();} - -/* End {put,get}_var1 */ -/* Begin {put,get}_vara */ - -int -nc3_put_vara_text(int ncid, int varid, - const size_t *startp, const size_t *countp, const char *op) {abort();} - -int -nc3_get_vara_text(int ncid, int varid, - const size_t *startp, const size_t *countp, char *ip) {abort();} - -int -nc3_put_vara_uchar(int ncid, int varid, - const size_t *startp, const size_t *countp, const unsigned char *op) {abort();} - -int -nc3_get_vara_uchar(int ncid, int varid, const size_t *startp, - const size_t *countp, unsigned char *ip) {abort();} - -int -nc3_put_vara_schar(int ncid, int varid, const size_t *startp, - const size_t *countp, const signed char *op) {abort();} - -int -nc3_get_vara_schar(int ncid, int varid, const size_t *startp, - const size_t *countp, signed char *ip) {abort();} - -int -nc3_put_vara_short(int ncid, int varid, const size_t *startp, - const size_t *countp, const short *op) {abort();} - -int -nc3_get_vara_short(int ncid, int varid, const size_t *startp, - const size_t *countp, short *ip) {abort();} - -int -nc3_put_vara_int(int ncid, int varid, const size_t *startp, - const size_t *countp, const int *op) {abort();} - -int -nc3_get_vara_int(int ncid, int varid, const size_t *startp, - const size_t *countp, int *ip) {abort();} - -int -nc3_put_vara_long(int ncid, int varid, const size_t *startp, - const size_t *countp, const long *op) {abort();} - -int -nc3_get_vara_long(int ncid, int varid, - const size_t *startp, const size_t *countp, long *ip) {abort();} - -int -nc3_put_vara_float(int ncid, int varid, - const size_t *startp, const size_t *countp, const float *op) {abort();} - -int -nc3_get_vara_float(int ncid, int varid, - const size_t *startp, const size_t *countp, float *ip) {abort();} - -int -nc3_put_vara_double(int ncid, int varid, const size_t *startp, - const size_t *countp, const double *op) {abort();} - -int -nc3_get_vara_double(int ncid, int varid, const size_t *startp, - const size_t *countp, double *ip) {abort();} - -int -nc3_put_vara_ubyte(int ncid, int varid, const size_t *startp, - const size_t *countp, const unsigned char *op) {abort();} - -int -nc3_get_vara_ubyte(int ncid, int varid, const size_t *startp, - const size_t *countp, unsigned char *ip) {abort();} - -int -nc3_put_vara_ushort(int ncid, int varid, const size_t *startp, - const size_t *countp, const unsigned short *op) {abort();} - -int -nc3_get_vara_ushort(int ncid, int varid, const size_t *startp, - const size_t *countp, unsigned short *ip) {abort();} - -int -nc3_put_vara_uint(int ncid, int varid, const size_t *startp, - const size_t *countp, const unsigned int *op) {abort();} - -int -nc3_get_vara_uint(int ncid, int varid, const size_t *startp, - const size_t *countp, unsigned int *ip) {abort();} - -int -nc3_put_vara_longlong(int ncid, int varid, const size_t *startp, - const size_t *countp, const long long *op) {abort();} - -int -nc3_get_vara_longlong(int ncid, int varid, const size_t *startp, - const size_t *countp, long long *ip) {abort();} - -int -nc3_put_vara_ulonglong(int ncid, int varid, const size_t *startp, - const size_t *countp, const unsigned long long *op) {abort();} - -int -nc3_get_vara_ulonglong(int ncid, int varid, const size_t *startp, - const size_t *countp, unsigned long long *ip) {abort();} - -int -nc3_put_vara_string(int ncid, int varid, const size_t *startp, - const size_t *countp, const char **op) {abort();} - -int -nc3_get_vara_string(int ncid, int varid, const size_t *startp, - const size_t *countp, char **ip) {abort();} - -/* End {put,get}_vara */ -/* Begin {put,get}_vars */ - -int -nc3_put_vars_text(int ncid, int varid, - const size_t *startp, const size_t *countp, const ptrdiff_t *stridep, - const char *op) {abort();} - -int -nc3_get_vars_text(int ncid, int varid, - const size_t *startp, const size_t *countp, const ptrdiff_t *stridep, - char *ip) {abort();} - -int -nc3_put_vars_uchar(int ncid, int varid, - const size_t *startp, const size_t *countp, const ptrdiff_t *stridep, - const unsigned char *op) {abort();} - -int -nc3_get_vars_uchar(int ncid, int varid, - const size_t *startp, const size_t *countp, const ptrdiff_t *stridep, - unsigned char *ip) {abort();} - -int -nc3_put_vars_schar(int ncid, int varid, - const size_t *startp, const size_t *countp, const ptrdiff_t *stridep, - const signed char *op) {abort();} - -int -nc3_get_vars_schar(int ncid, int varid, - const size_t *startp, const size_t *countp, const ptrdiff_t *stridep, - signed char *ip) {abort();} - -int -nc3_put_vars_short(int ncid, int varid, - const size_t *startp, const size_t *countp, const ptrdiff_t *stridep, - const short *op) {abort();} - -int -nc3_get_vars_short(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - short *ip) {abort();} - -int -nc3_put_vars_int(int ncid, int varid, - const size_t *startp, const size_t *countp, const ptrdiff_t *stridep, - const int *op) {abort();} - -int -nc3_get_vars_int(int ncid, int varid, - const size_t *startp, const size_t *countp, const ptrdiff_t *stridep, - int *ip) {abort();} - -int -nc3_put_vars_long(int ncid, int varid, - const size_t *startp, const size_t *countp, const ptrdiff_t *stridep, - const long *op) {abort();} - -int -nc3_get_vars_long(int ncid, int varid, - const size_t *startp, const size_t *countp, const ptrdiff_t *stridep, - long *ip) {abort();} - -int -nc3_put_vars_float(int ncid, int varid, - const size_t *startp, const size_t *countp, const ptrdiff_t *stridep, - const float *op) {abort();} - -int -nc3_get_vars_float(int ncid, int varid, - const size_t *startp, const size_t *countp, const ptrdiff_t *stridep, - float *ip) {abort();} - -int -nc3_put_vars_double(int ncid, int varid, - const size_t *startp, const size_t *countp, const ptrdiff_t *stridep, - const double *op) {abort();} - -int -nc3_get_vars_double(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - double *ip) {abort();} - -int -nc3_put_vars_ubyte(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const unsigned char *op) {abort();} - -int -nc3_get_vars_ubyte(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - unsigned char *ip) {abort();} - -int -nc3_put_vars_ushort(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const unsigned short *op) {abort();} - -int -nc3_get_vars_ushort(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - unsigned short *ip) {abort();} - -int -nc3_put_vars_uint(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const unsigned int *op) {abort();} - -int -nc3_get_vars_uint(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - unsigned int *ip) {abort();} - -int -nc3_put_vars_longlong(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const long long *op) {abort();} - -int -nc3_get_vars_longlong(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - long long *ip) {abort();} - -int -nc3_put_vars_ulonglong(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const unsigned long long *op) {abort();} - -int -nc3_get_vars_ulonglong(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - unsigned long long *ip) {abort();} - -int -nc3_put_vars_string(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const char **op) {abort();} - -int -nc3_get_vars_string(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - char **ip) {abort();} - -/* End {put,get}_vars */ -/* Begin {put,get}_varm */ - -int -nc3_put_varm_text(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t *imapp, const char *op) {abort();} - -int -nc3_get_varm_text(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t *imapp, char *ip) {abort();} - -int -nc3_put_varm_uchar(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t *imapp, const unsigned char *op) {abort();} - -int -nc3_get_varm_uchar(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t *imapp, unsigned char *ip) {abort();} - -int -nc3_put_varm_schar(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t *imapp, const signed char *op) {abort();} - -int -nc3_get_varm_schar(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t *imapp, signed char *ip) {abort();} - -int -nc3_put_varm_short(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t *imapp, const short *op) {abort();} - -int -nc3_get_varm_short(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t *imapp, short *ip) {abort();} - -int -nc3_put_varm_int(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t *imapp, const int *op) {abort();} - -int -nc3_get_varm_int(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t *imapp, int *ip) {abort();} - -int -nc3_put_varm_long(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t *imapp, const long *op) {abort();} - -int -nc3_get_varm_long(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t *imapp, long *ip) {abort();} - -int -nc3_put_varm_float(int ncid, int varid,const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t *imapp, const float *op) {abort();} - -int -nc3_get_varm_float(int ncid, int varid,const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t *imapp, float *ip) {abort();} - -int -nc3_put_varm_double(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t *imapp, const double *op) {abort();} - -int -nc3_get_varm_double(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t * imapp, double *ip) {abort();} - -int -nc3_put_varm_ubyte(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t * imapp, const unsigned char *op) {abort();} - -int -nc3_get_varm_ubyte(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t * imapp, unsigned char *ip) {abort();} - -int -nc3_put_varm_ushort(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t * imapp, const unsigned short *op) {abort();} - -int -nc3_get_varm_ushort(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t * imapp, unsigned short *ip) {abort();} - -int -nc3_put_varm_uint(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t * imapp, const unsigned int *op) {abort();} - -int -nc3_get_varm_uint(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t * imapp, unsigned int *ip) {abort();} - -int -nc3_put_varm_longlong(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t * imapp, const long long *op) {abort();} - -int -nc3_get_varm_longlong(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t * imapp, long long *ip) {abort();} - -int -nc3_put_varm_ulonglong(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t * imapp, const unsigned long long *op) {abort();} - -int -nc3_get_varm_ulonglong(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t * imapp, unsigned long long *ip) {abort();} - -int -nc3_put_varm_string(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t * imapp, const char **op) {abort();} - -int -nc3_get_varm_string(int ncid, int varid, const size_t *startp, - const size_t *countp, const ptrdiff_t *stridep, - const ptrdiff_t * imapp, char **ip) {abort();} - -/* End {put,get}_varm */ -/* Begin {put,get}_var */ - -int -nc3_put_var_text(int ncid, int varid, const char *op) {abort();} - -int -nc3_get_var_text(int ncid, int varid, char *ip) {abort();} - -int -nc3_put_var_uchar(int ncid, int varid, const unsigned char *op) {abort();} - -int -nc3_get_var_uchar(int ncid, int varid, unsigned char *ip) {abort();} - -int -nc3_put_var_schar(int ncid, int varid, const signed char *op) {abort();} - -int -nc3_get_var_schar(int ncid, int varid, signed char *ip) {abort();} - -int -nc3_put_var_short(int ncid, int varid, const short *op) {abort();} - -int -nc3_get_var_short(int ncid, int varid, short *ip) {abort();} - -int -nc3_put_var_int(int ncid, int varid, const int *op) {abort();} - -int -nc3_get_var_int(int ncid, int varid, int *ip) {abort();} - -int -nc3_put_var_long(int ncid, int varid, const long *op) {abort();} - -int -nc3_get_var_long(int ncid, int varid, long *ip) {abort();} - -int -nc3_put_var_float(int ncid, int varid, const float *op) {abort();} - -int -nc3_get_var_float(int ncid, int varid, float *ip) {abort();} - -int -nc3_put_var_double(int ncid, int varid, const double *op) {abort();} - -int -nc3_get_var_double(int ncid, int varid, double *ip) {abort();} - -int -nc3_put_var_ubyte(int ncid, int varid, const unsigned char *op) {abort();} - -int -nc3_get_var_ubyte(int ncid, int varid, unsigned char *ip) {abort();} - -int -nc3_put_var_ushort(int ncid, int varid, const unsigned short *op) {abort();} - -int -nc3_get_var_ushort(int ncid, int varid, unsigned short *ip) {abort();} - -int -nc3_put_var_uint(int ncid, int varid, const unsigned int *op) {abort();} - -int -nc3_get_var_uint(int ncid, int varid, unsigned int *ip) {abort();} - -int -nc3_put_var_longlong(int ncid, int varid, const long long *op) {abort();} - -int -nc3_get_var_longlong(int ncid, int varid, long long *ip) {abort();} - -int -nc3_put_var_ulonglong(int ncid, int varid, const unsigned long long *op) {abort();} - -int -nc3_get_var_ulonglong(int ncid, int varid, unsigned long long *ip) {abort();} - -int -nc3_put_var_string(int ncid, int varid, const char **op) {abort();} - -int -nc3_get_var_string(int ncid, int varid, char **ip) {abort();} - -int -nc3__create_mp(const char *path, int cmode, size_t initialsz, int basepe, - size_t *chunksizehintp, int *ncidp) {abort();} - -int -nc3__open_mp(const char *path, int mode, int basepe, - size_t *chunksizehintp, int *ncidp) {abort();} - -int -nc3_enddef(int ncid) {abort();} diff --git a/libsrc4/nc4attr.c b/libsrc4/nc4attr.c index 3648d15697..ea7ba0f88a 100644 --- a/libsrc4/nc4attr.c +++ b/libsrc4/nc4attr.c @@ -1,34 +1,121 @@ -/* -This file is part of netcdf-4, a netCDF-like interface for HDF5, or a -HDF5 backend for netCDF, depending on your point of view. - -This file handles the nc4 attribute functions. - -Remember that with atts, type conversion can take place when writing -them, and when reading them. - -Copyright 2003-2011, University Corporation for Atmospheric -Research. See COPYRIGHT file for copying and redistribution -conditions. -*/ - +/** + * @file + * + * @internal This file is part of netcdf-4, a netCDF-like interface + * for HDF5, or a HDF5 backend for netCDF, depending on your point of + * view. + * + * This file handles the nc4 attribute functions. + * + * Remember that with atts, type conversion can take place when + * writing them, and when reading them. + * + * Copyright 2003-2011, University Corporation for Atmospheric + * Research. See COPYRIGHT file for copying and redistribution + * conditions. + * + * @author Ed Hartnett + */ #include "nc4internal.h" #include "nc.h" #include "nc4dispatch.h" #include "ncdispatch.h" -static int nc4_get_att_special(NC_HDF5_FILE_INFO_T*, const char*, - nc_type*, nc_type, size_t*, int*, int, void*); - int nc4typelen(nc_type type); -/* Get or put attribute metadata from our linked list of file - info. Always locate the attribute by name, never by attnum. - The mem_type is ignored if data=NULL. */ +/** + * @internal Get special informatation about the attrobute. + * + * @param h5 Pointer to HDF5 file info struct. + * @param name Name of attribute. + * @param filetypep Pointer that gets type of the attribute data in + * file. + * @param mem_type Type of attribute data in memory. + * @param lenp Pointer that gets length of attribute array. + * @param attnump Pointer that gets the attribute number. + * @param is_long True if attribute data is of type NC_LONG. + * @param data Attribute data. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Dennis Heimbigner + */ +static int +nc4_get_att_special(NC_HDF5_FILE_INFO_T* h5, const char* name, + nc_type* filetypep, nc_type mem_type, size_t* lenp, + int* attnump, int is_long, void* data) +{ + /* Fail if asking for att id */ + if(attnump) + return NC_EATTMETA; + + if(strcmp(name,NCPROPS)==0) { + char* propdata = NULL; + int stat = NC_NOERR; + int len; + if(h5->fileinfo->propattr.version == 0) + return NC_ENOTATT; + if(mem_type == NC_NAT) mem_type = NC_CHAR; + if(mem_type != NC_CHAR) + return NC_ECHAR; + if(filetypep) *filetypep = NC_CHAR; + stat = NC4_buildpropinfo(&h5->fileinfo->propattr, &propdata); + if(stat != NC_NOERR) return stat; + len = strlen(propdata); + if(lenp) *lenp = len; + if(data) strncpy((char*)data,propdata,len+1); + free(propdata); + } else if(strcmp(name,ISNETCDF4ATT)==0 + || strcmp(name,SUPERBLOCKATT)==0) { + unsigned long long iv = 0; + if(filetypep) *filetypep = NC_INT; + if(lenp) *lenp = 1; + if(strcmp(name,SUPERBLOCKATT)==0) + iv = (unsigned long long)h5->fileinfo->superblockversion; + else /* strcmp(name,ISNETCDF4ATT)==0 */ + iv = NC4_isnetcdf4(h5); + if(mem_type == NC_NAT) mem_type = NC_INT; + if(data) + switch (mem_type) { + case NC_BYTE: *((char*)data) = (char)iv; break; + case NC_SHORT: *((short*)data) = (short)iv; break; + case NC_INT: *((int*)data) = (int)iv; break; + case NC_UBYTE: *((unsigned char*)data) = (unsigned char)iv; break; + case NC_USHORT: *((unsigned short*)data) = (unsigned short)iv; break; + case NC_UINT: *((unsigned int*)data) = (unsigned int)iv; break; + case NC_INT64: *((long long*)data) = (long long)iv; break; + case NC_UINT64: *((unsigned long long*)data) = (unsigned long long)iv; break; + default: + return NC_ERANGE; + } + } + return NC_NOERR; +} + +/** + * @internal Get or put attribute metadata from our linked list of + * file info. Always locate the attribute by name, never by attnum. + * The mem_type is ignored if data=NULL. + * + * @param ncid File and group ID. + * @param nc Pointer to file's NC struct. + * @param varid Variable ID. + * @param name Name of attribute. + * @param xtype Pointer that gets (file) type of attribute. + * @param mem_type The type of attribute data in memory. + * @param lenp Pointer that gets length of attribute array. + * @param attnum Pointer that gets the index number of this attribute. + * @param is_long True only if the type is NC_LONG. + * @param data Pointer that gets attribute data. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Ed Hartnett + */ int -nc4_get_att(int ncid, NC *nc, int varid, const char *name, - nc_type *xtype, nc_type mem_type, size_t *lenp, - int *attnum, int is_long, void *data) +nc4_get_att(int ncid, NC *nc, int varid, const char *name, nc_type *xtype, + nc_type mem_type, size_t *lenp, int *attnum, int is_long, + void *data) { NC_GRP_INFO_T *grp; NC_HDF5_FILE_INFO_T *h5; @@ -48,7 +135,7 @@ nc4_get_att(int ncid, NC *nc, int varid, const char *name, } LOG((3, "%s: ncid 0x%x varid %d name %s attnum %d mem_type %d", - __func__, ncid, varid, name, my_attnum, mem_type)); + __func__, ncid, varid, name, my_attnum, mem_type)); /* Find info for this file and group, and set pointer to each. */ h5 = NC4_DATA(nc); @@ -57,37 +144,37 @@ nc4_get_att(int ncid, NC *nc, int varid, const char *name, /* Check varid */ if (varid != NC_GLOBAL) { - if (varid < 0 || varid >= grp->vars.nelems) - return NC_ENOTVAR; - if (grp->vars.value[varid] == NULL) - return NC_ENOTVAR; - assert(grp->vars.value[varid]->varid == varid); + if (varid < 0 || varid >= grp->vars.nelems) + return NC_ENOTVAR; + if (grp->vars.value[varid] == NULL) + return NC_ENOTVAR; + assert(grp->vars.value[varid]->varid == varid); } if (name == NULL) - BAIL(NC_EBADNAME); + BAIL(NC_EBADNAME); /* Normalize name. */ if ((retval = nc4_normalize_name(name, norm_name))) BAIL(retval); if(nc->ext_ncid == ncid && varid == NC_GLOBAL) { - const char** sp; - for(sp = NC_RESERVED_SPECIAL_LIST;*sp;sp++) { - if(strcmp(name,*sp)==0) { - return nc4_get_att_special(h5, norm_name, xtype, mem_type, lenp, attnum, is_long, data); - } - } - } + const char** sp; + for(sp = NC_RESERVED_SPECIAL_LIST;*sp;sp++) { + if(strcmp(name,*sp)==0) { + return nc4_get_att_special(h5, norm_name, xtype, mem_type, lenp, attnum, is_long, data); + } + } + } /* Find the attribute, if it exists. If we don't find it, we are major failures. */ if ((retval = nc4_find_grp_att(grp, varid, norm_name, my_attnum, &att))) { - if(retval == NC_ENOTATT) - return retval; - else - BAIL(retval); + if(retval == NC_ENOTATT) + return retval; + else + BAIL(retval); } /* If mem_type is NC_NAT, it means we want to use the attribute's @@ -101,7 +188,7 @@ nc4_get_att(int ncid, NC *nc, int varid, const char *name, * Send him an NC_ECHAR error...*/ if (data && att->len && ((att->nc_typeid == NC_CHAR && mem_type != NC_CHAR) || - (att->nc_typeid != NC_CHAR && mem_type == NC_CHAR))) + (att->nc_typeid != NC_CHAR && mem_type == NC_CHAR))) BAIL(NC_ECHAR); /* take that, you freak! */ /* Copy the info. */ @@ -127,23 +214,23 @@ nc4_get_att(int ncid, NC *nc, int varid, const char *name, if (data && att->len && mem_type != att->nc_typeid && mem_type != NC_NAT && !(mem_type == NC_CHAR && - (att->nc_typeid == NC_UBYTE || att->nc_typeid == NC_BYTE))) + (att->nc_typeid == NC_UBYTE || att->nc_typeid == NC_BYTE))) { if (!(bufr = malloc((size_t)(att->len * type_size)))) - BAIL(NC_ENOMEM); + BAIL(NC_ENOMEM); need_to_convert++; if ((retval = nc4_convert_type(att->data, bufr, att->nc_typeid, - mem_type, (size_t)att->len, &range_error, - NULL, (h5->cmode & NC_CLASSIC_MODEL), 0, is_long))) - BAIL(retval); + mem_type, (size_t)att->len, &range_error, + NULL, (h5->cmode & NC_CLASSIC_MODEL), 0, is_long))) + BAIL(retval); /* For strict netcdf-3 rules, ignore erange errors between UBYTE * and BYTE types. */ if ((h5->cmode & NC_CLASSIC_MODEL) && - (att->nc_typeid == NC_UBYTE || att->nc_typeid == NC_BYTE) && - (mem_type == NC_UBYTE || mem_type == NC_BYTE) && - range_error) - range_error = 0; + (att->nc_typeid == NC_UBYTE || att->nc_typeid == NC_BYTE) && + (mem_type == NC_UBYTE || mem_type == NC_BYTE) && + range_error) + range_error = 0; } else { @@ -158,57 +245,57 @@ nc4_get_att(int ncid, NC *nc, int varid, const char *name, { if (att->vldata) { - size_t base_typelen; - hvl_t *vldest = data; - NC_TYPE_INFO_T *type; + size_t base_typelen; + hvl_t *vldest = data; + NC_TYPE_INFO_T *type; /* Get the type object for the attribute's type */ - if ((retval = nc4_find_type(h5, att->nc_typeid, &type))) - BAIL(retval); + if ((retval = nc4_find_type(h5, att->nc_typeid, &type))) + BAIL(retval); /* Retrieve the size of the base type */ if ((retval = nc4_get_typelen_mem(h5, type->u.v.base_nc_typeid, 0, &base_typelen))) BAIL(retval); - for (i = 0; i < att->len; i++) - { - vldest[i].len = att->vldata[i].len; - if (!(vldest[i].p = malloc(vldest[i].len * base_typelen))) - BAIL(NC_ENOMEM); - memcpy(vldest[i].p, att->vldata[i].p, vldest[i].len * base_typelen); - } + for (i = 0; i < att->len; i++) + { + vldest[i].len = att->vldata[i].len; + if (!(vldest[i].p = malloc(vldest[i].len * base_typelen))) + BAIL(NC_ENOMEM); + memcpy(vldest[i].p, att->vldata[i].p, vldest[i].len * base_typelen); + } } else if (att->stdata) { - for (i = 0; i < att->len; i++) - { + for (i = 0; i < att->len; i++) + { /* Check for NULL pointer for string (valid in HDF5) */ if(att->stdata[i]) { - if (!(((char **)data)[i] = strdup(att->stdata[i]))) - BAIL(NC_ENOMEM); + if (!(((char **)data)[i] = strdup(att->stdata[i]))) + BAIL(NC_ENOMEM); } else - ((char **)data)[i] = att->stdata[i]; - } + ((char **)data)[i] = att->stdata[i]; + } } else { - /* For long types, we need to handle this special... */ - if (is_long && att->nc_typeid == NC_INT) - { - long *lp = data; - int *ip = bufr; - - for (i = 0; i < att->len; i++) - *lp++ = *ip++; - } - else - memcpy(data, bufr, (size_t)(att->len * type_size)); + /* For long types, we need to handle this special... */ + if (is_long && att->nc_typeid == NC_INT) + { + long *lp = data; + int *ip = bufr; + + for (i = 0; i < att->len; i++) + *lp++ = *ip++; + } + else + memcpy(data, bufr, (size_t)(att->len * type_size)); } } - exit: +exit: if (need_to_convert) free(bufr); if (range_error) @@ -216,11 +303,27 @@ nc4_get_att(int ncid, NC *nc, int varid, const char *name, return retval; } -/* Put attribute metadata into our global metadata. */ +/** + * @internal Put attribute metadata into our global metadata. + * + * @param ncid File and group ID. + * @param nc Pointer to file's NC struct. + * @param varid Variable ID. + * @param name Name of attribute. + * @param file_type Type of the attribute data in file. + * @param mem_type Type of attribute data in memory. + * @param len Length of attribute array. + * @param is_long True if attribute is of type NC_LONG. + * @param data Attribute data. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Ed Hartnett + */ static int nc4_put_att(int ncid, NC *nc, int varid, const char *name, - nc_type file_type, nc_type mem_type, size_t len, int is_long, - const void *data) + nc_type file_type, nc_type mem_type, size_t len, int is_long, + const void *data) { NC_GRP_INFO_T *grp; NC_HDF5_FILE_INFO_T *h5; @@ -238,8 +341,8 @@ nc4_put_att(int ncid, NC *nc, int varid, const char *name, assert(nc && NC4_DATA(nc)); LOG((1, "nc4_put_att: ncid 0x%x varid %d name %s " - "file_type %d mem_type %d len %d", ncid, varid, - name, file_type, mem_type, len)); + "file_type %d mem_type %d len %d", ncid, varid, + name, file_type, mem_type, len)); /* If len is not zero, then there must be some data. */ if (len && !data) @@ -252,7 +355,7 @@ nc4_put_att(int ncid, NC *nc, int varid, const char *name, /* If the file is read-only, return an error. */ if (h5->no_write) - return NC_EPERM; + return NC_EPERM; /* Find att, if it exists. */ if (varid == NC_GLOBAL) @@ -260,7 +363,7 @@ nc4_put_att(int ncid, NC *nc, int varid, const char *name, else { if (varid < 0 || varid >= grp->vars.nelems) - return NC_ENOTVAR; + return NC_ENOTVAR; var = grp->vars.value[varid]; if (!var) return NC_ENOTVAR; attlist = &var->att; @@ -275,50 +378,50 @@ nc4_put_att(int ncid, NC *nc, int varid, const char *name, return retval; if(nc->ext_ncid == ncid && varid == NC_GLOBAL) { - const char** sp; - for(sp = NC_RESERVED_SPECIAL_LIST;*sp;sp++) { - if(strcmp(name,*sp)==0) { - return NC_ENOTATT; /* Not settable */ - } - } - } + const char** sp; + for(sp = NC_RESERVED_SPECIAL_LIST;*sp;sp++) { + if(strcmp(name,*sp)==0) { + return NC_ENOTATT; /* Not settable */ + } + } + } for (att = *attlist; att; att = att->l.next) - if (!strcmp(att->name, norm_name)) - break; + if (!strcmp(att->name, norm_name)) + break; /* If len is not zero, then there must be some data. */ if (len && !data) return NC_EINVAL; LOG((1, "nc4_put_att: ncid 0x%x varid %d name %s " - "file_type %d mem_type %d len %d", ncid, varid, - name, file_type, mem_type, len)); + "file_type %d mem_type %d len %d", ncid, varid, + name, file_type, mem_type, len)); if (!att) { /* If this is a new att, require define mode. */ if (!(h5->flags & NC_INDEF)) { - if (h5->cmode & NC_CLASSIC_MODEL) - return NC_EINDEFINE; - if ((retval = NC4_redef(ncid))) - BAIL(retval); + if (h5->cmode & NC_CLASSIC_MODEL) + return NC_EINDEFINE; + if ((retval = NC4_redef(ncid))) + BAIL(retval); } new_att = NC_TRUE; } else { /* For an existing att, if we're not in define mode, the len - must not be greater than the existing len for classic model. */ - if (!(h5->flags & NC_INDEF) && - len * nc4typelen(file_type) > (size_t)att->len * nc4typelen(att->nc_typeid)) - { + must not be greater than the existing len for classic model. */ + if (!(h5->flags & NC_INDEF) && + len * nc4typelen(file_type) > (size_t)att->len * nc4typelen(att->nc_typeid)) + { if (h5->cmode & NC_CLASSIC_MODEL) - return NC_EINDEFINE; + return NC_EINDEFINE; if ((retval = NC4_redef(ncid))) - BAIL(retval); - } + BAIL(retval); + } } /* We must have two valid types to continue. */ @@ -332,7 +435,7 @@ nc4_put_att(int ncid, NC *nc, int varid, const char *name, /* No character conversions are allowed. */ if (file_type != mem_type && (file_type == NC_CHAR || mem_type == NC_CHAR || - file_type == NC_STRING || mem_type == NC_STRING)) + file_type == NC_STRING || mem_type == NC_STRING)) return NC_ECHAR; /* For classic mode file, only allow atts with classic types to be @@ -346,9 +449,9 @@ nc4_put_att(int ncid, NC *nc, int varid, const char *name, { LOG((3, "adding attribute %s to the list...", norm_name)); if ((res = nc4_att_list_add(attlist, &att))) - BAIL (res); + BAIL (res); if (!(att->name = strdup(norm_name))) - return NC_ENOMEM; + return NC_ENOMEM; } /* Now fill in the metadata. */ @@ -360,14 +463,14 @@ nc4_put_att(int ncid, NC *nc, int varid, const char *name, { for (i = 0; i < att->len; i++) if(att->stdata[i]) - free(att->stdata[i]); + free(att->stdata[i]); free(att->stdata); att->stdata = NULL; } if (att->vldata) { for (i = 0; i < att->len; i++) - nc_free_vlen(&att->vldata[i]); + nc_free_vlen(&att->vldata[i]); free(att->vldata); att->vldata = NULL; } @@ -388,72 +491,72 @@ nc4_put_att(int ncid, NC *nc, int varid, const char *name, /* Fill value must be same type and have exactly one value */ if (att->nc_typeid != var->type_info->nc_typeid) - return NC_EBADTYPE; + return NC_EBADTYPE; if (att->len != 1) - return NC_EINVAL; + return NC_EINVAL; /* If we already wrote to the dataset, then return an error. */ if (var->written_to) - return NC_ELATEFILL; + return NC_ELATEFILL; /* If fill value hasn't been set, allocate space. Of course, * vlens have to be different... */ if ((retval = nc4_get_typelen_mem(grp->nc4_info, var->type_info->nc_typeid, 0, &type_size))) - return retval; + return retval; /* Already set a fill value? Now I'll have to free the old * one. Make up your damn mind, would you? */ if (var->fill_value) - { - if (var->type_info->nc_type_class == NC_VLEN) - { - if ((retval = nc_free_vlen(var->fill_value))) - return retval; - } - else if (var->type_info->nc_type_class == NC_STRING) - { - if (*(char **)var->fill_value) - free(*(char **)var->fill_value); - } - free(var->fill_value); - } + { + if (var->type_info->nc_type_class == NC_VLEN) + { + if ((retval = nc_free_vlen(var->fill_value))) + return retval; + } + else if (var->type_info->nc_type_class == NC_STRING) + { + if (*(char **)var->fill_value) + free(*(char **)var->fill_value); + } + free(var->fill_value); + } /* Allocate space for the fill value. */ if (var->type_info->nc_type_class == NC_VLEN) - size = sizeof(hvl_t); + size = sizeof(hvl_t); else if (var->type_info->nc_type_class == NC_STRING) - size = sizeof(char *); + size = sizeof(char *); else - size = type_size; + size = type_size; if (!(var->fill_value = calloc(1, size))) - return NC_ENOMEM; + return NC_ENOMEM; /* Copy the fill_value. */ LOG((4, "Copying fill value into metadata for variable %s", var->name)); if (var->type_info->nc_type_class == NC_VLEN) - { - nc_vlen_t *in_vlen = (nc_vlen_t *)data, *fv_vlen = (nc_vlen_t *)(var->fill_value); + { + nc_vlen_t *in_vlen = (nc_vlen_t *)data, *fv_vlen = (nc_vlen_t *)(var->fill_value); - fv_vlen->len = in_vlen->len; - if (!(fv_vlen->p = malloc(size * in_vlen->len))) + fv_vlen->len = in_vlen->len; + if (!(fv_vlen->p = malloc(size * in_vlen->len))) return NC_ENOMEM; - memcpy(fv_vlen->p, in_vlen->p, in_vlen->len * size); - } + memcpy(fv_vlen->p, in_vlen->p, in_vlen->len * size); + } else if (var->type_info->nc_type_class == NC_STRING) - { - if(NULL != (*(char **)data)) - { - if (!(*(char **)(var->fill_value) = malloc(strlen(*(char **)data) + 1))) - return NC_ENOMEM; - strcpy(*(char **)var->fill_value, *(char **)data); - } - else + { + if(NULL != (*(char **)data)) + { + if (!(*(char **)(var->fill_value) = malloc(strlen(*(char **)data) + 1))) + return NC_ENOMEM; + strcpy(*(char **)var->fill_value, *(char **)data); + } + else *(char **)var->fill_value = NULL; - } + } else - memcpy(var->fill_value, data, type_size); + memcpy(var->fill_value, data, type_size); /* Indicate that the fill value was changed, if the variable has already * been created in the file, so the dataset gets deleted and re-created. */ @@ -475,12 +578,12 @@ nc4_put_att(int ncid, NC *nc, int varid, const char *name, if (type_class == NC_VLEN) { const hvl_t *vldata1; - NC_TYPE_INFO_T *type; - size_t base_typelen; + NC_TYPE_INFO_T *type; + size_t base_typelen; /* Get the type object for the attribute's type */ - if ((retval = nc4_find_type(h5, file_type, &type))) - BAIL(retval); + if ((retval = nc4_find_type(h5, file_type, &type))) + BAIL(retval); /* Retrieve the size of the base type */ if ((retval = nc4_get_typelen_mem(h5, type->u.v.base_nc_typeid, 0, &base_typelen))) @@ -499,29 +602,29 @@ nc4_put_att(int ncid, NC *nc, int varid, const char *name, } else if (type_class == NC_STRING) { - LOG((4, "copying array of NC_STRING")); - if (!(att->stdata = malloc(sizeof(char *) * att->len))) { - BAIL(NC_ENOMEM); - } - - /* If we are overwriting an existing attribute, - specifically an NC_CHAR, we need to clean up - the pre-existing att->data. */ - if (!new_att && att->data) { - free(att->data); - att->data = NULL; - } - - for (i = 0; i < att->len; i++) - { + LOG((4, "copying array of NC_STRING")); + if (!(att->stdata = malloc(sizeof(char *) * att->len))) { + BAIL(NC_ENOMEM); + } + + /* If we are overwriting an existing attribute, + specifically an NC_CHAR, we need to clean up + the pre-existing att->data. */ + if (!new_att && att->data) { + free(att->data); + att->data = NULL; + } + + for (i = 0; i < att->len; i++) + { if(NULL != ((char **)data)[i]) { - LOG((5, "copying string %d of size %d", i, strlen(((char **)data)[i]) + 1)); - if (!(att->stdata[i] = strdup(((char **)data)[i]))) - BAIL(NC_ENOMEM); + LOG((5, "copying string %d of size %d", i, strlen(((char **)data)[i]) + 1)); + if (!(att->stdata[i] = strdup(((char **)data)[i]))) + BAIL(NC_ENOMEM); } else - att->stdata[i] = ((char **)data)[i]; - } + att->stdata[i] = ((char **)data)[i]; + } } else { @@ -549,9 +652,9 @@ nc4_put_att(int ncid, NC *nc, int varid, const char *name, /* Mark attributes on variable dirty, so they get written */ if(var) - var->attr_dirty = NC_TRUE; + var->attr_dirty = NC_TRUE; - exit: +exit: /* If there was an error return it, otherwise return any potential range error value. If none, return NC_NOERR as usual.*/ if (retval) @@ -561,8 +664,20 @@ nc4_put_att(int ncid, NC *nc, int varid, const char *name, return NC_NOERR; } -/* Learn about an att. All the nc4 nc_inq_ functions just call - * nc4_get_att to get the metadata on an attribute. */ +/** + * @internal Learn about an att. All the nc4 nc_inq_ functions just + * call nc4_get_att to get the metadata on an attribute. + * + * @param ncid File and group ID. + * @param varid Variable ID. + * @param name Name of attribute. + * @param xtypep Pointer that gets type of attribute. + * @param lenp Pointer that gets length of attribute data array. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Ed Hartnett + */ int NC4_inq_att(int ncid, int varid, const char *name, nc_type *xtypep, size_t *lenp) { @@ -583,7 +698,17 @@ NC4_inq_att(int ncid, int varid, const char *name, nc_type *xtypep, size_t *lenp return nc4_get_att(ncid, nc, varid, name, xtypep, NC_NAT, lenp, NULL, 0, NULL); } -/* Learn an attnum, given a name. */ +/** + * @internal Learn an attnum, given a name. + * + * @param ncid File and group ID. + * @param varid Variable ID. + * @param name Name of attribute. + * @param attnump Pointer that gets the attribute index number. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ int NC4_inq_attid(int ncid, int varid, const char *name, int *attnump) { @@ -603,12 +728,23 @@ NC4_inq_attid(int ncid, int varid, const char *name, int *attnump) /* Handle netcdf-4 files. */ stat = nc4_get_att(ncid, nc, varid, name, NULL, NC_NAT, - NULL, attnump, 0, NULL); + NULL, attnump, 0, NULL); return stat; } -/* Given an attnum, find the att's name. */ +/** + * @internal Given an attnum, find the att's name. + * + * @param ncid File and group ID. + * @param varid Variable ID. + * @param attnum The index number of the attribute. + * @param name Pointer that gets name of attrribute. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Ed Hartnett + */ int NC4_inq_attname(int ncid, int varid, int attnum, char *name) { @@ -618,7 +754,7 @@ NC4_inq_attname(int ncid, int varid, int attnum, char *name) int retval = NC_NOERR; LOG((2, "nc_inq_attname: ncid 0x%x varid %d attnum %d", - ncid, varid, attnum)); + ncid, varid, attnum)); /* Find metadata. */ if (!(nc = nc4_find_nc_file(ncid,NULL))) @@ -639,11 +775,21 @@ NC4_inq_attname(int ncid, int varid, int attnum, char *name) return NC_NOERR; } -/* I think all atts should be named the exact same thing, to avoid - confusion! */ +/** + * @internal I think all atts should be named the exact same thing, to + * avoid confusion! + * + * @param ncid File and group ID. + * @param varid Variable ID. + * @param name Name of attribute. + * @param newname New name for attribute. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Ed Hartnett + */ int -NC4_rename_att(int ncid, int varid, const char *name, - const char *newname) +NC4_rename_att(int ncid, int varid, const char *name, const char *newname) { NC *nc; NC_GRP_INFO_T *grp; @@ -658,7 +804,7 @@ NC4_rename_att(int ncid, int varid, const char *name, return NC_EINVAL; LOG((2, "nc_rename_att: ncid 0x%x varid %d name %s newname %s", - ncid, varid, name, newname)); + ncid, varid, name, newname)); /* If the new name is too long, that's an error. */ if (strlen(newname) > NC_MAX_NAME) @@ -672,7 +818,7 @@ NC4_rename_att(int ncid, int varid, const char *name, /* If the file is read-only, return an error. */ if (h5->no_write) - return NC_EPERM; + return NC_EPERM; /* Check and normalize the name. */ if ((retval = nc4_check_name(newname, norm_newname))) @@ -686,7 +832,7 @@ NC4_rename_att(int ncid, int varid, const char *name, else { if (varid < 0 || varid >= grp->vars.nelems) - return NC_ENOTVAR; + return NC_ENOTVAR; var = grp->vars.value[varid]; if (!var) return NC_ENOTVAR; assert(var->varid == varid); @@ -694,14 +840,14 @@ NC4_rename_att(int ncid, int varid, const char *name, } for (att = list; att; att = att->l.next) if (!strncmp(att->name, norm_newname, NC_MAX_NAME)) - return NC_ENAMEINUSE; + return NC_ENAMEINUSE; /* Normalize name and find the attribute. */ if ((retval = nc4_normalize_name(name, norm_name))) return retval; for (att = list; att; att = att->l.next) if (!strncmp(att->name, norm_name, NC_MAX_NAME)) - break; + break; if (!att) return NC_ENOTATT; @@ -717,14 +863,14 @@ NC4_rename_att(int ncid, int varid, const char *name, if (varid == NC_GLOBAL) { if (H5Adelete(grp->hdf_grpid, att->name) < 0) - return NC_EHDFERR; + return NC_EHDFERR; } else { - if ((retval = nc4_open_var_grp2(grp, varid, &datasetid))) - return retval; + if ((retval = nc4_open_var_grp2(grp, varid, &datasetid))) + return retval; if (H5Adelete(datasetid, att->name) < 0) - return NC_EHDFERR; + return NC_EHDFERR; } att->created = NC_FALSE; } @@ -738,16 +884,24 @@ NC4_rename_att(int ncid, int varid, const char *name, /* Mark attributes on variable dirty, so they get written */ if(var) - var->attr_dirty = NC_TRUE; + var->attr_dirty = NC_TRUE; return retval; } -/* Delete an att. Rub it out. Push the button on it. Liquidate - it. Bump it off. Take it for a one-way ride. Terminate it. Drop the - bomb on it. You get the idea. - Ed Hartnett, 10/1/3 -*/ +/** + * @internal Delete an att. Rub it out. Push the button on + * it. Liquidate it. Bump it off. Take it for a one-way + * ride. Terminate it. + * + * @param ncid File and group ID. + * @param varid Variable ID. + * @param name Name of attribute to delete. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Ed Hartnett + */ int NC4_del_att(int ncid, int varid, const char *name) { @@ -764,7 +918,7 @@ NC4_del_att(int ncid, int varid, const char *name) return NC_EINVAL; LOG((2, "nc_del_att: ncid 0x%x varid %d name %s", - ncid, varid, name)); + ncid, varid, name)); /* Find metadata for this file. */ if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5))) @@ -780,9 +934,9 @@ NC4_del_att(int ncid, int varid, const char *name) if (!(h5->flags & NC_INDEF)) { if (h5->cmode & NC_CLASSIC_MODEL) - return NC_ENOTINDEFINE; + return NC_ENOTINDEFINE; if ((retval = NC4_redef(ncid))) - BAIL(retval); + BAIL(retval); } /* Get either the global or a variable attribute list. Also figure @@ -795,19 +949,19 @@ NC4_del_att(int ncid, int varid, const char *name) else { if (varid < 0 || varid >= grp->vars.nelems) - return NC_ENOTVAR; + return NC_ENOTVAR; var = grp->vars.value[varid]; if (!var) return NC_ENOTVAR; attlist = &var->att; assert(var->varid == varid); if (var->created) - locid = var->hdf_datasetid; + locid = var->hdf_datasetid; } /* Now find the attribute by name or number. */ for (att = *attlist; att; att = att->l.next) if (!strcmp(att->name, name)) - break; + break; /* If att is NULL, we couldn't find the attribute. */ if (!att) @@ -819,7 +973,7 @@ NC4_del_att(int ncid, int varid, const char *name) assert(locid); if(H5Adelete(locid, att->name) < 0) - BAIL(NC_EATTMETA); + BAIL(NC_EATTMETA); } /* Renumber all following attributes. */ @@ -830,16 +984,32 @@ NC4_del_att(int ncid, int varid, const char *name) if ((retval = nc4_att_list_del(attlist, att))) BAIL(retval); - exit: +exit: if (datasetid > 0) H5Dclose(datasetid); return retval; } -/* Write an attribute with type conversion. */ +/** + * @internal Write an attribute with type conversion. + * + * @param ncid File and group ID. + * @param varid Variable ID. + * @param name Name of attribute. + * @param file_type Type of the attribute data in file. + * @param mem_type Type of attribute data in memory. + * @param mem_type_is_long True if attribute data in memory is of type + * NC_LONG. + * @param len Length of attribute array. + * @param op Attribute data. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Ed Hartnett + */ static int nc4_put_att_tc(int ncid, int varid, const char *name, nc_type file_type, - nc_type mem_type, int mem_type_is_long, size_t len, - const void *op) + nc_type mem_type, int mem_type_is_long, size_t len, + const void *op) { NC *nc; NC_HDF5_FILE_INFO_T *h5; @@ -859,108 +1029,70 @@ nc4_put_att_tc(int ncid, int varid, const char *name, nc_type file_type, /* Check varid */ if (varid != NC_GLOBAL) { - /* Find info for this file and group, and set pointer to each. */ - NC_GRP_INFO_T *grp; - if (!(grp = nc4_rec_find_grp(h5->root_grp, (ncid & GRP_ID_MASK)))) - return NC_EBADGRPID; - - if (varid < 0 || varid >= grp->vars.nelems) - return NC_ENOTVAR; - if (grp->vars.value[varid] == NULL) - return NC_ENOTVAR; - assert(grp->vars.value[varid]->varid == varid); + /* Find info for this file and group, and set pointer to each. */ + NC_GRP_INFO_T *grp; + if (!(grp = nc4_rec_find_grp(h5->root_grp, (ncid & GRP_ID_MASK)))) + return NC_EBADGRPID; + + if (varid < 0 || varid >= grp->vars.nelems) + return NC_ENOTVAR; + if (grp->vars.value[varid] == NULL) + return NC_ENOTVAR; + assert(grp->vars.value[varid]->varid == varid); } if (!name || strlen(name) > NC_MAX_NAME) return NC_EBADNAME; LOG((3, "nc4_put_att_tc: ncid 0x%x varid %d name %s file_type %d " - "mem_type %d len %d", ncid, varid, name, file_type, mem_type, len)); + "mem_type %d len %d", ncid, varid, name, file_type, mem_type, len)); if(nc->ext_ncid == ncid && varid == NC_GLOBAL) { const char** reserved = NC_RESERVED_ATT_LIST; for(;*reserved;reserved++) { - if(strcmp(name,*reserved)==0) - return NC_ENAMEINUSE; + if(strcmp(name,*reserved)==0) + return NC_ENAMEINUSE; } } if(varid != NC_GLOBAL) { const char** reserved = NC_RESERVED_VARATT_LIST; for(;*reserved;reserved++) { - if(strcmp(name,*reserved)==0) - return NC_ENAMEINUSE; + if(strcmp(name,*reserved)==0) + return NC_ENAMEINUSE; } } /* Otherwise, handle things the netcdf-4 way. */ return nc4_put_att(ncid, nc, varid, name, file_type, mem_type, len, - mem_type_is_long, op); -} - -static int -nc4_get_att_special(NC_HDF5_FILE_INFO_T* h5, const char* name, - nc_type* filetypep, nc_type mem_type, size_t* lenp, - int* attnump, int is_long, void* data) -{ - /* Fail if asking for att id */ - if(attnump) - return NC_EATTMETA; - - if(strcmp(name,NCPROPS)==0) { - char* propdata = NULL; - int stat = NC_NOERR; - int len; - if(h5->fileinfo->propattr.version == 0) - return NC_ENOTATT; - if(mem_type == NC_NAT) mem_type = NC_CHAR; - if(mem_type != NC_CHAR) - return NC_ECHAR; - if(filetypep) *filetypep = NC_CHAR; - stat = NC4_buildpropinfo(&h5->fileinfo->propattr, &propdata); - if(stat != NC_NOERR) return stat; - len = strlen(propdata); - if(lenp) *lenp = len; - if(data) strncpy((char*)data,propdata,len+1); - free(propdata); - } else if(strcmp(name,ISNETCDF4ATT)==0 - || strcmp(name,SUPERBLOCKATT)==0) { - unsigned long long iv = 0; - if(filetypep) *filetypep = NC_INT; - if(lenp) *lenp = 1; - if(strcmp(name,SUPERBLOCKATT)==0) - iv = (unsigned long long)h5->fileinfo->superblockversion; - else /* strcmp(name,ISNETCDF4ATT)==0 */ - iv = NC4_isnetcdf4(h5); - if(mem_type == NC_NAT) mem_type = NC_INT; - if(data) - switch (mem_type) { - case NC_BYTE: *((char*)data) = (char)iv; break; - case NC_SHORT: *((short*)data) = (short)iv; break; - case NC_INT: *((int*)data) = (int)iv; break; - case NC_UBYTE: *((unsigned char*)data) = (unsigned char)iv; break; - case NC_USHORT: *((unsigned short*)data) = (unsigned short)iv; break; - case NC_UINT: *((unsigned int*)data) = (unsigned int)iv; break; - case NC_INT64: *((long long*)data) = (long long)iv; break; - case NC_UINT64: *((unsigned long long*)data) = (unsigned long long)iv; break; - default: - return NC_ERANGE; - } - } - return NC_NOERR; + mem_type_is_long, op); } -/* Read an attribute of any type, with type conversion. This may be - * called by any of the nc_get_att_* functions. */ +/** + * @internal Read an attribute of any type, with type conversion. This + * may be called by any of the nc_get_att_* functions. + * + * @param ncid File and group ID. + * @param varid Variable ID. + * @param name Name of attribute. + * @param mem_type Type of attribute data in memory. + * @param mem_type_is_long True if attribute data in memory is of type + * NC_LONG. + * @param ip Attribute data. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Ed Hartnett + */ int nc4_get_att_tc(int ncid, int varid, const char *name, nc_type mem_type, - int mem_type_is_long, void *ip) + int mem_type_is_long, void *ip) { NC *nc; NC_HDF5_FILE_INFO_T *h5; LOG((3, "nc4_get_att_tc: ncid 0x%x varid %d name %s mem_type %d", - ncid, varid, name, mem_type)); + ncid, varid, name, mem_type)); /* Find metadata. */ if (!(nc = nc4_find_nc_file(ncid,NULL))) @@ -971,16 +1103,44 @@ nc4_get_att_tc(int ncid, int varid, const char *name, nc_type mem_type, assert(h5); return nc4_get_att(ncid, nc, varid, name, NULL, mem_type, - NULL, NULL, mem_type_is_long, ip); + NULL, NULL, mem_type_is_long, ip); } +/** + * @internal Write an attribute. + * + * @param ncid File and group ID. + * @param varid Variable ID. + * @param name Name of attribute. + * @param xtype Type of the attribute. + * @param nelems Number of elements in attribute array. + * @param value Attribute data. + * @param memtype Type of data in memory. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Ed Hartnett + */ int NC4_put_att(int ncid, int varid, const char *name, nc_type xtype, - size_t nelems, const void *value, nc_type memtype) + size_t nelems, const void *value, nc_type memtype) { return nc4_put_att_tc(ncid, varid, name, xtype, memtype, 0, nelems, value); } +/** + * @internal Get an attribute. + * + * @param ncid File and group ID. + * @param varid Variable ID. + * @param name Name of attribute. + * @param value Pointer that gets attribute data. + * @param memtype The type the data should be converted to as it is read. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Ed Hartnett + */ int NC4_get_att(int ncid, int varid, const char *name, void *value, nc_type memtype) { diff --git a/libsrc4/nc4dim.c b/libsrc4/nc4dim.c index 8d17c9aa5a..3037318303 100644 --- a/libsrc4/nc4dim.c +++ b/libsrc4/nc4dim.c @@ -1,22 +1,34 @@ -/* - -This file is part of netcdf-4, a netCDF-like interface for HDF5, or a -HDF5 backend for netCDF, depending on your point of view. - -This file handles the nc4 dimension functions. - -Copyright 2003-5, University Corporation for Atmospheric Research. See -the COPYRIGHT file for copying and redistribution conditions. - -$Id: nc4dim.c,v 1.41 2010/05/25 17:54:23 dmh Exp $ +/** + * @file + * @internal This file is part of netcdf-4, a netCDF-like interface + * for HDF5, or a HDF5 backend for netCDF, depending on your point of + * view. + * + * This file handles the nc4 dimension functions. + * + * Copyright 2003-5, University Corporation for Atmospheric Research. See + * the COPYRIGHT file for copying and redistribution conditions. + * + * @author Ed Hartnett */ #include "nc4internal.h" #include "nc4dispatch.h" -/* Netcdf-4 files might have more than one unlimited dimension, but - return the first one anyway. */ -/* Note that this code is inconsistent with nc_inq */ +/** + * @internal Netcdf-4 files might have more than one unlimited + * dimension, but return the first one anyway. + * + * @note that this code is inconsistent with nc_inq + * + * @param ncid File and group ID. + * @param unlimdimidp Pointer that gets ID of first unlimited + * dimension, or -1. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Ed Hartnett + */ int NC4_inq_unlimdim(int ncid, int *unlimdimidp) { @@ -52,8 +64,28 @@ NC4_inq_unlimdim(int ncid, int *unlimdimidp) return NC_NOERR; } -/* Dimensions are defined in attributes attached to the appropriate - group in the data file. */ +/** + * @internal Dimensions are defined in attributes attached to the + * appropriate group in the data file. + * + * @param ncid File and group ID. + * @param name Name of the new dimension. + * @param len Length of the new dimension. + * @param idp Pointer that gets the ID of the new dimension. Ignored + * if NULL. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_EMAXNAME Name is too long. + * @return ::NC_EBADNAME Name breaks netCDF name rules. + * @return ::NC_EINVAL Invalid input. + * @return ::NC_EPERM Read-only file. + * @return ::NC_EUNLIMIT Only one unlimited dim for classic model. + * @return ::NC_ENOTINDEFINE Not in define mode. + * @return ::NC_EDIMSIZE Dim length too large. + * @return ::NC_ENAMEINUSE Name already in use in group. + * @author Ed Hartnett + */ int NC4_def_dim(int ncid, const char *name, size_t len, int *idp) { @@ -135,7 +167,18 @@ NC4_def_dim(int ncid, const char *name, size_t len, int *idp) return retval; } -/* Given dim name, find its id. */ +/** + * @internal Given dim name, find its id. + * + * @param ncid File and group ID. + * @param name Name of the dimension to find. + * @param idp Pointer that gets dimension ID. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_EBADDIM Dimension not found. + * @author Ed Hartnett + */ int NC4_inq_dimid(int ncid, const char *name, int *idp) { @@ -176,9 +219,21 @@ NC4_inq_dimid(int ncid, const char *name, int *idp) return NC_EBADDIM; } -/* Find out name and len of a dim. For an unlimited dimension, the - length is the largest length so far written. If the name of lenp - pointers are NULL, they will be ignored. */ +/** + * @internal Find out name and len of a dim. For an unlimited + * dimension, the length is the largest length so far written. If the + * name of lenp pointers are NULL, they will be ignored. + * + * @param ncid File and group ID. + * @param dimid Dimension ID. + * @param name Pointer that gets name of the dimension. + * @param lenp Pointer that gets length of dimension. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_EDIMSIZE Dimension length too large. + * @author Ed Hartnett + */ int NC4_inq_dim(int ncid, int dimid, char *name, size_t *lenp) { @@ -234,7 +289,25 @@ NC4_inq_dim(int ncid, int dimid, char *name, size_t *lenp) return ret; } -/* Rename a dimension, for those who like to prevaricate. */ +/** + * @internal Rename a dimension, for those who like to prevaricate. + * + * @param ncid File and group ID. + * @param dimid Dimension ID. + * @param name New dimension name. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_EHDFERR HDF5 returned error. + * @return ::NC_ENOMEM Out of memory. + * @return ::NC_EINVAL Name must be provided. + * @return ::NC_ENAMEINUSE Name is already in use in group. + * @return ::NC_EMAXNAME Name is too long. + * @return ::NC_EBADDIM Dimension not found. + * @return ::NC_EBADNAME Name breaks netCDF name rules. + * @return ::NC_EDIMMETA Unable to delete HDF5 dataset. + * @author Ed Hartnett + */ int NC4_rename_dim(int ncid, int dimid, const char *name) { @@ -339,10 +412,21 @@ NC4_rename_dim(int ncid, int dimid, const char *name) return NC_NOERR; } -/* Returns an array of unlimited dimension ids.The user can get the - number of unlimited dimensions by first calling this with NULL for - the second pointer. -*/ +/** + * @internal Returns an array of unlimited dimension ids.The user can + * get the number of unlimited dimensions by first calling this with + * NULL for the second pointer. + * + * @param ncid File and group ID. + * @param nunlimdimsp Pointer that gets the number of unlimited + * dimensions. Ignored if NULL. + * @param unlimdimidsp Pointer that gets arrray of unlimited dimension + * ID. Ignored if NULL. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Ed Hartnett, Dennis Heimbigner + */ int NC4_inq_unlimdims(int ncid, int *nunlimdimsp, int *unlimdimidsp) { diff --git a/libsrc4/nc4dispatch.c b/libsrc4/nc4dispatch.c index 768eab25e7..24f83103df 100644 --- a/libsrc4/nc4dispatch.c +++ b/libsrc4/nc4dispatch.c @@ -102,6 +102,12 @@ NC4_get_var_chunk_cache, NC_Dispatch* NC4_dispatch_table = NULL; /* moved here from ddispatch.c */ +/** + * @internal Initialize netCDF-4. + * + * @return ::NC_NOERR No error. + * @author Dennis Heimbigner + */ int NC4_initialize(void) { @@ -109,6 +115,12 @@ NC4_initialize(void) return NC_NOERR; } +/** + * @internal Finalize netCDF-4. + * + * @return ::NC_NOERR No error. + * @author Dennis Heimbigner + */ int NC4_finalize(void) { diff --git a/libsrc4/nc4file.c b/libsrc4/nc4file.c index bfcd9e0462..aeb75115a3 100644 --- a/libsrc4/nc4file.c +++ b/libsrc4/nc4file.c @@ -1,208 +1,726 @@ -/** \file -The netCDF-4 file functions. - -This file is part of netcdf-4, a netCDF-like interface for HDF5, or -a HDF5 backend for netCDF, depending on your point of view. - -Copyright 2003, University Corporation for Atmospheric Research. See -COPYRIGHT file for copying and redistribution conditions. - -*/ - +/** + * @file + * @internal The netCDF-4 file functions. + * + * This file is part of netcdf-4, a netCDF-like interface for HDF5, or + * a HDF5 backend for netCDF, depending on your point of view. + * + * Copyright 2003, University Corporation for Atmospheric Research. See + * COPYRIGHT file for copying and redistribution conditions. + * @author Ed Hartnett + */ #include "config.h" #include /* netcdf functions sometimes return system errors */ - #include "nc.h" #include "nc4internal.h" #include "nc4dispatch.h" - -extern int nc4_vararray_add(NC_GRP_INFO_T *grp, - NC_VAR_INFO_T *var); - -/* must be after nc4internal.h */ -#include +#include /* must be after nc4internal.h */ #include #ifdef USE_HDF4 #include #endif #include -/* When we have open objects at file close, should - we log them or print to stdout. Default is to log -*/ +extern int nc4_vararray_add(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var); + +/** @internal When we have open objects at file close, should + we log them or print to stdout. Default is to log. */ #define LOGOPEN 1 -#define MIN_DEFLATE_LEVEL 0 -#define MAX_DEFLATE_LEVEL 9 +#define CD_NELEMS_ZLIB 1 /**< Number of parameters needed for ZLIB filter. */ -/*Forward*/ -static int read_hdf5_att(NC_GRP_INFO_T *grp, hid_t attid, NC_ATT_INFO_T *att); -static void hdf5free(void* memory); +/** + * @internal Wrap HDF5 allocated memory free operations + * + * @param memory Pointer to memory to be freed. + * + * @return ::NC_NOERR No error. + * @author Dennis Heimbigner +*/ +static void +hdf5free(void* memory) +{ +#ifndef JNA + /* On Windows using the microsoft runtime, it is an error + for one library to free memory allocated by a different library.*/ +#ifdef HDF5_HAS_H5FREE + if(memory != NULL) H5free_memory(memory); +#else +#ifndef _MSC_VER + if(memory != NULL) free(memory); +#endif +#endif +#endif +} /* Custom iteration callback data */ typedef struct { - NC_GRP_INFO_T *grp; - NC_VAR_INFO_T *var; + NC_GRP_INFO_T *grp; + NC_VAR_INFO_T *var; } att_iter_info; + +/** + * @internal Given an HDF5 type, set a pointer to netcdf type. + * + * @param h5 Pointer to HDF5 file info struct. + * @param native_typeid HDF5 type ID. + * @param xtype Pointer that gets netCDF type. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_EHDFERR HDF5 returned error. + * @return ::NC_EBADTYPID Type not found. + * @author Ed Hartnett +*/ +static int +get_netcdf_type(NC_HDF5_FILE_INFO_T *h5, hid_t native_typeid, + nc_type *xtype) +{ + NC_TYPE_INFO_T *type; + H5T_class_t class; + htri_t is_str, equal = 0; + + assert(h5 && xtype); + + if ((class = H5Tget_class(native_typeid)) < 0) + return NC_EHDFERR; + + /* H5Tequal doesn't work with H5T_C_S1 for some reason. But + * H5Tget_class will return H5T_STRING if this is a string. */ + if (class == H5T_STRING) + { + if ((is_str = H5Tis_variable_str(native_typeid)) < 0) + return NC_EHDFERR; + if (is_str) + *xtype = NC_STRING; + else + *xtype = NC_CHAR; + return NC_NOERR; + } + else if (class == H5T_INTEGER || class == H5T_FLOAT) + { + /* For integers and floats, we don't have to worry about + * endianness if we compare native types. */ + if ((equal = H5Tequal(native_typeid, H5T_NATIVE_SCHAR)) < 0) + return NC_EHDFERR; + if (equal) + { + *xtype = NC_BYTE; + return NC_NOERR; + } + if ((equal = H5Tequal(native_typeid, H5T_NATIVE_SHORT)) < 0) + return NC_EHDFERR; + if (equal) + { + *xtype = NC_SHORT; + return NC_NOERR; + } + if ((equal = H5Tequal(native_typeid, H5T_NATIVE_INT)) < 0) + return NC_EHDFERR; + if (equal) + { + *xtype = NC_INT; + return NC_NOERR; + } + if ((equal = H5Tequal(native_typeid, H5T_NATIVE_FLOAT)) < 0) + return NC_EHDFERR; + if (equal) + { + *xtype = NC_FLOAT; + return NC_NOERR; + } + if ((equal = H5Tequal(native_typeid, H5T_NATIVE_DOUBLE)) < 0) + return NC_EHDFERR; + if (equal) + { + *xtype = NC_DOUBLE; + return NC_NOERR; + } + if ((equal = H5Tequal(native_typeid, H5T_NATIVE_UCHAR)) < 0) + return NC_EHDFERR; + if (equal) + { + *xtype = NC_UBYTE; + return NC_NOERR; + } + if ((equal = H5Tequal(native_typeid, H5T_NATIVE_USHORT)) < 0) + return NC_EHDFERR; + if (equal) + { + *xtype = NC_USHORT; + return NC_NOERR; + } + if ((equal = H5Tequal(native_typeid, H5T_NATIVE_UINT)) < 0) + return NC_EHDFERR; + if (equal) + { + *xtype = NC_UINT; + return NC_NOERR; + } + if ((equal = H5Tequal(native_typeid, H5T_NATIVE_LLONG)) < 0) + return NC_EHDFERR; + if (equal) + { + *xtype = NC_INT64; + return NC_NOERR; + } + if ((equal = H5Tequal(native_typeid, H5T_NATIVE_ULLONG)) < 0) + return NC_EHDFERR; + if (equal) + { + *xtype = NC_UINT64; + return NC_NOERR; + } + } + + /* Maybe we already know about this type. */ + if (!equal) + if((type = nc4_rec_find_hdf_type(h5->root_grp, native_typeid))) + { + *xtype = type->nc_typeid; + return NC_NOERR; + } + + *xtype = NC_NAT; + return NC_EBADTYPID; +} + +/** + * @internal Read an attribute. This is called by att_read_var_callbk(). + * + * @param grp Pointer to group info struct. + * @param attid Attribute ID. + * @param att Pointer that gets att info struct. + * + * @return ::NC_NOERR No error. + * @return ::NC_EHDFERR HDF5 returned error. + * @author Ed Hartnett +*/ +static int +read_hdf5_att(NC_GRP_INFO_T *grp, hid_t attid, NC_ATT_INFO_T *att) +{ + hid_t spaceid = 0, file_typeid = 0; + hsize_t dims[1] = {0}; /* netcdf attributes always 1-D. */ + int retval = NC_NOERR; + size_t type_size; + int att_ndims; + hssize_t att_npoints; + H5T_class_t att_class; + int fixed_len_string = 0; + size_t fixed_size = 0; + + assert(att->name); + LOG((5, "%s: att->attnum %d att->name %s att->nc_typeid %d att->len %d", + __func__, att->attnum, att->name, (int)att->nc_typeid, att->len)); + + /* Get type of attribute in file. */ + if ((file_typeid = H5Aget_type(attid)) < 0) + return NC_EATTMETA; + if ((att->native_hdf_typeid = H5Tget_native_type(file_typeid, H5T_DIR_DEFAULT)) < 0) + BAIL(NC_EHDFERR); + if ((att_class = H5Tget_class(att->native_hdf_typeid)) < 0) + BAIL(NC_EATTMETA); + if (att_class == H5T_STRING && !H5Tis_variable_str(att->native_hdf_typeid)) + { + fixed_len_string++; + if (!(fixed_size = H5Tget_size(att->native_hdf_typeid))) + BAIL(NC_EATTMETA); + } + if ((retval = get_netcdf_type(grp->nc4_info, att->native_hdf_typeid, &(att->nc_typeid)))) + BAIL(retval); + + + /* Get len. */ + if ((spaceid = H5Aget_space(attid)) < 0) + BAIL(NC_EATTMETA); + if ((att_ndims = H5Sget_simple_extent_ndims(spaceid)) < 0) + BAIL(NC_EATTMETA); + if ((att_npoints = H5Sget_simple_extent_npoints(spaceid)) < 0) + BAIL(NC_EATTMETA); + + /* If both att_ndims and att_npoints are zero, then this is a + * zero length att. */ + if (att_ndims == 0 && att_npoints == 0) + dims[0] = 0; + else if (att->nc_typeid == NC_STRING) + dims[0] = att_npoints; + else if (att->nc_typeid == NC_CHAR) + { + /* NC_CHAR attributes are written as a scalar in HDF5, of type + * H5T_C_S1, of variable length. */ + if (att_ndims == 0) + { + if (!(dims[0] = H5Tget_size(file_typeid))) + BAIL(NC_EATTMETA); + } + else + { + /* This is really a string type! */ + att->nc_typeid = NC_STRING; + dims[0] = att_npoints; + } + } + else + { + H5S_class_t space_class; + + /* All netcdf attributes are scalar or 1-D only. */ + if (att_ndims > 1) + BAIL(NC_EATTMETA); + + /* Check class of HDF5 dataspace */ + if ((space_class = H5Sget_simple_extent_type(spaceid)) < 0) + BAIL(NC_EATTMETA); + + /* Check for NULL HDF5 dataspace class (should be weeded out earlier) */ + if (H5S_NULL == space_class) + BAIL(NC_EATTMETA); + + /* check for SCALAR HDF5 dataspace class */ + if (H5S_SCALAR == space_class) + dims[0] = 1; + else /* Must be "simple" dataspace */ + { + /* Read the size of this attribute. */ + if (H5Sget_simple_extent_dims(spaceid, dims, NULL) < 0) + BAIL(NC_EATTMETA); + } + } + + /* Tell the user what the length if this attribute is. */ + att->len = dims[0]; + + /* Allocate some memory if the len is not zero, and read the + attribute. */ + if (dims[0]) + { + if ((retval = nc4_get_typelen_mem(grp->nc4_info, att->nc_typeid, 0, + &type_size))) + return retval; + if (att_class == H5T_VLEN) + { + if (!(att->vldata = malloc((unsigned int)(att->len * sizeof(hvl_t))))) + BAIL(NC_ENOMEM); + if (H5Aread(attid, att->native_hdf_typeid, att->vldata) < 0) + BAIL(NC_EATTMETA); + } + else if (att->nc_typeid == NC_STRING) + { + if (!(att->stdata = calloc(att->len, sizeof(char *)))) + BAIL(NC_ENOMEM); + /* For a fixed length HDF5 string, the read requires + * contiguous memory. Meanwhile, the netCDF API requires that + * nc_free_string be called on string arrays, which would not + * work if one contiguous memory block were used. So here I + * convert the contiguous block of strings into an array of + * malloced strings (each string with its own malloc). Then I + * copy the data and free the contiguous memory. This + * involves copying the data, which is bad, but this only + * occurs for fixed length string attributes, and presumably + * these are small. (And netCDF-4 does not create them - it + * always uses variable length strings. */ + if (fixed_len_string) + { + int i; + char *contig_buf, *cur; + + /* Alloc space for the contiguous memory read. */ + if (!(contig_buf = malloc(att->len * fixed_size * sizeof(char)))) + BAIL(NC_ENOMEM); + + /* Read the fixed-len strings as one big block. */ + if (H5Aread(attid, att->native_hdf_typeid, contig_buf) < 0) { + free(contig_buf); + BAIL(NC_EATTMETA); + } + + /* Copy strings, one at a time, into their new home. Alloc + space for each string. The user will later free this + space with nc_free_string. */ + cur = contig_buf; + for (i = 0; i < att->len; i++) + { + if (!(att->stdata[i] = malloc(fixed_size))) { + free(contig_buf); + BAIL(NC_ENOMEM); + } + strncpy(att->stdata[i], cur, fixed_size); + cur += fixed_size; + } + + /* Free contiguous memory buffer. */ + free(contig_buf); + } + else + { + /* Read variable-length string atts. */ + if (H5Aread(attid, att->native_hdf_typeid, att->stdata) < 0) + BAIL(NC_EATTMETA); + } + } + else + { + if (!(att->data = malloc((unsigned int)(att->len * type_size)))) + BAIL(NC_ENOMEM); + if (H5Aread(attid, att->native_hdf_typeid, att->data) < 0) + BAIL(NC_EATTMETA); + } + } + + if (H5Tclose(file_typeid) < 0) + BAIL(NC_EHDFERR); + if (H5Sclose(spaceid) < 0) + return NC_EHDFERR; + + return NC_NOERR; + +exit: + if (H5Tclose(file_typeid) < 0) + BAIL2(NC_EHDFERR); + if (spaceid > 0 && H5Sclose(spaceid) < 0) + BAIL2(NC_EHDFERR); + return retval; +} + +/** + * @internal Callback function for reading attributes. This is used by read_var(). + * + * @param loc_id HDF5 attribute ID. + * @param att_name Name of the attrigute. + * @param ainfo HDF5 info struct for attribute. + * @param att_data The attribute data. + * + * @return ::NC_NOERR No error. + * @return ::NC_EHDFERR HDF5 returned error. + * @return ::NC_ENOMEM Out of memory. + * @return ::NC_EATTMETA HDF5 can't open attribute. + * @return ::NC_EBADTYPID Can't read attribute type. + */ static herr_t att_read_var_callbk(hid_t loc_id, const char *att_name, const H5A_info_t *ainfo, void *att_data) { - hid_t attid = 0; - int retval = NC_NOERR; - NC_ATT_INFO_T *att; - att_iter_info *att_info = (att_iter_info *)att_data; - const char** reserved; - + hid_t attid = 0; + int retval = NC_NOERR; + NC_ATT_INFO_T *att; + att_iter_info *att_info = (att_iter_info *)att_data; + const char** reserved; - /* Should we ignore this attribute? */ - for(reserved=NC_RESERVED_VARATT_LIST;*reserved;reserved++) { - if (strcmp(att_name, *reserved)==0) break; - } + /* Should we ignore this attribute? */ + for(reserved=NC_RESERVED_VARATT_LIST;*reserved;reserved++) { + if (strcmp(att_name, *reserved)==0) break; + } - if(*reserved == NULL) { + if(*reserved == NULL) { /* Open the att by name. */ if ((attid = H5Aopen(loc_id, att_name, H5P_DEFAULT)) < 0) - BAIL(NC_EATTMETA); + BAIL(NC_EATTMETA); LOG((4, "%s:: att_name %s", __func__, att_name)); /* Add to the end of the list of atts for this var. */ if ((retval = nc4_att_list_add(&att_info->var->att, &att))) - BAIL(retval); + BAIL(retval); /* Fill in the information we know. */ att->attnum = att_info->var->natts++; if (!(att->name = strdup(att_name))) - BAIL(NC_ENOMEM); + BAIL(NC_ENOMEM); /* Read the rest of the info about the att, * including its values. */ if ((retval = read_hdf5_att(att_info->grp, attid, att))) - { - if (NC_EBADTYPID == retval) - { - if ((retval = nc4_att_list_del(&att_info->var->att, att))) - BAIL(retval); - att = NULL; - } - else - BAIL(retval); - } + { + if (NC_EBADTYPID == retval) + { + if ((retval = nc4_att_list_del(&att_info->var->att, att))) + BAIL(retval); + att = NULL; + } + else + BAIL(retval); + } if (att) - att->created = NC_TRUE; + att->created = NC_TRUE; + + if (attid > 0 && H5Aclose(attid) < 0) + BAIL2(NC_EHDFERR); + + } /* endif not HDF5 att */ + + return NC_NOERR; + +exit: + if (attid > 0 && H5Aclose(attid) < 0) + BAIL2(NC_EHDFERR); + + return retval; +} + +/** @internal These flags may not be set for open mode. */ +static const int ILLEGAL_OPEN_FLAGS = (NC_MMAP|NC_64BIT_OFFSET); + +/** @internal These flags may not be set for create. */ +static const int ILLEGAL_CREATE_FLAGS = (NC_NOWRITE|NC_MMAP|NC_INMEMORY|NC_64BIT_OFFSET|NC_CDF5); + +extern void reportopenobjects(int log, hid_t); + +/** + * @internal Struct to track information about objects in a group, for + * nc4_rec_read_metadata() +*/ +typedef struct NC4_rec_read_metadata_obj_info +{ + hid_t oid; /* HDF5 object ID */ + char oname[NC_MAX_NAME + 1]; /* Name of object */ + H5G_stat_t statbuf; /* Information about the object */ + struct NC4_rec_read_metadata_obj_info *next; /* Pointer to next node in list */ +} NC4_rec_read_metadata_obj_info_t; + +/** + * @internal User data struct for call to H5Literate() in + * nc4_rec_read_metadata(). Tracks the groups, named datatypes and + * datasets in the group, for later use. +*/ +typedef struct NC4_rec_read_metadata_ud +{ + NC4_rec_read_metadata_obj_info_t *grps_head, *grps_tail; /* Pointers to head & tail of list of groups */ + NC_GRP_INFO_T *grp; /* Pointer to parent group */ +} NC4_rec_read_metadata_ud_t; + +/* Forward */ +static int NC4_enddef(int ncid); +static int nc4_rec_read_metadata(NC_GRP_INFO_T *grp); + +/** + * @internal This function will write all changed metadata, and + * (someday) reread all metadata from the file. + * + * @param h5 Pointer to HDF5 file info struct. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett +*/ +static int +sync_netcdf4_file(NC_HDF5_FILE_INFO_T *h5) +{ + int retval; - if (attid > 0 && H5Aclose(attid) < 0) - BAIL2(NC_EHDFERR); + assert(h5); + LOG((3, "%s", __func__)); - } /* endif not HDF5 att */ - - return NC_NOERR; + /* If we're in define mode, that's an error, for strict nc3 rules, + * otherwise, end define mode. */ + if (h5->flags & NC_INDEF) + { + if (h5->cmode & NC_CLASSIC_MODEL) + return NC_EINDEFINE; - exit: - if (attid > 0 && H5Aclose(attid) < 0) - BAIL2(NC_EHDFERR); + /* Turn define mode off. */ + h5->flags ^= NC_INDEF; - return retval; -} + /* Redef mode needs to be tracked separately for nc_abort. */ + h5->redef = NC_FALSE; + } -/* Define the illegal mode flags */ -static const int ILLEGAL_OPEN_FLAGS = (NC_MMAP|NC_64BIT_OFFSET); +#ifdef LOGGING + /* This will print out the names, types, lens, etc of the vars and + atts in the file, if the logging level is 2 or greater. */ + log_metadata_nc(h5->root_grp->nc4_info->controller); +#endif -static const int ILLEGAL_CREATE_FLAGS = (NC_NOWRITE|NC_MMAP|NC_INMEMORY|NC_64BIT_OFFSET|NC_CDF5); + /* Write any metadata that has changed. */ + if (!(h5->cmode & NC_NOWRITE)) + { + nc_bool_t bad_coord_order = NC_FALSE; /* if detected, propagate to all groups to consistently store dimids */ -extern void reportopenobjects(int log, hid_t); + if ((retval = nc4_rec_write_groups_types(h5->root_grp))) + return retval; + if ((retval = nc4_rec_detect_need_to_preserve_dimids(h5->root_grp, &bad_coord_order))) + return retval; + if ((retval = nc4_rec_write_metadata(h5->root_grp, bad_coord_order))) + return retval; + } -/*! Struct to track information about objects in a group, for nc4_rec_read_metadata() + if (H5Fflush(h5->hdfid, H5F_SCOPE_GLOBAL) < 0) + return NC_EHDFERR; - \internal + return retval; +} +/** + * @internal This function will free all allocated metadata memory, + * and close the HDF5 file. The group that is passed in must be the + * root group of the file. + * + * @param h5 Pointer to HDF5 file info struct. + * @param abort True if this is an abort. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett */ -typedef struct NC4_rec_read_metadata_obj_info +static int +close_netcdf4_file(NC_HDF5_FILE_INFO_T *h5, int abort) { - hid_t oid; /* HDF5 object ID */ - char oname[NC_MAX_NAME + 1]; /* Name of object */ - H5G_stat_t statbuf; /* Information about the object */ - struct NC4_rec_read_metadata_obj_info *next; /* Pointer to next node in list */ -} NC4_rec_read_metadata_obj_info_t; + int retval = NC_NOERR; -/*! User data struct for call to H5Literate() in nc4_rec_read_metadata() + assert(h5 && h5->root_grp); + LOG((3, "%s: h5->path %s abort %d", __func__, h5->controller->path, abort)); -\internal + /* According to the docs, always end define mode on close. */ + if (h5->flags & NC_INDEF) + h5->flags ^= NC_INDEF; -Tracks the groups, named datatypes and datasets in the group, for later use. -*/ -typedef struct NC4_rec_read_metadata_ud -{ - NC4_rec_read_metadata_obj_info_t *grps_head, *grps_tail; /* Pointers to head & tail of list of groups */ - NC_GRP_INFO_T *grp; /* Pointer to parent group */ -} NC4_rec_read_metadata_ud_t; + /* Sync the file, unless we're aborting, or this is a read-only + * file. */ + if (!h5->no_write && !abort) + if ((retval = sync_netcdf4_file(h5))) + goto exit; -/* Forward */ -static int NC4_enddef(int ncid); -static int nc4_rec_read_metadata(NC_GRP_INFO_T *grp); -static int close_netcdf4_file(NC_HDF5_FILE_INFO_T *h5, int abort); + /* Delete all the list contents for vars, dims, and atts, in each + * group. */ + if ((retval = nc4_rec_grp_del(&h5->root_grp, h5->root_grp))) + goto exit; + + /* Close hdf file. */ +#ifdef USE_HDF4 + if (h5->hdf4) + { + if (SDend(h5->sdid)) + BAIL_QUIET(NC_EHDFERR); + } + else +#endif /* USE_HDF4 */ + { +#ifdef USE_PARALLEL4 + /* Free the MPI Comm & Info objects, if we opened the file in parallel */ + if(h5->parallel) + { + if(MPI_COMM_NULL != h5->comm) + MPI_Comm_free(&h5->comm); + if(MPI_INFO_NULL != h5->info) + MPI_Info_free(&h5->info); + } +#endif + + if(h5->fileinfo) free(h5->fileinfo); + + if (H5Fclose(h5->hdfid) < 0) + { + int nobjs; + + nobjs = H5Fget_obj_count(h5->hdfid, H5F_OBJ_ALL); + /* Apparently we can get an error even when nobjs == 0 */ + if(nobjs < 0) { + BAIL_QUIET(NC_EHDFERR); + } else if(nobjs > 0) { +#ifdef LOGGING + char msg[1024]; + int logit = 1; + /* If the close doesn't work, probably there are still some HDF5 + * objects open, which means there's a bug in the library. So + * print out some info on to help the poor programmer figure it + * out. */ + snprintf(msg,sizeof(msg),"There are %d HDF5 objects open!", nobjs); +#ifdef LOGOPEN + LOG((0, msg)); +#else + fprintf(stdout,msg); + logit = 0; +#endif + reportopenobjects(logit,h5->hdfid); +#endif + } + } + } +exit: + /* Free the nc4_info struct; above code should have reclaimed + everything else */ + if(!retval && h5 != NULL) + free(h5); + return retval; +} -/* Define the names of attributes to ignore - * added by the HDF5 dimension scale; these - * attached to variables. - * They cannot be modified thru the netcdf-4 API. +/** + * @internal Define the names of attributes to ignore added by the + * HDF5 dimension scale; these attached to variables. They cannot be + * modified thru the netcdf-4 API. */ const char* NC_RESERVED_VARATT_LIST[] = { -NC_ATT_REFERENCE_LIST, -NC_ATT_CLASS, -NC_ATT_DIMENSION_LIST, -NC_ATT_NAME, -NC_ATT_COORDINATES, -NC_DIMID_ATT_NAME, -NULL + NC_ATT_REFERENCE_LIST, + NC_ATT_CLASS, + NC_ATT_DIMENSION_LIST, + NC_ATT_NAME, + NC_ATT_COORDINATES, + NC_DIMID_ATT_NAME, + NULL }; -/* Define the names of attributes to ignore - * because they are "hidden" global attributes. - * They can be read, but not modified thru the netcdf-4 API. +/** + * @internal Define the names of attributes to ignore because they are + * "hidden" global attributes. They can be read, but not modified thru + * the netcdf-4 API. */ const char* NC_RESERVED_ATT_LIST[] = { -NC_ATT_FORMAT, -NC3_STRICT_ATT_NAME, -NCPROPS, -ISNETCDF4ATT, -SUPERBLOCKATT, -NULL + NC_ATT_FORMAT, + NC3_STRICT_ATT_NAME, + NCPROPS, + ISNETCDF4ATT, + SUPERBLOCKATT, + NULL }; -/* Define the subset of the reserved list that is readable by name only */ +/** + * @internal Define the subset of the reserved list that is readable + * by name only +*/ const char* NC_RESERVED_SPECIAL_LIST[] = { -ISNETCDF4ATT, -SUPERBLOCKATT, -NCPROPS, -NULL + ISNETCDF4ATT, + SUPERBLOCKATT, + NCPROPS, + NULL }; -/* These are the default chunk cache sizes for HDF5 files created or - * opened with netCDF-4. */ -size_t nc4_chunk_cache_size = CHUNK_CACHE_SIZE; -size_t nc4_chunk_cache_nelems = CHUNK_CACHE_NELEMS; -float nc4_chunk_cache_preemption = CHUNK_CACHE_PREEMPTION; +size_t nc4_chunk_cache_size = CHUNK_CACHE_SIZE; /**< Default chunk cache size. */ +size_t nc4_chunk_cache_nelems = CHUNK_CACHE_NELEMS; /**< Default chunk cache number of elements. */ +float nc4_chunk_cache_preemption = CHUNK_CACHE_PREEMPTION; /**< Default chunk cache preemption. */ -/* For performance, fill this array only the first time, and keep it - * in global memory for each further use. */ -#define NUM_TYPES 12 +#define NUM_TYPES 12 /**< Number of netCDF atomic types. */ + +/** @internal Native HDF5 constants for atomic types. For performance, + * fill this array only the first time, and keep it in global memory + * for each further use. */ static hid_t h5_native_type_constant_g[NUM_TYPES]; + +/** @internal NetCDF atomic type names. */ static const char nc_type_name_g[NUM_TYPES][NC_MAX_NAME + 1] = {"char", "byte", "short", - "int", "float", "double", "ubyte", - "ushort", "uint", "int64", - "uint64", "string"}; + "int", "float", "double", "ubyte", + "ushort", "uint", "int64", + "uint64", "string"}; + +/** @internal NetCDF atomic types. */ static const nc_type nc_type_constant_g[NUM_TYPES] = {NC_CHAR, NC_BYTE, NC_SHORT, - NC_INT, NC_FLOAT, NC_DOUBLE, NC_UBYTE, - NC_USHORT, NC_UINT, NC_INT64, - NC_UINT64, NC_STRING}; -static const int nc_type_size_g[NUM_TYPES] = {sizeof(char), sizeof(char), sizeof(short), - sizeof(int), sizeof(float), sizeof(double), sizeof(unsigned char), - sizeof(unsigned short), sizeof(unsigned int), sizeof(long long), - sizeof(unsigned long long), sizeof(char *)}; + NC_INT, NC_FLOAT, NC_DOUBLE, NC_UBYTE, + NC_USHORT, NC_UINT, NC_INT64, + NC_UINT64, NC_STRING}; -/* Set chunk cache size. Only affects files opened/created *after* it - * is called. */ +/** @internal NetCDF atomic type sizes. */ +static const int nc_type_size_g[NUM_TYPES] = {sizeof(char), sizeof(char), sizeof(short), + sizeof(int), sizeof(float), sizeof(double), sizeof(unsigned char), + sizeof(unsigned short), sizeof(unsigned int), sizeof(long long), + sizeof(unsigned long long), sizeof(char *)}; + +/** + * Set chunk cache size. Only affects files opened/created *after* it + * is called. + * + * @param size Size in bytes to set cache. + * @param nelems Number of elements to hold in cache. + * @param preemption Premption stragety (between 0 and 1). + * + * @return ::NC_NOERR No error. + * @return ::NC_EINVAL Bad preemption. + * @author Ed Hartnett + */ int nc_set_chunk_cache(size_t size, size_t nelems, float preemption) { @@ -214,8 +732,17 @@ nc_set_chunk_cache(size_t size, size_t nelems, float preemption) return NC_NOERR; } -/* Get chunk cache size. Only affects files opened/created *after* it - * is called. */ +/** + * Get chunk cache size. Only affects files opened/created *after* it + * is called. + * + * @param sizep Pointer that gets size in bytes to set cache. + * @param nelemsp Pointer that gets number of elements to hold in cache. + * @param preemptionp Pointer that gets premption stragety (between 0 and 1). + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ int nc_get_chunk_cache(size_t *sizep, size_t *nelemsp, float *preemptionp) { @@ -230,7 +757,17 @@ nc_get_chunk_cache(size_t *sizep, size_t *nelemsp, float *preemptionp) return NC_NOERR; } -/* Required for fortran to avoid size_t issues. */ +/** + * @internal Set the chunk cache. Required for fortran to avoid size_t + * issues. + * + * @param size Cache size. + * @param nelems Number of elements. + * @param preemption Preemption * 100. + * + * @return NC_NOERR No error. + * @author Ed Hartnett + */ int nc_set_chunk_cache_ints(int size, int nelems, int preemption) { @@ -242,6 +779,17 @@ nc_set_chunk_cache_ints(int size, int nelems, int preemption) return NC_NOERR; } +/** + * @internal Get the chunk cache settings. Required for fortran to + * avoid size_t issues. + * + * @param sizep Pointer that gets cache size. + * @param nelemsp Pointer that gets number of elements. + * @param preemptionp Pointer that gets preemption * 100. + * + * @return NC_NOERR No error. + * @author Ed Hartnett + */ int nc_get_chunk_cache_ints(int *sizep, int *nelemsp, int *preemptionp) { @@ -255,32 +803,53 @@ nc_get_chunk_cache_ints(int *sizep, int *nelemsp, int *preemptionp) return NC_NOERR; } -/* This will return the length of a netcdf data type in bytes. */ +/** + * @internal This will return the length of a netcdf data type in bytes. + * + * @param type A netcdf atomic type. + * + * @return Type size in bytes, or -1 if type not found. + * @author Ed Hartnett + */ int nc4typelen(nc_type type) { switch(type){ - case NC_BYTE: - case NC_CHAR: - case NC_UBYTE: - return 1; - case NC_USHORT: - case NC_SHORT: - return 2; - case NC_FLOAT: - case NC_INT: - case NC_UINT: - return 4; - case NC_DOUBLE: - case NC_INT64: - case NC_UINT64: - return 8; + case NC_BYTE: + case NC_CHAR: + case NC_UBYTE: + return 1; + case NC_USHORT: + case NC_SHORT: + return 2; + case NC_FLOAT: + case NC_INT: + case NC_UINT: + return 4; + case NC_DOUBLE: + case NC_INT64: + case NC_UINT64: + return 8; } return -1; } -/* Create a HDF5/netcdf-4 file. */ - +/** + * @internal Create a netCDF-4/HDF5 file. + * + * @param path The file name of the new file. + * @param cmode The creation mode flag. + * @param comm MPI communicator (parallel IO only). + * @param info MPI info (parallel IO only). + * @param nc Pointer to an instance of NC. + * + * @return ::NC_NOERR No error. + * @return ::NC_EINVAL Invalid input (check cmode). + * @return ::NC_EEXIST File exists and NC_NOCLOBBER used. + * @return ::NC_EHDFERR HDF5 returned error. + * @ingroup netcdf4 + * @author Ed Hartnett, Dennis Heimbigner + */ static int nc4_create_file(const char *path, int cmode, MPI_Comm comm, MPI_Info info, NC *nc) @@ -297,24 +866,22 @@ nc4_create_file(const char *path, int cmode, MPI_Comm comm, MPI_Info info, int persist = 0; /* Should diskless try to persist its data into file?*/ #endif - assert(nc); + assert(nc && path); + LOG((3, "%s: path %s mode 0x%x", __func__, path, cmode)); if(cmode & NC_DISKLESS) - flags = H5F_ACC_TRUNC; + flags = H5F_ACC_TRUNC; else if(cmode & NC_NOCLOBBER) - flags = H5F_ACC_EXCL; + flags = H5F_ACC_EXCL; else - flags = H5F_ACC_TRUNC; - - LOG((3, "%s: path %s mode 0x%x", __func__, path, cmode)); - assert(nc && path); + flags = H5F_ACC_TRUNC; /* If this file already exists, and NC_NOCLOBBER is specified, return an error. */ if (cmode & NC_DISKLESS) { #ifndef USE_PARALLEL4 - if(cmode & NC_WRITE) - persist = 1; + if(cmode & NC_WRITE) + persist = 1; #endif } else if ((cmode & NC_NOCLOBBER) && (fp = fopen(path, "r"))) { fclose(fp); @@ -343,16 +910,16 @@ nc4_create_file(const char *path, int cmode, MPI_Comm comm, MPI_Info info, nc4_info->parallel = NC_TRUE; if (cmode & NC_MPIIO) /* MPI/IO */ { - LOG((4, "creating parallel file with MPI/IO")); - if (H5Pset_fapl_mpio(fapl_id, comm, info) < 0) - BAIL(NC_EPARINIT); + LOG((4, "creating parallel file with MPI/IO")); + if (H5Pset_fapl_mpio(fapl_id, comm, info) < 0) + BAIL(NC_EPARINIT); } #ifdef USE_PARALLEL_POSIX else /* MPI/POSIX */ { - LOG((4, "creating parallel file with MPI/posix")); - if (H5Pset_fapl_mpiposix(fapl_id, comm, 0) < 0) - BAIL(NC_EPARINIT); + LOG((4, "creating parallel file with MPI/posix")); + if (H5Pset_fapl_mpiposix(fapl_id, comm, 0) < 0) + BAIL(NC_EPARINIT); } #else /* USE_PARALLEL_POSIX */ /* Should not happen! Code in NC4_create/NC4_open should alias the @@ -381,14 +948,14 @@ nc4_create_file(const char *path, int cmode, MPI_Comm comm, MPI_Info info, } #else /* only set cache for non-parallel... */ if(cmode & NC_DISKLESS) { - if (H5Pset_fapl_core(fapl_id, 4096, persist)) - BAIL(NC_EDISKLESS); + if (H5Pset_fapl_core(fapl_id, 4096, persist)) + BAIL(NC_EDISKLESS); } if (H5Pset_cache(fapl_id, 0, nc4_chunk_cache_nelems, nc4_chunk_cache_size, - nc4_chunk_cache_preemption) < 0) + nc4_chunk_cache_preemption) < 0) BAIL(NC_EHDFERR); LOG((4, "%s: set HDF raw chunk cache to size %d nelems %d preemption %f", - __func__, nc4_chunk_cache_size, nc4_chunk_cache_nelems, nc4_chunk_cache_preemption)); + __func__, nc4_chunk_cache_size, nc4_chunk_cache_nelems, nc4_chunk_cache_preemption)); #endif /* USE_PARALLEL4 */ #ifdef HDF5_HAS_LIBVER_BOUNDS @@ -408,10 +975,10 @@ nc4_create_file(const char *path, int cmode, MPI_Comm comm, MPI_Info info, * H5P_CRT_ORDER_TRACKED in the creation property list. This turns * on HDF5 creation ordering. */ if (H5Pset_link_creation_order(fcpl_id, (H5P_CRT_ORDER_TRACKED | - H5P_CRT_ORDER_INDEXED)) < 0) + H5P_CRT_ORDER_INDEXED)) < 0) BAIL(NC_EHDFERR); if (H5Pset_attr_creation_order(fcpl_id, (H5P_CRT_ORDER_TRACKED | - H5P_CRT_ORDER_INDEXED)) < 0) + H5P_CRT_ORDER_INDEXED)) < 0) BAIL(NC_EHDFERR); /* Create the file. */ @@ -421,13 +988,13 @@ nc4_create_file(const char *path, int cmode, MPI_Comm comm, MPI_Info info, #endif if ((nc4_info->hdfid = H5Fcreate(path, flags, fcpl_id, fapl_id)) < 0) - /*Change the return error from NC_EFILEMETADATA to - System error EACCES because that is the more likely problem */ + /*Change the return error from NC_EFILEMETADATA to + System error EACCES because that is the more likely problem */ BAIL(EACCES); /* Open the root group. */ if ((nc4_info->root_grp->hdf_grpid = H5Gopen2(nc4_info->hdfid, "/", - H5P_DEFAULT)) < 0) + H5P_DEFAULT)) < 0) BAIL(NC_EFILEMETA); /* Release the property lists. */ @@ -453,25 +1020,29 @@ nc4_create_file(const char *path, int cmode, MPI_Comm comm, MPI_Info info, return retval; } -/** \ingroup netcdf4 -Create a netCDF-4/HDF5 file. - -\param path The file name of the new file. -\param cmode The creation mode flag. -\param initialsz Ignored by this function. -\param basepe Ignored by this function. -\param chunksizehintp Ignored by this function. -\param use_parallel 0 for sequential, non-zero for parallel I/O. -\param parameters pointer to struct holding extra data (e.g. for parallel I/O) -layer. Ignored if NULL. -\param dispatch Pointer to the dispatch table for this file. -\param nc_file Pointer to an instance of NC. -\return NC_INVAL Invalid input (check cmode). -*/ +/** + * @internal Create a netCDF-4/HDF5 file. + * + * @param path The file name of the new file. + * @param cmode The creation mode flag. + * @param initialsz Ignored by this function. + * @param basepe Ignored by this function. + * @param chunksizehintp Ignored by this function. + * @param use_parallel 0 for sequential, non-zero for parallel I/O. + * @param parameters pointer to struct holding extra data (e.g. for parallel I/O) + * layer. Ignored if NULL. + * @param dispatch Pointer to the dispatch table for this file. + * @param nc_file Pointer to an instance of NC. + * + * @return ::NC_NOERR No error. + * @return ::NC_EINVAL Invalid input (check cmode). + * @ingroup netcdf4 + * @author Ed Hartnett + */ int NC4_create(const char* path, int cmode, size_t initialsz, int basepe, - size_t *chunksizehintp, int use_parallel, void *parameters, - NC_Dispatch *dispatch, NC* nc_file) + size_t *chunksizehintp, int use_parallel, void *parameters, + NC_Dispatch *dispatch, NC* nc_file) { MPI_Comm comm = MPI_COMM_WORLD; MPI_Info info = MPI_INFO_NULL; @@ -480,7 +1051,7 @@ NC4_create(const char* path, int cmode, size_t initialsz, int basepe, assert(nc_file && path); LOG((1, "%s: path %s cmode 0x%x comm %d info %d", - __func__, path, cmode, comm, info)); + __func__, path, cmode, comm, info)); #ifdef USE_PARALLEL4 if (parameters) @@ -492,19 +1063,19 @@ NC4_create(const char* path, int cmode, size_t initialsz, int basepe, /* If this is our first file, turn off HDF5 error messages. */ if (!nc4_hdf5_initialized) - nc4_hdf5_initialize(); + nc4_hdf5_initialize(); /* Check the cmode for validity. */ if((cmode & ILLEGAL_CREATE_FLAGS) != 0) - {res = NC_EINVAL; goto done;} + {res = NC_EINVAL; goto done;} /* Cannot have both */ if((cmode & (NC_MPIIO|NC_MPIPOSIX)) == (NC_MPIIO|NC_MPIPOSIX)) - {res = NC_EINVAL; goto done;} + {res = NC_EINVAL; goto done;} /* Currently no parallel diskless io */ if((cmode & (NC_MPIIO | NC_MPIPOSIX)) && (cmode & NC_DISKLESS)) - {res = NC_EINVAL; goto done;} + {res = NC_EINVAL; goto done;} #ifndef USE_PARALLEL_POSIX /* If the HDF5 library has been compiled without the MPI-POSIX VFD, alias @@ -537,15 +1108,29 @@ NC4_create(const char* path, int cmode, size_t initialsz, int basepe, return res; } -/* This function is called by read_dataset when a dimension scale - * dataset is encountered. It reads in the dimension data (creating a - * new NC_DIM_INFO_T object), and also checks to see if this is a - * dimension without a variable - that is, a coordinate dimension - * which does not have any coordinate data. */ +/** + * @internal This function is called by read_dataset when a dimension + * scale dataset is encountered. It reads in the dimension data + * (creating a new NC_DIM_INFO_T object), and also checks to see if + * this is a dimension without a variable - that is, a coordinate + * dimension which does not have any coordinate data. + * + * @param grp Pointer to group info struct. + * @param datasetid The HDF5 dataset ID. + * @param obj_name + * @param statbuf + * @param scale_size Size of dimension scale. + * @param max_scale_size Maximum size of dim scale. + * @param dim Pointer to pointer that gets new dim info struct. + * + * @returns ::NC_NOERR No error. + * @return ::NC_EHDFERR HDF5 returned error. + * @author Ed Hartnett + */ static int read_scale(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, - const H5G_stat_t *statbuf, hsize_t scale_size, hsize_t max_scale_size, - NC_DIM_INFO_T **dim) + const H5G_stat_t *statbuf, hsize_t scale_size, hsize_t max_scale_size, + NC_DIM_INFO_T **dim) { NC_DIM_INFO_T *new_dim; /* Dimension added to group */ char dimscale_name_att[NC_MAX_NAME + 1] = ""; /* Dimscale name, for checking if dim without var */ @@ -636,9 +1221,9 @@ read_scale(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, /* On error, undo any dimscale creation */ if (retval < 0 && dimscale_created) { - /* Delete the dimension */ - if ((retval = nc4_dim_list_del(&grp->dim, new_dim))) - BAIL2(retval); + /* Delete the dimension */ + if ((retval = nc4_dim_list_del(&grp->dim, new_dim))) + BAIL2(retval); /* Reset the group's information */ grp->nc4_info->next_dimid = initial_next_dimid; @@ -647,8 +1232,16 @@ read_scale(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, return retval; } -/* This function reads the hacked in coordinates attribute I use for - * multi-dimensional coordinates. */ +/** + * @internal This function reads the hacked in coordinates attribute I + * use for multi-dimensional coordinates. + * + * @param grp Group info pointer. + * @param var Var info pointer. + * + * @return NC_NOERR No error. + * @author Ed Hartnett +*/ static int read_coord_dimids(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var) { @@ -676,8 +1269,8 @@ read_coord_dimids(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var) /* Update var->dim field based on the var->dimids */ for (d = 0; d < var->ndims; d++) { - /* Ok if does not find a dim at this time, but if found set it */ - nc4_find_dim(grp, var->dimids[d], &var->dim[d], NULL); + /* Ok if does not find a dim at this time, but if found set it */ + nc4_find_dim(grp, var->dimids[d], &var->dim[d], NULL); } /* Set my HDF5 IDs free! */ @@ -687,8 +1280,18 @@ read_coord_dimids(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var) return ret ? NC_EATTMETA : NC_NOERR; } -/* This function is called when reading a file's metadata for each - * dimension scale attached to a variable.*/ +/** + * @internal This function is called when reading a file's metadata + * for each dimension scale attached to a variable. + * + * @param did HDF5 ID for dimscale. + * @param dim + * @param dsid + * @param dimscale_hdf5_objids + * + * @return 0 for success, -1 for error. + * @author Ed Hartnett +*/ static herr_t dimscale_visitor(hid_t did, unsigned dim, hid_t dsid, void *dimscale_hdf5_objids) @@ -707,126 +1310,24 @@ dimscale_visitor(hid_t did, unsigned dim, hid_t dsid, return 0; } -/* Given an HDF5 type, set a pointer to netcdf type. */ -static int -get_netcdf_type(NC_HDF5_FILE_INFO_T *h5, hid_t native_typeid, - nc_type *xtype) -{ - NC_TYPE_INFO_T *type; - H5T_class_t class; - htri_t is_str, equal = 0; - - assert(h5 && xtype); - - if ((class = H5Tget_class(native_typeid)) < 0) - return NC_EHDFERR; - - /* H5Tequal doesn't work with H5T_C_S1 for some reason. But - * H5Tget_class will return H5T_STRING if this is a string. */ - if (class == H5T_STRING) - { - if ((is_str = H5Tis_variable_str(native_typeid)) < 0) - return NC_EHDFERR; - if (is_str) - *xtype = NC_STRING; - else - *xtype = NC_CHAR; - return NC_NOERR; - } - else if (class == H5T_INTEGER || class == H5T_FLOAT) - { - /* For integers and floats, we don't have to worry about - * endianness if we compare native types. */ - if ((equal = H5Tequal(native_typeid, H5T_NATIVE_SCHAR)) < 0) - return NC_EHDFERR; - if (equal) - { - *xtype = NC_BYTE; - return NC_NOERR; - } - if ((equal = H5Tequal(native_typeid, H5T_NATIVE_SHORT)) < 0) - return NC_EHDFERR; - if (equal) - { - *xtype = NC_SHORT; - return NC_NOERR; - } - if ((equal = H5Tequal(native_typeid, H5T_NATIVE_INT)) < 0) - return NC_EHDFERR; - if (equal) - { - *xtype = NC_INT; - return NC_NOERR; - } - if ((equal = H5Tequal(native_typeid, H5T_NATIVE_FLOAT)) < 0) - return NC_EHDFERR; - if (equal) - { - *xtype = NC_FLOAT; - return NC_NOERR; - } - if ((equal = H5Tequal(native_typeid, H5T_NATIVE_DOUBLE)) < 0) - return NC_EHDFERR; - if (equal) - { - *xtype = NC_DOUBLE; - return NC_NOERR; - } - if ((equal = H5Tequal(native_typeid, H5T_NATIVE_UCHAR)) < 0) - return NC_EHDFERR; - if (equal) - { - *xtype = NC_UBYTE; - return NC_NOERR; - } - if ((equal = H5Tequal(native_typeid, H5T_NATIVE_USHORT)) < 0) - return NC_EHDFERR; - if (equal) - { - *xtype = NC_USHORT; - return NC_NOERR; - } - if ((equal = H5Tequal(native_typeid, H5T_NATIVE_UINT)) < 0) - return NC_EHDFERR; - if (equal) - { - *xtype = NC_UINT; - return NC_NOERR; - } - if ((equal = H5Tequal(native_typeid, H5T_NATIVE_LLONG)) < 0) - return NC_EHDFERR; - if (equal) - { - *xtype = NC_INT64; - return NC_NOERR; - } - if ((equal = H5Tequal(native_typeid, H5T_NATIVE_ULLONG)) < 0) - return NC_EHDFERR; - if (equal) - { - *xtype = NC_UINT64; - return NC_NOERR; - } - } - - /* Maybe we already know about this type. */ - if (!equal) - if((type = nc4_rec_find_hdf_type(h5->root_grp, native_typeid))) - { - *xtype = type->nc_typeid; - return NC_NOERR; - } - - *xtype = NC_NAT; - return NC_EBADTYPID; -} - -/* Given an HDF5 type, set a pointer to netcdf type_info struct, +/** + * @internal Given an HDF5 type, set a pointer to netcdf type_info struct, * either an existing one (for user-defined types) or a newly created - * one. */ + * one. + * + * @param h5 Pointer to HDF5 file info struct. + * @param datasetid HDF5 dataset ID. + * @param type_info Pointer to pointer that gets type info struct. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_EHDFERR HDF5 returned error. + * @return ::NC_EBADTYPID Type not found. + * @author Ed Hartnett +*/ static int get_type_info2(NC_HDF5_FILE_INFO_T *h5, hid_t datasetid, - NC_TYPE_INFO_T **type_info) + NC_TYPE_INFO_T **type_info) { htri_t is_str, equal = 0; H5T_class_t class; @@ -874,63 +1375,63 @@ get_type_info2(NC_HDF5_FILE_INFO_T *h5, hid_t datasetid, { /* Allocate a phony NC_TYPE_INFO_T struct to hold type info. */ if (!(*type_info = calloc(1, sizeof(NC_TYPE_INFO_T)))) - return NC_ENOMEM; + return NC_ENOMEM; /* H5Tequal doesn't work with H5T_C_S1 for some reason. But * H5Tget_class will return H5T_STRING if this is a string. */ if (class == H5T_STRING) { - if ((is_str = H5Tis_variable_str(native_typeid)) < 0) - return NC_EHDFERR; - /* Make sure fixed-len strings will work like variable-len strings */ - if (is_str || H5Tget_size(hdf_typeid) > 1) + if ((is_str = H5Tis_variable_str(native_typeid)) < 0) + return NC_EHDFERR; + /* Make sure fixed-len strings will work like variable-len strings */ + if (is_str || H5Tget_size(hdf_typeid) > 1) { /* Set a class for the type */ - t = NUM_TYPES - 1; + t = NUM_TYPES - 1; (*type_info)->nc_type_class = NC_STRING; } - else + else { /* Set a class for the type */ - t = 0; + t = 0; (*type_info)->nc_type_class = NC_CHAR; } } else if (class == H5T_INTEGER || class == H5T_FLOAT) { - for (t = 1; t < NUM_TYPES - 1; t++) - { - if ((equal = H5Tequal(native_typeid, h5_native_type_constant_g[t])) < 0) - return NC_EHDFERR; - if (equal) - break; - } - - /* Find out about endianness. - * As of HDF 1.8.6, this works with all data types - * Not just H5T_INTEGER. - * - * See https://www.hdfgroup.org/HDF5/doc/RM/RM_H5T.html#Datatype-GetOrder - */ - if((order = H5Tget_order(hdf_typeid)) < 0) - return NC_EHDFERR; + for (t = 1; t < NUM_TYPES - 1; t++) + { + if ((equal = H5Tequal(native_typeid, h5_native_type_constant_g[t])) < 0) + return NC_EHDFERR; + if (equal) + break; + } - if(order == H5T_ORDER_LE) - (*type_info)->endianness = NC_ENDIAN_LITTLE; - else if(order == H5T_ORDER_BE) - (*type_info)->endianness = NC_ENDIAN_BIG; - else - return NC_EBADTYPE; - - if(class == H5T_INTEGER) - (*type_info)->nc_type_class = NC_INT; - else - (*type_info)->nc_type_class = NC_FLOAT; - } + /* Find out about endianness. + * As of HDF 1.8.6, this works with all data types + * Not just H5T_INTEGER. + * + * See https://www.hdfgroup.org/HDF5/doc/RM/RM_H5T.html#Datatype-GetOrder + */ + if((order = H5Tget_order(hdf_typeid)) < 0) + return NC_EHDFERR; + + if(order == H5T_ORDER_LE) + (*type_info)->endianness = NC_ENDIAN_LITTLE; + else if(order == H5T_ORDER_BE) + (*type_info)->endianness = NC_ENDIAN_BIG; + else + return NC_EBADTYPE; + + if(class == H5T_INTEGER) + (*type_info)->nc_type_class = NC_INT; + else + (*type_info)->nc_type_class = NC_FLOAT; + } (*type_info)->nc_typeid = nc_type_constant_g[t]; (*type_info)->size = nc_type_size_g[t]; if (!((*type_info)->name = strdup(nc_type_name_g[t]))) - return NC_ENOMEM; + return NC_ENOMEM; (*type_info)->hdf_typeid = hdf_typeid; (*type_info)->native_hdf_typeid = native_typeid; return NC_NOERR; @@ -941,15 +1442,15 @@ get_type_info2(NC_HDF5_FILE_INFO_T *h5, hid_t datasetid, /* This is a user-defined type. */ if((type = nc4_rec_find_hdf_type(h5->root_grp, native_typeid))) - *type_info = type; + *type_info = type; /* The type entry in the array of user-defined types already has * an open data typeid (and native typeid), so close the ones we * opened above. */ if (H5Tclose(native_typeid) < 0) - return NC_EHDFERR; + return NC_EHDFERR; if (H5Tclose(hdf_typeid) < 0) - return NC_EHDFERR; + return NC_EHDFERR; if (type) return NC_NOERR; @@ -958,195 +1459,20 @@ get_type_info2(NC_HDF5_FILE_INFO_T *h5, hid_t datasetid, return NC_EBADTYPID; } -/* Read an attribute. */ -static int -read_hdf5_att(NC_GRP_INFO_T *grp, hid_t attid, NC_ATT_INFO_T *att) -{ - hid_t spaceid = 0, file_typeid = 0; - hsize_t dims[1] = {0}; /* netcdf attributes always 1-D. */ - int retval = NC_NOERR; - size_t type_size; - int att_ndims; - hssize_t att_npoints; - H5T_class_t att_class; - int fixed_len_string = 0; - size_t fixed_size = 0; - - assert(att->name); - LOG((5, "%s: att->attnum %d att->name %s att->nc_typeid %d att->len %d", - __func__, att->attnum, att->name, (int)att->nc_typeid, att->len)); - - /* Get type of attribute in file. */ - if ((file_typeid = H5Aget_type(attid)) < 0) - return NC_EATTMETA; - if ((att->native_hdf_typeid = H5Tget_native_type(file_typeid, H5T_DIR_DEFAULT)) < 0) - BAIL(NC_EHDFERR); - if ((att_class = H5Tget_class(att->native_hdf_typeid)) < 0) - BAIL(NC_EATTMETA); - if (att_class == H5T_STRING && !H5Tis_variable_str(att->native_hdf_typeid)) - { - fixed_len_string++; - if (!(fixed_size = H5Tget_size(att->native_hdf_typeid))) - BAIL(NC_EATTMETA); - } - if ((retval = get_netcdf_type(grp->nc4_info, att->native_hdf_typeid, &(att->nc_typeid)))) - BAIL(retval); - - - /* Get len. */ - if ((spaceid = H5Aget_space(attid)) < 0) - BAIL(NC_EATTMETA); - if ((att_ndims = H5Sget_simple_extent_ndims(spaceid)) < 0) - BAIL(NC_EATTMETA); - if ((att_npoints = H5Sget_simple_extent_npoints(spaceid)) < 0) - BAIL(NC_EATTMETA); - - /* If both att_ndims and att_npoints are zero, then this is a - * zero length att. */ - if (att_ndims == 0 && att_npoints == 0) - dims[0] = 0; - else if (att->nc_typeid == NC_STRING) - dims[0] = att_npoints; - else if (att->nc_typeid == NC_CHAR) - { - /* NC_CHAR attributes are written as a scalar in HDF5, of type - * H5T_C_S1, of variable length. */ - if (att_ndims == 0) - { - if (!(dims[0] = H5Tget_size(file_typeid))) - BAIL(NC_EATTMETA); - } - else - { - /* This is really a string type! */ - att->nc_typeid = NC_STRING; - dims[0] = att_npoints; - } - } - else - { - H5S_class_t space_class; - - /* All netcdf attributes are scalar or 1-D only. */ - if (att_ndims > 1) - BAIL(NC_EATTMETA); - - /* Check class of HDF5 dataspace */ - if ((space_class = H5Sget_simple_extent_type(spaceid)) < 0) - BAIL(NC_EATTMETA); - - /* Check for NULL HDF5 dataspace class (should be weeded out earlier) */ - if (H5S_NULL == space_class) - BAIL(NC_EATTMETA); - - /* check for SCALAR HDF5 dataspace class */ - if (H5S_SCALAR == space_class) - dims[0] = 1; - else /* Must be "simple" dataspace */ - { - /* Read the size of this attribute. */ - if (H5Sget_simple_extent_dims(spaceid, dims, NULL) < 0) - BAIL(NC_EATTMETA); - } - } - - /* Tell the user what the length if this attribute is. */ - att->len = dims[0]; - - /* Allocate some memory if the len is not zero, and read the - attribute. */ - if (dims[0]) - { - if ((retval = nc4_get_typelen_mem(grp->nc4_info, att->nc_typeid, 0, - &type_size))) - return retval; - if (att_class == H5T_VLEN) - { - if (!(att->vldata = malloc((unsigned int)(att->len * sizeof(hvl_t))))) - BAIL(NC_ENOMEM); - if (H5Aread(attid, att->native_hdf_typeid, att->vldata) < 0) - BAIL(NC_EATTMETA); - } - else if (att->nc_typeid == NC_STRING) - { - if (!(att->stdata = calloc(att->len, sizeof(char *)))) - BAIL(NC_ENOMEM); - /* For a fixed length HDF5 string, the read requires - * contiguous memory. Meanwhile, the netCDF API requires that - * nc_free_string be called on string arrays, which would not - * work if one contiguous memory block were used. So here I - * convert the contiguous block of strings into an array of - * malloced strings (each string with its own malloc). Then I - * copy the data and free the contiguous memory. This - * involves copying the data, which is bad, but this only - * occurs for fixed length string attributes, and presumably - * these are small. (And netCDF-4 does not create them - it - * always uses variable length strings. */ - if (fixed_len_string) - { - int i; - char *contig_buf, *cur; - - /* Alloc space for the contiguous memory read. */ - if (!(contig_buf = malloc(att->len * fixed_size * sizeof(char)))) - BAIL(NC_ENOMEM); - - /* Read the fixed-len strings as one big block. */ - if (H5Aread(attid, att->native_hdf_typeid, contig_buf) < 0) { - free(contig_buf); - BAIL(NC_EATTMETA); - } - - /* Copy strings, one at a time, into their new home. Alloc - space for each string. The user will later free this - space with nc_free_string. */ - cur = contig_buf; - for (i = 0; i < att->len; i++) - { - if (!(att->stdata[i] = malloc(fixed_size))) { - free(contig_buf); - BAIL(NC_ENOMEM); - } - strncpy(att->stdata[i], cur, fixed_size); - cur += fixed_size; - } - - /* Free contiguous memory buffer. */ - free(contig_buf); - } - else - { - /* Read variable-length string atts. */ - if (H5Aread(attid, att->native_hdf_typeid, att->stdata) < 0) - BAIL(NC_EATTMETA); - } - } - else - { - if (!(att->data = malloc((unsigned int)(att->len * type_size)))) - BAIL(NC_ENOMEM); - if (H5Aread(attid, att->native_hdf_typeid, att->data) < 0) - BAIL(NC_EATTMETA); - } - } - - if (H5Tclose(file_typeid) < 0) - BAIL(NC_EHDFERR); - if (H5Sclose(spaceid) < 0) - return NC_EHDFERR; - - return NC_NOERR; - - exit: - if (H5Tclose(file_typeid) < 0) - BAIL2(NC_EHDFERR); - if (spaceid > 0 && H5Sclose(spaceid) < 0) - BAIL2(NC_EHDFERR); - return retval; -} - -/* Read information about a user defined type from the HDF5 file, and - * stash it in the group's list of types. */ +/** + * @internal Read information about a user defined type from the HDF5 + * file, and stash it in the group's list of types. + * + * @param grp Pointer to group info struct. + * @param hdf_typeid HDF5 type ID. + * @param type_name Pointer that gets the type name. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_EHDFERR HDF5 returned error. + * @return ::NC_EBADTYPID Type not found. + * @author Ed Hartnett +*/ static int read_type(NC_GRP_INFO_T *grp, hid_t hdf_typeid, char *type_name) { @@ -1184,253 +1510,266 @@ read_type(NC_GRP_INFO_T *grp, hid_t hdf_typeid, char *type_name) return NC_EHDFERR; switch (class) { - case H5T_STRING: - type->nc_type_class = NC_STRING; - break; + case H5T_STRING: + type->nc_type_class = NC_STRING; + break; - case H5T_COMPOUND: - { - int nmembers; - unsigned int m; - char* member_name = NULL; + case H5T_COMPOUND: + { + int nmembers; + unsigned int m; + char* member_name = NULL; #ifdef JNA - char jna[1001]; + char jna[1001]; #endif - type->nc_type_class = NC_COMPOUND; + type->nc_type_class = NC_COMPOUND; - if ((nmembers = H5Tget_nmembers(hdf_typeid)) < 0) - return NC_EHDFERR; - LOG((5, "compound type has %d members", nmembers)); - for (m = 0; m < nmembers; m++) - { - hid_t member_hdf_typeid; - hid_t member_native_typeid; - size_t member_offset; - H5T_class_t mem_class; - nc_type member_xtype; - - - /* Get the typeid and native typeid of this member of the - * compound type. */ - if ((member_hdf_typeid = H5Tget_member_type(type->native_hdf_typeid, m)) < 0) - return NC_EHDFERR; - - if ((member_native_typeid = H5Tget_native_type(member_hdf_typeid, H5T_DIR_DEFAULT)) < 0) - return NC_EHDFERR; - - /* Get the name of the member.*/ - member_name = H5Tget_member_name(type->native_hdf_typeid, m); - if (!member_name || strlen(member_name) > NC_MAX_NAME) { - retval = NC_EBADNAME; - break; - } -#ifdef JNA - else { - strncpy(jna,member_name,1000); - member_name = jna; - } -#endif + if ((nmembers = H5Tget_nmembers(hdf_typeid)) < 0) + return NC_EHDFERR; + LOG((5, "compound type has %d members", nmembers)); + for (m = 0; m < nmembers; m++) + { + hid_t member_hdf_typeid; + hid_t member_native_typeid; + size_t member_offset; + H5T_class_t mem_class; + nc_type member_xtype; - /* Offset in bytes on *this* platform. */ - member_offset = H5Tget_member_offset(type->native_hdf_typeid, m); - - /* Get dimensional data if this member is an array of something. */ - if ((mem_class = H5Tget_class(member_hdf_typeid)) < 0) - return NC_EHDFERR; - if (mem_class == H5T_ARRAY) - { - int ndims, dim_size[NC_MAX_VAR_DIMS]; - hsize_t dims[NC_MAX_VAR_DIMS]; - int d; - - if ((ndims = H5Tget_array_ndims(member_hdf_typeid)) < 0) { - retval = NC_EHDFERR; - break; - } - if (H5Tget_array_dims(member_hdf_typeid, dims, NULL) != ndims) { - retval = NC_EHDFERR; - break; - } - for (d = 0; d < ndims; d++) - dim_size[d] = dims[d]; - - /* What is the netCDF typeid of this member? */ - if ((retval = get_netcdf_type(grp->nc4_info, H5Tget_super(member_hdf_typeid), - &member_xtype))) - break; - - /* Add this member to our list of fields in this compound type. */ - if ((retval = nc4_field_list_add(&type->u.c.field, type->u.c.num_fields++, member_name, - member_offset, H5Tget_super(member_hdf_typeid), - H5Tget_super(member_native_typeid), - member_xtype, ndims, dim_size))) - break; - } - else - { - /* What is the netCDF typeid of this member? */ - if ((retval = get_netcdf_type(grp->nc4_info, member_native_typeid, - &member_xtype))) - break; - - /* Add this member to our list of fields in this compound type. */ - if ((retval = nc4_field_list_add(&type->u.c.field, type->u.c.num_fields++, member_name, - member_offset, member_hdf_typeid, member_native_typeid, - member_xtype, 0, NULL))) - break; - } - hdf5free(member_name); - member_name = NULL; - } - hdf5free(member_name); - member_name = NULL; - if(retval) /* error exit from loop */ - return retval; + /* Get the typeid and native typeid of this member of the + * compound type. */ + if ((member_hdf_typeid = H5Tget_member_type(type->native_hdf_typeid, m)) < 0) + return NC_EHDFERR; + + if ((member_native_typeid = H5Tget_native_type(member_hdf_typeid, H5T_DIR_DEFAULT)) < 0) + return NC_EHDFERR; + + /* Get the name of the member.*/ + member_name = H5Tget_member_name(type->native_hdf_typeid, m); + if (!member_name || strlen(member_name) > NC_MAX_NAME) { + retval = NC_EBADNAME; + break; } - break; +#ifdef JNA + else { + strncpy(jna,member_name,1000); + member_name = jna; + } +#endif + + /* Offset in bytes on *this* platform. */ + member_offset = H5Tget_member_offset(type->native_hdf_typeid, m); - case H5T_VLEN: + /* Get dimensional data if this member is an array of something. */ + if ((mem_class = H5Tget_class(member_hdf_typeid)) < 0) + return NC_EHDFERR; + if (mem_class == H5T_ARRAY) { - htri_t ret; + int ndims, dim_size[NC_MAX_VAR_DIMS]; + hsize_t dims[NC_MAX_VAR_DIMS]; + int d; - /* For conveninence we allow user to pass vlens of strings - * with null terminated strings. This means strings are - * treated slightly differently by the API, although they are - * really just VLENs of characters. */ - if ((ret = H5Tis_variable_str(hdf_typeid)) < 0) - return NC_EHDFERR; - if (ret) - type->nc_type_class = NC_STRING; - else - { - hid_t base_hdf_typeid; - nc_type base_nc_type = NC_NAT; - - type->nc_type_class = NC_VLEN; - - /* Find the base type of this vlen (i.e. what is this a - * vlen of?) */ - if (!(base_hdf_typeid = H5Tget_super(native_typeid))) - return NC_EHDFERR; - - /* What size is this type? */ - if (!(type_size = H5Tget_size(base_hdf_typeid))) - return NC_EHDFERR; - - /* What is the netcdf corresponding type. */ - if ((retval = get_netcdf_type(grp->nc4_info, base_hdf_typeid, - &base_nc_type))) - return retval; - LOG((5, "base_hdf_typeid 0x%x type_size %d base_nc_type %d", - base_hdf_typeid, type_size, base_nc_type)); - - /* Remember the base types for this vlen */ - type->u.v.base_nc_typeid = base_nc_type; - type->u.v.base_hdf_typeid = base_hdf_typeid; + if ((ndims = H5Tget_array_ndims(member_hdf_typeid)) < 0) { + retval = NC_EHDFERR; + break; + } + if (H5Tget_array_dims(member_hdf_typeid, dims, NULL) != ndims) { + retval = NC_EHDFERR; + break; } + for (d = 0; d < ndims; d++) + dim_size[d] = dims[d]; + + /* What is the netCDF typeid of this member? */ + if ((retval = get_netcdf_type(grp->nc4_info, H5Tget_super(member_hdf_typeid), + &member_xtype))) + break; + + /* Add this member to our list of fields in this compound type. */ + if ((retval = nc4_field_list_add(&type->u.c.field, type->u.c.num_fields++, member_name, + member_offset, H5Tget_super(member_hdf_typeid), + H5Tget_super(member_native_typeid), + member_xtype, ndims, dim_size))) + break; + } + else + { + /* What is the netCDF typeid of this member? */ + if ((retval = get_netcdf_type(grp->nc4_info, member_native_typeid, + &member_xtype))) + break; + + /* Add this member to our list of fields in this compound type. */ + if ((retval = nc4_field_list_add(&type->u.c.field, type->u.c.num_fields++, member_name, + member_offset, member_hdf_typeid, member_native_typeid, + member_xtype, 0, NULL))) + break; } - break; - case H5T_OPAQUE: - type->nc_type_class = NC_OPAQUE; - break; + hdf5free(member_name); + member_name = NULL; + } + hdf5free(member_name); + member_name = NULL; + if(retval) /* error exit from loop */ + return retval; + } + break; - case H5T_ENUM: - { - hid_t base_hdf_typeid; - nc_type base_nc_type = NC_NAT; - void *value; - int i; - char *member_name = NULL; -#ifdef JNA - char jna[1001]; -#endif + case H5T_VLEN: + { + htri_t ret; + + /* For conveninence we allow user to pass vlens of strings + * with null terminated strings. This means strings are + * treated slightly differently by the API, although they are + * really just VLENs of characters. */ + if ((ret = H5Tis_variable_str(hdf_typeid)) < 0) + return NC_EHDFERR; + if (ret) + type->nc_type_class = NC_STRING; + else + { + hid_t base_hdf_typeid; + nc_type base_nc_type = NC_NAT; + + type->nc_type_class = NC_VLEN; + + /* Find the base type of this vlen (i.e. what is this a + * vlen of?) */ + if (!(base_hdf_typeid = H5Tget_super(native_typeid))) + return NC_EHDFERR; + + /* What size is this type? */ + if (!(type_size = H5Tget_size(base_hdf_typeid))) + return NC_EHDFERR; + + /* What is the netcdf corresponding type. */ + if ((retval = get_netcdf_type(grp->nc4_info, base_hdf_typeid, + &base_nc_type))) + return retval; + LOG((5, "base_hdf_typeid 0x%x type_size %d base_nc_type %d", + base_hdf_typeid, type_size, base_nc_type)); + + /* Remember the base types for this vlen */ + type->u.v.base_nc_typeid = base_nc_type; + type->u.v.base_hdf_typeid = base_hdf_typeid; + } + } + break; - type->nc_type_class = NC_ENUM; + case H5T_OPAQUE: + type->nc_type_class = NC_OPAQUE; + break; - /* Find the base type of this enum (i.e. what is this a - * enum of?) */ - if (!(base_hdf_typeid = H5Tget_super(hdf_typeid))) - return NC_EHDFERR; - /* What size is this type? */ - if (!(type_size = H5Tget_size(base_hdf_typeid))) - return NC_EHDFERR; - /* What is the netcdf corresponding type. */ - if ((retval = get_netcdf_type(grp->nc4_info, base_hdf_typeid, - &base_nc_type))) - return retval; - LOG((5, "base_hdf_typeid 0x%x type_size %d base_nc_type %d", - base_hdf_typeid, type_size, base_nc_type)); + case H5T_ENUM: + { + hid_t base_hdf_typeid; + nc_type base_nc_type = NC_NAT; + void *value; + int i; + char *member_name = NULL; +#ifdef JNA + char jna[1001]; +#endif - /* Remember the base types for this enum */ - type->u.e.base_nc_typeid = base_nc_type; - type->u.e.base_hdf_typeid = base_hdf_typeid; + type->nc_type_class = NC_ENUM; - /* Find out how many member are in the enum. */ - if ((type->u.e.num_members = H5Tget_nmembers(hdf_typeid)) < 0) - return NC_EHDFERR; + /* Find the base type of this enum (i.e. what is this a + * enum of?) */ + if (!(base_hdf_typeid = H5Tget_super(hdf_typeid))) + return NC_EHDFERR; + /* What size is this type? */ + if (!(type_size = H5Tget_size(base_hdf_typeid))) + return NC_EHDFERR; + /* What is the netcdf corresponding type. */ + if ((retval = get_netcdf_type(grp->nc4_info, base_hdf_typeid, + &base_nc_type))) + return retval; + LOG((5, "base_hdf_typeid 0x%x type_size %d base_nc_type %d", + base_hdf_typeid, type_size, base_nc_type)); + + /* Remember the base types for this enum */ + type->u.e.base_nc_typeid = base_nc_type; + type->u.e.base_hdf_typeid = base_hdf_typeid; + + /* Find out how many member are in the enum. */ + if ((type->u.e.num_members = H5Tget_nmembers(hdf_typeid)) < 0) + return NC_EHDFERR; - /* Allocate space for one value. */ - if (!(value = calloc(1, type_size))) - return NC_ENOMEM; + /* Allocate space for one value. */ + if (!(value = calloc(1, type_size))) + return NC_ENOMEM; - /* Read each name and value defined in the enum. */ - for (i = 0; i < type->u.e.num_members; i++) - { + /* Read each name and value defined in the enum. */ + for (i = 0; i < type->u.e.num_members; i++) + { - /* Get the name and value from HDF5. */ - if (!(member_name = H5Tget_member_name(hdf_typeid, i))) - { - retval = NC_EHDFERR; - break; - } + /* Get the name and value from HDF5. */ + if (!(member_name = H5Tget_member_name(hdf_typeid, i))) + { + retval = NC_EHDFERR; + break; + } #ifdef JNA - strncpy(jna,member_name,1000); - member_name = jna; + strncpy(jna,member_name,1000); + member_name = jna; #endif - if (strlen(member_name) > NC_MAX_NAME) - { - retval = NC_EBADNAME; - break; - } - if (H5Tget_member_value(hdf_typeid, i, value) < 0) - { - retval = NC_EHDFERR; - break; - } - - /* Insert new field into this type's list of fields. */ - if ((retval = nc4_enum_member_add(&type->u.e.enum_member, type->size, - member_name, value))) - { - break; - } + if (strlen(member_name) > NC_MAX_NAME) + { + retval = NC_EBADNAME; + break; + } + if (H5Tget_member_value(hdf_typeid, i, value) < 0) + { + retval = NC_EHDFERR; + break; + } - hdf5free(member_name); - member_name = NULL; - } - hdf5free(member_name); - member_name = NULL; - if(value) free(value); - if(retval) /* error exit from loop */ - return retval; + /* Insert new field into this type's list of fields. */ + if ((retval = nc4_enum_member_add(&type->u.e.enum_member, type->size, + member_name, value))) + { + break; } - break; - default: - LOG((0, "unknown class")); - return NC_EBADCLASS; + hdf5free(member_name); + member_name = NULL; + } + hdf5free(member_name); + member_name = NULL; + if(value) free(value); + if(retval) /* error exit from loop */ + return retval; + } + break; + + default: + LOG((0, "unknown class")); + return NC_EBADCLASS; } return retval; } -/* This function is called by read_dataset, (which is called by - * nc4_rec_read_metadata) when a netCDF variable is found in the +/** + * @internal This function is called by read_dataset(), (which is called + * by nc4_rec_read_metadata()) when a netCDF variable is found in the * file. This function reads in all the metadata about the var, - * including the attributes. */ + * including the attributes. + * + * @param grp Pointer to group info struct. + * @param datasetid HDF5 dataset ID. + * @param obj_name Name of the HDF5 object to read. + * @param ndims Number of dimensions. + * @param dim + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_EHDFERR HDF5 returned error. + * @author Ed Hartnett +*/ static int read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, size_t ndims, NC_DIM_INFO_T *dim) @@ -1440,7 +1779,6 @@ read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, int incr_id_rc = 0; /* Whether the dataset ID's ref count has been incremented */ int d; att_iter_info att_info; /* Custom iteration information */ -#define CD_NELEMS_ZLIB 1 H5Z_filter_t filter; int num_filters; unsigned int cd_values_zip[CD_NELEMS_ZLIB]; @@ -1473,9 +1811,9 @@ read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, if (var->ndims) { if (!(var->dim = calloc(var->ndims, sizeof(NC_DIM_INFO_T *)))) - BAIL(NC_ENOMEM); + BAIL(NC_ENOMEM); if (!(var->dimids = calloc(var->ndims, sizeof(int)))) - BAIL(NC_ENOMEM); + BAIL(NC_ENOMEM); } /* Get the current chunk cache settings. */ @@ -1484,7 +1822,7 @@ read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, /* Learn about current chunk cache settings. */ if ((H5Pget_chunk_cache(access_pid, &(var->chunk_cache_nelems), - &(var->chunk_cache_size), &rdcc_w0)) < 0) + &(var->chunk_cache_size), &rdcc_w0)) < 0) BAIL(NC_EHDFERR); var->chunk_cache_preemption = rdcc_w0; @@ -1492,7 +1830,7 @@ read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, * same name as a dimension. It's legal in netcdf, and requires * that the HDF5 dataset name be changed. */ if (strlen(obj_name) > strlen(NON_COORD_PREPEND) && - !strncmp(obj_name, NON_COORD_PREPEND, strlen(NON_COORD_PREPEND))) + !strncmp(obj_name, NON_COORD_PREPEND, strlen(NON_COORD_PREPEND))) { /* Allocate space for the name. */ if (!(var->name = malloc(((strlen(obj_name) - strlen(NON_COORD_PREPEND))+ 1) * sizeof(char)))) @@ -1530,7 +1868,7 @@ read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, if (H5Pget_chunk(propid, NC_MAX_VAR_DIMS, chunksize) < 0) BAIL(NC_EHDFERR); if (!(var->chunksizes = malloc(var->ndims * sizeof(size_t)))) - BAIL(NC_ENOMEM); + BAIL(NC_ENOMEM); for (d = 0; d < var->ndims; d++) var->chunksizes[d] = chunksize[d]; } @@ -1548,42 +1886,42 @@ read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, BAIL(NC_EHDFERR); switch (filter) { - case H5Z_FILTER_SHUFFLE: - var->shuffle = NC_TRUE; - break; + case H5Z_FILTER_SHUFFLE: + var->shuffle = NC_TRUE; + break; - case H5Z_FILTER_FLETCHER32: - var->fletcher32 = NC_TRUE; - break; + case H5Z_FILTER_FLETCHER32: + var->fletcher32 = NC_TRUE; + break; - case H5Z_FILTER_DEFLATE: - var->deflate = NC_TRUE; - if (cd_nelems != CD_NELEMS_ZLIB || cd_values_zip[0] > MAX_DEFLATE_LEVEL) - BAIL(NC_EHDFERR); - var->deflate_level = cd_values_zip[0]; - break; + case H5Z_FILTER_DEFLATE: + var->deflate = NC_TRUE; + if (cd_nelems != CD_NELEMS_ZLIB || cd_values_zip[0] > NC_MAX_DEFLATE_LEVEL) + BAIL(NC_EHDFERR); + var->deflate_level = cd_values_zip[0]; + break; - default: - var->filterid = filter; - var->nparams = cd_nelems; - if(cd_nelems == 0) - var->params = NULL; - else { - /* We have to re-read the parameters based on actual nparams */ - var->params = (unsigned int*)calloc(1,sizeof(unsigned int)*var->nparams); - if(var->params == NULL) - BAIL(NC_ENOMEM); - if((filter = H5Pget_filter2(propid, f, NULL, &cd_nelems, - var->params, 0, NULL, NULL)) < 0) - BAIL(NC_EHDFERR); - } - break; + default: + var->filterid = filter; + var->nparams = cd_nelems; + if(cd_nelems == 0) + var->params = NULL; + else { + /* We have to re-read the parameters based on actual nparams */ + var->params = (unsigned int*)calloc(1,sizeof(unsigned int)*var->nparams); + if(var->params == NULL) + BAIL(NC_ENOMEM); + if((filter = H5Pget_filter2(propid, f, NULL, &cd_nelems, + var->params, 0, NULL, NULL)) < 0) + BAIL(NC_EHDFERR); + } + break; } } /* Learn all about the type of this variable. */ if ((retval = get_type_info2(grp->nc4_info, datasetid, - &var->type_info))) + &var->type_info))) BAIL(retval); /* Indicate that the variable has a pointer to the type */ @@ -1599,27 +1937,27 @@ read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, /* Allocate space to hold the fill value. */ if (!var->fill_value) { - if (var->type_info->nc_type_class == NC_VLEN) - { - if (!(var->fill_value = malloc(sizeof(nc_vlen_t)))) - BAIL(NC_ENOMEM); - } - else if (var->type_info->nc_type_class == NC_STRING) - { - if (!(var->fill_value = malloc(sizeof(char *)))) - BAIL(NC_ENOMEM); - } - else - { + if (var->type_info->nc_type_class == NC_VLEN) + { + if (!(var->fill_value = malloc(sizeof(nc_vlen_t)))) + BAIL(NC_ENOMEM); + } + else if (var->type_info->nc_type_class == NC_STRING) + { + if (!(var->fill_value = malloc(sizeof(char *)))) + BAIL(NC_ENOMEM); + } + else + { assert(var->type_info->size); - if (!(var->fill_value = malloc(var->type_info->size))) - BAIL(NC_ENOMEM); - } + if (!(var->fill_value = malloc(var->type_info->size))) + BAIL(NC_ENOMEM); + } } /* Get the fill value from the HDF5 property lust. */ if (H5Pget_fill_value(propid, var->type_info->native_hdf_typeid, - var->fill_value) < 0) + var->fill_value) < 0) BAIL(NC_EHDFERR); } else @@ -1632,8 +1970,8 @@ read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, var->dimscale = NC_TRUE; if (var->ndims > 1) { - if ((retval = read_coord_dimids(grp, var))) - BAIL(retval); + if ((retval = read_coord_dimids(grp, var))) + BAIL(retval); } else { @@ -1641,7 +1979,7 @@ read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, assert(0 == strcmp(var->name, dim->name)); var->dimids[0] = dim->dimid; - var->dim[0] = dim; + var->dim[0] = dim; } dim->coord_var = var; } @@ -1686,8 +2024,9 @@ read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, att_info.var = var; att_info.grp = grp; - if ((H5Aiterate2(var->hdf_datasetid, H5_INDEX_CRT_ORDER, H5_ITER_INC, NULL, att_read_var_callbk, &att_info)) < 0) - BAIL(NC_EATTMETA); + if ((H5Aiterate2(var->hdf_datasetid, H5_INDEX_CRT_ORDER, H5_ITER_INC, NULL, + att_read_var_callbk, &att_info)) < 0) + BAIL(NC_EATTMETA); nc4_vararray_add(grp, var); @@ -1699,10 +2038,10 @@ read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, exit: if (retval) { - if (incr_id_rc && H5Idec_ref(datasetid) < 0) - BAIL2(NC_EHDFERR); - if (var && nc4_var_del(var)) - BAIL2(NC_EHDFERR); + if (incr_id_rc && H5Idec_ref(datasetid) < 0) + BAIL2(NC_EHDFERR); + if (var && nc4_var_del(var)) + BAIL2(NC_EHDFERR); } if (access_pid && H5Pclose(access_pid) < 0) BAIL2(NC_EHDFERR); @@ -1711,8 +2050,17 @@ read_var(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, return retval; } -/* This function is called by nc4_rec_read_metadata to read all the - * group level attributes (the NC_GLOBAL atts for this group). */ +/** + * @internal This function is called by nc4_rec_read_metadata to read + * all the group level attributes (the NC_GLOBAL atts for this + * group). + * + * @param grp Pointer to group info struct. + * + * @return ::NC_NOERR No error. + * @return ::NC_EHDFERR HDF5 returned error. + * @author Ed Hartnett +*/ static int read_grp_atts(NC_GRP_INFO_T *grp) { @@ -1736,14 +2084,14 @@ read_grp_atts(NC_GRP_INFO_T *grp) /* See if this a hidden, global attribute */ if(grp->nc4_info->root_grp == grp) { - const char** reserved = NC_RESERVED_ATT_LIST; - hidden = 0; - for(;*reserved;reserved++) { - if(strcmp(*reserved,obj_name)==0) { - hidden = 1; - break; - } - } + const char** reserved = NC_RESERVED_ATT_LIST; + hidden = 0; + for(;*reserved;reserved++) { + if(strcmp(*reserved,obj_name)==0) { + hidden = 1; + break; + } + } } /* This may be an attribute telling us that strict netcdf-3 @@ -1751,30 +2099,30 @@ read_grp_atts(NC_GRP_INFO_T *grp) * but not add this attribute to the metadata. It's not a user * attribute, but an internal netcdf-4 one. */ if(strcmp(obj_name, NC3_STRICT_ATT_NAME)==0) - grp->nc4_info->cmode |= NC_CLASSIC_MODEL; + grp->nc4_info->cmode |= NC_CLASSIC_MODEL; else if(!hidden) { /* Add an att struct at the end of the list, and then go to it. */ if ((retval = nc4_att_list_add(&grp->att, &att))) BAIL(retval); - /* Add the info about this attribute. */ - max_len = strlen(obj_name) > NC_MAX_NAME ? NC_MAX_NAME : strlen(obj_name); - if (!(att->name = malloc((max_len + 1) * sizeof(char)))) - BAIL(NC_ENOMEM); + /* Add the info about this attribute. */ + max_len = strlen(obj_name) > NC_MAX_NAME ? NC_MAX_NAME : strlen(obj_name); + if (!(att->name = malloc((max_len + 1) * sizeof(char)))) + BAIL(NC_ENOMEM); strncpy(att->name, obj_name, max_len); att->name[max_len] = 0; att->attnum = grp->natts++; retval = read_hdf5_att(grp, attid, att); if(retval == NC_EBADTYPID) { - if((retval = nc4_att_list_del(&grp->att, att))) - BAIL(retval); - } else if(retval) { + if((retval = nc4_att_list_del(&grp->att, att))) BAIL(retval); + } else if(retval) { + BAIL(retval); } else { - att->created = NC_TRUE; - if ((retval = nc4_find_type(grp->nc4_info, att->nc_typeid, &type))) - BAIL(retval); - } + att->created = NC_TRUE; + if ((retval = nc4_find_type(grp->nc4_info, att->nc_typeid, &type))) + BAIL(retval); + } } /* Unconditionally close the open attribute */ H5Aclose(attid); @@ -1783,17 +2131,29 @@ read_grp_atts(NC_GRP_INFO_T *grp) exit: if (attid > 0) { - if(H5Aclose(attid) < 0) - BAIL2(NC_EHDFERR); + if(H5Aclose(attid) < 0) + BAIL2(NC_EHDFERR); } return retval; } -/* This function is called when nc4_rec_read_metadata encounters an HDF5 - * dataset when reading a file. */ +/** + * @internal This function is called when nc4_rec_read_metadata + * encounters an HDF5 dataset when reading a file. + * + * @param grp Pointer to group info struct. + * @param datasetid HDF5 dataset ID. + * @param obj_name Object name. + * @param statbuf HDF5 status buffer. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_EHDFERR HDF5 returned error. + * @author Ed Hartnett +*/ static int read_dataset(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, - const H5G_stat_t *statbuf) + const H5G_stat_t *statbuf) { NC_DIM_INFO_T *dim = NULL; /* Dimension created for scales */ hid_t spaceid = 0; @@ -1830,7 +2190,7 @@ read_dataset(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, * dimension in netCDF but not a variable. (Spooky!) */ if (NULL == dim || (dim && !dim->hdf_dimscaleid)) if ((retval = read_var(grp, datasetid, obj_name, ndims, dim))) - BAIL(retval); + BAIL(retval); exit: if (spaceid && H5Sclose(spaceid) <0) @@ -1839,10 +2199,21 @@ read_dataset(NC_GRP_INFO_T *grp, hid_t datasetid, const char *obj_name, return retval; } +/** + * @internal Add callback function to list. + * + * @param head + * @param tail + * @param oinfo The object info. + * + * @return ::NC_NOERR No error. + * @return ::NC_ENOMEM Out of memory. + * @author Ed Hartnett + */ static int nc4_rec_read_metadata_cb_list_add(NC4_rec_read_metadata_obj_info_t **head, - NC4_rec_read_metadata_obj_info_t **tail, - const NC4_rec_read_metadata_obj_info_t *oinfo) + NC4_rec_read_metadata_obj_info_t **tail, + const NC4_rec_read_metadata_obj_info_t *oinfo) { NC4_rec_read_metadata_obj_info_t *new_oinfo; /* Pointer to info for object */ @@ -1855,26 +2226,38 @@ nc4_rec_read_metadata_cb_list_add(NC4_rec_read_metadata_obj_info_t **head, if (*tail) { - assert(*head); - (*tail)->next = new_oinfo; - *tail = new_oinfo; + assert(*head); + (*tail)->next = new_oinfo; + *tail = new_oinfo; } else { - assert(NULL == *head); - *head = *tail = new_oinfo; + assert(NULL == *head); + *head = *tail = new_oinfo; } return (NC_NOERR); } +/** + * @internal Callback function called from nc4_rec_read_metadata(). + * + * @param grpid HDF5 group ID. + * @param name Name of object. + * @param info Info struct for object. + * @param _op_data Pointer to data. + * + * @return ::NC_NOERR No error. + * @return H5_ITER_ERROR HDF5 error. + * @author Ed Hartnett + */ static int nc4_rec_read_metadata_cb(hid_t grpid, const char *name, const H5L_info_t *info, - void *_op_data) + void *_op_data) { - NC4_rec_read_metadata_ud_t *udata = (NC4_rec_read_metadata_ud_t *)_op_data; /* Pointer to user data for callback */ - NC4_rec_read_metadata_obj_info_t oinfo; /* Pointer to info for object */ - int retval = H5_ITER_CONT; + NC4_rec_read_metadata_ud_t *udata = (NC4_rec_read_metadata_ud_t *)_op_data; /* Pointer to user data for callback */ + NC4_rec_read_metadata_obj_info_t oinfo; /* Pointer to info for object */ + int retval = H5_ITER_CONT; /* Reset the memory for the object's info */ memset(&oinfo, 0, sizeof(oinfo)); @@ -1892,56 +2275,56 @@ nc4_rec_read_metadata_cb(hid_t grpid, const char *name, const H5L_info_t *info, /* Add object to list, for later */ switch(oinfo.statbuf.type) { - case H5G_GROUP: - LOG((3, "found group %s", oinfo.oname)); - - /* Defer descending into child group immediately, so that the types - * in the current group can be processed and be ready for use by - * vars in the child group(s). - */ - if (nc4_rec_read_metadata_cb_list_add(&udata->grps_head, &udata->grps_tail, &oinfo)) - BAIL(H5_ITER_ERROR); - break; - - case H5G_DATASET: - LOG((3, "found dataset %s", oinfo.oname)); - - /* Learn all about this dataset, which may be a dimscale - * (i.e. dimension metadata), or real data. */ - if ((retval = read_dataset(udata->grp, oinfo.oid, oinfo.oname, &oinfo.statbuf))) - { - /* Allow NC_EBADTYPID to transparently skip over datasets - * which have a datatype that netCDF-4 doesn't undertand - * (currently), but break out of iteration for other - * errors. - */ - if(NC_EBADTYPID != retval) - BAIL(H5_ITER_ERROR); - else - retval = H5_ITER_CONT; - } + case H5G_GROUP: + LOG((3, "found group %s", oinfo.oname)); - /* Close the object */ - if (H5Oclose(oinfo.oid) < 0) - BAIL(H5_ITER_ERROR); - break; + /* Defer descending into child group immediately, so that the types + * in the current group can be processed and be ready for use by + * vars in the child group(s). + */ + if (nc4_rec_read_metadata_cb_list_add(&udata->grps_head, &udata->grps_tail, &oinfo)) + BAIL(H5_ITER_ERROR); + break; - case H5G_TYPE: - LOG((3, "found datatype %s", oinfo.oname)); + case H5G_DATASET: + LOG((3, "found dataset %s", oinfo.oname)); - /* Process the named datatype */ - if (read_type(udata->grp, oinfo.oid, oinfo.oname)) + /* Learn all about this dataset, which may be a dimscale + * (i.e. dimension metadata), or real data. */ + if ((retval = read_dataset(udata->grp, oinfo.oid, oinfo.oname, &oinfo.statbuf))) + { + /* Allow NC_EBADTYPID to transparently skip over datasets + * which have a datatype that netCDF-4 doesn't undertand + * (currently), but break out of iteration for other + * errors. + */ + if(NC_EBADTYPID != retval) BAIL(H5_ITER_ERROR); + else + retval = H5_ITER_CONT; + } - /* Close the object */ - if (H5Oclose(oinfo.oid) < 0) - BAIL(H5_ITER_ERROR); - break; + /* Close the object */ + if (H5Oclose(oinfo.oid) < 0) + BAIL(H5_ITER_ERROR); + break; - default: - LOG((0, "Unknown object class %d in %s!", oinfo.statbuf.type, __func__)); + case H5G_TYPE: + LOG((3, "found datatype %s", oinfo.oname)); + + /* Process the named datatype */ + if (read_type(udata->grp, oinfo.oid, oinfo.oname)) BAIL(H5_ITER_ERROR); - } + + /* Close the object */ + if (H5Oclose(oinfo.oid) < 0) + BAIL(H5_ITER_ERROR); + break; + + default: + LOG((0, "Unknown object class %d in %s!", oinfo.statbuf.type, __func__)); + BAIL(H5_ITER_ERROR); + } exit: if (retval) @@ -1953,136 +2336,153 @@ nc4_rec_read_metadata_cb(hid_t grpid, const char *name, const H5L_info_t *info, return (retval); } -/* This is the main function to recursively read all the metadata for the file. */ -/* The links in the 'grp' are iterated over and added to the file's metadata - * information. Note that child groups are not immediately processed, but - * are deferred until all the other links in the group are handled (so that - * vars in the child groups are guaranteed to have types that they use in - * a parent group in place). +/** + * @internal This is the main function to recursively read all the + * metadata for the file. The links in the 'grp' are iterated over + * and added to the file's metadata information. Note that child + * groups are not immediately processed, but are deferred until all + * the other links in the group are handled (so that vars in the child + * groups are guaranteed to have types that they use in a parent group + * in place). + * + * @param grp Pointer to a group. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett */ static int nc4_rec_read_metadata(NC_GRP_INFO_T *grp) { - NC4_rec_read_metadata_ud_t udata; /* User data for iteration */ - NC4_rec_read_metadata_obj_info_t *oinfo; /* Pointer to info for object */ - hsize_t idx=0; - hid_t pid = 0; - unsigned crt_order_flags = 0; - H5_index_t iter_index; - int i, retval = NC_NOERR; /* everything worked! */ - - assert(grp && grp->name); - LOG((3, "%s: grp->name %s", __func__, grp->name)); - - /* Portably initialize user data for later */ - memset(&udata, 0, sizeof(udata)); - - /* Open this HDF5 group and retain its grpid. It will remain open - * with HDF5 until this file is nc_closed. */ - if (!grp->hdf_grpid) - { - if (grp->parent) - { - if ((grp->hdf_grpid = H5Gopen2(grp->parent->hdf_grpid, - grp->name, H5P_DEFAULT)) < 0) - BAIL(NC_EHDFERR); - } - else - { - if ((grp->hdf_grpid = H5Gopen2(grp->nc4_info->hdfid, - "/", H5P_DEFAULT)) < 0) - BAIL(NC_EHDFERR); - } - } - assert(grp->hdf_grpid > 0); - - /* Get the group creation flags, to check for creation ordering */ - pid = H5Gget_create_plist(grp->hdf_grpid); - H5Pget_link_creation_order(pid, &crt_order_flags); - if (H5Pclose(pid) < 0) - BAIL(NC_EHDFERR); - - /* Set the iteration index to use */ - if (crt_order_flags & H5P_CRT_ORDER_TRACKED) - iter_index = H5_INDEX_CRT_ORDER; - else - { - NC_HDF5_FILE_INFO_T *h5 = grp->nc4_info; - - /* Without creation ordering, file must be read-only. */ - if (!h5->no_write) - BAIL(NC_ECANTWRITE); - - iter_index = H5_INDEX_NAME; - } - - /* Set user data for iteration */ - udata.grp = grp; - - /* Iterate over links in this group, building lists for the types, - * datasets and groups encountered - */ - if (H5Literate(grp->hdf_grpid, iter_index, H5_ITER_INC, &idx, - nc4_rec_read_metadata_cb, (void *)&udata) < 0) - BAIL(NC_EHDFERR); - - /* Process the child groups found */ - /* (Deferred until now, so that the types in the current group get - * processed and are available for vars in the child group(s).) - */ - for (oinfo = udata.grps_head; oinfo; oinfo = udata.grps_head) - { - NC_GRP_INFO_T *child_grp; - NC_HDF5_FILE_INFO_T *h5 = grp->nc4_info; - - /* Add group to file's hierarchy */ - if ((retval = nc4_grp_list_add(&(grp->children), h5->next_nc_grpid++, - grp, grp->nc4_info->controller, oinfo->oname, &child_grp))) - BAIL(retval); + NC4_rec_read_metadata_ud_t udata; /* User data for iteration */ + NC4_rec_read_metadata_obj_info_t *oinfo; /* Pointer to info for object */ + hsize_t idx=0; + hid_t pid = 0; + unsigned crt_order_flags = 0; + H5_index_t iter_index; + int i, retval = NC_NOERR; /* everything worked! */ + + assert(grp && grp->name); + LOG((3, "%s: grp->name %s", __func__, grp->name)); + + /* Portably initialize user data for later */ + memset(&udata, 0, sizeof(udata)); + + /* Open this HDF5 group and retain its grpid. It will remain open + * with HDF5 until this file is nc_closed. */ + if (!grp->hdf_grpid) + { + if (grp->parent) + { + if ((grp->hdf_grpid = H5Gopen2(grp->parent->hdf_grpid, + grp->name, H5P_DEFAULT)) < 0) + BAIL(NC_EHDFERR); + } + else + { + if ((grp->hdf_grpid = H5Gopen2(grp->nc4_info->hdfid, + "/", H5P_DEFAULT)) < 0) + BAIL(NC_EHDFERR); + } + } + assert(grp->hdf_grpid > 0); - /* Recursively read the child group's metadata */ - if ((retval = nc4_rec_read_metadata(child_grp))) - BAIL(retval); + /* Get the group creation flags, to check for creation ordering */ + pid = H5Gget_create_plist(grp->hdf_grpid); + H5Pget_link_creation_order(pid, &crt_order_flags); + if (H5Pclose(pid) < 0) + BAIL(NC_EHDFERR); + + /* Set the iteration index to use */ + if (crt_order_flags & H5P_CRT_ORDER_TRACKED) + iter_index = H5_INDEX_CRT_ORDER; + else + { + NC_HDF5_FILE_INFO_T *h5 = grp->nc4_info; + + /* Without creation ordering, file must be read-only. */ + if (!h5->no_write) + BAIL(NC_ECANTWRITE); + + iter_index = H5_INDEX_NAME; + } + + /* Set user data for iteration */ + udata.grp = grp; + + /* Iterate over links in this group, building lists for the types, + * datasets and groups encountered + */ + if (H5Literate(grp->hdf_grpid, iter_index, H5_ITER_INC, &idx, + nc4_rec_read_metadata_cb, (void *)&udata) < 0) + BAIL(NC_EHDFERR); - /* Close the object */ - if (H5Oclose(oinfo->oid) < 0) - BAIL(NC_EHDFERR); + /* Process the child groups found */ + /* (Deferred until now, so that the types in the current group get + * processed and are available for vars in the child group(s).) + */ + for (oinfo = udata.grps_head; oinfo; oinfo = udata.grps_head) + { + NC_GRP_INFO_T *child_grp; + NC_HDF5_FILE_INFO_T *h5 = grp->nc4_info; + + /* Add group to file's hierarchy */ + if ((retval = nc4_grp_list_add(&(grp->children), h5->next_nc_grpid++, + grp, grp->nc4_info->controller, oinfo->oname, &child_grp))) + BAIL(retval); + + /* Recursively read the child group's metadata */ + if ((retval = nc4_rec_read_metadata(child_grp))) + BAIL(retval); + + /* Close the object */ + if (H5Oclose(oinfo->oid) < 0) + BAIL(NC_EHDFERR); - /* Advance to next node, free current node */ - udata.grps_head = oinfo->next; - free(oinfo); - } + /* Advance to next node, free current node */ + udata.grps_head = oinfo->next; + free(oinfo); + } - /* Scan the group for global (i.e. group-level) attributes. */ - if ((retval = read_grp_atts(grp))) - BAIL(retval); + /* Scan the group for global (i.e. group-level) attributes. */ + if ((retval = read_grp_atts(grp))) + BAIL(retval); /* when exiting define mode, mark all variable written */ for (i=0; ivars.nelems; i++) grp->vars.value[i]->written_to = NC_TRUE; exit: - /* Clean up local information on error, if anything remains */ - if (retval) - { - for (oinfo = udata.grps_head; oinfo; oinfo = udata.grps_head) - { - /* Close the object */ - if (H5Oclose(oinfo->oid) < 0) - BAIL2(NC_EHDFERR); - - /* Advance to next node, free current node */ - udata.grps_head = oinfo->next; - free(oinfo); - } - } - - return retval; + /* Clean up local information on error, if anything remains */ + if (retval) + { + for (oinfo = udata.grps_head; oinfo; oinfo = udata.grps_head) + { + /* Close the object */ + if (H5Oclose(oinfo->oid) < 0) + BAIL2(NC_EHDFERR); + + /* Advance to next node, free current node */ + udata.grps_head = oinfo->next; + free(oinfo); + } + } + + return retval; } -/* Open a netcdf-4 file. Things have already been kicked off in - * ncfunc.c in nc_open, but here the netCDF-4 part of opening a file - * is handled. */ +/** + * @internal Open a netcdf-4 file. Things have already been kicked off + * in ncfunc.c in nc_open, but here the netCDF-4 part of opening a + * file is handled. + * + * @param path The file name of the new file. + * @param mode The open mode flag. + * @param parameters File parameters. + * @param nc Pointer to NC file info. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett, Dennis Heimbigner +*/ static int nc4_open_file(const char *path, int mode, void* parameters, NC *nc) { @@ -2125,16 +2525,16 @@ nc4_open_file(const char *path, int mode, void* parameters, NC *nc) nc4_info->parallel = NC_TRUE; if (mode & NC_MPIIO) /* MPI/IO */ { - LOG((4, "opening parallel file with MPI/IO")); - if (H5Pset_fapl_mpio(fapl_id, mpiinfo->comm, mpiinfo->info) < 0) - BAIL(NC_EPARINIT); + LOG((4, "opening parallel file with MPI/IO")); + if (H5Pset_fapl_mpio(fapl_id, mpiinfo->comm, mpiinfo->info) < 0) + BAIL(NC_EPARINIT); } #ifdef USE_PARALLEL_POSIX else /* MPI/POSIX */ { - LOG((4, "opening parallel file with MPI/posix")); - if (H5Pset_fapl_mpiposix(fapl_id, mpiinfo->comm, 0) < 0) - BAIL(NC_EPARINIT); + LOG((4, "opening parallel file with MPI/posix")); + if (H5Pset_fapl_mpiposix(fapl_id, mpiinfo->comm, 0) < 0) + BAIL(NC_EPARINIT); } #else /* USE_PARALLEL_POSIX */ /* Should not happen! Code in NC4_create/NC4_open should alias the @@ -2163,10 +2563,10 @@ nc4_open_file(const char *path, int mode, void* parameters, NC *nc) } #else /* only set cache for non-parallel. */ if (H5Pset_cache(fapl_id, 0, nc4_chunk_cache_nelems, nc4_chunk_cache_size, - nc4_chunk_cache_preemption) < 0) + nc4_chunk_cache_preemption) < 0) BAIL(NC_EHDFERR); LOG((4, "%s: set HDF raw chunk cache to size %d nelems %d preemption %f", - __func__, nc4_chunk_cache_size, nc4_chunk_cache_nelems, nc4_chunk_cache_preemption)); + __func__, nc4_chunk_cache_size, nc4_chunk_cache_nelems, nc4_chunk_cache_preemption)); #endif /* USE_PARALLEL4 */ /* The NetCDF-3.x prototype contains an mode option NC_SHARE for @@ -2176,11 +2576,11 @@ nc4_open_file(const char *path, int mode, void* parameters, NC *nc) H5Pset_all_coll_metadata_ops(fapl_id, 1 ); #endif if(inmemory) { - if((nc4_info->hdfid = H5LTopen_file_image(meminfo->memory,meminfo->size, - H5LT_FILE_IMAGE_DONT_COPY|H5LT_FILE_IMAGE_DONT_RELEASE - )) < 0) - BAIL(NC_EHDFERR); - nc4_info->no_write = NC_TRUE; + if((nc4_info->hdfid = H5LTopen_file_image(meminfo->memory,meminfo->size, + H5LT_FILE_IMAGE_DONT_COPY|H5LT_FILE_IMAGE_DONT_RELEASE + )) < 0) + BAIL(NC_EHDFERR); + nc4_info->no_write = NC_TRUE; } else if ((nc4_info->hdfid = H5Fopen(path, flags, fapl_id)) < 0) BAIL(NC_EHDFERR); @@ -2226,22 +2626,23 @@ nc4_open_file(const char *path, int mode, void* parameters, NC *nc) } #ifdef USE_HDF4 -/*! Given an HDF4 type, set a pointer to netcdf type. +/** + * @internal Given an HDF4 type, set a pointer to netcdf type. * - * Given an HDF4 type, set a pointer to a netcdf type. * See http://www.hdfgroup.org/training/HDFtraining/UsersGuide/Fundmtls.fm3.html * for more information re: HDF4 types. * - * \param NC_HDF5_FILE_INFO_T* Pointer to h5 - * \param int32 TypeID for hdf4 datatype. - * \param nc_type* Pointer to netcdf type, where result will be stored. - * \param NC_TYPE_INFO_T* (Optiona) Type info for the variable. - * \return Error code, 0 on success. + * @param h5 Pointer to HDF5 file info struct. + * @param hdf4_typeid Type ID for hdf4 datatype. + * @param xtype Pointer to netcdf type, where result will be stored. + * @param type_info Pointer to type info for the variable. * + * @return ::NC_NOERR No error. + * @author Ed Hartnett */ static int get_netcdf_type_from_hdf4(NC_HDF5_FILE_INFO_T *h5, int32 hdf4_typeid, - nc_type *xtype, NC_TYPE_INFO_T *type_info) + nc_type *xtype, NC_TYPE_INFO_T *type_info) { int t = 0; @@ -2251,116 +2652,125 @@ get_netcdf_type_from_hdf4(NC_HDF5_FILE_INFO_T *h5, int32 hdf4_typeid, * Not sure why it wouldn't be NC_ENDIAN_NATIVE, although * I can hazard a guess or two. */ - int endianness = NC_ENDIAN_BIG; assert(h5 && xtype); switch(hdf4_typeid) { case DFNT_CHAR: - *xtype = NC_CHAR; - t = 0; - break; + *xtype = NC_CHAR; + t = 0; + break; case DFNT_UCHAR: case DFNT_UINT8: - *xtype = NC_UBYTE; - t = 6; - break; + *xtype = NC_UBYTE; + t = 6; + break; case DFNT_LUINT8: - *xtype = NC_UBYTE; - t = 6; - endianness = NC_ENDIAN_LITTLE; - break; + *xtype = NC_UBYTE; + t = 6; + endianness = NC_ENDIAN_LITTLE; + break; case DFNT_INT8: - *xtype = NC_BYTE; - t = 1; - break; + *xtype = NC_BYTE; + t = 1; + break; case DFNT_LINT8: - *xtype = NC_BYTE; - t = 1; - endianness = NC_ENDIAN_LITTLE; - break; + *xtype = NC_BYTE; + t = 1; + endianness = NC_ENDIAN_LITTLE; + break; case DFNT_INT16: - *xtype = NC_SHORT; - t = 2; - break; + *xtype = NC_SHORT; + t = 2; + break; case DFNT_LINT16: - *xtype = NC_SHORT; - t = 2; - endianness = NC_ENDIAN_LITTLE; - break; + *xtype = NC_SHORT; + t = 2; + endianness = NC_ENDIAN_LITTLE; + break; case DFNT_UINT16: - *xtype = NC_USHORT; - t = 7; - break; + *xtype = NC_USHORT; + t = 7; + break; case DFNT_LUINT16: - *xtype = NC_USHORT; - t = 7; - endianness = NC_ENDIAN_LITTLE; - break; + *xtype = NC_USHORT; + t = 7; + endianness = NC_ENDIAN_LITTLE; + break; case DFNT_INT32: - *xtype = NC_INT; - t = 3; - break; + *xtype = NC_INT; + t = 3; + break; case DFNT_LINT32: - *xtype = NC_INT; - t = 3; - endianness = NC_ENDIAN_LITTLE; - break; + *xtype = NC_INT; + t = 3; + endianness = NC_ENDIAN_LITTLE; + break; case DFNT_UINT32: - *xtype = NC_UINT; - t = 8; - break; + *xtype = NC_UINT; + t = 8; + break; case DFNT_LUINT32: - *xtype = NC_UINT; - t = 8; - endianness = NC_ENDIAN_LITTLE; - break; + *xtype = NC_UINT; + t = 8; + endianness = NC_ENDIAN_LITTLE; + break; case DFNT_FLOAT32: - *xtype = NC_FLOAT; - t = 4; - break; + *xtype = NC_FLOAT; + t = 4; + break; case DFNT_LFLOAT32: - *xtype = NC_FLOAT; - t = 4; - endianness = NC_ENDIAN_LITTLE; - break; + *xtype = NC_FLOAT; + t = 4; + endianness = NC_ENDIAN_LITTLE; + break; case DFNT_FLOAT64: - *xtype = NC_DOUBLE; - t = 5; - break; + *xtype = NC_DOUBLE; + t = 5; + break; case DFNT_LFLOAT64: - *xtype = NC_DOUBLE; - t = 5; - endianness = NC_ENDIAN_LITTLE; - break; + *xtype = NC_DOUBLE; + t = 5; + endianness = NC_ENDIAN_LITTLE; + break; default: - *xtype = NC_NAT; - return NC_EBADTYPID; + *xtype = NC_NAT; + return NC_EBADTYPID; } if (type_info) { if (hdf4_typeid == DFNT_FLOAT32) - type_info->nc_type_class = NC_FLOAT; + type_info->nc_type_class = NC_FLOAT; else if (hdf4_typeid == DFNT_FLOAT64) - type_info->nc_type_class = NC_DOUBLE; + type_info->nc_type_class = NC_DOUBLE; else if (hdf4_typeid == DFNT_CHAR) - type_info->nc_type_class = NC_STRING; + type_info->nc_type_class = NC_STRING; else - type_info->nc_type_class = NC_INT; + type_info->nc_type_class = NC_INT; type_info->endianness = endianness; type_info->nc_typeid = *xtype; type_info->size = nc_type_size_g[t]; if (!(type_info->name = strdup(nc_type_name_g[t]))) - return NC_ENOMEM; + return NC_ENOMEM; } return NC_NOERR; } -/* Open a HDF4 file. Things have already been kicked off in nc_open, - * but here the netCDF-4 part of opening a file is handled. */ +/** + * @internal Open a HDF4 file. Things have already been kicked off in + * nc_open, but here the netCDF-4 part of opening a file is + * handled. + * + * @param path The file name of the new file. + * @param mode The open mode flag. + * @param nc Pointer that gets the NC file info struct. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett +*/ static int nc4_open_hdf4_file(const char *path, int mode, NC *nc) { @@ -2406,29 +2816,29 @@ nc4_open_hdf4_file(const char *path, int mode, NC *nc) /* Add to the end of the list of atts for this var. */ if ((retval = nc4_att_list_add(&h5->root_grp->att, &att))) - return retval; + return retval; att->attnum = grp->natts++; att->created = NC_TRUE; /* Learn about this attribute. */ if (!(att->name = malloc(NC_MAX_HDF4_NAME * sizeof(char)))) - return NC_ENOMEM; + return NC_ENOMEM; if (SDattrinfo(h5->sdid, a, att->name, &att_data_type, &att_count)) - return NC_EATTMETA; + return NC_EATTMETA; if ((retval = get_netcdf_type_from_hdf4(h5, att_data_type, - &att->nc_typeid, NULL))) - return retval; + &att->nc_typeid, NULL))) + return retval; att->len = att_count; /* Allocate memory to hold the data. */ if ((retval = nc4_get_typelen_mem(h5, att->nc_typeid, 0, &att_type_size))) - return retval; + return retval; if (!(att->data = malloc(att_type_size * att->len))) - return NC_ENOMEM; + return NC_ENOMEM; /* Read the data. */ if (SDreadattr(h5->sdid, a, att->data)) - return NC_EHDFERR; + return NC_EHDFERR; } /* Read each dataset. */ @@ -2437,12 +2847,12 @@ nc4_open_hdf4_file(const char *path, int mode, NC *nc) NC_VAR_INFO_T *var; int32 data_type, num_atts; /* Problem: Number of dims is returned by the call that requires - a pre-allocated array, 'dimsize'. - From SDS_SD website: - http://www.hdfgroup.org/training/HDFtraining/UsersGuide/SDS_SD.fm3.html - The maximum rank is 32, or MAX_VAR_DIMS (as defined in netcdf.h). + a pre-allocated array, 'dimsize'. + From SDS_SD website: + http://www.hdfgroup.org/training/HDFtraining/UsersGuide/SDS_SD.fm3.html + The maximum rank is 32, or MAX_VAR_DIMS (as defined in netcdf.h). - int32 dimsize[MAX_VAR_DIMS]; + int32 dimsize[MAX_VAR_DIMS]; */ int32 *dimsize = NULL; size_t var_type_size; @@ -2450,7 +2860,7 @@ nc4_open_hdf4_file(const char *path, int mode, NC *nc) /* Add a variable. */ if ((retval = nc4_var_add(&var))) - return retval; + return retval; var->varid = grp->nvars++; var->created = NC_TRUE; @@ -2460,24 +2870,24 @@ nc4_open_hdf4_file(const char *path, int mode, NC *nc) /* Open this dataset in HDF4 file. */ if ((var->sdsid = SDselect(h5->sdid, v)) == FAIL) - return NC_EVARMETA; + return NC_EVARMETA; /* Get shape, name, type, and attribute info about this dataset. */ if (!(var->name = malloc(NC_MAX_HDF4_NAME + 1))) - return NC_ENOMEM; + return NC_ENOMEM; /* Invoke SDgetInfo with null dimsize to get rank. */ if (SDgetinfo(var->sdsid, var->name, &rank, NULL, &data_type, &num_atts)) - return NC_EVARMETA; + return NC_EVARMETA; var->hash = hash_fast(var->name, strlen(var->name)); if(!(dimsize = (int32*)malloc(sizeof(int32)*rank))) - return NC_ENOMEM; + return NC_ENOMEM; if (SDgetinfo(var->sdsid, var->name, &rank, dimsize, &data_type, &num_atts)) { - if(dimsize) free(dimsize); - return NC_EVARMETA; + if(dimsize) free(dimsize); + return NC_EVARMETA; } var->ndims = rank; @@ -2485,168 +2895,168 @@ nc4_open_hdf4_file(const char *path, int mode, NC *nc) /* Fill special type_info struct for variable type information. */ if (!(var->type_info = calloc(1, sizeof(NC_TYPE_INFO_T)))) { - if(dimsize) free(dimsize); - return NC_ENOMEM; + if(dimsize) free(dimsize); + return NC_ENOMEM; } if ((retval = get_netcdf_type_from_hdf4(h5, data_type, &var->type_info->nc_typeid, var->type_info))) { - if(dimsize) free(dimsize); - return retval; + if(dimsize) free(dimsize); + return retval; } /* Indicate that the variable has a pointer to the type */ var->type_info->rc++; if ((retval = nc4_get_typelen_mem(h5, var->type_info->nc_typeid, 0, &var_type_size))) { - if(dimsize) free(dimsize); - return retval; + if(dimsize) free(dimsize); + return retval; } var->type_info->size = var_type_size; LOG((3, "reading HDF4 dataset %s, rank %d netCDF type %d", var->name, - rank, var->type_info->nc_typeid)); + rank, var->type_info->nc_typeid)); /* Get the fill value. */ if (!(var->fill_value = malloc(var_type_size))) { - if(dimsize) free(dimsize); - return NC_ENOMEM; + if(dimsize) free(dimsize); + return NC_ENOMEM; } if (SDgetfillvalue(var->sdsid, var->fill_value)) { - /* Whoops! No fill value! */ - free(var->fill_value); - var->fill_value = NULL; + /* Whoops! No fill value! */ + free(var->fill_value); + var->fill_value = NULL; } /* Allocate storage for dimension info in this variable. */ if (var->ndims) { - if (!(var->dim = malloc(sizeof(NC_DIM_INFO_T *) * var->ndims))) { - if(dimsize) free(dimsize); - return NC_ENOMEM; - } - - if (!(var->dimids = malloc(sizeof(int) * var->ndims))) { - if(dimsize) free(dimsize); - return NC_ENOMEM; - } + if (!(var->dim = malloc(sizeof(NC_DIM_INFO_T *) * var->ndims))) { + if(dimsize) free(dimsize); + return NC_ENOMEM; + } + + if (!(var->dimids = malloc(sizeof(int) * var->ndims))) { + if(dimsize) free(dimsize); + return NC_ENOMEM; + } } /* Find its dimensions. */ for (d = 0; d < var->ndims; d++) { - int32 dimid, dim_len, dim_data_type, dim_num_attrs; - char dim_name[NC_MAX_NAME + 1]; - NC_DIM_INFO_T *dim; - - if ((dimid = SDgetdimid(var->sdsid, d)) == FAIL) { - if(dimsize) free(dimsize); - return NC_EDIMMETA; - } - if (SDdiminfo(dimid, dim_name, &dim_len, &dim_data_type, - &dim_num_attrs)) - { - if(dimsize) free(dimsize); - return NC_EDIMMETA; - } - - /* Do we already have this dimension? HDF4 explicitly uses - * the name to tell. */ - for (dim = grp->dim; dim; dim = dim->l.next) - if (!strcmp(dim->name, dim_name)) - break; - - /* If we didn't find this dimension, add one. */ - if (!dim) - { - LOG((4, "adding dimension %s for HDF4 dataset %s", - dim_name, var->name)); - if ((retval = nc4_dim_list_add(&grp->dim, &dim))) - return retval; - dim->dimid = grp->nc4_info->next_dimid++; - if (strlen(dim_name) > NC_MAX_HDF4_NAME) - return NC_EMAXNAME; - if (!(dim->name = strdup(dim_name))) - return NC_ENOMEM; - if (dim_len) - dim->len = dim_len; - else - dim->len = *dimsize; - dim->hash = hash_fast(dim_name, strlen(dim_name)); - } - - /* Tell the variable the id of this dimension. */ - var->dimids[d] = dim->dimid; - var->dim[d] = dim; + int32 dimid, dim_len, dim_data_type, dim_num_attrs; + char dim_name[NC_MAX_NAME + 1]; + NC_DIM_INFO_T *dim; + + if ((dimid = SDgetdimid(var->sdsid, d)) == FAIL) { + if(dimsize) free(dimsize); + return NC_EDIMMETA; + } + if (SDdiminfo(dimid, dim_name, &dim_len, &dim_data_type, + &dim_num_attrs)) + { + if(dimsize) free(dimsize); + return NC_EDIMMETA; + } + + /* Do we already have this dimension? HDF4 explicitly uses + * the name to tell. */ + for (dim = grp->dim; dim; dim = dim->l.next) + if (!strcmp(dim->name, dim_name)) + break; + + /* If we didn't find this dimension, add one. */ + if (!dim) + { + LOG((4, "adding dimension %s for HDF4 dataset %s", + dim_name, var->name)); + if ((retval = nc4_dim_list_add(&grp->dim, &dim))) + return retval; + dim->dimid = grp->nc4_info->next_dimid++; + if (strlen(dim_name) > NC_MAX_HDF4_NAME) + return NC_EMAXNAME; + if (!(dim->name = strdup(dim_name))) + return NC_ENOMEM; + if (dim_len) + dim->len = dim_len; + else + dim->len = *dimsize; + dim->hash = hash_fast(dim_name, strlen(dim_name)); + } + + /* Tell the variable the id of this dimension. */ + var->dimids[d] = dim->dimid; + var->dim[d] = dim; } /* Read the atts. */ for (a = 0; a < num_atts; a++) { - int32 att_data_type, att_count; - size_t att_type_size; + int32 att_data_type, att_count; + size_t att_type_size; - /* Add to the end of the list of atts for this var. */ + /* Add to the end of the list of atts for this var. */ if ((retval = nc4_att_list_add(&var->att, &att))) { - if(dimsize) free(dimsize); - return retval; - } - att->attnum = var->natts++; - att->created = NC_TRUE; - - /* Learn about this attribute. */ - if (!(att->name = malloc(NC_MAX_HDF4_NAME * sizeof(char)))) { - if(dimsize) free(dimsize); - return NC_ENOMEM; - } - if (SDattrinfo(var->sdsid, a, att->name, &att_data_type, &att_count)) { - if(dimsize) free(dimsize); - return NC_EATTMETA; - } - if ((retval = get_netcdf_type_from_hdf4(h5, att_data_type, - &att->nc_typeid, NULL))) { - if(dimsize) free(dimsize); - return retval; - } - - att->len = att_count; - - /* Allocate memory to hold the data. */ - if ((retval = nc4_get_typelen_mem(h5, att->nc_typeid, 0, &att_type_size))) { - if(dimsize) free(dimsize); - return retval; - } - if (!(att->data = malloc(att_type_size * att->len))) { - if(dimsize) free(dimsize); - return NC_ENOMEM; - } - - /* Read the data. */ - if (SDreadattr(var->sdsid, a, att->data)) { - if(dimsize) free(dimsize); - return NC_EHDFERR; - } + if(dimsize) free(dimsize); + return retval; + } + att->attnum = var->natts++; + att->created = NC_TRUE; + + /* Learn about this attribute. */ + if (!(att->name = malloc(NC_MAX_HDF4_NAME * sizeof(char)))) { + if(dimsize) free(dimsize); + return NC_ENOMEM; + } + if (SDattrinfo(var->sdsid, a, att->name, &att_data_type, &att_count)) { + if(dimsize) free(dimsize); + return NC_EATTMETA; + } + if ((retval = get_netcdf_type_from_hdf4(h5, att_data_type, + &att->nc_typeid, NULL))) { + if(dimsize) free(dimsize); + return retval; + } + + att->len = att_count; + + /* Allocate memory to hold the data. */ + if ((retval = nc4_get_typelen_mem(h5, att->nc_typeid, 0, &att_type_size))) { + if(dimsize) free(dimsize); + return retval; + } + if (!(att->data = malloc(att_type_size * att->len))) { + if(dimsize) free(dimsize); + return NC_ENOMEM; + } + + /* Read the data. */ + if (SDreadattr(var->sdsid, a, att->data)) { + if(dimsize) free(dimsize); + return NC_EHDFERR; + } } if(dimsize) free(dimsize); { - /* HDF4 files can be chunked */ - HDF_CHUNK_DEF chunkdefs; - int flag; - if(!SDgetchunkinfo(var->sdsid, &chunkdefs, &flag)) { - if(flag == HDF_NONE) - var->contiguous = NC_TRUE; + /* HDF4 files can be chunked */ + HDF_CHUNK_DEF chunkdefs; + int flag; + if(!SDgetchunkinfo(var->sdsid, &chunkdefs, &flag)) { + if(flag == HDF_NONE) + var->contiguous = NC_TRUE; else if((flag & HDF_CHUNK) != 0) { - var->contiguous = NC_FALSE; - if (!(var->chunksizes = malloc(var->ndims * sizeof(size_t)))) - return NC_ENOMEM; - for (d = 0; d < var->ndims; d++) { - var->chunksizes[d] = chunkdefs.chunk_lengths[d]; - } - } - } + var->contiguous = NC_FALSE; + if (!(var->chunksizes = malloc(var->ndims * sizeof(size_t)))) + return NC_ENOMEM; + for (d = 0; d < var->ndims; d++) { + var->chunksizes[d] = chunkdefs.chunk_lengths[d]; + } + } + } } } /* next var */ @@ -2657,13 +3067,28 @@ nc4_open_hdf4_file(const char *path, int mode, NC *nc) log_metadata_nc(h5->root_grp->nc4_info->controller); #endif return NC_NOERR; - return NC_ENOTBUILT; } #endif /* USE_HDF4 */ +/** + * @internal Open a netCDF-4 file. + * + * @param path The file name of the new file. + * @param mode The open mode flag. + * @param basepe Ignored by this function. + * @param chunksizehintp Ignored by this function. + * @param use_parallel 0 for sequential, non-zero for parallel I/O. + * @param parameters pointer to struct holding extra data (e.g. for parallel I/O) + * layer. Ignored if NULL. + * @param dispatch Pointer to the dispatch table for this file. + * @param nc_file Pointer to an instance of NC. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ int NC4_open(const char *path, int mode, int basepe, size_t *chunksizehintp, - int use_parallel, void *parameters, NC_Dispatch *dispatch, NC *nc_file) + int use_parallel, void *parameters, NC_Dispatch *dispatch, NC *nc_file) { int res; int is_hdf5_file = 0; @@ -2680,24 +3105,24 @@ NC4_open(const char *path, int mode, int basepe, size_t *chunksizehintp, assert(nc_file && path); LOG((1, "%s: path %s mode %d params %x", - __func__, path, mode, parameters)); + __func__, path, mode, parameters)); #ifdef USE_PARALLEL4 if (!inmemory && use_parallel && parameters == NULL) - parameters = &mpidfalt; + parameters = &mpidfalt; #endif /* USE_PARALLEL4 */ /* If this is our first file, initialize HDF5. */ if (!nc4_hdf5_initialized) - nc4_hdf5_initialize(); + nc4_hdf5_initialize(); /* Check the mode for validity */ if((mode & ILLEGAL_OPEN_FLAGS) != 0) - {res = NC_EINVAL; goto done;} + {res = NC_EINVAL; goto done;} /* Cannot have both */ if((mode & (NC_MPIIO|NC_MPIPOSIX)) == (NC_MPIIO|NC_MPIPOSIX)) - {res = NC_EINVAL; goto done;} + {res = NC_EINVAL; goto done;} #ifndef USE_PARALLEL_POSIX /* If the HDF5 library has been compiled without the MPI-POSIX VFD, alias @@ -2712,33 +3137,41 @@ NC4_open(const char *path, int mode, int basepe, size_t *chunksizehintp, /* Figure out if this is a hdf4 or hdf5 file. */ if(nc_file->model == NC_FORMATX_NC4) - is_hdf5_file = 1; + is_hdf5_file = 1; #ifdef USE_HDF4 else if(nc_file->model == NC_FORMATX_NC_HDF4) - is_hdf4_file = 1; + is_hdf4_file = 1; #endif /* USE_HDF4 */ /* Depending on the type of file, open it. */ nc_file->int_ncid = nc_file->ext_ncid; if (is_hdf5_file) - res = nc4_open_file(path, mode, parameters, nc_file); + res = nc4_open_file(path, mode, parameters, nc_file); #ifdef USE_HDF4 else if (is_hdf4_file && inmemory) - {res = NC_EDISKLESS; goto done;} + {res = NC_EDISKLESS; goto done;} else if (is_hdf4_file) - res = nc4_open_hdf4_file(path, mode, nc_file); + res = nc4_open_hdf4_file(path, mode, nc_file); #endif /* USE_HDF4 */ else - res = NC_ENOTNC; + res = NC_ENOTNC; done: return res; } -/* Unfortunately HDF only allows specification of fill value only when - a dataset is created. Whereas in netcdf, you first create the - variable and then (optionally) specify the fill value. To - accomplish this in HDF5 I have to delete the dataset, and recreate - it, with the fill value specified. */ -/* QAK: This looks completely unused in the code. (?) */ +/** + * @internal Unfortunately HDF only allows specification of fill value + * only when a dataset is created. Whereas in netcdf, you first create + * the variable and then (optionally) specify the fill value. To + * accomplish this in HDF5 I have to delete the dataset, and recreate + * it, with the fill value specified. + * + * @param ncid File and group ID. + * @param fillmode File mode. + * @param old_modep Pointer that gets old mode. Ignored if NULL. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett +*/ int NC4_set_fill(int ncid, int fillmode, int *old_modep) { @@ -2769,12 +3202,19 @@ NC4_set_fill(int ncid, int fillmode, int *old_modep) return NC_NOERR; } -/* Put the file back in redef mode. This is done automatically for - * netcdf-4 files, if the user forgets. */ +/** + * @internal Put the file back in redef mode. This is done + * automatically for netcdf-4 files, if the user forgets. + * + * @param ncid File and group ID. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett +*/ int NC4_redef(int ncid) { - NC_HDF5_FILE_INFO_T* nc4_info; + NC_HDF5_FILE_INFO_T* nc4_info; LOG((1, "%s: ncid 0x%x", __func__, ncid)); @@ -2801,11 +3241,22 @@ NC4_redef(int ncid) return NC_NOERR; } -/* For netcdf-4 files, this just calls nc_enddef, ignoring the extra - * parameters. */ +/** + * @internal For netcdf-4 files, this just calls nc_enddef, ignoring + * the extra parameters. + * + * @param ncid File and group ID. + * @param h_minfree Ignored for netCDF-4 files. + * @param v_align Ignored for netCDF-4 files. + * @param v_minfree Ignored for netCDF-4 files. + * @param r_align Ignored for netCDF-4 files. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett +*/ int NC4__enddef(int ncid, size_t h_minfree, size_t v_align, - size_t v_minfree, size_t r_align) + size_t v_minfree, size_t r_align) { if (nc4_find_nc_file(ncid,NULL) == NULL) return NC_EBADID; @@ -2813,11 +3264,18 @@ NC4__enddef(int ncid, size_t h_minfree, size_t v_align, return NC4_enddef(ncid); } -/* Take the file out of define mode. This is called automatically for - * netcdf-4 files, if the user forgets. */ +/** + * @internal Take the file out of define mode. This is called + * automatically for netcdf-4 files, if the user forgets. + * + * @param ncid File and group ID. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett +*/ static int NC4_enddef(int ncid) { - NC *nc; + NC *nc; NC_HDF5_FILE_INFO_T* nc4_info; NC_GRP_INFO_T *grp; int i; @@ -2839,57 +3297,15 @@ static int NC4_enddef(int ncid) return nc4_enddef_netcdf4_file(nc4_info); } -/* This function will write all changed metadata, and (someday) reread - * all metadata from the file. */ -static int -sync_netcdf4_file(NC_HDF5_FILE_INFO_T *h5) -{ - int retval; - - assert(h5); - LOG((3, "%s", __func__)); - - /* If we're in define mode, that's an error, for strict nc3 rules, - * otherwise, end define mode. */ - if (h5->flags & NC_INDEF) - { - if (h5->cmode & NC_CLASSIC_MODEL) - return NC_EINDEFINE; - - /* Turn define mode off. */ - h5->flags ^= NC_INDEF; - - /* Redef mode needs to be tracked separately for nc_abort. */ - h5->redef = NC_FALSE; - } - -#ifdef LOGGING - /* This will print out the names, types, lens, etc of the vars and - atts in the file, if the logging level is 2 or greater. */ - log_metadata_nc(h5->root_grp->nc4_info->controller); -#endif - - /* Write any metadata that has changed. */ - if (!(h5->cmode & NC_NOWRITE)) - { - nc_bool_t bad_coord_order = NC_FALSE; /* if detected, propagate to all groups to consistently store dimids */ - - if ((retval = nc4_rec_write_groups_types(h5->root_grp))) - return retval; - if ((retval = nc4_rec_detect_need_to_preserve_dimids(h5->root_grp, &bad_coord_order))) - return retval; - if ((retval = nc4_rec_write_metadata(h5->root_grp, bad_coord_order))) - return retval; - } - - if (H5Fflush(h5->hdfid, H5F_SCOPE_GLOBAL) < 0) - return NC_EHDFERR; - - return retval; -} - -/* Flushes all buffers associated with the file, after writing all - changed metadata. This may only be called in data mode. */ +/** + * @internal Flushes all buffers associated with the file, after + * writing all changed metadata. This may only be called in data mode. + * + * @param ncid File and group ID. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett +*/ int NC4_sync(int ncid) { @@ -2907,105 +3323,27 @@ NC4_sync(int ncid) if (nc4_info && nc4_info->flags & NC_INDEF) { if (nc4_info->cmode & NC_CLASSIC_MODEL) - return NC_EINDEFINE; + return NC_EINDEFINE; if ((retval = NC4_enddef(ncid))) - return retval; + return retval; } return sync_netcdf4_file(nc4_info); } -/* This function will free all allocated metadata memory, and close - the HDF5 file. The group that is passed in must be the root group - of the file. */ -static int -close_netcdf4_file(NC_HDF5_FILE_INFO_T *h5, int abort) -{ - int retval = NC_NOERR; - - assert(h5 && h5->root_grp); - LOG((3, "%s: h5->path %s abort %d", __func__, h5->controller->path, abort)); - - /* According to the docs, always end define mode on close. */ - if (h5->flags & NC_INDEF) - h5->flags ^= NC_INDEF; - - /* Sync the file, unless we're aborting, or this is a read-only - * file. */ - if (!h5->no_write && !abort) - if ((retval = sync_netcdf4_file(h5))) - goto exit; - - /* Delete all the list contents for vars, dims, and atts, in each - * group. */ - if ((retval = nc4_rec_grp_del(&h5->root_grp, h5->root_grp))) - goto exit; - - /* Close hdf file. */ -#ifdef USE_HDF4 - if (h5->hdf4) - { - if (SDend(h5->sdid)) - BAIL_QUIET(NC_EHDFERR); - } - else -#endif /* USE_HDF4 */ - { -#ifdef USE_PARALLEL4 - /* Free the MPI Comm & Info objects, if we opened the file in parallel */ - if(h5->parallel) - { - if(MPI_COMM_NULL != h5->comm) - MPI_Comm_free(&h5->comm); - if(MPI_INFO_NULL != h5->info) - MPI_Info_free(&h5->info); - } -#endif - - if(h5->fileinfo) free(h5->fileinfo); - - if (H5Fclose(h5->hdfid) < 0) - { - int nobjs; - - nobjs = H5Fget_obj_count(h5->hdfid, H5F_OBJ_ALL); - /* Apparently we can get an error even when nobjs == 0 */ - if(nobjs < 0) { - BAIL_QUIET(NC_EHDFERR); - } else if(nobjs > 0) { -#ifdef LOGGING - char msg[1024]; - int logit = 1; - /* If the close doesn't work, probably there are still some HDF5 - * objects open, which means there's a bug in the library. So - * print out some info on to help the poor programmer figure it - * out. */ - snprintf(msg,sizeof(msg),"There are %d HDF5 objects open!", nobjs); -#ifdef LOGOPEN - LOG((0, msg)); -#else - fprintf(stdout,msg); - logit = 0; -#endif - reportopenobjects(logit,h5->hdfid); -#endif - } - } - } -exit: - /* Free the nc4_info struct; above code should have reclaimed - everything else */ - if(!retval && h5 != NULL) - free(h5); - return retval; -} - -/* From the netcdf-3 docs: The function nc_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 nc_redef, the netCDF dataset - is restored to its state before definition mode was entered and the - dataset is closed. */ +/** + * @internal From the netcdf-3 docs: The function nc_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 nc_redef, the netCDF dataset + * is restored to its state before definition mode was entered and the + * dataset is closed. + * + * @param ncid File and group ID. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ int NC4_abort(int ncid) { @@ -3038,12 +3376,19 @@ NC4_abort(int ncid) /* Delete the file, if we should. */ if (delete_file) if (remove(path) < 0) - return NC_ECANTREMOVE; + return NC_ECANTREMOVE; return retval; } -/* Close the netcdf file, writing any changes first. */ +/** + * @internal Close the netcdf file, writing any changes first. + * + * @param ncid File and group ID. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett +*/ int NC4_close(int ncid) { @@ -3071,8 +3416,23 @@ NC4_close(int ncid) return NC_NOERR; } -/* It's possible for any of these pointers to be NULL, in which case - don't try to figure out that value. */ +/** + * @internal Learn number of dimensions, variables, global attributes, + * and the ID of the first unlimited dimension (if any). + * + * @note It's possible for any of these pointers to be NULL, in which + * case don't try to figure out that value. + * + * @param ncid File and group ID. + * @param ndimsp Pointer that gets number of dimensions. + * @param nvarsp Pointer that gets number of variables. + * @param nattsp Pointer that gets number of global attributes. + * @param unlimdimidp Pointer that gets first unlimited dimension ID, + * or -1 if there are no unlimied dimensions. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett +*/ int NC4_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp) { @@ -3096,7 +3456,7 @@ NC4_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp) { *ndimsp = 0; for (dim = grp->dim; dim; dim = dim->l.next) - (*ndimsp)++; + (*ndimsp)++; } if (nvarsp) { @@ -3104,15 +3464,15 @@ NC4_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp) *nvarsp = 0; for (i=0; i < grp->vars.nelems; i++) { - if (grp->vars.value[i]) - (*nvarsp)++; + if (grp->vars.value[i]) + (*nvarsp)++; } } if (nattsp) - { + { *nattsp = 0; for (att = grp->att; att; att = att->l.next) - (*nattsp)++; + (*nattsp)++; } if (unlimdimidp) @@ -3121,21 +3481,28 @@ NC4_inq(int ncid, int *ndimsp, int *nvarsp, int *nattsp, int *unlimdimidp) *unlimdimidp = -1; /* If there's more than one unlimited dim, which was not possible - with netcdf-3, then only the last unlimited one will be reported - back in xtendimp. */ + with netcdf-3, then only the last unlimited one will be reported + back in xtendimp. */ /* Note that this code is inconsistent with nc_inq_unlimid() */ for (dim = grp->dim; dim; dim = dim->l.next) - if (dim->unlimited) - { - *unlimdimidp = dim->dimid; - break; - } + if (dim->unlimited) + { + *unlimdimidp = dim->dimid; + break; + } } return NC_NOERR; } -/* This function will do the enddef stuff for a netcdf-4 file. */ +/** + * @internal This function will do the enddef stuff for a netcdf-4 file. + * + * @param h5 Pointer to HDF5 file info struct. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett +*/ int nc4_enddef_netcdf4_file(NC_HDF5_FILE_INFO_T *h5) { @@ -3155,31 +3522,3 @@ nc4_enddef_netcdf4_file(NC_HDF5_FILE_INFO_T *h5) return sync_netcdf4_file(h5); } -#ifdef USE_PARALLEL4 -int -nc_use_parallel_enabled() -{ - return 0; -} -#endif /* USE_PARALLEL4 */ - - -/* -Wrap HDF5 allocated memory free operations -*/ - -static void -hdf5free(void* memory) -{ -#ifndef JNA - /* On Windows using the microsoft runtime, it is an error - for one library to free memory allocated by a different library.*/ -#ifdef HDF5_HAS_H5FREE - if(memory != NULL) H5free_memory(memory); -#else -#ifndef _MSC_VER - if(memory != NULL) free(memory); -#endif -#endif -#endif -} diff --git a/libsrc4/nc4grp.c b/libsrc4/nc4grp.c index ab8588126b..7ea43357d5 100644 --- a/libsrc4/nc4grp.c +++ b/libsrc4/nc4grp.c @@ -1,20 +1,34 @@ -/* -This file is part of netcdf-4, a netCDF-like interface for HDF5, or a -HDF5 backend for netCDF, depending on your point of view. - -This file handles the nc4 groups. - -Copyright 2005, University Corporation for Atmospheric Research. See -netcdf-4/docs/COPYRIGHT file for copying and redistribution -conditions. - -$Id: nc4grp.c,v 1.44 2010/05/25 17:54:23 dmh Exp $ +/** + * @file + * @internal This file is part of netcdf-4, a netCDF-like interface + * for HDF5, or a HDF5 backend for netCDF, depending on your point of + * view. + * + * This file handles the nc4 groups. + * + * Copyright 2005, University Corporation for Atmospheric Research. See + * netcdf-4/docs/COPYRIGHT file for copying and redistribution + * conditions. + * + * @author Ed Hartnett */ - #include "nc4internal.h" #include "nc4dispatch.h" -/* Create a group. It's ncid is returned in the new_ncid pointer. */ +/** + * @internal Create a group. It's ncid is returned in the new_ncid + * pointer. + * + * @param parent_ncid Parent group. + * @param name Name of new group. + * @param new_ncid Pointer that gets ncid for new group. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_ESTRICTNC3 Classic model in use for this file. + * @return ::NC_ENOTNC4 Not a netCDF-4 file. + * @author Ed Hartnett +*/ int NC4_def_grp(int parent_ncid, const char *name, int *new_ncid) { @@ -61,7 +75,21 @@ NC4_def_grp(int parent_ncid, const char *name, int *new_ncid) return NC_NOERR; } -/* Rename a group. */ +/** + * @internal Rename a group. + * + * @param grpid Group ID. + * @param name New name for group. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_ENOTNC4 Not a netCDF-4 file. + * @return ::NC_EPERM File opened read-only. + * @return ::NC_EBADGRPID Renaming root forbidden. + * @return ::NC_EHDFERR HDF5 function returned error. + * @return ::NC_ENOMEM Out of memory. + * @author Ed Hartnett +*/ int NC4_rename_grp(int grpid, const char *name) { @@ -129,8 +157,20 @@ NC4_rename_grp(int grpid, const char *name) return NC_NOERR; } -/* Given an ncid and group name (NULL gets root group), return - * the ncid of that group. */ +/** + * @internal Given an ncid and group name (NULL gets root group), + * return the ncid of that group. + * + * @param ncid File and group ID. + * @param name Pointer that gets name. + * @param grp_ncid Pointer that gets group ncid. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_ENOTNC4 Not a netCDF-4 file. + * @return ::NC_ENOGRP Group not found. + * @author Ed Hartnett +*/ int NC4_inq_ncid(int ncid, const char *name, int *grp_ncid) { @@ -166,8 +206,18 @@ NC4_inq_ncid(int ncid, const char *name, int *grp_ncid) return NC_ENOGRP; } -/* Given a location id, return the number of groups it contains, and - * an array of their locids. */ +/** + * @internal Given a location id, return the number of groups it + * contains, and an array of their locids. + * + * @param ncid File and group ID. + * @param numgrps Pointer that gets number of groups. Ignored if NULL. + * @param ncids Pointer that gets array of ncids. Ignored if NULL. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Ed Hartnett +*/ int NC4_inq_grps(int ncid, int *numgrps, int *ncids) { @@ -210,7 +260,17 @@ NC4_inq_grps(int ncid, int *numgrps, int *ncids) return NC_NOERR; } -/* Given locid, find name of group. (Root group is named "/".) */ +/** + * @internal Given locid, find name of group. (Root group is named + * "/".) + * + * @param ncid File and group ID. + * @param name Pointer that gets name. + + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Ed Hartnett +*/ int NC4_inq_grpname(int ncid, char *name) { @@ -234,10 +294,21 @@ NC4_inq_grpname(int ncid, char *name) return NC_NOERR; } -/* Find the full path name to the group represented by ncid. Either - * pointer argument may be NULL; pass a NULL for the third parameter - * to get the length of the full path name. The length will not - * include room for a null pointer. */ +/** + * @internal Find the full path name to the group represented by + * ncid. Either pointer argument may be NULL; pass a NULL for the + * third parameter to get the length of the full path name. The length + * will not include room for a null pointer. + * + * @param ncid File and group ID. + * @param lenp Pointer that gets length of full name. + * @param full_name Pointer that gets name. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_ENOMEM Out of memory. + * @author Ed Hartnett +*/ int NC4_inq_grpname_full(int ncid, size_t *lenp, char *full_name) { @@ -291,10 +362,20 @@ NC4_inq_grpname_full(int ncid, size_t *lenp, char *full_name) return ret; } -/* Find the parent ncid of a group. For the root group, return - * NC_ENOGRP error. *Now* I know what kind of tinfoil hat wearing nut - * job would call this function with a NULL pointer for parent_ncid - - * Russ Rew!! */ +/** + * @internal Find the parent ncid of a group. For the root group, + * return NC_ENOGRP error. *Now* I know what kind of tinfoil hat + * wearing nut job would call this function with a NULL pointer for + * parent_ncid - Russ Rew!! + * + * @param ncid File and group ID. + * @param parent_ncid Pointer that gets the ncid of parent group. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_ENOGRP Root has no parent. + * @author Ed Hartnett +*/ int NC4_inq_grp_parent(int ncid, int *parent_ncid) { @@ -324,7 +405,20 @@ NC4_inq_grp_parent(int ncid, int *parent_ncid) return NC_NOERR; } -/* Given a full name and ncid, find group ncid. */ +/** + * @internal Given a full name and ncid, find group ncid. + * + * @param ncid File and group ID. + * @param full_name Full name of group. + * @param grp_ncid Pointer that gets ncid of group. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_ENOGRP Group not found. + * @return ::NC_ENOMEM Out of memory. + * @return ::NC_EINVAL Name is required. + * @author Ed Hartnett +*/ int NC4_inq_grp_full_ncid(int ncid, const char *full_name, int *grp_ncid) { @@ -383,7 +477,17 @@ NC4_inq_grp_full_ncid(int ncid, const char *full_name, int *grp_ncid) return NC_NOERR; } -/* Get a list of ids for all the variables in a group. */ +/** + * @internal Get a list of ids for all the variables in a group. + * + * @param ncid File and group ID. + * @param nvars Pointer that gets number of vars in group. + * @param varids Pointer that gets array of var IDs. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Ed Hartnett +*/ int NC4_inq_varids(int ncid, int *nvars, int *varids) { @@ -432,8 +536,17 @@ NC4_inq_varids(int ncid, int *nvars, int *varids) return NC_NOERR; } -/* This is the comparison function used for sorting dim ids. Integer - comparison: returns negative if b > a and positive if a > b. */ +/** + * @internal This is the comparison function used for sorting dim + * ids. Integer comparison: returns negative if b > a and positive if + * a > b. + * + * @param a A pointer to an item to compare to b. + * @param b A pointer to an item to compare to a. + * + * @return a - b + * @author Ed Hartnett +*/ int int_cmp(const void *a, const void *b) { const int *ia = (const int *)a; @@ -441,9 +554,21 @@ int int_cmp(const void *a, const void *b) return *ia - *ib; } -/* Find all dimids for a location. This finds all dimensions in a - * group, with or without any of its parents, depending on last - * parameter. */ +/** + * @internal Find all dimids for a location. This finds all dimensions + * in a group, with or without any of its parents, depending on last + * parameter. + * + * @param ncid File and group ID. + * @param ndims Pointer that gets number of dimensions available in group. + * @param dimids Pointer that gets dim IDs. + * @param include_parents If non-zero, include dimensions from parent + * groups. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Ed Hartnett +*/ int NC4_inq_dimids(int ncid, int *ndims, int *dimids, int include_parents) { diff --git a/libsrc4/nc4hdf.c b/libsrc4/nc4hdf.c index b15072b674..b0a5c7bee8 100644 --- a/libsrc4/nc4hdf.c +++ b/libsrc4/nc4hdf.c @@ -1,17 +1,19 @@ -/* - This file is part of netcdf-4, a netCDF-like interface for HDF5, or a - HDF5 backend for netCDF, depending on your point of view. - - This file contains functions internal to the netcdf4 library. None of - the functions in this file are exposed in the exetnal API. These - functions handle the HDF interface. - - Copyright 2003, University Corporation for Atmospheric - Research. See the COPYRIGHT file for copying and redistribution - conditions. - - $Id: nc4hdf.c,v 1.273 2010/05/27 21:34:14 dmh Exp $ -*/ +/** + * + * @file + * This file is part of netcdf-4, a netCDF-like interface for HDF5, or a + * HDF5 backend for netCDF, depending on your point of view. + * + * This file contains functions internal to the netcdf4 library. None of + * the functions in this file are exposed in the exetnal API. These + * functions handle the HDF interface. + * + * Copyright 2003, University Corporation for Atmospheric + * Research. See the COPYRIGHT file for copying and redistribution + * conditions. + * + * @author Ed Hartnett, Dennis Heimbigner, Ward Fisher + */ #include "config.h" #include "nc4internal.h" @@ -23,653 +25,765 @@ #include "netcdf_par.h" #endif -#define NC3_STRICT_ATT_NAME "_nc3_strict" +#define NC3_STRICT_ATT_NAME "_nc3_strict" /**< @internal Indicates classic model. */ + +#define NC_HDF5_MAX_NAME 1024 /**< @internal Max size of HDF5 name. */ -#define NC_HDF5_MAX_NAME 1024 +#define MAXNAME 1024 /**< Max HDF5 name. */ -/*! Flag attributes in a linked list as dirty. +/** @internal HDF5 object types. */ +static unsigned int OTYPES[5] = {H5F_OBJ_FILE, H5F_OBJ_DATASET, H5F_OBJ_GROUP, + H5F_OBJ_DATATYPE, H5F_OBJ_ATTR}; + +/** + * @internal Flag attributes in a linked list as dirty. * - * Given a linked list of attributes, flag each - * dirty. + * @param attlist List of attributes, may be NULL. * - * @param[in] attlist List of attributes, may be NULL. - * @return Returns NC_NOERR on succes, error on failure. + * @return NC_NOERR No error. */ -static int flag_atts_dirty(NC_ATT_INFO_T **attlist) { +static int +flag_atts_dirty(NC_ATT_INFO_T **attlist) { - NC_ATT_INFO_T *att = NULL; + NC_ATT_INFO_T *att = NULL; - if(attlist == NULL) { - return NC_NOERR; - } + if(attlist == NULL) { + return NC_NOERR; + } - for(att = *attlist; att; att = att->l.next) { - att->dirty = NC_TRUE; - } + for(att = *attlist; att; att = att->l.next) { + att->dirty = NC_TRUE; + } - return NC_NOERR; + return NC_NOERR; } -/* This function is needed to handle one special case: what if the - * user defines a dim, writes metadata, then goes back into define - * mode and adds a coordinate var for the already existing dim. In - * that case, I need to recreate the dim's dimension scale dataset, - * and then I need to go to every var in the file which uses that - * dimension, and attach the new dimension scale. */ +/** + * @internal This function is needed to handle one special case: what + * if the user defines a dim, writes metadata, then goes back into + * define mode and adds a coordinate var for the already existing + * dim. In that case, I need to recreate the dim's dimension scale + * dataset, and then I need to go to every var in the file which uses + * that dimension, and attach the new dimension scale. + * + * @param grp Pointer to group info struct. + * @param dimid Dimension ID. + * @param dimscaleid HDF5 dimension scale ID. + * + * @returns NC_NOERR No error. + * @returns NC_EHDFERR HDF5 returned an error. + * @author Ed Hartnett + */ int rec_reattach_scales(NC_GRP_INFO_T *grp, int dimid, hid_t dimscaleid) { - NC_VAR_INFO_T *var; - NC_GRP_INFO_T *child_grp; - int d, i; - int retval; - - assert(grp && grp->name && dimid >= 0 && dimscaleid >= 0); - LOG((3, "%s: grp->name %s", __func__, grp->name)); - - /* If there are any child groups, attach dimscale there, if needed. */ - for (child_grp = grp->children; child_grp; child_grp = child_grp->l.next) - if ((retval = rec_reattach_scales(child_grp, dimid, dimscaleid))) - return retval; - - /* Find any vars that use this dimension id. */ - for (i=0; i < grp->vars.nelems; i++) - { - var = grp->vars.value[i]; - if (!var) continue; - for (d = 0; d < var->ndims; d++) - if (var->dimids[d] == dimid && !var->dimscale) - { - LOG((2, "%s: attaching scale for dimid %d to var %s", - __func__, var->dimids[d], var->name)); - if (var->created) + NC_VAR_INFO_T *var; + NC_GRP_INFO_T *child_grp; + int d, i; + int retval; + + assert(grp && grp->name && dimid >= 0 && dimscaleid >= 0); + LOG((3, "%s: grp->name %s", __func__, grp->name)); + + /* If there are any child groups, attach dimscale there, if needed. */ + for (child_grp = grp->children; child_grp; child_grp = child_grp->l.next) + if ((retval = rec_reattach_scales(child_grp, dimid, dimscaleid))) + return retval; + + /* Find any vars that use this dimension id. */ + for (i=0; i < grp->vars.nelems; i++) + { + var = grp->vars.value[i]; + if (!var) continue; + for (d = 0; d < var->ndims; d++) + if (var->dimids[d] == dimid && !var->dimscale) + { + LOG((2, "%s: attaching scale for dimid %d to var %s", + __func__, var->dimids[d], var->name)); + if (var->created) { - if (H5DSattach_scale(var->hdf_datasetid, dimscaleid, d) < 0) - return NC_EHDFERR; - var->dimscale_attached[d] = NC_TRUE; + if (H5DSattach_scale(var->hdf_datasetid, dimscaleid, d) < 0) + return NC_EHDFERR; + var->dimscale_attached[d] = NC_TRUE; } - } - } - return NC_NOERR; + } + } + return NC_NOERR; } -/* This function is needed to handle one special case: what if the - * user defines a dim, writes metadata, then goes back into define - * mode and adds a coordinate var for the already existing dim. In - * that case, I need to recreate the dim's dimension scale dataset, - * and then I need to go to every var in the file which uses that - * dimension, and attach the new dimension scale. */ +/** + * @internal This function is needed to handle one special case: what + * if the user defines a dim, writes metadata, then goes back into + * define mode and adds a coordinate var for the already existing + * dim. In that case, I need to recreate the dim's dimension scale + * dataset, and then I need to go to every var in the file which uses + * that dimension, and attach the new dimension scale. + * + * @param grp Pointer to group info struct. + * @param dimid Dimension ID. + * @param dimscaleid HDF5 dimension scale ID. + * + * @returns NC_NOERR No error. + * @returns NC_EHDFERR HDF5 returned an error. + * @author Ed Hartnett + */ int rec_detach_scales(NC_GRP_INFO_T *grp, int dimid, hid_t dimscaleid) { - NC_VAR_INFO_T *var; - NC_GRP_INFO_T *child_grp; - int d, i; - int retval; - - assert(grp && grp->name && dimid >= 0 && dimscaleid >= 0); - LOG((3, "%s: grp->name %s", __func__, grp->name)); - - /* If there are any child groups, detach dimscale there, if needed. */ - for (child_grp = grp->children; child_grp; child_grp = child_grp->l.next) - if ((retval = rec_detach_scales(child_grp, dimid, dimscaleid))) - return retval; - - /* Find any vars that use this dimension id. */ - for (i=0; i < grp->vars.nelems; i++) - { - var = grp->vars.value[i]; - if (!var) continue; - for (d = 0; d < var->ndims; d++) - if (var->dimids[d] == dimid && !var->dimscale) - { - LOG((2, "%s: detaching scale for dimid %d to var %s", - __func__, var->dimids[d], var->name)); - if (var->created) - if (var->dimscale_attached && var->dimscale_attached[d]) - { - if (H5DSdetach_scale(var->hdf_datasetid, dimscaleid, d) < 0) - return NC_EHDFERR; - var->dimscale_attached[d] = NC_FALSE; - } - } - } - return NC_NOERR; + NC_VAR_INFO_T *var; + NC_GRP_INFO_T *child_grp; + int d, i; + int retval; + + assert(grp && grp->name && dimid >= 0 && dimscaleid >= 0); + LOG((3, "%s: grp->name %s", __func__, grp->name)); + + /* If there are any child groups, detach dimscale there, if needed. */ + for (child_grp = grp->children; child_grp; child_grp = child_grp->l.next) + if ((retval = rec_detach_scales(child_grp, dimid, dimscaleid))) + return retval; + + /* Find any vars that use this dimension id. */ + for (i=0; i < grp->vars.nelems; i++) + { + var = grp->vars.value[i]; + if (!var) continue; + for (d = 0; d < var->ndims; d++) + if (var->dimids[d] == dimid && !var->dimscale) + { + LOG((2, "%s: detaching scale for dimid %d to var %s", + __func__, var->dimids[d], var->name)); + if (var->created) + if (var->dimscale_attached && var->dimscale_attached[d]) + { + if (H5DSdetach_scale(var->hdf_datasetid, dimscaleid, d) < 0) + return NC_EHDFERR; + var->dimscale_attached[d] = NC_FALSE; + } + } + } + return NC_NOERR; } -/* Open the dataset and leave it open. */ +/** + * @internal Open a HDF5 dataset and leave it open. + * + * @param grp Pointer to group info struct. + * @param varid Variable ID. + * @param dataset Pointer that gets the HDF5 dataset ID. + * + * @returns NC_NOERR No error. + * @returns NC_EHDFERR HDF5 returned an error. + * @author Ed Hartnett + */ int nc4_open_var_grp2(NC_GRP_INFO_T *grp, int varid, hid_t *dataset) { - NC_VAR_INFO_T *var; + NC_VAR_INFO_T *var; - /* Find the requested varid. */ + /* Find the requested varid. */ if (varid < 0 || varid >= grp->vars.nelems) - return NC_ENOTVAR; + return NC_ENOTVAR; var = grp->vars.value[varid]; if (!var) return NC_ENOTVAR; assert(var->varid == varid); - /* Open this dataset if necessary. */ - if (!var->hdf_datasetid) - if ((var->hdf_datasetid = H5Dopen2(grp->hdf_grpid, var->name, - H5P_DEFAULT)) < 0) - return NC_ENOTVAR; + /* Open this dataset if necessary. */ + if (!var->hdf_datasetid) + if ((var->hdf_datasetid = H5Dopen2(grp->hdf_grpid, var->name, + H5P_DEFAULT)) < 0) + return NC_ENOTVAR; - *dataset = var->hdf_datasetid; + *dataset = var->hdf_datasetid; - return NC_NOERR; + return NC_NOERR; } -/* Get the default fill value for an atomic type. Memory for - * fill_value must already be allocated, or you are DOOMED!!!*/ +/** + * @internal Get the default fill value for an atomic type. Memory for + * fill_value must already be allocated, or you are DOOMED! + * + * @param type_info Pointer to type info struct. + * @param fill_value Pointer that gets the default fill value. + * + * @returns NC_NOERR No error. + * @returns NC_EINVAL Can't find atomic type. + * @author Ed Hartnett + */ int nc4_get_default_fill_value(const NC_TYPE_INFO_T *type_info, void *fill_value) { - switch (type_info->nc_typeid) - { - case NC_CHAR: + switch (type_info->nc_typeid) + { + case NC_CHAR: *(char *)fill_value = NC_FILL_CHAR; break; - case NC_STRING: + case NC_STRING: *(char **)fill_value = strdup(NC_FILL_STRING); break; - case NC_BYTE: + case NC_BYTE: *(signed char *)fill_value = NC_FILL_BYTE; break; - case NC_SHORT: + case NC_SHORT: *(short *)fill_value = NC_FILL_SHORT; break; - case NC_INT: + case NC_INT: *(int *)fill_value = NC_FILL_INT; break; - case NC_UBYTE: + case NC_UBYTE: *(unsigned char *)fill_value = NC_FILL_UBYTE; break; - case NC_USHORT: + case NC_USHORT: *(unsigned short *)fill_value = NC_FILL_USHORT; break; - case NC_UINT: + case NC_UINT: *(unsigned int *)fill_value = NC_FILL_UINT; break; - case NC_INT64: + case NC_INT64: *(long long *)fill_value = NC_FILL_INT64; break; - case NC_UINT64: + case NC_UINT64: *(unsigned long long *)fill_value = NC_FILL_UINT64; break; - case NC_FLOAT: + case NC_FLOAT: *(float *)fill_value = NC_FILL_FLOAT; break; - case NC_DOUBLE: + case NC_DOUBLE: *(double *)fill_value = NC_FILL_DOUBLE; break; - default: + default: return NC_EINVAL; - } + } - return NC_NOERR; + return NC_NOERR; } -/* What fill value should be used for a variable? */ +/** + * @internal What fill value should be used for a variable? + * + * @param h5 Pointer to HDF5 file info struct. + * @param var Pointer to variable info struct. + * @param fillp Pointer that gets pointer to fill value. + * + * @returns NC_NOERR No error. + * @returns NC_ENOMEM Out of memory. + * @author Ed Hartnett + */ static int get_fill_value(NC_HDF5_FILE_INFO_T *h5, NC_VAR_INFO_T *var, void **fillp) { - size_t size; - int retval; - - /* Find out how much space we need for this type's fill value. */ - if (var->type_info->nc_type_class == NC_VLEN) - size = sizeof(nc_vlen_t); - else if (var->type_info->nc_type_class == NC_STRING) - size = sizeof(char *); - else - { + size_t size; + int retval; + + /* Find out how much space we need for this type's fill value. */ + if (var->type_info->nc_type_class == NC_VLEN) + size = sizeof(nc_vlen_t); + else if (var->type_info->nc_type_class == NC_STRING) + size = sizeof(char *); + else + { if ((retval = nc4_get_typelen_mem(h5, var->type_info->nc_typeid, 0, &size))) - return retval; - } - assert(size); - - /* Allocate the space. */ - if (!((*fillp) = calloc(1, size))) - return NC_ENOMEM; - - /* If the user has set a fill_value for this var, use, otherwise - * find the default fill value. */ - if (var->fill_value) - { + return retval; + } + assert(size); + + /* Allocate the space. */ + if (!((*fillp) = calloc(1, size))) + return NC_ENOMEM; + + /* If the user has set a fill_value for this var, use, otherwise + * find the default fill value. */ + if (var->fill_value) + { LOG((4, "Found a fill value for var %s", var->name)); if (var->type_info->nc_type_class == NC_VLEN) - { - nc_vlen_t *in_vlen = (nc_vlen_t *)(var->fill_value), *fv_vlen = (nc_vlen_t *)(*fillp); - - fv_vlen->len = in_vlen->len; - if (!(fv_vlen->p = malloc(size * in_vlen->len))) - { - free(*fillp); - *fillp = NULL; - return NC_ENOMEM; - } - memcpy(fv_vlen->p, in_vlen->p, in_vlen->len * size); - } + { + nc_vlen_t *in_vlen = (nc_vlen_t *)(var->fill_value), *fv_vlen = (nc_vlen_t *)(*fillp); + + fv_vlen->len = in_vlen->len; + if (!(fv_vlen->p = malloc(size * in_vlen->len))) + { + free(*fillp); + *fillp = NULL; + return NC_ENOMEM; + } + memcpy(fv_vlen->p, in_vlen->p, in_vlen->len * size); + } else if (var->type_info->nc_type_class == NC_STRING) - { - if (*(char **)var->fill_value) + { + if (*(char **)var->fill_value) if (!(**(char ***)fillp = strdup(*(char **)var->fill_value))) - { - free(*fillp); - *fillp = NULL; - return NC_ENOMEM; - } - } + { + free(*fillp); + *fillp = NULL; + return NC_ENOMEM; + } + } else - memcpy((*fillp), var->fill_value, size); - } - else - { + memcpy((*fillp), var->fill_value, size); + } + else + { if (nc4_get_default_fill_value(var->type_info, *fillp)) - { - /* Note: release memory, but don't return error on failure */ - free(*fillp); - *fillp = NULL; - } - } - - return NC_NOERR; + { + /* Note: release memory, but don't return error on failure */ + free(*fillp); + *fillp = NULL; + } + } + + return NC_NOERR; } -/* Given a netcdf type, return appropriate HDF typeid. */ -/* (All hdf_typeid's returned from this routine must be H5Tclosed by the caller) */ +/** + * @internal Given a netcdf type, return appropriate HDF typeid. (All + * hdf_typeid's returned from this routine must be H5Tclosed by the + * caller). + * + * @param h5 Pointer to HDF5 file info struct. + * @param xtype NetCDF type ID. + * @param hdf_typeid Pointer that gets the HDF5 type ID. + * @param endianness Desired endianness in HDF5 type. + * + * @returns NC_NOERR No error. + * @returns NC_ECHAR Conversions of NC_CHAR forbidden. + * @returns NC_EVARMETA HDF5 returning error creating datatype. + * @returns NC_EHDFERR HDF5 returning error. + * @returns NC_EBADTYE Type not found. + * @author Ed Hartnett + */ int nc4_get_hdf_typeid(NC_HDF5_FILE_INFO_T *h5, nc_type xtype, hid_t *hdf_typeid, int endianness) { - NC_TYPE_INFO_T *type; - hid_t typeid = 0; - int retval = NC_NOERR; + NC_TYPE_INFO_T *type; + hid_t typeid = 0; + int retval = NC_NOERR; - assert(hdf_typeid && h5); + assert(hdf_typeid && h5); - *hdf_typeid = -1; + *hdf_typeid = -1; - /* Determine an appropriate HDF5 datatype */ - if (xtype == NC_NAT) - /* NAT = 'Not A Type' (c.f. NaN) */ - return NC_EBADTYPE; - else if (xtype == NC_CHAR || xtype == NC_STRING) - { + /* Determine an appropriate HDF5 datatype */ + if (xtype == NC_NAT) + /* NAT = 'Not A Type' (c.f. NaN) */ + return NC_EBADTYPE; + else if (xtype == NC_CHAR || xtype == NC_STRING) + { /* NC_CHAR & NC_STRING types create a new HDF5 datatype */ if (xtype == NC_CHAR) - { - if ((typeid = H5Tcopy(H5T_C_S1)) < 0) + { + if ((typeid = H5Tcopy(H5T_C_S1)) < 0) return NC_EHDFERR; - if (H5Tset_strpad(typeid, H5T_STR_NULLTERM) < 0) + if (H5Tset_strpad(typeid, H5T_STR_NULLTERM) < 0) + BAIL(NC_EVARMETA); + if(H5Tset_cset(typeid, H5T_CSET_ASCII) < 0) BAIL(NC_EVARMETA); - if(H5Tset_cset(typeid, H5T_CSET_ASCII) < 0) - BAIL(NC_EVARMETA); - /* Take ownership of the newly created HDF5 datatype */ - *hdf_typeid = typeid; - typeid = 0; - } + /* Take ownership of the newly created HDF5 datatype */ + *hdf_typeid = typeid; + typeid = 0; + } else - { - if ((typeid = H5Tcopy(H5T_C_S1)) < 0) + { + if ((typeid = H5Tcopy(H5T_C_S1)) < 0) return NC_EHDFERR; - if (H5Tset_size(typeid, H5T_VARIABLE) < 0) + if (H5Tset_size(typeid, H5T_VARIABLE) < 0) BAIL(NC_EVARMETA); - if(H5Tset_cset(typeid, H5T_CSET_UTF8) < 0) - BAIL(NC_EVARMETA); - - /* Take ownership of the newly created HDF5 datatype */ - *hdf_typeid = typeid; - typeid = 0; - } - } - else - { + if(H5Tset_cset(typeid, H5T_CSET_UTF8) < 0) + BAIL(NC_EVARMETA); + + /* Take ownership of the newly created HDF5 datatype */ + *hdf_typeid = typeid; + typeid = 0; + } + } + else + { /* All other types use an existing HDF5 datatype */ switch (xtype) - { - case NC_BYTE: /* signed 1 byte integer */ - if (endianness == NC_ENDIAN_LITTLE) + { + case NC_BYTE: /* signed 1 byte integer */ + if (endianness == NC_ENDIAN_LITTLE) typeid = H5T_STD_I8LE; - else if (endianness == NC_ENDIAN_BIG) + else if (endianness == NC_ENDIAN_BIG) typeid = H5T_STD_I8BE; - else + else typeid = H5T_NATIVE_SCHAR; - break; + break; - case NC_SHORT: /* signed 2 byte integer */ - if (endianness == NC_ENDIAN_LITTLE) + case NC_SHORT: /* signed 2 byte integer */ + if (endianness == NC_ENDIAN_LITTLE) typeid = H5T_STD_I16LE; - else if (endianness == NC_ENDIAN_BIG) + else if (endianness == NC_ENDIAN_BIG) typeid = H5T_STD_I16BE; - else + else typeid = H5T_NATIVE_SHORT; - break; + break; - case NC_INT: - if (endianness == NC_ENDIAN_LITTLE) + case NC_INT: + if (endianness == NC_ENDIAN_LITTLE) typeid = H5T_STD_I32LE; - else if (endianness == NC_ENDIAN_BIG) + else if (endianness == NC_ENDIAN_BIG) typeid = H5T_STD_I32BE; - else + else typeid = H5T_NATIVE_INT; - break; + break; - case NC_UBYTE: - if (endianness == NC_ENDIAN_LITTLE) + case NC_UBYTE: + if (endianness == NC_ENDIAN_LITTLE) typeid = H5T_STD_U8LE; - else if (endianness == NC_ENDIAN_BIG) + else if (endianness == NC_ENDIAN_BIG) typeid = H5T_STD_U8BE; - else + else typeid = H5T_NATIVE_UCHAR; - break; + break; - case NC_USHORT: - if (endianness == NC_ENDIAN_LITTLE) + case NC_USHORT: + if (endianness == NC_ENDIAN_LITTLE) typeid = H5T_STD_U16LE; - else if (endianness == NC_ENDIAN_BIG) + else if (endianness == NC_ENDIAN_BIG) typeid = H5T_STD_U16BE; - else + else typeid = H5T_NATIVE_USHORT; - break; + break; - case NC_UINT: - if (endianness == NC_ENDIAN_LITTLE) + case NC_UINT: + if (endianness == NC_ENDIAN_LITTLE) typeid = H5T_STD_U32LE; - else if (endianness == NC_ENDIAN_BIG) + else if (endianness == NC_ENDIAN_BIG) typeid = H5T_STD_U32BE; - else + else typeid = H5T_NATIVE_UINT; - break; + break; - case NC_INT64: - if (endianness == NC_ENDIAN_LITTLE) + case NC_INT64: + if (endianness == NC_ENDIAN_LITTLE) typeid = H5T_STD_I64LE; - else if (endianness == NC_ENDIAN_BIG) + else if (endianness == NC_ENDIAN_BIG) typeid = H5T_STD_I64BE; - else + else typeid = H5T_NATIVE_LLONG; - break; + break; - case NC_UINT64: - if (endianness == NC_ENDIAN_LITTLE) + case NC_UINT64: + if (endianness == NC_ENDIAN_LITTLE) typeid = H5T_STD_U64LE; - else if (endianness == NC_ENDIAN_BIG) + else if (endianness == NC_ENDIAN_BIG) typeid = H5T_STD_U64BE; - else + else typeid = H5T_NATIVE_ULLONG; - break; + break; - case NC_FLOAT: - if (endianness == NC_ENDIAN_LITTLE) + case NC_FLOAT: + if (endianness == NC_ENDIAN_LITTLE) typeid = H5T_IEEE_F32LE; - else if (endianness == NC_ENDIAN_BIG) + else if (endianness == NC_ENDIAN_BIG) typeid = H5T_IEEE_F32BE; - else + else typeid = H5T_NATIVE_FLOAT; - break; + break; - case NC_DOUBLE: - if (endianness == NC_ENDIAN_LITTLE) + case NC_DOUBLE: + if (endianness == NC_ENDIAN_LITTLE) typeid = H5T_IEEE_F64LE; - else if (endianness == NC_ENDIAN_BIG) + else if (endianness == NC_ENDIAN_BIG) typeid = H5T_IEEE_F64BE; - else + else typeid = H5T_NATIVE_DOUBLE; - break; + break; - default: - /* Maybe this is a user defined type? */ - if (nc4_find_type(h5, xtype, &type)) + default: + /* Maybe this is a user defined type? */ + if (nc4_find_type(h5, xtype, &type)) return NC_EBADTYPE; - if (!type) + if (!type) return NC_EBADTYPE; - typeid = type->hdf_typeid; - break; - } + typeid = type->hdf_typeid; + break; + } assert(typeid); /* Copy the HDF5 datatype, so the function operates uniformly */ if ((*hdf_typeid = H5Tcopy(typeid)) < 0) - return NC_EHDFERR; + return NC_EHDFERR; typeid = 0; - } - assert(*hdf_typeid != -1); + } + assert(*hdf_typeid != -1); - exit: - if (typeid > 0 && H5Tclose(typeid) < 0) - BAIL2(NC_EHDFERR); - return retval; +exit: + if (typeid > 0 && H5Tclose(typeid) < 0) + BAIL2(NC_EHDFERR); + return retval; } -/* Do some common check for nc4_put_vara and nc4_get_vara. These - * checks have to be done when both reading and writing data. */ +/** + * @internal Do some common check for nc4_put_vara and + * nc4_get_vara. These checks have to be done when both reading and + * writing data. + * + * @param mem_nc_type Pointer to type of data in memory. + * @param var Pointer to var info struct. + * @param h5 Pointer to HDF5 file info struct. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ static int check_for_vara(nc_type *mem_nc_type, NC_VAR_INFO_T *var, NC_HDF5_FILE_INFO_T *h5) { - int retval; - - /* If mem_nc_type is NC_NAT, it means we want to use the file type - * as the mem type as well. */ - assert(mem_nc_type); - if (*mem_nc_type == NC_NAT) - *mem_nc_type = var->type_info->nc_typeid; - assert(*mem_nc_type); - - /* No NC_CHAR conversions, you pervert! */ - if (var->type_info->nc_typeid != *mem_nc_type && - (var->type_info->nc_typeid == NC_CHAR || *mem_nc_type == NC_CHAR)) - return NC_ECHAR; - - /* If we're in define mode, we can't read or write data. */ - if (h5->flags & NC_INDEF) - { + int retval; + + /* If mem_nc_type is NC_NAT, it means we want to use the file type + * as the mem type as well. */ + assert(mem_nc_type); + if (*mem_nc_type == NC_NAT) + *mem_nc_type = var->type_info->nc_typeid; + assert(*mem_nc_type); + + /* No NC_CHAR conversions, you pervert! */ + if (var->type_info->nc_typeid != *mem_nc_type && + (var->type_info->nc_typeid == NC_CHAR || *mem_nc_type == NC_CHAR)) + return NC_ECHAR; + + /* If we're in define mode, we can't read or write data. */ + if (h5->flags & NC_INDEF) + { if (h5->cmode & NC_CLASSIC_MODEL) - return NC_EINDEFINE; + return NC_EINDEFINE; if ((retval = nc4_enddef_netcdf4_file(h5))) - return retval; - } + return retval; + } - return NC_NOERR; + return NC_NOERR; } #ifdef LOGGING -/* Print some debug info about dimensions to the log. */ +/** + * @intarnal Print some debug info about dimensions to the log. + */ static void log_dim_info(NC_VAR_INFO_T *var, hsize_t *fdims, hsize_t *fmaxdims, hsize_t *start, hsize_t *count) { - int d2; + int d2; - /* Print some debugging info... */ - LOG((4, "%s: var name %s ndims %d", __func__, var->name, var->ndims)); - LOG((4, "File space, and requested:")); - for (d2 = 0; d2 < var->ndims; d2++) - { + /* Print some debugging info... */ + LOG((4, "%s: var name %s ndims %d", __func__, var->name, var->ndims)); + LOG((4, "File space, and requested:")); + for (d2 = 0; d2 < var->ndims; d2++) + { LOG((4, "fdims[%d]=%Ld fmaxdims[%d]=%Ld", d2, fdims[d2], d2, fmaxdims[d2])); LOG((4, "start[%d]=%Ld count[%d]=%Ld", d2, start[d2], d2, count[d2])); - } + } } #endif /* LOGGING */ #ifdef USE_PARALLEL4 +/** + * @internal Set the parallel access for a var (collective + * vs. independent). + * + * @param h5 Pointer to HDF5 file info struct. + * @param var Pointer to var info struct. + * @param xfer_plistid H5FD_MPIO_COLLECTIVE or H5FD_MPIO_INDEPENDENT. + * + * @returns NC_NOERR No error. + * @author Ed Hartnett + */ static int set_par_access(NC_HDF5_FILE_INFO_T *h5, NC_VAR_INFO_T *var, hid_t xfer_plistid) { - /* If netcdf is built with parallel I/O, then parallel access can - * be used, and, if this file was opened or created for parallel - * access, we need to set the transfer mode. */ - if (h5->parallel) - { + /* If netcdf is built with parallel I/O, then parallel access can + * be used, and, if this file was opened or created for parallel + * access, we need to set the transfer mode. */ + if (h5->parallel) + { H5FD_mpio_xfer_t hdf5_xfer_mode; /* Decide on collective or independent. */ hdf5_xfer_mode = (var->parallel_access != NC_INDEPENDENT) ? - H5FD_MPIO_COLLECTIVE : H5FD_MPIO_INDEPENDENT; + H5FD_MPIO_COLLECTIVE : H5FD_MPIO_INDEPENDENT; /* Set the mode in the transfer property list. */ if (H5Pset_dxpl_mpio(xfer_plistid, hdf5_xfer_mode) < 0) - return NC_EPARINIT; + return NC_EPARINIT; LOG((4, "%s: %d H5FD_MPIO_COLLECTIVE: %d H5FD_MPIO_INDEPENDENT: %d", __func__, (int)hdf5_xfer_mode, H5FD_MPIO_COLLECTIVE, H5FD_MPIO_INDEPENDENT)); - } - return NC_NOERR; + } + return NC_NOERR; } #endif -/* Write an array of data to a variable. When it comes right down to - * it, this is what netCDF-4 is all about, this is *the* function, the - * big enchilda, the grand poo-bah, the alpha dog, the head honcho, - * the big cheese, the mighty kahuna, the top bananna, the high - * muckity-muck, numero uno. Well, you get the idea. */ +/** + * @internal Write an array of data to a variable. + * + * @param nc Pointer to the file NC struct. + * @param ncid File ID. + * @param varid Variable ID. + * @param startp Array of start indicies. + * @param countp Array of counts. + * @param mem_nc_type The type of the data in memory. + * @param is_long True only if NC_LONG is the memory type. + * @param data The data to be written. + * + * @returns ::NC_NOERR No error. + * @returns ::NC_EBADID Bad ncid. + * @returns ::NC_ENOTVAR Var not found. + * @returns ::NC_EHDFERR HDF5 function returned error. + * @returns ::NC_EINVALCOORDS Incorrect start. + * @returns ::NC_EEDGE Incorrect start/count. + * @returns ::NC_ENOMEM Out of memory. + * @returns ::NC_EMPI MPI library error (parallel only) + * @returns ::NC_ECANTEXTEND Can't extend dimension for write. + * @returns ::NC_ERANGE Data conversion error. + * @author Ed Hartnett + */ int nc4_put_vara(NC *nc, int ncid, int varid, const size_t *startp, const size_t *countp, nc_type mem_nc_type, int is_long, void *data) { - NC_GRP_INFO_T *grp; - NC_HDF5_FILE_INFO_T *h5; - NC_VAR_INFO_T *var; - NC_DIM_INFO_T *dim; - hid_t file_spaceid = 0, mem_spaceid = 0, xfer_plistid = 0; - long long unsigned xtend_size[NC_MAX_VAR_DIMS]; - hsize_t fdims[NC_MAX_VAR_DIMS], fmaxdims[NC_MAX_VAR_DIMS]; - hsize_t start[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS]; - char *name_to_use; - int need_to_extend = 0; + NC_GRP_INFO_T *grp; + NC_HDF5_FILE_INFO_T *h5; + NC_VAR_INFO_T *var; + NC_DIM_INFO_T *dim; + hid_t file_spaceid = 0, mem_spaceid = 0, xfer_plistid = 0; + long long unsigned xtend_size[NC_MAX_VAR_DIMS]; + hsize_t fdims[NC_MAX_VAR_DIMS], fmaxdims[NC_MAX_VAR_DIMS]; + hsize_t start[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS]; + char *name_to_use; + int need_to_extend = 0; #ifdef USE_PARALLEL4 - int extend_possible = 0; + int extend_possible = 0; #endif - int retval = NC_NOERR, range_error = 0, i, d2; - void *bufr = NULL; + int retval = NC_NOERR, range_error = 0, i, d2; + void *bufr = NULL; #ifndef HDF5_CONVERT - int need_to_convert = 0; - size_t len = 1; + int need_to_convert = 0; + size_t len = 1; #endif #ifdef HDF5_CONVERT - hid_t mem_typeid = 0; + hid_t mem_typeid = 0; #endif - /* Find our metadata for this file, group, and var. */ - assert(nc); - if ((retval = nc4_find_g_var_nc(nc, ncid, varid, &grp, &var))) - return retval; - h5 = NC4_DATA(nc); - assert(grp && h5 && var && var->name); + /* Find our metadata for this file, group, and var. */ + assert(nc); + if ((retval = nc4_find_g_var_nc(nc, ncid, varid, &grp, &var))) + return retval; + h5 = NC4_DATA(nc); + assert(grp && h5 && var && var->name); - LOG((3, "%s: var->name %s mem_nc_type %d is_long %d", - __func__, var->name, mem_nc_type, is_long)); + LOG((3, "%s: var->name %s mem_nc_type %d is_long %d", + __func__, var->name, mem_nc_type, is_long)); - /* Check some stuff about the type and the file. If the file must - * be switched from define mode, it happens here. */ - if ((retval = check_for_vara(&mem_nc_type, var, h5))) - return retval; + /* Check some stuff about the type and the file. If the file must + * be switched from define mode, it happens here. */ + if ((retval = check_for_vara(&mem_nc_type, var, h5))) + return retval; - /* Convert from size_t and ptrdiff_t to hssize_t, and hsize_t. */ - for (i = 0; i < var->ndims; i++) - { + /* Convert from size_t and ptrdiff_t to hssize_t, and hsize_t. */ + for (i = 0; i < var->ndims; i++) + { start[i] = startp[i]; count[i] = countp[i]; - } - - /* Open this dataset if necessary, also checking for a weird case: - * a non-coordinate (and non-scalar) variable that has the same - * name as a dimension. */ - if (var->hdf5_name && strlen(var->hdf5_name) >= strlen(NON_COORD_PREPEND) && - strncmp(var->hdf5_name, NON_COORD_PREPEND, strlen(NON_COORD_PREPEND)) == 0 && - var->ndims) - name_to_use = var->hdf5_name; - else - name_to_use = var->name; - if (!var->hdf_datasetid) - if ((var->hdf_datasetid = H5Dopen2(grp->hdf_grpid, name_to_use, H5P_DEFAULT)) < 0) - return NC_ENOTVAR; - - /* Get file space of data. */ - if ((file_spaceid = H5Dget_space(var->hdf_datasetid)) < 0) - BAIL(NC_EHDFERR); + } + + /* Open this dataset if necessary, also checking for a weird case: + * a non-coordinate (and non-scalar) variable that has the same + * name as a dimension. */ + if (var->hdf5_name && strlen(var->hdf5_name) >= strlen(NON_COORD_PREPEND) && + strncmp(var->hdf5_name, NON_COORD_PREPEND, strlen(NON_COORD_PREPEND)) == 0 && + var->ndims) + name_to_use = var->hdf5_name; + else + name_to_use = var->name; + if (!var->hdf_datasetid) + if ((var->hdf_datasetid = H5Dopen2(grp->hdf_grpid, name_to_use, H5P_DEFAULT)) < 0) + return NC_ENOTVAR; + + /* Get file space of data. */ + if ((file_spaceid = H5Dget_space(var->hdf_datasetid)) < 0) + BAIL(NC_EHDFERR); - /* Check to ensure the user selection is - * valid. H5Sget_simple_extent_dims gets the sizes of all the dims - * and put them in fdims. */ - if (H5Sget_simple_extent_dims(file_spaceid, fdims, fmaxdims) < 0) - BAIL(NC_EHDFERR); + /* Check to ensure the user selection is + * valid. H5Sget_simple_extent_dims gets the sizes of all the dims + * and put them in fdims. */ + if (H5Sget_simple_extent_dims(file_spaceid, fdims, fmaxdims) < 0) + BAIL(NC_EHDFERR); #ifdef LOGGING - log_dim_info(var, fdims, fmaxdims, start, count); + log_dim_info(var, fdims, fmaxdims, start, count); #endif - /* Check dimension bounds. Remember that unlimited dimensions can - * put data beyond their current length. */ - for (d2 = 0; d2 < var->ndims; d2++) - { + /* Check dimension bounds. Remember that unlimited dimensions can + * put data beyond their current length. */ + for (d2 = 0; d2 < var->ndims; d2++) + { dim = var->dim[d2]; assert(dim && dim->dimid == var->dimids[d2]); if (!dim->unlimited) - { + { #ifdef RELAX_COORD_BOUND - if (start[d2] > (hssize_t)fdims[d2] || - (start[d2] == (hssize_t)fdims[d2] && count[d2] > 0)) + if (start[d2] > (hssize_t)fdims[d2] || + (start[d2] == (hssize_t)fdims[d2] && count[d2] > 0)) #else - if (start[d2] >= (hssize_t)fdims[d2]) + if (start[d2] >= (hssize_t)fdims[d2]) #endif - BAIL_QUIET(NC_EINVALCOORDS); - if (start[d2] + count[d2] > fdims[d2]) + BAIL_QUIET(NC_EINVALCOORDS); + if (start[d2] + count[d2] > fdims[d2]) BAIL_QUIET(NC_EEDGE); - } - } - - /* Now you would think that no one would be crazy enough to write - a scalar dataspace with one of the array function calls, but you - would be wrong. So let's check to see if the dataset is - scalar. If it is, we won't try to set up a hyperslab. */ - if (H5Sget_simple_extent_type(file_spaceid) == H5S_SCALAR) - { + } + } + + /* Now you would think that no one would be crazy enough to write + a scalar dataspace with one of the array function calls, but you + would be wrong. So let's check to see if the dataset is + scalar. If it is, we won't try to set up a hyperslab. */ + if (H5Sget_simple_extent_type(file_spaceid) == H5S_SCALAR) + { if ((mem_spaceid = H5Screate(H5S_SCALAR)) < 0) - BAIL(NC_EHDFERR); - } - else - { + BAIL(NC_EHDFERR); + } + else + { if (H5Sselect_hyperslab(file_spaceid, H5S_SELECT_SET, start, NULL, count, NULL) < 0) - BAIL(NC_EHDFERR); + BAIL(NC_EHDFERR); /* Create a space for the memory, just big enough to hold the slab we want. */ if ((mem_spaceid = H5Screate_simple(var->ndims, count, NULL)) < 0) - BAIL(NC_EHDFERR); - } + BAIL(NC_EHDFERR); + } #ifndef HDF5_CONVERT - /* Are we going to convert any data? (No converting of compound or - * opaque types.) */ - if ((mem_nc_type != var->type_info->nc_typeid || (var->type_info->nc_typeid == NC_INT && is_long)) && - mem_nc_type != NC_COMPOUND && mem_nc_type != NC_OPAQUE) - { + /* Are we going to convert any data? (No converting of compound or + * opaque types.) */ + if ((mem_nc_type != var->type_info->nc_typeid || (var->type_info->nc_typeid == NC_INT && is_long)) && + mem_nc_type != NC_COMPOUND && mem_nc_type != NC_OPAQUE) + { size_t file_type_size; /* We must convert - allocate a buffer. */ need_to_convert++; if (var->ndims) - for (d2=0; d2ndims; d2++) - len *= countp[d2]; + for (d2=0; d2ndims; d2++) + len *= countp[d2]; LOG((4, "converting data for var %s type=%d len=%d", var->name, var->type_info->nc_typeid, len)); @@ -682,339 +796,364 @@ nc4_put_vara(NC *nc, int ncid, int varid, const size_t *startp, * the data in the file. If we're writing, we need bufr to be * big enough to hold all the data in the file's type. */ if(len > 0) - if (!(bufr = malloc(len * file_type_size))) - BAIL(NC_ENOMEM); - } - else + if (!(bufr = malloc(len * file_type_size))) + BAIL(NC_ENOMEM); + } + else #endif /* ifndef HDF5_CONVERT */ - bufr = data; + bufr = data; #ifdef HDF5_CONVERT - /* Get the HDF type of the data in memory. */ - if ((retval = nc4_get_hdf_typeid(h5, mem_nc_type, &mem_typeid, - var->type_info->endianness))) - BAIL(retval); + /* Get the HDF type of the data in memory. */ + if ((retval = nc4_get_hdf_typeid(h5, mem_nc_type, &mem_typeid, + var->type_info->endianness))) + BAIL(retval); #endif - /* Create the data transfer property list. */ - if ((xfer_plistid = H5Pcreate(H5P_DATASET_XFER)) < 0) - BAIL(NC_EHDFERR); + /* Create the data transfer property list. */ + if ((xfer_plistid = H5Pcreate(H5P_DATASET_XFER)) < 0) + BAIL(NC_EHDFERR); - /* Apply the callback function which will detect range - * errors. Which one to call depends on the length of the - * destination buffer type. */ + /* Apply the callback function which will detect range + * errors. Which one to call depends on the length of the + * destination buffer type. */ #ifdef HDF5_CONVERT - if (H5Pset_type_conv_cb(xfer_plistid, except_func, &range_error) < 0) - BAIL(NC_EHDFERR); + if (H5Pset_type_conv_cb(xfer_plistid, except_func, &range_error) < 0) + BAIL(NC_EHDFERR); #endif #ifdef USE_PARALLEL4 - /* Set up parallel I/O, if needed. */ - if ((retval = set_par_access(h5, var, xfer_plistid))) - BAIL(retval); + /* Set up parallel I/O, if needed. */ + if ((retval = set_par_access(h5, var, xfer_plistid))) + BAIL(retval); #endif - /* Read/write this hyperslab into memory. */ - /* Does the dataset have to be extended? If it's already - extended to the required size, it will do no harm to reextend - it to that size. */ - if (var->ndims) - { + /* Read/write this hyperslab into memory. */ + /* Does the dataset have to be extended? If it's already + extended to the required size, it will do no harm to reextend + it to that size. */ + if (var->ndims) + { for (d2 = 0; d2 < var->ndims; d2++) - { - dim = var->dim[d2]; - assert(dim && dim->dimid == var->dimids[d2]); - if (dim->unlimited) - { + { + dim = var->dim[d2]; + assert(dim && dim->dimid == var->dimids[d2]); + if (dim->unlimited) + { #ifdef USE_PARALLEL4 - extend_possible = 1; + extend_possible = 1; #endif - if (start[d2] + count[d2] > fdims[d2]) - { - xtend_size[d2] = (long long unsigned)(start[d2] + count[d2]); - need_to_extend++; - } - else - xtend_size[d2] = (long long unsigned)fdims[d2]; - - if (start[d2] + count[d2] > dim->len) - { - dim->len = start[d2] + count[d2]; - dim->extended = NC_TRUE; - } + if (start[d2] + count[d2] > fdims[d2]) + { + xtend_size[d2] = (long long unsigned)(start[d2] + count[d2]); + need_to_extend++; } - else + else + xtend_size[d2] = (long long unsigned)fdims[d2]; + + if (start[d2] + count[d2] > dim->len) { - xtend_size[d2] = (long long unsigned)dim->len; + dim->len = start[d2] + count[d2]; + dim->extended = NC_TRUE; } - } + } + else + { + xtend_size[d2] = (long long unsigned)dim->len; + } + } #ifdef USE_PARALLEL4 /* Check if anyone wants to extend */ if (extend_possible && h5->parallel && NC_COLLECTIVE == var->parallel_access) - { - /* Form consensus opinion among all processes about whether to perform - * collective I/O - */ - if(MPI_SUCCESS != MPI_Allreduce(MPI_IN_PLACE, &need_to_extend, 1, MPI_INT, MPI_BOR, h5->comm)) + { + /* Form consensus opinion among all processes about whether to perform + * collective I/O + */ + if(MPI_SUCCESS != MPI_Allreduce(MPI_IN_PLACE, &need_to_extend, 1, MPI_INT, MPI_BOR, h5->comm)) BAIL(NC_EMPI); - } + } #endif /* USE_PARALLEL4 */ /* If we need to extend it, we also need a new file_spaceid to reflect the new size of the space. */ if (need_to_extend) - { - LOG((4, "extending dataset")); + { + LOG((4, "extending dataset")); #ifdef USE_PARALLEL4 - if (h5->parallel) - { - if(NC_COLLECTIVE != var->parallel_access) - BAIL(NC_ECANTEXTEND); - - /* Reach consensus about dimension sizes to extend to */ - if(MPI_SUCCESS != MPI_Allreduce(MPI_IN_PLACE, xtend_size, var->ndims, MPI_UNSIGNED_LONG_LONG, MPI_MAX, h5->comm)) - BAIL(NC_EMPI); - } + if (h5->parallel) + { + if(NC_COLLECTIVE != var->parallel_access) + BAIL(NC_ECANTEXTEND); + + /* Reach consensus about dimension sizes to extend to */ + if(MPI_SUCCESS != MPI_Allreduce(MPI_IN_PLACE, xtend_size, var->ndims, MPI_UNSIGNED_LONG_LONG, MPI_MAX, h5->comm)) + BAIL(NC_EMPI); + } #endif /* USE_PARALLEL4 */ - /* Convert xtend_size back to hsize_t for use with H5Dset_extent */ - for (d2 = 0; d2 < var->ndims; d2++) + /* Convert xtend_size back to hsize_t for use with H5Dset_extent */ + for (d2 = 0; d2 < var->ndims; d2++) fdims[d2] = (hsize_t)xtend_size[d2]; - if (H5Dset_extent(var->hdf_datasetid, fdims) < 0) + if (H5Dset_extent(var->hdf_datasetid, fdims) < 0) BAIL(NC_EHDFERR); - if (file_spaceid > 0 && H5Sclose(file_spaceid) < 0) + if (file_spaceid > 0 && H5Sclose(file_spaceid) < 0) BAIL2(NC_EHDFERR); - if ((file_spaceid = H5Dget_space(var->hdf_datasetid)) < 0) + if ((file_spaceid = H5Dget_space(var->hdf_datasetid)) < 0) BAIL(NC_EHDFERR); - if (H5Sselect_hyperslab(file_spaceid, H5S_SELECT_SET, - start, NULL, count, NULL) < 0) + if (H5Sselect_hyperslab(file_spaceid, H5S_SELECT_SET, + start, NULL, count, NULL) < 0) BAIL(NC_EHDFERR); - } - } + } + } #ifndef HDF5_CONVERT - /* Do we need to convert the data? */ - if (need_to_convert) - { + /* Do we need to convert the data? */ + if (need_to_convert) + { if ((retval = nc4_convert_type(data, bufr, mem_nc_type, var->type_info->nc_typeid, len, &range_error, var->fill_value, (h5->cmode & NC_CLASSIC_MODEL), is_long, 0))) - BAIL(retval); - } + BAIL(retval); + } #endif - /* Write the data. At last! */ - LOG((4, "about to H5Dwrite datasetid 0x%x mem_spaceid 0x%x " - "file_spaceid 0x%x", var->hdf_datasetid, mem_spaceid, file_spaceid)); - if (H5Dwrite(var->hdf_datasetid, var->type_info->hdf_typeid, - mem_spaceid, file_spaceid, xfer_plistid, bufr) < 0) - BAIL(NC_EHDFERR); - - /* Remember that we have written to this var so that Fill Value - * can't be set for it. */ - if (!var->written_to) - var->written_to = NC_TRUE; - - /* For strict netcdf-3 rules, ignore erange errors between UBYTE - * and BYTE types. */ - if ((h5->cmode & NC_CLASSIC_MODEL) && - (var->type_info->nc_typeid == NC_UBYTE || var->type_info->nc_typeid == NC_BYTE) && - (mem_nc_type == NC_UBYTE || mem_nc_type == NC_BYTE) && - range_error) - range_error = 0; - - exit: + /* Write the data. At last! */ + LOG((4, "about to H5Dwrite datasetid 0x%x mem_spaceid 0x%x " + "file_spaceid 0x%x", var->hdf_datasetid, mem_spaceid, file_spaceid)); + if (H5Dwrite(var->hdf_datasetid, var->type_info->hdf_typeid, + mem_spaceid, file_spaceid, xfer_plistid, bufr) < 0) + BAIL(NC_EHDFERR); + + /* Remember that we have written to this var so that Fill Value + * can't be set for it. */ + if (!var->written_to) + var->written_to = NC_TRUE; + + /* For strict netcdf-3 rules, ignore erange errors between UBYTE + * and BYTE types. */ + if ((h5->cmode & NC_CLASSIC_MODEL) && + (var->type_info->nc_typeid == NC_UBYTE || var->type_info->nc_typeid == NC_BYTE) && + (mem_nc_type == NC_UBYTE || mem_nc_type == NC_BYTE) && + range_error) + range_error = 0; + +exit: #ifdef HDF5_CONVERT - if (mem_typeid > 0 && H5Tclose(mem_typeid) < 0) - BAIL2(NC_EHDFERR); + if (mem_typeid > 0 && H5Tclose(mem_typeid) < 0) + BAIL2(NC_EHDFERR); #endif - if (file_spaceid > 0 && H5Sclose(file_spaceid) < 0) - BAIL2(NC_EHDFERR); - if (mem_spaceid > 0 && H5Sclose(mem_spaceid) < 0) - BAIL2(NC_EHDFERR); - if (xfer_plistid && (H5Pclose(xfer_plistid) < 0)) - BAIL2(NC_EPARINIT); + if (file_spaceid > 0 && H5Sclose(file_spaceid) < 0) + BAIL2(NC_EHDFERR); + if (mem_spaceid > 0 && H5Sclose(mem_spaceid) < 0) + BAIL2(NC_EHDFERR); + if (xfer_plistid && (H5Pclose(xfer_plistid) < 0)) + BAIL2(NC_EPARINIT); #ifndef HDF5_CONVERT - if (need_to_convert && bufr) free(bufr); + if (need_to_convert && bufr) free(bufr); #endif - /* If there was an error return it, otherwise return any potential - range error value. If none, return NC_NOERR as usual.*/ - if (retval) - return retval; - if (range_error) - return NC_ERANGE; - return NC_NOERR; + /* If there was an error return it, otherwise return any potential + range error value. If none, return NC_NOERR as usual.*/ + if (retval) + return retval; + if (range_error) + return NC_ERANGE; + return NC_NOERR; } +/** + * @internal Read an array of data from a variable. + * + * @param nc Pointer to the file NC struct. + * @param ncid File ID. + * @param varid Variable ID. + * @param startp Array of start indicies. + * @param countp Array of counts. + * @param mem_nc_type The type of the data in memory. (Convert to this + * type from file type.) + * @param is_long True only if NC_LONG is the memory type. + * @param data The data to be written. + * + * @returns ::NC_NOERR No error. + * @returns ::NC_EBADID Bad ncid. + * @returns ::NC_ENOTVAR Var not found. + * @returns ::NC_EHDFERR HDF5 function returned error. + * @returns ::NC_EINVALCOORDS Incorrect start. + * @returns ::NC_EEDGE Incorrect start/count. + * @returns ::NC_ENOMEM Out of memory. + * @returns ::NC_EMPI MPI library error (parallel only) + * @returns ::NC_ECANTEXTEND Can't extend dimension for write. + * @returns ::NC_ERANGE Data conversion error. + * @author Ed Hartnett + */ int nc4_get_vara(NC *nc, int ncid, int varid, const size_t *startp, const size_t *countp, nc_type mem_nc_type, int is_long, void *data) { - NC_GRP_INFO_T *grp; - NC_HDF5_FILE_INFO_T *h5; - NC_VAR_INFO_T *var; - NC_DIM_INFO_T *dim; - hid_t file_spaceid = 0, mem_spaceid = 0; - hid_t xfer_plistid = 0; - size_t file_type_size; - hsize_t *xtend_size = NULL, count[NC_MAX_VAR_DIMS]; - hsize_t fdims[NC_MAX_VAR_DIMS], fmaxdims[NC_MAX_VAR_DIMS]; - hsize_t start[NC_MAX_VAR_DIMS]; - char *name_to_use; - void *fillvalue = NULL; - int no_read = 0, provide_fill = 0; - int fill_value_size[NC_MAX_VAR_DIMS]; - int scalar = 0, retval = NC_NOERR, range_error = 0, i, d2; - void *bufr = NULL; + NC_GRP_INFO_T *grp; + NC_HDF5_FILE_INFO_T *h5; + NC_VAR_INFO_T *var; + NC_DIM_INFO_T *dim; + hid_t file_spaceid = 0, mem_spaceid = 0; + hid_t xfer_plistid = 0; + size_t file_type_size; + hsize_t *xtend_size = NULL, count[NC_MAX_VAR_DIMS]; + hsize_t fdims[NC_MAX_VAR_DIMS], fmaxdims[NC_MAX_VAR_DIMS]; + hsize_t start[NC_MAX_VAR_DIMS]; + char *name_to_use; + void *fillvalue = NULL; + int no_read = 0, provide_fill = 0; + int fill_value_size[NC_MAX_VAR_DIMS]; + int scalar = 0, retval = NC_NOERR, range_error = 0, i, d2; + void *bufr = NULL; #ifdef HDF5_CONVERT - hid_t mem_typeid = 0; + hid_t mem_typeid = 0; #endif #ifndef HDF5_CONVERT - int need_to_convert = 0; - size_t len = 1; + int need_to_convert = 0; + size_t len = 1; #endif - /* Find our metadata for this file, group, and var. */ - assert(nc); - if ((retval = nc4_find_g_var_nc(nc, ncid, varid, &grp, &var))) - return retval; - h5 = NC4_DATA(nc); - assert(grp && h5 && var && var->name); + /* Find our metadata for this file, group, and var. */ + assert(nc); + if ((retval = nc4_find_g_var_nc(nc, ncid, varid, &grp, &var))) + return retval; + h5 = NC4_DATA(nc); + assert(grp && h5 && var && var->name); - LOG((3, "%s: var->name %s mem_nc_type %d is_long %d", - __func__, var->name, mem_nc_type, is_long)); + LOG((3, "%s: var->name %s mem_nc_type %d is_long %d", + __func__, var->name, mem_nc_type, is_long)); - /* Check some stuff about the type and the file. */ - if ((retval = check_for_vara(&mem_nc_type, var, h5))) - return retval; + /* Check some stuff about the type and the file. */ + if ((retval = check_for_vara(&mem_nc_type, var, h5))) + return retval; - /* Convert from size_t and ptrdiff_t to hssize_t, and hsize_t. */ - for (i = 0; i < var->ndims; i++) - { + /* Convert from size_t and ptrdiff_t to hssize_t, and hsize_t. */ + for (i = 0; i < var->ndims; i++) + { start[i] = startp[i]; count[i] = countp[i]; - } - - /* Open this dataset if necessary, also checking for a weird case: - * a non-coordinate (and non-scalar) variable that has the same - * name as a dimension. */ - if (var->hdf5_name && strlen(var->hdf5_name) >= strlen(NON_COORD_PREPEND) && - strncmp(var->hdf5_name, NON_COORD_PREPEND, strlen(NON_COORD_PREPEND)) == 0 && - var->ndims) - name_to_use = var->hdf5_name; - else - name_to_use = var->name; - if (!var->hdf_datasetid) - if ((var->hdf_datasetid = H5Dopen2(grp->hdf_grpid, name_to_use, H5P_DEFAULT)) < 0) - return NC_ENOTVAR; - - /* Get file space of data. */ - if ((file_spaceid = H5Dget_space(var->hdf_datasetid)) < 0) - BAIL(NC_EHDFERR); + } + + /* Open this dataset if necessary, also checking for a weird case: + * a non-coordinate (and non-scalar) variable that has the same + * name as a dimension. */ + if (var->hdf5_name && strlen(var->hdf5_name) >= strlen(NON_COORD_PREPEND) && + strncmp(var->hdf5_name, NON_COORD_PREPEND, strlen(NON_COORD_PREPEND)) == 0 && + var->ndims) + name_to_use = var->hdf5_name; + else + name_to_use = var->name; + if (!var->hdf_datasetid) + if ((var->hdf_datasetid = H5Dopen2(grp->hdf_grpid, name_to_use, H5P_DEFAULT)) < 0) + return NC_ENOTVAR; + + /* Get file space of data. */ + if ((file_spaceid = H5Dget_space(var->hdf_datasetid)) < 0) + BAIL(NC_EHDFERR); - /* Check to ensure the user selection is - * valid. H5Sget_simple_extent_dims gets the sizes of all the dims - * and put them in fdims. */ - if (H5Sget_simple_extent_dims(file_spaceid, fdims, fmaxdims) < 0) - BAIL(NC_EHDFERR); + /* Check to ensure the user selection is + * valid. H5Sget_simple_extent_dims gets the sizes of all the dims + * and put them in fdims. */ + if (H5Sget_simple_extent_dims(file_spaceid, fdims, fmaxdims) < 0) + BAIL(NC_EHDFERR); #ifdef LOGGING - log_dim_info(var, fdims, fmaxdims, start, count); + log_dim_info(var, fdims, fmaxdims, start, count); #endif - /* Check dimension bounds. Remember that unlimited dimensions can - * put data beyond their current length. */ - for (d2 = 0; d2 < var->ndims; d2++) { - dim = var->dim[d2]; - assert(dim && dim->dimid == var->dimids[d2]); - if (dim->unlimited) + /* Check dimension bounds. Remember that unlimited dimensions can + * put data beyond their current length. */ + for (d2 = 0; d2 < var->ndims; d2++) { + dim = var->dim[d2]; + assert(dim && dim->dimid == var->dimids[d2]); + if (dim->unlimited) { - size_t ulen; + size_t ulen; - /* We can't go beyond the largest current extent of - the unlimited dim. */ - if ((retval = NC4_inq_dim(ncid, dim->dimid, NULL, &ulen))) - BAIL(retval); + /* We can't go beyond the largest current extent of + the unlimited dim. */ + if ((retval = NC4_inq_dim(ncid, dim->dimid, NULL, &ulen))) + BAIL(retval); - /* Check for out of bound requests. */ + /* Check for out of bound requests. */ #ifdef RELAX_COORD_BOUND - if (start[d2] > (hssize_t)ulen || - (start[d2] == (hssize_t)ulen && count[d2] > 0)) + if (start[d2] > (hssize_t)ulen || + (start[d2] == (hssize_t)ulen && count[d2] > 0)) #else - if (start[d2] >= (hssize_t)ulen && ulen > 0) + if (start[d2] >= (hssize_t)ulen && ulen > 0) #endif - BAIL_QUIET(NC_EINVALCOORDS); - if (start[d2] + count[d2] > ulen) - BAIL_QUIET(NC_EEDGE); - - /* Things get a little tricky here. If we're getting - a GET request beyond the end of this var's - current length in an unlimited dimension, we'll - later need to return the fill value for the - variable. */ - if (start[d2] >= (hssize_t)fdims[d2]) - fill_value_size[d2] = count[d2]; - else if (start[d2] + count[d2] > fdims[d2]) - fill_value_size[d2] = count[d2] - (fdims[d2] - start[d2]); - else - fill_value_size[d2] = 0; - count[d2] -= fill_value_size[d2]; - if (fill_value_size[d2]) - provide_fill++; + BAIL_QUIET(NC_EINVALCOORDS); + if (start[d2] + count[d2] > ulen) + BAIL_QUIET(NC_EEDGE); + + /* Things get a little tricky here. If we're getting + a GET request beyond the end of this var's + current length in an unlimited dimension, we'll + later need to return the fill value for the + variable. */ + if (start[d2] >= (hssize_t)fdims[d2]) + fill_value_size[d2] = count[d2]; + else if (start[d2] + count[d2] > fdims[d2]) + fill_value_size[d2] = count[d2] - (fdims[d2] - start[d2]); + else + fill_value_size[d2] = 0; + count[d2] -= fill_value_size[d2]; + if (fill_value_size[d2]) + provide_fill++; } - else + else { - /* Check for out of bound requests. */ + /* Check for out of bound requests. */ #ifdef RELAX_COORD_BOUND - if (start[d2] > (hssize_t)fdims[d2] || - (start[d2] == (hssize_t)fdims[d2] && count[d2] > 0)) + if (start[d2] > (hssize_t)fdims[d2] || + (start[d2] == (hssize_t)fdims[d2] && count[d2] > 0)) #else - if (start[d2] >= (hssize_t)fdims[d2]) + if (start[d2] >= (hssize_t)fdims[d2]) #endif - BAIL_QUIET(NC_EINVALCOORDS); - if (start[d2] + count[d2] > fdims[d2]) - BAIL_QUIET(NC_EEDGE); + BAIL_QUIET(NC_EINVALCOORDS); + if (start[d2] + count[d2] > fdims[d2]) + BAIL_QUIET(NC_EEDGE); - /* Set the fill value boundary */ - fill_value_size[d2] = count[d2]; + /* Set the fill value boundary */ + fill_value_size[d2] = count[d2]; } - } + } - /* A little quirk: if any of the count values are zero, don't - * read. */ - for (d2 = 0; d2 < var->ndims; d2++) - if (count[d2] == 0) - no_read++; + /* A little quirk: if any of the count values are zero, don't + * read. */ + for (d2 = 0; d2 < var->ndims; d2++) + if (count[d2] == 0) + no_read++; - /* Later on, we will need to know the size of this type in the - * file. */ - assert(var->type_info->size); - file_type_size = var->type_info->size; + /* Later on, we will need to know the size of this type in the + * file. */ + assert(var->type_info->size); + file_type_size = var->type_info->size; - if (!no_read) - { + if (!no_read) + { /* Now you would think that no one would be crazy enough to write a scalar dataspace with one of the array function calls, but you would be wrong. So let's check to see if the dataset is scalar. If it is, we won't try to set up a hyperslab. */ if (H5Sget_simple_extent_type(file_spaceid) == H5S_SCALAR) - { - if ((mem_spaceid = H5Screate(H5S_SCALAR)) < 0) + { + if ((mem_spaceid = H5Screate(H5S_SCALAR)) < 0) BAIL(NC_EHDFERR); - scalar++; - } + scalar++; + } else - { - if (H5Sselect_hyperslab(file_spaceid, H5S_SELECT_SET, - start, NULL, count, NULL) < 0) + { + if (H5Sselect_hyperslab(file_spaceid, H5S_SELECT_SET, + start, NULL, count, NULL) < 0) BAIL(NC_EHDFERR); - /* Create a space for the memory, just big enough to hold the slab - we want. */ - if ((mem_spaceid = H5Screate_simple(var->ndims, count, NULL)) < 0) + /* Create a space for the memory, just big enough to hold the slab + we want. */ + if ((mem_spaceid = H5Screate_simple(var->ndims, count, NULL)) < 0) BAIL(NC_EHDFERR); - } + } /* Fix bug when reading HDF5 files with variable of type * fixed-length string. We need to make it look like a @@ -1025,13 +1164,13 @@ nc4_get_vara(NC *nc, int ncid, int varid, const size_t *startp, if(var->type_info->nc_type_class == NC_STRING && H5Tget_size(var->type_info->hdf_typeid) > 1 && !H5Tis_variable_str(var->type_info->hdf_typeid)) { - hsize_t fstring_len; + hsize_t fstring_len; - if ((fstring_len = H5Tget_size(var->type_info->hdf_typeid)) == 0) - BAIL(NC_EHDFERR); - if (!(*(char **)data = malloc(1 + fstring_len))) - BAIL(NC_ENOMEM); - bufr = *(char **)data; + if ((fstring_len = H5Tget_size(var->type_info->hdf_typeid)) == 0) + BAIL(NC_EHDFERR); + if (!(*(char **)data = malloc(1 + fstring_len))) + BAIL(NC_ENOMEM); + bufr = *(char **)data; } #ifndef HDF5_CONVERT @@ -1039,57 +1178,57 @@ nc4_get_vara(NC *nc, int ncid, int varid, const size_t *startp, * opaque types.) */ if ((mem_nc_type != var->type_info->nc_typeid || (var->type_info->nc_typeid == NC_INT && is_long)) && mem_nc_type != NC_COMPOUND && mem_nc_type != NC_OPAQUE) - { - /* We must convert - allocate a buffer. */ - need_to_convert++; - if (var->ndims) + { + /* We must convert - allocate a buffer. */ + need_to_convert++; + if (var->ndims) for (d2 = 0; d2 < var->ndims; d2++) - len *= countp[d2]; - LOG((4, "converting data for var %s type=%d len=%d", var->name, - var->type_info->nc_typeid, len)); - - /* If we're reading, we need bufr to have enough memory to store - * the data in the file. If we're writing, we need bufr to be - * big enough to hold all the data in the file's type. */ - if(len > 0) + len *= countp[d2]; + LOG((4, "converting data for var %s type=%d len=%d", var->name, + var->type_info->nc_typeid, len)); + + /* If we're reading, we need bufr to have enough memory to store + * the data in the file. If we're writing, we need bufr to be + * big enough to hold all the data in the file's type. */ + if(len > 0) if (!(bufr = malloc(len * file_type_size))) - BAIL(NC_ENOMEM); - } + BAIL(NC_ENOMEM); + } else #endif /* ifndef HDF5_CONVERT */ - if(!bufr) - bufr = data; + if(!bufr) + bufr = data; /* Get the HDF type of the data in memory. */ #ifdef HDF5_CONVERT if ((retval = nc4_get_hdf_typeid(h5, mem_nc_type, &mem_typeid, var->type_info->endianness))) - BAIL(retval); + BAIL(retval); #endif /* Create the data transfer property list. */ if ((xfer_plistid = H5Pcreate(H5P_DATASET_XFER)) < 0) - BAIL(NC_EHDFERR); + BAIL(NC_EHDFERR); #ifdef HDF5_CONVERT /* Apply the callback function which will detect range * errors. Which one to call depends on the length of the * destination buffer type. */ if (H5Pset_type_conv_cb(xfer_plistid, except_func, &range_error) < 0) - BAIL(NC_EHDFERR); + BAIL(NC_EHDFERR); #endif #ifdef USE_PARALLEL4 /* Set up parallel I/O, if needed. */ if ((retval = set_par_access(h5, var, xfer_plistid))) - BAIL(retval); + BAIL(retval); #endif /* Read this hyperslab into memory. */ LOG((5, "About to H5Dread some data...")); if (H5Dread(var->hdf_datasetid, var->type_info->native_hdf_typeid, mem_spaceid, file_spaceid, xfer_plistid, bufr) < 0) - BAIL(NC_EHDFERR); + BAIL(NC_EHDFERR); #ifndef HDF5_CONVERT /* Eventually the block below will go away. Right now it's @@ -1098,20 +1237,20 @@ nc4_get_vara(NC *nc, int ncid, int varid, const size_t *startp, being added to HDF5 at the HDF5 World Hall of Coding right now, by a staff of thousands of programming gnomes. */ if (need_to_convert) - { - if ((retval = nc4_convert_type(bufr, data, var->type_info->nc_typeid, mem_nc_type, - len, &range_error, var->fill_value, - (h5->cmode & NC_CLASSIC_MODEL), 0, is_long))) + { + if ((retval = nc4_convert_type(bufr, data, var->type_info->nc_typeid, mem_nc_type, + len, &range_error, var->fill_value, + (h5->cmode & NC_CLASSIC_MODEL), 0, is_long))) BAIL(retval); - /* For strict netcdf-3 rules, ignore erange errors between UBYTE - * and BYTE types. */ - if ((h5->cmode & NC_CLASSIC_MODEL) && - (var->type_info->nc_typeid == NC_UBYTE || var->type_info->nc_typeid == NC_BYTE) && - (mem_nc_type == NC_UBYTE || mem_nc_type == NC_BYTE) && - range_error) + /* For strict netcdf-3 rules, ignore erange errors between UBYTE + * and BYTE types. */ + if ((h5->cmode & NC_CLASSIC_MODEL) && + (var->type_info->nc_typeid == NC_UBYTE || var->type_info->nc_typeid == NC_BYTE) && + (mem_nc_type == NC_UBYTE || mem_nc_type == NC_BYTE) && + range_error) range_error = 0; - } + } #endif /* For strict netcdf-3 rules, ignore erange errors between UBYTE @@ -1120,459 +1259,508 @@ nc4_get_vara(NC *nc, int ncid, int varid, const size_t *startp, (var->type_info->nc_typeid == NC_UBYTE || var->type_info->nc_typeid == NC_BYTE) && (mem_nc_type == NC_UBYTE || mem_nc_type == NC_BYTE) && range_error) - range_error = 0; + range_error = 0; - } /* endif ! no_read */ + } /* endif ! no_read */ - else { + else { #ifdef USE_PARALLEL4 /* Start block contributed by HDF group. */ - /* For collective IO read, some processes may not have any element for reading. - Collective requires all processes to participate, so we use H5Sselect_none - for these processes. */ - if(var->parallel_access == NC_COLLECTIVE) { - - /* Create the data transfer property list. */ - if ((xfer_plistid = H5Pcreate(H5P_DATASET_XFER)) < 0) - BAIL(NC_EHDFERR); - - if ((retval = set_par_access(h5, var, xfer_plistid))) - BAIL(retval); - - if (H5Sselect_none(file_spaceid)<0) - BAIL(NC_EHDFERR); - - /* Since no element will be selected, we just get the memory space the same as the file space. - */ - if((mem_spaceid = H5Dget_space(var->hdf_datasetid))<0) - BAIL(NC_EHDFERR); - if (H5Sselect_none(mem_spaceid)<0) - BAIL(NC_EHDFERR); - - /* Read this hyperslab into memory. */ - LOG((5, "About to H5Dread some data...")); - if (H5Dread(var->hdf_datasetid, var->type_info->native_hdf_typeid, - mem_spaceid, file_spaceid, xfer_plistid, bufr) < 0) - BAIL(NC_EHDFERR); - } + /* For collective IO read, some processes may not have any element for reading. + Collective requires all processes to participate, so we use H5Sselect_none + for these processes. */ + if(var->parallel_access == NC_COLLECTIVE) { + + /* Create the data transfer property list. */ + if ((xfer_plistid = H5Pcreate(H5P_DATASET_XFER)) < 0) + BAIL(NC_EHDFERR); + + if ((retval = set_par_access(h5, var, xfer_plistid))) + BAIL(retval); + + if (H5Sselect_none(file_spaceid)<0) + BAIL(NC_EHDFERR); + + /* Since no element will be selected, we just get the memory space the same as the file space. + */ + if((mem_spaceid = H5Dget_space(var->hdf_datasetid))<0) + BAIL(NC_EHDFERR); + if (H5Sselect_none(mem_spaceid)<0) + BAIL(NC_EHDFERR); + + /* Read this hyperslab into memory. */ + LOG((5, "About to H5Dread some data...")); + if (H5Dread(var->hdf_datasetid, var->type_info->native_hdf_typeid, + mem_spaceid, file_spaceid, xfer_plistid, bufr) < 0) + BAIL(NC_EHDFERR); + } #endif /* End ifdef USE_PARALLEL4 */ - } - /* Now we need to fake up any further data that was asked for, - using the fill values instead. First skip past the data we - just read, if any. */ - if (!scalar && provide_fill) - { + } + /* Now we need to fake up any further data that was asked for, + using the fill values instead. First skip past the data we + just read, if any. */ + if (!scalar && provide_fill) + { void *filldata; size_t real_data_size = 0; size_t fill_len; /* Skip past the real data we've already read. */ if (!no_read) - for (real_data_size = file_type_size, d2 = 0; d2 < var->ndims; d2++) - real_data_size *= (count[d2] - start[d2]); + for (real_data_size = file_type_size, d2 = 0; d2 < var->ndims; d2++) + real_data_size *= (count[d2] - start[d2]); /* Get the fill value from the HDF5 variable. Memory will be * allocated. */ if (get_fill_value(h5, var, &fillvalue) < 0) - BAIL(NC_EHDFERR); + BAIL(NC_EHDFERR); /* How many fill values do we need? */ for (fill_len = 1, d2 = 0; d2 < var->ndims; d2++) - fill_len *= (fill_value_size[d2] ? fill_value_size[d2] : 1); + fill_len *= (fill_value_size[d2] ? fill_value_size[d2] : 1); /* Copy the fill value into the rest of the data buffer. */ filldata = (char *)data + real_data_size; for (i = 0; i < fill_len; i++) - { + { - if (var->type_info->nc_type_class == NC_STRING) + if (var->type_info->nc_type_class == NC_STRING) + { + if (*(char **)fillvalue) { - if (*(char **)fillvalue) - { - if (!(*(char **)filldata = strdup(*(char **)fillvalue))) - BAIL(NC_ENOMEM); - } - else - *(char **)filldata = NULL; + if (!(*(char **)filldata = strdup(*(char **)fillvalue))) + BAIL(NC_ENOMEM); } - else if(var->type_info->nc_type_class == NC_VLEN) { + else + *(char **)filldata = NULL; + } + else if(var->type_info->nc_type_class == NC_VLEN) { if(fillvalue) { - memcpy(filldata,fillvalue,file_type_size); + memcpy(filldata,fillvalue,file_type_size); } else { - *(char **)filldata = NULL; + *(char **)filldata = NULL; } - } else + } else memcpy(filldata, fillvalue, file_type_size); - filldata = (char *)filldata + file_type_size; - } - } + filldata = (char *)filldata + file_type_size; + } + } - exit: +exit: #ifdef HDF5_CONVERT - if (mem_typeid > 0 && H5Tclose(mem_typeid) < 0) - BAIL2(NC_EHDFERR); + if (mem_typeid > 0 && H5Tclose(mem_typeid) < 0) + BAIL2(NC_EHDFERR); #endif - if (file_spaceid > 0) - { + if (file_spaceid > 0) + { if (H5Sclose(file_spaceid) < 0) - BAIL2(NC_EHDFERR); - } - if (mem_spaceid > 0) - { + BAIL2(NC_EHDFERR); + } + if (mem_spaceid > 0) + { if (H5Sclose(mem_spaceid) < 0) - BAIL2(NC_EHDFERR); - } - if (xfer_plistid > 0) - { + BAIL2(NC_EHDFERR); + } + if (xfer_plistid > 0) + { if (H5Pclose(xfer_plistid) < 0) - BAIL2(NC_EHDFERR); - } + BAIL2(NC_EHDFERR); + } #ifndef HDF5_CONVERT - if (need_to_convert && bufr != NULL) - free(bufr); + if (need_to_convert && bufr != NULL) + free(bufr); #endif - if (xtend_size) - free(xtend_size); - if (fillvalue) - { + if (xtend_size) + free(xtend_size); + if (fillvalue) + { if (var->type_info->nc_type_class == NC_VLEN) - nc_free_vlen((nc_vlen_t *)fillvalue); + nc_free_vlen((nc_vlen_t *)fillvalue); else if (var->type_info->nc_type_class == NC_STRING && *(char **)fillvalue) - free(*(char **)fillvalue); + free(*(char **)fillvalue); free(fillvalue); - } - - /* If there was an error return it, otherwise return any potential - range error value. If none, return NC_NOERR as usual.*/ - if (retval) - return retval; - if (range_error) - return NC_ERANGE; - return NC_NOERR; + } + + /* If there was an error return it, otherwise return any potential + range error value. If none, return NC_NOERR as usual.*/ + if (retval) + return retval; + if (range_error) + return NC_ERANGE; + return NC_NOERR; } -/* Read or write an attribute. */ +/** + * @internal Write an attribute. + * + * @param grp Pointer to group info struct. + * @param varid Variable ID or NC_GLOBAL. + * @param att Pointer to attribute info struct. + * + * @returns ::NC_NOERR No error. + * @returns ::NC_ENOTVAR Variable not found. + * @returns ::NC_EPERM Read-only file. + * @returns ::NC_EHDFERR HDF5 returned error. + * @returns ::NC_EATTMETA HDF5 returned error with attribute calls. + * @author Ed Hartnett + */ static int put_att_grpa(NC_GRP_INFO_T *grp, int varid, NC_ATT_INFO_T *att) { - hid_t datasetid = 0, locid; - hid_t attid = 0, spaceid = 0, file_typeid = 0; - hsize_t dims[1]; /* netcdf attributes always 1-D. */ - htri_t attr_exists; - int retval = NC_NOERR; - void *data; - int phoney_data = 99; - - assert(att->name); - LOG((3, "%s: varid %d att->attnum %d att->name %s att->nc_typeid %d att->len %d", - __func__, varid, att->attnum, att->name, - att->nc_typeid, att->len)); - - /* If the file is read-only, return an error. */ - if (grp->nc4_info->no_write) - BAIL(NC_EPERM); - - /* Get the hid to attach the attribute to, or read it from. */ - if (varid == NC_GLOBAL) - locid = grp->hdf_grpid; - else - { + hid_t datasetid = 0, locid; + hid_t attid = 0, spaceid = 0, file_typeid = 0; + hsize_t dims[1]; /* netcdf attributes always 1-D. */ + htri_t attr_exists; + int retval = NC_NOERR; + void *data; + int phoney_data = 99; + + assert(att->name); + LOG((3, "%s: varid %d att->attnum %d att->name %s att->nc_typeid %d att->len %d", + __func__, varid, att->attnum, att->name, + att->nc_typeid, att->len)); + + /* If the file is read-only, return an error. */ + if (grp->nc4_info->no_write) + BAIL(NC_EPERM); + + /* Get the hid to attach the attribute to, or read it from. */ + if (varid == NC_GLOBAL) + locid = grp->hdf_grpid; + else + { if ((retval = nc4_open_var_grp2(grp, varid, &datasetid))) - BAIL(retval); + BAIL(retval); locid = datasetid; - } + } - /* Delete the att if it exists already. */ - if ((attr_exists = H5Aexists(locid, att->name)) < 0) - BAIL(NC_EHDFERR); - if (attr_exists) - { + /* Delete the att if it exists already. */ + if ((attr_exists = H5Aexists(locid, att->name)) < 0) + BAIL(NC_EHDFERR); + if (attr_exists) + { if (H5Adelete(locid, att->name) < 0) - BAIL(NC_EHDFERR); - } - - /* Get the length ready, and find the HDF type we'll be - * writing. */ - dims[0] = att->len; - if ((retval = nc4_get_hdf_typeid(grp->nc4_info, att->nc_typeid, - &file_typeid, 0))) - BAIL(retval); - - /* Even if the length is zero, HDF5 won't let me write with a - * NULL pointer. So if the length of the att is zero, point to - * some phoney data (which won't be written anyway.)*/ - if (!dims[0]) - data = &phoney_data; - else if (att->data) - data = att->data; - else if (att->stdata) - data = att->stdata; - else - data = att->vldata; - - /* NC_CHAR types require some extra work. The space ID is set to - * scalar, and the type is told how long the string is. If it's - * really zero length, set the size to 1. (The fact that it's - * really zero will be marked by the NULL dataspace, but HDF5 - * doesn't allow me to set the size of the type to zero.)*/ - if (att->nc_typeid == NC_CHAR) - { + BAIL(NC_EHDFERR); + } + + /* Get the length ready, and find the HDF type we'll be + * writing. */ + dims[0] = att->len; + if ((retval = nc4_get_hdf_typeid(grp->nc4_info, att->nc_typeid, + &file_typeid, 0))) + BAIL(retval); + + /* Even if the length is zero, HDF5 won't let me write with a + * NULL pointer. So if the length of the att is zero, point to + * some phoney data (which won't be written anyway.)*/ + if (!dims[0]) + data = &phoney_data; + else if (att->data) + data = att->data; + else if (att->stdata) + data = att->stdata; + else + data = att->vldata; + + /* NC_CHAR types require some extra work. The space ID is set to + * scalar, and the type is told how long the string is. If it's + * really zero length, set the size to 1. (The fact that it's + * really zero will be marked by the NULL dataspace, but HDF5 + * doesn't allow me to set the size of the type to zero.)*/ + if (att->nc_typeid == NC_CHAR) + { size_t string_size = dims[0]; if (!string_size) - { - string_size = 1; - if ((spaceid = H5Screate(H5S_NULL)) < 0) + { + string_size = 1; + if ((spaceid = H5Screate(H5S_NULL)) < 0) BAIL(NC_EATTMETA); - } + } else - { - if ((spaceid = H5Screate(H5S_SCALAR)) < 0) + { + if ((spaceid = H5Screate(H5S_SCALAR)) < 0) BAIL(NC_EATTMETA); - } + } if (H5Tset_size(file_typeid, string_size) < 0) - BAIL(NC_EATTMETA); + BAIL(NC_EATTMETA); if (H5Tset_strpad(file_typeid, H5T_STR_NULLTERM) < 0) - BAIL(NC_EATTMETA); - } - else - { + BAIL(NC_EATTMETA); + } + else + { if (!att->len) - { - if ((spaceid = H5Screate(H5S_NULL)) < 0) + { + if ((spaceid = H5Screate(H5S_NULL)) < 0) BAIL(NC_EATTMETA); - } + } else - { - if ((spaceid = H5Screate_simple(1, dims, NULL)) < 0) + { + if ((spaceid = H5Screate_simple(1, dims, NULL)) < 0) BAIL(NC_EATTMETA); - } - } - if ((attid = H5Acreate(locid, att->name, file_typeid, spaceid, - H5P_DEFAULT)) < 0) - BAIL(NC_EATTMETA); - - /* Write the values, (even if length is zero). */ - if (H5Awrite(attid, file_typeid, data) < 0) - BAIL(NC_EATTMETA); - - exit: - if (file_typeid && H5Tclose(file_typeid)) - BAIL2(NC_EHDFERR); - if (attid > 0 && H5Aclose(attid) < 0) - BAIL2(NC_EHDFERR); - if (spaceid > 0 && H5Sclose(spaceid) < 0) - BAIL2(NC_EHDFERR); - return retval; + } + } + if ((attid = H5Acreate(locid, att->name, file_typeid, spaceid, + H5P_DEFAULT)) < 0) + BAIL(NC_EATTMETA); + + /* Write the values, (even if length is zero). */ + if (H5Awrite(attid, file_typeid, data) < 0) + BAIL(NC_EATTMETA); + +exit: + if (file_typeid && H5Tclose(file_typeid)) + BAIL2(NC_EHDFERR); + if (attid > 0 && H5Aclose(attid) < 0) + BAIL2(NC_EHDFERR); + if (spaceid > 0 && H5Sclose(spaceid) < 0) + BAIL2(NC_EHDFERR); + return retval; } -/* Write all the dirty atts in an attlist. */ +/** + * @internal Write all the dirty atts in an attlist. + * + * @param attlist Pointer to the list if attributes. + * @param varid Variable ID. + * @param grp Pointer to group info struct. + * + * @returns NC_NOERR No error. + * @returns NC_EHDFERR HDF5 returned an error. + * @author Ed Hartnett +*/ static int write_attlist(NC_ATT_INFO_T *attlist, int varid, NC_GRP_INFO_T *grp) { - NC_ATT_INFO_T *att; - int retval; + NC_ATT_INFO_T *att; + int retval; - for (att = attlist; att; att = att->l.next) - { + for (att = attlist; att; att = att->l.next) + { if (att->dirty) - { - LOG((4, "%s: writing att %s to varid %d", __func__, att->name, varid)); - if ((retval = put_att_grpa(grp, varid, att))) + { + LOG((4, "%s: writing att %s to varid %d", __func__, att->name, varid)); + if ((retval = put_att_grpa(grp, varid, att))) return retval; - att->dirty = NC_FALSE; - att->created = NC_TRUE; - } - } - return NC_NOERR; + att->dirty = NC_FALSE; + att->created = NC_TRUE; + } + } + return NC_NOERR; } -/* This function is a bit of a hack. Turns out that HDF5 dimension - * scales cannot themselves have scales attached. This leaves - * multidimensional coordinate variables hosed. So this function - * writes a special attribute for such a variable, which has the ids - * of all the dimensions for that coordinate variable. This sucks, - * really. But that's the way the cookie crumbles. Better luck next - * time. This function also contains a new way of dealing with HDF5 - * error handling, abandoning the BAIL macros for a more organic and - * natural approach, made with whole grains, and locally-grown - * vegetables. */ +/** + * @internal This function is a bit of a hack. Turns out that HDF5 + * dimension scales cannot themselves have scales attached. This + * leaves multidimensional coordinate variables hosed. So this + * function writes a special attribute for such a variable, which has + * the ids of all the dimensions for that coordinate variable. This + * sucks, really. But that's the way the cookie crumbles. Better luck + * next time. This function also contains a new way of dealing with + * HDF5 error handling, abandoning the BAIL macros for a more organic + * and natural approach, made with whole grains, and locally-grown + * vegetables. + * + * @param var Pointer to var info struct. + * + * @returns NC_NOERR No error. + * @returns NC_EHDFERR HDF5 returned an error. + * @author Ed Hartnett + */ static int write_coord_dimids(NC_VAR_INFO_T *var) { - hsize_t coords_len[1]; - hid_t c_spaceid = -1, c_attid = -1; - int ret = 0; - - /* Write our attribute. */ - coords_len[0] = var->ndims; - if ((c_spaceid = H5Screate_simple(1, coords_len, coords_len)) < 0) ret++; - if (!ret && (c_attid = H5Acreate(var->hdf_datasetid, COORDINATES, H5T_NATIVE_INT, - c_spaceid, H5P_DEFAULT)) < 0) ret++; - if (!ret && H5Awrite(c_attid, H5T_NATIVE_INT, var->dimids) < 0) ret++; - - /* Close up shop. */ - if (c_spaceid > 0 && H5Sclose(c_spaceid) < 0) ret++; - if (c_attid > 0 && H5Aclose(c_attid) < 0) ret++; - return ret ? NC_EHDFERR : 0; + hsize_t coords_len[1]; + hid_t c_spaceid = -1, c_attid = -1; + int ret = 0; + + /* Write our attribute. */ + coords_len[0] = var->ndims; + if ((c_spaceid = H5Screate_simple(1, coords_len, coords_len)) < 0) ret++; + if (!ret && (c_attid = H5Acreate(var->hdf_datasetid, COORDINATES, H5T_NATIVE_INT, + c_spaceid, H5P_DEFAULT)) < 0) ret++; + if (!ret && H5Awrite(c_attid, H5T_NATIVE_INT, var->dimids) < 0) ret++; + + /* Close up shop. */ + if (c_spaceid > 0 && H5Sclose(c_spaceid) < 0) ret++; + if (c_attid > 0 && H5Aclose(c_attid) < 0) ret++; + return ret ? NC_EHDFERR : 0; } -/* Write a special attribute for the netCDF-4 dimension ID. */ +/** + * @internal Write a special attribute for the netCDF-4 dimension ID. + * + * @param datasetid HDF5 datasset ID. + * @param dimid NetCDF dimension ID. + * + * @returns NC_NOERR No error. + * @returns NC_EHDFERR HDF5 returned an error. + * @author Ed Hartnett +*/ static int write_netcdf4_dimid(hid_t datasetid, int dimid) { - hid_t dimid_spaceid, dimid_attid; - htri_t attr_exists; - - /* Create the space. */ - if ((dimid_spaceid = H5Screate(H5S_SCALAR)) < 0) - return NC_EHDFERR; - - /* Does the attribute already exist? If so, don't try to create it. */ - if ((attr_exists = H5Aexists(datasetid, NC_DIMID_ATT_NAME)) < 0) - return NC_EHDFERR; - if (attr_exists) - dimid_attid = H5Aopen_by_name(datasetid, ".", NC_DIMID_ATT_NAME, - H5P_DEFAULT, H5P_DEFAULT); - else - /* Create the attribute if needed. */ - dimid_attid = H5Acreate(datasetid, NC_DIMID_ATT_NAME, - H5T_NATIVE_INT, dimid_spaceid, H5P_DEFAULT); - if (dimid_attid < 0) - return NC_EHDFERR; - - - /* Write it. */ - LOG((4, "%s: writing secret dimid %d", __func__, dimid)); - if (H5Awrite(dimid_attid, H5T_NATIVE_INT, &dimid) < 0) - return NC_EHDFERR; - - /* Close stuff*/ - if (H5Sclose(dimid_spaceid) < 0) - return NC_EHDFERR; - if (H5Aclose(dimid_attid) < 0) - return NC_EHDFERR; - - return NC_NOERR; + hid_t dimid_spaceid, dimid_attid; + htri_t attr_exists; + + /* Create the space. */ + if ((dimid_spaceid = H5Screate(H5S_SCALAR)) < 0) + return NC_EHDFERR; + + /* Does the attribute already exist? If so, don't try to create it. */ + if ((attr_exists = H5Aexists(datasetid, NC_DIMID_ATT_NAME)) < 0) + return NC_EHDFERR; + if (attr_exists) + dimid_attid = H5Aopen_by_name(datasetid, ".", NC_DIMID_ATT_NAME, + H5P_DEFAULT, H5P_DEFAULT); + else + /* Create the attribute if needed. */ + dimid_attid = H5Acreate(datasetid, NC_DIMID_ATT_NAME, + H5T_NATIVE_INT, dimid_spaceid, H5P_DEFAULT); + if (dimid_attid < 0) + return NC_EHDFERR; + + + /* Write it. */ + LOG((4, "%s: writing secret dimid %d", __func__, dimid)); + if (H5Awrite(dimid_attid, H5T_NATIVE_INT, &dimid) < 0) + return NC_EHDFERR; + + /* Close stuff*/ + if (H5Sclose(dimid_spaceid) < 0) + return NC_EHDFERR; + if (H5Aclose(dimid_attid) < 0) + return NC_EHDFERR; + + return NC_NOERR; } -/* This function creates the HDF5 dataset for a variable. */ +/** + * @internal This function creates the HDF5 dataset for a variable. + * + * @param grp Pointer to group info struct. + * @param var Pointer to variable info struct. + * @param write_dimid True to write dimid. + * + * @return ::NC_NOERR + * @author Ed Hartnett +*/ static int var_create_dataset(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, nc_bool_t write_dimid) { - hid_t plistid = 0, access_plistid = 0, typeid = 0, spaceid = 0; - hsize_t chunksize[H5S_MAX_RANK], dimsize[H5S_MAX_RANK], maxdimsize[H5S_MAX_RANK]; - int d; - void *fillp = NULL; - NC_DIM_INFO_T *dim = NULL; - char *name_to_use; - int retval = NC_NOERR; - - LOG((3, "%s:: name %s", __func__, var->name)); - - /* Scalar or not, we need a creation property list. */ - if ((plistid = H5Pcreate(H5P_DATASET_CREATE)) < 0) - BAIL(NC_EHDFERR); - if ((access_plistid = H5Pcreate(H5P_DATASET_ACCESS)) < 0) - BAIL(NC_EHDFERR); - - /* RJ: this suppose to be FALSE that is defined in H5 private.h as 0 */ - if (H5Pset_obj_track_times(plistid,0)<0) - BAIL(NC_EHDFERR); - - /* Find the HDF5 type of the dataset. */ - if ((retval = nc4_get_hdf_typeid(grp->nc4_info, var->type_info->nc_typeid, &typeid, - var->type_info->endianness))) - BAIL(retval); - - /* Figure out what fill value to set, if any. */ - if (var->no_fill) - { + hid_t plistid = 0, access_plistid = 0, typeid = 0, spaceid = 0; + hsize_t chunksize[H5S_MAX_RANK], dimsize[H5S_MAX_RANK], maxdimsize[H5S_MAX_RANK]; + int d; + void *fillp = NULL; + NC_DIM_INFO_T *dim = NULL; + char *name_to_use; + int retval = NC_NOERR; + + LOG((3, "%s:: name %s", __func__, var->name)); + + /* Scalar or not, we need a creation property list. */ + if ((plistid = H5Pcreate(H5P_DATASET_CREATE)) < 0) + BAIL(NC_EHDFERR); + if ((access_plistid = H5Pcreate(H5P_DATASET_ACCESS)) < 0) + BAIL(NC_EHDFERR); + + /* RJ: this suppose to be FALSE that is defined in H5 private.h as 0 */ + if (H5Pset_obj_track_times(plistid,0)<0) + BAIL(NC_EHDFERR); + + /* Find the HDF5 type of the dataset. */ + if ((retval = nc4_get_hdf_typeid(grp->nc4_info, var->type_info->nc_typeid, &typeid, + var->type_info->endianness))) + BAIL(retval); + + /* Figure out what fill value to set, if any. */ + if (var->no_fill) + { /* Required to truly turn HDF5 fill values off */ if (H5Pset_fill_time(plistid, H5D_FILL_TIME_NEVER) < 0) - BAIL(NC_EHDFERR); - } - else - { + BAIL(NC_EHDFERR); + } + else + { if ((retval = get_fill_value(grp->nc4_info, var, &fillp))) - BAIL(retval); + BAIL(retval); /* If there is a fill value, set it. */ if (fillp) - { - if (var->type_info->nc_type_class == NC_STRING) - { - if (H5Pset_fill_value(plistid, typeid, fillp) < 0) - BAIL(NC_EHDFERR); - } - else + { + if (var->type_info->nc_type_class == NC_STRING) + { + if (H5Pset_fill_value(plistid, typeid, fillp) < 0) + BAIL(NC_EHDFERR); + } + else + { + /* The fill value set in HDF5 must always be presented as + * a native type, even if the endianness for this dataset + * is non-native. HDF5 will translate the fill value to + * the target endiannesss. */ + hid_t fill_typeid = 0; + + if ((retval = nc4_get_hdf_typeid(grp->nc4_info, var->type_info->nc_typeid, &fill_typeid, + NC_ENDIAN_NATIVE))) + BAIL(retval); + if (H5Pset_fill_value(plistid, fill_typeid, fillp) < 0) { - /* The fill value set in HDF5 must always be presented as - * a native type, even if the endianness for this dataset - * is non-native. HDF5 will translate the fill value to - * the target endiannesss. */ - hid_t fill_typeid = 0; - - if ((retval = nc4_get_hdf_typeid(grp->nc4_info, var->type_info->nc_typeid, &fill_typeid, - NC_ENDIAN_NATIVE))) - BAIL(retval); - if (H5Pset_fill_value(plistid, fill_typeid, fillp) < 0) - { - if (H5Tclose(fill_typeid) < 0) - BAIL(NC_EHDFERR); + if (H5Tclose(fill_typeid) < 0) BAIL(NC_EHDFERR); - } - if (H5Tclose(fill_typeid) < 0) - BAIL(NC_EHDFERR); + BAIL(NC_EHDFERR); } - } - } - - /* If the user wants to shuffle the data, set that up now. */ - if (var->shuffle) { - if (H5Pset_shuffle(plistid) < 0) - BAIL(NC_EHDFERR); - } - - /* If the user wants to deflate the data, set that up now. */ - if (var->deflate) { - if (H5Pset_deflate(plistid, var->deflate_level) < 0) - BAIL(NC_EHDFERR); - } else if(var->filterid) { - /* Handle szip case here */ - if(var->filterid == H5Z_FILTER_SZIP) { - int options_mask; - int bits_per_pixel; - if(var->nparams != 2) - BAIL(NC_EFILTER); - options_mask = (int)var->params[0]; - bits_per_pixel = (int)var->params[1]; - if(H5Pset_szip(plistid, options_mask, bits_per_pixel) < 0) - BAIL(NC_EFILTER); - } else { - if(H5Pset_filter(plistid, var->filterid, H5Z_FLAG_MANDATORY, var->nparams, var->params) < 0) + if (H5Tclose(fill_typeid) < 0) + BAIL(NC_EHDFERR); + } + } + } + + /* If the user wants to shuffle the data, set that up now. */ + if (var->shuffle) { + if (H5Pset_shuffle(plistid) < 0) + BAIL(NC_EHDFERR); + } + + /* If the user wants to deflate the data, set that up now. */ + if (var->deflate) { + if (H5Pset_deflate(plistid, var->deflate_level) < 0) + BAIL(NC_EHDFERR); + } else if(var->filterid) { + /* Handle szip case here */ + if(var->filterid == H5Z_FILTER_SZIP) { + int options_mask; + int bits_per_pixel; + if(var->nparams != 2) BAIL(NC_EFILTER); - } - } - - /* If the user wants to fletcher error correcton, set that up now. */ - if (var->fletcher32) - if (H5Pset_fletcher32(plistid) < 0) - BAIL(NC_EHDFERR); - - /* If ndims non-zero, get info for all dimensions. We look up the - dimids and get the len of each dimension. We need this to create - the space for the dataset. In netCDF a dimension length of zero - means an unlimited dimension. */ - if (var->ndims) - { + options_mask = (int)var->params[0]; + bits_per_pixel = (int)var->params[1]; + if(H5Pset_szip(plistid, options_mask, bits_per_pixel) < 0) + BAIL(NC_EFILTER); + } else { + if(H5Pset_filter(plistid, var->filterid, H5Z_FLAG_MANDATORY, var->nparams, var->params) < 0) + BAIL(NC_EFILTER); + } + } + + /* If the user wants to fletcher error correcton, set that up now. */ + if (var->fletcher32) + if (H5Pset_fletcher32(plistid) < 0) + BAIL(NC_EHDFERR); + + /* If ndims non-zero, get info for all dimensions. We look up the + dimids and get the len of each dimension. We need this to create + the space for the dataset. In netCDF a dimension length of zero + means an unlimited dimension. */ + if (var->ndims) + { int unlimdim = 0; /* Check to see if any unlimited dimensions are used in this var. */ for (d = 0; d < var->ndims; d++) { - dim = var->dim[d]; - assert(dim && dim->dimid == var->dimids[d]); - if (dim->unlimited) - unlimdim++; + dim = var->dim[d]; + assert(dim && dim->dimid == var->dimids[d]); + if (dim->unlimited) + unlimdim++; } /* If there are no unlimited dims, and no filters, and the user @@ -1582,489 +1770,549 @@ var_create_dataset(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, nc_bool_t write_dimid if(!var->shuffle && !var->deflate && !var->fletcher32 && (var->chunksizes == NULL || !var->chunksizes[0])) { #ifdef USE_HDF4 - NC_HDF5_FILE_INFO_T *h5 = grp->nc4_info; - if(h5->hdf4 || !unlimdim) + NC_HDF5_FILE_INFO_T *h5 = grp->nc4_info; + if(h5->hdf4 || !unlimdim) #else - if(!unlimdim) + if(!unlimdim) #endif - var->contiguous = NC_TRUE; + var->contiguous = NC_TRUE; } /* Gather current & maximum dimension sizes, along with chunk sizes */ for (d = 0; d < var->ndims; d++) - { - dim = var->dim[d]; - assert(dim && dim->dimid == var->dimids[d]); - dimsize[d] = dim->unlimited ? NC_HDF5_UNLIMITED_DIMSIZE : dim->len; - maxdimsize[d] = dim->unlimited ? H5S_UNLIMITED : (hsize_t)dim->len; - if (!var->contiguous) { + { + dim = var->dim[d]; + assert(dim && dim->dimid == var->dimids[d]); + dimsize[d] = dim->unlimited ? NC_HDF5_UNLIMITED_DIMSIZE : dim->len; + maxdimsize[d] = dim->unlimited ? H5S_UNLIMITED : (hsize_t)dim->len; + if (!var->contiguous) { if (var->chunksizes[d]) - chunksize[d] = var->chunksizes[d]; + chunksize[d] = var->chunksizes[d]; else - { - size_t type_size; - if (var->type_info->nc_type_class == NC_STRING) + { + size_t type_size; + if (var->type_info->nc_type_class == NC_STRING) type_size = sizeof(char *); - else + else type_size = var->type_info->size; - /* Unlimited dim always gets chunksize of 1. */ - if (dim->unlimited) + /* Unlimited dim always gets chunksize of 1. */ + if (dim->unlimited) chunksize[d] = 1; - else + else chunksize[d] = pow((double)DEFAULT_CHUNK_SIZE/type_size, 1/(double)(var->ndims - unlimdim)); - /* If the chunksize is greater than the dim - * length, make it the dim length. */ - if (!dim->unlimited && chunksize[d] > dim->len) + /* If the chunksize is greater than the dim + * length, make it the dim length. */ + if (!dim->unlimited && chunksize[d] > dim->len) chunksize[d] = dim->len; - /* Remember the computed chunksize */ - var->chunksizes[d] = chunksize[d]; - } - } - } + /* Remember the computed chunksize */ + var->chunksizes[d] = chunksize[d]; + } + } + } if (var->contiguous) - { - if (H5Pset_layout(plistid, H5D_CONTIGUOUS) < 0) + { + if (H5Pset_layout(plistid, H5D_CONTIGUOUS) < 0) BAIL(NC_EHDFERR); - } + } else - { - if (H5Pset_chunk(plistid, var->ndims, chunksize) < 0) + { + if (H5Pset_chunk(plistid, var->ndims, chunksize) < 0) BAIL(NC_EHDFERR); - } + } /* Create the dataspace. */ if ((spaceid = H5Screate_simple(var->ndims, dimsize, maxdimsize)) < 0) - BAIL(NC_EHDFERR); - } - else - { + BAIL(NC_EHDFERR); + } + else + { if ((spaceid = H5Screate(H5S_SCALAR)) < 0) - BAIL(NC_EHDFERR); - } - - /* Turn on creation order tracking. */ - if (H5Pset_attr_creation_order(plistid, H5P_CRT_ORDER_TRACKED| - H5P_CRT_ORDER_INDEXED) < 0) - BAIL(NC_EHDFERR); - - /* Set per-var chunk cache, for chunked datasets. */ - if (!var->contiguous && var->chunk_cache_size) - if (H5Pset_chunk_cache(access_plistid, var->chunk_cache_nelems, - var->chunk_cache_size, var->chunk_cache_preemption) < 0) + BAIL(NC_EHDFERR); + } + + /* Turn on creation order tracking. */ + if (H5Pset_attr_creation_order(plistid, H5P_CRT_ORDER_TRACKED| + H5P_CRT_ORDER_INDEXED) < 0) BAIL(NC_EHDFERR); - /* At long last, create the dataset. */ - name_to_use = var->hdf5_name ? var->hdf5_name : var->name; - LOG((4, "%s: about to H5Dcreate2 dataset %s of type 0x%x", __func__, - name_to_use, typeid)); - if ((var->hdf_datasetid = H5Dcreate2(grp->hdf_grpid, name_to_use, typeid, - spaceid, H5P_DEFAULT, plistid, access_plistid)) < 0) - BAIL(NC_EHDFERR); - var->created = NC_TRUE; - var->is_new_var = NC_FALSE; - - /* If this is a dimscale, mark it as such in the HDF5 file. Also - * find the dimension info and store the dataset id of the dimscale - * dataset. */ - if (var->dimscale) - { + /* Set per-var chunk cache, for chunked datasets. */ + if (!var->contiguous && var->chunk_cache_size) + if (H5Pset_chunk_cache(access_plistid, var->chunk_cache_nelems, + var->chunk_cache_size, var->chunk_cache_preemption) < 0) + BAIL(NC_EHDFERR); + + /* At long last, create the dataset. */ + name_to_use = var->hdf5_name ? var->hdf5_name : var->name; + LOG((4, "%s: about to H5Dcreate2 dataset %s of type 0x%x", __func__, + name_to_use, typeid)); + if ((var->hdf_datasetid = H5Dcreate2(grp->hdf_grpid, name_to_use, typeid, + spaceid, H5P_DEFAULT, plistid, access_plistid)) < 0) + BAIL(NC_EHDFERR); + var->created = NC_TRUE; + var->is_new_var = NC_FALSE; + + /* If this is a dimscale, mark it as such in the HDF5 file. Also + * find the dimension info and store the dataset id of the dimscale + * dataset. */ + if (var->dimscale) + { if (H5DSset_scale(var->hdf_datasetid, var->name) < 0) - BAIL(NC_EHDFERR); + BAIL(NC_EHDFERR); /* If this is a multidimensional coordinate variable, write a * coordinates attribute. */ if (var->ndims > 1) - if ((retval = write_coord_dimids(var))) - BAIL(retval); + if ((retval = write_coord_dimids(var))) + BAIL(retval); /* If desired, write the netCDF dimid. */ if (write_dimid) - if ((retval = write_netcdf4_dimid(var->hdf_datasetid, var->dimids[0]))) - BAIL(retval); - } - - - /* Write attributes for this var. */ - if ((retval = write_attlist(var->att, var->varid, grp))) - BAIL(retval); - var->attr_dirty = NC_FALSE; - - exit: - if (typeid > 0 && H5Tclose(typeid) < 0) - BAIL2(NC_EHDFERR); - if (plistid > 0 && H5Pclose(plistid) < 0) - BAIL2(NC_EHDFERR); - if (access_plistid > 0 && H5Pclose(access_plistid) < 0) - BAIL2(NC_EHDFERR); - if (spaceid > 0 && H5Sclose(spaceid) < 0) - BAIL2(NC_EHDFERR); - if (fillp) - { + if ((retval = write_netcdf4_dimid(var->hdf_datasetid, var->dimids[0]))) + BAIL(retval); + } + + + /* Write attributes for this var. */ + if ((retval = write_attlist(var->att, var->varid, grp))) + BAIL(retval); + var->attr_dirty = NC_FALSE; + +exit: + if (typeid > 0 && H5Tclose(typeid) < 0) + BAIL2(NC_EHDFERR); + if (plistid > 0 && H5Pclose(plistid) < 0) + BAIL2(NC_EHDFERR); + if (access_plistid > 0 && H5Pclose(access_plistid) < 0) + BAIL2(NC_EHDFERR); + if (spaceid > 0 && H5Sclose(spaceid) < 0) + BAIL2(NC_EHDFERR); + if (fillp) + { if (var->type_info->nc_type_class == NC_VLEN) - nc_free_vlen((nc_vlen_t *)fillp); + nc_free_vlen((nc_vlen_t *)fillp); else if (var->type_info->nc_type_class == NC_STRING && *(char **)fillp) - free(*(char **)fillp); + free(*(char **)fillp); free(fillp); - } + } - return retval; + return retval; } -/* Adjust the chunk cache of a var for better performance. */ +/** + * @internal Adjust the chunk cache of a var for better + * performance. + * + * @param grp Pointer to group info struct. + * @param var Pointer to var info struct. + * + * @return NC_NOERR No error. + * @author Ed Hartnett +*/ int nc4_adjust_var_cache(NC_GRP_INFO_T *grp, NC_VAR_INFO_T * var) { - size_t chunk_size_bytes = 1; - int d; - int retval; + size_t chunk_size_bytes = 1; + int d; + int retval; - /* Nothing to be done. */ - if (var->contiguous) - return NC_NOERR; + /* Nothing to be done. */ + if (var->contiguous) + return NC_NOERR; #ifdef USE_PARALLEL4 - return NC_NOERR; + return NC_NOERR; #endif - /* How many bytes in the chunk? */ - for (d = 0; d < var->ndims; d++) - chunk_size_bytes *= var->chunksizes[d]; - if (var->type_info->size) - chunk_size_bytes *= var->type_info->size; - else - chunk_size_bytes *= sizeof(char *); - - /* If the chunk cache is too small, and the user has not changed - * the default value of the chunk cache size, then increase the - * size of the cache. */ - if (var->chunk_cache_size == CHUNK_CACHE_SIZE) - if (chunk_size_bytes > var->chunk_cache_size) + /* How many bytes in the chunk? */ + for (d = 0; d < var->ndims; d++) + chunk_size_bytes *= var->chunksizes[d]; + if (var->type_info->size) + chunk_size_bytes *= var->type_info->size; + else + chunk_size_bytes *= sizeof(char *); + + /* If the chunk cache is too small, and the user has not changed + * the default value of the chunk cache size, then increase the + * size of the cache. */ + if (var->chunk_cache_size == CHUNK_CACHE_SIZE) + if (chunk_size_bytes > var->chunk_cache_size) { - var->chunk_cache_size = chunk_size_bytes * DEFAULT_CHUNKS_IN_CACHE; - if (var->chunk_cache_size > MAX_DEFAULT_CACHE_SIZE) - var->chunk_cache_size = MAX_DEFAULT_CACHE_SIZE; - if ((retval = nc4_reopen_dataset(grp, var))) - return retval; + var->chunk_cache_size = chunk_size_bytes * DEFAULT_CHUNKS_IN_CACHE; + if (var->chunk_cache_size > MAX_DEFAULT_CACHE_SIZE) + var->chunk_cache_size = MAX_DEFAULT_CACHE_SIZE; + if ((retval = nc4_reopen_dataset(grp, var))) + return retval; } - return NC_NOERR; + return NC_NOERR; } -/* Create a HDF5 defined type from a NC_TYPE_INFO_T struct, and commit - * it to the file. */ +/** + * @internal Create a HDF5 defined type from a NC_TYPE_INFO_T struct, + * and commit it to the file. + * + * @param grp Pointer to group info struct. + * @param type Pointer to type info struct. + * + * @return NC_NOERR No error. + * @author Ed Hartnett +*/ static int commit_type(NC_GRP_INFO_T *grp, NC_TYPE_INFO_T *type) { - int retval; + int retval; - assert(grp && type); + assert(grp && type); - /* Did we already record this type? */ - if (type->committed) - return NC_NOERR; + /* Did we already record this type? */ + if (type->committed) + return NC_NOERR; - /* Is this a compound type? */ - if (type->nc_type_class == NC_COMPOUND) - { + /* Is this a compound type? */ + if (type->nc_type_class == NC_COMPOUND) + { NC_FIELD_INFO_T *field; hid_t hdf_base_typeid, hdf_typeid; if ((type->hdf_typeid = H5Tcreate(H5T_COMPOUND, type->size)) < 0) - return NC_EHDFERR; + return NC_EHDFERR; LOG((4, "creating compound type %s hdf_typeid 0x%x", type->name, type->hdf_typeid)); for (field = type->u.c.field; field; field = field->l.next) - { - if ((retval = nc4_get_hdf_typeid(grp->nc4_info, field->nc_typeid, - &hdf_base_typeid, type->endianness))) + { + if ((retval = nc4_get_hdf_typeid(grp->nc4_info, field->nc_typeid, + &hdf_base_typeid, type->endianness))) return retval; - /* If this is an array, create a special array type. */ - if (field->ndims) + /* If this is an array, create a special array type. */ + if (field->ndims) + { + int d; + hsize_t dims[NC_MAX_VAR_DIMS]; + + for (d = 0; d < field->ndims; d++) + dims[d] = field->dim_size[d]; + if ((hdf_typeid = H5Tarray_create(hdf_base_typeid, field->ndims, + dims, NULL)) < 0) { - int d; - hsize_t dims[NC_MAX_VAR_DIMS]; - - for (d = 0; d < field->ndims; d++) - dims[d] = field->dim_size[d]; - if ((hdf_typeid = H5Tarray_create(hdf_base_typeid, field->ndims, - dims, NULL)) < 0) - { - if (H5Tclose(hdf_base_typeid) < 0) - return NC_EHDFERR; + if (H5Tclose(hdf_base_typeid) < 0) return NC_EHDFERR; - } - if (H5Tclose(hdf_base_typeid) < 0) - return NC_EHDFERR; + return NC_EHDFERR; } - else + if (H5Tclose(hdf_base_typeid) < 0) + return NC_EHDFERR; + } + else hdf_typeid = hdf_base_typeid; - LOG((4, "inserting field %s offset %d hdf_typeid 0x%x", field->name, - field->offset, hdf_typeid)); - if (H5Tinsert(type->hdf_typeid, field->name, field->offset, - hdf_typeid) < 0) + LOG((4, "inserting field %s offset %d hdf_typeid 0x%x", field->name, + field->offset, hdf_typeid)); + if (H5Tinsert(type->hdf_typeid, field->name, field->offset, + hdf_typeid) < 0) return NC_EHDFERR; - if (H5Tclose(hdf_typeid) < 0) + if (H5Tclose(hdf_typeid) < 0) return NC_EHDFERR; - } - } - else if (type->nc_type_class == NC_VLEN) - { + } + } + else if (type->nc_type_class == NC_VLEN) + { /* Find the HDF typeid of the base type of this vlen. */ if ((retval = nc4_get_hdf_typeid(grp->nc4_info, type->u.v.base_nc_typeid, &type->u.v.base_hdf_typeid, type->endianness))) - return retval; + return retval; /* Create a vlen type. */ if ((type->hdf_typeid = H5Tvlen_create(type->u.v.base_hdf_typeid)) < 0) - return NC_EHDFERR; - } - else if (type->nc_type_class == NC_OPAQUE) - { + return NC_EHDFERR; + } + else if (type->nc_type_class == NC_OPAQUE) + { /* Create the opaque type. */ if ((type->hdf_typeid = H5Tcreate(H5T_OPAQUE, type->size)) < 0) - return NC_EHDFERR; - } - else if (type->nc_type_class == NC_ENUM) - { + return NC_EHDFERR; + } + else if (type->nc_type_class == NC_ENUM) + { NC_ENUM_MEMBER_INFO_T *enum_m; if (!type->u.e.enum_member) - return NC_EINVAL; + return NC_EINVAL; /* Find the HDF typeid of the base type of this enum. */ if ((retval = nc4_get_hdf_typeid(grp->nc4_info, type->u.e.base_nc_typeid, &type->u.e.base_hdf_typeid, type->endianness))) - return retval; + return retval; /* Create an enum type. */ if ((type->hdf_typeid = H5Tenum_create(type->u.e.base_hdf_typeid)) < 0) - return NC_EHDFERR; + return NC_EHDFERR; /* Add all the members to the HDF5 type. */ for (enum_m = type->u.e.enum_member; enum_m; enum_m = enum_m->l.next) - if (H5Tenum_insert(type->hdf_typeid, enum_m->name, enum_m->value) < 0) - return NC_EHDFERR; - } - else - { + if (H5Tenum_insert(type->hdf_typeid, enum_m->name, enum_m->value) < 0) + return NC_EHDFERR; + } + else + { LOG((0, "Unknown class: %d", type->nc_type_class)); return NC_EBADTYPE; - } - - /* Commit the type. */ - if (H5Tcommit(grp->hdf_grpid, type->name, type->hdf_typeid) < 0) - return NC_EHDFERR; - type->committed = NC_TRUE; - LOG((4, "just committed type %s, HDF typeid: 0x%x", type->name, - type->hdf_typeid)); - - /* Later we will always use the native typeid. In this case, it is - * a copy of the same type pointed to by hdf_typeid, but it's - * easier to maintain a copy. */ - if ((type->native_hdf_typeid = H5Tget_native_type(type->hdf_typeid, - H5T_DIR_DEFAULT)) < 0) - return NC_EHDFERR; - - return NC_NOERR; + } + + /* Commit the type. */ + if (H5Tcommit(grp->hdf_grpid, type->name, type->hdf_typeid) < 0) + return NC_EHDFERR; + type->committed = NC_TRUE; + LOG((4, "just committed type %s, HDF typeid: 0x%x", type->name, + type->hdf_typeid)); + + /* Later we will always use the native typeid. In this case, it is + * a copy of the same type pointed to by hdf_typeid, but it's + * easier to maintain a copy. */ + if ((type->native_hdf_typeid = H5Tget_native_type(type->hdf_typeid, + H5T_DIR_DEFAULT)) < 0) + return NC_EHDFERR; + + return NC_NOERR; } -/* Write an attribute, with value 1, to indicate that strict NC3 rules - * apply to this file. */ +/** + * @internal Write an attribute, with value 1, to indicate that strict + * NC3 rules apply to this file. + * + * @param hdf_grpid HDF5 group ID. + * + * @returns NC_NOERR No error. + * @returns NC_EHDFERR HDF5 returned an error. + * @author Ed Hartnett + */ static int write_nc3_strict_att(hid_t hdf_grpid) { - hid_t attid = 0, spaceid = 0; - int one = 1; - int retval = NC_NOERR; - htri_t attr_exists; - - /* If the attribute already exists, call that a success and return - * NC_NOERR. */ - if ((attr_exists = H5Aexists(hdf_grpid, NC3_STRICT_ATT_NAME)) < 0) - return NC_EHDFERR; - if (attr_exists) - return NC_NOERR; - - /* Create the attribute to mark this as a file that needs to obey - * strict netcdf-3 rules. */ - if ((spaceid = H5Screate(H5S_SCALAR)) < 0) - BAIL(NC_EFILEMETA); - if ((attid = H5Acreate(hdf_grpid, NC3_STRICT_ATT_NAME, - H5T_NATIVE_INT, spaceid, H5P_DEFAULT)) < 0) - BAIL(NC_EFILEMETA); - if (H5Awrite(attid, H5T_NATIVE_INT, &one) < 0) - BAIL(NC_EFILEMETA); - - exit: - if (spaceid > 0 && (H5Sclose(spaceid) < 0)) - BAIL2(NC_EFILEMETA); - if (attid > 0 && (H5Aclose(attid) < 0)) - BAIL2(NC_EFILEMETA); - return retval; + hid_t attid = 0, spaceid = 0; + int one = 1; + int retval = NC_NOERR; + htri_t attr_exists; + + /* If the attribute already exists, call that a success and return + * NC_NOERR. */ + if ((attr_exists = H5Aexists(hdf_grpid, NC3_STRICT_ATT_NAME)) < 0) + return NC_EHDFERR; + if (attr_exists) + return NC_NOERR; + + /* Create the attribute to mark this as a file that needs to obey + * strict netcdf-3 rules. */ + if ((spaceid = H5Screate(H5S_SCALAR)) < 0) + BAIL(NC_EFILEMETA); + if ((attid = H5Acreate(hdf_grpid, NC3_STRICT_ATT_NAME, + H5T_NATIVE_INT, spaceid, H5P_DEFAULT)) < 0) + BAIL(NC_EFILEMETA); + if (H5Awrite(attid, H5T_NATIVE_INT, &one) < 0) + BAIL(NC_EFILEMETA); + +exit: + if (spaceid > 0 && (H5Sclose(spaceid) < 0)) + BAIL2(NC_EFILEMETA); + if (attid > 0 && (H5Aclose(attid) < 0)) + BAIL2(NC_EFILEMETA); + return retval; } +/** + * @internal Create a HDF5 group. + * + * @param grp Pointer to group info struct. + * + * @return NC_NOERR No error. + * @author Ed Hartnett + */ static int create_group(NC_GRP_INFO_T *grp) { - hid_t gcpl_id = 0; - int retval = NC_NOERR;; + hid_t gcpl_id = 0; + int retval = NC_NOERR;; - assert(grp); + assert(grp); - /* If this is not the root group, create it in the HDF5 file. */ - if (grp->parent) - { + /* If this is not the root group, create it in the HDF5 file. */ + if (grp->parent) + { /* Create group, with link_creation_order set in the group * creation property list. */ if ((gcpl_id = H5Pcreate(H5P_GROUP_CREATE)) < 0) - return NC_EHDFERR; + return NC_EHDFERR; /* RJ: this suppose to be FALSE that is defined in H5 private.h as 0 */ if (H5Pset_obj_track_times(gcpl_id,0)<0) - BAIL(NC_EHDFERR); + BAIL(NC_EHDFERR); if (H5Pset_link_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED|H5P_CRT_ORDER_INDEXED) < 0) - BAIL(NC_EHDFERR); + BAIL(NC_EHDFERR); if (H5Pset_attr_creation_order(gcpl_id, H5P_CRT_ORDER_TRACKED|H5P_CRT_ORDER_INDEXED) < 0) - BAIL(NC_EHDFERR); + BAIL(NC_EHDFERR); if ((grp->hdf_grpid = H5Gcreate2(grp->parent->hdf_grpid, grp->name, H5P_DEFAULT, gcpl_id, H5P_DEFAULT)) < 0) - BAIL(NC_EHDFERR); + BAIL(NC_EHDFERR); if (H5Pclose(gcpl_id) < 0) - BAIL(NC_EHDFERR); - } - else - { + BAIL(NC_EHDFERR); + } + else + { /* Since this is the root group, we have to open it. */ if ((grp->hdf_grpid = H5Gopen2(grp->nc4_info->hdfid, "/", H5P_DEFAULT)) < 0) - BAIL(NC_EFILEMETA); - } - return NC_NOERR; - - exit: - if (gcpl_id > 0 && H5Pclose(gcpl_id) < 0) - BAIL2(NC_EHDFERR); - if (grp->hdf_grpid > 0 && H5Gclose(grp->hdf_grpid) < 0) - BAIL2(NC_EHDFERR); - return retval; + BAIL(NC_EFILEMETA); + } + return NC_NOERR; + +exit: + if (gcpl_id > 0 && H5Pclose(gcpl_id) < 0) + BAIL2(NC_EHDFERR); + if (grp->hdf_grpid > 0 && H5Gclose(grp->hdf_grpid) < 0) + BAIL2(NC_EHDFERR); + return retval; } -/* After all the datasets of the file have been read, it's time to - * sort the wheat from the chaff. Which of the datasets are netCDF - * dimensions, and which are coordinate variables, and which are - * non-coordinate variables. */ +/** + * @internal After all the datasets of the file have been read, it's + * time to sort the wheat from the chaff. Which of the datasets are + * netCDF dimensions, and which are coordinate variables, and which + * are non-coordinate variables. + * + * @param grp Pointer to group info struct. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett +*/ static int attach_dimscales(NC_GRP_INFO_T *grp) { - NC_VAR_INFO_T *var; - NC_DIM_INFO_T *dim1; - int d, i; - int retval = NC_NOERR; - - /* Attach dimension scales. */ - for (i=0; i < grp->vars.nelems; i++) - { + NC_VAR_INFO_T *var; + NC_DIM_INFO_T *dim1; + int d, i; + int retval = NC_NOERR; + + /* Attach dimension scales. */ + for (i=0; i < grp->vars.nelems; i++) + { var = grp->vars.value[i]; if (!var) continue; /* Scales themselves do not attach. But I really wish they * would. */ if (var->dimscale) - { - /* If this is a multidimensional coordinate variable, it will - * have a special coords attribute (read earlier) with a list - * of the dimensions for this variable. */ - } + { + /* If this is a multidimensional coordinate variable, it will + * have a special coords attribute (read earlier) with a list + * of the dimensions for this variable. */ + } else /* not a dimscale... */ - { - /* Find the scale for each dimension and attach it. */ - for (d = 0; d < var->ndims; d++) + { + /* Find the scale for each dimension and attach it. */ + for (d = 0; d < var->ndims; d++) + { + /* Is there a dimscale for this dimension? */ + if (var->dimscale_attached) { - /* Is there a dimscale for this dimension? */ - if (var->dimscale_attached) - { - if (!var->dimscale_attached[d]) - { - hid_t dim_datasetid; /* Dataset ID for dimension */ - dim1 = var->dim[d]; - assert(dim1 && dim1->dimid == var->dimids[d]); - - LOG((2, "%s: attaching scale for dimid %d to var %s", - __func__, var->dimids[d], var->name)); - - /* Find dataset ID for dimension */ - if (dim1->coord_var) - dim_datasetid = dim1->coord_var->hdf_datasetid; - else - dim_datasetid = dim1->hdf_dimscaleid; - assert(dim_datasetid > 0); - if (H5DSattach_scale(var->hdf_datasetid, dim_datasetid, d) < 0) - BAIL(NC_EHDFERR); - var->dimscale_attached[d] = NC_TRUE; - } - - /* If we didn't find a dimscale to attach, that's a problem! */ - if (!var->dimscale_attached[d]) - { - LOG((0, "no dimscale found!")); - return NC_EDIMSCALE; - } - } + if (!var->dimscale_attached[d]) + { + hid_t dim_datasetid; /* Dataset ID for dimension */ + dim1 = var->dim[d]; + assert(dim1 && dim1->dimid == var->dimids[d]); + + LOG((2, "%s: attaching scale for dimid %d to var %s", + __func__, var->dimids[d], var->name)); + + /* Find dataset ID for dimension */ + if (dim1->coord_var) + dim_datasetid = dim1->coord_var->hdf_datasetid; + else + dim_datasetid = dim1->hdf_dimscaleid; + assert(dim_datasetid > 0); + if (H5DSattach_scale(var->hdf_datasetid, dim_datasetid, d) < 0) + BAIL(NC_EHDFERR); + var->dimscale_attached[d] = NC_TRUE; + } + + /* If we didn't find a dimscale to attach, that's a problem! */ + if (!var->dimscale_attached[d]) + { + LOG((0, "no dimscale found!")); + return NC_EDIMSCALE; + } } - } - } + } + } + } - exit: - return retval; +exit: + return retval; } +/** + * @internal Does a variable exist? + * + * @param grpid HDF5 group ID. + * @param name Name of variable. + * @param exists Pointer that gets 1 of the variable exists, 0 otherwise. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ static int var_exists(hid_t grpid, char *name, nc_bool_t *exists) { - htri_t link_exists; + htri_t link_exists; - /* Reset the boolean */ - *exists = NC_FALSE; + /* Reset the boolean */ + *exists = NC_FALSE; - /* Check if the object name exists in the group */ - if ((link_exists = H5Lexists(grpid, name, H5P_DEFAULT)) < 0) - return NC_EHDFERR; - if (link_exists) - { + /* Check if the object name exists in the group */ + if ((link_exists = H5Lexists(grpid, name, H5P_DEFAULT)) < 0) + return NC_EHDFERR; + if (link_exists) + { H5G_stat_t statbuf; /* Get info about the object */ if (H5Gget_objinfo(grpid, name, 1, &statbuf) < 0) - return NC_EHDFERR; + return NC_EHDFERR; if (H5G_DATASET == statbuf.type) - *exists = NC_TRUE; - } + *exists = NC_TRUE; + } - return NC_NOERR; + return NC_NOERR; } -/* This function writes a variable. The principle difficulty comes - * from the possibility that this is a coordinate variable, and was - * already written to the file as a dimension-only dimscale. If this - * occurs, then it must be deleted and recreated. */ +/** + * @internal This function writes a variable. The principle difficulty + * comes from the possibility that this is a coordinate variable, and + * was already written to the file as a dimension-only dimscale. If + * this occurs, then it must be deleted and recreated. + * + * @param var Pointer to variable info struct. + * @param grp Pointer to group info struct. + * @param write_dimid + * + * @returns NC_NOERR No error. + * @returns NC_EHDFERR HDF5 returned an error. + * @author Ed Hartnett +*/ static int write_var(NC_VAR_INFO_T *var, NC_GRP_INFO_T *grp, nc_bool_t write_dimid) { - nc_bool_t replace_existing_var = NC_FALSE; - int retval; + nc_bool_t replace_existing_var = NC_FALSE; + int retval; - LOG((4, "%s: writing var %s", __func__, var->name)); + LOG((4, "%s: writing var %s", __func__, var->name)); - /* If the variable has already been created & the fill value changed, - * indicate that the existing variable should be replaced. */ - if (var->created && var->fill_val_changed) - { + /* If the variable has already been created & the fill value changed, + * indicate that the existing variable should be replaced. */ + if (var->created && var->fill_val_changed) + { replace_existing_var = NC_TRUE; var->fill_val_changed = NC_FALSE; /* If the variable is going to be replaced, @@ -2076,204 +2324,216 @@ write_var(NC_VAR_INFO_T *var, NC_GRP_INFO_T *grp, nc_bool_t write_dimid) * https://github.com/Unidata/netcdf-c/issues/239 */ flag_atts_dirty(&var->att); - } - - /* Is this a coordinate var that has already been created in - * the HDF5 file as a dimscale dataset? Check for dims with the - * same name in this group. If there is one, check to see if - * this object exists in the HDF group. */ - if (var->became_coord_var) - { + } + + /* Is this a coordinate var that has already been created in + * the HDF5 file as a dimscale dataset? Check for dims with the + * same name in this group. If there is one, check to see if + * this object exists in the HDF group. */ + if (var->became_coord_var) + { NC_DIM_INFO_T *d1; for (d1 = grp->dim; d1; d1 = d1->l.next) - if (!strcmp(d1->name, var->name)) - { + if (!strcmp(d1->name, var->name)) + { nc_bool_t exists; if ((retval = var_exists(grp->hdf_grpid, var->name, &exists))) - return retval; + return retval; if (exists) - { - /* Indicate that the variable already exists, and should be replaced */ - replace_existing_var = NC_TRUE; - flag_atts_dirty(&var->att); - break; - } - } - } - - /* Check dims if the variable will be replaced, so that the dimensions - * will be de-attached and re-attached correctly. */ - /* (Note: There's a temptation to merge this loop over the dimensions with - * the prior loop over dimensions, but that blurs the line over the - * purpose of them, so they are currently separate. If performance - * becomes an issue here, it would be possible to merge them. -QAK) - */ - if (replace_existing_var) - { + { + /* Indicate that the variable already exists, and should be replaced */ + replace_existing_var = NC_TRUE; + flag_atts_dirty(&var->att); + break; + } + } + } + + /* Check dims if the variable will be replaced, so that the dimensions + * will be de-attached and re-attached correctly. */ + /* (Note: There's a temptation to merge this loop over the dimensions with + * the prior loop over dimensions, but that blurs the line over the + * purpose of them, so they are currently separate. If performance + * becomes an issue here, it would be possible to merge them. -QAK) + */ + if (replace_existing_var) + { NC_DIM_INFO_T *d1; for (d1 = grp->dim; d1; d1 = d1->l.next) - if (!strcmp(d1->name, var->name)) - { + if (!strcmp(d1->name, var->name)) + { nc_bool_t exists; if ((retval = var_exists(grp->hdf_grpid, var->name, &exists))) - return retval; + return retval; if (exists) - { - hid_t dim_datasetid; /* Dataset ID for dimension */ + { + hid_t dim_datasetid; /* Dataset ID for dimension */ - /* Find dataset ID for dimension */ - if (d1->coord_var) + /* Find dataset ID for dimension */ + if (d1->coord_var) dim_datasetid = d1->coord_var->hdf_datasetid; - else + else dim_datasetid = d1->hdf_dimscaleid; - assert(dim_datasetid > 0); + assert(dim_datasetid > 0); - /* If we're replacing an existing dimscale dataset, go to - * every var in the file and detach this dimension scale, - * because we have to delete it. */ - if ((retval = rec_detach_scales(grp->nc4_info->root_grp, - var->dimids[0], dim_datasetid))) + /* If we're replacing an existing dimscale dataset, go to + * every var in the file and detach this dimension scale, + * because we have to delete it. */ + if ((retval = rec_detach_scales(grp->nc4_info->root_grp, + var->dimids[0], dim_datasetid))) return retval; - break; - } - } - } - - /* If this is not a dimension scale, do this stuff. */ - if (var->was_coord_var && var->dimscale_attached) - { + break; + } + } + } + + /* If this is not a dimension scale, do this stuff. */ + if (var->was_coord_var && var->dimscale_attached) + { /* If the variable already exists in the file, Remove any dimension scale * attributes from it, if they exist. */ /* (The HDF5 Dimension Scale API should really have an API routine * for making a dataset not a scale. -QAK) */ if (var->created) - { - htri_t attr_exists; + { + htri_t attr_exists; - /* (We could do a better job here and verify that the attributes are - * really dimension scale 'CLASS' & 'NAME' attributes, but that would be - * poking about in the HDF5 DimScale internal data) */ - if ((attr_exists = H5Aexists(var->hdf_datasetid, "CLASS")) < 0) + /* (We could do a better job here and verify that the attributes are + * really dimension scale 'CLASS' & 'NAME' attributes, but that would be + * poking about in the HDF5 DimScale internal data) */ + if ((attr_exists = H5Aexists(var->hdf_datasetid, "CLASS")) < 0) BAIL(NC_EHDFERR); - if (attr_exists) - { - if (H5Adelete(var->hdf_datasetid, "CLASS") < 0) - BAIL(NC_EHDFERR); - } - if ((attr_exists = H5Aexists(var->hdf_datasetid, "NAME")) < 0) + if (attr_exists) + { + if (H5Adelete(var->hdf_datasetid, "CLASS") < 0) + BAIL(NC_EHDFERR); + } + if ((attr_exists = H5Aexists(var->hdf_datasetid, "NAME")) < 0) BAIL(NC_EHDFERR); - if (attr_exists) - { - if (H5Adelete(var->hdf_datasetid, "NAME") < 0) - BAIL(NC_EHDFERR); - } - } + if (attr_exists) + { + if (H5Adelete(var->hdf_datasetid, "NAME") < 0) + BAIL(NC_EHDFERR); + } + } if (var->dimscale_attached) - { - int d; + { + int d; - /* If this is a regular var, detach all its dim scales. */ - for (d = 0; d < var->ndims; d++) + /* If this is a regular var, detach all its dim scales. */ + for (d = 0; d < var->ndims; d++) if (var->dimscale_attached[d]) - { - hid_t dim_datasetid; /* Dataset ID for dimension */ - NC_DIM_INFO_T *dim1 = var->dim[d]; - assert(dim1 && dim1->dimid == var->dimids[d]); + { + hid_t dim_datasetid; /* Dataset ID for dimension */ + NC_DIM_INFO_T *dim1 = var->dim[d]; + assert(dim1 && dim1->dimid == var->dimids[d]); - /* Find dataset ID for dimension */ - if (dim1->coord_var) + /* Find dataset ID for dimension */ + if (dim1->coord_var) dim_datasetid = dim1->coord_var->hdf_datasetid; - else + else dim_datasetid = dim1->hdf_dimscaleid; - assert(dim_datasetid > 0); + assert(dim_datasetid > 0); - if (H5DSdetach_scale(var->hdf_datasetid, dim_datasetid, d) < 0) + if (H5DSdetach_scale(var->hdf_datasetid, dim_datasetid, d) < 0) BAIL(NC_EHDFERR); - var->dimscale_attached[d] = NC_FALSE; - } - } - } - - /* Delete the HDF5 dataset that is to be replaced. */ - if (replace_existing_var) - { + var->dimscale_attached[d] = NC_FALSE; + } + } + } + + /* Delete the HDF5 dataset that is to be replaced. */ + if (replace_existing_var) + { /* Free the HDF5 dataset id. */ if (var->hdf_datasetid && H5Dclose(var->hdf_datasetid) < 0) - BAIL(NC_EHDFERR); + BAIL(NC_EHDFERR); var->hdf_datasetid = 0; /* Now delete the variable. */ if (H5Gunlink(grp->hdf_grpid, var->name) < 0) - return NC_EDIMMETA; - } + return NC_EDIMMETA; + } - /* Create the dataset. */ - if (var->is_new_var || replace_existing_var) - { + /* Create the dataset. */ + if (var->is_new_var || replace_existing_var) + { if ((retval = var_create_dataset(grp, var, write_dimid))) - return retval; - } - else - { + return retval; + } + else + { if (write_dimid && var->ndims) - if ((retval = write_netcdf4_dimid(var->hdf_datasetid, var->dimids[0]))) - BAIL(retval); - } + if ((retval = write_netcdf4_dimid(var->hdf_datasetid, var->dimids[0]))) + BAIL(retval); + } - if (replace_existing_var) - { + if (replace_existing_var) + { /* If this is a dimension scale, reattach the scale everywhere it * is used. (Recall that netCDF dimscales are always 1-D). */ if(var->dimscale) - { - if ((retval = rec_reattach_scales(grp->nc4_info->root_grp, - var->dimids[0], var->hdf_datasetid))) + { + if ((retval = rec_reattach_scales(grp->nc4_info->root_grp, + var->dimids[0], var->hdf_datasetid))) return retval; - } + } /* If it's not a dimension scale, clear the dimscale attached flags, * so the dimensions are re-attached. */ else - { - if (var->dimscale_attached) + { + if (var->dimscale_attached) memset(var->dimscale_attached, 0, sizeof(nc_bool_t) * var->ndims); - } - } + } + } - /* Clear coord. var state transition flags */ - var->was_coord_var = NC_FALSE; - var->became_coord_var = NC_FALSE; + /* Clear coord. var state transition flags */ + var->was_coord_var = NC_FALSE; + var->became_coord_var = NC_FALSE; - /* Now check the attributes for this var. */ - if (var->attr_dirty) - { + /* Now check the attributes for this var. */ + if (var->attr_dirty) + { /* Write attributes for this var. */ if ((retval = write_attlist(var->att, var->varid, grp))) - BAIL(retval); + BAIL(retval); var->attr_dirty = NC_FALSE; - } + } - return NC_NOERR; - exit: - return retval; + return NC_NOERR; +exit: + return retval; } +/** + * @internal Write a dimension. + * + * @param dim Pointer to dim info struct. + * @param grp Pointer to group info struct. + * @param write_dimid + * + * @returns ::NC_NOERR No error. + * @returns ::NC_EPERM Read-only file. + * @returns ::NC_EHDFERR HDF5 returned error. + * @author Ed Hartnett + */ static int write_dim(NC_DIM_INFO_T *dim, NC_GRP_INFO_T *grp, nc_bool_t write_dimid) { - int retval; - int i; - - /* If there's no dimscale dataset for this dim, create one, - * and mark that it should be hidden from netCDF as a - * variable. (That is, it should appear as a dimension - * without an associated variable.) */ - if (0 == dim->hdf_dimscaleid) - { + int retval; + int i; + + /* If there's no dimscale dataset for this dim, create one, + * and mark that it should be hidden from netCDF as a + * variable. (That is, it should appear as a dimension + * without an associated variable.) */ + if (0 == dim->hdf_dimscaleid) + { hid_t spaceid, create_propid; hsize_t dims[1], max_dims[1], chunk_dims[1] = {1}; char dimscale_wo_var[NC_MAX_NAME]; @@ -2287,52 +2547,52 @@ write_dim(NC_DIM_INFO_T *dim, NC_GRP_INFO_T *grp, nc_bool_t write_dimid) * unlimited (i.e. it's an unlimited dimension), then set * up chunking, with a chunksize of 1. */ if ((create_propid = H5Pcreate(H5P_DATASET_CREATE)) < 0) - BAIL(NC_EHDFERR); + BAIL(NC_EHDFERR); /* RJ: this suppose to be FALSE that is defined in H5 private.h as 0 */ if (H5Pset_obj_track_times(create_propid,0)<0) - BAIL(NC_EHDFERR); + BAIL(NC_EHDFERR); dims[0] = dim->len; max_dims[0] = dim->len; if (dim->unlimited) - { - max_dims[0] = H5S_UNLIMITED; - if (H5Pset_chunk(create_propid, 1, chunk_dims) < 0) + { + max_dims[0] = H5S_UNLIMITED; + if (H5Pset_chunk(create_propid, 1, chunk_dims) < 0) BAIL(NC_EHDFERR); - } + } /* Set up space. */ if ((spaceid = H5Screate_simple(1, dims, max_dims)) < 0) - BAIL(NC_EHDFERR); + BAIL(NC_EHDFERR); if (H5Pset_attr_creation_order(create_propid, H5P_CRT_ORDER_TRACKED| H5P_CRT_ORDER_INDEXED) < 0) - BAIL(NC_EHDFERR); + BAIL(NC_EHDFERR); /* Create the dataset that will be the dimension scale. */ LOG((4, "%s: about to H5Dcreate1 a dimscale dataset %s", __func__, dim->name)); if ((dim->hdf_dimscaleid = H5Dcreate1(grp->hdf_grpid, dim->name, H5T_IEEE_F32BE, spaceid, create_propid)) < 0) - BAIL(NC_EHDFERR); + BAIL(NC_EHDFERR); /* Close the spaceid and create_propid. */ if (H5Sclose(spaceid) < 0) - BAIL(NC_EHDFERR); + BAIL(NC_EHDFERR); if (H5Pclose(create_propid) < 0) - BAIL(NC_EHDFERR); + BAIL(NC_EHDFERR); /* Indicate that this is a scale. Also indicate that not * be shown to the user as a variable. It is hidden. It is * a DIM WITHOUT A VARIABLE! */ sprintf(dimscale_wo_var, "%s%10d", DIM_WITHOUT_VARIABLE, (int)dim->len); if (H5DSset_scale(dim->hdf_dimscaleid, dimscale_wo_var) < 0) - BAIL(NC_EHDFERR); - } + BAIL(NC_EHDFERR); + } - /* Did we extend an unlimited dimension? */ - if (dim->extended) - { + /* Did we extend an unlimited dimension? */ + if (dim->extended) + { NC_VAR_INFO_T *v1 = NULL; assert(dim->unlimited); @@ -2341,234 +2601,275 @@ write_dim(NC_DIM_INFO_T *dim, NC_GRP_INFO_T *grp, nc_bool_t write_dimid) * attribute. */ for (i=0; i < grp->vars.nelems; i++) { - if (grp->vars.value[i] && !strcmp(grp->vars.value[i]->name, dim->name)) - { - v1 = grp->vars.value[i]; - break; - } + if (grp->vars.value[i] && !strcmp(grp->vars.value[i]->name, dim->name)) + { + v1 = grp->vars.value[i]; + break; + } } if (v1) - { - hsize_t *new_size = NULL; - int d1; + { + hsize_t *new_size = NULL; + int d1; - /* Extend the dimension scale dataset to reflect the new - * length of the dimension. */ - if (!(new_size = malloc(v1->ndims * sizeof(hsize_t)))) + /* Extend the dimension scale dataset to reflect the new + * length of the dimension. */ + if (!(new_size = malloc(v1->ndims * sizeof(hsize_t)))) BAIL(NC_ENOMEM); - for (d1 = 0; d1 < v1->ndims; d1++) - { - assert(v1->dim[d1] && v1->dim[d1]->dimid == v1->dimids[d1]); - new_size[d1] = v1->dim[d1]->len; - } - if (H5Dset_extent(v1->hdf_datasetid, new_size) < 0) { + for (d1 = 0; d1 < v1->ndims; d1++) + { + assert(v1->dim[d1] && v1->dim[d1]->dimid == v1->dimids[d1]); + new_size[d1] = v1->dim[d1]->len; + } + if (H5Dset_extent(v1->hdf_datasetid, new_size) < 0) { free(new_size); BAIL(NC_EHDFERR); - } - free(new_size); - } - } - - /* If desired, write the secret dimid. This will be used instead of - * the dimid that the dimension would otherwise receive based on - * creation order. This can be necessary when dims and their - * coordinate variables were created in different order. */ - if (write_dimid && dim->hdf_dimscaleid) - if ((retval = write_netcdf4_dimid(dim->hdf_dimscaleid, dim->dimid))) - BAIL(retval); + } + free(new_size); + } + } + + /* If desired, write the secret dimid. This will be used instead of + * the dimid that the dimension would otherwise receive based on + * creation order. This can be necessary when dims and their + * coordinate variables were created in different order. */ + if (write_dimid && dim->hdf_dimscaleid) + if ((retval = write_netcdf4_dimid(dim->hdf_dimscaleid, dim->dimid))) + BAIL(retval); - return NC_NOERR; - exit: + return NC_NOERR; +exit: - return retval; + return retval; } -/* Recursively determine if there is a mismatch between order of - * coordinate creation and associated dimensions in this group or any - * subgroups, to find out if we have to handle that situation. Also - * check if there are any multidimensional coordinate variables - * defined, which require the same treatment to fix a potential bug - * when such variables occur in subgroups. */ +/** + * @internal Recursively determine if there is a mismatch between + * order of coordinate creation and associated dimensions in this + * group or any subgroups, to find out if we have to handle that + * situation. Also check if there are any multidimensional coordinate + * variables defined, which require the same treatment to fix a + * potential bug when such variables occur in subgroups. + * + * @param grp Pointer to group info struct. + * @param bad_coord_orderp Pointer that gets 1 if there is a bad + * coordinate order. + * + * @returns NC_NOERR No error. + * @returns NC_EHDFERR HDF5 returned an error. + * @author Ed Hartnett +*/ int nc4_rec_detect_need_to_preserve_dimids(NC_GRP_INFO_T *grp, nc_bool_t *bad_coord_orderp) { - NC_VAR_INFO_T *var; - NC_GRP_INFO_T *child_grp; - int last_dimid = -1; - int retval; - int i; - - /* Iterate over variables in this group */ - for (i=0; i < grp->vars.nelems; i++) - { + NC_VAR_INFO_T *var; + NC_GRP_INFO_T *child_grp; + int last_dimid = -1; + int retval; + int i; + + /* Iterate over variables in this group */ + for (i=0; i < grp->vars.nelems; i++) + { var = grp->vars.value[i]; if (!var) continue; /* Only matters for dimension scale variables, with non-scalar dimensionality */ if (var->dimscale && var->ndims) - { - /* If the user writes coord vars in a different order then he - * defined their dimensions, then, when the file is reopened, the - * order of the dimids will change to match the order of the coord - * vars. Detect if this is about to happen. */ - if (var->dimids[0] < last_dimid) - { - LOG((5, "%s: %s is out of order coord var", __func__, var->name)); - *bad_coord_orderp = NC_TRUE; - return NC_NOERR; - } - last_dimid = var->dimids[0]; - - /* If there are multidimensional coordinate variables defined, then - * it's also necessary to preserve dimension IDs when the file is - * reopened ... */ - if (var->ndims > 1) - { - LOG((5, "%s: %s is multidimensional coord var", __func__, var->name)); - *bad_coord_orderp = NC_TRUE; - return NC_NOERR; - } - - /* Did the user define a dimension, end define mode, reenter define - * mode, and then define a coordinate variable for that dimension? - * If so, dimensions will be out of order. */ - if (var->is_new_var || var->became_coord_var) - { - LOG((5, "%s: coord var defined after enddef/redef", __func__)); - *bad_coord_orderp = NC_TRUE; - return NC_NOERR; - } - } - } + { + /* If the user writes coord vars in a different order then he + * defined their dimensions, then, when the file is reopened, the + * order of the dimids will change to match the order of the coord + * vars. Detect if this is about to happen. */ + if (var->dimids[0] < last_dimid) + { + LOG((5, "%s: %s is out of order coord var", __func__, var->name)); + *bad_coord_orderp = NC_TRUE; + return NC_NOERR; + } + last_dimid = var->dimids[0]; + + /* If there are multidimensional coordinate variables defined, then + * it's also necessary to preserve dimension IDs when the file is + * reopened ... */ + if (var->ndims > 1) + { + LOG((5, "%s: %s is multidimensional coord var", __func__, var->name)); + *bad_coord_orderp = NC_TRUE; + return NC_NOERR; + } + + /* Did the user define a dimension, end define mode, reenter define + * mode, and then define a coordinate variable for that dimension? + * If so, dimensions will be out of order. */ + if (var->is_new_var || var->became_coord_var) + { + LOG((5, "%s: coord var defined after enddef/redef", __func__)); + *bad_coord_orderp = NC_TRUE; + return NC_NOERR; + } + } + } - /* If there are any child groups, check them also for this condition. */ - for (child_grp = grp->children; child_grp; child_grp = child_grp->l.next) - if ((retval = nc4_rec_detect_need_to_preserve_dimids(child_grp, bad_coord_orderp))) - return retval; + /* If there are any child groups, check them also for this condition. */ + for (child_grp = grp->children; child_grp; child_grp = child_grp->l.next) + if ((retval = nc4_rec_detect_need_to_preserve_dimids(child_grp, bad_coord_orderp))) + return retval; - return NC_NOERR; + return NC_NOERR; } - -/* Recursively write all the metadata in a group. Groups and types - * have all already been written. Propagate bad cooordinate order to - * subgroups, if detected. */ +/** + * @internal Recursively write all the metadata in a group. Groups and + * types have all already been written. Propagate bad cooordinate + * order to subgroups, if detected. + * + * @param grp Pointer to group info struct. + * @param bad_coord_order 1 if there is a bad coordinate order. + * + * @returns NC_NOERR No error. + * @returns NC_EHDFERR HDF5 returned an error. + * @author Ed Hartnett +*/ int nc4_rec_write_metadata(NC_GRP_INFO_T *grp, nc_bool_t bad_coord_order) { - NC_DIM_INFO_T *dim = NULL; - NC_VAR_INFO_T *var = NULL; - NC_GRP_INFO_T *child_grp = NULL; - int coord_varid = -1; - int var_index = 0; - - int retval; - assert(grp && grp->name && grp->hdf_grpid); - LOG((3, "%s: grp->name %s, bad_coord_order %d", __func__, grp->name, bad_coord_order)); - - /* Write global attributes for this group. */ - if ((retval = write_attlist(grp->att, NC_GLOBAL, grp))) - return retval; - /* Set the pointers to the beginning of the list of dims & vars in this - * group. */ - dim = grp->dim; - if (var_index < grp->vars.nelems) - var = grp->vars.value[var_index]; - - /* Because of HDF5 ordering the dims and vars have to be stored in - * this way to ensure that the dims and coordinate vars come out in - * the correct order. */ - while (dim || var) - { + NC_DIM_INFO_T *dim = NULL; + NC_VAR_INFO_T *var = NULL; + NC_GRP_INFO_T *child_grp = NULL; + int coord_varid = -1; + int var_index = 0; + + int retval; + assert(grp && grp->name && grp->hdf_grpid); + LOG((3, "%s: grp->name %s, bad_coord_order %d", __func__, grp->name, bad_coord_order)); + + /* Write global attributes for this group. */ + if ((retval = write_attlist(grp->att, NC_GLOBAL, grp))) + return retval; + /* Set the pointers to the beginning of the list of dims & vars in this + * group. */ + dim = grp->dim; + if (var_index < grp->vars.nelems) + var = grp->vars.value[var_index]; + + /* Because of HDF5 ordering the dims and vars have to be stored in + * this way to ensure that the dims and coordinate vars come out in + * the correct order. */ + while (dim || var) + { nc_bool_t found_coord, wrote_coord; /* Write non-coord dims in order, stopping at the first one that * has an associated coord var. */ for (found_coord = NC_FALSE; dim && !found_coord; dim = dim->l.next) - { - if (!dim->coord_var) - { - if ((retval = write_dim(dim, grp, bad_coord_order))) - return retval; - } - else - { - coord_varid = dim->coord_var->varid; - found_coord = NC_TRUE; - } - } + { + if (!dim->coord_var) + { + if ((retval = write_dim(dim, grp, bad_coord_order))) + return retval; + } + else + { + coord_varid = dim->coord_var->varid; + found_coord = NC_TRUE; + } + } /* Write each var. When we get to the coord var we are waiting * for (if any), then we break after writing it. */ for (wrote_coord = NC_FALSE; var && !wrote_coord; ) - { - if ((retval = write_var(var, grp, bad_coord_order))) + { + if ((retval = write_var(var, grp, bad_coord_order))) return retval; - if (found_coord && var->varid == coord_varid) + if (found_coord && var->varid == coord_varid) wrote_coord = NC_TRUE; - if (++var_index < grp->vars.nelems) - var = grp->vars.value[var_index]; - else - var = NULL; - } - } /* end while */ - - if ((retval = attach_dimscales(grp))) - return retval; - - /* If there are any child groups, write their metadata. */ - for (child_grp = grp->children; child_grp; child_grp = child_grp->l.next) - if ((retval = nc4_rec_write_metadata(child_grp, bad_coord_order))) + if (++var_index < grp->vars.nelems) + var = grp->vars.value[var_index]; + else + var = NULL; + } + } /* end while */ + + if ((retval = attach_dimscales(grp))) return retval; - return NC_NOERR; + /* If there are any child groups, write their metadata. */ + for (child_grp = grp->children; child_grp; child_grp = child_grp->l.next) + if ((retval = nc4_rec_write_metadata(child_grp, bad_coord_order))) + return retval; + + return NC_NOERR; } -/* Recursively write all groups and types. */ +/** + * @internal Recursively write all groups and types. + * + * @param grp Pointer to group info struct. + * + * @returns NC_NOERR No error. + * @returns NC_EHDFERR HDF5 returned an error. + * @author Ed Hartnett +*/ int nc4_rec_write_groups_types(NC_GRP_INFO_T *grp) { - NC_GRP_INFO_T *child_grp; - NC_TYPE_INFO_T *type; - int retval; - - assert(grp && grp->name); - LOG((3, "%s: grp->name %s", __func__, grp->name)); - - /* Create the group in the HDF5 file if it doesn't exist. */ - if (!grp->hdf_grpid) - if ((retval = create_group(grp))) - return retval; - - /* If this is the root group of a file with strict NC3 rules, write - * an attribute. But don't leave the attribute open. */ - if (!grp->parent && (grp->nc4_info->cmode & NC_CLASSIC_MODEL)) - if ((retval = write_nc3_strict_att(grp->hdf_grpid))) - return retval; - - /* If there are any user-defined types, write them now. */ - for (type = grp->type; type; type = type->l.next) - if ((retval = commit_type(grp, type))) - return retval; - - /* If there are any child groups, write their groups and types. */ - for (child_grp = grp->children; child_grp; child_grp = child_grp->l.next) - if ((retval = nc4_rec_write_groups_types(child_grp))) - return retval; - - return NC_NOERR; + NC_GRP_INFO_T *child_grp; + NC_TYPE_INFO_T *type; + int retval; + + assert(grp && grp->name); + LOG((3, "%s: grp->name %s", __func__, grp->name)); + + /* Create the group in the HDF5 file if it doesn't exist. */ + if (!grp->hdf_grpid) + if ((retval = create_group(grp))) + return retval; + + /* If this is the root group of a file with strict NC3 rules, write + * an attribute. But don't leave the attribute open. */ + if (!grp->parent && (grp->nc4_info->cmode & NC_CLASSIC_MODEL)) + if ((retval = write_nc3_strict_att(grp->hdf_grpid))) + return retval; + + /* If there are any user-defined types, write them now. */ + for (type = grp->type; type; type = type->l.next) + if ((retval = commit_type(grp, type))) + return retval; + + /* If there are any child groups, write their groups and types. */ + for (child_grp = grp->children; child_grp; child_grp = child_grp->l.next) + if ((retval = nc4_rec_write_groups_types(child_grp))) + return retval; + + return NC_NOERR; } -/*! Copy data from one buffer to another, performing appropriate data conversion. - - This function will copy data from one buffer to another, in - accordance with the types. Range errors will be noted, and the fill - value used (or the default fill value if none is supplied) for - values that overflow the type. - - I should be able to take this out when HDF5 does the right thing - with data type conversion. - - Ed Hartnett, 11/15/3 +/** + * @internal Copy data from one buffer to another, performing + * appropriate data conversion. + * + * This function will copy data from one buffer to another, in + * accordance with the types. Range errors will be noted, and the fill + * value used (or the default fill value if none is supplied) for + * values that overflow the type. + * + * @note I should be able to take this out when HDF5 does the right thing + * with data type conversion. Ed Hartnett, 11/15/3 + * + * @param src Pointer to source of data. + * @param dest Pointer that gets data. + * @param src_type Type ID of source data. + * @param dest_type Type ID of destination data. + * @param len Number of elements of data to copy. + * @param range_error Pointer that gets 1 if there was a range error. + * @param fill_value The fill value. + * @param strict_nc3 Non-zero if strict model in effect. + * @param src_long Is the source NC_LONG? + * @param dest_long Is the destination NC_LONG? + * + * @returns NC_NOERR No error. + * @returns NC_EBADTYPE Type not found. + * @author Ed Hartnett */ int nc4_convert_type(const void *src, void *dest, @@ -2577,985 +2878,994 @@ nc4_convert_type(const void *src, void *dest, const void *fill_value, int strict_nc3, int src_long, int dest_long) { - char *cp, *cp1; - float *fp, *fp1; - double *dp, *dp1; - int *ip, *ip1; - signed long *lp, *lp1; - short *sp, *sp1; - signed char *bp, *bp1; - unsigned char *ubp, *ubp1; - unsigned short *usp, *usp1; - unsigned int *uip, *uip1; - long long *lip, *lip1; - unsigned long long *ulip, *ulip1; - size_t count = 0; - - *range_error = 0; - LOG((3, "%s: len %d src_type %d dest_type %d src_long %d dest_long %d", - __func__, len, src_type, dest_type, src_long, dest_long)); - - /* OK, this is ugly. If you can think of anything better, I'm open - to suggestions! - - Note that we don't use a default fill value for type - NC_BYTE. This is because Lord Voldemort cast a nofilleramous spell - at Harry Potter, but it bounced off his scar and hit the netcdf-4 - code. - */ - switch (src_type) - { - case NC_CHAR: + char *cp, *cp1; + float *fp, *fp1; + double *dp, *dp1; + int *ip, *ip1; + signed long *lp, *lp1; + short *sp, *sp1; + signed char *bp, *bp1; + unsigned char *ubp, *ubp1; + unsigned short *usp, *usp1; + unsigned int *uip, *uip1; + long long *lip, *lip1; + unsigned long long *ulip, *ulip1; + size_t count = 0; + + *range_error = 0; + LOG((3, "%s: len %d src_type %d dest_type %d src_long %d dest_long %d", + __func__, len, src_type, dest_type, src_long, dest_long)); + + /* OK, this is ugly. If you can think of anything better, I'm open + to suggestions! + + Note that we don't use a default fill value for type + NC_BYTE. This is because Lord Voldemort cast a nofilleramous spell + at Harry Potter, but it bounced off his scar and hit the netcdf-4 + code. + */ + switch (src_type) + { + case NC_CHAR: switch (dest_type) - { - case NC_CHAR: - for (cp = (char *)src, cp1 = dest; count < len; count++) + { + case NC_CHAR: + for (cp = (char *)src, cp1 = dest; count < len; count++) *cp1++ = *cp++; - break; - default: - LOG((0, "%s: Uknown destination type.", __func__)); - } + break; + default: + LOG((0, "%s: Uknown destination type.", __func__)); + } break; - case NC_BYTE: + case NC_BYTE: switch (dest_type) - { - case NC_BYTE: - for (bp = (signed char *)src, bp1 = dest; count < len; count++) + { + case NC_BYTE: + for (bp = (signed char *)src, bp1 = dest; count < len; count++) *bp1++ = *bp++; - break; - case NC_UBYTE: - for (bp = (signed char *)src, ubp = dest; count < len; count++) - { - if (*bp < 0) - (*range_error)++; - *ubp++ = *bp++; - } - break; - case NC_SHORT: - for (bp = (signed char *)src, sp = dest; count < len; count++) + break; + case NC_UBYTE: + for (bp = (signed char *)src, ubp = dest; count < len; count++) + { + if (*bp < 0) + (*range_error)++; + *ubp++ = *bp++; + } + break; + case NC_SHORT: + for (bp = (signed char *)src, sp = dest; count < len; count++) *sp++ = *bp++; - break; - case NC_USHORT: - for (bp = (signed char *)src, usp = dest; count < len; count++) - { - if (*bp < 0) - (*range_error)++; - *usp++ = *bp++; - } - break; - case NC_INT: - if (dest_long) - { - for (bp = (signed char *)src, lp = dest; count < len; count++) - *lp++ = *bp++; - break; - } - else - { - for (bp = (signed char *)src, ip = dest; count < len; count++) - *ip++ = *bp++; - break; - } - case NC_UINT: - for (bp = (signed char *)src, uip = dest; count < len; count++) - { - if (*bp < 0) - (*range_error)++; - *uip++ = *bp++; - } - break; - case NC_INT64: - for (bp = (signed char *)src, lip = dest; count < len; count++) + break; + case NC_USHORT: + for (bp = (signed char *)src, usp = dest; count < len; count++) + { + if (*bp < 0) + (*range_error)++; + *usp++ = *bp++; + } + break; + case NC_INT: + if (dest_long) + { + for (bp = (signed char *)src, lp = dest; count < len; count++) + *lp++ = *bp++; + break; + } + else + { + for (bp = (signed char *)src, ip = dest; count < len; count++) + *ip++ = *bp++; + break; + } + case NC_UINT: + for (bp = (signed char *)src, uip = dest; count < len; count++) + { + if (*bp < 0) + (*range_error)++; + *uip++ = *bp++; + } + break; + case NC_INT64: + for (bp = (signed char *)src, lip = dest; count < len; count++) *lip++ = *bp++; - break; - case NC_UINT64: - for (bp = (signed char *)src, ulip = dest; count < len; count++) - { - if (*bp < 0) - (*range_error)++; - *ulip++ = *bp++; - } - break; - case NC_FLOAT: - for (bp = (signed char *)src, fp = dest; count < len; count++) + break; + case NC_UINT64: + for (bp = (signed char *)src, ulip = dest; count < len; count++) + { + if (*bp < 0) + (*range_error)++; + *ulip++ = *bp++; + } + break; + case NC_FLOAT: + for (bp = (signed char *)src, fp = dest; count < len; count++) *fp++ = *bp++; - break; - case NC_DOUBLE: - for (bp = (signed char *)src, dp = dest; count < len; count++) + break; + case NC_DOUBLE: + for (bp = (signed char *)src, dp = dest; count < len; count++) *dp++ = *bp++; - break; - default: - LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", - __func__, src_type, dest_type)); - return NC_EBADTYPE; - } + break; + default: + LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); + return NC_EBADTYPE; + } break; - case NC_UBYTE: + case NC_UBYTE: switch (dest_type) - { - case NC_BYTE: - for (ubp = (unsigned char *)src, bp = dest; count < len; count++) - { - if (!strict_nc3 && *ubp > X_SCHAR_MAX) - (*range_error)++; - *bp++ = *ubp++; - } - break; - case NC_SHORT: - for (ubp = (unsigned char *)src, sp = dest; count < len; count++) + { + case NC_BYTE: + for (ubp = (unsigned char *)src, bp = dest; count < len; count++) + { + if (!strict_nc3 && *ubp > X_SCHAR_MAX) + (*range_error)++; + *bp++ = *ubp++; + } + break; + case NC_SHORT: + for (ubp = (unsigned char *)src, sp = dest; count < len; count++) *sp++ = *ubp++; - break; - case NC_UBYTE: - for (ubp = (unsigned char *)src, ubp1 = dest; count < len; count++) + break; + case NC_UBYTE: + for (ubp = (unsigned char *)src, ubp1 = dest; count < len; count++) *ubp1++ = *ubp++; - break; - case NC_USHORT: - for (ubp = (unsigned char *)src, usp = dest; count < len; count++) + break; + case NC_USHORT: + for (ubp = (unsigned char *)src, usp = dest; count < len; count++) *usp++ = *ubp++; - break; - case NC_INT: - if (dest_long) - { - for (ubp = (unsigned char *)src, lp = dest; count < len; count++) - *lp++ = *ubp++; - break; - } - else - { - for (ubp = (unsigned char *)src, ip = dest; count < len; count++) - *ip++ = *ubp++; - break; - } - case NC_UINT: - for (ubp = (unsigned char *)src, uip = dest; count < len; count++) + break; + case NC_INT: + if (dest_long) + { + for (ubp = (unsigned char *)src, lp = dest; count < len; count++) + *lp++ = *ubp++; + break; + } + else + { + for (ubp = (unsigned char *)src, ip = dest; count < len; count++) + *ip++ = *ubp++; + break; + } + case NC_UINT: + for (ubp = (unsigned char *)src, uip = dest; count < len; count++) *uip++ = *ubp++; - break; - case NC_INT64: - for (ubp = (unsigned char *)src, lip = dest; count < len; count++) + break; + case NC_INT64: + for (ubp = (unsigned char *)src, lip = dest; count < len; count++) *lip++ = *ubp++; - break; - case NC_UINT64: - for (ubp = (unsigned char *)src, ulip = dest; count < len; count++) + break; + case NC_UINT64: + for (ubp = (unsigned char *)src, ulip = dest; count < len; count++) *ulip++ = *ubp++; - break; - case NC_FLOAT: - for (ubp = (unsigned char *)src, fp = dest; count < len; count++) + break; + case NC_FLOAT: + for (ubp = (unsigned char *)src, fp = dest; count < len; count++) *fp++ = *ubp++; - break; - case NC_DOUBLE: - for (ubp = (unsigned char *)src, dp = dest; count < len; count++) + break; + case NC_DOUBLE: + for (ubp = (unsigned char *)src, dp = dest; count < len; count++) *dp++ = *ubp++; - break; - default: - LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", - __func__, src_type, dest_type)); - return NC_EBADTYPE; - } + break; + default: + LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); + return NC_EBADTYPE; + } break; - case NC_SHORT: + case NC_SHORT: switch (dest_type) - { - case NC_UBYTE: - for (sp = (short *)src, ubp = dest; count < len; count++) - { - if (*sp > X_UCHAR_MAX || *sp < 0) - (*range_error)++; - *ubp++ = *sp++; - } - break; - case NC_BYTE: - for (sp = (short *)src, bp = dest; count < len; count++) - { - if (*sp > X_SCHAR_MAX || *sp < X_SCHAR_MIN) - (*range_error)++; - *bp++ = *sp++; - } - break; - case NC_SHORT: - for (sp = (short *)src, sp1 = dest; count < len; count++) + { + case NC_UBYTE: + for (sp = (short *)src, ubp = dest; count < len; count++) + { + if (*sp > X_UCHAR_MAX || *sp < 0) + (*range_error)++; + *ubp++ = *sp++; + } + break; + case NC_BYTE: + for (sp = (short *)src, bp = dest; count < len; count++) + { + if (*sp > X_SCHAR_MAX || *sp < X_SCHAR_MIN) + (*range_error)++; + *bp++ = *sp++; + } + break; + case NC_SHORT: + for (sp = (short *)src, sp1 = dest; count < len; count++) *sp1++ = *sp++; - break; - case NC_USHORT: - for (sp = (short *)src, usp = dest; count < len; count++) - { - if (*sp < 0) - (*range_error)++; - *usp++ = *sp++; - } - break; - case NC_INT: - if (dest_long) + break; + case NC_USHORT: + for (sp = (short *)src, usp = dest; count < len; count++) + { + if (*sp < 0) + (*range_error)++; + *usp++ = *sp++; + } + break; + case NC_INT: + if (dest_long) for (sp = (short *)src, lp = dest; count < len; count++) - *lp++ = *sp++; - else + *lp++ = *sp++; + else for (sp = (short *)src, ip = dest; count < len; count++) - *ip++ = *sp++; - break; - case NC_UINT: - for (sp = (short *)src, uip = dest; count < len; count++) - { - if (*sp < 0) - (*range_error)++; - *uip++ = *sp++; - } - break; - case NC_INT64: - for (sp = (short *)src, lip = dest; count < len; count++) + *ip++ = *sp++; + break; + case NC_UINT: + for (sp = (short *)src, uip = dest; count < len; count++) + { + if (*sp < 0) + (*range_error)++; + *uip++ = *sp++; + } + break; + case NC_INT64: + for (sp = (short *)src, lip = dest; count < len; count++) *lip++ = *sp++; - break; - case NC_UINT64: - for (sp = (short *)src, ulip = dest; count < len; count++) - { - if (*sp < 0) - (*range_error)++; - *ulip++ = *sp++; - } - break; - case NC_FLOAT: - for (sp = (short *)src, fp = dest; count < len; count++) + break; + case NC_UINT64: + for (sp = (short *)src, ulip = dest; count < len; count++) + { + if (*sp < 0) + (*range_error)++; + *ulip++ = *sp++; + } + break; + case NC_FLOAT: + for (sp = (short *)src, fp = dest; count < len; count++) *fp++ = *sp++; - break; - case NC_DOUBLE: - for (sp = (short *)src, dp = dest; count < len; count++) + break; + case NC_DOUBLE: + for (sp = (short *)src, dp = dest; count < len; count++) *dp++ = *sp++; - break; - default: - LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", - __func__, src_type, dest_type)); - return NC_EBADTYPE; - } + break; + default: + LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); + return NC_EBADTYPE; + } break; - case NC_USHORT: + case NC_USHORT: switch (dest_type) - { - case NC_UBYTE: - for (usp = (unsigned short *)src, ubp = dest; count < len; count++) - { - if (*usp > X_UCHAR_MAX) - (*range_error)++; - *ubp++ = *usp++; - } - break; - case NC_BYTE: - for (usp = (unsigned short *)src, bp = dest; count < len; count++) - { - if (*usp > X_SCHAR_MAX) - (*range_error)++; - *bp++ = *usp++; - } - break; - case NC_SHORT: - for (usp = (unsigned short *)src, sp = dest; count < len; count++) - { - if (*usp > X_SHORT_MAX) - (*range_error)++; - *sp++ = *usp++; - } - break; - case NC_USHORT: - for (usp = (unsigned short *)src, usp1 = dest; count < len; count++) + { + case NC_UBYTE: + for (usp = (unsigned short *)src, ubp = dest; count < len; count++) + { + if (*usp > X_UCHAR_MAX) + (*range_error)++; + *ubp++ = *usp++; + } + break; + case NC_BYTE: + for (usp = (unsigned short *)src, bp = dest; count < len; count++) + { + if (*usp > X_SCHAR_MAX) + (*range_error)++; + *bp++ = *usp++; + } + break; + case NC_SHORT: + for (usp = (unsigned short *)src, sp = dest; count < len; count++) + { + if (*usp > X_SHORT_MAX) + (*range_error)++; + *sp++ = *usp++; + } + break; + case NC_USHORT: + for (usp = (unsigned short *)src, usp1 = dest; count < len; count++) *usp1++ = *usp++; - break; - case NC_INT: - if (dest_long) + break; + case NC_INT: + if (dest_long) for (usp = (unsigned short *)src, lp = dest; count < len; count++) - *lp++ = *usp++; - else + *lp++ = *usp++; + else for (usp = (unsigned short *)src, ip = dest; count < len; count++) - *ip++ = *usp++; - break; - case NC_UINT: - for (usp = (unsigned short *)src, uip = dest; count < len; count++) + *ip++ = *usp++; + break; + case NC_UINT: + for (usp = (unsigned short *)src, uip = dest; count < len; count++) *uip++ = *usp++; - break; - case NC_INT64: - for (usp = (unsigned short *)src, lip = dest; count < len; count++) + break; + case NC_INT64: + for (usp = (unsigned short *)src, lip = dest; count < len; count++) *lip++ = *usp++; - break; - case NC_UINT64: - for (usp = (unsigned short *)src, ulip = dest; count < len; count++) + break; + case NC_UINT64: + for (usp = (unsigned short *)src, ulip = dest; count < len; count++) *ulip++ = *usp++; - break; - case NC_FLOAT: - for (usp = (unsigned short *)src, fp = dest; count < len; count++) + break; + case NC_FLOAT: + for (usp = (unsigned short *)src, fp = dest; count < len; count++) *fp++ = *usp++; - break; - case NC_DOUBLE: - for (usp = (unsigned short *)src, dp = dest; count < len; count++) + break; + case NC_DOUBLE: + for (usp = (unsigned short *)src, dp = dest; count < len; count++) *dp++ = *usp++; - break; - default: - LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", - __func__, src_type, dest_type)); - return NC_EBADTYPE; - } + break; + default: + LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); + return NC_EBADTYPE; + } break; - case NC_INT: + case NC_INT: if (src_long) - { - switch (dest_type) + { + switch (dest_type) + { + case NC_UBYTE: + for (lp = (long *)src, ubp = dest; count < len; count++) { - case NC_UBYTE: - for (lp = (long *)src, ubp = dest; count < len; count++) - { - if (*lp > X_UCHAR_MAX || *lp < 0) - (*range_error)++; - *ubp++ = *lp++; - } - break; - case NC_BYTE: - for (lp = (long *)src, bp = dest; count < len; count++) - { - if (*lp > X_SCHAR_MAX || *lp < X_SCHAR_MIN) - (*range_error)++; - *bp++ = *lp++; - } - break; - case NC_SHORT: - for (lp = (long *)src, sp = dest; count < len; count++) - { - if (*lp > X_SHORT_MAX || *lp < X_SHORT_MIN) - (*range_error)++; - *sp++ = *lp++; - } - break; - case NC_USHORT: - for (lp = (long *)src, usp = dest; count < len; count++) - { - if (*lp > X_USHORT_MAX || *lp < 0) - (*range_error)++; - *usp++ = *lp++; - } - break; - case NC_INT: /* src is long */ - if (dest_long) - { - for (lp = (long *)src, lp1 = dest; count < len; count++) - { - if (*lp > X_LONG_MAX || *lp < X_LONG_MIN) - (*range_error)++; - *lp1++ = *lp++; - } - } - else /* dest is int */ - { - for (lp = (long *)src, ip = dest; count < len; count++) - { - if (*lp > X_INT_MAX || *lp < X_INT_MIN) - (*range_error)++; - *ip++ = *lp++; - } - } - break; - case NC_UINT: - for (lp = (long *)src, uip = dest; count < len; count++) - { - if (*lp > X_UINT_MAX || *lp < 0) - (*range_error)++; - *uip++ = *lp++; - } - break; - case NC_INT64: - for (lp = (long *)src, lip = dest; count < len; count++) - *lip++ = *lp++; - break; - case NC_UINT64: - for (lp = (long *)src, ulip = dest; count < len; count++) - { - if (*lp < 0) - (*range_error)++; - *ulip++ = *lp++; - } - break; - case NC_FLOAT: - for (lp = (long *)src, fp = dest; count < len; count++) - *fp++ = *lp++; - break; - case NC_DOUBLE: - for (lp = (long *)src, dp = dest; count < len; count++) - *dp++ = *lp++; - break; - default: - LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", - __func__, src_type, dest_type)); - return NC_EBADTYPE; + if (*lp > X_UCHAR_MAX || *lp < 0) + (*range_error)++; + *ubp++ = *lp++; } - } - else - { - switch (dest_type) + break; + case NC_BYTE: + for (lp = (long *)src, bp = dest; count < len; count++) { - case NC_UBYTE: - for (ip = (int *)src, ubp = dest; count < len; count++) - { - if (*ip > X_UCHAR_MAX || *ip < 0) - (*range_error)++; - *ubp++ = *ip++; - } - break; - case NC_BYTE: - for (ip = (int *)src, bp = dest; count < len; count++) - { - if (*ip > X_SCHAR_MAX || *ip < X_SCHAR_MIN) - (*range_error)++; - *bp++ = *ip++; - } - break; - case NC_SHORT: - for (ip = (int *)src, sp = dest; count < len; count++) - { - if (*ip > X_SHORT_MAX || *ip < X_SHORT_MIN) - (*range_error)++; - *sp++ = *ip++; - } - break; - case NC_USHORT: - for (ip = (int *)src, usp = dest; count < len; count++) - { - if (*ip > X_USHORT_MAX || *ip < 0) - (*range_error)++; - *usp++ = *ip++; - } - break; - case NC_INT: /* src is int */ - if (dest_long) - { - for (ip = (int *)src, lp1 = dest; count < len; count++) - { - if (*ip > X_LONG_MAX || *ip < X_LONG_MIN) - (*range_error)++; - *lp1++ = *ip++; - } - } - else /* dest is int */ - { - for (ip = (int *)src, ip1 = dest; count < len; count++) - { - if (*ip > X_INT_MAX || *ip < X_INT_MIN) - (*range_error)++; - *ip1++ = *ip++; - } - } - break; - case NC_UINT: - for (ip = (int *)src, uip = dest; count < len; count++) - { - if (*ip > X_UINT_MAX || *ip < 0) - (*range_error)++; - *uip++ = *ip++; - } - break; - case NC_INT64: - for (ip = (int *)src, lip = dest; count < len; count++) - *lip++ = *ip++; - break; - case NC_UINT64: - for (ip = (int *)src, ulip = dest; count < len; count++) - { - if (*ip < 0) - (*range_error)++; - *ulip++ = *ip++; - } - break; - case NC_FLOAT: - for (ip = (int *)src, fp = dest; count < len; count++) - *fp++ = *ip++; - break; - case NC_DOUBLE: - for (ip = (int *)src, dp = dest; count < len; count++) - *dp++ = *ip++; - break; - default: - LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", - __func__, src_type, dest_type)); - return NC_EBADTYPE; + if (*lp > X_SCHAR_MAX || *lp < X_SCHAR_MIN) + (*range_error)++; + *bp++ = *lp++; } - } - break; - - case NC_UINT: - switch (dest_type) - { - case NC_UBYTE: - for (uip = (unsigned int *)src, ubp = dest; count < len; count++) + break; + case NC_SHORT: + for (lp = (long *)src, sp = dest; count < len; count++) { - if (*uip > X_UCHAR_MAX) - (*range_error)++; - *ubp++ = *uip++; + if (*lp > X_SHORT_MAX || *lp < X_SHORT_MIN) + (*range_error)++; + *sp++ = *lp++; } - break; - case NC_BYTE: - for (uip = (unsigned int *)src, bp = dest; count < len; count++) + break; + case NC_USHORT: + for (lp = (long *)src, usp = dest; count < len; count++) { - if (*uip > X_SCHAR_MAX) - (*range_error)++; - *bp++ = *uip++; + if (*lp > X_USHORT_MAX || *lp < 0) + (*range_error)++; + *usp++ = *lp++; } - break; - case NC_SHORT: - for (uip = (unsigned int *)src, sp = dest; count < len; count++) + break; + case NC_INT: /* src is long */ + if (dest_long) { - if (*uip > X_SHORT_MAX) - (*range_error)++; - *sp++ = *uip++; + for (lp = (long *)src, lp1 = dest; count < len; count++) + { + if (*lp > X_LONG_MAX || *lp < X_LONG_MIN) + (*range_error)++; + *lp1++ = *lp++; + } } - break; - case NC_USHORT: - for (uip = (unsigned int *)src, usp = dest; count < len; count++) + else /* dest is int */ { - if (*uip > X_USHORT_MAX) - (*range_error)++; - *usp++ = *uip++; + for (lp = (long *)src, ip = dest; count < len; count++) + { + if (*lp > X_INT_MAX || *lp < X_INT_MIN) + (*range_error)++; + *ip++ = *lp++; + } } - break; - case NC_INT: - if (dest_long) - for (uip = (unsigned int *)src, lp = dest; count < len; count++) - { - if (*uip > X_LONG_MAX) + break; + case NC_UINT: + for (lp = (long *)src, uip = dest; count < len; count++) + { + if (*lp > X_UINT_MAX || *lp < 0) (*range_error)++; - *lp++ = *uip++; - } - else - for (uip = (unsigned int *)src, ip = dest; count < len; count++) - { - if (*uip > X_INT_MAX) + *uip++ = *lp++; + } + break; + case NC_INT64: + for (lp = (long *)src, lip = dest; count < len; count++) + *lip++ = *lp++; + break; + case NC_UINT64: + for (lp = (long *)src, ulip = dest; count < len; count++) + { + if (*lp < 0) (*range_error)++; - *ip++ = *uip++; - } - break; - case NC_UINT: - for (uip = (unsigned int *)src, uip1 = dest; count < len; count++) + *ulip++ = *lp++; + } + break; + case NC_FLOAT: + for (lp = (long *)src, fp = dest; count < len; count++) + *fp++ = *lp++; + break; + case NC_DOUBLE: + for (lp = (long *)src, dp = dest; count < len; count++) + *dp++ = *lp++; + break; + default: + LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); + return NC_EBADTYPE; + } + } + else + { + switch (dest_type) + { + case NC_UBYTE: + for (ip = (int *)src, ubp = dest; count < len; count++) { - if (*uip > X_UINT_MAX) - (*range_error)++; - *uip1++ = *uip++; + if (*ip > X_UCHAR_MAX || *ip < 0) + (*range_error)++; + *ubp++ = *ip++; } - break; - case NC_INT64: - for (uip = (unsigned int *)src, lip = dest; count < len; count++) - *lip++ = *uip++; - break; - case NC_UINT64: - for (uip = (unsigned int *)src, ulip = dest; count < len; count++) - *ulip++ = *uip++; - break; - case NC_FLOAT: - for (uip = (unsigned int *)src, fp = dest; count < len; count++) - *fp++ = *uip++; - break; - case NC_DOUBLE: - for (uip = (unsigned int *)src, dp = dest; count < len; count++) - *dp++ = *uip++; - break; - default: - LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", - __func__, src_type, dest_type)); - return NC_EBADTYPE; - } - break; - - case NC_INT64: - switch (dest_type) - { - case NC_UBYTE: - for (lip = (long long *)src, ubp = dest; count < len; count++) + break; + case NC_BYTE: + for (ip = (int *)src, bp = dest; count < len; count++) { - if (*lip > X_UCHAR_MAX || *lip < 0) - (*range_error)++; - *ubp++ = *lip++; + if (*ip > X_SCHAR_MAX || *ip < X_SCHAR_MIN) + (*range_error)++; + *bp++ = *ip++; } - break; - case NC_BYTE: - for (lip = (long long *)src, bp = dest; count < len; count++) + break; + case NC_SHORT: + for (ip = (int *)src, sp = dest; count < len; count++) { - if (*lip > X_SCHAR_MAX || *lip < X_SCHAR_MIN) - (*range_error)++; - *bp++ = *lip++; + if (*ip > X_SHORT_MAX || *ip < X_SHORT_MIN) + (*range_error)++; + *sp++ = *ip++; } - break; - case NC_SHORT: - for (lip = (long long *)src, sp = dest; count < len; count++) + break; + case NC_USHORT: + for (ip = (int *)src, usp = dest; count < len; count++) { - if (*lip > X_SHORT_MAX || *lip < X_SHORT_MIN) - (*range_error)++; - *sp++ = *lip++; + if (*ip > X_USHORT_MAX || *ip < 0) + (*range_error)++; + *usp++ = *ip++; } - break; - case NC_USHORT: - for (lip = (long long *)src, usp = dest; count < len; count++) + break; + case NC_INT: /* src is int */ + if (dest_long) { - if (*lip > X_USHORT_MAX || *lip < 0) - (*range_error)++; - *usp++ = *lip++; + for (ip = (int *)src, lp1 = dest; count < len; count++) + { + if (*ip > X_LONG_MAX || *ip < X_LONG_MIN) + (*range_error)++; + *lp1++ = *ip++; + } } - break; - case NC_UINT: - for (lip = (long long *)src, uip = dest; count < len; count++) + else /* dest is int */ { - if (*lip > X_UINT_MAX || *lip < 0) - (*range_error)++; - *uip++ = *lip++; + for (ip = (int *)src, ip1 = dest; count < len; count++) + { + if (*ip > X_INT_MAX || *ip < X_INT_MIN) + (*range_error)++; + *ip1++ = *ip++; + } } - break; - case NC_INT: - if (dest_long) - for (lip = (long long *)src, lp = dest; count < len; count++) - { - if (*lip > X_LONG_MAX || *lip < X_LONG_MIN) - (*range_error)++; - *lp++ = *lip++; - } - else - for (lip = (long long *)src, ip = dest; count < len; count++) - { - if (*lip > X_INT_MAX || *lip < X_INT_MIN) + break; + case NC_UINT: + for (ip = (int *)src, uip = dest; count < len; count++) + { + if (*ip > X_UINT_MAX || *ip < 0) (*range_error)++; - *ip++ = *lip++; - } - break; - case NC_INT64: - for (lip = (long long *)src, lip1 = dest; count < len; count++) - *lip1++ = *lip++; - break; - case NC_UINT64: - for (lip = (long long *)src, ulip = dest; count < len; count++) + *uip++ = *ip++; + } + break; + case NC_INT64: + for (ip = (int *)src, lip = dest; count < len; count++) + *lip++ = *ip++; + break; + case NC_UINT64: + for (ip = (int *)src, ulip = dest; count < len; count++) { - if (*lip < 0) - (*range_error)++; - *ulip++ = *lip++; + if (*ip < 0) + (*range_error)++; + *ulip++ = *ip++; } - break; - case NC_FLOAT: - for (lip = (long long *)src, fp = dest; count < len; count++) - *fp++ = *lip++; - break; - case NC_DOUBLE: - for (lip = (long long *)src, dp = dest; count < len; count++) - *dp++ = *lip++; - break; - default: - LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", - __func__, src_type, dest_type)); - return NC_EBADTYPE; - } + break; + case NC_FLOAT: + for (ip = (int *)src, fp = dest; count < len; count++) + *fp++ = *ip++; + break; + case NC_DOUBLE: + for (ip = (int *)src, dp = dest; count < len; count++) + *dp++ = *ip++; + break; + default: + LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); + return NC_EBADTYPE; + } + } break; - case NC_UINT64: + case NC_UINT: switch (dest_type) - { - case NC_UBYTE: - for (ulip = (unsigned long long *)src, ubp = dest; count < len; count++) - { - if (*ulip > X_UCHAR_MAX) - (*range_error)++; - *ubp++ = *ulip++; - } - break; - case NC_BYTE: - for (ulip = (unsigned long long *)src, bp = dest; count < len; count++) + { + case NC_UBYTE: + for (uip = (unsigned int *)src, ubp = dest; count < len; count++) + { + if (*uip > X_UCHAR_MAX) + (*range_error)++; + *ubp++ = *uip++; + } + break; + case NC_BYTE: + for (uip = (unsigned int *)src, bp = dest; count < len; count++) + { + if (*uip > X_SCHAR_MAX) + (*range_error)++; + *bp++ = *uip++; + } + break; + case NC_SHORT: + for (uip = (unsigned int *)src, sp = dest; count < len; count++) + { + if (*uip > X_SHORT_MAX) + (*range_error)++; + *sp++ = *uip++; + } + break; + case NC_USHORT: + for (uip = (unsigned int *)src, usp = dest; count < len; count++) + { + if (*uip > X_USHORT_MAX) + (*range_error)++; + *usp++ = *uip++; + } + break; + case NC_INT: + if (dest_long) + for (uip = (unsigned int *)src, lp = dest; count < len; count++) { - if (*ulip > X_SCHAR_MAX) - (*range_error)++; - *bp++ = *ulip++; + if (*uip > X_LONG_MAX) + (*range_error)++; + *lp++ = *uip++; } - break; - case NC_SHORT: - for (ulip = (unsigned long long *)src, sp = dest; count < len; count++) + else + for (uip = (unsigned int *)src, ip = dest; count < len; count++) { - if (*ulip > X_SHORT_MAX) - (*range_error)++; - *sp++ = *ulip++; + if (*uip > X_INT_MAX) + (*range_error)++; + *ip++ = *uip++; } - break; - case NC_USHORT: - for (ulip = (unsigned long long *)src, usp = dest; count < len; count++) + break; + case NC_UINT: + for (uip = (unsigned int *)src, uip1 = dest; count < len; count++) + { + if (*uip > X_UINT_MAX) + (*range_error)++; + *uip1++ = *uip++; + } + break; + case NC_INT64: + for (uip = (unsigned int *)src, lip = dest; count < len; count++) + *lip++ = *uip++; + break; + case NC_UINT64: + for (uip = (unsigned int *)src, ulip = dest; count < len; count++) + *ulip++ = *uip++; + break; + case NC_FLOAT: + for (uip = (unsigned int *)src, fp = dest; count < len; count++) + *fp++ = *uip++; + break; + case NC_DOUBLE: + for (uip = (unsigned int *)src, dp = dest; count < len; count++) + *dp++ = *uip++; + break; + default: + LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); + return NC_EBADTYPE; + } + break; + + case NC_INT64: + switch (dest_type) + { + case NC_UBYTE: + for (lip = (long long *)src, ubp = dest; count < len; count++) + { + if (*lip > X_UCHAR_MAX || *lip < 0) + (*range_error)++; + *ubp++ = *lip++; + } + break; + case NC_BYTE: + for (lip = (long long *)src, bp = dest; count < len; count++) + { + if (*lip > X_SCHAR_MAX || *lip < X_SCHAR_MIN) + (*range_error)++; + *bp++ = *lip++; + } + break; + case NC_SHORT: + for (lip = (long long *)src, sp = dest; count < len; count++) + { + if (*lip > X_SHORT_MAX || *lip < X_SHORT_MIN) + (*range_error)++; + *sp++ = *lip++; + } + break; + case NC_USHORT: + for (lip = (long long *)src, usp = dest; count < len; count++) + { + if (*lip > X_USHORT_MAX || *lip < 0) + (*range_error)++; + *usp++ = *lip++; + } + break; + case NC_UINT: + for (lip = (long long *)src, uip = dest; count < len; count++) + { + if (*lip > X_UINT_MAX || *lip < 0) + (*range_error)++; + *uip++ = *lip++; + } + break; + case NC_INT: + if (dest_long) + for (lip = (long long *)src, lp = dest; count < len; count++) { - if (*ulip > X_USHORT_MAX) - (*range_error)++; - *usp++ = *ulip++; + if (*lip > X_LONG_MAX || *lip < X_LONG_MIN) + (*range_error)++; + *lp++ = *lip++; } - break; - case NC_UINT: - for (ulip = (unsigned long long *)src, uip = dest; count < len; count++) + else + for (lip = (long long *)src, ip = dest; count < len; count++) { - if (*ulip > X_UINT_MAX) - (*range_error)++; - *uip++ = *ulip++; + if (*lip > X_INT_MAX || *lip < X_INT_MIN) + (*range_error)++; + *ip++ = *lip++; } - break; - case NC_INT: - if (dest_long) + break; + case NC_INT64: + for (lip = (long long *)src, lip1 = dest; count < len; count++) + *lip1++ = *lip++; + break; + case NC_UINT64: + for (lip = (long long *)src, ulip = dest; count < len; count++) + { + if (*lip < 0) + (*range_error)++; + *ulip++ = *lip++; + } + break; + case NC_FLOAT: + for (lip = (long long *)src, fp = dest; count < len; count++) + *fp++ = *lip++; + break; + case NC_DOUBLE: + for (lip = (long long *)src, dp = dest; count < len; count++) + *dp++ = *lip++; + break; + default: + LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); + return NC_EBADTYPE; + } + break; + + case NC_UINT64: + switch (dest_type) + { + case NC_UBYTE: + for (ulip = (unsigned long long *)src, ubp = dest; count < len; count++) + { + if (*ulip > X_UCHAR_MAX) + (*range_error)++; + *ubp++ = *ulip++; + } + break; + case NC_BYTE: + for (ulip = (unsigned long long *)src, bp = dest; count < len; count++) + { + if (*ulip > X_SCHAR_MAX) + (*range_error)++; + *bp++ = *ulip++; + } + break; + case NC_SHORT: + for (ulip = (unsigned long long *)src, sp = dest; count < len; count++) + { + if (*ulip > X_SHORT_MAX) + (*range_error)++; + *sp++ = *ulip++; + } + break; + case NC_USHORT: + for (ulip = (unsigned long long *)src, usp = dest; count < len; count++) + { + if (*ulip > X_USHORT_MAX) + (*range_error)++; + *usp++ = *ulip++; + } + break; + case NC_UINT: + for (ulip = (unsigned long long *)src, uip = dest; count < len; count++) + { + if (*ulip > X_UINT_MAX) + (*range_error)++; + *uip++ = *ulip++; + } + break; + case NC_INT: + if (dest_long) for (ulip = (unsigned long long *)src, lp = dest; count < len; count++) - { - if (*ulip > X_LONG_MAX) + { + if (*ulip > X_LONG_MAX) (*range_error)++; - *lp++ = *ulip++; - } - else + *lp++ = *ulip++; + } + else for (ulip = (unsigned long long *)src, ip = dest; count < len; count++) - { - if (*ulip > X_INT_MAX) - (*range_error)++; - *ip++ = *ulip++; - } - break; - case NC_INT64: - for (ulip = (unsigned long long *)src, lip = dest; count < len; count++) { - if (*ulip > X_INT64_MAX) - (*range_error)++; - *lip++ = *ulip++; + if (*ulip > X_INT_MAX) + (*range_error)++; + *ip++ = *ulip++; } - break; - case NC_UINT64: - for (ulip = (unsigned long long *)src, ulip1 = dest; count < len; count++) + break; + case NC_INT64: + for (ulip = (unsigned long long *)src, lip = dest; count < len; count++) + { + if (*ulip > X_INT64_MAX) + (*range_error)++; + *lip++ = *ulip++; + } + break; + case NC_UINT64: + for (ulip = (unsigned long long *)src, ulip1 = dest; count < len; count++) *ulip1++ = *ulip++; - break; - case NC_FLOAT: - for (ulip = (unsigned long long *)src, fp = dest; count < len; count++) + break; + case NC_FLOAT: + for (ulip = (unsigned long long *)src, fp = dest; count < len; count++) *fp++ = *ulip++; - break; - case NC_DOUBLE: - for (ulip = (unsigned long long *)src, dp = dest; count < len; count++) + break; + case NC_DOUBLE: + for (ulip = (unsigned long long *)src, dp = dest; count < len; count++) *dp++ = *ulip++; - break; - default: - LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", - __func__, src_type, dest_type)); - return NC_EBADTYPE; - } + break; + default: + LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); + return NC_EBADTYPE; + } break; - case NC_FLOAT: + case NC_FLOAT: switch (dest_type) - { - case NC_UBYTE: - for (fp = (float *)src, ubp = dest; count < len; count++) - { - if (*fp > X_UCHAR_MAX || *fp < 0) - (*range_error)++; - *ubp++ = *fp++; - } - break; - case NC_BYTE: - for (fp = (float *)src, bp = dest; count < len; count++) - { - if (*fp > (double)X_SCHAR_MAX || *fp < (double)X_SCHAR_MIN) - (*range_error)++; - *bp++ = *fp++; - } - break; - case NC_SHORT: - for (fp = (float *)src, sp = dest; count < len; count++) - { - if (*fp > (double)X_SHORT_MAX || *fp < (double)X_SHORT_MIN) - (*range_error)++; - *sp++ = *fp++; - } - break; - case NC_USHORT: - for (fp = (float *)src, usp = dest; count < len; count++) - { - if (*fp > X_USHORT_MAX || *fp < 0) - (*range_error)++; - *usp++ = *fp++; - } - break; - case NC_UINT: - for (fp = (float *)src, uip = dest; count < len; count++) - { - if (*fp > X_UINT_MAX || *fp < 0) - (*range_error)++; - *uip++ = *fp++; - } - break; - case NC_INT: - if (dest_long) + { + case NC_UBYTE: + for (fp = (float *)src, ubp = dest; count < len; count++) + { + if (*fp > X_UCHAR_MAX || *fp < 0) + (*range_error)++; + *ubp++ = *fp++; + } + break; + case NC_BYTE: + for (fp = (float *)src, bp = dest; count < len; count++) + { + if (*fp > (double)X_SCHAR_MAX || *fp < (double)X_SCHAR_MIN) + (*range_error)++; + *bp++ = *fp++; + } + break; + case NC_SHORT: + for (fp = (float *)src, sp = dest; count < len; count++) + { + if (*fp > (double)X_SHORT_MAX || *fp < (double)X_SHORT_MIN) + (*range_error)++; + *sp++ = *fp++; + } + break; + case NC_USHORT: + for (fp = (float *)src, usp = dest; count < len; count++) + { + if (*fp > X_USHORT_MAX || *fp < 0) + (*range_error)++; + *usp++ = *fp++; + } + break; + case NC_UINT: + for (fp = (float *)src, uip = dest; count < len; count++) + { + if (*fp > X_UINT_MAX || *fp < 0) + (*range_error)++; + *uip++ = *fp++; + } + break; + case NC_INT: + if (dest_long) for (fp = (float *)src, lp = dest; count < len; count++) - { - if (*fp > (double)X_LONG_MAX || *fp < (double)X_LONG_MIN) - (*range_error)++; - *lp++ = *fp++; - } - else - for (fp = (float *)src, ip = dest; count < len; count++) - { - if (*fp > (double)X_INT_MAX || *fp < (double)X_INT_MIN) - (*range_error)++; - *ip++ = *fp++; - } - break; - case NC_INT64: - for (fp = (float *)src, lip = dest; count < len; count++) { - if (*fp > X_INT64_MAX || *fp X_UINT64_MAX || *fp < 0) - (*range_error)++; - *lip++ = *fp++; + if (*fp > (double)X_LONG_MAX || *fp < (double)X_LONG_MIN) + (*range_error)++; + *lp++ = *fp++; } - break; - case NC_FLOAT: - for (fp = (float *)src, fp1 = dest; count < len; count++) + else + for (fp = (float *)src, ip = dest; count < len; count++) { - /* if (*fp > X_FLOAT_MAX || *fp < X_FLOAT_MIN) - (*range_error)++;*/ - *fp1++ = *fp++; + if (*fp > (double)X_INT_MAX || *fp < (double)X_INT_MIN) + (*range_error)++; + *ip++ = *fp++; } - break; - case NC_DOUBLE: - for (fp = (float *)src, dp = dest; count < len; count++) + break; + case NC_INT64: + for (fp = (float *)src, lip = dest; count < len; count++) + { + if (*fp > X_INT64_MAX || *fp X_UINT64_MAX || *fp < 0) + (*range_error)++; + *lip++ = *fp++; + } + break; + case NC_FLOAT: + for (fp = (float *)src, fp1 = dest; count < len; count++) + { + /* if (*fp > X_FLOAT_MAX || *fp < X_FLOAT_MIN) + (*range_error)++;*/ + *fp1++ = *fp++; + } + break; + case NC_DOUBLE: + for (fp = (float *)src, dp = dest; count < len; count++) *dp++ = *fp++; - break; - default: - LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", - __func__, src_type, dest_type)); - return NC_EBADTYPE; - } + break; + default: + LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); + return NC_EBADTYPE; + } break; - case NC_DOUBLE: + case NC_DOUBLE: switch (dest_type) - { - case NC_UBYTE: - for (dp = (double *)src, ubp = dest; count < len; count++) - { - if (*dp > X_UCHAR_MAX || *dp < 0) - (*range_error)++; - *ubp++ = *dp++; - } - break; - case NC_BYTE: - for (dp = (double *)src, bp = dest; count < len; count++) - { - if (*dp > X_SCHAR_MAX || *dp < X_SCHAR_MIN) - (*range_error)++; - *bp++ = *dp++; - } - break; - case NC_SHORT: - for (dp = (double *)src, sp = dest; count < len; count++) - { - if (*dp > X_SHORT_MAX || *dp < X_SHORT_MIN) - (*range_error)++; - *sp++ = *dp++; - } - break; - case NC_USHORT: - for (dp = (double *)src, usp = dest; count < len; count++) - { - if (*dp > X_USHORT_MAX || *dp < 0) - (*range_error)++; - *usp++ = *dp++; - } - break; - case NC_UINT: - for (dp = (double *)src, uip = dest; count < len; count++) - { - if (*dp > X_UINT_MAX || *dp < 0) - (*range_error)++; - *uip++ = *dp++; - } - break; - case NC_INT: - if (dest_long) + { + case NC_UBYTE: + for (dp = (double *)src, ubp = dest; count < len; count++) + { + if (*dp > X_UCHAR_MAX || *dp < 0) + (*range_error)++; + *ubp++ = *dp++; + } + break; + case NC_BYTE: + for (dp = (double *)src, bp = dest; count < len; count++) + { + if (*dp > X_SCHAR_MAX || *dp < X_SCHAR_MIN) + (*range_error)++; + *bp++ = *dp++; + } + break; + case NC_SHORT: + for (dp = (double *)src, sp = dest; count < len; count++) + { + if (*dp > X_SHORT_MAX || *dp < X_SHORT_MIN) + (*range_error)++; + *sp++ = *dp++; + } + break; + case NC_USHORT: + for (dp = (double *)src, usp = dest; count < len; count++) + { + if (*dp > X_USHORT_MAX || *dp < 0) + (*range_error)++; + *usp++ = *dp++; + } + break; + case NC_UINT: + for (dp = (double *)src, uip = dest; count < len; count++) + { + if (*dp > X_UINT_MAX || *dp < 0) + (*range_error)++; + *uip++ = *dp++; + } + break; + case NC_INT: + if (dest_long) for (dp = (double *)src, lp = dest; count < len; count++) - { - if (*dp > X_LONG_MAX || *dp < X_LONG_MIN) - (*range_error)++; - *lp++ = *dp++; - } - else - for (dp = (double *)src, ip = dest; count < len; count++) - { - if (*dp > X_INT_MAX || *dp < X_INT_MIN) - (*range_error)++; - *ip++ = *dp++; - } - break; - case NC_INT64: - for (dp = (double *)src, lip = dest; count < len; count++) { - if (*dp > X_INT64_MAX || *dp < X_INT64_MIN) - (*range_error)++; - *lip++ = *dp++; - } - break; - case NC_UINT64: - for (dp = (double *)src, lip = dest; count < len; count++) - { - if (*dp > X_UINT64_MAX || *dp < 0) - (*range_error)++; - *lip++ = *dp++; - } - break; - case NC_FLOAT: - for (dp = (double *)src, fp = dest; count < len; count++) - { - if (*dp > X_FLOAT_MAX || *dp < X_FLOAT_MIN) - (*range_error)++; - *fp++ = *dp++; + if (*dp > X_LONG_MAX || *dp < X_LONG_MIN) + (*range_error)++; + *lp++ = *dp++; } - break; - case NC_DOUBLE: - for (dp = (double *)src, dp1 = dest; count < len; count++) + else + for (dp = (double *)src, ip = dest; count < len; count++) { - /* if (*dp > X_DOUBLE_MAX || *dp < X_DOUBLE_MIN) */ - /* (*range_error)++; */ - *dp1++ = *dp++; + if (*dp > X_INT_MAX || *dp < X_INT_MIN) + (*range_error)++; + *ip++ = *dp++; } - break; - default: - LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", - __func__, src_type, dest_type)); - return NC_EBADTYPE; - } + break; + case NC_INT64: + for (dp = (double *)src, lip = dest; count < len; count++) + { + if (*dp > X_INT64_MAX || *dp < X_INT64_MIN) + (*range_error)++; + *lip++ = *dp++; + } + break; + case NC_UINT64: + for (dp = (double *)src, lip = dest; count < len; count++) + { + if (*dp > X_UINT64_MAX || *dp < 0) + (*range_error)++; + *lip++ = *dp++; + } + break; + case NC_FLOAT: + for (dp = (double *)src, fp = dest; count < len; count++) + { + if (*dp > X_FLOAT_MAX || *dp < X_FLOAT_MIN) + (*range_error)++; + *fp++ = *dp++; + } + break; + case NC_DOUBLE: + for (dp = (double *)src, dp1 = dest; count < len; count++) + { + /* if (*dp > X_DOUBLE_MAX || *dp < X_DOUBLE_MIN) */ + /* (*range_error)++; */ + *dp1++ = *dp++; + } + break; + default: + LOG((0, "%s: unexpected dest type. src_type %d, dest_type %d", + __func__, src_type, dest_type)); + return NC_EBADTYPE; + } break; - default: + default: LOG((0, "%s: unexpected src type. src_type %d, dest_type %d", __func__, src_type, dest_type)); return NC_EBADTYPE; - } - return NC_NOERR; + } + return NC_NOERR; } -/* In our first pass through the data, we may have encountered - * variables before encountering their dimscales, so go through the - * vars in this file and make sure we've got a dimid for each. */ +/** + * @internal In our first pass through the data, we may have + * encountered variables before encountering their dimscales, so go + * through the vars in this file and make sure we've got a dimid for + * each. + * + * @param grp Pointer to group info struct. + * + * @returns NC_NOERR No error. + * @returns NC_EHDFERR HDF5 returned an error. + * @author Ed Hartnett +*/ int nc4_rec_match_dimscales(NC_GRP_INFO_T *grp) { - NC_GRP_INFO_T *g; - NC_VAR_INFO_T *var; - NC_DIM_INFO_T *dim; - int retval = NC_NOERR; - int i; - - assert(grp && grp->name); - LOG((4, "%s: grp->name %s", __func__, grp->name)); - - /* Perform var dimscale match for child groups. */ - for (g = grp->children; g; g = g->l.next) - if ((retval = nc4_rec_match_dimscales(g))) - return retval; - - /* Check all the vars in this group. If they have dimscale info, - * try and find a dimension for them. */ - for (i=0; i < grp->vars.nelems; i++) - { + NC_GRP_INFO_T *g; + NC_VAR_INFO_T *var; + NC_DIM_INFO_T *dim; + int retval = NC_NOERR; + int i; + + assert(grp && grp->name); + LOG((4, "%s: grp->name %s", __func__, grp->name)); + + /* Perform var dimscale match for child groups. */ + for (g = grp->children; g; g = g->l.next) + if ((retval = nc4_rec_match_dimscales(g))) + return retval; + + /* Check all the vars in this group. If they have dimscale info, + * try and find a dimension for them. */ + for (i=0; i < grp->vars.nelems; i++) + { int ndims; int d; var = grp->vars.value[i]; @@ -3563,479 +3873,566 @@ nc4_rec_match_dimscales(NC_GRP_INFO_T *grp) /* Check all vars and see if dim[i] != NULL if dimids[i] valid. */ ndims = var->ndims; for (d = 0; d < ndims; d++) - { - if (var->dim[d] == NULL) { - nc4_find_dim(grp, var->dimids[d], &var->dim[d], NULL); - } - /* assert(var->dim[d] && var->dim[d]->dimid == var->dimids[d]); */ - } + { + if (var->dim[d] == NULL) { + nc4_find_dim(grp, var->dimids[d], &var->dim[d], NULL); + } + /* assert(var->dim[d] && var->dim[d]->dimid == var->dimids[d]); */ + } /* Skip dimension scale variables */ if (!var->dimscale) - { - int d; + { + int d; - /* Are there dimscales for this variable? */ - if (var->dimscale_hdf5_objids) + /* Are there dimscales for this variable? */ + if (var->dimscale_hdf5_objids) + { + for (d = 0; d < var->ndims; d++) { - for (d = 0; d < var->ndims; d++) - { - nc_bool_t finished = NC_FALSE; - - LOG((5, "%s: var %s has dimscale info...", __func__, var->name)); - /* Look at all the dims in this group to see if they - * match. */ - for (g = grp; g && !finished; g = g->parent) - { - for (dim = g->dim; dim; dim = dim->l.next) - { - if (var->dimscale_hdf5_objids[d].fileno[0] == dim->hdf5_objid.fileno[0] && - var->dimscale_hdf5_objids[d].objno[0] == dim->hdf5_objid.objno[0] && - var->dimscale_hdf5_objids[d].fileno[1] == dim->hdf5_objid.fileno[1] && - var->dimscale_hdf5_objids[d].objno[1] == dim->hdf5_objid.objno[1]) - { - LOG((4, "%s: for dimension %d, found dim %s", - __func__, d, dim->name)); - var->dimids[d] = dim->dimid; - var->dim[d] = dim; - finished = NC_TRUE; - break; - } - } /* next dim */ - } /* next grp */ - LOG((5, "%s: dimid for this dimscale is %d", __func__, var->type_info->nc_typeid)); - } /* next var->dim */ + nc_bool_t finished = NC_FALSE; + + LOG((5, "%s: var %s has dimscale info...", __func__, var->name)); + /* Look at all the dims in this group to see if they + * match. */ + for (g = grp; g && !finished; g = g->parent) + { + for (dim = g->dim; dim; dim = dim->l.next) + { + if (var->dimscale_hdf5_objids[d].fileno[0] == dim->hdf5_objid.fileno[0] && + var->dimscale_hdf5_objids[d].objno[0] == dim->hdf5_objid.objno[0] && + var->dimscale_hdf5_objids[d].fileno[1] == dim->hdf5_objid.fileno[1] && + var->dimscale_hdf5_objids[d].objno[1] == dim->hdf5_objid.objno[1]) + { + LOG((4, "%s: for dimension %d, found dim %s", + __func__, d, dim->name)); + var->dimids[d] = dim->dimid; + var->dim[d] = dim; + finished = NC_TRUE; + break; + } + } /* next dim */ + } /* next grp */ + LOG((5, "%s: dimid for this dimscale is %d", __func__, var->type_info->nc_typeid)); + } /* next var->dim */ + } + /* No dimscales for this var! Invent phony dimensions. */ + else + { + hid_t spaceid = 0; + hsize_t *h5dimlen = NULL, *h5dimlenmax = NULL; + int dataset_ndims; + + /* Find the space information for this dimension. */ + if ((spaceid = H5Dget_space(var->hdf_datasetid)) < 0) + return NC_EHDFERR; + + /* Get the len of each dim in the space. */ + if (var->ndims) + { + if (!(h5dimlen = malloc(var->ndims * sizeof(hsize_t)))) + return NC_ENOMEM; + if (!(h5dimlenmax = malloc(var->ndims * sizeof(hsize_t)))) + { + free(h5dimlen); + return NC_ENOMEM; + } + if ((dataset_ndims = H5Sget_simple_extent_dims(spaceid, h5dimlen, + h5dimlenmax)) < 0) { + free(h5dimlenmax); + free(h5dimlen); + return NC_EHDFERR; + } + if (dataset_ndims != var->ndims) { + free(h5dimlenmax); + free(h5dimlen); + return NC_EHDFERR; + } } - /* No dimscales for this var! Invent phony dimensions. */ - else + else { - hid_t spaceid = 0; - hsize_t *h5dimlen = NULL, *h5dimlenmax = NULL; - int dataset_ndims; - - /* Find the space information for this dimension. */ - if ((spaceid = H5Dget_space(var->hdf_datasetid)) < 0) - return NC_EHDFERR; - - /* Get the len of each dim in the space. */ - if (var->ndims) - { - if (!(h5dimlen = malloc(var->ndims * sizeof(hsize_t)))) - return NC_ENOMEM; - if (!(h5dimlenmax = malloc(var->ndims * sizeof(hsize_t)))) - { - free(h5dimlen); - return NC_ENOMEM; - } - if ((dataset_ndims = H5Sget_simple_extent_dims(spaceid, h5dimlen, - h5dimlenmax)) < 0) { - free(h5dimlenmax); - free(h5dimlen); - return NC_EHDFERR; + /* Make sure it's scalar. */ + if (H5Sget_simple_extent_type(spaceid) != H5S_SCALAR) + return NC_EHDFERR; + } + + /* Release the space object. */ + if (H5Sclose(spaceid) < 0) { + free(h5dimlen); + free(h5dimlenmax); + return NC_EHDFERR; + } + + /* Create a phony dimension for each dimension in the + * dataset, unless there already is one the correct + * size. */ + for (d = 0; d < var->ndims; d++) + { + /* Is there already a phony dimension of the correct size? */ + for (dim = grp->dim; dim; dim = dim->l.next) + if ((dim->len == h5dimlen[d]) && + ((h5dimlenmax[d] == H5S_UNLIMITED && dim->unlimited) || + (h5dimlenmax[d] != H5S_UNLIMITED && !dim->unlimited))) + break; + + /* Didn't find a phony dim? Then create one. */ + if (!dim) + { + char phony_dim_name[NC_MAX_NAME + 1]; + + LOG((3, "%s: creating phony dim for var %s", __func__, var->name)); + if ((retval = nc4_dim_list_add(&grp->dim, &dim))) { + free(h5dimlenmax); + free(h5dimlen); + return retval; } - if (dataset_ndims != var->ndims) { - free(h5dimlenmax); - free(h5dimlen); - return NC_EHDFERR; + dim->dimid = grp->nc4_info->next_dimid++; + sprintf(phony_dim_name, "phony_dim_%d", dim->dimid); + if (!(dim->name = strdup(phony_dim_name))) { + free(h5dimlenmax); + free(h5dimlen); + return NC_ENOMEM; } - } - else - { - /* Make sure it's scalar. */ - if (H5Sget_simple_extent_type(spaceid) != H5S_SCALAR) - return NC_EHDFERR; - } - - /* Release the space object. */ - if (H5Sclose(spaceid) < 0) { - free(h5dimlen); - free(h5dimlenmax); - return NC_EHDFERR; - } - - /* Create a phony dimension for each dimension in the - * dataset, unless there already is one the correct - * size. */ - for (d = 0; d < var->ndims; d++) - { - /* Is there already a phony dimension of the correct size? */ - for (dim = grp->dim; dim; dim = dim->l.next) - if ((dim->len == h5dimlen[d]) && - ((h5dimlenmax[d] == H5S_UNLIMITED && dim->unlimited) || - (h5dimlenmax[d] != H5S_UNLIMITED && !dim->unlimited))) - break; - - /* Didn't find a phony dim? Then create one. */ - if (!dim) - { - char phony_dim_name[NC_MAX_NAME + 1]; - - LOG((3, "%s: creating phony dim for var %s", __func__, var->name)); - if ((retval = nc4_dim_list_add(&grp->dim, &dim))) { - free(h5dimlenmax); - free(h5dimlen); - return retval; - } - dim->dimid = grp->nc4_info->next_dimid++; - sprintf(phony_dim_name, "phony_dim_%d", dim->dimid); - if (!(dim->name = strdup(phony_dim_name))) { - free(h5dimlenmax); - free(h5dimlen); - return NC_ENOMEM; - } - dim->len = h5dimlen[d]; - dim->hash = hash_fast(phony_dim_name, strlen(phony_dim_name)); - if (h5dimlenmax[d] == H5S_UNLIMITED) - dim->unlimited = NC_TRUE; - } - - /* The variable must remember the dimid. */ - var->dimids[d] = dim->dimid; - var->dim[d] = dim; - } /* next dim */ + dim->len = h5dimlen[d]; + dim->hash = hash_fast(phony_dim_name, strlen(phony_dim_name)); + if (h5dimlenmax[d] == H5S_UNLIMITED) + dim->unlimited = NC_TRUE; + } + + /* The variable must remember the dimid. */ + var->dimids[d] = dim->dimid; + var->dim[d] = dim; + } /* next dim */ /* Free the memory we malloced. */ - free(h5dimlen); - free(h5dimlenmax); - } - } - } + free(h5dimlen); + free(h5dimlenmax); + } + } + } - return retval; + return retval; } -/* Get the length, in bytes, of one element of a type in memory. */ +/** + * @internal Get the length, in bytes, of one element of a type in + * memory. + * + * @param h5 Pointer to HDF5 file info struct. + * @param xtype NetCDF type ID. + * @param is_long True only if NC_LONG is the memory type. + * @param len Pointer that gets lenght in bytes. + * + * @returns NC_NOERR No error. + * @returns NC_EBADTYPE Type not found + * @author Ed Hartnett +*/ int nc4_get_typelen_mem(NC_HDF5_FILE_INFO_T *h5, nc_type xtype, int is_long, size_t *len) { - NC_TYPE_INFO_T *type; - int retval; - - LOG((4, "%s xtype: %d", __func__, xtype)); - assert(len); - - /* If this is an atomic type, the answer is easy. */ - switch (xtype) - { - case NC_BYTE: - case NC_CHAR: - case NC_UBYTE: + NC_TYPE_INFO_T *type; + int retval; + + LOG((4, "%s xtype: %d", __func__, xtype)); + assert(len); + + /* If this is an atomic type, the answer is easy. */ + switch (xtype) + { + case NC_BYTE: + case NC_CHAR: + case NC_UBYTE: *len = sizeof(char); return NC_NOERR; - case NC_SHORT: - case NC_USHORT: + case NC_SHORT: + case NC_USHORT: *len = sizeof(short); return NC_NOERR; - case NC_INT: - case NC_UINT: + case NC_INT: + case NC_UINT: if (is_long) - *len = sizeof(long); + *len = sizeof(long); else - *len = sizeof(int); + *len = sizeof(int); return NC_NOERR; - case NC_FLOAT: + case NC_FLOAT: *len = sizeof(float); return NC_NOERR; - case NC_DOUBLE: + case NC_DOUBLE: *len = sizeof(double); return NC_NOERR; - case NC_INT64: - case NC_UINT64: + case NC_INT64: + case NC_UINT64: *len = sizeof(long long); return NC_NOERR; - case NC_STRING: + case NC_STRING: *len = sizeof(char *); return NC_NOERR; - } + } - /* See if var is compound type. */ - if ((retval = nc4_find_type(h5, xtype, &type))) - return retval; + /* See if var is compound type. */ + if ((retval = nc4_find_type(h5, xtype, &type))) + return retval; - if (!type) - return NC_EBADTYPE; + if (!type) + return NC_EBADTYPE; - *len = type->size; + *len = type->size; - LOG((5, "type->size: %d", type->size)); + LOG((5, "type->size: %d", type->size)); - return NC_NOERR; + return NC_NOERR; } -/* Get the class of a type */ +/** + * @internal Get the class of a type + * + * @param h5 Pointer to the HDF5 file info struct. + * @param xtype NetCDF type ID. + * @param type_class Pointer that gets class of type, NC_INT, + * NC_FLOAT, NC_CHAR, or NC_STRING, NC_ENUM, NC_VLEN, NC_COMPOUND, or + * NC_OPAQUE. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett +*/ int nc4_get_typeclass(const NC_HDF5_FILE_INFO_T *h5, nc_type xtype, int *type_class) { - int retval = NC_NOERR; + int retval = NC_NOERR; - LOG((4, "%s xtype: %d", __func__, xtype)); - assert(type_class); + LOG((4, "%s xtype: %d", __func__, xtype)); + assert(type_class); - /* If this is an atomic type, the answer is easy. */ - if (xtype <= NC_STRING) - { + /* If this is an atomic type, the answer is easy. */ + if (xtype <= NC_STRING) + { switch (xtype) - { - case NC_BYTE: - case NC_UBYTE: - case NC_SHORT: - case NC_USHORT: - case NC_INT: - case NC_UINT: - case NC_INT64: - case NC_UINT64: - /* NC_INT is class used for all integral types */ - *type_class = NC_INT; - break; - - case NC_FLOAT: - case NC_DOUBLE: - /* NC_FLOAT is class used for all floating-point types */ - *type_class = NC_FLOAT; - break; - - case NC_CHAR: - *type_class = NC_CHAR; - break; - - case NC_STRING: - *type_class = NC_STRING; - break; - - default: - BAIL(NC_EBADTYPE); - } - } - else - { + { + case NC_BYTE: + case NC_UBYTE: + case NC_SHORT: + case NC_USHORT: + case NC_INT: + case NC_UINT: + case NC_INT64: + case NC_UINT64: + /* NC_INT is class used for all integral types */ + *type_class = NC_INT; + break; + + case NC_FLOAT: + case NC_DOUBLE: + /* NC_FLOAT is class used for all floating-point types */ + *type_class = NC_FLOAT; + break; + + case NC_CHAR: + *type_class = NC_CHAR; + break; + + case NC_STRING: + *type_class = NC_STRING; + break; + + default: + BAIL(NC_EBADTYPE); + } + } + else + { NC_TYPE_INFO_T *type; /* See if it's a used-defined type */ if ((retval = nc4_find_type(h5, xtype, &type))) - BAIL(retval); + BAIL(retval); if (!type) - BAIL(NC_EBADTYPE); + BAIL(NC_EBADTYPE); *type_class = type->nc_type_class; - } + } - exit: - return retval; +exit: + return retval; } -int -NC4_test_netcdf4(void) -{ - return NC_NOERR; -} +/** + * @internal + * + * @param log + * @param id HDF5 ID. + * @param type + * + * @return NC_NOERR No error. + */ void reportobject(int log, hid_t id, unsigned int type) { -# define MAXNAME 1024 - char name[MAXNAME]; - ssize_t len; - const char* typename = NULL; - - len = H5Iget_name(id, name, MAXNAME); - if(len < 0) return; - name[len] = '\0'; - - switch (type) { - case H5F_OBJ_FILE: typename = "File"; break; - case H5F_OBJ_DATASET: typename = "Dataset"; break; - case H5F_OBJ_GROUP: typename = "Group"; break; - case H5F_OBJ_DATATYPE: typename = "Datatype"; break; - case H5F_OBJ_ATTR: - typename = "Attribute"; - len = H5Aget_name(id, MAXNAME, name); - if(len < 0) len = 0; - name[len] = '\0'; - break; - default: typename = ""; break; - } - if(log) { + char name[MAXNAME]; + ssize_t len; + const char* typename = NULL; + + len = H5Iget_name(id, name, MAXNAME); + if(len < 0) return; + name[len] = '\0'; + + switch (type) { + case H5F_OBJ_FILE: typename = "File"; break; + case H5F_OBJ_DATASET: typename = "Dataset"; break; + case H5F_OBJ_GROUP: typename = "Group"; break; + case H5F_OBJ_DATATYPE: typename = "Datatype"; break; + case H5F_OBJ_ATTR: + typename = "Attribute"; + len = H5Aget_name(id, MAXNAME, name); + if(len < 0) len = 0; + name[len] = '\0'; + break; + default: typename = ""; break; + } + if(log) { #ifdef LOGGING - LOG((0,"Type = %s(%8u) name='%s'",typename,id,name)); + LOG((0,"Type = %s(%8u) name='%s'",typename,id,name)); #endif - } else { - fprintf(stderr,"Type = %s(%8u) name='%s'",typename,(unsigned int)id,name); - } + } else { + fprintf(stderr,"Type = %s(%8u) name='%s'",typename,(unsigned int)id,name); + } } -static unsigned int OTYPES[5] = {H5F_OBJ_FILE, H5F_OBJ_DATASET, H5F_OBJ_GROUP, H5F_OBJ_DATATYPE, H5F_OBJ_ATTR}; - +/** + * @internal + * + * @param log + * @param fid HDF5 ID. + * @param ntypes Number of types. + * @param otypes Pointer that gets number of open types. + * + * @return ::NC_NOERR No error. + */ static void reportopenobjectsT(int log, hid_t fid, int ntypes, unsigned int* otypes) { - int t,i; - ssize_t ocount; - size_t maxobjs = -1; - hid_t* idlist = NULL; + int t,i; + ssize_t ocount; + size_t maxobjs = -1; + hid_t* idlist = NULL; - if(log) { + if(log) { #ifdef LOGGING - LOG((0,"\nReport: open objects on %d\n",fid)); + LOG((0,"\nReport: open objects on %d\n",fid)); #endif - } else { - fprintf(stdout,"\nReport: open objects on %d\n",(int)fid); - } - maxobjs = H5Fget_obj_count(fid,H5F_OBJ_ALL); - if(idlist != NULL) free(idlist); - idlist = (hid_t*)malloc(sizeof(hid_t)*maxobjs); - for(t=0;thdfid)) < 0) - {stat = NC_EHDFERR; goto done;} - if(H5Pget_version(plist, &super, NULL, NULL, NULL) < 0) - {stat = NC_EHDFERR; goto done;} - if(idp) *idp = (int)super; + int stat = NC_NOERR; + unsigned super; + hid_t plist = -1; + if((plist = H5Fget_create_plist(h5->hdfid)) < 0) + {stat = NC_EHDFERR; goto done;} + if(H5Pget_version(plist, &super, NULL, NULL, NULL) < 0) + {stat = NC_EHDFERR; goto done;} + if(idp) *idp = (int)super; done: - if(plist >= 0) H5Pclose(plist); - return stat; + if(plist >= 0) H5Pclose(plist); + return stat; } -/* We define a file as being from netcdf-4 if any of the following -are true: -1. NCPROPS attribute exists in root group -2. NC3_STRICT_ATT_NAME exists in root group -3. any of NC_ATT_REFERENCE_LIST, NC_ATT_CLASS, - NC_ATT_DIMENSION_LIST, NC_ATT_NAME, - NC_ATT_COORDINATES, NC_DIMID_ATT_NAME - exist anywhere in the file; note that this - requires walking the file. -WARNINGS: -1. False negatives are possible for a small subset of netcdf-4 - created files. -2. Deliberate falsification in the file can be used to cause - a false positive. -*/ - static int NC4_get_strict_att(NC_HDF5_FILE_INFO_T*); static int NC4_walk(hid_t, int*); +/** + * @internal Determine whether file is netCDF-4. + * + * We define a file as being from netcdf-4 if any of the following + * are true: + * 1. NCPROPS attribute exists in root group + * 2. NC3_STRICT_ATT_NAME exists in root group + * 3. any of NC_ATT_REFERENCE_LIST, NC_ATT_CLASS, + * NC_ATT_DIMENSION_LIST, NC_ATT_NAME, + * NC_ATT_COORDINATES, NC_DIMID_ATT_NAME + * exist anywhere in the file; note that this + * requires walking the file. + + * @note WARNINGS: + * 1. False negatives are possible for a small subset of netcdf-4 + * created files. + * 2. Deliberate falsification in the file can be used to cause + * a false positive. + * + * @param h5 Pointer to HDF5 file info struct. + * + * @returns NC_NOERR No error. + * @author Dennis Heimbigner. +*/ int NC4_isnetcdf4(struct NC_HDF5_FILE_INFO* h5) { - int stat; - int isnc4 = 0; - int count; - - /* Look for NC3_STRICT_ATT_NAME */ - isnc4 = NC4_get_strict_att(h5); - if(isnc4 > 0) - goto done; - /* attribute did not exist */ - /* => last resort: walk the HDF5 file looking for markers */ - count = 0; - stat = NC4_walk(h5->root_grp->hdf_grpid, &count); - if(stat != NC_NOERR) - isnc4 = 0; - else /* Threshold is at least two matches */ - isnc4 = (count >= 2); + int stat; + int isnc4 = 0; + int count; + + /* Look for NC3_STRICT_ATT_NAME */ + isnc4 = NC4_get_strict_att(h5); + if(isnc4 > 0) + goto done; + /* attribute did not exist */ + /* => last resort: walk the HDF5 file looking for markers */ + count = 0; + stat = NC4_walk(h5->root_grp->hdf_grpid, &count); + if(stat != NC_NOERR) + isnc4 = 0; + else /* Threshold is at least two matches */ + isnc4 = (count >= 2); done: - return isnc4; + return isnc4; } +/** + * @internal Get the NC3 strict attribute. + * + * @param h5 Pointer to HDF5 file info struct. + * + * @returns NC_NOERR No error. + * @author Dennis Heimbigner. +*/ static int NC4_get_strict_att(NC_HDF5_FILE_INFO_T* h5) { - hid_t grp = -1; - hid_t attid = -1; - - /* Get root group */ - grp = h5->root_grp->hdf_grpid; /* get root group */ - /* Try to extract the NC3_STRICT_ATT_NAME attribute */ - attid = H5Aopen_name(grp, NC3_STRICT_ATT_NAME); - H5Aclose(attid); - return attid; + hid_t grp = -1; + hid_t attid = -1; + + /* Get root group */ + grp = h5->root_grp->hdf_grpid; /* get root group */ + /* Try to extract the NC3_STRICT_ATT_NAME attribute */ + attid = H5Aopen_name(grp, NC3_STRICT_ATT_NAME); + H5Aclose(attid); + return attid; } +/** + * @internal Walk group struct. + * + * @param gid HDF5 ID of starting group. + * @param countp Pointer that gets count. + * + * @returns NC_NOERR No error. + * @author Dennis Heimbigner + */ static int NC4_walk(hid_t gid, int* countp) { - int ncstat = NC_NOERR; - int i,j,na; - ssize_t len; - hsize_t nobj; - herr_t err; - int otype; - hid_t grpid, dsid; - char name[NC_HDF5_MAX_NAME]; - - /* walk group members of interest */ - err = H5Gget_num_objs(gid, &nobj); - if(err < 0) return err; - - for(i = 0; i < nobj; i++) { - /* Get name & kind of object in the group */ - len = H5Gget_objname_by_idx(gid,(hsize_t)i,name,(size_t)NC_HDF5_MAX_NAME); - if(len < 0) return len; - - otype = H5Gget_objtype_by_idx(gid,(size_t)i); - switch(otype) { - case H5G_GROUP: - grpid = H5Gopen(gid,name); - NC4_walk(grpid,countp); - H5Gclose(grpid); - break; - case H5G_DATASET: /* variables */ - /* Check for phony_dim */ - if(strcmp(name,"phony_dim")==0) - *countp = *countp + 1; - dsid = H5Dopen(gid,name); - na = H5Aget_num_attrs(dsid); - for(j = 0; j < na; j++) { - hid_t aid = H5Aopen_idx(dsid,(unsigned int) j); - if(aid >= 0) { - const char** p; - ssize_t len = H5Aget_name(aid, NC_HDF5_MAX_NAME, name); - if(len < 0) return len; - /* Is this a netcdf-4 marker attribute */ - for(p=NC_RESERVED_VARATT_LIST;*p;p++) { - if(strcmp(name,*p) == 0) { - *countp = *countp + 1; - } - } - } - H5Aclose(aid); - } - H5Dclose(dsid); - break; - default:/* ignore */ - break; + int ncstat = NC_NOERR; + int i,j,na; + ssize_t len; + hsize_t nobj; + herr_t err; + int otype; + hid_t grpid, dsid; + char name[NC_HDF5_MAX_NAME]; + + /* walk group members of interest */ + err = H5Gget_num_objs(gid, &nobj); + if(err < 0) return err; + + for(i = 0; i < nobj; i++) { + /* Get name & kind of object in the group */ + len = H5Gget_objname_by_idx(gid,(hsize_t)i,name,(size_t)NC_HDF5_MAX_NAME); + if(len < 0) return len; + + otype = H5Gget_objtype_by_idx(gid,(size_t)i); + switch(otype) { + case H5G_GROUP: + grpid = H5Gopen(gid,name); + NC4_walk(grpid,countp); + H5Gclose(grpid); + break; + case H5G_DATASET: /* variables */ + /* Check for phony_dim */ + if(strcmp(name,"phony_dim")==0) + *countp = *countp + 1; + dsid = H5Dopen(gid,name); + na = H5Aget_num_attrs(dsid); + for(j = 0; j < na; j++) { + hid_t aid = H5Aopen_idx(dsid,(unsigned int) j); + if(aid >= 0) { + const char** p; + ssize_t len = H5Aget_name(aid, NC_HDF5_MAX_NAME, name); + if(len < 0) return len; + /* Is this a netcdf-4 marker attribute */ + for(p=NC_RESERVED_VARATT_LIST;*p;p++) { + if(strcmp(name,*p) == 0) { + *countp = *countp + 1; + } + } } - } - return ncstat; + H5Aclose(aid); + } + H5Dclose(dsid); + break; + default:/* ignore */ + break; + } + } + return ncstat; } diff --git a/libsrc4/nc4info.c b/libsrc4/nc4info.c index 71c97f2bb1..4fa6585497 100644 --- a/libsrc4/nc4info.c +++ b/libsrc4/nc4info.c @@ -1,8 +1,11 @@ -/********************************************************************* -* Copyright 2010, UCAR/Unidata -* See netcdf/COPYRIGHT file for copying and redistribution conditions. -* ********************************************************************/ - +/** + * @file + * @internal Add provenance info for netcdf-4 files. + * + * Copyright 2010, UCAR/Unidata See netcdf/COPYRIGHT file for copying + * and redistribution conditions. + * @author Dennis Heimbigner + */ #include "config.h" #include #include @@ -10,16 +13,22 @@ #include "netcdf.h" #include "nc4internal.h" -#define IGNORE 0 - -#define HDF5_MAX_NAME 1024 +#define HDF5_MAX_NAME 1024 /**< HDF5 max name. */ +/** @internal Check NetCDF return code. */ #define NCHECK(expr) {if((expr)!=NC_NOERR) {goto done;}} + +/** @internal Check HDF5 return code. */ #define HCHECK(expr) {if((expr)<0) {ncstat = NC_EHDFERR; goto done;}} -/* Global */ -struct NCPROPINFO globalpropinfo; +struct NCPROPINFO globalpropinfo; /**< Global property info. */ +/** + * @internal Initialize file info. + * + * @return ::NC_NOERR No error. + * @author Dennis Heimbigner + */ int NC4_fileinfo_init(void) { @@ -41,6 +50,15 @@ NC4_fileinfo_init(void) return stat; } +/** + * @internal Parse file properties. + * + * @param ncprops Property info. + * @param text Text properties. + * + * @return ::NC_NOERR No error. + * @author Dennis Heimbigner + */ static int NC4_properties_parse(struct NCPROPINFO* ncprops, const char* text) { @@ -93,6 +111,14 @@ NC4_properties_parse(struct NCPROPINFO* ncprops, const char* text) return ret; } +/** + * @internal Get properties attribure. + * + * @param h5 Pointer to HDF5 file info struct. + * + * @return ::NC_NOERR No error. + * @author Dennis Heimbigner + */ static int NC4_get_propattr(NC_HDF5_FILE_INFO_T* h5) { @@ -137,6 +163,14 @@ NC4_get_propattr(NC_HDF5_FILE_INFO_T* h5) return ncstat; } +/** + * @internal Write the properties attribute to file. + * + * @param h5 Pointer to HDF5 file info struct. + * + * @return ::NC_NOERR No error. + * @author Dennis Heimbigner + */ int NC4_put_propattr(NC_HDF5_FILE_INFO_T* h5) { @@ -175,6 +209,15 @@ NC4_put_propattr(NC_HDF5_FILE_INFO_T* h5) return ncstat; } +/** + * @internal + * + * @param h5 Pointer to HDF5 file info struct. + * @param init Initialization. + * + * @return ::NC_NOERR No error. + * @author Dennis Heimbigner + */ int NC4_get_fileinfo(NC_HDF5_FILE_INFO_T* h5, struct NCPROPINFO* init) { @@ -197,6 +240,15 @@ NC4_get_fileinfo(NC_HDF5_FILE_INFO_T* h5, struct NCPROPINFO* init) return ncstat; } +/** + * @internal Build properties attribute. + * + * @param info Properties info. + * @param propdatap Pointer that gets properties data. + * + * @return ::NC_NOERR No error. + * @author Dennis Heimbigner + */ int NC4_buildpropinfo(struct NCPROPINFO* info,char** propdatap) { diff --git a/libsrc4/nc4internal.c b/libsrc4/nc4internal.c index 97351c16c3..1a6f56a7b5 100644 --- a/libsrc4/nc4internal.c +++ b/libsrc4/nc4internal.c @@ -1,17 +1,19 @@ -/** \file \internal -Internal netcdf-4 functions. - -This file contains functions internal to the netcdf4 library. None of -the functions in this file are exposed in the exetnal API. These -functions all relate to the manipulation of netcdf-4's in-memory -buffer of metadata information, i.e. the linked list of NC -structs. - -Copyright 2003-2011, University Corporation for Atmospheric -Research. See the COPYRIGHT file for copying and redistribution -conditions. - -*/ +/** + * @file + * @internal + * Internal netcdf-4 functions. + * + * This file contains functions internal to the netcdf4 library. None of + * the functions in this file are exposed in the exetnal API. These + * functions all relate to the manipulation of netcdf-4's in-memory + * buffer of metadata information, i.e. the linked list of NC + * structs. + * + * Copyright 2003-2011, University Corporation for Atmospheric + * Research. See the COPYRIGHT file for copying and redistribution + * conditions. + * @author Ed Hartnett + */ #include "config.h" #include "nc4internal.h" #include "nc.h" /* from libsrc */ @@ -19,21 +21,24 @@ conditions. #include "ncutf8.h" #include "H5DSpublic.h" -#define MEGABYTE 1048576 - #undef DEBUGH5 #ifdef DEBUGH5 -/* Provide a catchable error reporting function */ +/** + * @internal Provide a catchable error reporting function + * + * @param ignored Ignored. + * + * @return 0 for success. + */ static herr_t h5catch(void* ignored) { - H5Eprint(NULL); - return 0; + H5Eprint(NULL); + return 0; } #endif - /* These are the default chunk cache sizes for HDF5 files created or * opened with netCDF-4. */ extern size_t nc4_chunk_cache_size; @@ -48,34 +53,48 @@ int nc_log_level = NC_TURN_OFF_LOGGING; #endif /* LOGGING */ -int nc4_hdf5_initialized = 0; +int nc4_hdf5_initialized = 0; /**< True if initialization has happened. */ -/* Provide a wrapper for H5Eset_auto */ +/** + * @internal Provide a wrapper for H5Eset_auto + * @param func Pointer to func. + * @param client_data Client data. + * + * @return 0 for success + */ static herr_t set_auto(void* func, void *client_data) { #ifdef DEBUGH5 - return H5Eset_auto2(H5E_DEFAULT,(H5E_auto2_t)h5catch,client_data); + return H5Eset_auto2(H5E_DEFAULT,(H5E_auto2_t)h5catch,client_data); #else - return H5Eset_auto2(H5E_DEFAULT,(H5E_auto2_t)func,client_data); + return H5Eset_auto2(H5E_DEFAULT,(H5E_auto2_t)func,client_data); #endif } -/* -Provide a function to do any necessary initialization -of the HDF5 library. -*/ - +/** + * @internal Provide a function to do any necessary initialization of + * the HDF5 library. + */ void nc4_hdf5_initialize(void) { - if (set_auto(NULL, NULL) < 0) - LOG((0, "Couldn't turn off HDF5 error messages!")); - LOG((1, "HDF5 error messages have been turned off.")); - nc4_hdf5_initialized = 1; + if (set_auto(NULL, NULL) < 0) + LOG((0, "Couldn't turn off HDF5 error messages!")); + LOG((1, "HDF5 error messages have been turned off.")); + nc4_hdf5_initialized = 1; } -/* Check and normalize and name. */ +/** + * @internal Check and normalize and name. + * + * @param name Name to normalize. + * @param norm_name The normalized name. + * + * @return ::NC_NOERR No error. + * @return ::NC_EMAXNAME Name too long. + * @author Dennis Heimbigner + */ int nc4_check_name(const char *name, char *norm_name) { @@ -98,8 +117,8 @@ nc4_check_name(const char *name, char *norm_name) return retval; if(strlen(temp) > NC_MAX_NAME) { - free(temp); - return NC_EMAXNAME; + free(temp); + return NC_EMAXNAME; } strcpy(norm_name, temp); @@ -108,8 +127,18 @@ nc4_check_name(const char *name, char *norm_name) return NC_NOERR; } -/* Given a varid, return the maximum length of a dimension using dimid */ - +/** + * @internal Given a varid, return the maximum length of a dimension + * using dimid. + * + * @param grp Pointer to group info struct. + * @param varid Variable ID. + * @param dimid Dimension ID. + * @param maxlen Pointer that gets the max length. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ static int find_var_dim_max_length(NC_GRP_INFO_T *grp, int varid, int dimid, size_t *maxlen) { @@ -123,7 +152,7 @@ find_var_dim_max_length(NC_GRP_INFO_T *grp, int varid, int dimid, size_t *maxlen /* Find this var. */ if (varid < 0 || varid >= grp->vars.nelems) - return NC_ENOTVAR; + return NC_ENOTVAR; var = grp->vars.value[varid]; if (!var) return NC_ENOTVAR; assert(var->varid == varid); @@ -131,47 +160,47 @@ find_var_dim_max_length(NC_GRP_INFO_T *grp, int varid, int dimid, size_t *maxlen /* If the var hasn't been created yet, its size is 0. */ if (!var->created) { - *maxlen = 0; + *maxlen = 0; } else { - /* Get the number of records in the dataset. */ - if ((retval = nc4_open_var_grp2(grp, var->varid, &datasetid))) - BAIL(retval); - if ((spaceid = H5Dget_space(datasetid)) < 0) - BAIL(NC_EHDFERR); - - /* If it's a scalar dataset, it has length one. */ - if (H5Sget_simple_extent_type(spaceid) == H5S_SCALAR) - { - *maxlen = (var->dimids && var->dimids[0] == dimid) ? 1 : 0; - } - else - { - /* Check to make sure ndims is right, then get the len of each - dim in the space. */ - if ((dataset_ndims = H5Sget_simple_extent_ndims(spaceid)) < 0) - BAIL(NC_EHDFERR); - if (dataset_ndims != var->ndims) - BAIL(NC_EHDFERR); - if (!(h5dimlen = malloc(dataset_ndims * sizeof(hsize_t)))) - BAIL(NC_ENOMEM); - if (!(h5dimlenmax = malloc(dataset_ndims * sizeof(hsize_t)))) - BAIL(NC_ENOMEM); - if ((dataset_ndims = H5Sget_simple_extent_dims(spaceid, - h5dimlen, h5dimlenmax)) < 0) - BAIL(NC_EHDFERR); - LOG((5, "find_var_dim_max_length: varid %d len %d max: %d", - varid, (int)h5dimlen[0], (int)h5dimlenmax[0])); - for (d=0; ddimids[d] == dimid) { - *maxlen = *maxlen > h5dimlen[d] ? *maxlen : h5dimlen[d]; - } - } - } + /* Get the number of records in the dataset. */ + if ((retval = nc4_open_var_grp2(grp, var->varid, &datasetid))) + BAIL(retval); + if ((spaceid = H5Dget_space(datasetid)) < 0) + BAIL(NC_EHDFERR); + + /* If it's a scalar dataset, it has length one. */ + if (H5Sget_simple_extent_type(spaceid) == H5S_SCALAR) + { + *maxlen = (var->dimids && var->dimids[0] == dimid) ? 1 : 0; + } + else + { + /* Check to make sure ndims is right, then get the len of each + dim in the space. */ + if ((dataset_ndims = H5Sget_simple_extent_ndims(spaceid)) < 0) + BAIL(NC_EHDFERR); + if (dataset_ndims != var->ndims) + BAIL(NC_EHDFERR); + if (!(h5dimlen = malloc(dataset_ndims * sizeof(hsize_t)))) + BAIL(NC_ENOMEM); + if (!(h5dimlenmax = malloc(dataset_ndims * sizeof(hsize_t)))) + BAIL(NC_ENOMEM); + if ((dataset_ndims = H5Sget_simple_extent_dims(spaceid, + h5dimlen, h5dimlenmax)) < 0) + BAIL(NC_EHDFERR); + LOG((5, "find_var_dim_max_length: varid %d len %d max: %d", + varid, (int)h5dimlen[0], (int)h5dimlenmax[0])); + for (d=0; ddimids[d] == dimid) { + *maxlen = *maxlen > h5dimlen[d] ? *maxlen : h5dimlen[d]; + } + } + } } - exit: +exit: if (spaceid > 0 && H5Sclose(spaceid) < 0) BAIL2(NC_EHDFERR); if (h5dimlen) free(h5dimlen); @@ -179,8 +208,17 @@ find_var_dim_max_length(NC_GRP_INFO_T *grp, int varid, int dimid, size_t *maxlen return retval; } -/* Given an NC pointer, add the necessary stuff for a - * netcdf-4 file. */ +/** + * @internal Given an NC pointer, add the necessary stuff for a + * netcdf-4 file. + * + * @param nc Pointer to file's NC struct. + * @param path The file name of the new file. + * @param mode The mode flag. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ int nc4_nc4f_list_add(NC *nc, const char *path, int mode) { @@ -206,12 +244,22 @@ nc4_nc4f_list_add(NC *nc, const char *path, int mode) * group. Allocate space for one group's worth of information. Set * its hdf id, name, and a pointer to it's file structure. */ return nc4_grp_list_add(&(h5->root_grp), h5->next_nc_grpid++, - NULL, nc, NC_GROUP_NAME, NULL); + NULL, nc, NC_GROUP_NAME, NULL); } -/* Given an ncid, find the relevant group and return a pointer to it, - * return an error of this is not a netcdf-4 file (or if strict nc3 is - * turned on for this file.) */ +/** + * @internal Given an ncid, find the relevant group and return a + * pointer to it, return an error of this is not a netcdf-4 file (or + * if strict nc3 is turned on for this file.) + * + * @param ncid File and group ID. + * @param grp Pointer that gets pointer to group info struct. + * + * @return ::NC_NOERR No error. + * @return ::NC_ENOTNC4 Not a netCDF-4 file. + * @return ::NC_ESTRICTNC3 Not allowed for classic model. + * @author Ed Hartnett + */ int nc4_find_nc4_grp(int ncid, NC_GRP_INFO_T **grp) { @@ -233,61 +281,91 @@ nc4_find_nc4_grp(int ncid, NC_GRP_INFO_T **grp) return NC_NOERR; } -/* Given an ncid, find the relevant group and return a pointer to it, - * also set a pointer to the nc4_info struct of the related file. For - * netcdf-3 files, *h5 will be set to NULL. */ +/** + * @internal Given an ncid, find the relevant group and return a + * pointer to it, also set a pointer to the nc4_info struct of the + * related file. For netcdf-3 files, *h5 will be set to NULL. + * + * @param ncid File and group ID. + * @param grpp Pointer that gets pointer to group info struct. + * @param h5p Pointer to HDF5 file struct. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Ed Hartnett + */ int nc4_find_grp_h5(int ncid, NC_GRP_INFO_T **grpp, NC_HDF5_FILE_INFO_T **h5p) { - NC_HDF5_FILE_INFO_T *h5; - NC_GRP_INFO_T *grp; - NC *f = nc4_find_nc_file(ncid,&h5); - if(f == NULL) return NC_EBADID; - if (h5) { - assert(h5->root_grp); - /* If we can't find it, the grp id part of ncid is bad. */ - if (!(grp = nc4_rec_find_grp(h5->root_grp, (ncid & GRP_ID_MASK)))) - return NC_EBADID; - h5 = (grp)->nc4_info; - assert(h5); - } else { - h5 = NULL; - grp = NULL; - } - if(h5p) *h5p = h5; - if(grpp) *grpp = grp; - return NC_NOERR; + NC_HDF5_FILE_INFO_T *h5; + NC_GRP_INFO_T *grp; + NC *f = nc4_find_nc_file(ncid,&h5); + if(f == NULL) return NC_EBADID; + if (h5) { + assert(h5->root_grp); + /* If we can't find it, the grp id part of ncid is bad. */ + if (!(grp = nc4_rec_find_grp(h5->root_grp, (ncid & GRP_ID_MASK)))) + return NC_EBADID; + h5 = (grp)->nc4_info; + assert(h5); + } else { + h5 = NULL; + grp = NULL; + } + if(h5p) *h5p = h5; + if(grpp) *grpp = grp; + return NC_NOERR; } +/** + * @internal Find info for this file and group, and set pointer to each. + * + * @param ncid File and group ID. + * @param nc Pointer that gets a pointer to the file's NC struct. + * @param grpp Pointer that gets a pointer to the group struct. + * @param h5p Pointer that gets HDF5 file struct. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Ed Hartnett + */ int nc4_find_nc_grp_h5(int ncid, NC **nc, NC_GRP_INFO_T **grpp, - NC_HDF5_FILE_INFO_T **h5p) + NC_HDF5_FILE_INFO_T **h5p) { - NC_GRP_INFO_T *grp; - NC_HDF5_FILE_INFO_T* h5; - NC *f = nc4_find_nc_file(ncid,&h5); - - if(f == NULL) return NC_EBADID; - *nc = f; - - if (h5) { - assert(h5->root_grp); - /* If we can't find it, the grp id part of ncid is bad. */ - if (!(grp = nc4_rec_find_grp(h5->root_grp, (ncid & GRP_ID_MASK)))) - return NC_EBADID; - - h5 = (grp)->nc4_info; - assert(h5); - } else { - h5 = NULL; - grp = NULL; - } - if(h5p) *h5p = h5; - if(grpp) *grpp = grp; - return NC_NOERR; + NC_GRP_INFO_T *grp; + NC_HDF5_FILE_INFO_T* h5; + NC *f = nc4_find_nc_file(ncid,&h5); + + if(f == NULL) return NC_EBADID; + *nc = f; + + if (h5) { + assert(h5->root_grp); + /* If we can't find it, the grp id part of ncid is bad. */ + if (!(grp = nc4_rec_find_grp(h5->root_grp, (ncid & GRP_ID_MASK)))) + return NC_EBADID; + + h5 = (grp)->nc4_info; + assert(h5); + } else { + h5 = NULL; + grp = NULL; + } + if(h5p) *h5p = h5; + if(grpp) *grpp = grp; + return NC_NOERR; } -/* Recursively hunt for a group id. */ +/** + * @internal Recursively hunt for a group id. + * + * @param start_grp Pointer to group where search should be started. + * @param target_nc_grpid Group ID to be found. + * + * @return Pointer to group info struct, or NULL if not found. + * @author Ed Hartnett + */ NC_GRP_INFO_T * nc4_rec_find_grp(NC_GRP_INFO_T *start_grp, int target_nc_grpid) { @@ -302,18 +380,28 @@ nc4_rec_find_grp(NC_GRP_INFO_T *start_grp, int target_nc_grpid) /* Shake down the kids. */ if (start_grp->children) for (g = start_grp->children; g; g = g->l.next) - if ((res = nc4_rec_find_grp(g, target_nc_grpid))) - return res; + if ((res = nc4_rec_find_grp(g, target_nc_grpid))) + return res; /* Can't find it. Fate, why do you mock me? */ return NULL; } -/* Given an ncid and varid, get pointers to the group and var - * metadata. */ +/** + * @internal Given an ncid and varid, get pointers to the group and var + * metadata. + * + * @param nc Pointer to file's NC struct. + * @param ncid File ID. + * @param varid Variable ID. + * @param grp Pointer that gets pointer to group info. + * @param var Pointer that gets pointer to var info. + * + * @return ::NC_NOERR No error. + */ int nc4_find_g_var_nc(NC *nc, int ncid, int varid, - NC_GRP_INFO_T **grp, NC_VAR_INFO_T **var) + NC_GRP_INFO_T **grp, NC_VAR_INFO_T **var) { NC_HDF5_FILE_INFO_T* h5 = NC4_DATA(nc); @@ -324,20 +412,31 @@ nc4_find_g_var_nc(NC *nc, int ncid, int varid, /* It is possible for *grp to be NULL. If it is, return an error. */ if(*grp == NULL) - return NC_ENOTVAR; + return NC_EBADID; /* Find the var info. */ if (varid < 0 || varid >= (*grp)->vars.nelems) - return NC_ENOTVAR; + return NC_ENOTVAR; (*var) = (*grp)->vars.value[varid]; return NC_NOERR; } -/* Find a dim in a grp (or parents). */ +/** + * @internal Find a dim in a grp (or its parents). + * + * @param grp Pointer to group info struct. + * @param dimid Dimension ID to find. + * @param dim Pointer that gets pointer to dim info if found. + * @param dim_grp Pointer that gets pointer to group info of group that contians dimension. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADDIM Dimension not found. + * @author Ed Hartnett + */ int nc4_find_dim(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T **dim, - NC_GRP_INFO_T **dim_grp) + NC_GRP_INFO_T **dim_grp) { NC_GRP_INFO_T *g, *dg = NULL; int finished = 0; @@ -347,16 +446,16 @@ nc4_find_dim(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T **dim, /* Find the dim info. */ for (g = grp; g && !finished; g = g->parent) for ((*dim) = g->dim; (*dim); (*dim) = (*dim)->l.next) - if ((*dim)->dimid == dimid) - { - dg = g; - finished++; - break; - } + if ((*dim)->dimid == dimid) + { + dg = g; + finished++; + break; + } /* If we didn't find it, return an error. */ if (!(*dim)) - return NC_EBADDIM; + return NC_EBADDIM; /* Give the caller the group the dimension is in. */ if (dim_grp) @@ -365,27 +464,44 @@ nc4_find_dim(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T **dim, return NC_NOERR; } -/* Find a var (by name) in a grp. */ +/** + * @internal Find a var (by name) in a grp. + * + * @param grp Pointer to group info. + * @param name Name of var to find. + * @param var Pointer that gets pointer to var info struct, if found. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ int nc4_find_var(NC_GRP_INFO_T *grp, const char *name, NC_VAR_INFO_T **var) { - int i; + int i; assert(grp && var && name); /* Find the var info. */ *var = NULL; for (i=0; i < grp->vars.nelems; i++) { - if (0 == strcmp(name, grp->vars.value[i]->name)) - { - *var = grp->vars.value[i]; - break; - } + if (0 == strcmp(name, grp->vars.value[i]->name)) + { + *var = grp->vars.value[i]; + break; + } } return NC_NOERR; } -/* Recursively hunt for a HDF type id. */ +/** + * @internal Recursively hunt for a HDF type id. + * + * @param start_grp Pointer to starting group info. + * @param target_hdf_typeid HDF5 type ID to find. + * + * @return Pointer to type info struct, or NULL if not found. + * @author Ed Hartnett + */ NC_TYPE_INFO_T * nc4_rec_find_hdf_type(NC_GRP_INFO_T *start_grp, hid_t target_hdf_typeid) { @@ -399,22 +515,30 @@ nc4_rec_find_hdf_type(NC_GRP_INFO_T *start_grp, hid_t target_hdf_typeid) for (type = start_grp->type; type; type = type->l.next) { if ((equal = H5Tequal(type->native_hdf_typeid ? type->native_hdf_typeid : type->hdf_typeid, target_hdf_typeid)) < 0) - return NULL; + return NULL; if (equal) - return type; + return type; } /* Shake down the kids. */ if (start_grp->children) for (g = start_grp->children; g; g = g->l.next) - if ((res = nc4_rec_find_hdf_type(g, target_hdf_typeid))) - return res; + if ((res = nc4_rec_find_hdf_type(g, target_hdf_typeid))) + return res; /* Can't find it. Fate, why do you mock me? */ return NULL; } -/* Recursively hunt for a netCDF type by name. */ +/** + * @internal Recursively hunt for a netCDF type by name. + * + * @param start_grp Pointer to starting group info. + * @param name Name of type to find. + * + * @return Pointer to type info, or NULL if not found. + * @author Ed Hartnett + */ NC_TYPE_INFO_T * nc4_rec_find_named_type(NC_GRP_INFO_T *start_grp, char *name) { @@ -426,19 +550,27 @@ nc4_rec_find_named_type(NC_GRP_INFO_T *start_grp, char *name) /* Does this group have the type we are searching for? */ for (type = start_grp->type; type; type = type->l.next) if (!strcmp(type->name, name)) - return type; + return type; /* Search subgroups. */ if (start_grp->children) for (g = start_grp->children; g; g = g->l.next) - if ((res = nc4_rec_find_named_type(g, name))) - return res; + if ((res = nc4_rec_find_named_type(g, name))) + return res; /* Can't find it. Oh, woe is me! */ return NULL; } -/* Recursively hunt for a netCDF type id. */ +/** + * @internal Recursively hunt for a netCDF type id. + * + * @param start_grp Pointer to starting group info. + * @param target_nc_typeid NetCDF type ID to find. + * + * @return Pointer to type info, or NULL if not found. + * @author Ed Hartnett + */ NC_TYPE_INFO_T * nc4_rec_find_nc_type(const NC_GRP_INFO_T *start_grp, nc_type target_nc_typeid) { @@ -449,7 +581,7 @@ nc4_rec_find_nc_type(const NC_GRP_INFO_T *start_grp, nc_type target_nc_typeid) /* Does this group have the type we are searching for? */ for (type = start_grp->type; type; type = type->l.next) if (type->nc_typeid == target_nc_typeid) - return type; + return type; /* Shake down the kids. */ if (start_grp->children) @@ -460,8 +592,8 @@ nc4_rec_find_nc_type(const NC_GRP_INFO_T *start_grp, nc_type target_nc_typeid) { NC_TYPE_INFO_T *res; - if ((res = nc4_rec_find_nc_type(g, target_nc_typeid))) - return res; + if ((res = nc4_rec_find_nc_type(g, target_nc_typeid))) + return res; } } @@ -469,7 +601,17 @@ nc4_rec_find_nc_type(const NC_GRP_INFO_T *start_grp, nc_type target_nc_typeid) return NULL; } -/* Use a netCDF typeid to find a type in a type_list. */ +/** + * @internal Use a netCDF typeid to find a type in a type_list. + * + * @param h5 Pointer to HDF5 file info struct. + * @param typeid The netCDF type ID. + * @param type Pointer to pointer to the list of type info structs. + * + * @return ::NC_NOERR No error. + * @return ::NC_EINVAL Invalid input. + * @author Ed Hartnett + */ int nc4_find_type(const NC_HDF5_FILE_INFO_T *h5, nc_type typeid, NC_TYPE_INFO_T **type) { @@ -489,9 +631,18 @@ nc4_find_type(const NC_HDF5_FILE_INFO_T *h5, nc_type typeid, NC_TYPE_INFO_T **ty return NC_NOERR; } -/* Find the actual length of a dim by checking the length of that dim - * in all variables that use it, in grp or children. **len must be - * initialized to zero before this function is called. */ +/** + * @internal Find the actual length of a dim by checking the length of + * that dim in all variables that use it, in grp or children. **len + * must be initialized to zero before this function is called. + * + * @param grp Pointer to group info struct. + * @param dimid Dimension ID. + * @param len Pointer to pointer that gets length. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ int nc4_find_dim_len(NC_GRP_INFO_T *grp, int dimid, size_t **len) { @@ -507,37 +658,51 @@ nc4_find_dim_len(NC_GRP_INFO_T *grp, int dimid, size_t **len) * them. */ for (g = grp->children; g; g = g->l.next) if ((retval = nc4_find_dim_len(g, dimid, len))) - return retval; + return retval; /* For all variables in this group, find the ones that use this * dimension, and remember the max length. */ for (i=0; i < grp->vars.nelems; i++) { - size_t mylen; - var = grp->vars.value[i]; - if (!var) continue; + size_t mylen; + var = grp->vars.value[i]; + if (!var) continue; - /* Find max length of dim in this variable... */ - if ((retval = find_var_dim_max_length(grp, var->varid, dimid, &mylen))) - return retval; + /* Find max length of dim in this variable... */ + if ((retval = find_var_dim_max_length(grp, var->varid, dimid, &mylen))) + return retval; - **len = **len > mylen ? **len : mylen; + **len = **len > mylen ? **len : mylen; } return NC_NOERR; } /* Given a group, find an att. */ +/** + * @internal + * + * @param grp Pointer to group info struct. + * @param varid Variable ID. + * @param name Name to of attribute. + * @param attnum Number of attribute. + * @param att Pointer to pointer that gets attribute info struct. + * + * @return ::NC_NOERR No error. + * @return ::NC_ENOTVAR Variable not found. + * @return ::NC_ENOTATT Attribute not found. + * @author Ed Hartnett + */ int nc4_find_grp_att(NC_GRP_INFO_T *grp, int varid, const char *name, int attnum, - NC_ATT_INFO_T **att) + NC_ATT_INFO_T **att) { NC_VAR_INFO_T *var; NC_ATT_INFO_T *attlist = NULL; assert(grp && grp->name); LOG((4, "nc4_find_grp_att: grp->name %s varid %d name %s attnum %d", - grp->name, varid, name, attnum)); + grp->name, varid, name, attnum)); /* Get either the global or a variable attribute list. */ if (varid == NC_GLOBAL) @@ -545,7 +710,7 @@ nc4_find_grp_att(NC_GRP_INFO_T *grp, int varid, const char *name, int attnum, else { if (varid < 0 || varid >= grp->vars.nelems) - return NC_ENOTVAR; + return NC_ENOTVAR; var = grp->vars.value[varid]; if (!var) return NC_ENOTVAR; attlist = var->att; @@ -555,22 +720,35 @@ nc4_find_grp_att(NC_GRP_INFO_T *grp, int varid, const char *name, int attnum, /* Now find the attribute by name or number. If a name is provided, * ignore the attnum. */ if(attlist) - for (*att = attlist; *att; *att = (*att)->l.next) { - if (name && (*att)->name && !strcmp((*att)->name, name)) - return NC_NOERR; - if (!name && (*att)->attnum == attnum) - return NC_NOERR; - } + for (*att = attlist; *att; *att = (*att)->l.next) { + if (name && (*att)->name && !strcmp((*att)->name, name)) + return NC_NOERR; + if (!name && (*att)->attnum == attnum) + return NC_NOERR; + } /* If we get here, we couldn't find the attribute. */ return NC_ENOTATT; } -/* Given an ncid, varid, and name or attnum, find and return pointer - to NC_ATT_INFO_T metadata. */ +/** + * @internal Given an ncid, varid, and name or attnum, find and return + * pointer to NC_ATT_INFO_T metadata. + * + * @param ncid File and group ID. + * @param varid Variable ID. + * @param name Name to of attribute. + * @param attnum Number of attribute. + * @param att Pointer to pointer that gets attribute info struct. + * + * @return ::NC_NOERR No error. + * @return ::NC_ENOTVAR Variable not found. + * @return ::NC_ENOTATT Attribute not found. + * @author Ed Hartnett + */ int nc4_find_nc_att(int ncid, int varid, const char *name, int attnum, - NC_ATT_INFO_T **att) + NC_ATT_INFO_T **att) { NC_GRP_INFO_T *grp; NC_HDF5_FILE_INFO_T *h5; @@ -579,7 +757,7 @@ nc4_find_nc_att(int ncid, int varid, const char *name, int attnum, int retval; LOG((4, "nc4_find_nc_att: ncid 0x%x varid %d name %s attnum %d", - ncid, varid, name, attnum)); + ncid, varid, name, attnum)); /* Find info for this file and group, and set pointer to each. */ if ((retval = nc4_find_grp_h5(ncid, &grp, &h5))) @@ -592,7 +770,7 @@ nc4_find_nc_att(int ncid, int varid, const char *name, int attnum, else { if (varid < 0 || varid >= grp->vars.nelems) - return NC_ENOTVAR; + return NC_ENOTVAR; var = grp->vars.value[varid]; if (!var) return NC_ENOTVAR; attlist = var->att; @@ -602,16 +780,23 @@ nc4_find_nc_att(int ncid, int varid, const char *name, int attnum, /* Now find the attribute by name or number. If a name is provided, ignore the attnum. */ for (*att = attlist; *att; *att = (*att)->l.next) if ((name && !strcmp((*att)->name, name)) || - (!name && (*att)->attnum == attnum)) - return NC_NOERR; + (!name && (*att)->attnum == attnum)) + return NC_NOERR; /* If we get here, we couldn't find the attribute. */ return NC_ENOTATT; } -/* Given an id, walk the list and find the appropriate - NC. */ +/** + * @internal Given an id, walk the list and find the appropriate NC. + * + * @param ext_ncid File/group ID to find. + * @param h5p Pointer to pointer that gets the HDF5 file info struct. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett, Dennis Heimbigner + */ NC* nc4_find_nc_file(int ext_ncid, NC_HDF5_FILE_INFO_T** h5p) { @@ -620,15 +805,23 @@ nc4_find_nc_file(int ext_ncid, NC_HDF5_FILE_INFO_T** h5p) stat = NC_check_id(ext_ncid,&nc); if(stat != NC_NOERR) - nc = NULL; + nc = NULL; if(nc) - if(h5p) *h5p = (NC_HDF5_FILE_INFO_T*)nc->dispatchdata; + if(h5p) *h5p = (NC_HDF5_FILE_INFO_T*)nc->dispatchdata; return nc; } -/* Add object to the end of a list. */ +/** + * @internal Add object to the end of a list. + * + * @param list List + * @param obj Pointer to object to add. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ static void obj_list_add(NC_LIST_NODE_T **list, NC_LIST_NODE_T *obj) { @@ -639,8 +832,8 @@ obj_list_add(NC_LIST_NODE_T **list, NC_LIST_NODE_T *obj) NC_LIST_NODE_T *o; for (o = *list; o; o = o->next) - if (!o->next) - break; + if (!o->next) + break; o->next = obj; obj->prev = o; } @@ -648,7 +841,15 @@ obj_list_add(NC_LIST_NODE_T **list, NC_LIST_NODE_T *obj) *list = obj; } -/* Remove object from a list. */ +/** + * @internal Remove object from a list. + * + * @param list List + * @param obj Pointer to object to delete. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ static void obj_list_del(NC_LIST_NODE_T **list, NC_LIST_NODE_T *obj) { @@ -662,7 +863,15 @@ obj_list_del(NC_LIST_NODE_T **list, NC_LIST_NODE_T *obj) ((NC_LIST_NODE_T *)obj->next)->prev = obj->prev; } -/* Return a pointer to the new var. */ +/** + * @internal Return a pointer to the new var. + * + * @param var Pointer to pointer that gets variable info struct. + * + * @return ::NC_NOERR No error. + * @return ::NC_ENOMEM Out of memory. + * @author Ed Hartnett + */ int nc4_var_add(NC_VAR_INFO_T **var) { @@ -681,12 +890,20 @@ nc4_var_add(NC_VAR_INFO_T **var) if (var) *var = new_var; else - free(new_var); + free(new_var); return NC_NOERR; } -/* Add to the beginning of a dim list. */ +/** + * @internal Add to the beginning of a dim list. + * + * @param list List of dimension info structs. + * @param dim Pointer to pointer that gets the new dim info struct. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ int nc4_dim_list_add(NC_DIM_INFO_T **list, NC_DIM_INFO_T **dim) { @@ -705,7 +922,15 @@ nc4_dim_list_add(NC_DIM_INFO_T **list, NC_DIM_INFO_T **dim) return NC_NOERR; } -/* Add to the end of an att list. */ +/** + * @internal Add to the end of an att list. + * + * @param list List of att info structs. + * @param att Pointer to pointer that gets the new att info struct. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ int nc4_att_list_add(NC_ATT_INFO_T **list, NC_ATT_INFO_T **att) { @@ -724,12 +949,24 @@ nc4_att_list_add(NC_ATT_INFO_T **list, NC_ATT_INFO_T **att) return NC_NOERR; } -/* Add to the end of a group list. Can't use 0 as a new_nc_grpid - - * it's reserverd for the root group. */ +/** + * @internal Add to the end of a group list. Can't use 0 as a + * new_nc_grpid - it's reserverd for the root group. + * + * @param list List + * @param new_nc_grpid New group ID. + * @param parent_grp The parent group. + * @param nc Pointer to the file's NC struct. + * @param name Name of the group. + * @param grp Pointer to pointer that gets new group info struct. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ int nc4_grp_list_add(NC_GRP_INFO_T **list, int new_nc_grpid, - NC_GRP_INFO_T *parent_grp, NC *nc, - char *name, NC_GRP_INFO_T **grp) + NC_GRP_INFO_T *parent_grp, NC *nc, + char *name, NC_GRP_INFO_T **grp) { NC_GRP_INFO_T *new_grp; @@ -754,15 +991,24 @@ nc4_grp_list_add(NC_GRP_INFO_T **list, int new_nc_grpid, /* Set the group pointer, if one was given */ if (grp) - *grp = new_grp; + *grp = new_grp; return NC_NOERR; } -/* Names for groups, variables, and types must not be the same. This - * function checks that a proposed name is not already in +/** + * @internal Names for groups, variables, and types must not be the + * same. This function checks that a proposed name is not already in * use. Normalzation of UTF8 strings should happen before this - * function is called. */ + * function is called. + * + * @param grp Pointer to group info struct. + * @param name Name to check. + * + * @return ::NC_NOERR No error. + * @return ::NC_ENAMEINUSE Name is in use. + * @author Ed Hartnett + */ int nc4_check_dup_name(NC_GRP_INFO_T *grp, char *name) { @@ -775,12 +1021,12 @@ nc4_check_dup_name(NC_GRP_INFO_T *grp, char *name) /* Any types of this name? */ for (type = grp->type; type; type = type->l.next) if (!strcmp(type->name, name)) - return NC_ENAMEINUSE; + return NC_ENAMEINUSE; /* Any child groups of this name? */ for (g = grp->children; g; g = g->l.next) if (!strcmp(g->name, name)) - return NC_ENAMEINUSE; + return NC_ENAMEINUSE; /* Any variables of this name? */ hash = hash_fast(name, strlen(name)); @@ -789,12 +1035,24 @@ nc4_check_dup_name(NC_GRP_INFO_T *grp, char *name) var = grp->vars.value[i]; if (!var) continue; if (var->hash == hash && !strcmp(var->name, name)) - return NC_ENAMEINUSE; + return NC_ENAMEINUSE; } return NC_NOERR; } -/* Add to the end of a type list. */ +/** + * @internal Add to the end of a type list. + * + * @param grp Pointer to group info struct. + * @param size Size of type in bytes. + * @param name Name of type. + * @param type Pointer that gets pointer to new type info + * struct. Ignored if NULL. + * + * @return ::NC_NOERR No error. + * @return ::NC_ENOMEM Out of memory. + * @author Ed Hartnett + */ int nc4_type_list_add(NC_GRP_INFO_T *grp, size_t size, const char *name, NC_TYPE_INFO_T **type) @@ -824,11 +1082,26 @@ nc4_type_list_add(NC_GRP_INFO_T *grp, size_t size, const char *name, return NC_NOERR; } -/* Add to the end of a compound field list. */ +/** + * @internal Add to the end of a compound field list. + * + * @param list Pointer to pointer of list of field info structs. + * @param fieldid The ID of this field. + * @param name Name of the field. + * @param offset Offset in bytes. + * @param field_hdf_typeid The HDF5 type ID of the field. + * @param native_typeid The HDF5 native type ID of the field. + * @param xtype The netCDF type of the field. + * @param ndims The number of dimensions of the field. + * @param dim_sizesp An array of dim sizes for the field. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ int nc4_field_list_add(NC_FIELD_INFO_T **list, int fieldid, const char *name, - size_t offset, hid_t field_hdf_typeid, hid_t native_typeid, - nc_type xtype, int ndims, const int *dim_sizesp) + size_t offset, hid_t field_hdf_typeid, hid_t native_typeid, + nc_type xtype, int ndims, const int *dim_sizesp) { NC_FIELD_INFO_T *field; @@ -860,10 +1133,10 @@ nc4_field_list_add(NC_FIELD_INFO_T **list, int fieldid, const char *name, { free(field->name); free(field); - return NC_ENOMEM; + return NC_ENOMEM; } for (i = 0; i < ndims; i++) - field->dim_size[i] = dim_sizesp[i]; + field->dim_size[i] = dim_sizesp[i]; } /* Add object to list */ @@ -872,10 +1145,21 @@ nc4_field_list_add(NC_FIELD_INFO_T **list, int fieldid, const char *name, return NC_NOERR; } -/* Add a member to an enum type. */ +/** + * @internal Add a member to an enum type. + * + * @param list Pointer to pointer of list of enum member info structs. + * @param size Size in bytes of new member. + * @param name Name of the member. + * @param value Value to associate with member. + * + * @return ::NC_NOERR No error. + * @return ::NC_ENOMEM Out of memory. + * @author Ed Hartnett + */ int nc4_enum_member_add(NC_ENUM_MEMBER_INFO_T **list, size_t size, - const char *name, const void *value) + const char *name, const void *value) { NC_ENUM_MEMBER_INFO_T *member; @@ -905,7 +1189,15 @@ nc4_enum_member_add(NC_ENUM_MEMBER_INFO_T **list, size_t size, return NC_NOERR; } -/* Delete a field from a field list, and nc_free the memory. */ +/** + * @internal Delete a field from a field list, and nc_free the memory. + * + * @param list Pointer to pointer of list of field info structs. + * @param field Pointer to field info of field to delete. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ static void field_list_del(NC_FIELD_INFO_T **list, NC_FIELD_INFO_T *field) { @@ -922,7 +1214,14 @@ field_list_del(NC_FIELD_INFO_T **list, NC_FIELD_INFO_T *field) free(field); } -/* Free allocated space for type information. */ +/** + * @internal Free allocated space for type information. + * + * @param type Pointer to type info struct. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ int nc4_type_free(NC_TYPE_INFO_T *type) { @@ -946,50 +1245,50 @@ nc4_type_free(NC_TYPE_INFO_T *type) /* Class-specific cleanup */ switch (type->nc_type_class) { - case NC_COMPOUND: - { - NC_FIELD_INFO_T *field; - - /* Delete all the fields in this type (there will be some if its a - * compound). */ - field = type->u.c.field; - while (field) - { - NC_FIELD_INFO_T *f = field->l.next; - - field_list_del(&type->u.c.field, field); - field = f; - } - } - break; + case NC_COMPOUND: + { + NC_FIELD_INFO_T *field; - case NC_ENUM: - { - NC_ENUM_MEMBER_INFO_T *enum_member; - - /* Delete all the enum_members, if any. */ - enum_member = type->u.e.enum_member; - while (enum_member) - { - NC_ENUM_MEMBER_INFO_T *em = enum_member->l.next; - - free(enum_member->value); - free(enum_member->name); - free(enum_member); - enum_member = em; - } - - if (H5Tclose(type->u.e.base_hdf_typeid) < 0) - return NC_EHDFERR; - } - break; + /* Delete all the fields in this type (there will be some if its a + * compound). */ + field = type->u.c.field; + while (field) + { + NC_FIELD_INFO_T *f = field->l.next; - case NC_VLEN: - if (H5Tclose(type->u.v.base_hdf_typeid) < 0) - return NC_EHDFERR; + field_list_del(&type->u.c.field, field); + field = f; + } + } + break; - default: - break; + case NC_ENUM: + { + NC_ENUM_MEMBER_INFO_T *enum_member; + + /* Delete all the enum_members, if any. */ + enum_member = type->u.e.enum_member; + while (enum_member) + { + NC_ENUM_MEMBER_INFO_T *em = enum_member->l.next; + + free(enum_member->value); + free(enum_member->name); + free(enum_member); + enum_member = em; + } + + if (H5Tclose(type->u.e.base_hdf_typeid) < 0) + return NC_EHDFERR; + } + break; + + case NC_VLEN: + if (H5Tclose(type->u.v.base_hdf_typeid) < 0) + return NC_EHDFERR; + + default: + break; } /* Release the memory. */ @@ -999,7 +1298,14 @@ nc4_type_free(NC_TYPE_INFO_T *type) return NC_NOERR; } -/* Delete a var, and free the memory. */ +/** + * @internal Delete a var, and free the memory. + * + * @param var Pointer to the var info struct of var to delete. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ int nc4_var_del(NC_VAR_INFO_T *var) { @@ -1007,7 +1313,7 @@ nc4_var_del(NC_VAR_INFO_T *var) int ret; if(var == NULL) - return NC_NOERR; + return NC_NOERR; /* First delete all the attributes attached to this var. */ att = var->att; @@ -1015,25 +1321,25 @@ nc4_var_del(NC_VAR_INFO_T *var) { a = att->l.next; if ((ret = nc4_att_list_del(&var->att, att))) - return ret; + return ret; att = a; } /* Free some things that may be allocated. */ if (var->chunksizes) - {free(var->chunksizes);var->chunksizes = NULL;} + {free(var->chunksizes);var->chunksizes = NULL;} if (var->hdf5_name) - {free(var->hdf5_name); var->hdf5_name = NULL;} + {free(var->hdf5_name); var->hdf5_name = NULL;} if (var->name) - {free(var->name); var->name = NULL;} + {free(var->name); var->name = NULL;} if (var->dimids) - {free(var->dimids); var->dimids = NULL;} + {free(var->dimids); var->dimids = NULL;} if (var->dim) - {free(var->dim); var->dim = NULL;} + {free(var->dim); var->dim = NULL;} /* Delete any fill value allocation. This must be done before the * type_info is freed. */ @@ -1059,7 +1365,7 @@ nc4_var_del(NC_VAR_INFO_T *var) int retval; if ((retval = nc4_type_free(var->type_info))) - return retval; + return retval; var->type_info = NULL; } @@ -1081,7 +1387,15 @@ nc4_var_del(NC_VAR_INFO_T *var) return NC_NOERR; } -/* Delete a type from a type list, and nc_free the memory. */ +/** + * @internal Delete a type from a type list, and nc_free the memory. + * + * @param list Pointer to pointer of list of types. + * @param type Pointer to type info struct of type to delete. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ static int type_list_del(NC_TYPE_INFO_T **list, NC_TYPE_INFO_T *type) { @@ -1092,7 +1406,15 @@ type_list_del(NC_TYPE_INFO_T **list, NC_TYPE_INFO_T *type) return nc4_type_free(type); } -/* Delete a del from a var list, and nc_free the memory. */ +/** + * @internal Delete a del from a var list, and nc_free the memory. + * + * @param list Pointer to pointer of list of dims. + * @param dim Pointer to dim info struct of type to delete. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ int nc4_dim_list_del(NC_DIM_INFO_T **list, NC_DIM_INFO_T *dim) { @@ -1107,8 +1429,16 @@ nc4_dim_list_del(NC_DIM_INFO_T **list, NC_DIM_INFO_T *dim) return NC_NOERR; } -/* Remove a NC_GRP_INFO_T from the linked list. This will nc_free the - memory too. */ +/** + * @internal Remove a NC_GRP_INFO_T from the linked list. This will + * nc_free the memory too. + * + * @param list Pointer to pointer of list of group info structs. + * @param grp Pointer to group info struct. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ static void grp_list_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp) { @@ -1118,8 +1448,16 @@ grp_list_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp) free(grp); } -/* Recursively delete the data for a group (and everything it - * contains) in our internal metadata store. */ +/** + * @internal Recursively delete the data for a group (and everything + * it contains) in our internal metadata store. + * + * @param list Pointer to pointer of list. + * @param grp Pointer to group info struct. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ int nc4_rec_grp_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp) { @@ -1141,7 +1479,7 @@ nc4_rec_grp_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp) { c = g->l.next; if ((retval = nc4_rec_grp_del(&(grp->children), g))) - return retval; + return retval; g = c; } @@ -1153,7 +1491,7 @@ nc4_rec_grp_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp) LOG((4, "%s: deleting att %s", __func__, att->name)); a = att->l.next; if ((retval = nc4_att_list_del(&grp->att, att))) - return retval; + return retval; att = a; } @@ -1167,9 +1505,9 @@ nc4_rec_grp_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp) /* Close HDF5 dataset associated with this var, unless it's a * scale. */ if (var->hdf_datasetid && H5Dclose(var->hdf_datasetid) < 0) - return NC_EHDFERR; + return NC_EHDFERR; if ((retval = nc4_var_del(var))) - return retval; + return retval; grp->vars.value[i] = NULL; } @@ -1177,10 +1515,10 @@ nc4_rec_grp_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp) then need to iterate value and free vars from it. */ if (grp->vars.nalloc != 0) { - assert(grp->vars.value != NULL); - free(grp->vars.value); - grp->vars.value = NULL; - grp->vars.nalloc = 0; + assert(grp->vars.value != NULL); + free(grp->vars.value); + grp->vars.value = NULL; + grp->vars.nalloc = 0; } /* Delete all dims. */ @@ -1190,10 +1528,10 @@ nc4_rec_grp_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp) LOG((4, "%s: deleting dim %s", __func__, dim->name)); /* Close HDF5 dataset associated with this dim. */ if (dim->hdf_dimscaleid && H5Dclose(dim->hdf_dimscaleid) < 0) - return NC_EHDFERR; + return NC_EHDFERR; d = dim->l.next; if ((retval = nc4_dim_list_del(&grp->dim, dim))) - return retval; + return retval; dim = d; } @@ -1204,7 +1542,7 @@ nc4_rec_grp_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp) LOG((4, "%s: deleting type %s", __func__, type->name)); t = type->l.next; if ((retval = type_list_del(&grp->type, type))) - return retval; + return retval; type = t; } @@ -1223,9 +1561,16 @@ nc4_rec_grp_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp) return NC_NOERR; } -/* Remove a NC_ATT_INFO_T from the linked list. This will nc_free the - memory too. -*/ +/** + * @internal Remove a NC_ATT_INFO_T from the linked list. This will + * nc_free the memory too. + * + * @param list Pointer to pointer of list. + * @param att Pointer to attribute info struct. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ int nc4_att_list_del(NC_ATT_INFO_T **list, NC_ATT_INFO_T *att) { @@ -1257,7 +1602,7 @@ nc4_att_list_del(NC_ATT_INFO_T **list, NC_ATT_INFO_T *att) { for (i = 0; i < att->len; i++) if(att->stdata[i]) - free(att->stdata[i]); + free(att->stdata[i]); free(att->stdata); } @@ -1265,7 +1610,7 @@ nc4_att_list_del(NC_ATT_INFO_T **list, NC_ATT_INFO_T *att) if (att->vldata) { for (i = 0; i < att->len; i++) - nc_free_vlen(&att->vldata[i]); + nc_free_vlen(&att->vldata[i]); free(att->vldata); } @@ -1273,7 +1618,18 @@ nc4_att_list_del(NC_ATT_INFO_T **list, NC_ATT_INFO_T *att) return NC_NOERR; } -/* Break a coordinate variable to separate the dimension and the variable */ +/** + * @internal Break a coordinate variable to separate the dimension and + * the variable. + * + * @param grp Pointer to group info struct. + * @param coord_var Pointer to variable info struct. + * @param dim Pointer to dimension info struct. + * + * @return ::NC_NOERR No error. + * @return ::NC_ENOMEM Out of memory. + * @author Quincey Koziol + */ int nc4_break_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *coord_var, NC_DIM_INFO_T *dim) { @@ -1313,7 +1669,17 @@ nc4_break_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *coord_var, NC_DIM_INFO_T return NC_NOERR; } -/* Reform a coordinate variable from a dimension and a variable */ +/** + * @internal Reform a coordinate variable from a dimension and a + * variable + * + * @param grp Pointer to group info struct. + * @param var Pointer to variable info struct. + * @param dim Pointer to dimension info struct. + * + * @return ::NC_NOERR No error. + * @author Quincey Koziol + */ int nc4_reform_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, NC_DIM_INFO_T *dim) { @@ -1344,9 +1710,9 @@ nc4_reform_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, NC_DIM_INFO_T *dim) /* Find dataset ID for dimension */ if (dim1->coord_var) - dim_datasetid = dim1->coord_var->hdf_datasetid; + dim_datasetid = dim1->coord_var->hdf_datasetid; else - dim_datasetid = dim1->hdf_dimscaleid; + dim_datasetid = dim1->hdf_dimscaleid; assert(dim_datasetid > 0); if (H5DSdetach_scale(var->hdf_datasetid, dim_datasetid, d) < 0) BAIL(NC_EHDFERR); @@ -1372,7 +1738,7 @@ nc4_reform_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, NC_DIM_INFO_T *dim) /* Now delete the dimscale's dataset (it will be recreated later, if necessary) */ if (H5Gunlink(grp->hdf_grpid, dim->name) < 0) - return NC_EDIMMETA; + return NC_EDIMMETA; } /* Attach variable to dimension */ @@ -1395,14 +1761,23 @@ nc4_reform_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, NC_DIM_INFO_T *dim) /* Set state transition indicator */ var->became_coord_var = NC_TRUE; - exit: +exit: return retval; } -/* Normalize a UTF8 name. Put the result in norm_name, which can be - * NC_MAX_NAME + 1 in size. This function makes sure the free() gets - * called on the return from utf8proc_NFC, and also ensures that the - * name is not too long. */ +/** + * @internal Normalize a UTF8 name. Put the result in norm_name, which + * can be NC_MAX_NAME + 1 in size. This function makes sure the free() + * gets called on the return from utf8proc_NFC, and also ensures that + * the name is not too long. + * + * @param name Name to normalize. + * @param norm_name The normalized name. + * + * @return ::NC_NOERR No error. + * @return ::NC_EMAXNAME Name too long. + * @author Dennis Heimbigner + */ int nc4_normalize_name(const char *name, char *norm_name) { @@ -1423,14 +1798,21 @@ nc4_normalize_name(const char *name, char *norm_name) /* Print out a bunch of info to stderr about the metadata for debugging purposes. */ #ifdef LOGGING -/* Use this to set the global log level. Set it to NC_TURN_OFF_LOGGING - (-1) to turn off all logging. Set it to 0 to show only errors, and - to higher numbers to show more and more logging details. */ +/** + * Use this to set the global log level. Set it to NC_TURN_OFF_LOGGING + * (-1) to turn off all logging. Set it to 0 to show only errors, and + * to higher numbers to show more and more logging details. + * + * @param new_level The new logging level. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ int nc_set_log_level(int new_level) { if(!nc4_hdf5_initialized) - nc4_hdf5_initialize(); + nc4_hdf5_initialize(); /* If the user wants to completely turn off logging, turn off HDF5 logging too. Now I truely can't think of what to do if this @@ -1446,7 +1828,7 @@ nc_set_log_level(int new_level) nc_log_level <= NC_TURN_OFF_LOGGING) { if (set_auto((H5E_auto_t)&H5Eprint, stderr) < 0) - LOG((0, "H5Eset_auto failed!")); + LOG((0, "H5Eset_auto failed!")); LOG((1, "HDF5 error messages turned on.")); } @@ -1456,8 +1838,16 @@ nc_set_log_level(int new_level) return 0; } -/* Recursively print the metadata of a group. */ #define MAX_NESTS 10 +/** + * @internal Recursively print the metadata of a group. + * + * @param grp Pointer to group info struct. + * @param tab_count Number of tabs. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ static int rec_print_metadata(NC_GRP_INFO_T *grp, int tab_count) { @@ -1477,15 +1867,15 @@ rec_print_metadata(NC_GRP_INFO_T *grp, int tab_count) strcat(tabs, "\t"); LOG((2, "%s GROUP - %s nc_grpid: %d nvars: %d natts: %d", - tabs, grp->name, grp->nc_grpid, grp->nvars, grp->natts)); + tabs, grp->name, grp->nc_grpid, grp->nvars, grp->natts)); for(att = grp->att; att; att = att->l.next) LOG((2, "%s GROUP ATTRIBUTE - attnum: %d name: %s type: %d len: %d", - tabs, att->attnum, att->name, att->nc_typeid, att->len)); + tabs, att->attnum, att->name, att->nc_typeid, att->len)); for(dim = grp->dim; dim; dim = dim->l.next) LOG((2, "%s DIMENSION - dimid: %d name: %s len: %d unlimited: %d", - tabs, dim->dimid, dim->name, dim->len, dim->unlimited)); + tabs, dim->dimid, dim->name, dim->len, dim->unlimited)); for (i=0; i < grp->vars.nelems; i++) { @@ -1496,17 +1886,17 @@ rec_print_metadata(NC_GRP_INFO_T *grp, int tab_count) dims_string = (char*)malloc(sizeof(char)*(var->ndims*4)); strcpy(dims_string, ""); for (d = 0; d < var->ndims; d++) - { - sprintf(temp_string, " %d", var->dimids[d]); - strcat(dims_string, temp_string); - } + { + sprintf(temp_string, " %d", var->dimids[d]); + strcat(dims_string, temp_string); + } } LOG((2, "%s VARIABLE - varid: %d name: %s type: %d ndims: %d dimscale: %d dimids:%s endianness: %d, hdf_typeid: %d", - tabs, var->varid, var->name, var->type_info->nc_typeid, var->ndims, (int)var->dimscale, - (dims_string ? dims_string : " -"),var->type_info->endianness, var->type_info->native_hdf_typeid)); + tabs, var->varid, var->name, var->type_info->nc_typeid, var->ndims, (int)var->dimscale, + (dims_string ? dims_string : " -"),var->type_info->endianness, var->type_info->native_hdf_typeid)); for(att = var->att; att; att = att->l.next) - LOG((2, "%s VAR ATTRIBUTE - attnum: %d name: %s type: %d len: %d", - tabs, att->attnum, att->name, att->nc_typeid, att->len)); + LOG((2, "%s VAR ATTRIBUTE - attnum: %d name: %s type: %d len: %d", + tabs, att->attnum, att->name, att->nc_typeid, att->len)); if(dims_string) { free(dims_string); @@ -1517,33 +1907,33 @@ rec_print_metadata(NC_GRP_INFO_T *grp, int tab_count) for (type = grp->type; type; type = type->l.next) { LOG((2, "%s TYPE - nc_typeid: %d hdf_typeid: 0x%x size: %d committed: %d " - "name: %s num_fields: %d", tabs, type->nc_typeid, - type->hdf_typeid, type->size, (int)type->committed, type->name, - type->u.c.num_fields)); + "name: %s num_fields: %d", tabs, type->nc_typeid, + type->hdf_typeid, type->size, (int)type->committed, type->name, + type->u.c.num_fields)); /* Is this a compound type? */ if (type->nc_type_class == NC_COMPOUND) { - LOG((3, "compound type")); - for (field = type->u.c.field; field; field = field->l.next) - LOG((4, "field %s offset %d nctype %d ndims %d", field->name, - field->offset, field->nc_typeid, field->ndims)); + LOG((3, "compound type")); + for (field = type->u.c.field; field; field = field->l.next) + LOG((4, "field %s offset %d nctype %d ndims %d", field->name, + field->offset, field->nc_typeid, field->ndims)); } else if (type->nc_type_class == NC_VLEN) { - LOG((3, "VLEN type")); + LOG((3, "VLEN type")); LOG((4, "base_nc_type: %d", type->u.v.base_nc_typeid)); } else if (type->nc_type_class == NC_OPAQUE) - LOG((3, "Opaque type")); + LOG((3, "Opaque type")); else if (type->nc_type_class == NC_ENUM) { - LOG((3, "Enum type")); + LOG((3, "Enum type")); LOG((4, "base_nc_type: %d", type->u.e.base_nc_typeid)); } else { - LOG((0, "Unknown class: %d", type->nc_type_class)); - return NC_EBADTYPE; + LOG((0, "Unknown class: %d", type->nc_type_class)); + return NC_EBADTYPE; } } @@ -1551,38 +1941,50 @@ rec_print_metadata(NC_GRP_INFO_T *grp, int tab_count) if (grp->children) { for (g = grp->children; g; g = g->l.next) - if ((retval = rec_print_metadata(g, tab_count + 1))) - return retval; + if ((retval = rec_print_metadata(g, tab_count + 1))) + return retval; } return NC_NOERR; } -/* Print out the internal metadata for a file. This is useful to check - * that netCDF is working! Nonetheless, this function will print - * nothing if logging is not set to at least two. */ +/** + * @internal Print out the internal metadata for a file. This is + * useful to check that netCDF is working! Nonetheless, this function + * will print nothing if logging is not set to at least two. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ int log_metadata_nc(NC *nc) { NC_HDF5_FILE_INFO_T *h5 = NC4_DATA(nc); LOG((2, "*** NetCDF-4 Internal Metadata: int_ncid 0x%x ext_ncid 0x%x", - nc->int_ncid, nc->ext_ncid)); + nc->int_ncid, nc->ext_ncid)); if (!h5) { LOG((2, "This is a netCDF-3 file.")); return NC_NOERR; } LOG((2, "FILE - hdfid: 0x%x path: %s cmode: 0x%x parallel: %d redef: %d " - "fill_mode: %d no_write: %d next_nc_grpid: %d", h5->hdfid, nc->path, - h5->cmode, (int)h5->parallel, (int)h5->redef, h5->fill_mode, (int)h5->no_write, - h5->next_nc_grpid)); + "fill_mode: %d no_write: %d next_nc_grpid: %d", h5->hdfid, nc->path, + h5->cmode, (int)h5->parallel, (int)h5->redef, h5->fill_mode, (int)h5->no_write, + h5->next_nc_grpid)); return rec_print_metadata(h5->root_grp, 0); } #endif /*LOGGING */ -/* Show the in-memory metadata for a netcdf file. */ +/** + * @internal Show the in-memory metadata for a netcdf file. + * + * @param ncid File and group ID. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett + */ int NC4_show_metadata(int ncid) { diff --git a/libsrc4/nc4type.c b/libsrc4/nc4type.c index 57eb28ffdc..186e311dd1 100644 --- a/libsrc4/nc4type.c +++ b/libsrc4/nc4type.c @@ -1,27 +1,56 @@ -/* - -This file is part of netcdf-4, a netCDF-like interface for HDF5, or a -HDF5 backend for netCDF, depending on your point of view. - -This file handles the nc4 user-defined type functions (i.e. compound -and opaque types). - -Copyright 2005, University Corporation for Atmospheric Research. See -the COPYRIGHT file for copying and redistribution conditions. - -$Id: nc4type.c,v 1.73 2010/05/25 17:54:24 dmh Exp $ -*/ - +/** + * @file + * + * @internal This file is part of netcdf-4, a netCDF-like interface + * for HDF5, or a HDF5 backend for netCDF, depending on your point of + * view. + * + * This file handles the nc4 user-defined type functions + * (i.e. compound and opaque types). + * + * Copyright 2005, University Corporation for Atmospheric Research. See + * the COPYRIGHT file for copying and redistribution conditions. + * + * @author Ed Hartnett + */ #include "nc4internal.h" #include "nc4dispatch.h" -#define NUM_ATOMIC_TYPES 13 +#define NUM_ATOMIC_TYPES 13 /**< Number of netCDF atomic types. */ + +/** @internal Names of atomic types. */ char atomic_name[NUM_ATOMIC_TYPES][NC_MAX_NAME + 1] = {"none", "byte", "char", "short", "int", "float", "double", "ubyte", "ushort", "uint", "int64", "uint64", "string"}; +/* The sizes of types may vary from platform to platform, but within + * netCDF files, type sizes are fixed. */ +#define NC_CHAR_LEN sizeof(char) /**< @internal Size of char. */ +#define NC_STRING_LEN sizeof(char *) /**< @internal Size of char *. */ +#define NC_BYTE_LEN 1 /**< @internal Size of byte. */ +#define NC_SHORT_LEN 2 /**< @internal Size of short. */ +#define NC_INT_LEN 4 /**< @internal Size of int. */ +#define NC_FLOAT_LEN 4 /**< @internal Size of float. */ +#define NC_DOUBLE_LEN 8 /**< @internal Size of double. */ +#define NC_INT64_LEN 8 /**< @internal Size of int64. */ + +/** + * @internal Determine if two types are equal. + * + * @param ncid1 First file/group ID. + * @param typeid1 First type ID. + * @param ncid2 Second file/group ID. + * @param typeid2 Second type ID. + * @param equalp Pointer that will get 1 if the two types are equal. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_EBADTYPE Type not found. + * @return ::NC_EINVAL Invalid type. + * @author Ed Hartnett + */ extern int NC4_inq_type_equal(int ncid1, nc_type typeid1, int ncid2, nc_type typeid2, int *equalp) @@ -80,7 +109,20 @@ NC4_inq_type_equal(int ncid1, nc_type typeid1, int ncid2, return NC_NOERR; } -/* Get the id of a type from the name. */ +/** + * @internal Get the id of a type from the name. + * + * @param ncid File and group ID. + * @param name Name of type. + * @param typeidp Pointer that will get the type ID. + * + * @return ::NC_NOERR No error. + * @return ::NC_ENOMEM Out of memory. + * @return ::NC_EINVAL Bad size. + * @return ::NC_ENOTNC4 User types in netCDF-4 files only. + * @return ::NC_EBADTYPE Type not found. + * @author Ed Hartnett + */ extern int NC4_inq_typeid(int ncid, const char *name, nc_type *typeidp) { @@ -146,8 +188,19 @@ NC4_inq_typeid(int ncid, const char *name, nc_type *typeidp) return NC_NOERR; } -/* Find all user-defined types for a location. This finds all - * user-defined types in a group. */ +/** + * @internal Find all user-defined types for a location. This finds + * all user-defined types in a group. + * + * @param ncid File and group ID. + * @param ntypes Pointer that gets the number of user-defined + * types. Ignored if NULL + * @param typeids Array that gets the typeids. Ignored if NULL. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Ed Hartnett + */ int NC4_inq_typeids(int ncid, int *ntypes, int *typeids) { @@ -179,9 +232,25 @@ NC4_inq_typeids(int ncid, int *ntypes, int *typeids) return NC_NOERR; } - -/* This internal function adds a new user defined type to the metadata - * of a group of an open file. */ +/** + * @internal This internal function adds a new user defined type to + * the metadata of a group of an open file. + * + * @param ncid File and group ID. + * @param size Size in bytes of new type. + * @param name Name of new type. + * @param base_typeid Base type ID. + * @param type_class NC_VLEN, NC_ENUM, or NC_STRING + * @param typeidp Pointer that gets new type ID. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_ENOTNC4 User types in netCDF-4 files only. + * @return ::NC_EINVAL Bad size. + * @return ::NC_EMAXNAME Name is too long. + * @return ::NC_EBADNAME Name breaks netCDF name rules. + * @author Ed Hartnett +*/ static int add_user_type(int ncid, size_t size, const char *name, nc_type base_typeid, nc_type type_class, nc_type *typeidp) @@ -244,20 +313,20 @@ add_user_type(int ncid, size_t size, const char *name, nc_type base_typeid, return NC_NOERR; } - -/* The sizes of types may vary from platform to platform, but within - * netCDF files, type sizes are fixed. */ -#define NC_CHAR_LEN sizeof(char) -#define NC_STRING_LEN sizeof(char *) -#define NC_BYTE_LEN 1 -#define NC_SHORT_LEN 2 -#define NC_INT_LEN 4 -#define NC_FLOAT_LEN 4 -#define NC_DOUBLE_LEN 8 -#define NC_INT64_LEN 8 - -/* Get the name and size of a type. For strings, 1 is returned. For - * VLEN the base type len is returned. */ +/** + * @internal Get the name and size of a type. For strings, 1 is + * returned. For VLEN the base type len is returned. + * + * @param ncid File and group ID. + * @param typeid1 Type ID. + * @param name Gets the name of the type. + * @param size Gets the size of one element of the type in bytes. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_EBADTYPE Type not found. + * @author Ed Hartnett +*/ int NC4_inq_type(int ncid, nc_type typeid1, char *name, size_t *size) { @@ -306,14 +375,41 @@ NC4_inq_type(int ncid, nc_type typeid1, char *name, size_t *size) return NC_NOERR; } -/* Create a compound type. */ +/** + * @internal Create a compound type. + * + * @param ncid File and group ID. + * @param size Gets size in bytes of one element of type. + * @param name Name of the type. + * @param typeidp Gets the type ID. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_EMAXNAME Name is too long. + * @return ::NC_EBADNAME Name breaks netCDF name rules. + * @author Ed Hartnett +*/ int NC4_def_compound(int ncid, size_t size, const char *name, nc_type *typeidp) { return add_user_type(ncid, size, name, 0, NC_COMPOUND, typeidp); } -/* Insert a named field into a compound type. */ +/** + * @internal Insert a named field into a compound type. + * + * @param ncid File and group ID. + * @param typeid1 Type ID. + * @param name Name of the type. + * @param offset Offset of field. + * @param field_typeid Field type ID. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_EMAXNAME Name is too long. + * @return ::NC_EBADNAME Name breaks netCDF name rules. + * @author Ed Hartnett +*/ int NC4_insert_compound(int ncid, nc_type typeid1, const char *name, size_t offset, nc_type field_typeid) @@ -322,7 +418,23 @@ NC4_insert_compound(int ncid, nc_type typeid1, const char *name, size_t offset, field_typeid, 0, NULL); } -/* Insert a named array into a compound type. */ +/** + * @internal Insert a named array into a compound type. + * + * @param ncid File and group ID. + * @param typeid1 Type ID. + * @param name Name of the array field. + * @param offset Offset in bytes. + * @param field_typeid Type of field. + * @param ndims Number of dims for field. + * @param dim_sizesp Array of dim sizes. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_EMAXNAME Name is too long. + * @return ::NC_EBADNAME Name breaks netCDF name rules. + * @author Ed Hartnett +*/ extern int NC4_insert_array_compound(int ncid, int typeid1, const char *name, size_t offset, nc_type field_typeid, @@ -368,7 +480,22 @@ NC4_insert_array_compound(int ncid, int typeid1, const char *name, return NC_NOERR; } -/* Find info about any user defined type. */ +/** + * @internal Find info about any user defined type. + * + * @param ncid File and group ID. + * @param typeid1 Type ID. + * @param name Gets name of the type. + * @param size Gets size in bytes of one element of type. + * @param base_nc_typep Gets the base nc_type. + * @param nfieldsp Gets the number of fields. + * @param classp Gets the type class (NC_COMPOUND, NC_ENUM, NC_VLEN). + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_EBADTYPE Type not found. + * @author Ed Hartnett +*/ int NC4_inq_user_type(int ncid, nc_type typeid1, char *name, size_t *size, nc_type *base_nc_typep, size_t *nfieldsp, int *classp) @@ -431,7 +558,23 @@ NC4_inq_user_type(int ncid, nc_type typeid1, char *name, size_t *size, return NC_NOERR; } -/* Given the ncid, typeid and fieldid, get info about the field. */ +/** + * @internal Given the ncid, typeid and fieldid, get info about the + * field. + * + * @param ncid File and group ID. + * @param typeid1 Type ID. + * @param fieldid Field ID. + * @param name Gets name of field. + * @param offsetp Gets offset of field. + * @param field_typeidp Gets field type ID. + * @param ndimsp Gets number of dims for this field. + * @param dim_sizesp Gets the dim sizes for this field. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Ed Hartnett +*/ int NC4_inq_compound_field(int ncid, nc_type typeid1, int fieldid, char *name, size_t *offsetp, nc_type *field_typeidp, int *ndimsp, @@ -471,8 +614,18 @@ NC4_inq_compound_field(int ncid, nc_type typeid1, int fieldid, char *name, return NC_EBADFIELD; } -/* Find a netcdf-4 file. THis will return an error if it finds a - * netcdf-3 file, or a netcdf-4 file with strict nc3 rules. */ +/** + * @internal Find a netcdf-4 file. THis will return an error if it + * finds a netcdf-3 file, or a netcdf-4 file with strict nc3 rules. + * + * @param ncid File and group ID. + * @param nc Pointer to pointer that gets NC struct for file. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_ESTRICTNC3 File uses classic model. + * @author Ed Hartnett +*/ static int find_nc4_file(int ncid, NC **nc) { @@ -488,7 +641,20 @@ find_nc4_file(int ncid, NC **nc) return NC_NOERR; } -/* Given the typeid and the name, get the fieldid. */ +/** + * @internal Given the typeid and the name, get the fieldid. + * + * @param ncid File and group ID. + * @param typeid1 Type ID. + * @param name Name of field. + * @param fieldidp Pointer that gets new field ID. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_EBADTYPE Type not found. + * @return ::NC_EBADFIELD Field not found. + * @author Ed Hartnett +*/ int NC4_inq_compound_fieldindex(int ncid, nc_type typeid1, const char *name, int *fieldidp) { @@ -533,7 +699,20 @@ NC4_inq_compound_fieldindex(int ncid, nc_type typeid1, const char *name, int *fi /* Opaque type. */ -/* Create an opaque type. Provide a size and a name. */ +/** + * @internal Create an opaque type. Provide a size and a name. + * + * @param ncid File and group ID. + * @param datum_size Size in bytes of a datum. + * @param name Name of new vlen type. + * @param typeidp Pointer that gets new type ID. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_EMAXNAME Name is too long. + * @return ::NC_EBADNAME Name breaks netCDF name rules. + * @author Ed Hartnett +*/ int NC4_def_opaque(int ncid, size_t datum_size, const char *name, nc_type *typeidp) @@ -542,7 +721,20 @@ NC4_def_opaque(int ncid, size_t datum_size, const char *name, } -/* Define a variable length type. */ +/** + * @internal Define a variable length type. + * + * @param ncid File and group ID. + * @param name Name of new vlen type. + * @param base_typeid Base type of vlen. + * @param typeidp Pointer that gets new type ID. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_EMAXNAME Name is too long. + * @return ::NC_EBADNAME Name breaks netCDF name rules. + * @author Ed Hartnett +*/ int NC4_def_vlen(int ncid, const char *name, nc_type base_typeid, nc_type *typeidp) @@ -550,8 +742,20 @@ NC4_def_vlen(int ncid, const char *name, nc_type base_typeid, return add_user_type(ncid, 0, name, base_typeid, NC_VLEN, typeidp); } -/* Create an enum type. Provide a base type and a name. At the moment - * only ints are accepted as base types. */ +/** + * @internal Create an enum type. Provide a base type and a name. At + * the moment only ints are accepted as base types. + * + * @param ncid File and group ID. + * @param base_typeid Base type of vlen. + * @param name Name of new vlen type. + * @param typeidp Pointer that gets new type ID. + * + * @return ::NC_NOERR No error. + * @return ::NC_EMAXNAME Name is too long. + * @return ::NC_EBADNAME Name breaks netCDF name rules. + * @author Ed Hartnett +*/ int NC4_def_enum(int ncid, nc_type base_typeid, const char *name, nc_type *typeidp) @@ -560,7 +764,21 @@ NC4_def_enum(int ncid, nc_type base_typeid, const char *name, } -/* Get enum name from enum value. Name size will be <= NC_MAX_NAME. */ +/** + * @internal Get enum name from enum value. Name size will be <= + * NC_MAX_NAME. + * + * @param ncid File and group ID. + * @param xtype Type ID. + * @param value Value of enum. + * @param identifier Gets the identifier for this enum value. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_EBADTYPE Type not found. + * @return ::NC_EINVAL Invalid type data. + * @author Ed Hartnett +*/ int NC4_inq_enum_ident(int ncid, nc_type xtype, long long value, char *identifier) { @@ -634,8 +852,22 @@ NC4_inq_enum_ident(int ncid, nc_type xtype, long long value, char *identifier) return NC_NOERR; } -/* Get information about an enum member: an identifier and - * value. Identifier size will be <= NC_MAX_NAME. */ +/** + * @internal Get information about an enum member: an identifier and + * value. Identifier size will be <= NC_MAX_NAME. + * + * @param ncid File and group ID. + * @param typeid1 Type ID. + * @param idx Enum member index. + * @param identifier Gets the identifier. + * @param value Gets the enum value. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_EBADTYPE Type not found. + * @return ::NC_EINVAL Bad idx. + * @author Ed Hartnett +*/ int NC4_inq_enum_member(int ncid, nc_type typeid1, int idx, char *identifier, void *value) @@ -678,8 +910,22 @@ NC4_inq_enum_member(int ncid, nc_type typeid1, int idx, char *identifier, return NC_NOERR; } -/* Insert a identifierd value into an enum type. The value must fit within - * the size of the enum type, the identifier size must be <= NC_MAX_NAME. */ +/** + * @internal Insert a identifier value into an enum type. The value + * must fit within the size of the enum type, the identifier size must + * be <= NC_MAX_NAME. + * + * @param ncid File and group ID. + * @param typeid1 Type ID. + * @param identifier Name of this enum value. + * @param value Value of enum. + * + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_EBADTYPE Type not found. + * @return ::NC_ETYPDEFINED Type already defined. + * @author Ed Hartnett +*/ int NC4_insert_enum(int ncid, nc_type typeid1, const char *identifier, const void *value) @@ -722,7 +968,19 @@ NC4_insert_enum(int ncid, nc_type typeid1, const char *identifier, return NC_NOERR; } -/* Insert one element into an already allocated vlen array element. */ +/** + * @internal Insert one element into an already allocated vlen array + * element. + * + * @param ncid File and group ID. + * @param typeid1 Type ID. + * @param vlen_element The VLEN element to insert. + * @param len Length of element in bytes. + * @param data Element data. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett +*/ int NC4_put_vlen_element(int ncid, int typeid1, void *vlen_element, size_t len, const void *data) @@ -733,7 +991,19 @@ NC4_put_vlen_element(int ncid, int typeid1, void *vlen_element, return NC_NOERR; } -/* Insert one element into an already allocated vlen array element. */ +/** + * @internal Insert one element into an already allocated vlen array + * element. + * + * @param ncid File and group ID. + * @param typeid1 Type ID. + * @param vlen_element The VLEN element to insert. + * @param len Length of element in bytes. + * @param data Element data. + * + * @return ::NC_NOERR No error. + * @author Ed Hartnett +*/ int NC4_get_vlen_element(int ncid, int typeid1, const void *vlen_element, size_t *len, void *data) diff --git a/libsrc4/nc4var.c b/libsrc4/nc4var.c index 889c7f7a67..36be4e7488 100644 --- a/libsrc4/nc4var.c +++ b/libsrc4/nc4var.c @@ -1,35 +1,43 @@ -/* -This file is part of netcdf-4, a netCDF-like interface for HDF5, or a -HDF5 backend for netCDF, depending on your point of view. +/** + * @file + * This file is part of netcdf-4, a netCDF-like interface for HDF5, or a + * HDF5 backend for netCDF, depending on your point of view. -This file handles the nc4 variable functions. + * This file handles the NetCDF-4 variable functions. -Copyright 2003-2006, University Corporation for Atmospheric -Research. See COPYRIGHT file for copying and redistribution -conditions. -*/ + * Copyright 2003-2006, University Corporation for Atmospheric + * Research. See COPYRIGHT file for copying and redistribution + * conditions. + */ #include #include "nc4dispatch.h" #include -/* Min and max deflate levels tolerated by HDF5. */ -#define MIN_DEFLATE_LEVEL 0 -#define MAX_DEFLATE_LEVEL 9 - -/* One meg is the minimum buffer size. */ -#define ONE_MEG 1048576 - /* Szip options. */ -#define NC_SZIP_EC_OPTION_MASK 4 -#define NC_SZIP_NN_OPTION_MASK 32 -#define NC_SZIP_MAX_PIXELS_PER_BLOCK 32 - -extern int nc4_get_default_fill_value(const NC_TYPE_INFO_T *type_info, void *fill_value); - - -/* If the HDF5 dataset for this variable is open, then close it and - * reopen it, with the perhaps new settings for chunk caching. */ +#define NC_SZIP_EC_OPTION_MASK 4 /**< @internal SZIP EC option mask. */ +#define NC_SZIP_NN_OPTION_MASK 32 /**< @internal SZIP NN option mask. */ +#define NC_SZIP_MAX_PIXELS_PER_BLOCK 32 /**< @internal SZIP max pixels per block. */ + +/** @internal Default size for unlimited dim chunksize */ +#define DEFAULT_1D_UNLIM_SIZE (4096) + +#define NC_ARRAY_GROWBY 4 /**< @internal Amount to grow array. */ + +extern int nc4_get_default_fill_value(const NC_TYPE_INFO_T *type_info, + void *fill_value); + +/** + * @internal If the HDF5 dataset for this variable is open, then close + * it and reopen it, with the perhaps new settings for chunk caching. + * + * @param grp Pointer to the group info. + * @param var Pointer to the var info. + * + * @returns ::NC_NOERR No error. + * @returns ::NC_EHDFERR HDF5 error. + * @author Ed Hartnett + */ int nc4_reopen_dataset(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var) { @@ -38,27 +46,44 @@ nc4_reopen_dataset(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var) if (var->hdf_datasetid) { if ((access_pid = H5Pcreate(H5P_DATASET_ACCESS)) < 0) - return NC_EHDFERR; + return NC_EHDFERR; if (H5Pset_chunk_cache(access_pid, var->chunk_cache_nelems, - var->chunk_cache_size, - var->chunk_cache_preemption) < 0) - return NC_EHDFERR; + var->chunk_cache_size, + var->chunk_cache_preemption) < 0) + return NC_EHDFERR; if (H5Dclose(var->hdf_datasetid) < 0) - return NC_EHDFERR; + return NC_EHDFERR; if ((var->hdf_datasetid = H5Dopen2(grp->hdf_grpid, var->name, - access_pid)) < 0) - return NC_EHDFERR; + access_pid)) < 0) + return NC_EHDFERR; if (H5Pclose(access_pid) < 0) - return NC_EHDFERR; + return NC_EHDFERR; } return NC_NOERR; } -/* Set chunk cache size for a variable. */ +/** + * @internal Set chunk cache size for a variable. This is the internal + * function called by nc_set_var_chunk_cache(). + * + * @param ncid File ID. + * @param varid Variable ID. + * @param size Size in bytes to set cache. + * @param nelems Number of elements in cache. + * @param preemption Controls cache swapping. + * + * @returns ::NC_NOERR No error. + * @returns ::NC_EBADID Bad ncid. + * @returns ::NC_ENOTVAR Invalid variable ID. + * @returns ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3 netcdf-4 file. + * @returns ::NC_EINVAL Invalid input. + * @returns ::NC_EHDFERR HDF5 error. + * @author Ed Hartnett + */ int NC4_set_var_chunk_cache(int ncid, int varid, size_t size, size_t nelems, - float preemption) + float preemption) { NC *nc; NC_GRP_INFO_T *grp; @@ -73,20 +98,13 @@ NC4_set_var_chunk_cache(int ncid, int varid, size_t size, size_t nelems, /* Find info for this file and group, and set pointer to each. */ if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5))) return retval; - - /* An attempt to do any of these things on a netCDF-3 file is - * ignored with no error. */ - if (!h5) - return NC_NOERR; - assert(nc && grp && h5); /* Find the var. */ if (varid < 0 || varid >= grp->vars.nelems) - return NC_ENOTVAR; + return NC_ENOTVAR; var = grp->vars.value[varid]; - if (!var) return NC_ENOTVAR; - assert(var->varid == varid); + assert(var && var->varid == varid); /* Set the values. */ var->chunk_cache_size = size; @@ -99,18 +117,29 @@ NC4_set_var_chunk_cache(int ncid, int varid, size_t size, size_t nelems, return NC_NOERR; } -/* Need this version for fortran. Accept negative numbers to leave - * settings as they are. */ +/** + * @internal A wrapper for NC4_set_var_chunk_cache(), we need this + * version for fortran. Negative values leave settings as they are. + * + * @param ncid File ID. + * @param varid Variable ID. + * @param size Size in bytes to set cache. + * @param nelems Number of elements in cache. + * @param preemption Controls cache swapping. + * + * @returns ::NC_NOERR for success + * @author Ed Hartnett + */ int nc_set_var_chunk_cache_ints(int ncid, int varid, int size, int nelems, - int preemption) + int preemption) { size_t real_size = H5D_CHUNK_CACHE_NBYTES_DEFAULT; size_t real_nelems = H5D_CHUNK_CACHE_NSLOTS_DEFAULT; - float real_preemption = H5D_CHUNK_CACHE_W0_DEFAULT; + float real_preemption = CHUNK_CACHE_PREEMPTION; if (size >= 0) - real_size = ((size_t) size) * MEGABYTE; + real_size = ((size_t) size) * MEGABYTE; if (nelems >= 0) real_nelems = nelems; @@ -119,13 +148,28 @@ nc_set_var_chunk_cache_ints(int ncid, int varid, int size, int nelems, real_preemption = preemption / 100.; return NC4_set_var_chunk_cache(ncid, varid, real_size, real_nelems, - real_preemption); + real_preemption); } -/* Get chunk cache size for a variable. */ +/** + * @internal This is called by nc_get_var_chunk_cache(). Get chunk + * cache size for a variable. + * + * @param ncid File ID. + * @param varid Variable ID. + * @param sizep Gets size in bytes of cache. + * @param nelemsp Gets number of element slots in cache. + * @param preemptionp Gets cache swapping setting. + * + * @returns ::NC_NOERR No error. + * @returns ::NC_EBADID Bad ncid. + * @returns ::NC_ENOTVAR Invalid variable ID. + * @returns ::NC_ENOTNC4 Not a netCDF-4 file. + * @author Ed Hartnett + */ int NC4_get_var_chunk_cache(int ncid, int varid, size_t *sizep, - size_t *nelemsp, float *preemptionp) + size_t *nelemsp, float *preemptionp) { NC *nc; NC_GRP_INFO_T *grp; @@ -136,20 +180,13 @@ NC4_get_var_chunk_cache(int ncid, int varid, size_t *sizep, /* Find info for this file and group, and set pointer to each. */ if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5))) return retval; - - /* Attempting to do any of these things on a netCDF-3 file produces - * an error. */ - if (!h5) - return NC_ENOTNC4; - assert(nc && grp && h5); /* Find the var. */ if (varid < 0 || varid >= grp->vars.nelems) - return NC_ENOTVAR; + return NC_ENOTVAR; var = grp->vars.value[varid]; - if (!var) return NC_ENOTVAR; - assert(var->varid == varid); + assert(var && var->varid == varid); /* Give the user what they want. */ if (sizep) @@ -162,17 +199,32 @@ NC4_get_var_chunk_cache(int ncid, int varid, size_t *sizep, return NC_NOERR; } -/* Get chunk cache size for a variable. */ +/** + * @internal A wrapper for NC4_get_var_chunk_cache(), we need this + * version for fortran. + * + * @param ncid File ID. + * @param varid Variable ID. + * @param sizep Gets size in bytes of cache. + * @param nelemsp Gets number of element slots in cache. + * @param preemptionp Gets cache swapping setting. + * + * @returns ::NC_NOERR No error. + * @returns ::NC_EBADID Bad ncid. + * @returns ::NC_ENOTVAR Invalid variable ID. + * @returns ::NC_ENOTNC4 Not a netCDF-4 file. + * @author Ed Hartnett + */ int nc_get_var_chunk_cache_ints(int ncid, int varid, int *sizep, - int *nelemsp, int *preemptionp) + int *nelemsp, int *preemptionp) { size_t real_size, real_nelems; float real_preemption; int ret; if ((ret = NC4_get_var_chunk_cache(ncid, varid, &real_size, - &real_nelems, &real_preemption))) + &real_nelems, &real_preemption))) return ret; if (sizep) @@ -185,7 +237,19 @@ nc_get_var_chunk_cache_ints(int ncid, int varid, int *sizep, return NC_NOERR; } -/* Check a set of chunksizes to see if they specify a chunk that is too big. */ +/** + * @internal Check a set of chunksizes to see if they specify a chunk + * that is too big. + * + * @param grp Pointer to the group info. + * @param var Pointer to the var info. + * @param chunksizes Array of chunksizes to check. + * + * @returns ::NC_NOERR No error. + * @returns ::NC_EBADID Bad ncid. + * @returns ::NC_ENOTVAR Invalid variable ID. + * @returns ::NC_EBADCHUNK Bad chunksize. + */ static int check_chunksizes(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, const size_t *chunksizes) { @@ -197,13 +261,13 @@ check_chunksizes(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, const size_t *chunksize if ((retval = nc4_get_typelen_mem(grp->nc4_info, var->type_info->nc_typeid, 0, &type_len))) return retval; if (var->type_info->nc_type_class == NC_VLEN) - dprod = (double)sizeof(hvl_t); + dprod = (double)sizeof(hvl_t); else - dprod = (double)type_len; + dprod = (double)type_len; for (d = 0; d < var->ndims; d++) { if (chunksizes[d] < 1) - return NC_EINVAL; + return NC_EINVAL; dprod *= (double) chunksizes[d]; } @@ -213,8 +277,17 @@ check_chunksizes(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, const size_t *chunksize return NC_NOERR; } -/* Find the default chunk nelems (i.e. length of chunk along each - * dimension). */ +/** + * @internal Determine some default chunksizes for a variable. + * + * @param grp Pointer to the group info. + * @param var Pointer to the var info. + * + * @returns ::NC_NOERR for success + * @returns ::NC_EBADID Bad ncid. + * @returns ::NC_ENOTVAR Invalid variable ID. + * @author Ed Hartnett + */ static int nc4_find_default_chunksizes2(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var) { @@ -244,35 +317,34 @@ nc4_find_default_chunksizes2(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var) { assert(var->dim[d]); if (! var->dim[d]->unlimited) - num_values *= (float)var->dim[d]->len; + num_values *= (float)var->dim[d]->len; else { - num_unlim++; - var->chunksizes[d] = 1; /* overwritten below, if all dims are unlimited */ + num_unlim++; + var->chunksizes[d] = 1; /* overwritten below, if all dims are unlimited */ } } /* Special case to avoid 1D vars with unlim dim taking huge amount of space (DEFAULT_CHUNK_SIZE bytes). Instead we limit to about 4KB */ -#define DEFAULT_1D_UNLIM_SIZE (4096) /* TODO: make build-time parameter? */ if (var->ndims == 1 && num_unlim == 1) { - if (DEFAULT_CHUNK_SIZE / type_size <= 0) - suggested_size = 1; - else if (DEFAULT_CHUNK_SIZE / type_size > DEFAULT_1D_UNLIM_SIZE) - suggested_size = DEFAULT_1D_UNLIM_SIZE; - else - suggested_size = DEFAULT_CHUNK_SIZE / type_size; - var->chunksizes[0] = suggested_size / type_size; - LOG((4, "%s: name %s dim %d DEFAULT_CHUNK_SIZE %d num_values %f type_size %d " - "chunksize %ld", __func__, var->name, d, DEFAULT_CHUNK_SIZE, num_values, type_size, var->chunksizes[0])); + if (DEFAULT_CHUNK_SIZE / type_size <= 0) + suggested_size = 1; + else if (DEFAULT_CHUNK_SIZE / type_size > DEFAULT_1D_UNLIM_SIZE) + suggested_size = DEFAULT_1D_UNLIM_SIZE; + else + suggested_size = DEFAULT_CHUNK_SIZE / type_size; + var->chunksizes[0] = suggested_size / type_size; + LOG((4, "%s: name %s dim %d DEFAULT_CHUNK_SIZE %d num_values %f type_size %d " + "chunksize %ld", __func__, var->name, d, DEFAULT_CHUNK_SIZE, num_values, type_size, var->chunksizes[0])); } if (var->ndims > 1 && var->ndims == num_unlim) { /* all dims unlimited */ - suggested_size = pow((double)DEFAULT_CHUNK_SIZE/type_size, 1.0/(double)(var->ndims)); - for (d = 0; d < var->ndims; d++) - { - var->chunksizes[d] = suggested_size ? suggested_size : 1; - LOG((4, "%s: name %s dim %d DEFAULT_CHUNK_SIZE %d num_values %f type_size %d " - "chunksize %ld", __func__, var->name, d, DEFAULT_CHUNK_SIZE, num_values, type_size, var->chunksizes[d])); - } + suggested_size = pow((double)DEFAULT_CHUNK_SIZE/type_size, 1.0/(double)(var->ndims)); + for (d = 0; d < var->ndims; d++) + { + var->chunksizes[d] = suggested_size ? suggested_size : 1; + LOG((4, "%s: name %s dim %d DEFAULT_CHUNK_SIZE %d num_values %f type_size %d " + "chunksize %ld", __func__, var->name, d, DEFAULT_CHUNK_SIZE, num_values, type_size, var->chunksizes[d])); + } } /* Pick a chunk length for each dimension, if one has not already @@ -280,19 +352,19 @@ nc4_find_default_chunksizes2(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var) for (d = 0; d < var->ndims; d++) if (!var->chunksizes[d]) { - suggested_size = (pow((double)DEFAULT_CHUNK_SIZE/(num_values * type_size), - 1.0/(double)(var->ndims - num_unlim)) * var->dim[d]->len - .5); - if (suggested_size > var->dim[d]->len) - suggested_size = var->dim[d]->len; - var->chunksizes[d] = suggested_size ? suggested_size : 1; - LOG((4, "%s: name %s dim %d DEFAULT_CHUNK_SIZE %d num_values %f type_size %d " - "chunksize %ld", __func__, var->name, d, DEFAULT_CHUNK_SIZE, num_values, type_size, var->chunksizes[d])); + suggested_size = (pow((double)DEFAULT_CHUNK_SIZE/(num_values * type_size), + 1.0/(double)(var->ndims - num_unlim)) * var->dim[d]->len - .5); + if (suggested_size > var->dim[d]->len) + suggested_size = var->dim[d]->len; + var->chunksizes[d] = suggested_size ? suggested_size : 1; + LOG((4, "%s: name %s dim %d DEFAULT_CHUNK_SIZE %d num_values %f type_size %d " + "chunksize %ld", __func__, var->name, d, DEFAULT_CHUNK_SIZE, num_values, type_size, var->chunksizes[d])); } #ifdef LOGGING /* Find total chunk size. */ for (d = 0; d < var->ndims; d++) - total_chunk_size *= (double) var->chunksizes[d]; + total_chunk_size *= (double) var->chunksizes[d]; LOG((4, "total_chunk_size %f", total_chunk_size)); #endif @@ -302,12 +374,12 @@ nc4_find_default_chunksizes2(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var) { /* Other error? */ if (retval != NC_EBADCHUNK) - return retval; + return retval; /* Chunk is too big! Reduce each dimension by half and try again. */ for ( ; retval == NC_EBADCHUNK; retval = check_chunksizes(grp, var, var->chunksizes)) - for (d = 0; d < var->ndims; d++) - var->chunksizes[d] = var->chunksizes[d]/2 ? var->chunksizes[d]/2 : 1; + for (d = 0; d < var->ndims; d++) + var->chunksizes[d] = var->chunksizes[d]/2 ? var->chunksizes[d]/2 : 1; } /* Do we have any big data overhangs? They can be dangerous to @@ -315,55 +387,92 @@ nc4_find_default_chunksizes2(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var) * beer. */ for (d = 0; d < var->ndims; d++) { - size_t num_chunks; - size_t overhang; - assert(var->chunksizes[d] > 0); - num_chunks = (var->dim[d]->len + var->chunksizes[d] - 1) / var->chunksizes[d]; - if(num_chunks > 0) { - overhang = (num_chunks * var->chunksizes[d]) - var->dim[d]->len; - var->chunksizes[d] -= overhang / num_chunks; - } + size_t num_chunks; + size_t overhang; + assert(var->chunksizes[d] > 0); + num_chunks = (var->dim[d]->len + var->chunksizes[d] - 1) / var->chunksizes[d]; + if(num_chunks > 0) { + overhang = (num_chunks * var->chunksizes[d]) - var->dim[d]->len; + var->chunksizes[d] -= overhang / num_chunks; + } } return NC_NOERR; } -#define NC_ARRAY_GROWBY 4 -int nc4_vararray_add(NC_GRP_INFO_T *grp, - NC_VAR_INFO_T *var) +/** + * @internal Grow the variable array. + * + * @param grp Pointer to the group info. + * @param var Pointer to the var info. + * + * @returns ::NC_NOERR No error. + * @returns ::NC_ENOMEM Out of memory. + * @author Dennis Heimbigner + */ +int nc4_vararray_add(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var) { - NC_VAR_INFO_T **vp = NULL; + NC_VAR_INFO_T **vp = NULL; + + if (grp->vars.nalloc == 0) { + assert(grp->vars.nelems == 0); + vp = (NC_VAR_INFO_T **) malloc(NC_ARRAY_GROWBY * sizeof(NC_VAR_INFO_T *)); + if(vp == NULL) + return NC_ENOMEM; + grp->vars.value = vp; + grp->vars.nalloc = NC_ARRAY_GROWBY; + } + else if(grp->vars.nelems +1 > grp->vars.nalloc) { + vp = (NC_VAR_INFO_T **) realloc(grp->vars.value, + (grp->vars.nalloc + NC_ARRAY_GROWBY) * sizeof(NC_VAR_INFO_T *)); + if(vp == NULL) + return NC_ENOMEM; + grp->vars.value = vp; + grp->vars.nalloc += NC_ARRAY_GROWBY; + } - if (grp->vars.nalloc == 0) { - assert(grp->vars.nelems == 0); - vp = (NC_VAR_INFO_T **) malloc(NC_ARRAY_GROWBY * sizeof(NC_VAR_INFO_T *)); - if(vp == NULL) - return NC_ENOMEM; - grp->vars.value = vp; - grp->vars.nalloc = NC_ARRAY_GROWBY; - } - else if(grp->vars.nelems +1 > grp->vars.nalloc) { - vp = (NC_VAR_INFO_T **) realloc(grp->vars.value, - (grp->vars.nalloc + NC_ARRAY_GROWBY) * sizeof(NC_VAR_INFO_T *)); - if(vp == NULL) - return NC_ENOMEM; - grp->vars.value = vp; - grp->vars.nalloc += NC_ARRAY_GROWBY; - } - - if(var != NULL) { - assert(var->varid == grp->vars.nelems); - grp->vars.value[grp->vars.nelems] = var; - grp->vars.nelems++; - } - return NC_NOERR; + if(var != NULL) { + assert(var->varid == grp->vars.nelems); + grp->vars.value[grp->vars.nelems] = var; + grp->vars.nelems++; + } + return NC_NOERR; } -/* This is called when a new netCDF-4 variable is defined. Break it - * down! */ -static int -nc_def_var_nc4(int ncid, const char *name, nc_type xtype, - int ndims, const int *dimidsp, int *varidp) +/** + * @internal This is called when a new netCDF-4 variable is defined + * with nc_def_var(). + * + * @param ncid File ID. + * @param name Name. + * @param xtype Type. + * @param ndims Number of dims. + * @param dimidsp Array of dim IDs. + * @param varidp Gets the var ID. + * + * @returns ::NC_NOERR No error. + * @returns ::NC_EBADID Bad ncid. + * @returns ::NC_ENOTVAR Invalid variable ID. + * @returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is + * not netCDF-4/HDF5. + * @returns ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3 + * netcdf-4 file. + * @returns ::NC_ELATEDEF Too late to change settings for this variable. + * @returns ::NC_ENOTINDEFINE Not in define mode. + * @returns ::NC_EPERM File is read only. + * @returns ::NC_EMAXDIMS Classic model file exceeds ::NC_MAX_VAR_DIMS. + * @returns ::NC_ESTRICTNC3 Attempting to create netCDF-4 type var in + * classic model file + * @returns ::NC_EBADNAME Bad name. + * @returns ::NC_EBADTYPE Bad type. + * @returns ::NC_ENOMEM Out of memory. + * @returns ::NC_EHDFERR Error returned by HDF5 layer. + * @returns ::NC_EINVAL Invalid input + * @author Ed Hartnett, Dennis Heimbigner + */ +int +NC4_def_var(int ncid, const char *name, nc_type xtype, + int ndims, const int *dimidsp, int *varidp) { NC_GRP_INFO_T *grp; NC_VAR_INFO_T *var; @@ -380,7 +489,8 @@ nc_def_var_nc4(int ncid, const char *name, nc_type xtype, assert(grp && h5); /* If it's not in define mode, strict nc3 files error out, - * otherwise switch to define mode. */ + * otherwise switch to define mode. This will also check that the + * file is writable. */ if (!(h5->flags & NC_INDEF)) { if (h5->cmode & NC_CLASSIC_MODEL) @@ -388,6 +498,7 @@ nc_def_var_nc4(int ncid, const char *name, nc_type xtype, if ((retval = NC4_redef(ncid))) BAIL(retval); } + assert(!h5->no_write); /* Check and normalize the name. */ if ((retval = nc4_check_name(name, norm_name))) @@ -413,9 +524,9 @@ nc_def_var_nc4(int ncid, const char *name, nc_type xtype, if ((retval = nc4_check_dup_name(grp, norm_name))) BAIL(retval); - /* If the file is read-only, return an error. */ - if (h5->no_write) - BAIL(NC_EPERM); + /* If there for non-scalar vars, dim IDs must be provided. */ + if (ndims && !dimidsp) + BAIL(NC_EINVAL); /* Check all the dimids to make sure they exist. */ for (d = 0; d < ndims; d++) @@ -432,39 +543,24 @@ nc_def_var_nc4(int ncid, const char *name, nc_type xtype, } #endif - /* Add a new var. */ - if ((retval = nc4_var_add(&var))) - BAIL(retval); - - /* Now fill in the values in the var info structure. */ - if (!(var->name = malloc((strlen(norm_name) + 1) * sizeof(char)))) - BAIL(NC_ENOMEM); - strcpy(var->name, norm_name); - var->hash = hash_fast(norm_name, strlen(norm_name)); - var->varid = grp->nvars++; - var->ndims = ndims; - var->is_new_var = NC_TRUE; - - nc4_vararray_add(grp, var); - /* If this is a user-defined type, there is a type_info struct with * all the type information. For atomic types, fake up a type_info * struct. */ if (xtype <= NC_STRING) { if (!(type_info = calloc(1, sizeof(NC_TYPE_INFO_T)))) - BAIL(NC_ENOMEM); + BAIL(NC_ENOMEM); type_info->nc_typeid = xtype; type_info->endianness = NC_ENDIAN_NATIVE; if ((retval = nc4_get_hdf_typeid(h5, xtype, &type_info->hdf_typeid, - type_info->endianness))) - BAIL(retval); + type_info->endianness))) + BAIL(retval); if ((type_info->native_hdf_typeid = H5Tget_native_type(type_info->hdf_typeid, - H5T_DIR_DEFAULT)) < 0) + H5T_DIR_DEFAULT)) < 0) BAIL(NC_EHDFERR); if ((retval = nc4_get_typelen_mem(h5, type_info->nc_typeid, 0, - &type_info->size))) - BAIL(retval); + &type_info->size))) + BAIL(retval); /* Set the "class" of the type */ if (xtype == NC_CHAR) @@ -477,20 +573,20 @@ nc_def_var_nc4(int ncid, const char *name, nc_type xtype, BAIL(NC_EHDFERR); switch(class) { - case H5T_STRING: - type_info->nc_type_class = NC_STRING; - break; + case H5T_STRING: + type_info->nc_type_class = NC_STRING; + break; - case H5T_INTEGER: - type_info->nc_type_class = NC_INT; - break; + case H5T_INTEGER: + type_info->nc_type_class = NC_INT; + break; - case H5T_FLOAT: - type_info->nc_type_class = NC_FLOAT; - break; + case H5T_FLOAT: + type_info->nc_type_class = NC_FLOAT; + break; - default: - BAIL(NC_EBADTYPID); + default: + BAIL(NC_EBADTYPID); } } } @@ -501,18 +597,33 @@ nc_def_var_nc4(int ncid, const char *name, nc_type xtype, BAIL(NC_EBADTYPE); } - /* Point to the type, and increment its ref. count */ - var->type_info = type_info; - var->type_info->rc++; - type_info = NULL; + /* Add a new var. */ + if ((retval = nc4_var_add(&var))) + BAIL(retval); + + /* Now fill in the values in the var info structure. */ + if (!(var->name = malloc((strlen(norm_name) + 1) * sizeof(char)))) + BAIL(NC_ENOMEM); + strcpy(var->name, norm_name); + var->hash = hash_fast(norm_name, strlen(norm_name)); + var->varid = grp->nvars++; + var->ndims = ndims; + var->is_new_var = NC_TRUE; + + nc4_vararray_add(grp, var); + + /* Point to the type, and increment its ref. count */ + var->type_info = type_info; + var->type_info->rc++; + type_info = NULL; /* Allocate space for dimension information. */ if (ndims) { if (!(var->dim = calloc(ndims, sizeof(NC_DIM_INFO_T *)))) - BAIL(NC_ENOMEM); + BAIL(NC_ENOMEM); if (!(var->dimids = calloc(ndims, sizeof(int)))) - BAIL(NC_ENOMEM); + BAIL(NC_ENOMEM); } /* Set variables no_fill to match the database default @@ -551,7 +662,7 @@ nc_def_var_nc4(int ncid, const char *name, nc_type xtype, BAIL(retval); if (H5Dclose(dim->hdf_dimscaleid) < 0) - BAIL(NC_EHDFERR); + BAIL(NC_EHDFERR); dim->hdf_dimscaleid = 0; /* Now delete the dataset (it will be recreated later, if necessary) */ @@ -565,9 +676,9 @@ nc_def_var_nc4(int ncid, const char *name, nc_type xtype, #ifdef USE_HDF4 if (dim->unlimited && !h5->hdf4) #else - if (dim->unlimited) + if (dim->unlimited) #endif - var->contiguous = NC_FALSE; + var->contiguous = NC_FALSE; /* Track dimensions for variable */ var->dimids[d] = dimidsp[d]; @@ -577,10 +688,10 @@ nc_def_var_nc4(int ncid, const char *name, nc_type xtype, /* Determine default chunksizes for this variable. (Even for * variables which may be contiguous. */ LOG((4, "allocating array of %d size_t to hold chunksizes for var %s", - var->ndims, var->name)); + var->ndims, var->name)); if (var->ndims) if (!(var->chunksizes = calloc(var->ndims, sizeof(size_t)))) - BAIL(NC_ENOMEM); + BAIL(NC_ENOMEM); if ((retval = nc4_find_default_chunksizes2(grp, var))) BAIL(retval); @@ -597,17 +708,17 @@ nc_def_var_nc4(int ncid, const char *name, nc_type xtype, * and this var has the same name. */ for (dim = grp->dim; dim; dim = dim->l.next) if (dim->hash == var->hash && !strcmp(dim->name, norm_name) && - (!var->ndims || dimidsp[0] != dim->dimid)) + (!var->ndims || dimidsp[0] != dim->dimid)) { - /* Set a different hdf5 name for this variable to avoid name - * clash. */ - if (strlen(norm_name) + strlen(NON_COORD_PREPEND) > NC_MAX_NAME) - BAIL(NC_EMAXNAME); - if (!(var->hdf5_name = malloc((strlen(NON_COORD_PREPEND) + - strlen(norm_name) + 1) * sizeof(char)))) - BAIL(NC_ENOMEM); - - sprintf(var->hdf5_name, "%s%s", NON_COORD_PREPEND, norm_name); + /* Set a different hdf5 name for this variable to avoid name + * clash. */ + if (strlen(norm_name) + strlen(NON_COORD_PREPEND) > NC_MAX_NAME) + BAIL(NC_EMAXNAME); + if (!(var->hdf5_name = malloc((strlen(NON_COORD_PREPEND) + + strlen(norm_name) + 1) * sizeof(char)))) + BAIL(NC_ENOMEM); + + sprintf(var->hdf5_name, "%s%s", NON_COORD_PREPEND, norm_name); } /* If this is a coordinate var, it is marked as a HDF5 dimension @@ -631,41 +742,47 @@ nc_def_var_nc4(int ncid, const char *name, nc_type xtype, return retval; } -/* Create a new variable to hold user data. This is what it's all - * about baby! */ -int -NC4_def_var(int ncid, const char *name, nc_type xtype, int ndims, - const int *dimidsp, int *varidp) -{ - NC *nc; - NC_HDF5_FILE_INFO_T *h5; - - LOG((2, "%s: ncid 0x%x name %s xtype %d ndims %d", - __func__, ncid, name, xtype, ndims)); - - /* If there are dimensions, I need their ids. */ - if (ndims && !dimidsp) - return NC_EINVAL; - - /* Find metadata for this file. */ - if (!(nc = nc4_find_nc_file(ncid,&h5))) - return NC_EBADID; - - /* Handle netcdf-4 cases. */ - return nc_def_var_nc4(ncid, name, xtype, ndims, dimidsp, varidp); -} - -/* Get all the information about a variable. Pass NULL for whatever - * you don't care about. This is an internal function, not exposed to - * the user. */ +/** + * @internal Get all the information about a variable. Pass NULL for whatever + * you don't care about. + * + * @param ncid File ID. + * @param varid Variable ID. + * @param name Gets name. + * @param xtypep Gets type. + * @param ndimsp Gets number of dims. + * @param dimidsp Gets array of dim IDs. + * @param nattsp Gets number of attributes. + * @param shufflep Gets shuffle setting. + * @param deflatep Gets deflate setting. + * @param deflate_levelp Gets deflate level. + * @param fletcher32p Gets fletcher32 setting. + * @param contiguousp Gets contiguous setting. + * @param chunksizesp Gets chunksizes. + * @param no_fill Gets fill mode. + * @param fill_valuep Gets fill value. + * @param endiannessp Gets one of ::NC_ENDIAN_BIG ::NC_ENDIAN_LITTLE + * ::NC_ENDIAN_NATIVE + * @param idp Pointer to memory to store filter id. + * @param nparamsp Pointer to memory to store filter parameter count. + * @param params Pointer to vector of unsigned integers into which + * to store filter parameters. + * + * @returns ::NC_NOERR No error. + * @returns ::NC_EBADID Bad ncid. + * @returns ::NC_ENOTVAR Bad varid. + * @returns ::NC_ENOMEM Out of memory. + * @returns ::NC_EINVAL Invalid input. + * @author Ed Hartnett, Dennis Heimbigner + */ int NC4_inq_var_all(int ncid, int varid, char *name, nc_type *xtypep, - int *ndimsp, int *dimidsp, int *nattsp, - int *shufflep, int *deflatep, int *deflate_levelp, - int *fletcher32p, int *contiguousp, size_t *chunksizesp, - int *no_fill, void *fill_valuep, int *endiannessp, - unsigned int* idp, size_t* nparamsp, unsigned int* params - ) + int *ndimsp, int *dimidsp, int *nattsp, + int *shufflep, int *deflatep, int *deflate_levelp, + int *fletcher32p, int *contiguousp, size_t *chunksizesp, + int *no_fill, void *fill_valuep, int *endiannessp, + unsigned int* idp, size_t* nparamsp, unsigned int* params + ) { NC *nc; NC_GRP_INFO_T *grp; @@ -701,10 +818,9 @@ NC4_inq_var_all(int ncid, int varid, char *name, nc_type *xtypep, /* Find the var. */ if (varid < 0 || varid >= grp->vars.nelems) - return NC_ENOTVAR; + return NC_ENOTVAR; var = grp->vars.value[varid]; - if (!var) return NC_ENOTVAR; - assert(var->varid == varid); + assert(var && var->varid == varid); /* Copy the data to the user's data buffers. */ if (name) @@ -749,7 +865,7 @@ NC4_inq_var_all(int ncid, int varid, char *name, nc_type *xtypep, if (nparamsp) *nparamsp = (var->params == NULL ? 0 : var->nparams); if (params && var->params != NULL) - memcpy(params,var->params,var->nparams*sizeof(unsigned int)); + memcpy(params,var->params,var->nparams*sizeof(unsigned int)); /* Fill value stuff. */ if (no_fill) @@ -760,25 +876,25 @@ NC4_inq_var_all(int ncid, int varid, char *name, nc_type *xtypep, if (!var->no_fill && fill_valuep) { /* Do we have a fill value for this var? */ - if (var->fill_value) - { + if (var->fill_value) + { if (var->type_info->nc_type_class == NC_STRING) - { - if (*(char **)var->fill_value) { + { + if (*(char **)var->fill_value) { if (!(fill_valuep = calloc(1, sizeof(char *)))) - return NC_ENOMEM; + return NC_ENOMEM; if (!(*(char **)fill_valuep = strdup(*(char **)var->fill_value))) - { - free(fill_valuep); - return NC_ENOMEM; - } - } - } + { + free(fill_valuep); + return NC_ENOMEM; + } + } + } else { - assert(var->type_info->size); - memcpy(fill_valuep, var->fill_value, var->type_info->size); + assert(var->type_info->size); + memcpy(fill_valuep, var->fill_value, var->type_info->size); } } else @@ -793,8 +909,8 @@ NC4_inq_var_all(int ncid, int varid, char *name, nc_type *xtypep, free(fill_valuep); return retval; } else { - free(fill_valuep); - } + free(fill_valuep); + } } else { @@ -811,14 +927,41 @@ NC4_inq_var_all(int ncid, int varid, char *name, nc_type *xtypep, return NC_NOERR; } -/* This functions sets extra stuff about a netCDF-4 variable which - must be set before the enddef but after the def_var. This is an - internal function, deliberately hidden from the user so that we can - change the prototype of this functions without changing the API. */ +/** + * @internal This functions sets extra stuff about a netCDF-4 variable which + * must be set before the enddef but after the def_var. + * + * @note All pointer parameters may be NULL, in which case they are ignored. + * @param ncid File ID. + * @param varid Variable ID. + * @param shuffle Pointer to shuffle setting. + * @param deflate Pointer to deflate setting. + * @param deflate_level Pointer to deflate level. + * @param fletcher32 Pointer to fletcher32 setting. + * @param contiguous Pointer to contiguous setting. + * @param chunksizes Array of chunksizes. + * @param no_fill Pointer to no_fill setting. + * @param fill_value Pointer to fill value. + * @param endianness Pointer to endianness setting. + * + * @returns ::NC_NOERR for success + * @returns ::NC_EBADID Bad ncid. + * @returns ::NC_ENOTVAR Invalid variable ID. + * @returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is + * not netCDF-4/HDF5. + * @returns ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3 + * netcdf-4 file. + * @returns ::NC_ELATEDEF Too late to change settings for this variable. + * @returns ::NC_ENOTINDEFINE Not in define mode. + * @returns ::NC_EPERM File is read only. + * @returns ::NC_EINVAL Invalid input + * @returns ::NC_EBADCHUNK Bad chunksize. + * @author Ed Hartnett + */ static int nc_def_var_extra(int ncid, int varid, int *shuffle, int *deflate, - int *deflate_level, int *fletcher32, int *contiguous, - const size_t *chunksizes, int *no_fill, + int *deflate_level, int *fletcher32, int *contiguous, + const size_t *chunksizes, int *no_fill, const void *fill_value, int *endianness) { NC *nc; @@ -835,35 +978,28 @@ nc_def_var_extra(int ncid, int varid, int *shuffle, int *deflate, /* Find info for this file and group, and set pointer to each. */ if ((retval = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5))) return retval; + assert(nc && grp && h5); #ifdef USE_HDF4 ishdf4 = h5->hdf4; #endif - /* Attempting to do any of these things on a netCDF-3 file produces - * an error. */ - if (!h5) - return NC_ENOTNC4; - - assert(nc && grp && h5); - /* Find the var. */ if (varid < 0 || varid >= grp->vars.nelems) - return NC_ENOTVAR; + return NC_ENOTVAR; var = grp->vars.value[varid]; - if (!var) return NC_ENOTVAR; - assert(var->varid == varid); + assert(var && var->varid == varid); /* Can't turn on contiguous and deflate/fletcher32/szip. */ if (contiguous) if ((*contiguous != NC_CHUNKED && deflate) || - (*contiguous != NC_CHUNKED && fletcher32)) - return NC_EINVAL; + (*contiguous != NC_CHUNKED && fletcher32)) + return NC_EINVAL; /* Can't turn on parallel and deflate/fletcher32/szip/shuffle. */ if (nc->mode & (NC_MPIIO | NC_MPIPOSIX)) { if (deflate || fletcher32 || shuffle) - return NC_EINVAL; + return NC_EINVAL; } /* If the HDF5 dataset has already been created, then it is too @@ -879,13 +1015,13 @@ nc_def_var_extra(int ncid, int varid, int *shuffle, int *deflate, if (deflate && deflate_level) { if (*deflate) - if (*deflate_level < MIN_DEFLATE_LEVEL || - *deflate_level > MAX_DEFLATE_LEVEL) + if (*deflate_level < NC_MIN_DEFLATE_LEVEL || + *deflate_level > NC_MAX_DEFLATE_LEVEL) return NC_EINVAL; /* For scalars, just ignore attempt to deflate. */ if (!var->ndims) - return NC_NOERR; + return NC_NOERR; /* Well, if we couldn't find any errors, I guess we have to take * the users settings. Darn! */ @@ -916,17 +1052,17 @@ nc_def_var_extra(int ncid, int varid, int *shuffle, int *deflate, if (contiguous && *contiguous) { if (var->deflate || var->fletcher32 || var->shuffle) - return NC_EINVAL; + return NC_EINVAL; - if (!ishdf4) { - for (d = 0; d < var->ndims; d++) - { - dim = var->dim[d]; - if (dim->unlimited) - return NC_EINVAL; + if (!ishdf4) { + for (d = 0; d < var->ndims; d++) + { + dim = var->dim[d]; + if (dim->unlimited) + return NC_EINVAL; + } + var->contiguous = NC_TRUE; } - var->contiguous = NC_TRUE; - } } /* Chunksizes anyone? */ @@ -939,16 +1075,16 @@ nc_def_var_extra(int ncid, int varid, int *shuffle, int *deflate, if (chunksizes) { - if ((retval = check_chunksizes(grp, var, chunksizes))) - return retval; - for (d = 0; d < var->ndims; d++) { - if(var->dim[d]->len > 0 && chunksizes[d] > var->dim[d]->len) - return NC_EBADCHUNK; - } + if ((retval = check_chunksizes(grp, var, chunksizes))) + return retval; + for (d = 0; d < var->ndims; d++) { + if(var->dim[d]->len > 0 && chunksizes[d] > var->dim[d]->len) + return NC_EBADCHUNK; + } - /* Set the chunksizes for this variable. */ - for (d = 0; d < var->ndims; d++) - var->chunksizes[d] = chunksizes[d]; + /* Set the chunksizes for this variable. */ + for (d = 0; d < var->ndims; d++) + var->chunksizes[d] = chunksizes[d]; } } @@ -956,14 +1092,15 @@ nc_def_var_extra(int ncid, int varid, int *shuffle, int *deflate, * cache size? */ if (!var->contiguous && (chunksizes || deflate || contiguous)) { - /* Determine default chunksizes for this variable. */ - if (!var->chunksizes[0]) - if ((retval = nc4_find_default_chunksizes2(grp, var))) - return retval; + /* Determine default chunksizes for this variable (do nothing + * for scalar vars). */ + if (var->chunksizes && !var->chunksizes[0]) + if ((retval = nc4_find_default_chunksizes2(grp, var))) + return retval; /* Adjust the cache. */ if ((retval = nc4_adjust_var_cache(grp, var))) - return retval; + return retval; } /* Are we setting a fill modes? */ @@ -999,19 +1136,53 @@ nc_def_var_extra(int ncid, int varid, int *shuffle, int *deflate, return NC_NOERR; } -/* Set the deflate level for a var, lower is faster, higher is - * better. Must be called after nc_def_var and before nc_enddef or any - * functions which writes data to the file. */ +/** + * @internal Set compression settings on a variable. This is called by + * nc_def_var_deflate(). + * + * @param ncid File ID. + * @param varid Variable ID. + * @param shuffle True to turn on the shuffle filter. + * @param deflate True to turn on deflation. + * @param deflate_level A number between 0 (no compression) and 9 + * (maximum compression). + * + * @returns ::NC_NOERR No error. + * @returns ::NC_EBADID Bad ncid. + * @returns ::NC_ENOTVAR Invalid variable ID. + * @returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is + * not netCDF-4/HDF5. + * @returns ::NC_ELATEDEF Too late to change settings for this variable. + * @returns ::NC_ENOTINDEFINE Not in define mode. + * @returns ::NC_EINVAL Invalid input + * @author Ed Hartnett, Dennis Heimbigner + */ int NC4_def_var_deflate(int ncid, int varid, int shuffle, int deflate, - int deflate_level) + int deflate_level) { return nc_def_var_extra(ncid, varid, &shuffle, &deflate, &deflate_level, NULL, NULL, NULL, NULL, NULL, NULL); } -/* Set checksum for a var. This must be called after the nc_def_var - * but before the nc_enddef. */ +/** + * @internal Set checksum on a variable. This is called by + * nc_def_var_fletcher32(). + * + * @param ncid File ID. + * @param varid Variable ID. + * @param fletcher32 Pointer to fletcher32 setting. + * + * @returns ::NC_NOERR No error. + * @returns ::NC_EBADID Bad ncid. + * @returns ::NC_ENOTVAR Invalid variable ID. + * @returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is + * not netCDF-4/HDF5. + * @returns ::NC_ELATEDEF Too late to change settings for this variable. + * @returns ::NC_ENOTINDEFINE Not in define mode. + * @returns ::NC_EINVAL Invalid input + * @author Ed Hartnett, Dennis Heimbigner + */ int NC4_def_var_fletcher32(int ncid, int varid, int fletcher32) { @@ -1019,15 +1190,28 @@ NC4_def_var_fletcher32(int ncid, int varid, int fletcher32) NULL, NULL, NULL, NULL, NULL); } -/* Define chunking stuff for a var. This must be done after nc_def_var - and before nc_enddef. - - Chunking is required in any dataset with one or more unlimited - dimensions in HDF5, or any dataset using a filter. - - Where chunksize is a pointer to an array of size ndims, with the - chunksize in each dimension. -*/ +/** + * @internal Define chunking stuff for a var. This is called by + * nc_def_var_chunking(). Chunking is required in any dataset with one + * or more unlimited dimensions in HDF5, or any dataset using a + * filter. + * + * @param ncid File ID. + * @param varid Variable ID. + * @param contiguous Pointer to contiguous setting. + * @param chunksizesp Array of chunksizes. + * + * @returns ::NC_NOERR No error. + * @returns ::NC_EBADID Bad ncid. + * @returns ::NC_ENOTVAR Invalid variable ID. + * @returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is + * not netCDF-4/HDF5. + * @returns ::NC_ELATEDEF Too late to change settings for this variable. + * @returns ::NC_ENOTINDEFINE Not in define mode. + * @returns ::NC_EINVAL Invalid input + * @returns ::NC_EBADCHUNK Bad chunksize. + * @author Ed Hartnett, Dennis Heimbigner + */ int NC4_def_var_chunking(int ncid, int varid, int contiguous, const size_t *chunksizesp) { @@ -1035,9 +1219,22 @@ NC4_def_var_chunking(int ncid, int varid, int contiguous, const size_t *chunksiz &contiguous, chunksizesp, NULL, NULL, NULL); } -/* Inquire about chunking stuff for a var. This is a private, - * undocumented function, used by the f77 API to avoid size_t - * problems. */ +/** + * @internal Inquire about chunking settings for a var. This is used + * by the fortran API. + * + * @param ncid File ID. + * @param varid Variable ID. + * @param contiguousp Gets contiguous setting. + * @param chunksizesp Gets chunksizes. + * + * @returns ::NC_NOERR No error. + * @returns ::NC_EBADID Bad ncid. + * @returns ::NC_ENOTVAR Invalid variable ID. + * @returns ::NC_EINVAL Invalid input + * @returns ::NC_ENOMEM Out of memory. + * @author Ed Hartnett + */ int nc_inq_var_chunking_ints(int ncid, int varid, int *contiguousp, int *chunksizesp) { @@ -1061,19 +1258,19 @@ nc_inq_var_chunking_ints(int ncid, int varid, int *contiguousp, int *chunksizesp /* Allocate space for the size_t copy of the chunksizes array. */ if (var->ndims) if (!(cs = malloc(var->ndims * sizeof(size_t)))) - return NC_ENOMEM; + return NC_ENOMEM; retval = NC4_inq_var_all(ncid, varid, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, contiguousp, cs, NULL, - NULL, NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, contiguousp, cs, NULL, + NULL, NULL, NULL, NULL, NULL); /* Copy from size_t array. */ - if (*contiguousp == NC_CHUNKED) + if (chunksizesp && var->contiguous == NC_CHUNKED) for (i = 0; i < var->ndims; i++) { - chunksizesp[i] = (int)cs[i]; - if (cs[i] > NC_MAX_INT) - retval = NC_ERANGE; + chunksizesp[i] = (int)cs[i]; + if (cs[i] > NC_MAX_INT) + retval = NC_ERANGE; } if (var->ndims) @@ -1081,10 +1278,26 @@ nc_inq_var_chunking_ints(int ncid, int varid, int *contiguousp, int *chunksizesp return retval; } -/* This function defines the chunking with ints, which works better - * with F77 portability. It is a secret function, which has been - * rendered unmappable, and it is impossible to apparate anywhere in - * this function. */ +/** + * @internal Define chunking stuff for a var. This is called by + * the fortran API. + * + * @param ncid File ID. + * @param varid Variable ID. + * @param contiguous Pointer to contiguous setting. + * @param chunksizesp Array of chunksizes. + * + * @returns ::NC_NOERR No error. + * @returns ::NC_EBADID Bad ncid. + * @returns ::NC_ENOTVAR Invalid variable ID. + * @returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is + * not netCDF-4/HDF5. + * @returns ::NC_ELATEDEF Too late to change settings for this variable. + * @returns ::NC_ENOTINDEFINE Not in define mode. + * @returns ::NC_EINVAL Invalid input + * @returns ::NC_EBADCHUNK Bad chunksize. + * @author Ed Hartnett + */ int nc_def_var_chunking_ints(int ncid, int varid, int contiguous, int *chunksizesp) { @@ -1102,7 +1315,7 @@ nc_def_var_chunking_ints(int ncid, int varid, int contiguous, int *chunksizesp) #ifdef USE_HDF4 if(h5->hdf4) - return NC_NOERR; + return NC_NOERR; #endif /* Find var cause I need the number of dims. */ @@ -1112,7 +1325,7 @@ nc_def_var_chunking_ints(int ncid, int varid, int contiguous, int *chunksizesp) /* Allocate space for the size_t copy of the chunksizes array. */ if (var->ndims) if (!(cs = malloc(var->ndims * sizeof(size_t)))) - return NC_ENOMEM; + return NC_ENOMEM; /* Copy to size_t array. */ for (i = 0; i < var->ndims; i++) @@ -1126,8 +1339,29 @@ nc_def_var_chunking_ints(int ncid, int varid, int contiguous, int *chunksizesp) return retval; } -/* Define fill value behavior for a variable. This must be done after - nc_def_var and before nc_enddef. */ +/** + * @internal This functions sets fill value and no_fill mode for a + * netCDF-4 variable. It is called by nc_def_var_fill(). + * + * @note All pointer parameters may be NULL, in which case they are ignored. + * @param ncid File ID. + * @param varid Variable ID. + * @param no_fill No_fill setting. + * @param fill_value Pointer to fill value. + * + * @returns ::NC_NOERR for success + * @returns ::NC_EBADID Bad ncid. + * @returns ::NC_ENOTVAR Invalid variable ID. + * @returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is + * not netCDF-4/HDF5. + * @returns ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3 + * netcdf-4 file. + * @returns ::NC_ELATEDEF Too late to change settings for this variable. + * @returns ::NC_ENOTINDEFINE Not in define mode. + * @returns ::NC_EPERM File is read only. + * @returns ::NC_EINVAL Invalid input + * @author Ed Hartnett + */ int NC4_def_var_fill(int ncid, int varid, int no_fill, const void *fill_value) { @@ -1135,8 +1369,28 @@ NC4_def_var_fill(int ncid, int varid, int no_fill, const void *fill_value) NULL, &no_fill, fill_value, NULL); } - -/* Define the endianness of a variable. */ +/** + * @internal This functions sets endianness for a netCDF-4 + * variable. Called by nc_def_var_endian(). + * + * @note All pointer parameters may be NULL, in which case they are ignored. + * @param ncid File ID. + * @param varid Variable ID. + * @param endianness Endianness setting. + * + * @returns ::NC_NOERR for success + * @returns ::NC_EBADID Bad ncid. + * @returns ::NC_ENOTVAR Invalid variable ID. + * @returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is + * not netCDF-4/HDF5. + * @returns ::NC_ESTRICTNC3 Attempting netcdf-4 operation on strict nc3 + * netcdf-4 file. + * @returns ::NC_ELATEDEF Too late to change settings for this variable. + * @returns ::NC_ENOTINDEFINE Not in define mode. + * @returns ::NC_EPERM File is read only. + * @returns ::NC_EINVAL Invalid input + * @author Ed Hartnett + */ int NC4_def_var_endian(int ncid, int varid, int endianness) { @@ -1144,8 +1398,28 @@ NC4_def_var_endian(int ncid, int varid, int endianness) NULL, NULL, NULL, &endianness); } +/** + * @internal Define filter settings. Called by nc_def_var_filter(). + * + * @param ncid File ID. + * @param varid Variable ID. + * @param id Filter ID + * @param nparams Number of parameters for filter. + * @param parms Filter parameters. + * + * @returns ::NC_NOERR for success + * @returns ::NC_EBADID Bad ncid. + * @returns ::NC_ENOTVAR Invalid variable ID. + * @returns ::NC_ENOTNC4 Attempting netcdf-4 operation on file that is + * not netCDF-4/HDF5. + * @returns ::NC_ELATEDEF Too late to change settings for this variable. + * @returns ::NC_EFILTER Filter error. + * @returns ::NC_EINVAL Invalid input + * @author Dennis Heimbigner + */ int -NC4_def_var_filter(int ncid, int varid, unsigned int id, size_t nparams, const unsigned int* parms) +NC4_def_var_filter(int ncid, int varid, unsigned int id, size_t nparams, + const unsigned int* parms) { int retval = NC_NOERR; NC *nc; @@ -1161,57 +1435,68 @@ NC4_def_var_filter(int ncid, int varid, unsigned int id, size_t nparams, const u assert(nc && grp && h5); - /* Find the var. */ - if (varid < 0 || varid >= grp->vars.nelems) - return NC_ENOTVAR; - var = grp->vars.value[varid]; - if (!var) return NC_ENOTVAR; - assert(var->varid == varid); + /* Find the var. */ + if (varid < 0 || varid >= grp->vars.nelems) + return NC_ENOTVAR; + var = grp->vars.value[varid]; + if (!var) return NC_ENOTVAR; + assert(var->varid == varid); /* Can't turn on parallel and filters */ if (nc->mode & (NC_MPIIO | NC_MPIPOSIX)) { - return NC_EINVAL; + return NC_EINVAL; } - /* If the HDF5 dataset has already been created, then it is too + /* If the HDF5 dataset has already been created, then it is too * late to set all the extra stuff. */ - if (var->created) + if (var->created) return NC_ELATEDEF; #ifdef HAVE_H5Z_SZIP - if(id == H5Z_FILTER_SZIP) { - if(nparams != 2) - return NC_EFILTER; /* incorrect no. of parameters */ - } + if(id == H5Z_FILTER_SZIP) { + if(nparams != 2) + return NC_EFILTER; /* incorrect no. of parameters */ + } #else /*!HAVE_H5Z_SZIP*/ - if(id == H5Z_FILTER_SZIP) - return NC_EFILTER; /* Not allowed */ + if(id == H5Z_FILTER_SZIP) + return NC_EFILTER; /* Not allowed */ #endif #if 0 { - unsigned int fcfg = 0; - herr_t herr = H5Zget_filter_info(id,&fcfg); - if(herr < 0) - return NC_EFILTER; - if((H5Z_FILTER_CONFIG_ENCODE_ENABLED & fcfg) == 0 - || (H5Z_FILTER_CONFIG_DECODE_ENABLED & fcfg) == 0) - return NC_EFILTER; - } + unsigned int fcfg = 0; + herr_t herr = H5Zget_filter_info(id,&fcfg); + if(herr < 0) + return NC_EFILTER; + if((H5Z_FILTER_CONFIG_ENCODE_ENABLED & fcfg) == 0 + || (H5Z_FILTER_CONFIG_DECODE_ENABLED & fcfg) == 0) + return NC_EFILTER; + } #endif /*0*/ - var->filterid = id; - var->nparams = nparams; - var->params = NULL; - if(parms != NULL) { - var->params = (unsigned int*)calloc(nparams,sizeof(unsigned int)); - if(var->params == NULL) return NC_ENOMEM; - memcpy(var->params,parms,sizeof(unsigned int)*var->nparams); - } - return NC_NOERR; + var->filterid = id; + var->nparams = nparams; + var->params = NULL; + if(parms != NULL) { + var->params = (unsigned int*)calloc(nparams,sizeof(unsigned int)); + if(var->params == NULL) return NC_ENOMEM; + memcpy(var->params,parms,sizeof(unsigned int)*var->nparams); + } + return NC_NOERR; } -/* Get var id from name. */ +/** + * @internal Find the ID of a variable, from the name. This function + * is called by nc_inq_varid(). + * + * @param ncid File ID. + * @param name Name of the variable. + * @param varidp Gets variable ID. + + * @returns ::NC_NOERR No error. + * @returns ::NC_EBADID Bad ncid. + * @returns ::NC_ENOTVAR Bad variable ID. + */ int NC4_inq_varid(int ncid, const char *name, int *varidp) { @@ -1222,7 +1507,7 @@ NC4_inq_varid(int ncid, const char *name, int *varidp) int retval; uint32_t nn_hash; int i; - + if (!name) return NC_EINVAL; if (!varidp) @@ -1242,22 +1527,35 @@ NC4_inq_varid(int ncid, const char *name, int *varidp) /* Find var of this name. */ for (i=0; i < grp->vars.nelems; i++) + { + var = grp->vars.value[i]; + if (!var) continue; + if (nn_hash == var->hash && !(strcmp(var->name, norm_name))) { - var = grp->vars.value[i]; - if (!var) continue; - if (nn_hash == var->hash && !(strcmp(var->name, norm_name))) - { - *varidp = var->varid; - return NC_NOERR; - } + *varidp = var->varid; + return NC_NOERR; } + } return NC_ENOTVAR; } -/* Rename a var to "bubba," for example. - - According to the netcdf-3.5 docs: If the new name is longer than - the old name, the netCDF dataset must be in define mode. */ +/** + * @internal Rename a var to "bubba," for example. This is called by + * nc_rename_var() for netCDF-4 files. + * + * @param ncid File ID. + * @param varid Variable ID + * @param name New name of the variable. + * + * @returns ::NC_NOERR No error. + * @returns ::NC_EBADID Bad ncid. + * @returns ::NC_ENOTVAR Invalid variable ID. + * @returns ::NC_EBADNAME Bad name. + * @returns ::NC_EMAXNAME Name is too long. + * @returns ::NC_ENAMEINUSE Name in use. + * @returns ::NC_ENOMEM Out of memory. + * @author Ed Hartnett +*/ int NC4_rename_var(int ncid, int varid, const char *name) { @@ -1345,26 +1643,43 @@ NC4_rename_var(int ncid, int varid, const char *name) NC_GRP_INFO_T *dim_grp; NC_DIM_INFO_T *dim; - /* Check to see if this is became a coordinate variable. If so, it - * will have the same name as dimension index 0. If it is a - * coordinate var, is it a coordinate var in the same group as the dim? - */ + /* Check to see if this is became a coordinate variable. If so, it + * will have the same name as dimension index 0. If it is a + * coordinate var, is it a coordinate var in the same group as the dim? + */ if ((retval = nc4_find_dim(grp, var->dimids[0], &dim, &dim_grp))) return retval; if (strcmp(dim->name, name) == 0 && dim_grp == grp) { - /* Reform the coordinate variable */ - if ((retval = nc4_reform_coord_var(grp, var, dim))) - return retval; + /* Reform the coordinate variable */ + if ((retval = nc4_reform_coord_var(grp, var, dim))) + return retval; } } } - exit: +exit: return retval; } - +/** + * @internal + * + * This function will change the parallel access of a variable from + * independent to collective. + * + * @param ncid File ID. + * @param varid Variable ID. + * @param par_access NC_COLLECTIVE or NC_INDEPENDENT. + * + * @returns ::NC_NOERR No error. + * @returns ::NC_EBADID Invalid ncid passed. + * @returns ::NC_ENOTVAR Invalid varid passed. + * @returns ::NC_ENOPAR LFile was not opened with nc_open_par/nc_create_var. + * @returns ::NC_EINVAL Invalid par_access specified. + * @returns ::NC_NOERR for success + * @author Ed Hartnett, Dennis Heimbigner + */ int NC4_var_par_access(int ncid, int varid, int par_access) { @@ -1393,7 +1708,7 @@ NC4_var_par_access(int ncid, int varid, int par_access) /* Find the var, and set its preference. */ if (varid < 0 || varid >= grp->vars.nelems) - return NC_ENOTVAR; + return NC_ENOTVAR; var = grp->vars.value[varid]; if (!var) return NC_ENOTVAR; assert(var->varid == varid); @@ -1406,26 +1721,23 @@ NC4_var_par_access(int ncid, int varid, int par_access) #endif /* USE_PARALLEL4 */ } -static int -nc4_put_vara_tc(int ncid, int varid, nc_type mem_type, int mem_type_is_long, - const size_t *startp, const size_t *countp, const void *op) -{ - NC *nc; - - LOG((2, "%s: ncid 0x%x varid %d mem_type %d mem_type_is_long %d", - __func__, ncid, varid, mem_type, mem_type_is_long)); - - if (!(nc = nc4_find_nc_file(ncid,NULL))) - return NC_EBADID; - - return nc4_put_vara(nc, ncid, varid, startp, countp, mem_type, - mem_type_is_long, (void *)op); -} - #ifdef USE_HDF4 +/** + * @internal Get data from an HDF4 SD dataset. + * + * @param ncid File ID. + * @param varid Variable ID. + * @param startp Array of start indicies. + * @param countp Array of counts. + * @param mem_nc_type The type of these data after it is read into memory. + * @param is_long Ignored for HDF4. + * @param data pointer that gets the data. + * @returns ::NC_NOERR for success + * @author Ed Hartnett + */ static int nc4_get_hdf4_vara(NC *nc, int ncid, int varid, const size_t *startp, - const size_t *countp, nc_type mem_nc_type, int is_long, void *data) + const size_t *countp, nc_type mem_nc_type, int is_long, void *data) { NC_GRP_INFO_T *grp; NC_HDF5_FILE_INFO_T *h5; @@ -1453,44 +1765,69 @@ nc4_get_hdf4_vara(NC *nc, int ncid, int varid, const size_t *startp, } #endif /* USE_HDF4 */ -/* Get an array. */ -static int -nc4_get_vara_tc(int ncid, int varid, nc_type mem_type, int mem_type_is_long, - const size_t *startp, const size_t *countp, void *ip) +/** + * @internal Write an array of data to a variable. This is called by + * nc_put_vara() and other nc_put_vara_* functions, for netCDF-4 + * files. + * + * @param ncid File ID. + * @param varid Variable ID. + * @param startp Array of start indicies. + * @param countp Array of counts. + * @param op pointer that gets the data. + * @param memtype The type of these data in memory. + * + * @returns ::NC_NOERR for success + * @author Ed Hartnett, Dennis Heimbigner + */ +int +NC4_put_vara(int ncid, int varid, const size_t *startp, + const size_t *countp, const void *op, int memtype) +{ + NC *nc; + + if (!(nc = nc4_find_nc_file(ncid, NULL))) + return NC_EBADID; + + return nc4_put_vara(nc, ncid, varid, startp, countp, memtype, 0, (void *)op); +} + +/** + * Read an array of values. This is called by nc_get_vara() for + * netCDF-4 files, as well as all the other nc_get_vara_* + * functions. HDF4 files are handled as a special case. + * + * @param ncid File ID. + * @param varid Variable ID. + * @param startp Array of start indicies. + * @param countp Array of counts. + * @param ip pointer that gets the data. + * @param memtype The type of these data after it is read into memory. + + * @returns ::NC_NOERR for success + * @author Ed Hartnett, Dennis Heimbigner + */ +int +NC4_get_vara(int ncid, int varid, const size_t *startp, + const size_t *countp, void *ip, int memtype) { NC *nc; NC_HDF5_FILE_INFO_T* h5; - LOG((2, "%s: ncid 0x%x varid %d mem_type %d mem_type_is_long %d", - __func__, ncid, varid, mem_type, mem_type_is_long)); + LOG((2, "%s: ncid 0x%x varid %d memtype %d", __func__, ncid, varid, + memtype)); - if (!(nc = nc4_find_nc_file(ncid,&h5))) + if (!(nc = nc4_find_nc_file(ncid, &h5))) return NC_EBADID; #ifdef USE_HDF4 /* Handle HDF4 cases. */ if (h5->hdf4) - return nc4_get_hdf4_vara(nc, ncid, varid, startp, countp, mem_type, - mem_type_is_long, (void *)ip); + return nc4_get_hdf4_vara(nc, ncid, varid, startp, countp, memtype, + 0, (void *)ip); #endif /* USE_HDF4 */ /* Handle HDF5 cases. */ - return nc4_get_vara(nc, ncid, varid, startp, countp, mem_type, - mem_type_is_long, (void *)ip); -} - -int -NC4_put_vara(int ncid, int varid, const size_t *startp, - const size_t *countp, const void *op, int memtype) -{ - return nc4_put_vara_tc(ncid, varid, memtype, 0, startp, countp, op); -} - - -/* Read an array of values. */ -int -NC4_get_vara(int ncid, int varid, const size_t *startp, - const size_t *countp, void *ip, int memtype) -{ - return nc4_get_vara_tc(ncid, varid, memtype, 0, startp, countp, ip); + return nc4_get_vara(nc, ncid, varid, startp, countp, memtype, + 0, (void *)ip); } diff --git a/libsrc4/ncfunc.c b/libsrc4/ncfunc.c index 0f7cd4c0f9..9e3b050614 100644 --- a/libsrc4/ncfunc.c +++ b/libsrc4/ncfunc.c @@ -1,30 +1,30 @@ -/* - Copyright 2003, University Corporation for Atmospheric Research. See - netcdf-4/docs/COPYRIGHT file for copying and redistribution - conditions. - - This file is part of netcdf-4, a netCDF-like interface for HDF5, or a - HDF5 backend for netCDF, depending on your point of view. - - This file handles the (useless) *_base_pe() functions, and the - inq_format functions. - - @author Ed Hartnett, Dennis Heimbigner - +/** + * @internal + * + * Copyright 2003, University Corporation for Atmospheric + * Research. See netcdf-4/docs/COPYRIGHT file for copying and + * redistribution conditions. + * + * This file is part of netcdf-4, a netCDF-like interface for HDF5, or a + * HDF5 backend for netCDF, depending on your point of view. + * + * This file handles the (useless) *_base_pe() functions, and the + * inq_format functions. + * + * @author Ed Hartnett, Dennis Heimbigner */ #include "nc4internal.h" #include "nc4dispatch.h" /** - * This function only does anything for netcdf-3 files. + * @internal This function only does anything for netcdf-3 files. * - * \param ncid File ID (ignored). - * \param pe Processor element (ignored). + * @param ncid File ID (ignored). + * @param pe Processor element (ignored). * - * \returns ::NC_ENOTNC3 Not a netCDF classic format file. - * \internal - * \author Ed Hartnett + * @return ::NC_ENOTNC3 Not a netCDF classic format file. + * @author Ed Hartnett */ int NC4_set_base_pe(int ncid, int pe) @@ -33,15 +33,14 @@ NC4_set_base_pe(int ncid, int pe) } /** - * This function only does anything for netcdf-3 files. + * @internal This function only does anything for netcdf-3 files. * - * \param ncid File ID (ignored). - * \param pe Pointer to processor element. Ignored if NULL. Gets a 0 + * @param ncid File ID (ignored). + * @param pe Pointer to processor element. Ignored if NULL. Gets a 0 * if present. * - * \returns ::NC_ENOTNC3 Not a netCDF classic format file. - * \internal - * \author Ed Hartnett + * @return ::NC_ENOTNC3 Not a netCDF classic format file. + * @author Ed Hartnett */ int NC4_inq_base_pe(int ncid, int *pe) @@ -50,16 +49,15 @@ NC4_inq_base_pe(int ncid, int *pe) } /** - * Get the format (i.e. NC_FORMAT_NETCDF4 pr + * @internal Get the format (i.e. NC_FORMAT_NETCDF4 pr * NC_FORMAT_NETCDF4_CLASSIC) of an open netCDF-4 file. * - * \param ncid File ID (ignored). - * \param formatp Pointer that gets the constant indicating format. + * @param ncid File ID (ignored). + * @param formatp Pointer that gets the constant indicating format. - * \returns ::NC_NOERR No error. - * \returns ::NC_EBADID Bad ncid. - * \internal - * \author Ed Hartnett + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Ed Hartnett */ int NC4_inq_format(int ncid, int *formatp) @@ -87,22 +85,21 @@ NC4_inq_format(int ncid, int *formatp) } /** - * Return the extended format (i.e. the dispatch model), plus the mode - * associated with an open file. + * @internal Return the extended format (i.e. the dispatch model), + * plus the mode associated with an open file. * - * \param ncid File ID (ignored). - * \param formatp a pointer that gets the extended format. Note that + * @param ncid File ID (ignored). + * @param formatp a pointer that gets the extended format. Note that * this is not the same as the format provided by nc_inq_format(). The * extended foramt indicates the dispatch layer model. NetCDF-4 files * will always get NC_FORMATX_NC4 for netCDF files, NC_FORMATX_HDF4 * for HDF4 files. - * \param modep a pointer that gets the open/create mode associated with + * @param modep a pointer that gets the open/create mode associated with * this file. Ignored if NULL. - * \returns ::NC_NOERR No error. - * \returns ::NC_EBADID Bad ncid. - * \internal - * \author Dennis Heimbigner + * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @author Dennis Heimbigner */ int NC4_inq_format_extended(int ncid, int *formatp, int *modep) diff --git a/libsrcp/Makefile.am b/libsrcp/Makefile.am index 9e59f0c3ef..291a51cb77 100644 --- a/libsrcp/Makefile.am +++ b/libsrcp/Makefile.am @@ -11,11 +11,6 @@ libnetcdfp_la_CPPFLAGS = ${AM_CPPFLAGS} # This is the code for a dispatch table for pnetcdf # (which has CDF5 as its magic number) -# Turn on a pre-processor flag when building a DLL for windows. -if BUILD_DLL -libnetcdfp_la_CPPFLAGS += -DDLL_EXPORT -endif # BUILD_DLL - # These files comprise the pnetcdf dispatch library code. libnetcdfp_la_SOURCES = ncpdispatch.c diff --git a/nc_test/tst_global_fillval.c b/nc_test/tst_global_fillval.c index b2bd99770b..b3de668bb8 100644 --- a/nc_test/tst_global_fillval.c +++ b/nc_test/tst_global_fillval.c @@ -9,55 +9,56 @@ * https://github.com/Unidata/netcdf-c/issues/388 * https://github.com/Unidata/netcdf-c/pull/389 -*/ + + Modified by Ed Hartnett, see: + https://github.com/Unidata/netcdf-c/issues/392 + */ #include "config.h" #include -#include -#include - -#ifdef USE_CDF5 -#define NUMFORMATS 5 -#else -#define NUMFORMATS 4 -#endif +#include "err_macros.h" #define FILE_NAME "tst_global_fillval.nc" -#define ERR {if(err!=NC_NOERR){printf("Error at line %d: %s\n",__LINE__,nc_strerror(err)); toterrs++; break;}} int main(int argc, char **argv) { - int i, ncid, cmode, err, fillv=9; - int toterrs = 0; - int formats[NUMFORMATS]={0, - NC_64BIT_OFFSET, + printf("*** testing proper elatefill return..."); + { + int num_formats = 2; + int n = 0; + int i; + + /* Determine how many formats are in use. */ #ifdef USE_CDF5 - NC_64BIT_DATA, + num_formats++; +#endif +#ifdef USE_NETCDF4 + num_formats += 2; #endif - NC_NETCDF4, - NC_CLASSIC_MODEL | NC_NETCDF4}; - char *formatnames[NUMFORMATS]={"CDF-1", - "CDF-2", + + int formats[num_formats]; + formats[n++] = 0; + formats[n++] = NC_64BIT_OFFSET; #ifdef USE_CDF5 - "CDF-5", + formats[n++] = NC_64BIT_DATA; +#endif +#ifdef USE_NETCDF4 + formats[n++] = NC_NETCDF4; + formats[n++] = NC_CLASSIC_MODEL | NC_NETCDF4; #endif - "NETCDF4", - "CLASSIC_MODEL"}; - - for (i=0; i @@ -56,6 +56,12 @@ main(int argc, char **argv) NC_COMPOUND_OFFSET(struct s1, i1), NC_INT)) ERR; if (nc_insert_compound(ncid, typeid, DATES_WITH_ALIENS, NC_COMPOUND_OFFSET(struct s1, i2), NC_INT)) ERR; + + /* This won't work due to bad typeid. */ + if (nc_def_var(ncid, SERVICE_RECORD, typeid + TEST_VAL_42, 0, NULL, + &varid) != NC_EBADTYPE) ERR; + + /* Define the variable. */ if (nc_def_var(ncid, SERVICE_RECORD, typeid, 0, NULL, &varid)) ERR; if (nc_put_var(ncid, varid, &data)) ERR; if (nc_close(ncid)) ERR; diff --git a/nc_test4/tst_files.c b/nc_test4/tst_files.c index ae934f0e7e..2d60c2411d 100644 --- a/nc_test4/tst_files.c +++ b/nc_test4/tst_files.c @@ -2,12 +2,11 @@ Copyright 2005 University Corporation for Atmospheric Research/Unidata See COPYRIGHT file for conditions of use. - Test internal netcdf-4 file code. - $Id: tst_files.c,v 1.42 2010/05/18 12:30:05 ed Exp $ + Test netcdf-4 file code. + Ed Hartnett */ #include -#include "netcdf.h" #include #include "err_macros.h" @@ -53,10 +52,14 @@ main(int argc, char **argv) if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR; if (nc_close(ncid)) ERR; + /* This will fail. */ if (nc_open(FILE_NAME, NC_MPIIO|NC_MPIPOSIX, &ncid) != NC_EINVAL) ERR; + /* These will all fail due to incorrect mode flag combinations. */ if (nc_create(FILE_NAME, NC_64BIT_OFFSET|NC_NETCDF4, &ncid) != NC_EINVAL) ERR; if (nc_create(FILE_NAME, NC_CLASSIC_MODEL|NC_MPIIO|NC_MPIPOSIX, &ncid) != NC_EINVAL) ERR; + if (nc_create(FILE_NAME, NC_64BIT_OFFSET|NC_CDF5, &ncid) != NC_EINVAL) ERR; + if (nc_create(FILE_NAME, NC_NETCDF4|NC_CDF5, &ncid) != NC_EINVAL) ERR; if (nc_create(FILE_NAME, NC_MPIIO|NC_MPIPOSIX, &ncid) != NC_EINVAL) ERR; } SUMMARIZE_ERR; diff --git a/nc_test4/tst_vars.c b/nc_test4/tst_vars.c index 33cb02c203..70883d4651 100644 --- a/nc_test4/tst_vars.c +++ b/nc_test4/tst_vars.c @@ -3,7 +3,7 @@ See COPYRIGHT file for conditions of use. Test netcdf-4 variables. - $Id: tst_vars.c,v 1.49 2009/12/30 12:03:48 ed Exp $ + Ed Hartnett, Ward Fisher */ #include "nc_tests.h" @@ -184,6 +184,12 @@ create_4D_example(char *file_name, int cmode) for (rec = 0; rec < NREC; rec++) { start[0] = rec; + + /* This won't work due to bad id. */ + if (nc_put_vara_float(ncid + MILLION, pres_varid, start, count, + &pres_out[0][0][0]) != NC_EBADID) ERR; + + /* Now write the data. */ if (nc_put_vara_float(ncid, pres_varid, start, count, &pres_out[0][0][0])) ERR; if (nc_put_vara_float(ncid, temp_varid, start, count, @@ -335,11 +341,33 @@ main(int argc, char **argv) printf("*** testing simple variables..."); { + int bad_dimids[3] = {1, 2, 5}; /* "Three sir!" */ + /* Create a file with a variable of each type. */ if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR; if (nc_def_dim(ncid, DIM1_NAME, DIM1_LEN, &dimids[0])) ERR; if (nc_def_dim(ncid, DIM2_NAME, DIM2_LEN, &dimids[1])) ERR; if (nc_def_dim(ncid, DIM3_NAME, DIM3_LEN, &dimids[2])) ERR; + + /* These attempts will fail due to bad paramters. */ + if (nc_def_var(ncid + MILLION, VAR_BYTE_NAME, NC_BYTE, 2, dimids, + &byte_varid) != NC_EBADID) ERR; + if (nc_def_var(ncid + TEST_VAL_42, VAR_BYTE_NAME, NC_BYTE, 2, dimids, + &byte_varid) != NC_EBADID) ERR; + if (nc_def_var(ncid, BAD_NAME, NC_BYTE, 2, dimids, + &byte_varid) != NC_EBADNAME) ERR; + if (nc_def_var(ncid, VAR_BYTE_NAME, 0, 2, dimids, + &byte_varid) != NC_EBADTYPE) ERR; + if (nc_def_var(ncid, VAR_BYTE_NAME, TEST_VAL_42, 2, dimids, + &byte_varid) != NC_EBADTYPE) ERR; + if (nc_def_var(ncid, VAR_BYTE_NAME, NC_BYTE, -2, dimids, + &byte_varid) != NC_EINVAL) ERR; + if (nc_def_var(ncid, VAR_BYTE_NAME, NC_BYTE, 2, NULL, + &byte_varid) != NC_EINVAL) ERR; + if (nc_def_var(ncid, VAR_BYTE_NAME, NC_BYTE, 3, bad_dimids, + &byte_varid) != NC_EBADDIM) ERR; + + /* Now create our variables. */ if (nc_def_var(ncid, VAR_BYTE_NAME, NC_BYTE, 2, dimids, &byte_varid)) ERR; if (nc_def_var(ncid, VAR_CHAR_NAME, NC_CHAR, 3, dimids, &char_varid)) ERR; if (nc_def_var(ncid, VAR_SHORT_NAME, NC_SHORT, 2, dimids, &short_varid)) ERR; @@ -826,6 +854,10 @@ main(int argc, char **argv) /* Open the file and check the same stuff. */ if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR; + /* Can't define a var! */ + if (nc_def_var(ncid, "this_wont_work", NC_INT, NDIMS4, dimids, &varid) + != NC_EPERM) ERR; + if (nc_inq(ncid, &ndims, &nvars, &natts, &unlimdimid)) ERR; if (ndims != NDIMS4 || nvars != NVARS4 || natts != 0 || unlimdimid != -1) ERR; diff --git a/nc_test4/tst_vars2.c b/nc_test4/tst_vars2.c index 3fbd431d27..91769fe2e0 100644 --- a/nc_test4/tst_vars2.c +++ b/nc_test4/tst_vars2.c @@ -3,15 +3,17 @@ See COPYRIGHT file for conditions of use. Test netcdf-4 variables. - $Id: tst_vars2.c,v 1.35 2010/01/25 21:01:08 ed Exp $ + Ed Hartnett */ #include #include "err_macros.h" #include "netcdf.h" +#include "netcdf_f.h" #define FILE_NAME "tst_vars2.nc" #define NUM_DIMS 1 +#define NUM_VARS 3 #define DIM1_LEN NC_UNLIMITED #define DIM1_NAME "Hoplites_Engaged" #define VAR_NAME "Battle_of_Marathon" @@ -24,13 +26,18 @@ main(int argc, char **argv) { int ncid, dimids[NUM_DIMS]; int varid; - int nvars_in, varids_in[NUM_DIMS]; + int nvars_in, varids_in[NUM_VARS]; signed char fill_value = 42, fill_value_in; nc_type xtype_in; size_t len_in; char name_in[NC_MAX_NAME + 1]; int attnum_in; int cnum; + char too_long_name[NC_MAX_NAME + 2]; + + /* Set up a name that is too long for netCDF. */ + memset(too_long_name, 'a', NC_MAX_NAME + 1); + too_long_name[NC_MAX_NAME + 1] = 0; printf("\n*** Testing netcdf-4 variable functions, even more.\n"); for (cnum = 0; cnum < MAX_CNUM; cnum++) @@ -123,6 +130,9 @@ main(int argc, char **argv) /* Open the file and check. */ if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR; + /* This will not work because file was opened read-only. */ + if (nc_rename_var(ncid, 0, "something_very_new") != NC_EPERM) ERR; + /* Check metadata. */ if (nc_inq_varids(ncid, &nvars_in, varids_in)) ERR; if (nvars_in != 1 || varids_in[0] != 0) ERR; @@ -404,6 +414,17 @@ main(int argc, char **argv) if (nc_def_dim(ncid, DIMNAME, 1, &dimid)) ERR; if (nc_enddef(ncid)) ERR; if (nc_redef(ncid)) ERR; + + /* Check that these netCDF-4 things will fail on this classic + * model file. */ + if (nc_def_var(ncid, DIMNAME, NC_UINT, 1, &dimid, &xvarid) != NC_ESTRICTNC3) ERR; + if (nc_def_var(ncid, DIMNAME, NC_INT, NC_MAX_VAR_DIMS + 1, &dimid, + &xvarid) != NC_EMAXDIMS) ERR; + if (nc_enddef(ncid)) ERR; + if (nc_def_var(ncid, DIMNAME, NC_INT, 1, &dimid, &xvarid) != NC_ENOTINDEFINE) ERR; + if (nc_redef(ncid)) ERR; + + /* Define the variable for the test. */ if (nc_def_var(ncid, DIMNAME, NC_INT, 1, &dimid, &xvarid)) ERR; if (nc_put_att_text(ncid, xvarid, UNITS, strlen(units), units)) ERR; if (nc_def_var(ncid, VARNAME, NC_INT, 1, &dimid, &varid)) ERR; @@ -439,6 +460,12 @@ main(int argc, char **argv) if (nc_close(ncid)) ERR; if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR; + + /* These won't work. */ + if (nc_rename_var(ncid + TEST_VAL_42, 0, "az") != NC_EBADID) ERR; + if (nc_rename_var(ncid + MILLION, 0, "az") != NC_EBADID) ERR; + + /* Rename the var. */ if (nc_rename_var(ncid, 0, "az")) ERR; if (nc_close(ncid)) ERR; } @@ -446,12 +473,13 @@ main(int argc, char **argv) SUMMARIZE_ERR; printf("**** testing dimension and variable renaming..."); { - /* This test contributed by Jeff Whitaker of NOAA - Thanks Jeff! */ - int ncid, lat_dim, time_dim, lon_dim, wind_id; + /* This test based on code contributed by Jeff Whitaker of NOAA + * - Thanks Jeff! */ + int ncid, lat_dim, time_dim, lon_dim, wind_id, temp2_id; size_t lat_len = 73, time_len = 10, lon_len = 145; int wind_dims[RANK_wind], wind_slobber[1], cdf_goober[1]; - if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR; + if (nc_create(FILE_NAME, NC_NETCDF4|NC_CLASSIC_MODEL, &ncid)) ERR; /* define dimensions */ if (nc_def_dim(ncid, "lon", lon_len, &lon_dim)) ERR; @@ -465,6 +493,7 @@ main(int argc, char **argv) /* define variables */ wind_dims[0] = lon_dim; if (nc_def_var(ncid, "temp", NC_FLOAT, RANK_wind, wind_dims, &wind_id)) ERR; + if (nc_def_var(ncid, "temp2", NC_FLOAT, RANK_wind, wind_dims, &temp2_id)) ERR; if (nc_put_att_text(ncid, wind_id, "bar", 3, "foo")) ERR; wind_slobber[0] = 3; @@ -475,13 +504,58 @@ main(int argc, char **argv) if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR; if (nc_inq_dimid(ncid, "lon", &lon_dim)) ERR; + /* THese won't work due to bad params. */ + if (nc_rename_dim(ncid + MILLION, lon_dim, "longitude") != NC_EBADID) ERR; + if (nc_rename_dim(ncid + TEST_VAL_42, lon_dim, "longitude") != NC_EBADID) ERR; + /* rename dimension */ if (nc_rename_dim(ncid, lon_dim, "longitude")) ERR; + + /* These will fail due to bad params. */ + if (nc_inq_varid(ncid + MILLION, "temp", &wind_id) != NC_EBADID) ERR; + if (nc_inq_varid(ncid + TEST_VAL_42, "temp", &wind_id) != NC_EBADID) ERR; + if (nc_inq_varid(ncid, NULL, &wind_id) != NC_EINVAL) ERR; + if (nc_inq_varid(ncid, "not_a_real_name", &wind_id) != NC_ENOTVAR) ERR; + if (nc_inq_varid(ncid, BAD_NAME, &wind_id) != NC_ENOTVAR) ERR; + if (nc_inq_varid(ncid, too_long_name, &wind_id) != NC_EMAXNAME) ERR; + + /* Now get the variable ID. */ if (nc_inq_varid(ncid, "temp", &wind_id)) ERR; + /* THis also works, pointlessly. */ + if (nc_inq_varid(ncid, "temp", NULL)) ERR; + + /* These won't work due to bad paramters. */ + if (nc_rename_var(ncid + MILLION, wind_id, "wind") != NC_EBADID) ERR; + if (nc_rename_var(ncid, wind_id + TEST_VAL_42, "wind") != NC_ENOTVAR) ERR; + if (nc_rename_var(ncid, -TEST_VAL_42, "wind") != NC_ENOTVAR) ERR; + if (nc_rename_var(ncid, wind_id, BAD_NAME) != NC_EBADNAME) ERR; + if (nc_rename_var(ncid, wind_id, too_long_name) != NC_EMAXNAME) ERR; + if (nc_rename_var(ncid, wind_id, "temp2") != NC_ENAMEINUSE) ERR; + if (nc_rename_var(ncid, wind_id, "windy") != NC_ENOTINDEFINE) ERR; + /* rename variable */ if (nc_rename_var(ncid, wind_id, "wind")) ERR; + + /* Enter define mode and rename it to something longer. */ + if (nc_redef(ncid)) ERR; + if (nc_rename_var(ncid, wind_id, "windy")) ERR; + if (nc_inq_varid(ncid, "windy", &wind_id)) ERR; if (nc_close(ncid)) ERR; + + /* Try again without classic. */ + if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR; + + /* define dimension */ + if (nc_def_dim(ncid, "lon", lon_len, &lon_dim)) ERR; + + /* define variable */ + wind_dims[0] = lon_dim; + if (nc_def_var(ncid, "temp", NC_FLOAT, RANK_wind, wind_dims, &wind_id)) ERR; + if (nc_enddef(ncid)) ERR; + if (nc_rename_var(ncid, wind_id, "windy")) ERR; + if (nc_close(ncid)) ERR; + } SUMMARIZE_ERR; @@ -592,7 +666,7 @@ main(int argc, char **argv) #define DIM4_LEN 10 { int dimids[NDIMS4], dimids_in[NDIMS4]; - int varid; + int varid, varid1; int ndims, nvars, natts, unlimdimid; nc_type xtype_in; char name_in[NC_MAX_NAME + 1]; @@ -619,17 +693,39 @@ main(int argc, char **argv) if (nc_inq_varids(ncid, &nvars, varids_in)) ERR; if (nvars != 1) ERR; if (varids_in[0] != 0) ERR; + + /* Test some bad parameter values. */ + if (nc_inq_var(ncid + MILLION, 0, name_in, &xtype_in, &ndims, + dimids_in, &natts) != NC_EBADID) ERR; + if (nc_inq_var(ncid + TEST_VAL_42, 0, name_in, &xtype_in, &ndims, + dimids_in, &natts) != NC_EBADID) ERR; + if (nc_inq_var(ncid, -TEST_VAL_42, name_in, &xtype_in, &ndims, + dimids_in, &natts) != NC_ENOTVAR) ERR; + if (nc_inq_var(ncid, 1, name_in, &xtype_in, &ndims, + dimids_in, &natts) != NC_ENOTVAR) ERR; + if (nc_inq_var(ncid, TEST_VAL_42, name_in, &xtype_in, &ndims, + dimids_in, &natts) != NC_ENOTVAR) ERR; + + /* Now pass correct parameters. */ if (nc_inq_var(ncid, 0, name_in, &xtype_in, &ndims, dimids_in, &natts)) ERR; if (strcmp(name_in, VAR_NAME4) || xtype_in != NC_INT || ndims != 1 || natts != 0 || dimids_in[0] != 0) ERR; if (nc_inq_var_endian(ncid, 0, &endian_in)) ERR; if (endian_in != NC_ENDIAN_BIG) ERR; + + /* This also works, uselessly. */ + if (nc_inq_var(ncid, 0, name_in, NULL, NULL, NULL, NULL)) ERR; + if (nc_close(ncid)) ERR; /* Open the file and check the same stuff. */ if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR; + /* This won't work. */ + if (nc_def_var(ncid, "this_wont_work", NC_BYTE, NDIMS4, dimids, + &varid1) != NC_EPERM) ERR; + if (nc_inq(ncid, &ndims, &nvars, &natts, &unlimdimid)) ERR; if (ndims != NDIMS4 || nvars != 1 || natts != 0 || unlimdimid != -1) ERR; @@ -655,22 +751,34 @@ main(int argc, char **argv) #define NDIMS5 1 #define DIM5_NAME "D5" #define VAR_NAME5 "V5" +#define VAR_NAME5_1 "V5_1" +#define VAR_NAME5_2 "V5_2" #define DIM5_LEN 1000 #define CACHE_SIZE 32000000 #define CACHE_NELEMS 1009 #define CACHE_PREEMPTION .75 +#define CACHE_SIZE2 64000000 +#define CACHE_NELEMS2 2000 +#define CACHE_PREEMPTION2 .50 int dimids[NDIMS5], dimids_in[NDIMS5]; - int varid; + int varid, varid1, varid2; int ndims, nvars, natts, unlimdimid; nc_type xtype_in; char name_in[NC_MAX_NAME + 1]; int data[DIM5_LEN], data_in[DIM5_LEN]; size_t chunksize[NDIMS5] = {5}; + size_t bad_chunksize[NDIMS5] = {-5}; size_t chunksize_in[NDIMS5]; + int chunksize_int[NDIMS5]; + int chunksize_int_in[NDIMS5]; int storage_in; size_t cache_size_in, cache_nelems_in; float cache_preemption_in; + int cache_size_int_in, cache_nelems_int_in; + int cache_preemption_int_in; + int cache_size_int_default, cache_nelems_int_default; + int cache_preemption_int_default; int i, d; for (i = 0; i < DIM5_LEN; i++) @@ -680,8 +788,45 @@ main(int argc, char **argv) if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR; if (nc_def_dim(ncid, DIM5_NAME, DIM5_LEN, &dimids[0])) ERR; if (dimids[0] != 0) ERR; + + /* Define the variable. */ if (nc_def_var(ncid, VAR_NAME5, NC_INT, NDIMS5, dimids, &varid)) ERR; + + /* These will fail due to bad parameters. */ + if (nc_def_var_chunking(ncid + MILLION, varid, NC_CHUNKED, + chunksize) != NC_EBADID) ERR; + if (nc_def_var_chunking(ncid + TEST_VAL_42, varid, NC_CHUNKED, + chunksize) != NC_EBADID) ERR; + if (nc_def_var_chunking(ncid, varid + TEST_VAL_42, NC_CHUNKED, + chunksize) != NC_ENOTVAR) ERR; + if (nc_def_var_chunking(ncid, varid + 1, NC_CHUNKED, + chunksize) != NC_ENOTVAR) ERR; + if (nc_def_var_chunking(ncid, -1, NC_CHUNKED, + chunksize) != NC_ENOTVAR) ERR; + if (nc_def_var_chunking(ncid, varid, NC_CHUNKED, bad_chunksize) != + NC_EBADCHUNK) ERR; + + /* Define the chunking. */ if (nc_def_var_chunking(ncid, varid, NC_CHUNKED, chunksize)) ERR; + + /* Try to set var cache with bad parameters. They will be + * rejected. */ + if (nc_set_var_chunk_cache(ncid + MILLION, varid, CACHE_SIZE, CACHE_NELEMS, + CACHE_PREEMPTION) != NC_EBADID) ERR; + if (nc_set_var_chunk_cache(ncid + 1, varid, CACHE_SIZE, CACHE_NELEMS, + CACHE_PREEMPTION) != NC_EBADID) ERR; + if (nc_set_var_chunk_cache(ncid, varid + TEST_VAL_42, CACHE_SIZE, CACHE_NELEMS, + CACHE_PREEMPTION) != NC_ENOTVAR) ERR; + if (nc_set_var_chunk_cache(ncid, -TEST_VAL_42, CACHE_SIZE, CACHE_NELEMS, + CACHE_PREEMPTION) != NC_ENOTVAR) ERR; + if (nc_set_var_chunk_cache(ncid, varid + 1, CACHE_SIZE, CACHE_NELEMS, + CACHE_PREEMPTION) != NC_ENOTVAR) ERR; + if (nc_set_var_chunk_cache(ncid, varid, CACHE_SIZE, CACHE_NELEMS, + CACHE_PREEMPTION + TEST_VAL_42) != NC_EINVAL) ERR; + if (nc_set_var_chunk_cache(ncid, varid, CACHE_SIZE, CACHE_NELEMS, + CACHE_PREEMPTION - TEST_VAL_42) != NC_EINVAL) ERR; + + /* Set the cache. */ if (nc_set_var_chunk_cache(ncid, varid, CACHE_SIZE, CACHE_NELEMS, CACHE_PREEMPTION)) ERR; if (nc_put_var_int(ncid, varid, data)) ERR; @@ -703,10 +848,80 @@ main(int argc, char **argv) for (i = 0; i < DIM5_LEN; i++) if (data[i] != data_in[i]) ERR_RET; + + /* These will not work due to bad paramters. */ + if (nc_inq_var_chunking_ints(ncid + MILLION, 0, &storage_in, + chunksize_int_in) != NC_EBADID) ERR; + if (nc_inq_var_chunking_ints(ncid + TEST_VAL_42, 0, &storage_in, + chunksize_int_in) != NC_EBADID) ERR; + if (nc_inq_var_chunking_ints(ncid, -1, &storage_in, + chunksize_int_in) != NC_ENOTVAR) ERR; + if (nc_inq_var_chunking_ints(ncid, varid + 1, &storage_in, + chunksize_int_in) != NC_ENOTVAR) ERR; + if (nc_inq_var_chunking_ints(ncid, varid + TEST_VAL_42, &storage_in, + chunksize_int_in) != NC_ENOTVAR) ERR; + + /* Now check with the fortran versions of the var_chunking. */ + if (nc_inq_var_chunking_ints(ncid, 0, &storage_in, chunksize_int_in)) ERR; + for (d = 0; d < NDIMS5; d++) + if (chunksize_int_in[d] != chunksize[d]) ERR; + for (d = 0; d < NDIMS5; d++) + chunksize_int[d] = chunksize[d] * 2; + + /* Check that some bad parameter values are rejected properly. */ + if (nc_def_var_chunking_ints(ncid + MILLION, varid, NC_CHUNKED, + chunksize_int) != NC_EBADID) ERR; + if (nc_def_var_chunking_ints(ncid + TEST_VAL_42, varid, NC_CHUNKED, + chunksize_int) != NC_EBADID) ERR; + if (nc_def_var_chunking_ints(ncid, -1, NC_CHUNKED, + chunksize_int) != NC_ENOTVAR) ERR; + if (nc_def_var_chunking_ints(ncid, varid + 1, NC_CHUNKED, + chunksize_int) != NC_ENOTVAR) ERR; + if (nc_def_var_chunking_ints(ncid, varid + TEST_VAL_42, NC_CHUNKED, + chunksize_int) != NC_ENOTVAR) ERR; + + if (nc_def_var_chunking_ints(ncid, varid, NC_CHUNKED, chunksize_int) != NC_ELATEDEF) ERR; + if (nc_redef(ncid)) ERR; + if (nc_def_var(ncid, VAR_NAME5_1, NC_INT, NDIMS5, dimids, &varid1)) ERR; + if (nc_def_var(ncid, VAR_NAME5_2, NC_INT, 0, NULL, &varid2)) ERR; + if (nc_def_var_chunking(ncid, varid2, NC_CHUNKED, chunksize)) ERR; + if (nc_def_var_chunking_ints(ncid, varid2, NC_CHUNKED, chunksize_int)) ERR; + if (nc_def_var_chunking_ints(ncid, varid1, NC_CHUNKED, chunksize_int)) ERR; + if (nc_inq_var_chunking_ints(ncid, varid2, NC_CHUNKED, chunksize_int_in)) ERR; + if (nc_inq_var_chunking_ints(ncid, varid1, NULL, chunksize_int_in)) ERR; + for (d = 0; d < NDIMS5; d++) + if (chunksize_int_in[d] != chunksize[d] * 2) ERR; + if (nc_inq_var_chunking_ints(ncid, varid1, NULL, NULL)) ERR; + + /* Check that some bad parameter values are rejected properly. */ + if (nc_get_var_chunk_cache(ncid + MILLION, varid, &cache_size_in, &cache_nelems_in, + &cache_preemption_in) != NC_EBADID) ERR; + if (nc_get_var_chunk_cache(ncid + 1, -TEST_VAL_42, &cache_size_in, &cache_nelems_in, + &cache_preemption_in) != NC_EBADID) ERR; + if (nc_get_var_chunk_cache(ncid, varid + TEST_VAL_42, &cache_size_in, &cache_nelems_in, + &cache_preemption_in) != NC_ENOTVAR) ERR; + if (nc_get_var_chunk_cache(ncid, varid2 + 1, &cache_size_in, &cache_nelems_in, + &cache_preemption_in) != NC_ENOTVAR) ERR; + if (nc_get_var_chunk_cache(ncid, -TEST_VAL_42, &cache_size_in, &cache_nelems_in, + &cache_preemption_in) != NC_ENOTVAR) ERR; + + /* Get the var chunk cache settings. */ if (nc_get_var_chunk_cache(ncid, varid, &cache_size_in, &cache_nelems_in, &cache_preemption_in)) ERR; if (cache_size_in != CACHE_SIZE || cache_nelems_in != CACHE_NELEMS || cache_preemption_in != CACHE_PREEMPTION) ERR; + /* THis should also work, pointlessly. */ + if (nc_get_var_chunk_cache(ncid, varid, NULL, NULL, NULL)) ERR; + + /* Check the _int version of this function, used by the F77 API. */ + if (nc_get_var_chunk_cache_ints(ncid, varid, &cache_size_int_in, &cache_nelems_int_in, + &cache_preemption_int_in)) ERR; + if (cache_size_int_in != CACHE_SIZE / MEGABYTE) ERR; + if (cache_nelems_int_in != CACHE_NELEMS) ERR; + if (cache_preemption_int_in != (int)(CACHE_PREEMPTION * 100)) ERR; + /* THis should also work, pointlessly. */ + if (nc_get_var_chunk_cache_ints(ncid, varid, NULL, NULL, NULL)) ERR; + if (nc_close(ncid)) ERR; /* Open the file and check the same stuff. */ @@ -714,11 +929,11 @@ main(int argc, char **argv) /* Check stuff. */ if (nc_inq(ncid, &ndims, &nvars, &natts, &unlimdimid)) ERR; - if (ndims != NDIMS5 || nvars != 1 || natts != 0 || + if (ndims != NDIMS5 || nvars != NUM_VARS || natts != 0 || unlimdimid != -1) ERR; if (nc_inq_varids(ncid, &nvars, varids_in)) ERR; - if (nvars != 1) ERR; - if (varids_in[0] != 0) ERR; + if (nvars != NUM_VARS) ERR; + if (varids_in[0] != 0 || varids_in[1] != 1) ERR; if (nc_inq_var(ncid, 0, name_in, &xtype_in, &ndims, dimids_in, &natts)) ERR; if (strcmp(name_in, VAR_NAME5) || xtype_in != NC_INT || ndims != 1 || natts != 0 || dimids_in[0] != 0) ERR; @@ -726,6 +941,139 @@ main(int argc, char **argv) for (d = 0; d < NDIMS5; d++) if (chunksize[d] != chunksize_in[d]) ERR; if (storage_in != NC_CHUNKED) ERR; + if (nc_get_var_int(ncid, varid, data_in)) ERR; + for (i = 0; i < DIM5_LEN; i++) + if (data[i] != data_in[i]) + ERR_RET; + + /* Use the _int function to change the var chunk cache settings. */ + if (nc_set_var_chunk_cache_ints(ncid, varid, CACHE_SIZE2 / MEGABYTE, CACHE_NELEMS2, + (int)(CACHE_PREEMPTION2 * 100))) ERR; + + /* These will fail due to bad ncid and group ID. */ + if (nc_get_var_chunk_cache_ints(ncid + MILLION, varid, &cache_size_int_in, &cache_nelems_int_in, + &cache_preemption_int_in) != NC_EBADID) ERR; + if (nc_get_var_chunk_cache_ints(ncid + TEST_VAL_42, varid, &cache_size_int_in, &cache_nelems_int_in, + &cache_preemption_int_in) != NC_EBADID) ERR; + + /* Now get the settings. */ + if (nc_get_var_chunk_cache_ints(ncid, varid, &cache_size_int_in, &cache_nelems_int_in, + &cache_preemption_int_in)) ERR; + if (cache_size_int_in != CACHE_SIZE2 / MEGABYTE || cache_nelems_int_in != CACHE_NELEMS2 || + cache_preemption_int_in != (int)(CACHE_PREEMPTION2 * 100)) ERR; + + /* Passing negative values to the _int function causes them to + * be ignored and a default setting used. Set all to negative to + * get defaults.. */ + if (nc_set_var_chunk_cache_ints(ncid, varid, -CACHE_SIZE / MEGABYTE, -CACHE_NELEMS2, + -(int)(CACHE_PREEMPTION2 * 100))) ERR; + if (nc_get_var_chunk_cache_ints(ncid, varid, &cache_size_int_default, &cache_nelems_int_default, + &cache_preemption_int_default)) ERR; + + /* Now set the size only. */ + if (nc_set_var_chunk_cache_ints(ncid, varid, CACHE_SIZE / MEGABYTE, -CACHE_NELEMS2, + -(int)(CACHE_PREEMPTION2 * 100))) ERR; + if (nc_get_var_chunk_cache_ints(ncid, varid, &cache_size_int_in, &cache_nelems_int_in, + &cache_preemption_int_in)) ERR; + if (cache_size_int_in != CACHE_SIZE / MEGABYTE || cache_nelems_int_in != cache_nelems_int_default || + cache_preemption_int_in != cache_preemption_int_default) ERR; + /* Now set the nelems only. */ + if (nc_set_var_chunk_cache_ints(ncid, varid, -CACHE_SIZE / MEGABYTE, CACHE_NELEMS, + -(int)(CACHE_PREEMPTION2 * 100))) ERR; + if (nc_get_var_chunk_cache_ints(ncid, varid, &cache_size_int_in, &cache_nelems_int_in, + &cache_preemption_int_in)) ERR; + if (cache_size_int_in != cache_size_int_default || cache_nelems_int_in != CACHE_NELEMS || + cache_preemption_int_in != cache_preemption_int_default) ERR; + /* Now set the preemption only. */ + if (nc_set_var_chunk_cache_ints(ncid, varid, -CACHE_SIZE / MEGABYTE, -CACHE_NELEMS, + (int)(CACHE_PREEMPTION2 * 100))) ERR; + if (nc_get_var_chunk_cache_ints(ncid, varid, &cache_size_int_in, &cache_nelems_int_in, + &cache_preemption_int_in)) ERR; + if (cache_size_int_in != cache_size_int_default || cache_nelems_int_in != cache_nelems_int_default || + cache_preemption_int_in != (int)(CACHE_PREEMPTION2 * 100)) ERR; + + if (nc_close(ncid)) ERR; + } + + SUMMARIZE_ERR; + printf("**** testing netCDF-4 functions on netCDF-3 files..."); + { + int dimids[NDIMS5], dimids_in[NDIMS5]; + int varid; + int ndims, nvars, natts, unlimdimid; + nc_type xtype_in; + char name_in[NC_MAX_NAME + 1]; + int data[DIM5_LEN], data_in[DIM5_LEN]; + size_t chunksize[NDIMS5] = {5}; + size_t chunksize_in[NDIMS5]; + int storage_in; + size_t cache_size_in, cache_nelems_in; + float cache_preemption_in; + int i; + + for (i = 0; i < DIM5_LEN; i++) + data[i] = i; + + /* Create a netcdf classic file with one dim and one var. */ + if (nc_create(FILE_NAME, 0, &ncid)) ERR; + if (nc_def_dim(ncid, DIM5_NAME, DIM5_LEN, &dimids[0])) ERR; + if (dimids[0] != 0) ERR; + if (nc_def_var(ncid, VAR_NAME5, NC_INT, NDIMS5, dimids, &varid)) ERR; + + /* These will return error. */ + if (nc_def_var_chunking(ncid, varid, NC_CHUNKED, chunksize) != NC_ENOTNC4) ERR; + if (nc_set_var_chunk_cache(ncid, varid, CACHE_SIZE, CACHE_NELEMS, + CACHE_PREEMPTION) != NC_ENOTNC4) ERR; + + if (nc_enddef(ncid)) ERR; + if (nc_put_var_int(ncid, varid, data)) ERR; + + /* Check stuff. */ + if (nc_inq(ncid, &ndims, &nvars, &natts, &unlimdimid)) ERR; + if (ndims != NDIMS5 || nvars != 1 || natts != 0 || + unlimdimid != -1) ERR; + if (nc_inq_varids(ncid, &nvars, varids_in)) ERR; + if (nvars != 1) ERR; + if (varids_in[0] != 0) ERR; + if (nc_inq_var(ncid, 0, name_in, &xtype_in, &ndims, dimids_in, &natts)) ERR; + if (strcmp(name_in, VAR_NAME5) || xtype_in != NC_INT || ndims != 1 || natts != 0 || + dimids_in[0] != 0) ERR; + + /* This call fails. */ + if (nc_get_var_chunk_cache(ncid, varid, &cache_size_in, &cache_nelems_in, + &cache_preemption_in) != NC_ENOTNC4) ERR; + + /* This call passes but does nothing. */ + if (nc_inq_var_chunking(ncid, 0, &storage_in, chunksize_in)) ERR; + + if (nc_get_var_int(ncid, varid, data_in)) ERR; + for (i = 0; i < DIM5_LEN; i++) + if (data[i] != data_in[i]) + ERR_RET; + + if (nc_close(ncid)) ERR; + + /* Open the file and check the same stuff. */ + if (nc_open(FILE_NAME, NC_NOWRITE, &ncid)) ERR; + + /* Check stuff. */ + if (nc_inq(ncid, &ndims, &nvars, &natts, &unlimdimid)) ERR; + if (ndims != NDIMS5 || nvars != 1 || natts != 0 || + unlimdimid != -1) ERR; + if (nc_inq_varids(ncid, &nvars, varids_in)) ERR; + if (nvars != 1) ERR; + if (varids_in[0] != 0) ERR; + if (nc_inq_var(ncid, 0, name_in, &xtype_in, &ndims, dimids_in, &natts)) ERR; + if (strcmp(name_in, VAR_NAME5) || xtype_in != NC_INT || ndims != 1 || natts != 0 || + dimids_in[0] != 0) ERR; + + /* This call fails. */ + if (nc_get_var_chunk_cache(ncid, varid, &cache_size_in, &cache_nelems_in, + &cache_preemption_in) != NC_ENOTNC4) ERR; + + /* This call passes but does nothing. */ + if (nc_inq_var_chunking(ncid, 0, &storage_in, chunksize_in)) ERR; + if (nc_get_var_int(ncid, varid, data_in)) ERR; for (i = 0; i < DIM5_LEN; i++) if (data[i] != data_in[i]) @@ -1037,6 +1385,37 @@ main(int argc, char **argv) } SUMMARIZE_ERR; + printf("**** testing error conditions on nc_def_var functions..."); + { + int ncid; + int dimids[NDIMS6]; + int varid; + int num_models = 2; + int m; + int mode = NC_NETCDF4; + + /* Test without and with classic model. */ + for (m = 0; m < num_models; m++) + { + if (m) + mode |= NC_CLASSIC_MODEL; + + /* Create a netcdf-4 file. */ + if (nc_create(FILE_NAME, mode, &ncid)) ERR; + if (nc_def_dim(ncid, DIM8_NAME, TEST_VAL_42, &dimids[0])) ERR; + if (nc_def_var(ncid, VAR_NAME8, NC_INT, NDIMS6, dimids, &varid)) ERR; + + /* Set the var to contiguous. */ + if (nc_def_var_chunking(ncid, varid, NC_CONTIGUOUS, NULL)) ERR; + + /* Now defalte can't be set. */ + if (nc_def_var_deflate(ncid, varid, 0, 1, 4)) ERR; + + if (nc_close(ncid)) ERR; + } + + } + SUMMARIZE_ERR; #define NDIMS6 1 #define DIM8_NAME "num_monkeys" #define DIM9_NAME "num_coconuts" diff --git a/nc_test4/tst_vars3.c b/nc_test4/tst_vars3.c index f876798223..fd200f16cd 100644 --- a/nc_test4/tst_vars3.c +++ b/nc_test4/tst_vars3.c @@ -3,7 +3,7 @@ See COPYRIGHT file for conditions of use. Test netcdf-4 variables. - $Id: tst_vars3.c,v 1.29 2010/04/30 18:21:52 ed Exp $ + Ed Hartnett, Russ Rew, Dennis Heimbigner, Ward Fisher */ #include @@ -12,6 +12,7 @@ #define FILE_NAME "tst_vars3.nc" #define NDIMS1 1 +#define NDIMS2 2 #define D_SMALL "small_dim" #define D_SMALL_LEN 16 #define D_MEDIUM "medium_dim" @@ -263,6 +264,10 @@ main(int argc, char **argv) if (nc_inq_var(ncid, 1, NULL, NULL, &ndims, dimids_in, NULL)) ERR; if (ndims != 3 || dimids_in[0] != 0 || dimids_in[1] != 2 || dimids_in[2] != 1) ERR; + /* These will not work due to bad parameters. */ + if (nc_get_vara(ncid + MILLION, 1, cor, edg, P_data) != NC_EBADID) ERR; + if (nc_get_vara(ncid + TEST_VAL_42, 1, cor, edg, P_data) != NC_EBADID) ERR; + /* Read the record of non-existent data. */ if (nc_get_vara(ncid, 1, cor, edg, P_data)) ERR; for (i = 0; i < LEN; i++) @@ -378,6 +383,26 @@ main(int argc, char **argv) if (nc_close(ncid)) ERR; } SUMMARIZE_ERR; + printf("**** testing bad inputs to put/get_vara calls..."); + { + int ncid, dimid[NDIMS2], varid; + size_t start[NDIMS2] = {0, 0}, count[NDIMS2] = {NX, NY}; + double double_data[NX * NY]; + + /* Create file with two dims, one 2D var. */ + if (nc_create(FILE_NAME, NC_NETCDF4, &ncid)) ERR; + if (nc_def_dim(ncid, ZD1_NAME, NX, &dimid[0])) ERR; + if (nc_def_dim(ncid, D2_NAME, NY, &dimid[1])) ERR; + if (nc_def_var(ncid, ZD1_NAME, NC_DOUBLE, NDIMS2, dimid, &varid)) ERR; + if (nc_enddef(ncid)) ERR; + + /* Try to write some data, but fail. */ + if (nc_put_vara_double(ncid + MILLION, 0, start, count, double_data) != NC_EBADID) ERR; + if (nc_put_vara_double(ncid + TEST_VAL_42, 0, start, count, double_data) != NC_EBADID) ERR; + + if (nc_close(ncid)) ERR; + } + SUMMARIZE_ERR; /* #ifdef USE_SZIP */ /* printf("**** testing that szip works..."); */ /* { */ diff --git a/ncdap_test/test_cvt.c b/ncdap_test/test_cvt.c index bf7a2a43a9..f9bb03f71e 100644 --- a/ncdap_test/test_cvt.c +++ b/ncdap_test/test_cvt.c @@ -112,7 +112,6 @@ int main() int ncstat = NC_NOERR; char url[8192]; const char* topsrcdir; - size_t len; #ifndef USE_NETCDF4 int i,j; #endif diff --git a/ncdump/nccopy.c b/ncdump/nccopy.c index 0d1fccf411..1a664ce5e1 100644 --- a/ncdump/nccopy.c +++ b/ncdump/nccopy.c @@ -1989,4 +1989,3 @@ main(int argc, char**argv) exit(EXIT_FAILURE); exit(EXIT_SUCCESS); } -END_OF_MAIN() diff --git a/ncdump/ncdump.c b/ncdump/ncdump.c index b914ad8bd9..5bd2f2d7b4 100644 --- a/ncdump/ncdump.c +++ b/ncdump/ncdump.c @@ -2357,6 +2357,3 @@ main(int argc, char *argv[]) } exit(EXIT_SUCCESS); } - - -END_OF_MAIN() diff --git a/ncgen/main.c b/ncgen/main.c index eb87a73f26..5eb97df512 100644 --- a/ncgen/main.c +++ b/ncgen/main.c @@ -588,7 +588,6 @@ main( return 0; } -END_OF_MAIN() void init_netcdf(void) /* initialize global counts, flags */ diff --git a/ncgen3/main.c b/ncgen3/main.c index 2e035fe15a..c27f5ed6a5 100644 --- a/ncgen3/main.c +++ b/ncgen3/main.c @@ -243,4 +243,3 @@ main( return 1; return 0; } -END_OF_MAIN() diff --git a/oc2/ocnode.c b/oc2/ocnode.c index de099d0fbf..46604837a0 100644 --- a/oc2/ocnode.c +++ b/oc2/ocnode.c @@ -482,7 +482,7 @@ occorrelater(OCnode* dds, OCnode* dxd) if(dxd->name != NULL && dxd->name != NULL && strcmp(dxd->name,dds->name) != 0) { OCTHROWCHK((ocstat = OC_EINVAL)); goto fail; - } else if(dxd->name != dxd->name) { /* test NULL==NULL */ + } else if(dxd->name != dds->name) { /* test NULL==NULL */ OCTHROWCHK((ocstat = OC_EINVAL)); goto fail; }