Merged latest from trunk.

This commit is contained in:
Ward Fisher 2013-07-11 17:01:15 +00:00
commit eef6e4679b
41 changed files with 1808 additions and 1226 deletions

View File

@ -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 { \

View File

@ -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

View File

@ -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. */

View File

@ -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 */

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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

View 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 ;
}

View 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" ;
}

View File

@ -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);
}

View File

@ -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

View File

@ -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

View 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 ;
}

View 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" ;
}

View File

@ -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
View 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
View 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

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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);
}

View File

@ -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;

View File

@ -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*/

View File

@ -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;

View File

@ -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*);

View File

@ -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"

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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

View File

@ -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 */

View File

@ -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));

File diff suppressed because it is too large Load Diff

View File

@ -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 */

File diff suppressed because it is too large Load Diff

View File

@ -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)
{

View File

@ -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;