mirror of
https://github.com/Unidata/netcdf-c.git
synced 2025-02-17 16:50:18 +08:00
Merged latest from trunk.
This commit is contained in:
commit
eef6e4679b
@ -46,6 +46,13 @@ fprintf(stderr, "Sorry! Unexpected result, %s, line: %d\n", \
|
||||
return 2; \
|
||||
} while (0)
|
||||
|
||||
#define ERR_GOTO do { \
|
||||
fflush(stdout); /* Make sure our stdout is synced with stderr. */ \
|
||||
fprintf(stderr, "Sorry! Unexpected result, %s, line: %d\n", \
|
||||
__FILE__, __LINE__); \
|
||||
goto error; \
|
||||
} while (0)
|
||||
|
||||
/* After a set of tests, report the number of errors, and increment
|
||||
* total_err. */
|
||||
#define SUMMARIZE_ERR do { \
|
||||
|
@ -151,9 +151,15 @@ nc4_get_att(int ncid, NC *nc, int varid, const char *name,
|
||||
{
|
||||
for (i = 0; i < att->len; i++)
|
||||
{
|
||||
if (!(((char **)data)[i] = malloc(strlen(att->stdata[i]) + 1)))
|
||||
BAIL(NC_ENOMEM);
|
||||
strcpy(((char **)data)[i], att->stdata[i]);
|
||||
/* Check for NULL pointer for string (valid in HDF5) */
|
||||
if(att->stdata[i])
|
||||
{
|
||||
if (!(((char **)data)[i] = malloc(strlen(att->stdata[i]) + 1)))
|
||||
BAIL(NC_ENOMEM);
|
||||
strcpy(((char **)data)[i], att->stdata[i]);
|
||||
}
|
||||
else
|
||||
((char **)data)[i] = att->stdata[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -308,6 +314,24 @@ nc4_put_att(int ncid, NC *nc, int varid, const char *name,
|
||||
return NC_ENOMEM;
|
||||
strcpy(att->name, norm_name);
|
||||
att->xtype = file_type;
|
||||
|
||||
/* If this att has vlen or string data, release it before we lose the length value. */
|
||||
if (att->stdata)
|
||||
{
|
||||
for (i = 0; i < att->len; i++)
|
||||
if(att->stdata[i])
|
||||
free(att->stdata[i]);
|
||||
free(att->stdata);
|
||||
att->stdata = NULL;
|
||||
}
|
||||
if (att->vldata)
|
||||
{
|
||||
for (i = 0; i < att->len; i++)
|
||||
nc_free_vlen(&att->vldata[i]);
|
||||
free(att->vldata);
|
||||
att->vldata = NULL;
|
||||
}
|
||||
|
||||
att->len = len;
|
||||
if (att->prev)
|
||||
att->attnum = att->prev->attnum + 1;
|
||||
@ -357,11 +381,14 @@ nc4_put_att(int ncid, NC *nc, int varid, const char *name,
|
||||
if (type_info && type_info->class == NC_VLEN)
|
||||
size = sizeof(hvl_t);
|
||||
else if (var->xtype == NC_STRING)
|
||||
size = sizeof(char *);
|
||||
{
|
||||
size = 1;
|
||||
if(NULL != (*(char **)data))
|
||||
size += strlen(*(char **)data);
|
||||
}
|
||||
else
|
||||
size = type_size;
|
||||
|
||||
/* size = strlen(*(char **)data) + 1; */
|
||||
if (!(var->fill_value = malloc(size)))
|
||||
return NC_ENOMEM;
|
||||
|
||||
@ -377,9 +404,10 @@ nc4_put_att(int ncid, NC *nc, int varid, const char *name,
|
||||
}
|
||||
else if (var->xtype == NC_STRING)
|
||||
{
|
||||
if (!(*(char **)var->fill_value = malloc(strlen(*(char **)data) + 1)))
|
||||
return NC_ENOMEM;
|
||||
strcpy(*(char **)(var->fill_value), *(char **)data);
|
||||
if(NULL != (*(char **)data))
|
||||
strcpy((char *)var->fill_value, *(char **)data);
|
||||
else
|
||||
strcpy((char *)var->fill_value, "");
|
||||
}
|
||||
else
|
||||
memcpy(var->fill_value, data, type_size);
|
||||
@ -415,10 +443,14 @@ nc4_put_att(int ncid, NC *nc, int varid, const char *name,
|
||||
BAIL(NC_ENOMEM);
|
||||
for (i = 0; i < att->len; i++)
|
||||
{
|
||||
LOG((5, "copying string %d of size %d", i, strlen(((char **)data)[i]) + 1));
|
||||
if (!(att->stdata[i] = malloc(strlen(((char **)data)[i]) + 1)))
|
||||
BAIL(NC_ENOMEM);
|
||||
strcpy(att->stdata[i], ((char **)data)[i]);
|
||||
if(NULL != ((char **)data)[i]) {
|
||||
LOG((5, "copying string %d of size %d", i, strlen(((char **)data)[i]) + 1));
|
||||
if (!(att->stdata[i] = malloc(strlen(((char **)data)[i]) + 1)))
|
||||
BAIL(NC_ENOMEM);
|
||||
strcpy(att->stdata[i], ((char **)data)[i]);
|
||||
}
|
||||
else
|
||||
att->stdata[i] = ((char **)data)[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -924,13 +924,29 @@ read_hdf5_att(NC_GRP_INFO_T *grp, hid_t attid, NC_ATT_INFO_T *att)
|
||||
}
|
||||
else
|
||||
{
|
||||
H5S_class_t space_class;
|
||||
|
||||
/* All netcdf attributes are scalar or 1-D only. */
|
||||
if (att_ndims > 1)
|
||||
BAIL(NC_EATTMETA);
|
||||
|
||||
/* Read the size of this attribute. */
|
||||
if (H5Sget_simple_extent_dims(spaceid, dims, NULL) < 0)
|
||||
/* 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. */
|
||||
|
@ -215,7 +215,7 @@ nc4_pg_var1(NC_PG_T pg, NC *nc, int ncid, int varid,
|
||||
/* Get the default fill value for an atomic type. Memory for
|
||||
* fill_value must already be allocated, or you are DOOMED!!!*/
|
||||
int
|
||||
nc4_get_default_fill_value(NC_TYPE_INFO_T *type_info, void *fill_value)
|
||||
nc4_get_default_fill_value(const NC_TYPE_INFO_T *type_info, void *fill_value)
|
||||
{
|
||||
switch (type_info->nc_typeid)
|
||||
{
|
||||
@ -270,28 +270,26 @@ get_fill_value(NC_HDF5_FILE_INFO_T *h5, NC_VAR_INFO_T *var, void **fillp)
|
||||
int retval;
|
||||
|
||||
/* Find out how much space we need for this type's fill value. */
|
||||
if ((retval = nc4_get_typelen_mem(h5, var->xtype, 0, &size)))
|
||||
return retval;
|
||||
|
||||
/* Strings have a size of one for the empty sting (to hold the
|
||||
* null), otherwise the length of the users fill_value string, plus
|
||||
* one. */
|
||||
if (var->xtype == NC_STRING)
|
||||
{
|
||||
size = 1;
|
||||
}
|
||||
|
||||
/* Allocate the space. VLENS are different, of course. */
|
||||
if (var->type_info->class == NC_VLEN)
|
||||
size = sizeof(nc_vlen_t);
|
||||
else if (var->xtype == NC_STRING)
|
||||
{
|
||||
if (!((*fillp) = malloc(sizeof(nc_vlen_t))))
|
||||
return NC_ENOMEM;
|
||||
/* Strings have a size of one for the empty string (to hold the null),
|
||||
* otherwise the length of the users fill_value string, plus one. */
|
||||
size = 1;
|
||||
if (var->fill_value)
|
||||
size += strlen((char *)var->fill_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!((*fillp) = malloc(size)))
|
||||
return NC_ENOMEM;
|
||||
if ((retval = nc4_get_typelen_mem(h5, var->xtype, 0, &size)))
|
||||
return retval;
|
||||
}
|
||||
assert(size);
|
||||
|
||||
/* Allocate the space. */
|
||||
if (!((*fillp) = malloc(size)))
|
||||
return NC_ENOMEM;
|
||||
|
||||
/* If the user has set a fill_value for this var, use, otherwise
|
||||
* find the default fill value. */
|
||||
@ -308,9 +306,6 @@ get_fill_value(NC_HDF5_FILE_INFO_T *h5, NC_VAR_INFO_T *var, void **fillp)
|
||||
}
|
||||
else if (var->xtype == NC_STRING)
|
||||
{
|
||||
if (!(*(char **)fillp = malloc((strlen((char *)var->fill_value) + 1) *
|
||||
sizeof(char))))
|
||||
return NC_ENOMEM;
|
||||
strcpy(*(char **)fillp, (char *)var->fill_value);
|
||||
}
|
||||
else
|
||||
@ -1303,7 +1298,6 @@ var_create_dataset(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, int write_dimid)
|
||||
hsize_t *chunksize = NULL, *dimsize = NULL, *maxdimsize = NULL;
|
||||
int d;
|
||||
NC_DIM_INFO_T *dim = NULL;
|
||||
void *fillp = NULL;
|
||||
int dims_found = 0;
|
||||
int set_chunksizes = 0;
|
||||
char *name_to_use;
|
||||
@ -1331,6 +1325,8 @@ var_create_dataset(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, int write_dimid)
|
||||
/* Figure out what fill value to set, if any. */
|
||||
if (!var->no_fill)
|
||||
{
|
||||
void *fillp = NULL;
|
||||
|
||||
if ((retval = get_fill_value(grp->nc4_info, var, &fillp)))
|
||||
BAIL(retval);
|
||||
|
||||
@ -1341,7 +1337,6 @@ var_create_dataset(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, int write_dimid)
|
||||
{
|
||||
if (H5Pset_fill_value(plistid, typeid, &fillp) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
free((char *)fillp);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1357,12 +1352,11 @@ var_create_dataset(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, int write_dimid)
|
||||
BAIL(NC_EHDFERR);
|
||||
if (var->type_info->class == NC_VLEN)
|
||||
nc_free_vlen((nc_vlen_t *)fillp);
|
||||
else
|
||||
free(fillp);
|
||||
if (var->type_info->nc_typeid == NC_STRING || var->type_info->nc_typeid == NC_CHAR)
|
||||
if (H5Tclose(fill_typeid) < 0)
|
||||
BAIL(NC_EHDFERR);
|
||||
}
|
||||
free(fillp);
|
||||
}
|
||||
} else {
|
||||
/* Required to truly turn HDF5 fill values off */
|
||||
|
@ -935,12 +935,8 @@ nc4_var_list_del(NC_VAR_INFO_T **list, NC_VAR_INFO_T *var)
|
||||
if (var->hdf_datasetid)
|
||||
{
|
||||
if (var->type_info)
|
||||
{
|
||||
if (var->type_info->class == NC_VLEN)
|
||||
nc_free_vlen((nc_vlen_t *)var->fill_value);
|
||||
else if (var->type_info->nc_typeid == NC_STRING)
|
||||
free(*(char **)var->fill_value);
|
||||
}
|
||||
}
|
||||
free(var->fill_value);
|
||||
var->fill_value = NULL;
|
||||
@ -1240,7 +1236,8 @@ nc4_att_list_del(NC_ATT_INFO_T **list, NC_ATT_INFO_T *att)
|
||||
if (att->stdata)
|
||||
{
|
||||
for (i = 0; i < att->len; i++)
|
||||
free(att->stdata[i]);
|
||||
if(att->stdata[i])
|
||||
free(att->stdata[i]);
|
||||
free(att->stdata);
|
||||
}
|
||||
|
||||
@ -1350,20 +1347,27 @@ rec_print_metadata(NC_GRP_INFO_T *grp, int *tab_count)
|
||||
;
|
||||
for( ; var; var = var->prev)
|
||||
{
|
||||
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);
|
||||
}
|
||||
if(var->ndims > 0)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
LOG((2, "%s VARIABLE - varid: %d name: %s type: %d ndims: %d dimscale: %d dimids:%s",
|
||||
tabs, var->varid, var->name, var->xtype, var->ndims, var->dimscale,
|
||||
dims_string));
|
||||
(dims_string ? dims_string : " -")));
|
||||
for(att = var->att; att; att = att->next)
|
||||
LOG((2, "%s VAR ATTRIBUTE - attnum: %d name: %s type: %d len: %d",
|
||||
tabs, att->attnum, att->name, att->xtype, att->len));
|
||||
free(dims_string); dims_string = NULL;
|
||||
if(dims_string)
|
||||
{
|
||||
free(dims_string);
|
||||
dims_string = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (type = grp->type; type; type = type->next)
|
||||
|
@ -35,7 +35,7 @@ extern int num_plists;
|
||||
#define NC_SZIP_NN_OPTION_MASK 32
|
||||
#define NC_SZIP_MAX_PIXELS_PER_BLOCK 32
|
||||
|
||||
int nc4_get_default_fill_value(NC_TYPE_INFO_T *type_info, void *fill_value);
|
||||
extern int nc4_get_default_fill_value(const NC_TYPE_INFO_T *type_info, void *fill_value);
|
||||
|
||||
|
||||
/* If the HDF5 dataset for this variable is open, then close it and
|
||||
|
@ -20,7 +20,8 @@ tst_enums tst_coords tst_coords2 tst_coords3 tst_vars3 tst_vars4 \
|
||||
tst_chunks tst_chunks2 tst_utf8 tst_fills tst_fills2 tst_fillbug \
|
||||
tst_xplatform tst_xplatform2 tst_h_atts2 tst_endian_fill tst_atts \
|
||||
t_type cdm_sea_soundings tst_camrun tst_vl tst_atts1 tst_atts2 \
|
||||
tst_vars2 tst_files5 tst_files6 tst_sync tst_h_strbug tst_h_refs
|
||||
tst_vars2 tst_files5 tst_files6 tst_sync tst_h_strbug tst_h_refs
|
||||
#tst_h_scalar
|
||||
|
||||
check_PROGRAMS = $(NC4_TESTS)
|
||||
|
||||
|
@ -72,6 +72,7 @@ IF(ENABLE_TESTS)
|
||||
add_bin_test(ncdump tst_comp)
|
||||
add_bin_test(ncdump tst_comp2)
|
||||
add_bin_test(ncdump tst_nans)
|
||||
add_bin_test(ncdump tst_h_scalar)
|
||||
#add_bin_test(ncdump tst_special_atts)
|
||||
# Add this test by hand, as it is also called from a script.
|
||||
# Editing the script would break autotools compatibility.
|
||||
@ -109,6 +110,7 @@ IF(ENABLE_TESTS)
|
||||
ENDIF()
|
||||
add_sh_test(ncdump tst_grp_spec)
|
||||
add_sh_test(ncdump tst_mud)
|
||||
add_sh_test(ncdump_shell tst_h_scalar)
|
||||
ENDIF()
|
||||
|
||||
#add_sh_test(tst_ncgen4_classic)
|
||||
|
@ -42,13 +42,13 @@ if USE_NETCDF4
|
||||
check_PROGRAMS += 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_chunking tst_h_scalar
|
||||
|
||||
TESTS += tst_create_files 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_netcdf4.sh tst_h_rdc0 tst_unicode tst_fillbug \
|
||||
tst_fillbug.sh tst_netcdf4_4.sh tst_compress tst_nccopy4.sh \
|
||||
tst_grp_spec.sh tst_mud.sh
|
||||
tst_grp_spec.sh tst_mud.sh tst_h_scalar tst_h_scalar.sh
|
||||
|
||||
if EXTRA_TESTS
|
||||
TESTS += run_back_comp_tests.sh
|
||||
@ -102,7 +102,7 @@ tmp_subset.cdl tst_inflated4.nc tst_deflated.nc tst_chunking.nc tmp*.nc \
|
||||
tst_charfill.nc tmp_tst_charfill.cdl \
|
||||
iter.* \
|
||||
tst_nc_test_netcdf4_4_0.cdl tst_mud4.nc tst_mud4.cdl \
|
||||
tst_ncf213.cdl tst_ncf213.nc
|
||||
tst_ncf213.cdl tst_ncf213.nc tst_h_scalar.cdl tst_h_scalar.nc
|
||||
|
||||
# These files all have to be included with the distribution.
|
||||
EXTRA_DIST = run_tests.sh tst_64bit.sh tst_output.sh test0.cdl \
|
||||
@ -123,7 +123,8 @@ ref_nc_test_netcdf4.cdl ref_tst_special_atts3.cdl tst_brecs.cdl \
|
||||
ref_tst_grp_spec0.cdl ref_tst_grp_spec.cdl tst_grp_spec.sh \
|
||||
ref_tst_charfill.cdl tst_charfill.cdl tst_charfill.sh \
|
||||
tst_iter.sh tst_mud.sh ref_tst_mud4.cdl \
|
||||
ref_tst_ncf213.cdl CMakeLists.txt XGetopt.c
|
||||
ref_tst_ncf213.cdl cdl4/ref_tst_h_scalar.cdl tst_h_scalar.sh CMakeLists.txt \
|
||||
XGetopt.c
|
||||
|
||||
# NCGEN4 additions
|
||||
SUBDIRS=cdl4 expected4
|
||||
|
@ -21,4 +21,7 @@ bigf1.cdl bigf2.cdl bigf3.cdl bigr1.cdl bigr2.cdl bigr3.cdl \
|
||||
n3time.cdl ref_tst_special_atts3.cdl ref_tst_unlim2.cdl ref_tst_chardata.cdl \
|
||||
ref_solar.cdl unlimtest1.cdl unlimtest2.cdl \
|
||||
ref_tst_opaque_data.cdl \
|
||||
ref_tst_vlen_data.cdl ref_tst_vlen_data2.cdl
|
||||
ref_tst_vlen_data.cdl ref_tst_vlen_data2.cdl \
|
||||
ref_niltest.cdl ref_tst_h_scalar.cdl
|
||||
|
||||
|
||||
|
18
ncdump/cdl4/ref_niltest.cdl
Normal file
18
ncdump/cdl4/ref_niltest.cdl
Normal file
@ -0,0 +1,18 @@
|
||||
netcdf ref_niltest {
|
||||
dimensions:
|
||||
d1 = 1 ;
|
||||
d2 = 2 ;
|
||||
variables:
|
||||
string v1 ;
|
||||
string v2(d1) ;
|
||||
string v3(d2, d2) ;
|
||||
data:
|
||||
|
||||
v1 = NIL ;
|
||||
|
||||
v2 = NIL ;
|
||||
|
||||
v3 =
|
||||
NIL, NIL,
|
||||
NIL, NIL ;
|
||||
}
|
48
ncdump/cdl4/ref_tst_h_scalar.cdl
Normal file
48
ncdump/cdl4/ref_tst_h_scalar.cdl
Normal file
@ -0,0 +1,48 @@
|
||||
netcdf tst_h_scalar {
|
||||
variables:
|
||||
string vstrvar1 ;
|
||||
string vstrvar1:vstratt1 = NIL ;
|
||||
string vstrvar1:vstratt2 = NIL ;
|
||||
string vstrvar1:vstratt3 = "" ;
|
||||
string vstrvar1:vstratt4 = "foo" ;
|
||||
vstrvar1:fstratt = "" ;
|
||||
vstrvar1:intatt = 0 ;
|
||||
string fstrvar ;
|
||||
string fstrvar:vstratt1 = NIL ;
|
||||
string fstrvar:vstratt2 = NIL ;
|
||||
string fstrvar:vstratt3 = "" ;
|
||||
string fstrvar:vstratt4 = "foo" ;
|
||||
fstrvar:fstratt = "" ;
|
||||
fstrvar:intatt = 0 ;
|
||||
int intvar ;
|
||||
string intvar:vstratt1 = NIL ;
|
||||
string intvar:vstratt2 = NIL ;
|
||||
string intvar:vstratt3 = "" ;
|
||||
string intvar:vstratt4 = "foo" ;
|
||||
intvar:fstratt = "" ;
|
||||
intvar:intatt = 0 ;
|
||||
string vstrvar2 ;
|
||||
string vstrvar3 ;
|
||||
string vstrvar4 ;
|
||||
|
||||
// global attributes:
|
||||
string :vstratt1 = NIL ;
|
||||
string :vstratt2 = NIL ;
|
||||
string :vstratt3 = "" ;
|
||||
string :vstratt4 = "foo" ;
|
||||
:fstratt = "" ;
|
||||
:intatt = 0 ;
|
||||
data:
|
||||
|
||||
vstrvar1 = NIL ;
|
||||
|
||||
fstrvar = _ ;
|
||||
|
||||
intvar = 0 ;
|
||||
|
||||
vstrvar2 = NIL ;
|
||||
|
||||
vstrvar3 = _ ;
|
||||
|
||||
vstrvar4 = "foo" ;
|
||||
}
|
130
ncdump/dumplib.c
130
ncdump/dumplib.c
@ -632,6 +632,12 @@ ncuint64_val_equals(const nctype_t *this,
|
||||
bool_t
|
||||
ncstring_val_equals(const nctype_t *this,
|
||||
const void *v1p, const void *v2p) {
|
||||
if (NULL == *((char **)v1p) && NULL == *((char **)v2p))
|
||||
return(1);
|
||||
else if (NULL != *((char **)v1p) && NULL == *((char **)v2p))
|
||||
return(0);
|
||||
else if (NULL == *((char **)v1p) && NULL != *((char **)v2p))
|
||||
return(0);
|
||||
return (strcmp(*((char **)v1p), *((char **)v2p)) == 0);
|
||||
}
|
||||
|
||||
@ -867,69 +873,75 @@ ncuint64_typ_tostring(const nctype_t *typ, safebuf_t *sfbf, const void *valp) {
|
||||
}
|
||||
|
||||
int ncstring_typ_tostring(const nctype_t *typ, safebuf_t *sfbf, const void *valp) {
|
||||
size_t slen;
|
||||
char *sout;
|
||||
const char *cp;
|
||||
char *sp;
|
||||
unsigned char uc;
|
||||
|
||||
cp = ((char **)valp)[0];
|
||||
slen = 3 + 5 * strlen(cp); /* need "'s around string, and extra space to escape control characters */
|
||||
sout = emalloc(slen);
|
||||
sp = sout;
|
||||
*sp++ = '"' ;
|
||||
while(*cp) {
|
||||
switch (uc = *cp++ & 0377) {
|
||||
case '\b':
|
||||
*sp++ = '\\';
|
||||
*sp++ = 'b' ;
|
||||
break;
|
||||
case '\f':
|
||||
*sp++ = '\\';
|
||||
*sp++ = 'f';
|
||||
break;
|
||||
case '\n':
|
||||
*sp++ = '\\';
|
||||
*sp++ = 'n';
|
||||
break;
|
||||
case '\r':
|
||||
*sp++ = '\\';
|
||||
*sp++ = 'r';
|
||||
break;
|
||||
case '\t':
|
||||
*sp++ = '\\';
|
||||
*sp++ = 't';
|
||||
break;
|
||||
case '\v':
|
||||
*sp++ = '\\';
|
||||
*sp++ = 'n';
|
||||
break;
|
||||
case '\\':
|
||||
*sp++ = '\\';
|
||||
*sp++ = '\\';
|
||||
break;
|
||||
case '\'':
|
||||
*sp++ = '\\';
|
||||
*sp++ = '\'';
|
||||
break;
|
||||
case '\"':
|
||||
*sp++ = '\\';
|
||||
*sp++ = '\"';
|
||||
break;
|
||||
default:
|
||||
if (iscntrl(uc)) {
|
||||
snprintf(sp,3,"\\%03o",uc);
|
||||
sp += 4;
|
||||
}
|
||||
else
|
||||
*sp++ = uc;
|
||||
break;
|
||||
}
|
||||
if(cp) {
|
||||
size_t slen;
|
||||
char *sout;
|
||||
char *sp;
|
||||
unsigned char uc;
|
||||
|
||||
slen = 3 + 5 * strlen(cp); /* need "'s around string, and extra space to escape control characters */
|
||||
sout = emalloc(slen);
|
||||
sp = sout;
|
||||
*sp++ = '"' ;
|
||||
while(*cp) {
|
||||
switch (uc = *cp++ & 0377) {
|
||||
case '\b':
|
||||
*sp++ = '\\';
|
||||
*sp++ = 'b' ;
|
||||
break;
|
||||
case '\f':
|
||||
*sp++ = '\\';
|
||||
*sp++ = 'f';
|
||||
break;
|
||||
case '\n':
|
||||
*sp++ = '\\';
|
||||
*sp++ = 'n';
|
||||
break;
|
||||
case '\r':
|
||||
*sp++ = '\\';
|
||||
*sp++ = 'r';
|
||||
break;
|
||||
case '\t':
|
||||
*sp++ = '\\';
|
||||
*sp++ = 't';
|
||||
break;
|
||||
case '\v':
|
||||
*sp++ = '\\';
|
||||
*sp++ = 'n';
|
||||
break;
|
||||
case '\\':
|
||||
*sp++ = '\\';
|
||||
*sp++ = '\\';
|
||||
break;
|
||||
case '\'':
|
||||
*sp++ = '\\';
|
||||
*sp++ = '\'';
|
||||
break;
|
||||
case '\"':
|
||||
*sp++ = '\\';
|
||||
*sp++ = '\"';
|
||||
break;
|
||||
default:
|
||||
if (iscntrl(uc)) {
|
||||
snprintf(sp,3,"\\%03o",uc);
|
||||
sp += 4;
|
||||
}
|
||||
else
|
||||
*sp++ = uc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*sp++ = '"' ;
|
||||
*sp = '\0' ;
|
||||
sbuf_cpy(sfbf, sout);
|
||||
free(sout);
|
||||
}
|
||||
else {
|
||||
sbuf_cpy(sfbf, "NIL");
|
||||
}
|
||||
*sp++ = '"' ;
|
||||
*sp = '\0' ;
|
||||
sbuf_cpy(sfbf, sout);
|
||||
free(sout);
|
||||
return sbuf_len(sfbf);
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,12 @@ extern char float_att_fmt[];
|
||||
extern char float_attx_fmt[];
|
||||
extern char double_att_fmt[];
|
||||
|
||||
/* Display for netCDF-4 and HDF5 string values representing NULL
|
||||
* pointers rather than empty strings. HDF5 distinguishes these two
|
||||
* kinds of string values so NULL pointers can be used as fill values
|
||||
* for lists of strings that might include empty strings. */
|
||||
#define NIL_STRING "NIL"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -19,7 +19,8 @@ ref_typescope.dmp sfc_pres_temp.dmp \
|
||||
simple_xy.dmp small.dmp small2.dmp test0.dmp tst_ncml.dmp \
|
||||
n3time.dmp ref_tst_special_atts3.dmp ref_tst_chardata.dmp ref_tst_unlim2.dmp \
|
||||
ref_solar.dmp unlimtest1.dmp unlimtest2.dmp \
|
||||
ref_tst_vlen_data.dmp ref_tst_vlen_data2.dmp
|
||||
ref_tst_vlen_data.dmp ref_tst_vlen_data2.dmp \
|
||||
ref_niltest.dmp ref_tst_h_scalar.dmp
|
||||
|
||||
# These do not exist because they are not run as usual tests
|
||||
# bigf1.dmp bigf2.dmp bigf3.dmp bigr1.dmp bigr2.dmp bigr3.dmp gfs1.dmp
|
||||
|
18
ncdump/expected4/ref_niltest.dmp
Normal file
18
ncdump/expected4/ref_niltest.dmp
Normal file
@ -0,0 +1,18 @@
|
||||
netcdf ref_niltest {
|
||||
dimensions:
|
||||
d1 = 1 ;
|
||||
d2 = 2 ;
|
||||
variables:
|
||||
string v1 ;
|
||||
string v2(d1) ;
|
||||
string v3(d2, d2) ;
|
||||
data:
|
||||
|
||||
v1 = NIL ;
|
||||
|
||||
v2 = NIL ;
|
||||
|
||||
v3 =
|
||||
NIL, NIL,
|
||||
NIL, NIL ;
|
||||
}
|
48
ncdump/expected4/ref_tst_h_scalar.dmp
Normal file
48
ncdump/expected4/ref_tst_h_scalar.dmp
Normal file
@ -0,0 +1,48 @@
|
||||
netcdf ref_tst_h_scalar {
|
||||
variables:
|
||||
string vstrvar1 ;
|
||||
string vstrvar1:vstratt1 = NIL ;
|
||||
string vstrvar1:vstratt2 = NIL ;
|
||||
string vstrvar1:vstratt3 = "" ;
|
||||
string vstrvar1:vstratt4 = "foo" ;
|
||||
vstrvar1:fstratt = "" ;
|
||||
vstrvar1:intatt = 0 ;
|
||||
string fstrvar ;
|
||||
string fstrvar:vstratt1 = NIL ;
|
||||
string fstrvar:vstratt2 = NIL ;
|
||||
string fstrvar:vstratt3 = "" ;
|
||||
string fstrvar:vstratt4 = "foo" ;
|
||||
fstrvar:fstratt = "" ;
|
||||
fstrvar:intatt = 0 ;
|
||||
int intvar ;
|
||||
string intvar:vstratt1 = NIL ;
|
||||
string intvar:vstratt2 = NIL ;
|
||||
string intvar:vstratt3 = "" ;
|
||||
string intvar:vstratt4 = "foo" ;
|
||||
intvar:fstratt = "" ;
|
||||
intvar:intatt = 0 ;
|
||||
string vstrvar2 ;
|
||||
string vstrvar3 ;
|
||||
string vstrvar4 ;
|
||||
|
||||
// global attributes:
|
||||
string :vstratt1 = NIL ;
|
||||
string :vstratt2 = NIL ;
|
||||
string :vstratt3 = "" ;
|
||||
string :vstratt4 = "foo" ;
|
||||
:fstratt = "" ;
|
||||
:intatt = 0 ;
|
||||
data:
|
||||
|
||||
vstrvar1 = NIL ;
|
||||
|
||||
fstrvar = _ ;
|
||||
|
||||
intvar = 0 ;
|
||||
|
||||
vstrvar2 = NIL ;
|
||||
|
||||
vstrvar3 = _ ;
|
||||
|
||||
vstrvar4 = "foo" ;
|
||||
}
|
@ -489,7 +489,10 @@ pr_att_valgs(
|
||||
break;
|
||||
case NC_STRING:
|
||||
stringp = ((char **) vals)[iel];
|
||||
pr_att_string(kind, strlen(stringp), stringp);
|
||||
if(stringp)
|
||||
pr_att_string(kind, strlen(stringp), stringp);
|
||||
else
|
||||
printf("NIL");
|
||||
printf("%s", delim);
|
||||
break;
|
||||
#endif /* USE_NETCDF4 */
|
||||
|
223
ncdump/tst_h_scalar.c
Normal file
223
ncdump/tst_h_scalar.c
Normal file
@ -0,0 +1,223 @@
|
||||
/* This is part of the netCDF package. Copyright 2013 University
|
||||
Corporation for Atmospheric Research/Unidata See COPYRIGHT file for
|
||||
conditions of use.
|
||||
|
||||
This program sets up HDF5 files that contain scalar attributes and
|
||||
variables, of both string and numeric datatypes. ncdump should handle
|
||||
all of these.
|
||||
*/
|
||||
|
||||
#include <nc_tests.h>
|
||||
#include <hdf5.h>
|
||||
|
||||
#define FILE_NAME "tst_h_scalar.nc"
|
||||
#define VSTR_ATT1_NAME "vstratt1"
|
||||
#define VSTR_ATT2_NAME "vstratt2"
|
||||
#define VSTR_ATT3_NAME "vstratt3"
|
||||
#define VSTR_ATT4_NAME "vstratt4"
|
||||
#define VSTR_VAR1_NAME "vstrvar1"
|
||||
#define VSTR_VAR2_NAME "vstrvar2"
|
||||
#define VSTR_VAR3_NAME "vstrvar3"
|
||||
#define VSTR_VAR4_NAME "vstrvar4"
|
||||
#define FSTR_ATT_NAME "fstratt"
|
||||
#define FSTR_VAR_NAME "fstrvar"
|
||||
#define INT_ATT_NAME "intatt"
|
||||
#define INT_VAR_NAME "intvar"
|
||||
|
||||
int
|
||||
add_attrs(hid_t objid)
|
||||
{
|
||||
hid_t scalar_spaceid = -1;
|
||||
hid_t vlstr_typeid = -1, fixstr_typeid = -1;
|
||||
char *vlstr;
|
||||
hid_t attid = -1;
|
||||
|
||||
/* Create scalar dataspace */
|
||||
if ((scalar_spaceid = H5Screate(H5S_SCALAR)) < 0) ERR_GOTO;
|
||||
|
||||
/* Create string datatypes */
|
||||
if ((vlstr_typeid = H5Tcreate(H5T_STRING, (size_t)H5T_VARIABLE)) < 0) ERR_GOTO;
|
||||
if ((fixstr_typeid = H5Tcreate(H5T_STRING, (size_t)10)) < 0) ERR_GOTO;
|
||||
|
||||
|
||||
/* Create attribute with VL string datatype on object */
|
||||
if ((attid = H5Acreate2(objid, VSTR_ATT1_NAME, vlstr_typeid, scalar_spaceid, H5P_DEFAULT, H5P_DEFAULT)) < 0) ERR_GOTO;
|
||||
/* No write, use fill value */
|
||||
if (H5Aclose(attid) < 0) ERR_GOTO;
|
||||
|
||||
/* Create attribute with VL string datatype on object */
|
||||
if ((attid = H5Acreate2(objid, VSTR_ATT2_NAME, vlstr_typeid, scalar_spaceid, H5P_DEFAULT, H5P_DEFAULT)) < 0) ERR_GOTO;
|
||||
vlstr = NULL;
|
||||
if (H5Awrite(attid, vlstr_typeid, &vlstr) < 0) ERR_GOTO;
|
||||
if (H5Aclose(attid) < 0) ERR_GOTO;
|
||||
|
||||
/* Create attribute with VL string datatype on object */
|
||||
if ((attid = H5Acreate2(objid, VSTR_ATT3_NAME, vlstr_typeid, scalar_spaceid, H5P_DEFAULT, H5P_DEFAULT)) < 0) ERR_GOTO;
|
||||
vlstr = malloc(10);
|
||||
*vlstr = '\0';
|
||||
if (H5Awrite(attid, vlstr_typeid, &vlstr) < 0) ERR_GOTO;
|
||||
if (H5Aclose(attid) < 0) ERR_GOTO;
|
||||
|
||||
/* Create attribute with VL string datatype on object */
|
||||
if ((attid = H5Acreate2(objid, VSTR_ATT4_NAME, vlstr_typeid, scalar_spaceid, H5P_DEFAULT, H5P_DEFAULT)) < 0) ERR_GOTO;
|
||||
strcpy(vlstr, "foo");
|
||||
if (H5Awrite(attid, vlstr_typeid, &vlstr) < 0) ERR_GOTO;
|
||||
free(vlstr);
|
||||
if (H5Aclose(attid) < 0) ERR_GOTO;
|
||||
|
||||
/* Create attribute with fixed-length string datatype on object */
|
||||
if ((attid = H5Acreate2(objid, FSTR_ATT_NAME, fixstr_typeid, scalar_spaceid, H5P_DEFAULT, H5P_DEFAULT)) < 0) ERR_GOTO;
|
||||
if (H5Aclose(attid) < 0) ERR_GOTO;
|
||||
|
||||
/* Create attribute with native integer datatype on object */
|
||||
if ((attid = H5Acreate2(objid, INT_ATT_NAME, H5T_NATIVE_INT, scalar_spaceid, H5P_DEFAULT, H5P_DEFAULT)) < 0) ERR_GOTO;
|
||||
if (H5Aclose(attid) < 0) ERR_GOTO;
|
||||
|
||||
|
||||
/* Clean up objects created */
|
||||
if (H5Sclose(scalar_spaceid) < 0) ERR_GOTO;
|
||||
if (H5Tclose(vlstr_typeid) < 0) ERR_GOTO;
|
||||
if (H5Tclose(fixstr_typeid) < 0) ERR_GOTO;
|
||||
|
||||
return(0);
|
||||
|
||||
error:
|
||||
H5E_BEGIN_TRY {
|
||||
H5Aclose(attid);
|
||||
H5Sclose(scalar_spaceid);
|
||||
H5Tclose(vlstr_typeid);
|
||||
H5Tclose(fixstr_typeid);
|
||||
} H5E_END_TRY;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
printf("\n*** Create file with datasets & attributes that have scalar dataspaces...");
|
||||
{
|
||||
hid_t fileid;
|
||||
hid_t fcplid;
|
||||
hid_t dsetid;
|
||||
hid_t dcplid;
|
||||
hid_t scalar_spaceid;
|
||||
hid_t vlstr_typeid, fixstr_typeid;
|
||||
hid_t attid;
|
||||
|
||||
/* Create scalar dataspace */
|
||||
if ((scalar_spaceid = H5Screate(H5S_SCALAR)) < 0) ERR;
|
||||
|
||||
/* Set creation ordering for file, so we can revise its contents later */
|
||||
if ((fcplid = H5Pcreate(H5P_FILE_CREATE)) < 0) ERR;
|
||||
if (H5Pset_link_creation_order(fcplid, H5P_CRT_ORDER_TRACKED) < 0) ERR;
|
||||
if (H5Pset_attr_creation_order(fcplid, H5P_CRT_ORDER_TRACKED) < 0) ERR;
|
||||
|
||||
/* Create new file, using default properties */
|
||||
if ((fileid = H5Fcreate(FILE_NAME, H5F_ACC_TRUNC, fcplid, H5P_DEFAULT)) < 0) ERR;
|
||||
|
||||
/* Close file creation property list */
|
||||
if (H5Pclose(fcplid) < 0) ERR;
|
||||
|
||||
|
||||
/* Create variable-length string datatype */
|
||||
if ((vlstr_typeid = H5Tcreate(H5T_STRING, (size_t)H5T_VARIABLE)) < 0) ERR;
|
||||
|
||||
/* Create fixed-length string datatype */
|
||||
if ((fixstr_typeid = H5Tcreate(H5T_STRING, (size_t)10)) < 0) ERR;
|
||||
|
||||
|
||||
/* Set creation ordering for dataset, so we can revise its contents later */
|
||||
if ((dcplid = H5Pcreate(H5P_DATASET_CREATE)) < 0) ERR;
|
||||
if (H5Pset_attr_creation_order(dcplid, H5P_CRT_ORDER_TRACKED) < 0) ERR;
|
||||
|
||||
|
||||
/* Create scalar dataset with VL string datatype */
|
||||
if ((dsetid = H5Dcreate2(fileid, VSTR_VAR1_NAME, vlstr_typeid, scalar_spaceid, H5P_DEFAULT, dcplid, H5P_DEFAULT)) < 0) ERR;
|
||||
|
||||
/* Add attributes to dataset */
|
||||
if (add_attrs(dsetid) < 0) ERR;
|
||||
|
||||
/* Close VL string dataset */
|
||||
if (H5Dclose(dsetid) < 0) ERR;
|
||||
|
||||
|
||||
/* Create scalar dataset with fixed-length string datatype */
|
||||
if ((dsetid = H5Dcreate2(fileid, FSTR_VAR_NAME, fixstr_typeid, scalar_spaceid, H5P_DEFAULT, dcplid, H5P_DEFAULT)) < 0) ERR;
|
||||
|
||||
/* Add attributes to dataset */
|
||||
if (add_attrs(dsetid) < 0) ERR;
|
||||
|
||||
/* Close fixed-length string dataset */
|
||||
if (H5Dclose(dsetid) < 0) ERR;
|
||||
|
||||
|
||||
/* Create scalar dataset with native integer datatype */
|
||||
if ((dsetid = H5Dcreate2(fileid, INT_VAR_NAME, H5T_NATIVE_INT, scalar_spaceid, H5P_DEFAULT, dcplid, H5P_DEFAULT)) < 0) ERR;
|
||||
|
||||
/* Add attributes to dataset */
|
||||
if (add_attrs(dsetid) < 0) ERR;
|
||||
|
||||
/* Close native integer dataset */
|
||||
if (H5Dclose(dsetid) < 0) ERR;
|
||||
|
||||
|
||||
/* Add attributes to root group */
|
||||
if (add_attrs(fileid) < 0) ERR;
|
||||
|
||||
|
||||
/* Close dataset creation property list */
|
||||
if (H5Pclose(dcplid) < 0) ERR;
|
||||
|
||||
/* Close string datatypes */
|
||||
if (H5Tclose(vlstr_typeid) < 0) ERR;
|
||||
if (H5Tclose(fixstr_typeid) < 0) ERR;
|
||||
|
||||
|
||||
/* Close rest */
|
||||
if (H5Sclose(scalar_spaceid) < 0) ERR;
|
||||
if (H5Fclose(fileid) < 0) ERR;
|
||||
}
|
||||
SUMMARIZE_ERR;
|
||||
|
||||
printf("*** Revise file through netCDF-4 API...");
|
||||
{
|
||||
int ncid, varid;
|
||||
int ret;
|
||||
char *vlstr;
|
||||
|
||||
if (nc_open(FILE_NAME, NC_WRITE, &ncid)) ERR;
|
||||
|
||||
|
||||
/* Define new VL string variable */
|
||||
if (nc_def_var(ncid, VSTR_VAR2_NAME , NC_STRING, 0, NULL, &varid)) ERR;
|
||||
|
||||
/* Write to the variable */
|
||||
vlstr = NULL;
|
||||
if (nc_put_var(ncid, varid, &vlstr)) ERR;
|
||||
|
||||
|
||||
/* Define new VL string variable */
|
||||
if (nc_def_var(ncid, VSTR_VAR3_NAME , NC_STRING, 0, NULL, &varid)) ERR;
|
||||
|
||||
/* Write to the variable */
|
||||
vlstr = malloc(10);
|
||||
*vlstr = '\0';
|
||||
if (nc_put_var(ncid, varid, &vlstr)) ERR;
|
||||
|
||||
|
||||
/* Define new VL string variable */
|
||||
if (nc_def_var(ncid, VSTR_VAR4_NAME , NC_STRING, 0, NULL, &varid)) ERR;
|
||||
|
||||
/* Write to the variable */
|
||||
strcpy(vlstr, "foo");
|
||||
if (nc_put_var(ncid, varid, &vlstr)) ERR;
|
||||
free(vlstr);
|
||||
|
||||
|
||||
if (nc_close(ncid)) ERR;
|
||||
}
|
||||
SUMMARIZE_ERR;
|
||||
|
||||
FINAL_RESULTS;
|
||||
}
|
||||
|
15
ncdump/tst_h_scalar.sh
Executable file
15
ncdump/tst_h_scalar.sh
Executable file
@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
# This shell script runs ncdump to verify scalar attribute and variable output
|
||||
|
||||
set -e
|
||||
echo ""
|
||||
echo "*** Running ncdump scalar test."
|
||||
|
||||
# echo "*** dumping tst_h_scalar.nc to tst_h_scalar.cdl..."
|
||||
./ncdump tst_h_scalar.nc > tst_h_scalar.cdl
|
||||
# echo "*** comparing tst_h_scalar.cdl with ref_tst_h_scalar.cdl..."
|
||||
diff -b tst_h_scalar.cdl $srcdir/cdl4/ref_tst_h_scalar.cdl
|
||||
|
||||
echo "*** All ncdump scalar test output for netCDF-4 format passed!"
|
||||
exit 0
|
||||
|
@ -2,6 +2,15 @@
|
||||
verbose=1
|
||||
set -e
|
||||
|
||||
# To add a new test,
|
||||
# 1. put the .cdl file in the 'cdl4' directory
|
||||
# 2. put the result of running ncgen then ncdump
|
||||
# into the directory 'expected4' as .dmp
|
||||
# 3. Modify the file tst_ncgen4_shared.sh to add
|
||||
# the test to the end of the TESTS4 variable
|
||||
# 4. Add the new files into cdl4/Makfile.am
|
||||
# and expected4/Makefile.am
|
||||
|
||||
if test "x$builddir" = "x"; then builddir=`pwd`; fi
|
||||
if test "x$srcdir" = "x"; then srcdir=`dirname $0`; fi
|
||||
|
||||
|
@ -1,5 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
# To add a new test,
|
||||
# 1. put the .cdl file in the 'cdl4' directory
|
||||
# 2. put the result of running ncgen then ncdump
|
||||
# into the directory 'expected4' as .dmp
|
||||
# 3. Modify the file tst_ncgen4_shared.sh to add
|
||||
# the test to the end of the TESTS4 variable
|
||||
# 4. Add the new files into cdl4/Makfile.am
|
||||
# and expected4/Makefile.am
|
||||
|
||||
set -e
|
||||
RESULTSDIR="./results"
|
||||
#SHOWXFAILS=1
|
||||
@ -79,6 +88,8 @@ unlimtest2 \
|
||||
ref_tst_vlen_data \
|
||||
ref_tst_vlen_data \
|
||||
ref_tst_vlen_data2 \
|
||||
ref_niltest \
|
||||
ref_tst_h_scalar \
|
||||
"
|
||||
|
||||
SPECIALTESTS3="ref_tst_special_atts3"
|
||||
|
10
ncgen/Make0
10
ncgen/Make0
@ -1,9 +1,13 @@
|
||||
# Test c output
|
||||
T=z
|
||||
T=niltest
|
||||
#VG=valgrind --leak-check=full
|
||||
|
||||
CFLAGS=-I../include -I/share/ed/local/spock/include
|
||||
LDFLAGS=../liblib/.libs/libnetcdf.a -L/share/ed/local/spock/lib -lhdf5_hl -lhdf5 -lz -lcurl -lm -llber -lldap -lrt -lssl -lcrypto -ldl
|
||||
#STDLIB=/usr/local
|
||||
STDLIB=/share/ed/local/${HOST}
|
||||
|
||||
CFLAGS=-I../include -I${STDLIB}/include
|
||||
LDFLAGS=../liblib/.libs/libnetcdf.a -L${STDLIB}/lib -lhdf5_hl -lhdf5 -lz -lm -lcurl
|
||||
# -lcurl -lm -llber -lldap -lrt -lssl -lcrypto -ldl
|
||||
|
||||
CLASSPATH=".:ncCore-4.2.jar"
|
||||
|
||||
|
@ -76,14 +76,20 @@ bin_constant(Generator* generator, Constant* con, Bytebuffer* buf,...)
|
||||
su64.i64 = con->value.uint64v;
|
||||
bbAppendn(buf,(void*)su64.ch,sizeof(su64.ch));
|
||||
} break;
|
||||
case NC_NIL:
|
||||
case NC_STRING: {
|
||||
char* ptr;
|
||||
int len = (size_t)con->value.stringv.len;
|
||||
ptr = (char*)malloc(len+1);
|
||||
memcpy(ptr,con->value.stringv.stringv,len);
|
||||
ptr[len] = '\0';
|
||||
bbAppendn(buf,(void*)&ptr,sizeof(ptr));
|
||||
} break;
|
||||
if(len == 0 && con->value.stringv.stringv == NULL) {
|
||||
char* nil = NULL;
|
||||
bbAppendn(buf,(void*)&nil,sizeof(nil));
|
||||
} else {
|
||||
ptr = (char*)malloc(len+1);
|
||||
memcpy(ptr,con->value.stringv.stringv,len);
|
||||
ptr[len] = '\0';
|
||||
bbAppendn(buf,(void*)&ptr,sizeof(ptr));
|
||||
}
|
||||
} break;
|
||||
|
||||
default: PANIC1("bin_constant: unexpected type: %d",con->nctype);
|
||||
}
|
||||
|
@ -81,13 +81,19 @@ c_constant(Generator* generator, Constant* con, Bytebuffer* buf,...)
|
||||
case NC_ECONST:
|
||||
bbprintf(codetmp,"%s",cname(con->value.enumv));
|
||||
break;
|
||||
case NC_NIL:
|
||||
case NC_STRING: { /* handle separately */
|
||||
char* escaped = escapify(con->value.stringv.stringv,
|
||||
if(con->value.stringv.len == 0 && con->value.stringv.stringv == NULL) {
|
||||
char* nil = NULL;
|
||||
bbprintf(codetmp,"NULL");
|
||||
} else {
|
||||
char* escaped = escapify(con->value.stringv.stringv,
|
||||
'"',con->value.stringv.len);
|
||||
special = poolalloc(1+2+strlen(escaped));
|
||||
strcpy(special,"\"");
|
||||
strcat(special,escaped);
|
||||
strcat(special,"\"");
|
||||
special = poolalloc(1+2+strlen(escaped));
|
||||
strcpy(special,"\"");
|
||||
strcat(special,escaped);
|
||||
strcat(special,"\"");
|
||||
}
|
||||
} break;
|
||||
case NC_OPAQUE: {
|
||||
char* p;
|
||||
|
@ -540,6 +540,12 @@ case CASE(NC_OPAQUE,NC_OPAQUE):
|
||||
tmp.opaquev.len = src->value.opaquev.len;
|
||||
tmp.opaquev.stringv[tmp.opaquev.len] = '\0';
|
||||
break;
|
||||
case CASE(NC_NIL,NC_NIL):
|
||||
break; /* probably will never happen */
|
||||
case CASE(NC_NIL,NC_STRING):
|
||||
tmp.stringv.len = 0;
|
||||
tmp.stringv.stringv = NULL;
|
||||
break;
|
||||
|
||||
/* We are missing all CASE(X,NC_ECONST) cases*/
|
||||
|
||||
|
@ -18,6 +18,8 @@ extern int lvsnprintf(char*, size_t, const char*, va_list);
|
||||
Constant nullconstant;
|
||||
Constant fillconstant;
|
||||
|
||||
Datalist nildatalist; // to support NIL keyword
|
||||
|
||||
Bytebuffer* codebuffer;
|
||||
Bytebuffer* codetmp;
|
||||
Bytebuffer* stmt;
|
||||
|
@ -120,6 +120,8 @@ int srcline(Datasrc* ds);
|
||||
#define isfillconst(con) ((con)!=NULL && (con)->nctype == NC_FILLVALUE)
|
||||
#define constline(con) (con==NULL?0:(con)->lineno)
|
||||
|
||||
#define isnilconst(con) ((con)!=NULL && (con)->nctype == NC_NIL)
|
||||
|
||||
Constant* emptystringconst(int,Constant*);
|
||||
|
||||
Constant cloneconstant(Constant* con); /* shallow clone*/
|
||||
@ -157,6 +159,7 @@ Constant* srcpeek(Datasrc*);
|
||||
|
||||
extern Constant nullconstant;
|
||||
extern Constant fillconstant;
|
||||
extern Constant nilconstant;
|
||||
|
||||
/* From genchar.c */
|
||||
void gen_charattr(Datalist*, Bytebuffer*);
|
||||
|
@ -1,7 +1,7 @@
|
||||
# test: ../ncdump/cdl4/ref_const_test.cdl
|
||||
# test: ../ncdump/cdl4/ref_tst_chardata.cdl
|
||||
K="-k3"
|
||||
F="fail.cdl"
|
||||
F="niltest.cdl"
|
||||
#B="-B12"
|
||||
DBG="-d"
|
||||
#DBG="-D2"
|
||||
|
@ -455,11 +455,11 @@ genbin_writeattr(Generator* generator, Symbol* asym, Bytebuffer* databuf,
|
||||
} break;
|
||||
#ifdef USE_NETCDF4
|
||||
case NC_STRING: {
|
||||
const char** data;
|
||||
const char** data;
|
||||
data = (const char**)bbContents(databuf);
|
||||
stat = nc_put_att_string(grpid,varid,asym->name,
|
||||
bbLength(databuf)/sizeof(char*),
|
||||
data);
|
||||
bbLength(databuf)/sizeof(char*),
|
||||
data);
|
||||
} break;
|
||||
case NC_UBYTE: {
|
||||
unsigned char* data = (unsigned char*)bbContents(databuf);
|
||||
|
45
ncgen/genc.c
45
ncgen/genc.c
@ -948,18 +948,18 @@ genc_writevar(Generator* generator, Symbol* vsym, Bytebuffer* code,
|
||||
}
|
||||
|
||||
if(rank == 0) {
|
||||
codelined(1,"size_t zero = 0;");
|
||||
codelined(1,"size_t count = 0;");
|
||||
/* We make the data be an array so we do not need to
|
||||
ampersand it later => we need an outer pair of braces
|
||||
*/
|
||||
commify(code); /* insert commas at proper places */
|
||||
bbprintf0(stmt,"%sstatic %s %s_data[1] = {%s};\n",
|
||||
commify(code); /* insert commas at proper places */
|
||||
bbprintf0(stmt,"%sstatic %s %s_data[1] = {%s};\n",
|
||||
indented(1),
|
||||
ctypename(basetype),
|
||||
cname(vsym),
|
||||
bbContents(code));
|
||||
codedump(stmt);
|
||||
bbprintf0(stmt,"%sstat = nc_put_var1(%s, %s, &zero, %s_data);\n",
|
||||
bbprintf0(stmt,"%sstat = nc_put_var1(%s, %s, &count, %s_data);\n",
|
||||
indented(1),
|
||||
groupncid(vsym->container),
|
||||
varncid(vsym),
|
||||
@ -1055,27 +1055,26 @@ genc_writeattr(Generator* generator, Symbol* asym, Bytebuffer* code,
|
||||
cquotestring(code,'"');
|
||||
} else {
|
||||
/* All other cases */
|
||||
/* Dump any vlen decls first */
|
||||
List* vlendecls;
|
||||
generator_getstate(generator,(void**)&vlendecls);
|
||||
if(vlendecls != NULL && listlength(vlendecls) > 0) {
|
||||
int i;
|
||||
for(i=0;i<listlength(vlendecls);i++) {
|
||||
Bytebuffer* decl = (Bytebuffer*)listget(vlendecls,i);
|
||||
codelined(1,bbContents(decl));
|
||||
bbFree(decl);
|
||||
}
|
||||
listfree(vlendecls);
|
||||
generator_reset(generator,NULL);
|
||||
}
|
||||
|
||||
/* Dump any vlen decls first */
|
||||
List* vlendecls;
|
||||
generator_getstate(generator,(void**)&vlendecls);
|
||||
if(vlendecls != NULL && listlength(vlendecls) > 0) {
|
||||
int i;
|
||||
for(i=0;i<listlength(vlendecls);i++) {
|
||||
Bytebuffer* decl = (Bytebuffer*)listget(vlendecls,i);
|
||||
codelined(1,bbContents(decl));
|
||||
bbFree(decl);
|
||||
}
|
||||
listfree(vlendecls);
|
||||
generator_reset(generator,NULL);
|
||||
}
|
||||
commify(code);
|
||||
bbprintf0(stmt,"%sstatic const %s %s_att[%ld] = ",
|
||||
indented(1),
|
||||
ctypename(basetype),
|
||||
cname(asym),
|
||||
asym->data->length
|
||||
);
|
||||
indented(1),
|
||||
ctypename(basetype),
|
||||
cname(asym),
|
||||
asym->data->length
|
||||
);
|
||||
codedump(stmt);
|
||||
codepartial("{");
|
||||
codedump(code);
|
||||
|
@ -58,7 +58,7 @@ generate_attrdata(Symbol* asym, Generator* generator, Writer writer, Bytebuffer*
|
||||
Symbol* basetype = asym->typ.basetype;
|
||||
nc_type typecode = basetype->typ.typecode;
|
||||
|
||||
if(typecode == NC_CHAR) {
|
||||
if(typecode == NC_CHAR) {
|
||||
gen_charattr(asym->data,codebuf);
|
||||
} else {
|
||||
int uid;
|
||||
|
@ -359,6 +359,9 @@ distinguished variable attribute named `_FillValue'. The
|
||||
types of constants need not match the type declared for a variable;
|
||||
coercions are done to convert integers to floating point, for example.
|
||||
The constant `_' can be used to designate the fill value for a variable.
|
||||
If the type of the variable is explicitly `string', then the special
|
||||
constant `NIL` can be used to represent a nil string, which is not the
|
||||
same as a zero length string.
|
||||
.SS "Primitive Data Types"
|
||||
.LP
|
||||
.RS
|
||||
@ -594,6 +597,8 @@ type to ensure the proper choice.
|
||||
String constants are assumed to always be UTF-8 encoded. This
|
||||
specifically means that the string constant may actually
|
||||
contain multi-byte UTF-8 characters.
|
||||
The special constant `NIL` can be used to represent a nil string, which is not the
|
||||
same as a zero length string.
|
||||
.LP
|
||||
\fIOpaque\fP constants are represented as
|
||||
sequences of hexadecimal digits preceded by 0X or 0x: 0xaa34ffff,
|
||||
@ -646,24 +651,25 @@ The type being referenced (t1) is the one within group g2, which in
|
||||
turn is nested in group g1.
|
||||
The similarity of this notation to Unix file paths is deliberate,
|
||||
and one can consider groups as a form of directory structure.
|
||||
.HP
|
||||
1. When name is not prefixed, then scope rules are applied to locate the
|
||||
.LP
|
||||
When name is not prefixed, then scope rules are applied to locate the
|
||||
specified declaration. Currently, there are three rules: one for dimensions,
|
||||
one for types and enumeration constants, and one for all others.
|
||||
.HP
|
||||
2. When an unprefixed name of a dimension is used (as in a variable declaration),
|
||||
ncgen first looks in the immediately enclosing group for the dimension.
|
||||
If it is not found there, then it looks in the group enclosing this group.
|
||||
This continues up the group hierarchy until the dimension is found,
|
||||
or there are no more groups to search.
|
||||
1. When an unprefixed name of a dimension is used (as in a
|
||||
variable declaration), ncgen first looks in the immediately
|
||||
enclosing group for the dimension. If it is not found
|
||||
there, then it looks in the group enclosing this group.
|
||||
This continues up the group hierarchy until the dimension is
|
||||
found, or there are no more groups to search.
|
||||
.HP
|
||||
3. For all other names, only the immediately enclosing group is searched.
|
||||
.LP
|
||||
When an unprefixed name of a type or an enumeration constant
|
||||
2. When an unprefixed name of a type or an enumeration constant
|
||||
is used, ncgen searches the group tree using a pre-order depth-first
|
||||
search. This essentially means that it will find the matching declaration
|
||||
that precedes the reference textually in the cdl file and that
|
||||
is "highest" in the group hierarchy.
|
||||
.HP
|
||||
3. For all other names, only the immediately enclosing group is searched.
|
||||
.LP
|
||||
One final note. Forward references are not allowed.
|
||||
This means that specifying, for example,
|
||||
|
@ -41,7 +41,9 @@
|
||||
#define NC_LIST NC_COMPOUND /* alias */
|
||||
|
||||
/* Extend nc types with generic fill value*/
|
||||
#define NC_FILLVALUE 31
|
||||
#define NC_FILLVALUE 31
|
||||
/* Extend nc types with NIL value*/
|
||||
#define NC_NIL 32
|
||||
|
||||
/* Must be a better way to do this */
|
||||
#ifndef INFINITE
|
||||
|
@ -258,6 +258,16 @@ NaNf|nanf { /* missing value (pre-2.4 backward compatibility) */
|
||||
return lexdebug(FLOAT_CONST);
|
||||
}
|
||||
|
||||
NIL|nil|Nil {
|
||||
#ifdef USE_NETCDF4
|
||||
if(c_flag != 0 || binary_flag != 0)
|
||||
return lexdebug(NIL);
|
||||
yyerror("NIL only allowed for netcdf-4 and for -lc or -lb");
|
||||
#else
|
||||
yyerror("NIL only allowed for netcdf-4 and for -lc or -lb");
|
||||
#endif
|
||||
}
|
||||
|
||||
{PATH} {
|
||||
bbClear(lextext);
|
||||
bbAppendn(lextext,(char*)yytext,yyleng+1); /* include null */
|
||||
|
@ -162,7 +162,7 @@ Constant constant;
|
||||
UINT_CONST /* unsigned long long constant */
|
||||
UINT64_CONST /* unsigned int constant */
|
||||
FLOAT_CONST /* float constant */
|
||||
DOUBLE_CONST /* double constant */
|
||||
DOUBLE_CONST/* double constant */
|
||||
DIMENSIONS /* keyword starting dimensions section, if any */
|
||||
VARIABLES /* keyword starting variables section, if any */
|
||||
NETCDF /* keyword declaring netcdf name */
|
||||
@ -175,6 +175,7 @@ Constant constant;
|
||||
GROUP
|
||||
PATH /* / or (/IDENT)+ */
|
||||
FILLMARKER /* "_" as opposed to the attribute */
|
||||
NIL /* NIL */
|
||||
_FILLVALUE
|
||||
_FORMAT
|
||||
_STORAGE
|
||||
@ -805,6 +806,7 @@ constdata:
|
||||
simpleconstant {$$=$1;}
|
||||
| OPAQUESTRING {$$=makeconstdata(NC_OPAQUE);}
|
||||
| FILLMARKER {$$=makeconstdata(NC_FILLVALUE);}
|
||||
| NIL {$$=makeconstdata(NC_NIL);}
|
||||
| path {$$=makeenumconst($1);}
|
||||
| function
|
||||
;
|
||||
@ -1042,11 +1044,14 @@ makeconstdata(nc_type nctype)
|
||||
con.value.opaquev.stringv = s;
|
||||
con.value.opaquev.len = len;
|
||||
} break;
|
||||
|
||||
case NC_NIL:
|
||||
break; /* no associated value*/
|
||||
#endif
|
||||
|
||||
case NC_FILLVALUE:
|
||||
break; /* no associated value*/
|
||||
|
||||
|
||||
default:
|
||||
yyerror("Data constant: unexpected NC type: %s",
|
||||
nctypename(nctype));
|
||||
|
822
ncgen/ncgentab.c
822
ncgen/ncgentab.c
File diff suppressed because it is too large
Load Diff
@ -83,16 +83,17 @@ extern int ncgdebug;
|
||||
GROUP = 292,
|
||||
PATH = 293,
|
||||
FILLMARKER = 294,
|
||||
_FILLVALUE = 295,
|
||||
_FORMAT = 296,
|
||||
_STORAGE = 297,
|
||||
_CHUNKSIZES = 298,
|
||||
_DEFLATELEVEL = 299,
|
||||
_SHUFFLE = 300,
|
||||
_ENDIANNESS = 301,
|
||||
_NOFILL = 302,
|
||||
_FLETCHER32 = 303,
|
||||
DATASETID = 304
|
||||
NIL = 295,
|
||||
_FILLVALUE = 296,
|
||||
_FORMAT = 297,
|
||||
_STORAGE = 298,
|
||||
_CHUNKSIZES = 299,
|
||||
_DEFLATELEVEL = 300,
|
||||
_SHUFFLE = 301,
|
||||
_ENDIANNESS = 302,
|
||||
_NOFILL = 303,
|
||||
_FLETCHER32 = 304,
|
||||
DATASETID = 305
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -112,7 +113,7 @@ Constant constant;
|
||||
|
||||
|
||||
/* Line 2077 of yacc.c */
|
||||
#line 116 "ncgen.tab.h"
|
||||
#line 117 "ncgen.tab.h"
|
||||
} YYSTYPE;
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
|
||||
|
1242
ncgen/ncgenyy.c
1242
ncgen/ncgenyy.c
File diff suppressed because it is too large
Load Diff
@ -20,8 +20,8 @@ static void processspecials(void);
|
||||
static void processunlimiteddims(void);
|
||||
|
||||
static void inferattributetype(Symbol* asym);
|
||||
static void validateNIL(Symbol* sym);
|
||||
static void checkconsistency(void);
|
||||
static void validate(void);
|
||||
static int tagvlentypes(Symbol* tsym);
|
||||
|
||||
static Symbol* uniquetreelocate(Symbol* refsym, Symbol* root);
|
||||
@ -53,8 +53,6 @@ processsemantics(void)
|
||||
processunlimiteddims();
|
||||
/* check internal consistency*/
|
||||
checkconsistency();
|
||||
/* do any needed additional semantic checks*/
|
||||
validate();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -438,6 +436,8 @@ processvars(void)
|
||||
Symbol* basetype = vsym->typ.basetype;
|
||||
/* fill in the typecode*/
|
||||
vsym->typ.typecode = basetype->typ.typecode;
|
||||
/* validate uses of NIL */
|
||||
validateNIL(vsym);
|
||||
for(j=0;j<vsym->typ.dimset.ndims;j++) {
|
||||
/* validate the dimensions*/
|
||||
/* UNLIMITED must only be in first place if using classic */
|
||||
@ -583,29 +583,24 @@ processattributes(void)
|
||||
/* process global attributes*/
|
||||
for(i=0;i<listlength(gattdefs);i++) {
|
||||
Symbol* asym = (Symbol*)listget(gattdefs,i);
|
||||
/* If the attribute has a zero length, then default it */
|
||||
if(asym->data == NULL || asym->data->length == 0) {
|
||||
asym->data = builddatalist(1);
|
||||
emptystringconst(asym->lineno,&asym->data->data[asym->data->length]);
|
||||
/* force type to be NC_CHAR */
|
||||
asym->typ.basetype = primsymbols[NC_CHAR];
|
||||
}
|
||||
if(asym->typ.basetype == NULL) inferattributetype(asym);
|
||||
/* fill in the typecode*/
|
||||
asym->typ.typecode = asym->typ.basetype->typ.typecode;
|
||||
if(asym->data->length == 0) {
|
||||
/* If the attribute has a zero length, then default it;
|
||||
note that it must be of type NC_CHAR */
|
||||
if(asym->typ.typecode != NC_CHAR)
|
||||
semerror(asym->lineno,"Empty datalist can only be assigned to attributes of type char",fullname(asym));
|
||||
asym->data = builddatalist(1);
|
||||
emptystringconst(asym->lineno,&asym->data->data[asym->data->length]);
|
||||
}
|
||||
validateNIL(asym);
|
||||
}
|
||||
/* process per variable attributes*/
|
||||
for(i=0;i<listlength(attdefs);i++) {
|
||||
Symbol* asym = (Symbol*)listget(attdefs,i);
|
||||
/* If the attribute has a zero length, then default it */
|
||||
if(asym->data == NULL || asym->data->length == 0) {
|
||||
asym->data = builddatalist(1);
|
||||
emptystringconst(asym->lineno,&asym->data->data[asym->data->length]);
|
||||
/* force type to be NC_CHAR */
|
||||
asym->typ.basetype = primsymbols[NC_CHAR];
|
||||
}
|
||||
/* If no basetype is specified, then try to infer it;
|
||||
the exception if _Fillvalue, whose type is that of the
|
||||
the exception is _Fillvalue, whose type is that of the
|
||||
containing variable.
|
||||
*/
|
||||
if(strcmp(asym->name,specialname(_FILLVALUE_FLAG)) == 0) {
|
||||
@ -622,6 +617,14 @@ processattributes(void)
|
||||
}
|
||||
/* fill in the typecode*/
|
||||
asym->typ.typecode = asym->typ.basetype->typ.typecode;
|
||||
if(asym->data->length == 0) {
|
||||
/* If the attribute has a zero length, and is char type, then default it */
|
||||
if(asym->typ.typecode != NC_CHAR)
|
||||
semerror(asym->lineno,"Empty datalist can only be assigned to attributes of type char",fullname(asym));
|
||||
asym->data = builddatalist(1);
|
||||
emptystringconst(asym->lineno,&asym->data->data[asym->data->length]);
|
||||
}
|
||||
validateNIL(asym);
|
||||
}
|
||||
/* collect per-variable attributes per variable*/
|
||||
for(i=0;i<listlength(vardefs);i++) {
|
||||
@ -708,6 +711,34 @@ inferattributetype(Symbol* asym)
|
||||
asym->typ.basetype = basetypefor(nctype);
|
||||
}
|
||||
|
||||
#ifdef USE_NETCDF4
|
||||
/* recursive helper for validataNIL */
|
||||
static void
|
||||
validateNILr(Datalist* src)
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<src->length;i++) {
|
||||
Constant* con = datalistith(src,i);
|
||||
if(isnilconst(con))
|
||||
semerror(con->lineno,"NIL data can only be assigned to variables or attributes of type string");
|
||||
else if(islistconst(con)) /* recurse */
|
||||
validateNILr(con->value.compoundv);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
validateNIL(Symbol* sym)
|
||||
{
|
||||
#ifdef USE_NETCDF4
|
||||
Datalist* datalist = sym->data;
|
||||
|
||||
if(sym->data == NULL || datalist->length == 0) return;
|
||||
if(sym->typ.typecode == NC_STRING) return;
|
||||
validateNILr(sym->data);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Find name within group structure*/
|
||||
Symbol*
|
||||
lookupgroup(List* prefix)
|
||||
@ -826,16 +857,6 @@ checkconsistency(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
validate(void)
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<listlength(vardefs);i++) {
|
||||
Symbol* sym = (Symbol*)listget(vardefs,i);
|
||||
if(sym->var.special._Fillvalue != NULL) {
|
||||
}
|
||||
}
|
||||
}
|
||||
static void
|
||||
computeunlimitedsizes(Dimset* dimset, int dimindex, Datalist* data, int ischar)
|
||||
{
|
||||
|
@ -168,6 +168,7 @@ nctypename(nc_type nctype)
|
||||
if(nctype >= NC_GRP && nctype <= NC_PRIM)
|
||||
return nctypenamesextend[(nctype - NC_GRP)];
|
||||
if(nctype == NC_FILLVALUE) return "NC_FILL";
|
||||
if(nctype == NC_NIL) return "NC_NIL";
|
||||
s = poolalloc(128);
|
||||
sprintf(s,"NC_<%d>",nctype);
|
||||
return s;
|
||||
|
Loading…
Reference in New Issue
Block a user