mirror of
https://github.com/Unidata/netcdf-c.git
synced 2025-01-18 15:55:12 +08:00
Merge pull request #2109 from DennisHeimbigner/ncgenenum.dmh
Fix handling of enum constants nested in compound types.
This commit is contained in:
commit
e763e6caf1
@ -9,5 +9,5 @@ variables:
|
||||
data:
|
||||
test1=pass;
|
||||
test2=e2.undefined;
|
||||
test3=/e1.fail;
|
||||
test3=e1.fail;
|
||||
}
|
||||
|
46
ncdump/cdl/ref_tst_econst2.cdl
Normal file
46
ncdump/cdl/ref_tst_econst2.cdl
Normal file
@ -0,0 +1,46 @@
|
||||
netcdf foo { // an example netCDF specification in CDL
|
||||
|
||||
types:
|
||||
ubyte enum enum_t {Clear = 0, Cumulonimbus = 1, Stratus = 2};
|
||||
opaque(11) opaque_t;
|
||||
int(*) vlen_t;
|
||||
|
||||
dimensions:
|
||||
lat = 10, lon = 5, time = unlimited ;
|
||||
|
||||
variables:
|
||||
long lat(lat), lon(lon), time(time);
|
||||
float Z(time,lat,lon), t(time,lat,lon);
|
||||
double p(time,lat,lon);
|
||||
long rh(time,lat,lon);
|
||||
|
||||
string country(time,lat,lon);
|
||||
ubyte tag;
|
||||
|
||||
// variable attributes
|
||||
lat:long_name = "latitude";
|
||||
lat:units = "degrees_north";
|
||||
lon:long_name = "longitude";
|
||||
lon:units = "degrees_east";
|
||||
time:units = "seconds since 1992-1-1 00:00:00";
|
||||
|
||||
// typed variable attributes
|
||||
string Z:units = "geopotential meters";
|
||||
float Z:valid_range = 0., 5000.;
|
||||
double p:_FillValue = -9999.;
|
||||
long rh:_FillValue = -1;
|
||||
vlen_t :globalatt = {17, 18, 19};
|
||||
data:
|
||||
lat = 0, 10, 20, 30, 40, 50, 60, 70, 80, 90;
|
||||
lon = -140, -118, -96, -84, -52;
|
||||
group: g {
|
||||
types:
|
||||
compound cmpd_t { vlen_t f1; enum_t f2; enum_t f3;};
|
||||
} // group g
|
||||
group: h {
|
||||
variables:
|
||||
/g/cmpd_t compoundvar;
|
||||
data:
|
||||
compoundvar = { {3,4,5}, Stratus, enum_t.Clear } ;
|
||||
} // group h
|
||||
}
|
56
ncdump/expected/ref_tst_econst2.dmp
Normal file
56
ncdump/expected/ref_tst_econst2.dmp
Normal file
@ -0,0 +1,56 @@
|
||||
netcdf ref_tst_econst2 {
|
||||
types:
|
||||
ubyte enum enum_t {Clear = 0, Cumulonimbus = 1, Stratus = 2} ;
|
||||
opaque(11) opaque_t ;
|
||||
int(*) vlen_t ;
|
||||
dimensions:
|
||||
lat = 10 ;
|
||||
lon = 5 ;
|
||||
time = UNLIMITED ; // (0 currently)
|
||||
variables:
|
||||
int lat(lat) ;
|
||||
lat:long_name = "latitude" ;
|
||||
lat:units = "degrees_north" ;
|
||||
int lon(lon) ;
|
||||
lon:long_name = "longitude" ;
|
||||
lon:units = "degrees_east" ;
|
||||
int time(time) ;
|
||||
time:units = "seconds since 1992-1-1 00:00:00" ;
|
||||
float Z(time, lat, lon) ;
|
||||
string Z:units = "geopotential meters" ;
|
||||
Z:valid_range = 0.f, 5000.f ;
|
||||
float t(time, lat, lon) ;
|
||||
double p(time, lat, lon) ;
|
||||
p:_FillValue = -9999. ;
|
||||
int rh(time, lat, lon) ;
|
||||
rh:_FillValue = -1 ;
|
||||
string country(time, lat, lon) ;
|
||||
ubyte tag ;
|
||||
|
||||
// global attributes:
|
||||
vlen_t :globalatt = {17, 18, 19} ;
|
||||
data:
|
||||
|
||||
lat = 0, 10, 20, 30, 40, 50, 60, 70, 80, 90 ;
|
||||
|
||||
lon = -140, -118, -96, -84, -52 ;
|
||||
|
||||
tag = 255 ;
|
||||
|
||||
group: g {
|
||||
types:
|
||||
compound cmpd_t {
|
||||
vlen_t f1 ;
|
||||
enum_t f2 ;
|
||||
enum_t f3 ;
|
||||
}; // cmpd_t
|
||||
} // group g
|
||||
|
||||
group: h {
|
||||
variables:
|
||||
/g/cmpd_t compoundvar ;
|
||||
data:
|
||||
|
||||
compoundvar = {{3, 4, 5}, Stratus, Clear} ;
|
||||
} // group h
|
||||
}
|
@ -31,9 +31,15 @@ for x in ${TESTSET} ; do
|
||||
for t in ${XFAILTESTS} ; do
|
||||
if test "x${t}" = "x${x}" ; then isxfail=1; fi
|
||||
done
|
||||
isnocycle=0
|
||||
for t in ${NOCYCLE} ; do
|
||||
if test "x${t}" = "x${x}" ; then isnocycle=1; fi
|
||||
done
|
||||
if test "${isxfail}" = "1"; then
|
||||
echo "xfail test: ${x}: ignored"
|
||||
xfailcount=`expr $xfailcount + 1`
|
||||
elif test "${isnocycle}" = "1"; then
|
||||
echo "test: ${x}: ignored for cycle test"
|
||||
else
|
||||
rm -f ${x}_$$.nc ${x}_$$.dmp
|
||||
# step 1: use original cdl to build the .nc
|
||||
|
@ -97,12 +97,17 @@ unlimtest2 \
|
||||
ref_niltest \
|
||||
ref_tst_h_scalar \
|
||||
ref_tst_nul4 \
|
||||
ref_tst_econst \
|
||||
ref_tst_econst2 \
|
||||
"
|
||||
|
||||
if test "x$NC_VLEN_NOTEST" = x ; then
|
||||
TESTS4="$TESTS4 ref_tst_vlen_data ref_tst_vlen_data2"
|
||||
fi
|
||||
|
||||
# These tests should not be cycle tested because ncdump loses information
|
||||
NOCYCLE="ref_tst_econst"
|
||||
|
||||
SPECIALTESTS3="ref_tst_special_atts3"
|
||||
|
||||
SPECIALTESTS="${SPECIALTESTS3} ref_tst_special_atts"
|
||||
|
@ -34,7 +34,6 @@ static void inferattributetype(Symbol* asym);
|
||||
static void validateNIL(Symbol* sym);
|
||||
static void checkconsistency(void);
|
||||
static int tagvlentypes(Symbol* tsym);
|
||||
static void computefqns(void);
|
||||
static Symbol* uniquetreelocate(Symbol* refsym, Symbol* root);
|
||||
static char* createfilename(void);
|
||||
|
||||
@ -468,61 +467,124 @@ processeconstrefsR(Symbol* avsym, Datalist* data)
|
||||
if(con->nctype == NC_COMPOUND) {
|
||||
/* Iterate over the sublists */
|
||||
processeconstrefsR(avsym,con->value.compoundv);
|
||||
} else if(con->nctype == NC_ECONST || con->nctype == NC_FILLVALUE) {
|
||||
} else if(con->nctype == NC_ECONST) {
|
||||
fixeconstref(avsym,con);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Collect all types in all groups using preorder depth-first traversal.
|
||||
*/
|
||||
static void
|
||||
typewalk(Symbol* root, nc_type typ, List* list)
|
||||
{
|
||||
unsigned long i;
|
||||
for(i=0;i<listlength(root->subnodes);i++) {
|
||||
Symbol* sym = (Symbol*)listget(root->subnodes,i);
|
||||
if(sym->objectclass == NC_GRP) {
|
||||
typewalk(sym,typ,list);
|
||||
} else if(sym->objectclass == NC_TYPE && (typ == NC_NAT || typ == sym->subclass)) {
|
||||
if(!listcontains(list,sym))
|
||||
listpush(list,sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Find all user-define types of type typ in access order */
|
||||
static void
|
||||
orderedtypes(Symbol* avsym, nc_type typ, List* types)
|
||||
{
|
||||
Symbol* container = NULL;
|
||||
listclear(types);
|
||||
/* find innermost containing group */
|
||||
if(avsym->objectclass == NC_VAR) {
|
||||
container = avsym->container;
|
||||
} else {
|
||||
ASSERT(avsym->objectclass == NC_ATT);
|
||||
container = avsym->container;
|
||||
if(container->objectclass == NC_VAR)
|
||||
container = container->container;
|
||||
}
|
||||
/* walk up the containing groups and collect type */
|
||||
for(;container!= NULL;container = container->container) {
|
||||
int i;
|
||||
/* Walk types in the container */
|
||||
for(i=0;i<listlength(container->subnodes);i++) {
|
||||
Symbol* sym = (Symbol*)listget(container->subnodes,i);
|
||||
if(sym->objectclass == NC_TYPE && (typ == NC_NAT || sym->subclass == typ))
|
||||
listpush(types,sym);
|
||||
}
|
||||
}
|
||||
/* Now do all-tree search */
|
||||
typewalk(rootgroup,typ,types);
|
||||
}
|
||||
|
||||
static Symbol*
|
||||
locateeconst(Symbol* enumt, const char* ecname)
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<listlength(enumt->subnodes);i++) {
|
||||
Symbol* esym = (Symbol*)listget(enumt->subnodes,i);
|
||||
ASSERT(esym->subclass == NC_ECONST);
|
||||
if(strcmp(esym->name,ecname)==0)
|
||||
return esym;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Symbol*
|
||||
findeconstenum(Symbol* avsym, NCConstant* con)
|
||||
{
|
||||
int i;
|
||||
Symbol* refsym = con->value.enumv;
|
||||
List* typdefs = listnew();
|
||||
Symbol* enumt = NULL;
|
||||
Symbol* candidate = NULL; /* possible enum type */
|
||||
Symbol* econst = NULL;
|
||||
char* path = NULL;
|
||||
char* name = NULL;
|
||||
|
||||
/* get all enum types */
|
||||
orderedtypes(avsym,NC_ENUM,typdefs);
|
||||
|
||||
/* It is possible that the enum const is prefixed with the type name */
|
||||
|
||||
path = strchr(refsym->name,'.');
|
||||
if(path != NULL) {
|
||||
path = strdup(refsym->name);
|
||||
name = strchr(path,'.');
|
||||
*name++ = '\0';
|
||||
} else
|
||||
name = refsym->name;
|
||||
/* See if we can find the enum type */
|
||||
for(i=0;i<listlength(typdefs);i++) {
|
||||
Symbol* sym = (Symbol*)listget(typdefs,i);
|
||||
ASSERT(sym->objectclass == NC_TYPE && sym->subclass == NC_ENUM);
|
||||
if(path != NULL && strcmp(sym->name,path)==0) {enumt = sym; break;}
|
||||
/* See if enum has a matching econst */
|
||||
econst = locateeconst(sym,name);
|
||||
if(candidate == NULL && econst != NULL) candidate = sym; /* remember this */
|
||||
}
|
||||
if(enumt != NULL) goto done;
|
||||
/* otherwise use the candidate */
|
||||
enumt = candidate;
|
||||
done:
|
||||
if(enumt) econst = locateeconst(enumt,name);
|
||||
nullfree(path);
|
||||
if(econst == NULL)
|
||||
semerror(con->lineno,"Undefined enum constant: %s",refsym->name);
|
||||
return econst;
|
||||
}
|
||||
|
||||
static void
|
||||
fixeconstref(Symbol* avsym, NCConstant* con)
|
||||
{
|
||||
Symbol* basetype = NULL;
|
||||
Symbol* refsym = con->value.enumv;
|
||||
Symbol* varsym = NULL;
|
||||
int i;
|
||||
Symbol* econst = NULL;
|
||||
|
||||
/* Figure out the proper type associated with avsym */
|
||||
ASSERT(avsym->objectclass == NC_VAR || avsym->objectclass == NC_ATT);
|
||||
|
||||
if(avsym->objectclass == NC_VAR) {
|
||||
basetype = avsym->typ.basetype;
|
||||
varsym = avsym;
|
||||
} else { /*(avsym->objectclass == NC_ATT)*/
|
||||
basetype = avsym->typ.basetype;
|
||||
varsym = avsym->container;
|
||||
if(varsym->objectclass == NC_GRP)
|
||||
varsym = NULL;
|
||||
}
|
||||
|
||||
/* If this is a non-econst fillvalue, then ignore it */
|
||||
if(con->nctype == NC_FILLVALUE && basetype->subclass != NC_ENUM)
|
||||
return;
|
||||
|
||||
/* If this is an econst then validate against type */
|
||||
if(con->nctype == NC_ECONST && basetype->subclass != NC_ENUM)
|
||||
semerror(con->lineno,"Enumconstant associated with a non-econst type");
|
||||
|
||||
if(con->nctype == NC_FILLVALUE) {
|
||||
Datalist* filllist = NULL;
|
||||
NCConstant* filler = NULL;
|
||||
filllist = getfiller(varsym == NULL?basetype:varsym);
|
||||
if(filllist == NULL)
|
||||
semerror(con->lineno, "Cannot determine enum constant fillvalue");
|
||||
filler = datalistith(filllist,0);
|
||||
con->value.enumv = filler->value.enumv;
|
||||
return;
|
||||
}
|
||||
|
||||
for(i=0;i<listlength(basetype->subnodes);i++) {
|
||||
Symbol* econst = listget(basetype->subnodes,i);
|
||||
ASSERT(econst->subclass == NC_ECONST);
|
||||
if(strcmp(econst->name,refsym->name)==0) {
|
||||
con->value.enumv = econst;
|
||||
return;
|
||||
}
|
||||
}
|
||||
semerror(con->lineno,"Undefined enum or enum constant reference: %s",refsym->name);
|
||||
econst = findeconstenum(avsym,con);
|
||||
assert(econst != NULL && econst->subclass == NC_ECONST);
|
||||
con->value.enumv = econst;
|
||||
}
|
||||
|
||||
/* Compute type sizes and compound offsets*/
|
||||
@ -1131,7 +1193,6 @@ processunlimiteddims(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Rules for specifying the dataset name:
|
||||
1. use -o name
|
||||
2. use the datasetname from the .cdl file
|
||||
|
Loading…
Reference in New Issue
Block a user