diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in index 376d4a820..eaf65f93b 100644 --- a/docs/Doxyfile.in +++ b/docs/Doxyfile.in @@ -788,6 +788,7 @@ 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 \ @@ -796,6 +797,9 @@ INPUT = \ @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/include/netcdf.h b/include/netcdf.h index 4b131fa43..4e26e8b94 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 @@ classic or 64-bit offset file, or an netCDF-4 file with #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; @@ -1958,11 +1962,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 +1973,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/libdispatch/dcopy.c b/libdispatch/dcopy.c index ebf32fdad..d16fb0488 100644 --- a/libdispatch/dcopy.c +++ b/libdispatch/dcopy.c @@ -1,11 +1,12 @@ -/* 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" @@ -229,25 +230,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) @@ -576,16 +585,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 733fbf27e..24a0885e6 100644 --- a/libdispatch/derror.c +++ b/libdispatch/derror.c @@ -12,7 +12,7 @@ Research/Unidata. See COPYRIGHT file for more info. #include /* for ncmpi_strerror() */ #endif -/* Tell the user the version of netCDF. */ +/** @internal The version of netCDF. */ static const char nc_libvers[] = PACKAGE_VERSION " of "__DATE__" "__TIME__" $"; /** diff --git a/libdispatch/dfile.c b/libdispatch/dfile.c index 1a4e8eba3..ccc0ce89d 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 @@ done: 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,31 @@ 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. - -\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. + * @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, @@ -1813,25 +1845,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 +2060,15 @@ havetable: 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) diff --git a/libdispatch/dv2i.c b/libdispatch/dv2i.c index 2ba621433..5d4123803 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 a72d24e75..11bc55903 100644 --- a/libdispatch/dvar.c +++ b/libdispatch/dvar.c @@ -1049,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 cd5634f8d..e11cb61d1 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 7b29d09e9..c7e1fc863 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/libsrc4/Makefile.am b/libsrc4/Makefile.am index b064eb285..80bdd8767 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 15fd4cdac..000000000 --- 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 058af2b85..ea7ba0f88 100644 --- a/libsrc4/nc4attr.c +++ b/libsrc4/nc4attr.c @@ -21,11 +21,77 @@ #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); +/** + * @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. @@ -605,8 +671,8 @@ exit: * @param ncid File and group ID. * @param varid Variable ID. * @param name Name of attribute. - * @param xtype Pointer that gets type of attribute. - * @oaram lenp Pointer that gets length of attribute data array. + * @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. @@ -1002,74 +1068,6 @@ nc4_put_att_tc(int ncid, int varid, const char *name, nc_type file_type, mem_type_is_long, op); } -/** - * @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 len Length of attribute array. - * @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 Read an attribute of any type, with type conversion. This * may be called by any of the nc_get_att_* functions. diff --git a/libsrc4/nc4dim.c b/libsrc4/nc4dim.c index 6c888a6a2..303731830 100644 --- a/libsrc4/nc4dim.c +++ b/libsrc4/nc4dim.c @@ -22,7 +22,7 @@ * @note that this code is inconsistent with nc_inq * * @param ncid File and group ID. - * @param unlimdimidsp Pointer that gets ID of first unlimited + * @param unlimdimidp Pointer that gets ID of first unlimited * dimension, or -1. * * @return ::NC_NOERR No error. diff --git a/libsrc4/nc4dispatch.c b/libsrc4/nc4dispatch.c index 768eab25e..24f83103d 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 bfcd9e046..aeb75115a 100644 --- a/libsrc4/nc4file.c +++ b/libsrc4/nc4file.c @@ -1,716 +1,81 @@ -/** \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; -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; - - - /* Should we ignore this attribute? */ - for(reserved=NC_RESERVED_VARATT_LIST;*reserved;reserved++) { - if (strcmp(att_name, *reserved)==0) break; - } - - if(*reserved == NULL) { - /* Open the att by name. */ - if ((attid = H5Aopen(loc_id, att_name, H5P_DEFAULT)) < 0) - 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); - /* Fill in the information we know. */ - att->attnum = att_info->var->natts++; - if (!(att->name = strdup(att_name))) - 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 (att) - 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; -} - -/* Define the illegal mode flags */ -static const int ILLEGAL_OPEN_FLAGS = (NC_MMAP|NC_64BIT_OFFSET); - -static const int ILLEGAL_CREATE_FLAGS = (NC_NOWRITE|NC_MMAP|NC_INMEMORY|NC_64BIT_OFFSET|NC_CDF5); - -extern void reportopenobjects(int log, hid_t); - -/*! Struct to track information about objects in a group, for nc4_rec_read_metadata() - - \internal +/** + * @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 */ -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; - -/*! User data struct for call to H5Literate() in nc4_rec_read_metadata() - -\internal - -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); -static int close_netcdf4_file(NC_HDF5_FILE_INFO_T *h5, int abort); - -/* 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 -}; - -/* 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 -}; - -/* Define the subset of the reserved list that is readable by name only */ -const char* NC_RESERVED_SPECIAL_LIST[] = { -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; - -/* For performance, fill this array only the first time, and keep it - * in global memory for each further use. */ -#define NUM_TYPES 12 -static hid_t h5_native_type_constant_g[NUM_TYPES]; -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"}; -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 *)}; - -/* Set chunk cache size. Only affects files opened/created *after* it - * is called. */ -int -nc_set_chunk_cache(size_t size, size_t nelems, float preemption) -{ - if (preemption < 0 || preemption > 1) - return NC_EINVAL; - nc4_chunk_cache_size = size; - nc4_chunk_cache_nelems = nelems; - nc4_chunk_cache_preemption = preemption; - return NC_NOERR; -} - -/* Get chunk cache size. Only affects files opened/created *after* it - * is called. */ -int -nc_get_chunk_cache(size_t *sizep, size_t *nelemsp, float *preemptionp) -{ - if (sizep) - *sizep = nc4_chunk_cache_size; - - if (nelemsp) - *nelemsp = nc4_chunk_cache_nelems; - - if (preemptionp) - *preemptionp = nc4_chunk_cache_preemption; - return NC_NOERR; -} - -/* Required for fortran to avoid size_t issues. */ -int -nc_set_chunk_cache_ints(int size, int nelems, int preemption) -{ - if (size <= 0 || nelems <= 0 || preemption < 0 || preemption > 100) - return NC_EINVAL; - nc4_chunk_cache_size = size; - nc4_chunk_cache_nelems = nelems; - nc4_chunk_cache_preemption = (float)preemption / 100; - return NC_NOERR; -} - -int -nc_get_chunk_cache_ints(int *sizep, int *nelemsp, int *preemptionp) -{ - if (sizep) - *sizep = (int)nc4_chunk_cache_size; - if (nelemsp) - *nelemsp = (int)nc4_chunk_cache_nelems; - if (preemptionp) - *preemptionp = (int)(nc4_chunk_cache_preemption * 100); - - return NC_NOERR; -} - -/* This will return the length of a netcdf data type in bytes. */ -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; - } - return -1; -} - -/* Create a HDF5/netcdf-4 file. */ - -static int -nc4_create_file(const char *path, int cmode, MPI_Comm comm, MPI_Info info, - NC *nc) -{ - hid_t fcpl_id, fapl_id = -1; - unsigned flags; - FILE *fp; - int retval = NC_NOERR; - NC_HDF5_FILE_INFO_T* nc4_info = NULL; -#ifdef USE_PARALLEL4 - int comm_duped = 0; /* Whether the MPI Communicator was duplicated */ - int info_duped = 0; /* Whether the MPI Info object was duplicated */ -#else /* !USE_PARALLEL4 */ - int persist = 0; /* Should diskless try to persist its data into file?*/ -#endif - - assert(nc); - - if(cmode & NC_DISKLESS) - flags = H5F_ACC_TRUNC; - else if(cmode & NC_NOCLOBBER) - flags = H5F_ACC_EXCL; - else - flags = H5F_ACC_TRUNC; - - LOG((3, "%s: path %s mode 0x%x", __func__, path, cmode)); - assert(nc && path); - - /* 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; -#endif - } else if ((cmode & NC_NOCLOBBER) && (fp = fopen(path, "r"))) { - fclose(fp); - return NC_EEXIST; - } - - /* Add necessary structs to hold netcdf-4 file data. */ - if ((retval = nc4_nc4f_list_add(nc, path, (NC_WRITE | cmode)))) - BAIL(retval); - nc4_info = NC4_DATA(nc); - assert(nc4_info && nc4_info->root_grp); - - /* Need this access plist to control how HDF5 handles open objects - * on file close. (Setting H5F_CLOSE_SEMI will cause H5Fclose to - * fail if there are any open objects in the file. */ - if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) - BAIL(NC_EHDFERR); - if (H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI)) - BAIL(NC_EHDFERR); - -#ifdef USE_PARALLEL4 - /* If this is a parallel file create, set up the file creation - property list. */ - if ((cmode & NC_MPIIO) || (cmode & NC_MPIPOSIX)) - { - 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); - } -#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); - } -#else /* USE_PARALLEL_POSIX */ - /* Should not happen! Code in NC4_create/NC4_open should alias the - * NC_MPIPOSIX flag to NC_MPIIO, if the MPI-POSIX VFD is not - * available in HDF5. -QAK - */ - else /* MPI/POSIX */ - BAIL(NC_EPARINIT); -#endif /* USE_PARALLEL_POSIX */ - - /* Keep copies of the MPI Comm & Info objects */ - if (MPI_SUCCESS != MPI_Comm_dup(comm, &nc4_info->comm)) - BAIL(NC_EMPI); - comm_duped++; - if (MPI_INFO_NULL != info) - { - if (MPI_SUCCESS != MPI_Info_dup(info, &nc4_info->info)) - BAIL(NC_EMPI); - info_duped++; - } - else - { - /* No dup, just copy it. */ - nc4_info->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_cache(fapl_id, 0, nc4_chunk_cache_nelems, nc4_chunk_cache_size, - 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)); -#endif /* USE_PARALLEL4 */ - -#ifdef HDF5_HAS_LIBVER_BOUNDS - if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_EARLIEST, H5F_LIBVER_LATEST) < 0) - BAIL(NC_EHDFERR); -#endif - - /* Create the property list. */ - if ((fcpl_id = H5Pcreate(H5P_FILE_CREATE)) < 0) - BAIL(NC_EHDFERR); - - /* RJ: this suppose to be FALSE that is defined in H5 private.h as 0 */ - if (H5Pset_obj_track_times(fcpl_id,0)<0) - BAIL(NC_EHDFERR); - - /* Set latest_format in access propertly list and - * 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) - BAIL(NC_EHDFERR); - if (H5Pset_attr_creation_order(fcpl_id, (H5P_CRT_ORDER_TRACKED | - H5P_CRT_ORDER_INDEXED)) < 0) - BAIL(NC_EHDFERR); - - /* Create the file. */ -#ifdef HDF5_HAS_COLL_METADATA_OPS - H5Pset_all_coll_metadata_ops(fapl_id, 1 ); - H5Pset_coll_metadata_write(fapl_id, 1); -#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 */ - BAIL(EACCES); - - /* Open the root group. */ - if ((nc4_info->root_grp->hdf_grpid = H5Gopen2(nc4_info->hdfid, "/", - H5P_DEFAULT)) < 0) - BAIL(NC_EFILEMETA); - - /* Release the property lists. */ - if (H5Pclose(fapl_id) < 0 || H5Pclose(fcpl_id) < 0) - BAIL(NC_EHDFERR); - - /* Define mode gets turned on automatically on create. */ - nc4_info->flags |= NC_INDEF; - - NC4_get_fileinfo(nc4_info,&globalpropinfo); - NC4_put_propattr(nc4_info); - - return NC_NOERR; - -exit: /*failure exit*/ -#ifdef USE_PARALLEL4 - if (comm_duped) MPI_Comm_free(&nc4_info->comm); - if (info_duped) MPI_Info_free(&nc4_info->info); -#endif - if (fapl_id != H5P_DEFAULT) H5Pclose(fapl_id); - if(!nc4_info) return retval; - close_netcdf4_file(nc4_info,1); /* treat like abort */ - 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). -*/ -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) -{ - MPI_Comm comm = MPI_COMM_WORLD; - MPI_Info info = MPI_INFO_NULL; - int res; - - assert(nc_file && path); - - LOG((1, "%s: path %s cmode 0x%x comm %d info %d", - __func__, path, cmode, comm, info)); - -#ifdef USE_PARALLEL4 - if (parameters) - { - comm = ((NC_MPI_INFO *)parameters)->comm; - info = ((NC_MPI_INFO *)parameters)->info; - } -#endif /* USE_PARALLEL4 */ - - /* If this is our first file, turn off HDF5 error messages. */ - if (!nc4_hdf5_initialized) - nc4_hdf5_initialize(); - - /* Check the cmode for validity. */ - if((cmode & ILLEGAL_CREATE_FLAGS) != 0) - {res = NC_EINVAL; goto done;} - - /* Cannot have both */ - if((cmode & (NC_MPIIO|NC_MPIPOSIX)) == (NC_MPIIO|NC_MPIPOSIX)) - {res = NC_EINVAL; goto done;} - - /* Currently no parallel diskless io */ - if((cmode & (NC_MPIIO | NC_MPIPOSIX)) && (cmode & NC_DISKLESS)) - {res = NC_EINVAL; goto done;} - -#ifndef USE_PARALLEL_POSIX -/* If the HDF5 library has been compiled without the MPI-POSIX VFD, alias - * the NC_MPIPOSIX flag to NC_MPIIO. -QAK - */ - if(cmode & NC_MPIPOSIX) - { - cmode &= ~NC_MPIPOSIX; - cmode |= NC_MPIIO; - } -#endif /* USE_PARALLEL_POSIX */ - - cmode |= NC_NETCDF4; - - /* Apply default create format. */ - if (nc_get_default_format() == NC_FORMAT_CDF5) - cmode |= NC_CDF5; - else if (nc_get_default_format() == NC_FORMAT_64BIT_OFFSET) - cmode |= NC_64BIT_OFFSET; - else if (nc_get_default_format() == NC_FORMAT_NETCDF4_CLASSIC) - cmode |= NC_CLASSIC_MODEL; - - LOG((2, "cmode after applying default format: 0x%x", cmode)); - - nc_file->int_ncid = nc_file->ext_ncid; - - res = nc4_create_file(path, cmode, comm, info, nc_file); - -done: - 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. */ -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) -{ - 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 */ - htri_t attr_exists = -1; /* Flag indicating hidden attribute exists */ - hid_t attid = -1; /* ID of hidden attribute (to store dim ID) */ - int dimscale_created = 0; /* Remember if a dimension was created (for error recovery) */ - short initial_next_dimid = grp->nc4_info->next_dimid;/* Retain for error recovery */ - int retval; - - /* Add a dimension for this scale. */ - if ((retval = nc4_dim_list_add(&grp->dim, &new_dim))) - BAIL(retval); - dimscale_created++; - - /* Does this dataset have a hidden attribute that tells us its - * dimid? If so, read it. */ - if ((attr_exists = H5Aexists(datasetid, NC_DIMID_ATT_NAME)) < 0) - BAIL(NC_EHDFERR); - if (attr_exists) - { - if ((attid = H5Aopen_name(datasetid, NC_DIMID_ATT_NAME)) < 0) - BAIL(NC_EHDFERR); - - if (H5Aread(attid, H5T_NATIVE_INT, &new_dim->dimid) < 0) - BAIL(NC_EHDFERR); - - /* Check if scale's dimid should impact the group's next dimid */ - if (new_dim->dimid >= grp->nc4_info->next_dimid) - grp->nc4_info->next_dimid = new_dim->dimid + 1; - } - else - { - /* Assign dimid */ - new_dim->dimid = grp->nc4_info->next_dimid++; - } - - if (!(new_dim->name = strdup(obj_name))) - BAIL(NC_ENOMEM); - if (SIZEOF_SIZE_T < 8 && scale_size > NC_MAX_UINT) - { - new_dim->len = NC_MAX_UINT; - new_dim->too_long = NC_TRUE; - } - else - new_dim->len = scale_size; - new_dim->hdf5_objid.fileno[0] = statbuf->fileno[0]; - new_dim->hdf5_objid.fileno[1] = statbuf->fileno[1]; - new_dim->hdf5_objid.objno[0] = statbuf->objno[0]; - new_dim->hdf5_objid.objno[1] = statbuf->objno[1]; - new_dim->hash = hash_fast(obj_name, strlen(obj_name)); - - /* If the dimscale has an unlimited dimension, then this dimension - * is unlimited. */ - if (max_scale_size == H5S_UNLIMITED) - new_dim->unlimited = NC_TRUE; - - /* If the scale name is set to DIM_WITHOUT_VARIABLE, then this is a - * dimension, but not a variable. (If get_scale_name returns an - * error, just move on, there's no NAME.) */ - if (H5DSget_scale_name(datasetid, dimscale_name_att, NC_MAX_NAME) >= 0) - { - if (!strncmp(dimscale_name_att, DIM_WITHOUT_VARIABLE, - strlen(DIM_WITHOUT_VARIABLE))) - { - if (new_dim->unlimited) - { - size_t len = 0, *lenp = &len; - - if ((retval = nc4_find_dim_len(grp, new_dim->dimid, &lenp))) - BAIL(retval); - new_dim->len = *lenp; - } - - /* Hold open the dataset, since the dimension doesn't have a coordinate variable */ - new_dim->hdf_dimscaleid = datasetid; - H5Iinc_ref(new_dim->hdf_dimscaleid); /* Increment number of objects using ID */ - } - } - - /* Set the dimension created */ - *dim = new_dim; - -exit: - /* Close the hidden attribute, if it was opened (error, or no error) */ - if (attid > 0 && H5Aclose(attid) < 0) - BAIL2(NC_EHDFERR); - - /* 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); - - /* Reset the group's information */ - grp->nc4_info->next_dimid = initial_next_dimid; - } - - return retval; -} - -/* This function reads the hacked in coordinates attribute I use for - * multi-dimensional coordinates. */ -static int -read_coord_dimids(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var) -{ - hid_t coord_att_typeid = -1, coord_attid = -1, spaceid = -1; - hssize_t npoints; - int ret = 0; - int d; - - /* There is a hidden attribute telling us the ids of the - * dimensions that apply to this multi-dimensional coordinate - * variable. Read it. */ - if ((coord_attid = H5Aopen_name(var->hdf_datasetid, COORDINATES)) < 0) ret++; - if (!ret && (coord_att_typeid = H5Aget_type(coord_attid)) < 0) ret++; - - /* How many dimensions are there? */ - if (!ret && (spaceid = H5Aget_space(coord_attid)) < 0) ret++; - if (!ret && (npoints = H5Sget_simple_extent_npoints(spaceid)) < 0) ret++; - - /* Check that the number of points is the same as the number of dimensions - * for the variable */ - if (!ret && npoints != var->ndims) ret++; - - if (!ret && H5Aread(coord_attid, coord_att_typeid, var->dimids) < 0) ret++; - LOG((4, "dimscale %s is multidimensional and has coords", var->name)); - - /* 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); - } - - /* Set my HDF5 IDs free! */ - if (spaceid >= 0 && H5Sclose(spaceid) < 0) ret++; - if (coord_att_typeid >= 0 && H5Tclose(coord_att_typeid) < 0) ret++; - if (coord_attid >= 0 && H5Aclose(coord_attid) < 0) ret++; - return ret ? NC_EATTMETA : NC_NOERR; -} - -/* This function is called when reading a file's metadata for each - * dimension scale attached to a variable.*/ -static herr_t -dimscale_visitor(hid_t did, unsigned dim, hid_t dsid, - void *dimscale_hdf5_objids) -{ - H5G_stat_t statbuf; - - /* Get more info on the dimscale object.*/ - if (H5Gget_objinfo(dsid, ".", 1, &statbuf) < 0) - return -1; - - /* Pass this information back to caller. */ - (*(HDF5_OBJID_T *)dimscale_hdf5_objids).fileno[0] = statbuf.fileno[0]; - (*(HDF5_OBJID_T *)dimscale_hdf5_objids).fileno[1] = statbuf.fileno[1]; - (*(HDF5_OBJID_T *)dimscale_hdf5_objids).objno[0] = statbuf.objno[0]; - (*(HDF5_OBJID_T *)dimscale_hdf5_objids).objno[1] = statbuf.objno[1]; - 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 *xtype) { NC_TYPE_INFO_T *type; H5T_class_t class; @@ -821,12 +186,1148 @@ get_netcdf_type(NC_HDF5_FILE_INFO_T *h5, hid_t native_typeid, return NC_EBADTYPID; } -/* Given an HDF5 type, set a pointer to netcdf type_info struct, +/** + * @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; + + /* Should we ignore this attribute? */ + for(reserved=NC_RESERVED_VARATT_LIST;*reserved;reserved++) { + if (strcmp(att_name, *reserved)==0) break; + } + + if(*reserved == NULL) { + /* Open the att by name. */ + if ((attid = H5Aopen(loc_id, att_name, H5P_DEFAULT)) < 0) + 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); + /* Fill in the information we know. */ + att->attnum = att_info->var->natts++; + if (!(att->name = strdup(att_name))) + 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 (att) + 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; + + 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; +} + +/** + * @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 +*/ +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; +} + +/** + * @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 +}; + +/** + * @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 +}; + +/** + * @internal Define the subset of the reserved list that is readable + * by name only +*/ +const char* NC_RESERVED_SPECIAL_LIST[] = { + ISNETCDF4ATT, + SUPERBLOCKATT, + NCPROPS, + NULL +}; + +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. */ + +#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"}; + +/** @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}; + +/** @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) +{ + if (preemption < 0 || preemption > 1) + return NC_EINVAL; + nc4_chunk_cache_size = size; + nc4_chunk_cache_nelems = nelems; + nc4_chunk_cache_preemption = preemption; + return NC_NOERR; +} + +/** + * 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) +{ + if (sizep) + *sizep = nc4_chunk_cache_size; + + if (nelemsp) + *nelemsp = nc4_chunk_cache_nelems; + + if (preemptionp) + *preemptionp = nc4_chunk_cache_preemption; + return NC_NOERR; +} + +/** + * @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) +{ + if (size <= 0 || nelems <= 0 || preemption < 0 || preemption > 100) + return NC_EINVAL; + nc4_chunk_cache_size = size; + nc4_chunk_cache_nelems = nelems; + nc4_chunk_cache_preemption = (float)preemption / 100; + 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) +{ + if (sizep) + *sizep = (int)nc4_chunk_cache_size; + if (nelemsp) + *nelemsp = (int)nc4_chunk_cache_nelems; + if (preemptionp) + *preemptionp = (int)(nc4_chunk_cache_preemption * 100); + + return NC_NOERR; +} + +/** + * @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; + } + return -1; +} + +/** + * @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) +{ + hid_t fcpl_id, fapl_id = -1; + unsigned flags; + FILE *fp; + int retval = NC_NOERR; + NC_HDF5_FILE_INFO_T* nc4_info = NULL; +#ifdef USE_PARALLEL4 + int comm_duped = 0; /* Whether the MPI Communicator was duplicated */ + int info_duped = 0; /* Whether the MPI Info object was duplicated */ +#else /* !USE_PARALLEL4 */ + int persist = 0; /* Should diskless try to persist its data into file?*/ +#endif + + assert(nc && path); + LOG((3, "%s: path %s mode 0x%x", __func__, path, cmode)); + + if(cmode & NC_DISKLESS) + flags = H5F_ACC_TRUNC; + else if(cmode & NC_NOCLOBBER) + flags = H5F_ACC_EXCL; + else + 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; +#endif + } else if ((cmode & NC_NOCLOBBER) && (fp = fopen(path, "r"))) { + fclose(fp); + return NC_EEXIST; + } + + /* Add necessary structs to hold netcdf-4 file data. */ + if ((retval = nc4_nc4f_list_add(nc, path, (NC_WRITE | cmode)))) + BAIL(retval); + nc4_info = NC4_DATA(nc); + assert(nc4_info && nc4_info->root_grp); + + /* Need this access plist to control how HDF5 handles open objects + * on file close. (Setting H5F_CLOSE_SEMI will cause H5Fclose to + * fail if there are any open objects in the file. */ + if ((fapl_id = H5Pcreate(H5P_FILE_ACCESS)) < 0) + BAIL(NC_EHDFERR); + if (H5Pset_fclose_degree(fapl_id, H5F_CLOSE_SEMI)) + BAIL(NC_EHDFERR); + +#ifdef USE_PARALLEL4 + /* If this is a parallel file create, set up the file creation + property list. */ + if ((cmode & NC_MPIIO) || (cmode & NC_MPIPOSIX)) + { + 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); + } +#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); + } +#else /* USE_PARALLEL_POSIX */ + /* Should not happen! Code in NC4_create/NC4_open should alias the + * NC_MPIPOSIX flag to NC_MPIIO, if the MPI-POSIX VFD is not + * available in HDF5. -QAK + */ + else /* MPI/POSIX */ + BAIL(NC_EPARINIT); +#endif /* USE_PARALLEL_POSIX */ + + /* Keep copies of the MPI Comm & Info objects */ + if (MPI_SUCCESS != MPI_Comm_dup(comm, &nc4_info->comm)) + BAIL(NC_EMPI); + comm_duped++; + if (MPI_INFO_NULL != info) + { + if (MPI_SUCCESS != MPI_Info_dup(info, &nc4_info->info)) + BAIL(NC_EMPI); + info_duped++; + } + else + { + /* No dup, just copy it. */ + nc4_info->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_cache(fapl_id, 0, nc4_chunk_cache_nelems, nc4_chunk_cache_size, + 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)); +#endif /* USE_PARALLEL4 */ + +#ifdef HDF5_HAS_LIBVER_BOUNDS + if (H5Pset_libver_bounds(fapl_id, H5F_LIBVER_EARLIEST, H5F_LIBVER_LATEST) < 0) + BAIL(NC_EHDFERR); +#endif + + /* Create the property list. */ + if ((fcpl_id = H5Pcreate(H5P_FILE_CREATE)) < 0) + BAIL(NC_EHDFERR); + + /* RJ: this suppose to be FALSE that is defined in H5 private.h as 0 */ + if (H5Pset_obj_track_times(fcpl_id,0)<0) + BAIL(NC_EHDFERR); + + /* Set latest_format in access propertly list and + * 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) + BAIL(NC_EHDFERR); + if (H5Pset_attr_creation_order(fcpl_id, (H5P_CRT_ORDER_TRACKED | + H5P_CRT_ORDER_INDEXED)) < 0) + BAIL(NC_EHDFERR); + + /* Create the file. */ +#ifdef HDF5_HAS_COLL_METADATA_OPS + H5Pset_all_coll_metadata_ops(fapl_id, 1 ); + H5Pset_coll_metadata_write(fapl_id, 1); +#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 */ + BAIL(EACCES); + + /* Open the root group. */ + if ((nc4_info->root_grp->hdf_grpid = H5Gopen2(nc4_info->hdfid, "/", + H5P_DEFAULT)) < 0) + BAIL(NC_EFILEMETA); + + /* Release the property lists. */ + if (H5Pclose(fapl_id) < 0 || H5Pclose(fcpl_id) < 0) + BAIL(NC_EHDFERR); + + /* Define mode gets turned on automatically on create. */ + nc4_info->flags |= NC_INDEF; + + NC4_get_fileinfo(nc4_info,&globalpropinfo); + NC4_put_propattr(nc4_info); + + return NC_NOERR; + +exit: /*failure exit*/ +#ifdef USE_PARALLEL4 + if (comm_duped) MPI_Comm_free(&nc4_info->comm); + if (info_duped) MPI_Info_free(&nc4_info->info); +#endif + if (fapl_id != H5P_DEFAULT) H5Pclose(fapl_id); + if(!nc4_info) return retval; + close_netcdf4_file(nc4_info,1); /* treat like abort */ + return retval; +} + +/** + * @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) +{ + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Info info = MPI_INFO_NULL; + int res; + + assert(nc_file && path); + + LOG((1, "%s: path %s cmode 0x%x comm %d info %d", + __func__, path, cmode, comm, info)); + +#ifdef USE_PARALLEL4 + if (parameters) + { + comm = ((NC_MPI_INFO *)parameters)->comm; + info = ((NC_MPI_INFO *)parameters)->info; + } +#endif /* USE_PARALLEL4 */ + + /* If this is our first file, turn off HDF5 error messages. */ + if (!nc4_hdf5_initialized) + nc4_hdf5_initialize(); + + /* Check the cmode for validity. */ + if((cmode & ILLEGAL_CREATE_FLAGS) != 0) + {res = NC_EINVAL; goto done;} + + /* Cannot have both */ + if((cmode & (NC_MPIIO|NC_MPIPOSIX)) == (NC_MPIIO|NC_MPIPOSIX)) + {res = NC_EINVAL; goto done;} + + /* Currently no parallel diskless io */ + if((cmode & (NC_MPIIO | NC_MPIPOSIX)) && (cmode & NC_DISKLESS)) + {res = NC_EINVAL; goto done;} + +#ifndef USE_PARALLEL_POSIX +/* If the HDF5 library has been compiled without the MPI-POSIX VFD, alias + * the NC_MPIPOSIX flag to NC_MPIIO. -QAK + */ + if(cmode & NC_MPIPOSIX) + { + cmode &= ~NC_MPIPOSIX; + cmode |= NC_MPIIO; + } +#endif /* USE_PARALLEL_POSIX */ + + cmode |= NC_NETCDF4; + + /* Apply default create format. */ + if (nc_get_default_format() == NC_FORMAT_CDF5) + cmode |= NC_CDF5; + else if (nc_get_default_format() == NC_FORMAT_64BIT_OFFSET) + cmode |= NC_64BIT_OFFSET; + else if (nc_get_default_format() == NC_FORMAT_NETCDF4_CLASSIC) + cmode |= NC_CLASSIC_MODEL; + + LOG((2, "cmode after applying default format: 0x%x", cmode)); + + nc_file->int_ncid = nc_file->ext_ncid; + + res = nc4_create_file(path, cmode, comm, info, nc_file); + +done: + return res; +} + +/** + * @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) +{ + 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 */ + htri_t attr_exists = -1; /* Flag indicating hidden attribute exists */ + hid_t attid = -1; /* ID of hidden attribute (to store dim ID) */ + int dimscale_created = 0; /* Remember if a dimension was created (for error recovery) */ + short initial_next_dimid = grp->nc4_info->next_dimid;/* Retain for error recovery */ + int retval; + + /* Add a dimension for this scale. */ + if ((retval = nc4_dim_list_add(&grp->dim, &new_dim))) + BAIL(retval); + dimscale_created++; + + /* Does this dataset have a hidden attribute that tells us its + * dimid? If so, read it. */ + if ((attr_exists = H5Aexists(datasetid, NC_DIMID_ATT_NAME)) < 0) + BAIL(NC_EHDFERR); + if (attr_exists) + { + if ((attid = H5Aopen_name(datasetid, NC_DIMID_ATT_NAME)) < 0) + BAIL(NC_EHDFERR); + + if (H5Aread(attid, H5T_NATIVE_INT, &new_dim->dimid) < 0) + BAIL(NC_EHDFERR); + + /* Check if scale's dimid should impact the group's next dimid */ + if (new_dim->dimid >= grp->nc4_info->next_dimid) + grp->nc4_info->next_dimid = new_dim->dimid + 1; + } + else + { + /* Assign dimid */ + new_dim->dimid = grp->nc4_info->next_dimid++; + } + + if (!(new_dim->name = strdup(obj_name))) + BAIL(NC_ENOMEM); + if (SIZEOF_SIZE_T < 8 && scale_size > NC_MAX_UINT) + { + new_dim->len = NC_MAX_UINT; + new_dim->too_long = NC_TRUE; + } + else + new_dim->len = scale_size; + new_dim->hdf5_objid.fileno[0] = statbuf->fileno[0]; + new_dim->hdf5_objid.fileno[1] = statbuf->fileno[1]; + new_dim->hdf5_objid.objno[0] = statbuf->objno[0]; + new_dim->hdf5_objid.objno[1] = statbuf->objno[1]; + new_dim->hash = hash_fast(obj_name, strlen(obj_name)); + + /* If the dimscale has an unlimited dimension, then this dimension + * is unlimited. */ + if (max_scale_size == H5S_UNLIMITED) + new_dim->unlimited = NC_TRUE; + + /* If the scale name is set to DIM_WITHOUT_VARIABLE, then this is a + * dimension, but not a variable. (If get_scale_name returns an + * error, just move on, there's no NAME.) */ + if (H5DSget_scale_name(datasetid, dimscale_name_att, NC_MAX_NAME) >= 0) + { + if (!strncmp(dimscale_name_att, DIM_WITHOUT_VARIABLE, + strlen(DIM_WITHOUT_VARIABLE))) + { + if (new_dim->unlimited) + { + size_t len = 0, *lenp = &len; + + if ((retval = nc4_find_dim_len(grp, new_dim->dimid, &lenp))) + BAIL(retval); + new_dim->len = *lenp; + } + + /* Hold open the dataset, since the dimension doesn't have a coordinate variable */ + new_dim->hdf_dimscaleid = datasetid; + H5Iinc_ref(new_dim->hdf_dimscaleid); /* Increment number of objects using ID */ + } + } + + /* Set the dimension created */ + *dim = new_dim; + +exit: + /* Close the hidden attribute, if it was opened (error, or no error) */ + if (attid > 0 && H5Aclose(attid) < 0) + BAIL2(NC_EHDFERR); + + /* 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); + + /* Reset the group's information */ + grp->nc4_info->next_dimid = initial_next_dimid; + } + + return retval; +} + +/** + * @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) +{ + hid_t coord_att_typeid = -1, coord_attid = -1, spaceid = -1; + hssize_t npoints; + int ret = 0; + int d; + + /* There is a hidden attribute telling us the ids of the + * dimensions that apply to this multi-dimensional coordinate + * variable. Read it. */ + if ((coord_attid = H5Aopen_name(var->hdf_datasetid, COORDINATES)) < 0) ret++; + if (!ret && (coord_att_typeid = H5Aget_type(coord_attid)) < 0) ret++; + + /* How many dimensions are there? */ + if (!ret && (spaceid = H5Aget_space(coord_attid)) < 0) ret++; + if (!ret && (npoints = H5Sget_simple_extent_npoints(spaceid)) < 0) ret++; + + /* Check that the number of points is the same as the number of dimensions + * for the variable */ + if (!ret && npoints != var->ndims) ret++; + + if (!ret && H5Aread(coord_attid, coord_att_typeid, var->dimids) < 0) ret++; + LOG((4, "dimscale %s is multidimensional and has coords", var->name)); + + /* 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); + } + + /* Set my HDF5 IDs free! */ + if (spaceid >= 0 && H5Sclose(spaceid) < 0) ret++; + if (coord_att_typeid >= 0 && H5Tclose(coord_att_typeid) < 0) ret++; + if (coord_attid >= 0 && H5Aclose(coord_attid) < 0) ret++; + return ret ? NC_EATTMETA : NC_NOERR; +} + +/** + * @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) +{ + H5G_stat_t statbuf; + + /* Get more info on the dimscale object.*/ + if (H5Gget_objinfo(dsid, ".", 1, &statbuf) < 0) + return -1; + + /* Pass this information back to caller. */ + (*(HDF5_OBJID_T *)dimscale_hdf5_objids).fileno[0] = statbuf.fileno[0]; + (*(HDF5_OBJID_T *)dimscale_hdf5_objids).fileno[1] = statbuf.fileno[1]; + (*(HDF5_OBJID_T *)dimscale_hdf5_objids).objno[0] = statbuf.objno[0]; + (*(HDF5_OBJID_T *)dimscale_hdf5_objids).objno[1] = statbuf.objno[1]; + return 0; +} + +/** + * @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; - } + 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; + /* 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(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; - } + 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: + case H5T_STRING: + type->nc_type_class = NC_STRING; + break; + + case H5T_COMPOUND: + { + int nmembers; + unsigned int m; + char* member_name = NULL; +#ifdef JNA + char jna[1001]; +#endif + + 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 + + /* 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; + } + break; + + 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; - break; + else + { + hid_t base_hdf_typeid; + nc_type base_nc_type = NC_NAT; - case H5T_COMPOUND: + 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; + + case H5T_OPAQUE: + type->nc_type_class = NC_OPAQUE; + 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 + + type->nc_type_class = NC_ENUM; + + /* 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; + + /* 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))) { - int nmembers; - unsigned int m; - char* member_name = NULL; -#ifdef JNA - char jna[1001]; -#endif - - 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 - - /* 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; + retval = NC_EHDFERR; + break; } - break; +#ifdef JNA + strncpy(jna,member_name,1000); + member_name = jna; +#endif - case H5T_VLEN: + if (strlen(member_name) > NC_MAX_NAME) { - 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; - } + retval = NC_EBADNAME; + break; } - break; - - case H5T_OPAQUE: - type->nc_type_class = NC_OPAQUE; - break; - - case H5T_ENUM: + if (H5Tget_member_value(hdf_typeid, i, value) < 0) { - 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 - - type->nc_type_class = NC_ENUM; - - /* 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; - - /* 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; - } -#ifdef 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; - } - - hdf5free(member_name); - member_name = NULL; - } - hdf5free(member_name); - member_name = NULL; - if(value) free(value); - if(retval) /* error exit from loop */ - return retval; + retval = NC_EHDFERR; + break; } - break; - default: - LOG((0, "unknown class")); - return NC_EBADCLASS; + /* 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; + } + + 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) + 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); - 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; + } + 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 @@ exit: 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 @@ exit: 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)); + 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; - } - - /* Close the object */ - if (H5Oclose(oinfo.oid) < 0) - BAIL(H5_ITER_ERROR); - break; - - 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__)); + /* 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; + } + + /* Close the object */ + if (H5Oclose(oinfo.oid) < 0) + BAIL(H5_ITER_ERROR); + break; + + 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 @@ exit: 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! */ + 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)); + assert(grp && grp->name); + LOG((3, "%s: grp->name %s", __func__, grp->name)); - /* Portably initialize user data for later */ - memset(&udata, 0, sizeof(udata)); + /* 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); + /* 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); + /* 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; + /* 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); + /* Without creation ordering, file must be read-only. */ + if (!h5->no_write) + BAIL(NC_ECANTWRITE); - iter_index = H5_INDEX_NAME; - } + iter_index = H5_INDEX_NAME; + } - /* Set user data for iteration */ - udata.grp = grp; + /* 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); + /* 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; + /* 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); + /* 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); + /* 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); + /* 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); + /* 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); - } - } + /* Advance to next node, free current node */ + udata.grps_head = oinfo->next; + free(oinfo); + } + } - return retval; + 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 @@ exit: } #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->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->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; + 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; - } + 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; + /* 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)); - } + /* 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; + /* 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; + 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; - } + /* 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; + 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; - } + /* 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; - } + /* 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 fa4b4e2b7..7ea43357d 100644 --- a/libsrc4/nc4grp.c +++ b/libsrc4/nc4grp.c @@ -24,6 +24,7 @@ * @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 @@ -81,10 +82,12 @@ NC4_def_grp(int parent_ncid, const char *name, int *new_ncid) * @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 @@ -160,8 +163,12 @@ NC4_rename_grp(int grpid, const char *name) * * @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 @@ -204,8 +211,11 @@ NC4_inq_ncid(int ncid, const char *name, int *grp_ncid) * 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 @@ -258,6 +268,7 @@ NC4_inq_grps(int ncid, int *numgrps, int *ncids) * @param name Pointer that gets name. * @return ::NC_NOERR No error. + * @return ::NC_EBADID Bad ncid. * @author Ed Hartnett */ int @@ -294,6 +305,8 @@ NC4_inq_grpname(int ncid, char *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 @@ -348,6 +361,7 @@ NC4_inq_grpname_full(int ncid, size_t *lenp, char *full_name) return ret; } + /** * @internal Find the parent ncid of a group. For the root group, * return NC_ENOGRP error. *Now* I know what kind of tinfoil hat @@ -355,7 +369,11 @@ NC4_inq_grpname_full(int ncid, size_t *lenp, char *full_name) * 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 @@ -391,7 +409,14 @@ NC4_inq_grp_parent(int ncid, int *parent_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 @@ -456,7 +481,11 @@ NC4_inq_grp_full_ncid(int ncid, const char *full_name, int *grp_ncid) * @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 @@ -531,8 +560,13 @@ int int_cmp(const void *a, const void *b) * 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 diff --git a/libsrc4/nc4hdf.c b/libsrc4/nc4hdf.c index 00b2471fb..b0a5c7bee 100644 --- a/libsrc4/nc4hdf.c +++ b/libsrc4/nc4hdf.c @@ -25,9 +25,15 @@ #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 +#define NC_HDF5_MAX_NAME 1024 /**< @internal Max size of HDF5 name. */ + +#define MAXNAME 1024 /**< Max HDF5 name. */ + +/** @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. @@ -527,8 +533,14 @@ exit: /** * @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. + * 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) @@ -1504,7 +1516,17 @@ exit: 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) { @@ -1526,16 +1548,24 @@ write_attlist(NC_ATT_INFO_T *attlist, int varid, NC_GRP_INFO_T *grp) } -/* 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) { @@ -1556,7 +1586,16 @@ write_coord_dimids(NC_VAR_INFO_T *var) 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) { @@ -1595,7 +1634,16 @@ write_netcdf4_dimid(hid_t datasetid, int dimid) 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) { @@ -1855,7 +1903,16 @@ exit: 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) { @@ -1894,8 +1951,16 @@ nc4_adjust_var_cache(NC_GRP_INFO_T *grp, NC_VAR_INFO_T * var) 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) { @@ -2014,8 +2079,16 @@ commit_type(NC_GRP_INFO_T *grp, NC_TYPE_INFO_T *type) 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) { @@ -2049,6 +2122,14 @@ exit: 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) { @@ -2095,10 +2176,17 @@ exit: 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) { @@ -2163,6 +2251,16 @@ 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) { @@ -2189,10 +2287,20 @@ var_exists(hid_t grpid, char *name, nc_bool_t *exists) 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) { @@ -2402,6 +2510,18 @@ 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) { @@ -2523,12 +2643,22 @@ exit: 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) { @@ -2588,10 +2718,18 @@ nc4_rec_detect_need_to_preserve_dimids(NC_GRP_INFO_T *grp, nc_bool_t *bad_coord_ 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) { @@ -2663,7 +2801,15 @@ nc4_rec_write_metadata(NC_GRP_INFO_T *grp, nc_bool_t bad_coord_order) 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) { @@ -3687,9 +3833,18 @@ nc4_convert_type(const void *src, void *dest, 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) { @@ -3859,7 +4014,19 @@ nc4_rec_match_dimscales(NC_GRP_INFO_T *grp) 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) @@ -3918,7 +4085,18 @@ nc4_get_typelen_mem(NC_HDF5_FILE_INFO_T *h5, nc_type xtype, int is_long, 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) { @@ -3979,15 +4157,18 @@ 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; @@ -4018,8 +4199,16 @@ reportobject(int log, hid_t id, unsigned int type) } } -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) { @@ -4049,6 +4238,14 @@ reportopenobjectsT(int log, hid_t fid, int ntypes, unsigned int* otypes) if(idlist != NULL) free(idlist); } +/** + * @internal Report open objects. + * + * @param log + * @param fid HDF5 file ID. + * + * @return NC_NOERR No error. + */ void reportopenobjects(int log, hid_t fid) { diff --git a/libsrc4/nc4info.c b/libsrc4/nc4info.c index 71c97f2bb..4fa658549 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 @@ done: 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 @@ done: 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 @@ done: 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 @@ done: 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 7de1b7bb8..1a6f56a7b 100644 --- a/libsrc4/nc4internal.c +++ b/libsrc4/nc4internal.c @@ -8,12 +8,12 @@ * 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 */ @@ -21,17 +21,21 @@ #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 @@ -49,34 +53,40 @@ 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 } /** * @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; } /** - * @internal Check and normalize and name. + * @internal Check and normalize and name. * * @param name Name to normalize. * @param norm_name The normalized name. @@ -107,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); @@ -142,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); @@ -150,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); + /* 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]; - } - } - } + /* 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); @@ -200,7 +210,11 @@ find_var_dim_max_length(NC_GRP_INFO_T *grp, int varid, int dimid, size_t *maxlen /** * @internal Given an NC pointer, add the necessary stuff for a - * netcdf-4 file. + * 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 @@ -230,17 +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); } /** * @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.) + * 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) { @@ -265,36 +284,41 @@ nc4_find_nc4_grp(int ncid, NC_GRP_INFO_T **grp) /** * @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. + * 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. + * @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. @@ -303,45 +327,45 @@ nc4_find_grp_h5(int ncid, NC_GRP_INFO_T **grpp, NC_HDF5_FILE_INFO_T **h5p) * * @return ::NC_NOERR No error. * @return ::NC_EBADID Bad ncid. - * @author Ed Hartnett -*/ + * @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); + 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(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; + 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; + h5 = (grp)->nc4_info; + assert(h5); + } else { + h5 = NULL; + grp = NULL; + } + if(h5p) *h5p = h5; + if(grpp) *grpp = grp; + return NC_NOERR; } /** - * @internal 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) { @@ -356,8 +380,8 @@ 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; @@ -365,7 +389,7 @@ nc4_rec_find_grp(NC_GRP_INFO_T *start_grp, int target_nc_grpid) /** * @internal Given an ncid and varid, get pointers to the group and var - * metadata. + * metadata. * * @param nc Pointer to file's NC struct. * @param ncid File ID. @@ -377,7 +401,7 @@ nc4_rec_find_grp(NC_GRP_INFO_T *start_grp, int target_nc_grpid) */ 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); @@ -388,31 +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_EBADID; + 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; } /** - * @internal Find a dim in a grp (or its 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. - * + * @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; @@ -422,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) @@ -441,36 +465,43 @@ nc4_find_dim(NC_GRP_INFO_T *grp, int dimid, NC_DIM_INFO_T **dim, } /** - * @internal 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; } /** - * @internal Recursively hunt for a HDF type id. + * @internal Recursively hunt for a HDF type id. * - * @return ::NC_NOERR No error. + * @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) { @@ -484,27 +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; } /** - * @internal Recursively hunt for a netCDF type by name. + * @internal Recursively hunt for a netCDF type by name. * - * @return ::NC_NOERR No error. + * @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) { @@ -516,25 +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 + * @internal Recursively hunt for a netCDF type id. * - * @return ::NC_NOERR No error. + * @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) { @@ -545,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) @@ -556,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; } } @@ -575,7 +611,7 @@ nc4_rec_find_nc_type(const NC_GRP_INFO_T *start_grp, nc_type target_nc_typeid) * @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) { @@ -606,7 +642,7 @@ nc4_find_type(const NC_HDF5_FILE_INFO_T *h5, nc_type typeid, NC_TYPE_INFO_T **ty * * @return ::NC_NOERR No error. * @author Ed Hartnett -*/ + */ int nc4_find_dim_len(NC_GRP_INFO_T *grp, int dimid, size_t **len) { @@ -622,21 +658,21 @@ 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; @@ -644,7 +680,7 @@ nc4_find_dim_len(NC_GRP_INFO_T *grp, int dimid, size_t **len) /* Given a group, find an att. */ /** - * @internal + * @internal * * @param grp Pointer to group info struct. * @param varid Variable ID. @@ -656,17 +692,17 @@ nc4_find_dim_len(NC_GRP_INFO_T *grp, int dimid, size_t **len) * @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) @@ -674,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; @@ -684,12 +720,12 @@ 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; @@ -709,10 +745,10 @@ nc4_find_grp_att(NC_GRP_INFO_T *grp, int varid, const char *name, int attnum, * @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; @@ -721,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))) @@ -734,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; @@ -744,8 +780,8 @@ 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; @@ -760,7 +796,7 @@ nc4_find_nc_att(int ncid, int varid, const char *name, int attnum, * * @return ::NC_NOERR No error. * @author Ed Hartnett, Dennis Heimbigner -*/ + */ NC* nc4_find_nc_file(int ext_ncid, NC_HDF5_FILE_INFO_T** h5p) { @@ -769,23 +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; } /** - * @internal 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) { @@ -796,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; } @@ -806,14 +842,14 @@ obj_list_add(NC_LIST_NODE_T **list, NC_LIST_NODE_T *obj) } /** - * @internal 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) { @@ -828,14 +864,14 @@ obj_list_del(NC_LIST_NODE_T **list, NC_LIST_NODE_T *obj) } /** - * @internal 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) { @@ -854,7 +890,7 @@ nc4_var_add(NC_VAR_INFO_T **var) if (var) *var = new_var; else - free(new_var); + free(new_var); return NC_NOERR; } @@ -867,7 +903,7 @@ nc4_var_add(NC_VAR_INFO_T **var) * * @return ::NC_NOERR No error. * @author Ed Hartnett -*/ + */ int nc4_dim_list_add(NC_DIM_INFO_T **list, NC_DIM_INFO_T **dim) { @@ -894,7 +930,7 @@ nc4_dim_list_add(NC_DIM_INFO_T **list, NC_DIM_INFO_T **dim) * * @return ::NC_NOERR No error. * @author Ed Hartnett -*/ + */ int nc4_att_list_add(NC_ATT_INFO_T **list, NC_ATT_INFO_T **att) { @@ -926,11 +962,11 @@ nc4_att_list_add(NC_ATT_INFO_T **list, NC_ATT_INFO_T **att) * * @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; @@ -955,7 +991,7 @@ 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; } @@ -972,7 +1008,7 @@ nc4_grp_list_add(NC_GRP_INFO_T **list, int new_nc_grpid, * @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) { @@ -985,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)); @@ -999,13 +1035,13 @@ 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; } /** - * @internal 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. @@ -1016,7 +1052,7 @@ nc4_check_dup_name(NC_GRP_INFO_T *grp, char *name) * @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) @@ -1047,7 +1083,7 @@ nc4_type_list_add(NC_GRP_INFO_T *grp, size_t size, const char *name, } /** - * @internal 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. @@ -1058,14 +1094,14 @@ nc4_type_list_add(NC_GRP_INFO_T *grp, size_t size, const char *name, * @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; @@ -1097,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 */ @@ -1110,7 +1146,7 @@ nc4_field_list_add(NC_FIELD_INFO_T **list, int fieldid, const char *name, } /** - * @internal 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. @@ -1120,10 +1156,10 @@ nc4_field_list_add(NC_FIELD_INFO_T **list, int fieldid, const char *name, * @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; @@ -1161,7 +1197,7 @@ nc4_enum_member_add(NC_ENUM_MEMBER_INFO_T **list, size_t size, * * @return ::NC_NOERR No error. * @author Ed Hartnett -*/ + */ static void field_list_del(NC_FIELD_INFO_T **list, NC_FIELD_INFO_T *field) { @@ -1179,13 +1215,13 @@ field_list_del(NC_FIELD_INFO_T **list, NC_FIELD_INFO_T *field) } /** - * @internal 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) { @@ -1209,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; + 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; + /* 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; + field_list_del(&type->u.c.field, field); + field = f; + } + } + break; - case NC_ENUM: - { - NC_ENUM_MEMBER_INFO_T *enum_member; + 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; + /* 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; - } + 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; + 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; + case NC_VLEN: + if (H5Tclose(type->u.v.base_hdf_typeid) < 0) + return NC_EHDFERR; - default: - break; + default: + break; } /* Release the memory. */ @@ -1263,13 +1299,13 @@ nc4_type_free(NC_TYPE_INFO_T *type) } /** - * @internal 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) { @@ -1277,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; @@ -1285,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. */ @@ -1329,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; } @@ -1359,7 +1395,7 @@ nc4_var_del(NC_VAR_INFO_T *var) * * @return ::NC_NOERR No error. * @author Ed Hartnett -*/ + */ static int type_list_del(NC_TYPE_INFO_T **list, NC_TYPE_INFO_T *type) { @@ -1378,7 +1414,7 @@ type_list_del(NC_TYPE_INFO_T **list, NC_TYPE_INFO_T *type) * * @return ::NC_NOERR No error. * @author Ed Hartnett -*/ + */ int nc4_dim_list_del(NC_DIM_INFO_T **list, NC_DIM_INFO_T *dim) { @@ -1402,7 +1438,7 @@ nc4_dim_list_del(NC_DIM_INFO_T **list, NC_DIM_INFO_T *dim) * * @return ::NC_NOERR No error. * @author Ed Hartnett -*/ + */ static void grp_list_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp) { @@ -1421,7 +1457,7 @@ grp_list_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp) * * @return ::NC_NOERR No error. * @author Ed Hartnett -*/ + */ int nc4_rec_grp_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp) { @@ -1443,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; } @@ -1455,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; } @@ -1469,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; } @@ -1479,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. */ @@ -1492,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; } @@ -1506,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; } @@ -1534,7 +1570,7 @@ nc4_rec_grp_del(NC_GRP_INFO_T **list, NC_GRP_INFO_T *grp) * * @return ::NC_NOERR No error. * @author Ed Hartnett -*/ + */ int nc4_att_list_del(NC_ATT_INFO_T **list, NC_ATT_INFO_T *att) { @@ -1566,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); } @@ -1574,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); } @@ -1593,7 +1629,7 @@ nc4_att_list_del(NC_ATT_INFO_T **list, NC_ATT_INFO_T *att) * @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) { @@ -1643,7 +1679,7 @@ nc4_break_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *coord_var, NC_DIM_INFO_T * * @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) { @@ -1674,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); @@ -1702,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 */ @@ -1725,7 +1761,7 @@ 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; } @@ -1741,7 +1777,7 @@ nc4_reform_coord_var(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, NC_DIM_INFO_T *dim) * @return ::NC_NOERR No error. * @return ::NC_EMAXNAME Name too long. * @author Dennis Heimbigner -*/ + */ int nc4_normalize_name(const char *name, char *norm_name) { @@ -1771,12 +1807,12 @@ nc4_normalize_name(const char *name, char *norm_name) * * @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 @@ -1792,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.")); } @@ -1804,14 +1840,14 @@ nc_set_log_level(int new_level) #define MAX_NESTS 10 /** - * @internal Recursively print the metadata of a group. + * @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) { @@ -1831,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++) { @@ -1850,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); @@ -1871,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; } } @@ -1905,8 +1941,8 @@ 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; @@ -1915,27 +1951,27 @@ rec_print_metadata(NC_GRP_INFO_T *grp, int tab_count) /** * @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. + * 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); } @@ -1944,9 +1980,11 @@ log_metadata_nc(NC *nc) /** * @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 7012e7b73..186e311dd 100644 --- a/libsrc4/nc4type.c +++ b/libsrc4/nc4type.c @@ -16,7 +16,9 @@ #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", @@ -25,14 +27,14 @@ char atomic_name[NUM_ATOMIC_TYPES][NC_MAX_NAME + 1] = {"none", "byte", "char", /* 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 +#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. @@ -43,7 +45,10 @@ char atomic_name[NUM_ATOMIC_TYPES][NC_MAX_NAME + 1] = {"none", "byte", "char", * @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_NOERR No error. + * @return ::NC_EBADID Bad ncid. + * @return ::NC_EBADTYPE Type not found. + * @return ::NC_EINVAL Invalid type. * @author Ed Hartnett */ extern int @@ -111,7 +116,11 @@ NC4_inq_type_equal(int ncid1, nc_type typeid1, int ncid2, * @param name Name of type. * @param typeidp Pointer that will get the type ID. * - * @return NC_NOERR No error. + * @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 @@ -238,6 +247,8 @@ NC4_inq_typeids(int ncid, int *ntypes, int *typeids) * @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 @@ -374,6 +385,8 @@ NC4_inq_type(int ncid, nc_type typeid1, char *name, size_t *size) * * @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 @@ -393,6 +406,8 @@ NC4_def_compound(int ncid, size_t size, const char *name, nc_type *typeidp) * * @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 @@ -407,9 +422,17 @@ NC4_insert_compound(int ncid, nc_type typeid1, const char *name, size_t offset, * @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 @@ -629,6 +652,7 @@ find_nc4_file(int ncid, NC **nc) * @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 @@ -685,6 +709,8 @@ NC4_inq_compound_fieldindex(int ncid, nc_type typeid1, const char *name, int *fi * * @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 @@ -705,6 +731,8 @@ NC4_def_opaque(int ncid, size_t datum_size, const char *name, * * @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 @@ -724,6 +752,8 @@ NC4_def_vlen(int ncid, const char *name, nc_type base_typeid, * @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 @@ -834,6 +864,8 @@ NC4_inq_enum_ident(int ncid, nc_type xtype, long long value, char *identifier) * * @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 @@ -891,7 +923,7 @@ NC4_inq_enum_member(int ncid, nc_type typeid1, int idx, char *identifier, * @return ::NC_NOERR No error. * @return ::NC_EBADID Bad ncid. * @return ::NC_EBADTYPE Type not found. - * @return ::NC_ETYPEDEFINED Type already defined. + * @return ::NC_ETYPDEFINED Type already defined. * @author Ed Hartnett */ int diff --git a/libsrc4/nc4var.c b/libsrc4/nc4var.c index 2ffd7c426..36be4e748 100644 --- a/libsrc4/nc4var.c +++ b/libsrc4/nc4var.c @@ -14,17 +14,15 @@ #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 +#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); @@ -282,6 +280,9 @@ check_chunksizes(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, const size_t *chunksize /** * @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. @@ -325,7 +326,6 @@ nc4_find_default_chunksizes2(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var) /* 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; @@ -400,16 +400,17 @@ nc4_find_default_chunksizes2(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var) return NC_NOERR; } -#define NC_ARRAY_GROWBY 4 /** * @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) +int nc4_vararray_add(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var) { NC_VAR_INFO_T **vp = NULL; @@ -1014,8 +1015,8 @@ 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. */ diff --git a/ncdump/nccopy.c b/ncdump/nccopy.c index 0d1fccf41..1a664ce5e 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 b914ad8bd..5bd2f2d7b 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 eb87a73f2..5eb97df51 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 2e035fe15..c27f5ed6a 100644 --- a/ncgen3/main.c +++ b/ncgen3/main.c @@ -243,4 +243,3 @@ main( return 1; return 0; } -END_OF_MAIN()