diff --git a/CMakeLists.txt b/CMakeLists.txt index b1211d026..384b4bcba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -935,6 +935,13 @@ IF(ENABLE_TESTS) OPTION(ENABLE_FAILING_TESTS "Run tests which are known to fail, check to see if any have been fixed." OFF) + ### + # Option to turn on unit testing. See https://github.com/Unidata/netcdf-c/pull/1472 for more information. + # Currently (August 21, 2019): Will not work with Visual Studio + ### + IF(NOT MSVC) + OPTION(ENABLE_UNIT_TESTS "Run Unit Tests." ON) + ENDIF(NOT MSVC) ### # End known-failures. ### @@ -1621,6 +1628,7 @@ MACRO(print_conf_summary) MESSAGE(STATUS "Parallel Tests: ${ENABLE_PARALLEL_TESTS}") MESSAGE(STATUS "Large File Tests: ${ENABLE_LARGE_FILE_TESTS}") MESSAGE(STATUS "Extreme Numbers: ${ENABLE_EXTREME_NUMBERS}") + MESSAGE(STATUS "Unit Tests: ${ENABLE_UNIT_TESTS}") ENDIF() MESSAGE("") @@ -1794,6 +1802,9 @@ IF(ENABLE_TESTS) IF(ENABLE_EXAMPLES) ADD_SUBDIRECTORY(examples) ENDIF() + IF(ENABLE_UNIT_TESTS) + ADD_SUBDIRECTORY(unit_test) + ENDIF(ENABLE_UNIT_TESTS) ENDIF() # Code to generate an export header diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 04c7eb960..0b33d26a9 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -7,18 +7,24 @@ This file contains a high-level description of this package's evolution. Release ## 4.7.1 - TBD +* [Enhancement] Added unit_test directory, which contains unit tests +for the libdispatch and libsrc4 code (and any other directories that +want to put unit tests there). Use --disable-unit-tests to run without +unit tests (ex. for code coverage analysis). +See [GitHub #1458](https://github.com/Unidata/netcdf-c/issues/1458) + * [Bug Fix] Remove obsolete _CRAYMPP and LOCKNUMREC macros from code. Also brought documentation up to date in man page. These macros were used in ancient times, before modern parallel I/O systems were developed. Programmers interested in parallel I/O should see nc_open_par() and nc_create_par(). -See [GitHub #1436](https://github.com/Unidata/netcdf-c/issues/1459) +See [GitHub #1459](https://github.com/Unidata/netcdf-c/issues/1459) * [Enhancement] Remove obsolete and deprecated functions nc_set_base_pe() and nc_inq_base_pe() from the dispatch table. (Both functions are still supported in the library, this is an internal change only.) -See [GitHub #1436](https://github.com/Unidata/netcdf-c/issues/1468) +See [GitHub #1468](https://github.com/Unidata/netcdf-c/issues/1468) * [Bug Fix] Reverted nccopy behavior so that if no -c parameters are given, then any default chunking is left to the netcdf-c library diff --git a/include/nc4internal.h b/include/nc4internal.h index 0728adf7e..b4e07c7d3 100644 --- a/include/nc4internal.h +++ b/include/nc4internal.h @@ -33,48 +33,53 @@ /* Always needed */ #include "nc.h" +/** The file ID is stored in the first two bytes of ncid. */ #define FILE_ID_MASK (0xffff0000) + +/** The group ID is stored in the last two bytes of ncid. */ #define GRP_ID_MASK (0x0000ffff) + +/** File and group IDs are each 16 bits of the ncid. */ #define ID_SHIFT (16) -typedef enum {GET, PUT} NC_PG_T; +/* typedef enum {GET, PUT} NC_PG_T; */ +/** These are the different objects that can be in our hash-lists. */ typedef enum {NCNAT, NCVAR, NCDIM, NCATT, NCTYP, NCFLD, NCGRP} NC_SORT; +/** The netCDF V2 error code. */ #define NC_V2_ERR (-1) -/* The name of the root group. */ +/** The name of the root group. */ #define NC_GROUP_NAME "/" +/** One mega-byte. */ #define MEGABYTE 1048576 -/* - * limits of the external representation - */ -#define X_SCHAR_MIN (-128) -#define X_SCHAR_MAX 127 -#define X_UCHAR_MAX 255U -#define X_SHORT_MIN (-32768) -#define X_SHRT_MIN X_SHORT_MIN /* alias compatible with limits.h */ -#define X_SHORT_MAX 32767 -#define X_SHRT_MAX X_SHORT_MAX /* alias compatible with limits.h */ -#define X_USHORT_MAX 65535U -#define X_USHRT_MAX X_USHORT_MAX /* alias compatible with limits.h */ -#define X_INT_MIN (-2147483647-1) -#define X_INT_MAX 2147483647 -#define X_LONG_MIN X_INT_MIN -#define X_LONG_MAX X_INT_MAX -#define X_UINT_MAX 4294967295U -#define X_INT64_MIN (-9223372036854775807LL-1LL) -#define X_INT64_MAX 9223372036854775807LL -#define X_UINT64_MAX 18446744073709551615ULL +#define X_SCHAR_MIN (-128) /**< Minimum signed char value. */ +#define X_SCHAR_MAX 127 /**< Maximum signed char value. */ +#define X_UCHAR_MAX 255U /**< Maximum unsigned char value. */ +#define X_SHORT_MIN (-32768) /**< Minumum short value. */ +#define X_SHRT_MIN X_SHORT_MIN /**< This alias is compatible with limits.h. */ +#define X_SHORT_MAX 32767 /**< Maximum short value. */ +#define X_SHRT_MAX X_SHORT_MAX /**< This alias is compatible with limits.h. */ +#define X_USHORT_MAX 65535U /**< Maximum unsigned short value. */ +#define X_USHRT_MAX X_USHORT_MAX /**< This alias is compatible with limits.h. */ +#define X_INT_MIN (-2147483647-1) /**< Minimum int value. */ +#define X_INT_MAX 2147483647 /**< Maximum int value. */ +#define X_LONG_MIN X_INT_MIN /**< Minimum long value. */ +#define X_LONG_MAX X_INT_MAX /**< Maximum long value. */ +#define X_UINT_MAX 4294967295U /**< Maximum unsigned int value. */ +#define X_INT64_MIN (-9223372036854775807LL-1LL) /**< Minimum int64 value. */ +#define X_INT64_MAX 9223372036854775807LL /**< Maximum int64 value. */ +#define X_UINT64_MAX 18446744073709551615ULL /**< Maximum unsigned int64 value. */ #ifdef WIN32 /* Windows, of course, has to be a *little* different. */ #define X_FLOAT_MAX 3.402823466e+38f #else -#define X_FLOAT_MAX 3.40282347e+38f +#define X_FLOAT_MAX 3.40282347e+38f /**< Maximum float value. */ #endif /* WIN32 */ -#define X_FLOAT_MIN (-X_FLOAT_MAX) -#define X_DOUBLE_MAX 1.7976931348623157e+308 -#define X_DOUBLE_MIN (-X_DOUBLE_MAX) +#define X_FLOAT_MIN (-X_FLOAT_MAX) /**< Minimum float value. */ +#define X_DOUBLE_MAX 1.7976931348623157e+308 /**< Maximum double value. */ +#define X_DOUBLE_MIN (-X_DOUBLE_MAX) /**< Minimum double value. */ /** This is the number of netCDF atomic types. */ #define NUM_ATOMIC_TYPES (NC_MAX_ATOMIC_TYPE + 1) @@ -82,221 +87,263 @@ typedef enum {NCNAT, NCVAR, NCDIM, NCATT, NCTYP, NCFLD, NCGRP} NC_SORT; /** Number of parameters needed for ZLIB filter. */ #define CD_NELEMS_ZLIB 1 -/* Boolean type, to make the code easier to read */ +/** Get a pointer to the NC_FILE_INFO_T from dispatchdata field. */ +#define NC4_DATA(nc) ((NC_FILE_INFO_T *)(nc)->dispatchdata) + +/** Set a pointer to the NC_FILE_INFO_T in the dispatchdata field. */ +#define NC4_DATA_SET(nc,data) ((nc)->dispatchdata = (void *)(data)) + +/* Reserved attribute flags: must be powers of 2. */ +/** Hidden dimscale-related, per-variable attributes; immutable and + * unreadable thru API. */ +#define DIMSCALEFLAG 1 + +/** Readonly global attributes; readable, but immutable thru the + * API. */ +#define READONLYFLAG 2 + +/** Subset of readonly flags; readable by name only thru the API. */ +#define NAMEONLYFLAG 4 + +/** Subset of readonly flags; Value is actually in file. */ +#define MATERIALIZEDFLAG 8 + +/* Generic reserved Attributes */ +#define NC_ATT_REFERENCE_LIST "REFERENCE_LIST" /**< HDF5 reference list attribute name. */ +#define NC_ATT_CLASS "CLASS" /**< HDF5 class atttribute name. */ +#define NC_ATT_DIMENSION_LIST "DIMENSION_LIST" /**< HDF5 dimension list attribute name. */ +#define NC_ATT_NAME "NAME" /**< HDF5 name atttribute name. */ +#define NC_ATT_COORDINATES COORDINATES /**< Coordinates atttribute name. */ +#define NC_ATT_FORMAT "_Format" /**< Format atttribute name. */ + +/** Boolean type, to make the code easier to read. */ typedef enum {NC_FALSE = 0, NC_TRUE = 1} nc_bool_t; -/*Forward*/ +/* Forward declarations. */ struct NC_GRP_INFO; struct NC_TYPE_INFO; -/* - Indexed Access to Meta-data objects: - - See the document docs/indexing.dox for detailed information. - - Basically provide a common header and use NCindex instances - instead of linked lists. - - WARNING: ALL OBJECTS THAT CAN BE INSERTED INTO AN NCindex - MUST HAVE AN INSTANCE of NC_OBJ AS THE FIRST FIELD. +/** + * This struct provides indexed Access to Meta-data objects. See the + * document docs/indexing.dox for detailed information. + * + * Basically it provides a common header and use NCindex instances + * instead of linked lists. + * + * WARNING: ALL OBJECTS THAT CAN BE INSERTED INTO AN NCindex MUST HAVE + * AN INSTANCE of NC_OBJ AS THE FIRST FIELD. */ - -typedef struct NC_OBJ { - NC_SORT sort; - char* name; /* assumed to be null terminated */ - size_t id; - unsigned int hashkey; /* crc32(name) */ +typedef struct NC_OBJ +{ + NC_SORT sort; /**< Type of object. */ + char* name; /**< Name, assumed to be null terminated. */ + size_t id; /**< This objects ID. */ + unsigned int hashkey; /**< The hash key, crc32(name). */ } NC_OBJ; -/* This is a struct to handle the dim metadata. */ +/** + * This struct holds information about reserved attributes. These + * attributes cannot be created or read by the user (through the + * netCDF API). */ +typedef struct NC_reservedatt +{ + const char *name; /**< Name of the reserved attribute. */ + int flags; /**< Flags that control handling of reserved attribute. */ +} NC_reservedatt; + +/** This is a struct to handle the dimension metadata. */ typedef struct NC_DIM_INFO { - NC_OBJ hdr; - struct NC_GRP_INFO *container; /* containing group */ - size_t len; - nc_bool_t unlimited; /* True if the dimension is unlimited */ - nc_bool_t extended; /* True if the dimension needs to be extended */ - nc_bool_t too_long; /* True if len is too big to fit in local size_t. */ - void *format_dim_info; /* Pointer to format-specific dim info. */ - struct NC_VAR_INFO *coord_var; /* The coord var, if it exists. */ + NC_OBJ hdr; /**< The hdr contains the name and ID. */ + struct NC_GRP_INFO *container; /**< Pointer to containing group. */ + size_t len; /**< Length of this dimension. */ + nc_bool_t unlimited; /**< True if the dimension is unlimited */ + nc_bool_t extended; /**< True if the dimension needs to be extended. */ + nc_bool_t too_long; /**< True if len is too big to fit in local size_t. */ + void *format_dim_info; /**< Pointer to format-specific dim info. */ + struct NC_VAR_INFO *coord_var; /**< The coord var, if it exists. */ } NC_DIM_INFO_T; +/** This is a struct to handle the attribute metadata. */ typedef struct NC_ATT_INFO { - NC_OBJ hdr; - struct NC_OBJ *container; /* containing group|var */ - int len; - nc_bool_t dirty; /* True if attribute modified */ - nc_bool_t created; /* True if attribute already created */ - nc_type nc_typeid; /* netCDF type of attribute's data */ - void *format_att_info; - void *data; - nc_vlen_t *vldata; /* only used for vlen */ - char **stdata; /* only for string type. */ + NC_OBJ hdr; /**< The hdr contains the name and ID. */ + struct NC_OBJ *container; /**< Pointer to containing group|var. */ + int len; /**< Length of attribute data. */ + nc_bool_t dirty; /**< True if attribute modified. */ + nc_bool_t created; /**< True if attribute already created. */ + nc_type nc_typeid; /**< NetCDF type of attribute's data. */ + void *format_att_info; /**< Pointer to format-specific att info. */ + void *data; /**< The attribute data. */ + nc_vlen_t *vldata; /**< VLEN data (only used for vlen types). */ + char **stdata; /**< String data (only for string type). */ } NC_ATT_INFO_T; -/* This is a struct to handle the var metadata. */ +/** This is a struct to handle the var metadata. */ typedef struct NC_VAR_INFO { - NC_OBJ hdr; - char *hdf5_name; /* used if different from name */ - struct NC_GRP_INFO *container; /* containing group */ - size_t ndims; - int *dimids; - NC_DIM_INFO_T **dim; - nc_bool_t is_new_var; /* True if variable is newly created */ - nc_bool_t was_coord_var; /* True if variable was a coordinate var, but either the dim or var has been renamed */ - nc_bool_t became_coord_var; /* True if variable _became_ a coordinate var, because either the dim or var has been renamed */ - nc_bool_t fill_val_changed; /* True if variable's fill value changes after it has been created */ - nc_bool_t attr_dirty; /* True if variable's attributes are dirty and should be rewritten */ - nc_bool_t created; /* Variable has already been created (_not_ that it was just created) */ - nc_bool_t written_to; /* True if variable has data written to it */ + NC_OBJ hdr; /**< The hdr contains the name and ID. */ + char *hdf5_name; /**< Used if name in HDF5 must be different from name. */ + struct NC_GRP_INFO *container; /**< Pointer to containing group. */ + size_t ndims; /**< Number of dims. */ + int *dimids; /**< Dim IDs. */ + NC_DIM_INFO_T **dim; /**< Pointer to dim. */ + nc_bool_t is_new_var; /**< True if variable is newly created */ + nc_bool_t was_coord_var; /**< True if variable was a coordinate var, but either the dim or var has been renamed */ + nc_bool_t became_coord_var; /**< True if variable _became_ a coordinate var, because either the dim or var has been renamed */ + nc_bool_t fill_val_changed; /**< True if variable's fill value changes after it has been created */ + nc_bool_t attr_dirty; /**< True if variable's attributes are dirty and should be rewritten */ + nc_bool_t created; /**< Variable has already been created (_not_ that it was just created) */ + nc_bool_t written_to; /**< True if variable has data written to it */ struct NC_TYPE_INFO *type_info; - int atts_read; /* If true, the atts have been read. */ - nc_bool_t meta_read; /* True if this vars metadata has been completely read. */ - nc_bool_t coords_read; /* True if this var has hidden coordinates att, and it has been read. */ - NCindex *att; /* NCindex */ - nc_bool_t no_fill; /* True if no fill value is defined for var */ + int atts_read; /**< If true, the atts have been read. */ + nc_bool_t meta_read; /**< True if this vars metadata has been completely read. */ + nc_bool_t coords_read; /**< True if this var has hidden coordinates att, and it has been read. */ + NCindex *att; /**< NCindex */ + nc_bool_t no_fill; /**< True if no fill value is defined for var */ void *fill_value; size_t *chunksizes; - nc_bool_t contiguous; /* True if variable is stored contiguously in HDF5 file */ - int parallel_access; /* Type of parallel access for I/O on variable (collective or independent) */ - nc_bool_t dimscale; /* True if var is a dimscale */ - nc_bool_t *dimscale_attached; /* Array of flags that are true if dimscale is attached for that dim index */ - nc_bool_t deflate; /* True if var has deflate filter applied */ + nc_bool_t contiguous; /**< True if variable is stored contiguously in HDF5 file */ + int parallel_access; /**< Type of parallel access for I/O on variable (collective or independent) */ + nc_bool_t dimscale; /**< True if var is a dimscale */ + nc_bool_t *dimscale_attached; /**< Array of flags that are true if dimscale is attached for that dim index */ + nc_bool_t deflate; /**< True if var has deflate filter applied */ int deflate_level; - nc_bool_t shuffle; /* True if var has shuffle filter applied */ - nc_bool_t fletcher32; /* True if var has fletcher32 filter applied */ + nc_bool_t shuffle; /**< True if var has shuffle filter applied */ + nc_bool_t fletcher32; /**< True if var has fletcher32 filter applied */ size_t chunk_cache_size, chunk_cache_nelems; float chunk_cache_preemption; - void *format_var_info; /* Pointer to any binary format info. */ - /* Stuff for arbitrary filters */ - unsigned int filterid; - size_t nparams; - unsigned int *params; + void *format_var_info; /**< Pointer to any binary format info. */ + unsigned int filterid; /**< ID for arbitrary filter. */ + size_t nparams; /**< nparams for arbitrary filter. */ + unsigned int *params; /**< Params for arbitrary filter. */ } NC_VAR_INFO_T; +/** This is a struct to handle the field metadata from a user-defined + * type. */ typedef struct NC_FIELD_INFO { - NC_OBJ hdr; - nc_type nc_typeid; - size_t offset; - int ndims; - int *dim_size; - void *format_field_info; /* Pointer to any binary format info for field. */ + NC_OBJ hdr; /**< The hdr contains the name and ID. */ + nc_type nc_typeid; /**< The type of this field. */ + size_t offset; /**< Offset in bytes of field. */ + int ndims; /**< Number of dims. */ + int *dim_size; /**< Dim sizes. */ + void *format_field_info; /**< Pointer to any binary format info for field. */ } NC_FIELD_INFO_T; +/** This is a struct to handle metadata for a user-defined enum + * type. */ typedef struct NC_ENUM_MEMBER_INFO { - char *name; - void *value; + char *name; /**< Name of member. */ + void *value; /**< Value of member. */ } NC_ENUM_MEMBER_INFO_T; +/** This is a struct to handle metadata for a user-defined type. */ typedef struct NC_TYPE_INFO { - NC_OBJ hdr; /* NetCDF type ID. */ - struct NC_GRP_INFO *container; /* Containing group */ - unsigned rc; /* Ref. count of objects using this type */ - int endianness; /* What endianness for the type? */ - size_t size; /* Size of the type in memory, in bytes */ - nc_bool_t committed; /* True when datatype is committed in the file */ - nc_type nc_type_class; /* NC_VLEN, NC_COMPOUND, NC_OPAQUE, - * NC_ENUM, NC_INT, NC_FLOAT, or - * NC_STRING. */ - void *format_type_info; /* HDF5-specific type info. */ + NC_OBJ hdr; /**< The hdr contains the name and ID. */ + struct NC_GRP_INFO *container; /**< Containing group */ + unsigned rc; /**< Ref. count of objects using this type */ + int endianness; /**< What endianness for the type? */ + size_t size; /**< Size of the type in memory, in bytes */ + nc_bool_t committed; /**< True when datatype is committed in the file */ + nc_type nc_type_class; /**< NC_VLEN, NC_COMPOUND, NC_OPAQUE, NC_ENUM, NC_INT, NC_FLOAT, or NC_STRING. */ + void *format_type_info; /**< HDF5-specific type info. */ - /* Information for each type or class */ + /** Information for each type or class */ union { struct { - NClist* enum_member; /* */ - nc_type base_nc_typeid; - } e; /* Enum */ + NClist* enum_member; /**< */ + nc_type base_nc_typeid; /**< Typeid of the base type. */ + } e; /**< Enum */ struct Fields { - NClist* field; /* */ - } c; /* Compound */ + NClist* field; /**< */ + } c; /**< Compound */ struct { - nc_type base_nc_typeid; - } v; /* Variable-length */ - } u; /* Union of structs, for each type/class */ + nc_type base_nc_typeid; /**< Typeid of the base type. */ + } v; /**< Variable-length. */ + } u; /**< Union of structs, for each type/class. */ } NC_TYPE_INFO_T; -/* This holds information for one group. Groups reproduce with +/** This holds information for one group. Groups reproduce with * parthenogenesis. */ typedef struct NC_GRP_INFO { - NC_OBJ hdr; - void *format_grp_info; - struct NC_FILE_INFO *nc4_info; - struct NC_GRP_INFO *parent; - int atts_read; /* True if atts have been read for this group. */ - NCindex* children; /* NCindex */ - NCindex* dim; /* NCindex * */ - NCindex* att; /* NCindex * */ - NCindex* type; /* NCindex * */ + NC_OBJ hdr; /**< The hdr contains the name and ID. */ + void *format_grp_info; /**< Pointer to binary format info for group. */ + struct NC_FILE_INFO *nc4_info; /**< Pointer containing NC_FILE_INFO_T. */ + struct NC_GRP_INFO *parent; /**< Pointer tp parent group. */ + int atts_read; /**< True if atts have been read for this group. */ + NCindex* children; /**< NCindex */ + NCindex* dim; /**< NCindex * */ + NCindex* att; /**< NCindex * */ + NCindex* type; /**< NCindex * */ /* Note that this is the list of vars with position == varid */ - NCindex* vars; /* NCindex * */ + NCindex* vars; /**< NCindex * */ } NC_GRP_INFO_T; /* These constants apply to the cmode parameter in the * HDF5_FILE_INFO_T defined below. */ -#define NC_CREAT 2 /* in create phase, cleared by ncendef */ -#define NC_INDEF 8 /* in define mode, cleared by ncendef */ -#define NC_NSYNC 0x10 /* synchronise numrecs on change */ -#define NC_HSYNC 0x20 /* synchronise whole header on change */ -#define NC_NDIRTY 0x40 /* numrecs has changed */ -#define NC_HDIRTY 0x80 /* header info has changed */ +#define NC_CREAT 2 /**< in create phase, cleared by ncendef */ +#define NC_INDEF 8 /**< in define mode, cleared by ncendef */ +#define NC_NSYNC 0x10 /**< synchronise numrecs on change */ +#define NC_HSYNC 0x20 /**< synchronise whole header on change */ +#define NC_NDIRTY 0x40 /**< numrecs has changed */ +#define NC_HDIRTY 0x80 /**< header info has changed */ -/* This is the metadata we need to keep track of for each - netcdf-4/HDF5 file. */ +/** This is the metadata we need to keep track of for each + * netcdf-4/HDF5 file. */ typedef struct NC_FILE_INFO { - NC* controller; + NC *controller; /**< Pointer to containing NC. */ #ifdef USE_PARALLEL4 - MPI_Comm comm; /* Copy of MPI Communicator used to open the file */ - MPI_Info info; /* Copy of MPI Information Object used to open the file */ + MPI_Comm comm; /**< Copy of MPI Communicator used to open the file. */ + MPI_Info info; /**< Copy of MPI Information Object used to open the file. */ #endif - int flags; - int cmode; - nc_bool_t parallel; /* True if file is open for parallel access */ - nc_bool_t redef; /* True if redefining an existing file */ - int fill_mode; /* Fill mode for vars - Unused internally currently */ - nc_bool_t no_write; /* true if nc_open has mode NC_NOWRITE. */ - NC_GRP_INFO_T *root_grp; - /* Track indices to assign to grps, types, and dims */ - short next_nc_grpid; - int next_typeid; - int next_dimid; - /* Provide convenience vectors indexed by the object id. - This allows for direct conversion of e.g. an nc_type to - the corresponding NC_TYPE_INFO_T object. - */ - NClist* alldims; - NClist* alltypes; - NClist* allgroups; /* including root group */ - void *format_file_info; - NC4_Provenance provenance; - struct NC4_Memio { - NC_memio memio; /* What we sent to image_init and what comes back*/ - int locked; /* do not copy and do not free */ - int persist; /* Should file be persisted out on close? */ - int inmemory; /* NC_INMEMORY flag was set */ - int diskless; /* NC_DISKLESS flag was set => inmemory */ - int created; /* 1 => create, 0 => open */ - unsigned int imageflags; /* for H5LTopen_file_image */ - size_t initialsize; - void* udata; /* extra memory allocated in NC4_image_init */ + int flags; /**< Flags used to open the file. */ + int cmode; /**< Create mode used to create the file. */ + nc_bool_t parallel; /**< True if file is open for parallel access */ + nc_bool_t redef; /**< True if redefining an existing file */ + int fill_mode; /**< Fill mode for vars - Unused internally currently */ + nc_bool_t no_write; /**< true if nc_open has mode NC_NOWRITE. */ + NC_GRP_INFO_T *root_grp; /**< Pointer to root group. */ + short next_nc_grpid; /**< Next available group ID. */ + int next_typeid; /**< Next available type ID. */ + int next_dimid; /**< Next available dim ID. */ + /* Provide convenience vectors indexed by the object id. This + allows for direct conversion of e.g. an nc_type to the + corresponding NC_TYPE_INFO_T object. */ + NClist *alldims; /**< List of all dims. */ + NClist *alltypes; /**< List of all types. */ + NClist *allgroups; /**< List of all groups, including root group. */ + void *format_file_info; /**< Pointer to binary format info for file. */ + NC4_Provenance provenance; /**< File provenence info. */ + struct NC4_Memio + { + NC_memio memio; /**< What we sent to image_init and what comes back. */ + int locked; /**< Do not copy and do not free. */ + int persist; /**< Should file be persisted out on close? */ + int inmemory; /**< NC_INMEMORY flag was set. */ + int diskless; /**< NC_DISKLESS flag was set => inmemory. */ + int created; /**< 1 => create, 0 => open. */ + unsigned int imageflags; /**< for H5LTopen_file_image. */ + size_t initialsize; /**< Initial size. */ + void *udata; /**< Extra memory allocated in NC4_image_init. */ } mem; } NC_FILE_INFO_T; -/* Variable Length Datatype struct in memory. Must be identical to +/** Variable Length Datatype struct in memory. Must be identical to * HDF5 hvl_t. (This is only used for VL sequences, not VL strings, * which are stored in char *'s) */ -typedef struct { - size_t len; /* Length of VL data (in base type units) */ - void *p; /* Pointer to VL data */ +typedef struct +{ + size_t len; /**< Length of VL data (in base type units) */ + void *p; /**< Pointer to VL data */ } nc_hvl_t; -extern const char* nc4_atomic_name[NC_MAX_ATOMIC_TYPE+1]; +/** The names of the atomic data types. */ +extern const char *nc4_atomic_name[NC_MAX_ATOMIC_TYPE + 1]; /* These functions convert between netcdf and HDF5 types. */ int nc4_get_typelen_mem(NC_FILE_INFO_T *h5, nc_type xtype, size_t *len); @@ -396,35 +443,7 @@ extern void nc4_hdf5_finalize(void); int log_metadata_nc(NC_FILE_INFO_T *h5); #endif -/* Define accessors for the dispatchdata */ -#define NC4_DATA(nc) ((NC_FILE_INFO_T*)(nc)->dispatchdata) -#define NC4_DATA_SET(nc,data) ((nc)->dispatchdata = (void*)(data)) - -/* Reserved Attributes Info */ -typedef struct NC_reservedatt { - const char* name; - int flags; -} NC_reservedatt; - -/* Reserved attribute flags: must be powers of 2*/ -/* Hidden dimscale-related, per-variable attributes; immutable and unreadable thru API */ -#define DIMSCALEFLAG 1 -/* Readonly global attributes; readable, but immutable thru the API */ -#define READONLYFLAG 2 -/* Subset of readonly flags; readable by name only thru the API */ -#define NAMEONLYFLAG 4 -/* Subset of readonly flags; Value is actually in file */ -#define MATERIALIZEDFLAG 8 - /* Binary searcher for reserved attributes */ -extern const NC_reservedatt* NC_findreserved(const char* name); - -/* Generic reserved Attributes */ -#define NC_ATT_REFERENCE_LIST "REFERENCE_LIST" -#define NC_ATT_CLASS "CLASS" -#define NC_ATT_DIMENSION_LIST "DIMENSION_LIST" -#define NC_ATT_NAME "NAME" -#define NC_ATT_COORDINATES COORDINATES /*defined above*/ -#define NC_ATT_FORMAT "_Format" +extern const NC_reservedatt *NC_findreserved(const char *name); #endif /* _NC4INTERNAL_ */ diff --git a/libdispatch/nc.c b/libdispatch/nc.c index f7b6d6750..0c600c73a 100644 --- a/libdispatch/nc.c +++ b/libdispatch/nc.c @@ -68,10 +68,11 @@ free_NC(NC *ncp) /** * Create and initialize a new NC struct. The ncid is assigned later. * - * @param dispatcher + * @param dispatcher An pointer to the NC_Dispatch table that should + * be used by this NC. * @param path The name of the file. * @param mode The open or create mode. - * @param model + * @param model An NCmodel instance, provided by NC_infermodel(). * @param ncpp A pointer that gets a pointer to the newlly allocacted * and initialized NC struct. * diff --git a/libsrc4/nc4internal.c b/libsrc4/nc4internal.c index bc02d1cd0..ad4d3a70f 100644 --- a/libsrc4/nc4internal.c +++ b/libsrc4/nc4internal.c @@ -89,7 +89,7 @@ nc4_check_name(const char *name, char *norm_name) * nc4_nc4f_list_add(), except it takes an ncid instead of an NC *, * and also passes back the dispatchdata pointer. * - * @param ncid The ncid of the file (aka ext_ncid). + * @param ncid The (already-assigned) ncid of the file (aka ext_ncid). * @param path The file name of the new file. * @param mode The mode flag. * @param dispatchdata Void * that gets pointer to dispatch data, @@ -125,10 +125,35 @@ nc4_file_list_add(int ncid, const char *path, int mode, void **dispatchdata) return NC_NOERR; } +/* /\** */ +/* * @internal Change the ncid of an open file. This is needed for PIO */ +/* * integration. */ +/* * */ +/* * @param ncid The ncid of the file (aka ext_ncid). */ +/* * @param new_ncid The new ncid to use. */ +/* * */ +/* * @return ::NC_NOERR No error. */ +/* * @return ::NC_EBADID No NC struct with this ext_ncid. */ +/* * @return ::NC_ENOMEM Out of memory. */ +/* * @author Ed Hartnett */ +/* *\/ */ +/* int */ +/* nc4_file_change_ncid(int ncid, int new_ncid) */ +/* { */ +/* NC *nc; */ +/* int ret; */ + +/* /\* Find NC pointer for this file. *\/ */ +/* if ((ret = NC_check_id(ncid, &nc))) */ +/* return ret; */ + +/* return NC_NOERR; */ +/* } */ + /** - * @internal Get info about a file on the list of libsrc4 open files. This is - * used by dispatch layers that wish to use the libsrc4 metadata - * model, but don't know about struct NC. + * @internal Get info about a file on the list of libsrc4 open + * files. This is used by dispatch layers that wish to use the libsrc4 + * metadata model, but don't know about struct NC. * * @param ncid The ncid of the file (aka ext_ncid). * @param path A pointer that gets file name (< NC_MAX_NAME). Igored @@ -212,7 +237,7 @@ nc4_nc4f_list_add(NC *nc, const char *path, int mode) /* There's always at least one open group - the root * group. Allocate space for one group's worth of information. Set - * its hdf id, name, and a pointer to it's file structure. */ + * its grp id, name, and allocate associated empty lists. */ if ((retval = nc4_grp_list_add(h5, NULL, NC_GROUP_NAME, &h5->root_grp))) return retval; diff --git a/nc_test4/CMakeLists.txt b/nc_test4/CMakeLists.txt index 38d433824..50eed3fe4 100644 --- a/nc_test4/CMakeLists.txt +++ b/nc_test4/CMakeLists.txt @@ -90,5 +90,3 @@ IF(TEST_PARALLEL4) build_bin_test(tst_simplerw_coll_r) add_sh_test(nc_test4 run_par_test) ENDIF() - -ADD_EXTRA_DIST(findplugin.in run_par_test.sh.in) diff --git a/unit_test/CMakeLists.txt b/unit_test/CMakeLists.txt new file mode 100644 index 000000000..004d44a73 --- /dev/null +++ b/unit_test/CMakeLists.txt @@ -0,0 +1,21 @@ +# Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, +# 2015, 2016, 2017, 2018, 2019 +# University Corporation for Atmospheric Research/Unidata. + +# See netcdf-c/COPYRIGHT file for more info. + +# This is the cmake build file for unit_test/ directory. +# @author Ward Fisher + +# Some unit testing + +SET(UNIT_TESTS tst_nclist) + +IF(ENABLE_NETCDF_4) + SET(UNIT_TESTS ${UNIT_TESTS} tst_nc4internal) +ENDIF(ENABLE_NETCDF_4) + +FOREACH(CTEST ${UNIT_TESTS}) + add_bin_test(unit_test ${CTEST}) +ENDFOREACH() diff --git a/unit_test/Makefile.am b/unit_test/Makefile.am index c83024a77..9e2f87d13 100644 --- a/unit_test/Makefile.am +++ b/unit_test/Makefile.am @@ -14,8 +14,14 @@ include $(top_srcdir)/lib_flags.am # Find and link to the netcdf-c library. LDADD = ${top_builddir}/liblib/libnetcdf.la -check_PROGRAMS = tst_nclist -TESTS = tst_nclist +if USE_NETCDF4 +NC4_TESTS = tst_nc4internal +endif # USE_NETCDF4 + +check_PROGRAMS = tst_nclist $(NC4_TESTS) +TESTS = tst_nclist $(NC4_TESTS) + +EXTRA_DIST = CMakeLists.txt # If valgrind is present, add valgrind targets. @VALGRIND_CHECK_RULES@ diff --git a/unit_test/tst_nc4internal.c b/unit_test/tst_nc4internal.c new file mode 100644 index 000000000..323a47989 --- /dev/null +++ b/unit_test/tst_nc4internal.c @@ -0,0 +1,300 @@ +/* This is part of the netCDF package. Copyright 2005-2019 University + Corporation for Atmospheric Research/Unidata. See COPYRIGHT file + for conditions of use. + + Test list functions in nc4internal.c. + + Ed Hartnett, 8/21/19 +*/ + +#include "config.h" +#include +#include "nc.h" +#include "nc4internal.h" +#include "ncdispatch.h" +#include "err_macros.h" + +/* An integer value to use in testing. */ +#define TEST_VAL_42 42 + +#define FILE_NAME "tst_nc4internal.nc" +#define VAR_NAME "Hilary_Duff" +#define DIM_NAME "Foggy" +#define DIM_LEN 5 +#define TYPE_NAME "Madonna" +#define TYPE_SIZE TEST_VAL_42 +#define FIELD_NAME "Britany_Spears" +#define FIELD_OFFSET 9 + +int +main(int argc, char **argv) +{ + printf("\n*** Testing netcdf nc4internal functions.\n"); + printf("Testing adding new file to nc4internal file lists with " + "nc4_file_list_add()..."); + { + NC *ncp; + NCmodel model; + char *path; + /* The NC3_dispatch_table is defined in nc3dispatch.c and + * externed in ncdispatch.h. But it will be 0 because we have + * not yet called NC3_initialize(). */ + const void *dispatcher = NC3_dispatch_table; + void *dispatchdata_in; + int mode = 0, mode_in; + + /* This won't work because there is no NC in the NC list which + * has an ncid of TEST_VAL_42. */ + if (nc4_file_list_add(TEST_VAL_42, FILE_NAME, 0, NULL) != NC_EBADID) ERR; + + /* Create the NC* instance and insert its dispatcher and + * model. */ + if (new_NC(dispatcher, FILE_NAME, mode, &model, &ncp)) ERR; + + /* Add to array of open files nc_filelist and define + * ext_ncid by left-shifting the index 16 bits. */ + add_to_NCList(ncp); + + /* Create the NC_FILE_INFO_T instance associated empty lists + * to hold dims, types, groups, and the root group. */ + if (nc4_file_list_add(ncp->ext_ncid, FILE_NAME, mode, NULL)) ERR; + + /* Find the file in the list. */ + if (!(path = malloc(NC_MAX_NAME + 1))) ERR; + if (nc4_file_list_get(ncp->ext_ncid, &path, &mode_in, &dispatchdata_in)) ERR; + if (strcmp(path, FILE_NAME)) ERR; + free(path); + if (mode_in != mode) ERR; + + /* This won't work. */ + if (nc4_file_list_del(TEST_VAL_42) != NC_EBADID) ERR; + + /* Delete the NC_FILE_INFO_T and related storage. */ + if (nc4_file_list_del(ncp->ext_ncid)) ERR; + + /* Delete the ncp from the list. (In fact, just null out its + * entry in the array of file slots.) */ + del_from_NCList(ncp); /* Will free empty list. */ + + /* Now free the NC struct. */ + free_NC(ncp); + } + SUMMARIZE_ERR; + printf("Testing adding new file to nc4internal file lists with " + "nc4_nc4f_list_add()..."); + { + NC *ncp, *ncp_in, *ncp_in2; + NCmodel model; + char *path; + void *dispatchdata_in; + int mode = 0, mode_in; + NC_GRP_INFO_T *grp, *grp2; + NC_FILE_INFO_T *h5, *h52; + + /* Create the NC* instance and insert its dispatcher and + * model. */ + if (new_NC(NC3_dispatch_table, FILE_NAME, mode, &model, &ncp)) ERR; + + /* Add to array of open files nc_filelist and define + * ext_ncid by left-shifting the index 16 bits. */ + add_to_NCList(ncp); + + /* Create the NC_FILE_INFO_T instance associated empty lists + * to hold dims, types, groups, and the root group. */ + if (nc4_nc4f_list_add(ncp, FILE_NAME, mode)) ERR; + + /* Find the file in the list. */ + if (!(path = malloc(NC_MAX_NAME + 1))) ERR; + if (nc4_file_list_get(ncp->ext_ncid, &path, &mode_in, &dispatchdata_in)) ERR; + if (strcmp(path, FILE_NAME)) ERR; + free(path); + if (mode_in != mode) ERR; + + /* Find it again. */ + if (nc4_find_nc_grp_h5(ncp->ext_ncid, &ncp_in, &grp, &h5)) ERR; + if (ncp_in->ext_ncid != ncp->ext_ncid) ERR; + if (grp->nc4_info->controller->ext_ncid != ncp->ext_ncid) ERR; + if (h5->controller->ext_ncid != ncp->ext_ncid) ERR; + + /* Any of the pointer parameters may be NULL. */ + if (nc4_find_nc_grp_h5(ncp->ext_ncid, NULL, NULL, NULL)) ERR; + if (nc4_find_nc_grp_h5(ncp->ext_ncid, &ncp_in2, NULL, NULL)) ERR; + if (ncp_in2->ext_ncid != ncp->ext_ncid) ERR; + if (nc4_find_nc_grp_h5(ncp->ext_ncid, NULL, &grp2, NULL)) ERR; + if (grp2->nc4_info->controller->ext_ncid != ncp->ext_ncid) ERR; + if (nc4_find_nc_grp_h5(ncp->ext_ncid, NULL, NULL, &h52)) ERR; + if (h52->controller->ext_ncid != ncp->ext_ncid) ERR; + + /* There are additional functions which use the NULL + * parameters of nc4_find_nc_grp_h5(). */ + grp2 = NULL; + h52 = NULL; + if (nc4_find_grp_h5(ncp->ext_ncid, NULL, NULL)) ERR; + if (nc4_find_grp_h5(ncp->ext_ncid, &grp2, NULL)) ERR; + if (grp2->nc4_info->controller->ext_ncid != ncp->ext_ncid) ERR; + if (nc4_find_grp_h5(ncp->ext_ncid, NULL, &h52)) ERR; + if (h52->controller->ext_ncid != ncp->ext_ncid) ERR; + grp2 = NULL; + if (nc4_find_nc4_grp(ncp->ext_ncid, NULL)) ERR; + if (nc4_find_nc4_grp(ncp->ext_ncid, &grp2)) ERR; + if (grp2->nc4_info->controller->ext_ncid != ncp->ext_ncid) ERR; + + /* Delete the NC_FILE_INFO_T and related storage. */ + if (nc4_file_list_del(ncp->ext_ncid)) ERR; + + /* Delete the ncp from the list. (In fact, just null out its + * entry in the array of file slots.) */ + del_from_NCList(ncp); /* Will free empty list. */ + + /* Now free the NC struct. */ + free_NC(ncp); + } + SUMMARIZE_ERR; + printf("Testing adding new var to nc4internal file..."); + { + NC *ncp, *ncp_in; + NCmodel model; + NC_GRP_INFO_T *grp; + NC_VAR_INFO_T *var, *var_in; + NC_FILE_INFO_T *h5; + + /* Create the NC* instance and insert its dispatcher and + * model. */ + if (new_NC(NC3_dispatch_table, FILE_NAME, 0, &model, &ncp)) ERR; + + /* Add to array of open files nc_filelist and define + * ext_ncid by left-shifting the index 16 bits. */ + add_to_NCList(ncp); + + /* Create the NC_FILE_INFO_T instance associated empty lists + * to hold dims, types, groups, and the root group. */ + if (nc4_file_list_add(ncp->ext_ncid, FILE_NAME, 0, NULL)) ERR; + + /* Find the file in the list. */ + if (nc4_find_nc_grp_h5(ncp->ext_ncid, &ncp_in, &grp, &h5)) ERR; + if (ncp_in->ext_ncid != ncp->ext_ncid) ERR; + + /* Add a var to the varlist. */ + if (nc4_var_list_add(grp, VAR_NAME, 0, &var)) ERR; + + /* Find the var. */ + if (nc4_find_var(grp, VAR_NAME, &var_in)) ERR; + if (strcmp(var_in->hdr.name, var->hdr.name)) ERR; + + /* Find it again. */ + h5 = NULL; + grp = NULL; + var_in = NULL; + if (nc4_find_grp_h5_var(ncp->ext_ncid, 0, &h5, &grp, &var_in)) ERR; + if (h5->controller->ext_ncid != ncp->ext_ncid) ERR; + if (grp->nc4_info->controller->ext_ncid != ncp->ext_ncid) ERR; + if (strcmp(var_in->hdr.name, var->hdr.name)) ERR; + + /* Delete the NC_FILE_INFO_T and related storage, including + * all vars, dims, types, etc. */ + if (nc4_file_list_del(ncp->ext_ncid)) ERR; + + /* Delete the ncp from the list. (In fact, just null out its + * entry in the array of file slots.) */ + del_from_NCList(ncp); /* Will free empty list. */ + + /* Now free the NC struct. */ + free_NC(ncp); + } + SUMMARIZE_ERR; + printf("Testing adding new dim to nc4internal file..."); + { + NC *ncp; + NCmodel model; + NC_GRP_INFO_T *grp, *dim_grp; + NC_DIM_INFO_T *dim, *dim_in; + + /* Create the NC, add it to nc_filelist array, add and init + * NC_FILE_INFO_T. */ + if (new_NC(NC3_dispatch_table, FILE_NAME, 0, &model, &ncp)) ERR; + add_to_NCList(ncp); + if (nc4_file_list_add(ncp->ext_ncid, FILE_NAME, 0, NULL)) ERR; + if (nc4_find_nc_grp_h5(ncp->ext_ncid, NULL, &grp, NULL)) ERR; + + /* Add a dim. */ + if (nc4_dim_list_add(grp, DIM_NAME, DIM_LEN, 0, &dim)) ERR; + + /* Find the dim. */ + if (nc4_find_dim(grp, 0, &dim_in, &dim_grp)) ERR; + if (strcmp(dim_in->hdr.name, dim->hdr.name)) ERR; + if (strcmp(dim_grp->hdr.name, grp->hdr.name)) ERR; + dim_in = NULL; + if (nc4_find_dim(grp, 0, &dim_in, NULL)) ERR; + if (strcmp(dim_in->hdr.name, dim->hdr.name)) ERR; + + /* Release resources. */ + if (nc4_file_list_del(ncp->ext_ncid)) ERR; + del_from_NCList(ncp); + free_NC(ncp); + } + SUMMARIZE_ERR; + printf("Testing adding new type to nc4internal file..."); + { + NC *ncp; + NCmodel model; + NC_GRP_INFO_T *grp; + NC_TYPE_INFO_T *type, *type_in; + NC_FILE_INFO_T *h5; + + /* Create the NC, add it to nc_filelist array, add and init + * NC_FILE_INFO_T. */ + if (new_NC(NC3_dispatch_table, FILE_NAME, 0, &model, &ncp)) ERR; + add_to_NCList(ncp); + if (nc4_file_list_add(ncp->ext_ncid, FILE_NAME, 0, NULL)) ERR; + if (nc4_find_nc_grp_h5(ncp->ext_ncid, NULL, &grp, &h5)) ERR; + + /* Add a type. */ + if (nc4_type_list_add(grp, TYPE_SIZE, TYPE_NAME, &type)) ERR; + + /* Add a field to the type. */ + /* if (nc4_field_list_add(type, FIELD_NAME, FIELD_OFFSET, NC_INT, 0, */ + /* NULL)) ERR; */ + + /* Find it. */ + if (nc4_find_type(h5, type->hdr.id, &type_in)) ERR; + if (strcmp(type_in->hdr.name, type->hdr.name)) ERR; + + /* Release resources. */ + if (nc4_file_list_del(ncp->ext_ncid)) ERR; + del_from_NCList(ncp); + free_NC(ncp); + } + SUMMARIZE_ERR; + /* printf("Testing changing ncid..."); */ + /* { */ + /* NC *ncp, *ncp2; */ + /* int mode = 0; */ + /* NCmodel model; */ + /* int ret; */ + + /* /\* Create the NC* instance and insert its dispatcher and model. *\/ */ + /* if ((ret = new_NC(NULL, FILE_NAME, mode, &model, &ncp))) ERR; */ + + /* /\* Add to list of known open files and define ext_ncid. *\/ */ + /* add_to_NCList(ncp); */ + + /* /\* Find it in the list. *\/ */ + /* if (!(ncp2 = find_in_NCList(ncp->ext_ncid))) ERR; */ + /* if (!(ncp2 = find_in_NCList_by_name(FILE_NAME))) ERR; */ + /* if ((ret = iterate_NCList(1, &ncp2))) ERR; */ + /* if (count_NCList() != 1) ERR; */ + + /* /\* Change the ncid. *\/ */ + /* if (nc4_file_change_ncid(ncp->ext_ncid, TEST_VAL_42)) ERR; */ + + /* /\* Delete it. *\/ */ + /* del_from_NCList(ncp); /\* Will free empty list. *\/ */ + /* free_NC(ncp); */ + + /* /\* Ensure it is no longer in list. *\/ */ + /* /\* if (find_in_NCList(ncp->ext_ncid)) ERR; *\/ */ + + /* } */ + /* SUMMARIZE_ERR; */ + FINAL_RESULTS; +} diff --git a/unit_test/tst_nclist.c b/unit_test/tst_nclist.c index 3637a1642..0daae16a9 100644 --- a/unit_test/tst_nclist.c +++ b/unit_test/tst_nclist.c @@ -16,6 +16,8 @@ /* An integer value to use in testing. */ #define TEST_VAL_42 42 +#define FILE_NAME "tst_nclist.nc" + int main(int argc, char **argv) { @@ -36,16 +38,20 @@ main(int argc, char **argv) NC *ncp, *ncp2; int mode = 0; NCmodel model; - char path[] = {"file.nc"}; int ret; /* Create the NC* instance and insert its dispatcher and model. */ - if ((ret = new_NC(NULL, path, mode, &model, &ncp))) ERR; + if ((ret = new_NC(NULL, FILE_NAME, mode, &model, &ncp))) ERR; /* Nothing to find yet. */ if (find_in_NCList(TEST_VAL_42)) ERR; - /* Add to list of known open files and define ext_ncid. */ + /* Add to list of known open files and define ext_ncid. To get + * the ncid, we find the first open index > 1 in the + * nc_filelist array, which has a size of 65536. Then we + * left-shift that index 16 bits to put it in the first + * 2-bytes of the 4-byte ncid. (The other two bytes are + * reserved for grpid of netCDF-4 groups.) */ add_to_NCList(ncp); /* These won't work! */ @@ -55,7 +61,7 @@ main(int argc, char **argv) /* Find it in the list. */ if (!(ncp2 = find_in_NCList(ncp->ext_ncid))) ERR; - if (!(ncp2 = find_in_NCList_by_name(path))) ERR; + if (!(ncp2 = find_in_NCList_by_name(FILE_NAME))) ERR; if ((ret = iterate_NCList(1, &ncp2))) ERR; if (count_NCList() != 1) ERR; @@ -66,6 +72,8 @@ main(int argc, char **argv) ncid = ncp->ext_ncid; del_from_NCList(ncp); /* Will free empty list. */ free_NC(ncp); + + /* Ensure it is no longer in list. */ if (find_in_NCList(ncid)) ERR; } SUMMARIZE_ERR; @@ -76,7 +84,6 @@ main(int argc, char **argv) NC *ncp; int mode = 0; NCmodel model; - char path[] = {"file.nc"}; int max_num_nc = 65535; int i; int ret; @@ -84,7 +91,7 @@ main(int argc, char **argv) /* Fill the NC list. */ for (i = 0; i < max_num_nc; i++) { - if ((ret = new_NC(NULL, path, mode, &model, &ncp))) ERR; + if ((ret = new_NC(NULL, FILE_NAME, mode, &model, &ncp))) ERR; if (add_to_NCList(ncp)) ERR; }