diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index b87d17d426..4c263665cf 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -7,6 +7,7 @@ This file contains a high-level description of this package's evolution. Release ## 4.9.1 - T.B.D. +* [Bug Fix] Provide a default enum const when fill value does not match any enum constant for the value zero. See [Github #2462](https://github.com/Unidata/netcdf-c/pull/2462). * [Bug Fi] Fix the json submodule symbol conflicts between libnetcdf and the plugin specific netcdf_json.h. See [Github #2448](https://github.com/Unidata/netcdf-c/pull/2448). * [Bug Fix] Fix quantize with CLASSIC_MODEL files. See [Github #2405](https://github.com/Unidata/netcdf-c/pull/2445). * [Enhancement] Add `--disable-quantize` option to `configure`. diff --git a/include/netcdf.h b/include/netcdf.h index a4b69071dd..71cb9babb1 100644 --- a/include/netcdf.h +++ b/include/netcdf.h @@ -836,6 +836,9 @@ nc_inq_enum_member(int ncid, nc_type xtype, int idx, char *name, /* Get enum name from enum value. Name size will be <= NC_MAX_NAME. */ +/* If value is zero and there is no matching ident, then return _UNDEFINED */ +#define NC_UNDEFINED_ENUM_IDENT "_UNDEFINED" + EXTERNL int nc_inq_enum_ident(int ncid, nc_type xtype, long long value, char *identifier); diff --git a/libsrc4/nc4type.c b/libsrc4/nc4type.c index 7166016e7c..5758323cf7 100644 --- a/libsrc4/nc4type.c +++ b/libsrc4/nc4type.c @@ -397,8 +397,9 @@ NC4_inq_compound_fieldindex(int ncid, nc_type typeid1, const char *name, int *fi } /** - * @internal Get enum name from enum value. Name size will be <= - * NC_MAX_NAME. + * @internal Get enum name from enum value. Name size will be <= NC_MAX_NAME. + * If the value is not a legitimate enum identifier and the value is zero + * (the default HDF5 enum fill value), then return the identifier "_UNDEFINED". * * @param ncid File and group ID. * @param xtype Type ID. @@ -408,7 +409,7 @@ 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_EBADTYPE Type not found. - * @return ::NC_EINVAL Invalid type data. + * @return ::NC_EINVAL Invalid type data or no matching enum value is found * @author Ed Hartnett */ int @@ -479,9 +480,13 @@ NC4_inq_enum_ident(int ncid, nc_type xtype, long long value, char *identifier) } /* If we didn't find it, life sucks for us. :-( */ - if (!found) - return NC_EINVAL; - + if(!found) { + if(value == 0) /* Special case for HDF5 default Fill Value*/ + strcpy(identifier, NC_UNDEFINED_ENUM_IDENT); + else + return NC_EINVAL; + } + return NC_NOERR; } diff --git a/ncdump/CMakeLists.txt b/ncdump/CMakeLists.txt index 7e53c13a22..df4fb5a889 100644 --- a/ncdump/CMakeLists.txt +++ b/ncdump/CMakeLists.txt @@ -180,10 +180,10 @@ endif() IF(USE_HDF5) build_bin_test_no_prefix(tst_h_rdc0) build_bin_test_no_prefix(tst_unicode) + build_bin_test_no_prefix(tst_vlen_data) add_bin_test_no_prefix(tst_create_files) add_bin_test_no_prefix(tst_opaque_data) add_bin_test_no_prefix(tst_string_data) - add_bin_test_no_prefix(tst_vlen_data) add_bin_test_no_prefix(tst_comp2) add_bin_test_no_prefix(tst_nans) add_bin_test_no_prefix(tst_h_scalar) @@ -191,6 +191,7 @@ endif() add_bin_test_no_prefix(tst_chunking) add_bin_test_no_prefix(tst_group_data) add_bin_test_no_prefix(tst_enum_data) + add_bin_test_no_prefix(tst_enum_undef) add_bin_test_no_prefix(tst_comp) # Add this test by hand, as it is also called from a script. # Editing the script would break autotools compatibility. diff --git a/ncdump/Makefile.am b/ncdump/Makefile.am index 3f958b1597..e601cdca49 100644 --- a/ncdump/Makefile.am +++ b/ncdump/Makefile.am @@ -111,7 +111,8 @@ if USE_HDF5 check_PROGRAMS += tst_fileinfo tst_create_files tst_h_rdc0 \ tst_group_data tst_enum_data tst_opaque_data tst_string_data \ tst_vlen_data tst_comp tst_comp2 tst_nans tst_special_atts \ -tst_unicode tst_fillbug tst_compress tst_chunking tst_h_scalar +tst_unicode tst_fillbug tst_compress tst_chunking tst_h_scalar \ +tst_enum_undef check_PROGRAMS += tst_vlen_demo @@ -204,7 +205,7 @@ test_keywords.sh ref_keyword1.cdl ref_keyword2.cdl ref_keyword3.cdl ref_keyword4 ref_tst_nofilters.cdl test_scope.sh \ test_rcmerge.sh ref_rcmerge1.txt ref_rcmerge2.txt ref_rcmerge3.txt \ scope_ancestor_only.cdl scope_ancestor_subgroup.cdl scope_group_only.cdl scope_preorder.cdl \ -ref_rcapi.txt +ref_rcapi.txt ref_tst_enum_undef.cdl # The L512.bin file is file containing exactly 512 bytes each of value 0. # It is used for creating hdf5 files with varying offsets for testing. @@ -246,7 +247,7 @@ tst_roman_szip_unlim.cdl tst_perdimpspecs.nc tmppds.* \ keyword1.nc keyword2.nc keyword3.nc keyword4.nc \ tmp_keyword1.cdl tmp_keyword2.cdl tmp_keyword3.cdl tmp_keyword4.cdl \ type_*.nc copy_type_*.cdl \ -scope_*.nc copy_scope_*.cdl keyword5.nc +scope_*.nc copy_scope_*.cdl keyword5.nc tst_enum_undef.cdl # Remove directories clean-local: diff --git a/ncdump/ref_tst_enum_undef.cdl b/ncdump/ref_tst_enum_undef.cdl new file mode 100644 index 0000000000..358d601a15 --- /dev/null +++ b/ncdump/ref_tst_enum_undef.cdl @@ -0,0 +1,13 @@ +netcdf tst_enum_undef { +types: + ubyte enum cloud_class_t {Cumulonimbus = 1, Stratus = 2, Stratocumulus = 3, + Cumulus = 4, Altostratus = 5, Nimbostratus = 6, Altocumulus = 7, + Cirrostratus = 8, Cirrocumulus = 9, Cirrus = 10, Missing = 255} ; +dimensions: + station = 5 ; +variables: + cloud_class_t primary_cloud(station) ; +data: + + primary_cloud = _UNDEFINED, Stratus, _UNDEFINED, Cumulonimbus, Missing ; +} diff --git a/ncdump/tst_enum_undef.c b/ncdump/tst_enum_undef.c new file mode 100644 index 0000000000..a2f75a675f --- /dev/null +++ b/ncdump/tst_enum_undef.c @@ -0,0 +1,148 @@ +/* This is part of the netCDF package. Copyright 2018 University + Corporation for Atmospheric Research/Unidata See COPYRIGHT file for + conditions of use. See www.unidata.ucar.edu for more info. + + Create a test file with an enum type and enum data for ncdump to read. + + $Id: tst_enum_data.c,v 1.8 2008/10/20 01:48:08 ed Exp $ +*/ + +#include +#include "err_macros.h" +#include + +#undef WITHFILL + +#define FILE2_NAME "tst_enum_undef.nc" +#define TYPE2_NAME "cloud_class_t" +#define DIM2_NAME "station" +#define DIM2_LEN 5 +#define VAR2_NAME "primary_cloud" +#define VAR2_RANK 1 +#define ATT2_NAME "_FillValue" +#define ATT2_LEN 1 + +int +main(int argc, char **argv) +{ + int ncid; + int dimid, varid; + nc_type typeid; + int num_members; + char name_in[NC_MAX_NAME+1]; + nc_type base_nc_type_in; + size_t nfields_in, base_size_in, num_members_in; + int class_in; + unsigned char value_in; +#ifdef WITHFILL + char zero = 0; +#endif + + int i; + + enum clouds { /* a C enumeration */ + /* No 0 value */ + CUMULONIMBUS=1, + STRATUS=2, + STRATOCUMULUS=3, + CUMULUS=4, + ALTOSTRATUS=5, + NIMBOSTRATUS=6, + ALTOCUMULUS=7, + CIRROSTRATUS=8, + CIRROCUMULUS=9, + CIRRUS=10, + MISSING=255}; + + struct { + char *name; + unsigned char value; + } cloud_types[] = { + {"Cumulonimbus", CUMULONIMBUS}, + {"Stratus", STRATUS}, + {"Stratocumulus", STRATOCUMULUS}, + {"Cumulus", CUMULUS}, + {"Altostratus", ALTOSTRATUS}, + {"Nimbostratus", NIMBOSTRATUS}, + {"Altocumulus", ALTOCUMULUS}, + {"Cirrostratus", CIRROSTRATUS}, + {"Cirrocumulus", CIRROCUMULUS}, + {"Cirrus", CIRRUS}, + {"Missing", MISSING} + }; + int var_dims[VAR2_RANK]; + unsigned char cloud_data[DIM2_LEN] = { + 0, STRATUS, 0, CUMULONIMBUS, MISSING}; + unsigned char cloud_data_in[DIM2_LEN]; + + printf("\n*** Testing enum undefined identifier.\n"); + printf("*** creating enum test file %s...", FILE2_NAME); + /*nc_set_log_level(3);*/ + if (nc_create(FILE2_NAME, NC_CLOBBER | NC_NETCDF4, &ncid)) ERR; + + /* Create an enum type. */ + if (nc_def_enum(ncid, NC_UBYTE, TYPE2_NAME, &typeid)) ERR; + num_members = (sizeof cloud_types) / (sizeof cloud_types[0]); + for (i = 0; i < num_members; i++) { + if (nc_insert_enum(ncid, typeid, cloud_types[i].name, + &cloud_types[i].value)) + ERR; + } + /* Declare a station dimension */ + if (nc_def_dim(ncid, DIM2_NAME, DIM2_LEN, &dimid)) ERR; + /* Declare a variable of the enum type */ + var_dims[0] = dimid; + if (nc_def_var(ncid, VAR2_NAME, typeid, VAR2_RANK, var_dims, &varid)) ERR; +#ifdef WITHFILL + if (nc_def_var_fill(ncid, varid, NC_FILL, &zero)) ERR; +#endif + if (nc_enddef(ncid)) ERR; + /* Store some data of the enum type */ + if(nc_put_var(ncid, varid, cloud_data)) ERR; + /* Write the file. */ + if (nc_close(ncid)) ERR; + + /* Check it out. */ + + /* Reopen the file. */ + if (nc_open(FILE2_NAME, NC_NOWRITE, &ncid)) ERR; + + if (nc_inq_user_type(ncid, typeid, name_in, &base_size_in, &base_nc_type_in, + &nfields_in, &class_in)) ERR; + if (strcmp(name_in, TYPE2_NAME) || + base_size_in != sizeof(unsigned char) || + base_nc_type_in != NC_UBYTE || + nfields_in != num_members || + class_in != NC_ENUM) ERR; + if (nc_inq_enum(ncid, typeid, name_in, + &base_nc_type_in, &base_size_in, &num_members_in)) ERR; + if (strcmp(name_in, TYPE2_NAME) || + base_nc_type_in != NC_UBYTE || + num_members_in != num_members) ERR; + for (i = 0; i < num_members; i++) + { + if (nc_inq_enum_member(ncid, typeid, i, name_in, &value_in)) ERR; + if (strcmp(name_in, cloud_types[i].name) || + value_in != cloud_types[i].value) ERR; + if (nc_inq_enum_ident(ncid, typeid, cloud_types[i].value, + name_in)) ERR; + if (strcmp(name_in, cloud_types[i].name)) ERR; + } + if (nc_inq_varid(ncid, VAR2_NAME, &varid)) ERR; + +#ifdef WITHFILL + if (nc_get_att(ncid, varid, ATT2_NAME, &value_in)) ERR; + if (value_in != 0) ERR; +#endif + + if(nc_get_var(ncid, varid, cloud_data_in)) ERR; + for (i = 0; i < DIM2_LEN; i++) { + if (cloud_data_in[i] != cloud_data[i]) ERR; + } + + if (nc_close(ncid)) ERR; + + + SUMMARIZE_ERR; + FINAL_RESULTS; +} diff --git a/ncdump/tst_nccopy4.sh b/ncdump/tst_nccopy4.sh index 81493b0382..cd2d6b7593 100755 --- a/ncdump/tst_nccopy4.sh +++ b/ncdump/tst_nccopy4.sh @@ -7,10 +7,12 @@ set -e # For a netCDF-4 build, test nccopy on netCDF files in this directory +#if 0 if test -f tst_group_data${ext} ; then ${execdir}/tst_group_data ; fi if test -f tst_enum_data${ext} ; then ${execdir}/tst_enum_data ; fi if test -f tst_comp${ext} ; then ${execdir}/tst_comp ; fi if test -f tst_comp2${ext} ; then ${execdir}/tst_comp2 ; fi +#endif echo "" diff --git a/ncdump/tst_netcdf4.sh b/ncdump/tst_netcdf4.sh index da7a571d7f..8a9dbb7823 100755 --- a/ncdump/tst_netcdf4.sh +++ b/ncdump/tst_netcdf4.sh @@ -75,6 +75,11 @@ ${execdir}/tst_enum_data ; ERR ${NCDUMP} tst_enum_data.nc | sed 's/e+0/e+/g' > tst_enum_data.cdl ; ERR diff -b tst_enum_data.cdl $srcdir/ref_tst_enum_data.cdl ; ERR +echo "*** Running tst_enum_undef.c to create test files." +${execdir}/tst_enum_undef ; ERR +${NCDUMP} tst_enum_undef.nc | sed 's/e+0/e+/g' > tst_enum_undef.cdl ; ERR +diff -b tst_enum_undef.cdl $srcdir/ref_tst_enum_undef.cdl ; ERR + echo "*** Running tst_opaque_data.c to create test files." ${execdir}/tst_opaque_data ; ERR ${NCDUMP} tst_opaque_data.nc | sed 's/e+0/e+/g' > tst_opaque_data.cdl ; ERR diff --git a/nczarr_test/run_newformat.sh b/nczarr_test/run_newformat.sh index d5bc2ce76a..dbb93e99f4 100755 --- a/nczarr_test/run_newformat.sh +++ b/nczarr_test/run_newformat.sh @@ -3,6 +3,7 @@ if test "x$srcdir" = x ; then srcdir=`pwd`; fi . ../test_common.sh +set -x . "$srcdir/test_nczarr.sh" set -e