netcdf-c/libdap2/dapattr.c

503 lines
15 KiB
C
Raw Normal View History

2011-04-18 02:56:10 +08:00
/*********************************************************************
* Copyright 1993, UCAR/Unidata
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
*********************************************************************/
Primary change: add dap4 support Specific changes: 1. Add dap4 code: libdap4 and dap4_test. Note that until the d4ts server problem is solved, dap4 is turned off. 2. Modify various files to support dap4 flags: configure.ac, Makefile.am, CMakeLists.txt, etc. 3. Add nc_test/test_common.sh. This centralizes the handling of the locations of various things in the build tree: e.g. where is ncgen.exe located. See nc_test/test_common.sh for details. 4. Modify .sh files to use test_common.sh 5. Obsolete separate oc2 by moving it to be part of netcdf-c. This means replacing code with netcdf-c equivalents. 5. Add --with-testserver to configure.ac to allow override of the servers to be used for --enable-dap-remote-tests. 6. There were multiple versions of nctypealignment code. Try to centralize in libdispatch/doffset.c and include/ncoffsets.h 7. Add a unit test for the ncuri code because of its complexity. 8. Move the findserver code out of libdispatch and into a separate, self contained program in ncdap_test and dap4_test. 9. Move the dispatch header files (nc{3,4}dispatch.h) to .../include because they are now shared by modules. 10. Revamp the handling of TOPSRCDIR and TOPBUILDDIR for shell scripts. 11. Make use of MREMAP if available 12. Misc. minor changes e.g. - #include <config.h> -> #include "config.h" - Add some no-install headers to /include - extern -> EXTERNL and vice versa as needed - misc header cleanup - clean up checking for misc. unix vs microsoft functions 13. Change copyright decls in some files to point to LICENSE file. 14. Add notes to RELEASENOTES.md
2017-03-09 08:01:10 +08:00
#include "dapincludes.h"
2011-04-18 02:56:10 +08:00
#define OCCHECK(exp) if((ocstat = (exp))) {THROWCHK(ocstat); goto done;}
2011-04-18 02:56:10 +08:00
/* Forward */
static NCerror buildattribute(char*,nc_type,size_t,char**,NCattribute**);
2011-04-18 02:56:10 +08:00
/*
Invoke oc_merge_das and then extract special
attributes such as "strlen" and "dimname"
and stuff from DODS_EXTRA.
*/
int
dapmerge(NCDAPCOMMON* nccomm, CDFnode* ddsroot, OCddsnode dasroot)
{
int i,j;
NCerror ncstat = NC_NOERR;
OCerror ocstat = OC_NOERR;
NClist* allnodes;
OClink conn;
char* ocname = NULL;
char** values = NULL;
conn = nccomm->oc.conn;
if(ddsroot == NULL || dasroot == NULL)
return NC_NOERR;
/* Merge the das tree onto the dds tree */
ocstat = oc_merge_das(nccomm->oc.conn,dasroot,ddsroot->ocnode);
if(ocstat != OC_NOERR) goto done;
/* Create attributes on CDFnodes */
allnodes = ddsroot->tree->nodes;
for(i=0;i<nclistlength(allnodes);i++) {
CDFnode* node = (CDFnode*)nclistget(allnodes,i);
OCddsnode ocnode = node->ocnode;
size_t attrcount;
OCtype ocetype;
OCCHECK(oc_dds_attr_count(conn,ocnode,&attrcount));
for(j=0;j<attrcount;j++) {
size_t nvalues;
NCattribute* att = NULL;
if(ocname != NULL) {
free(ocname); ocname = NULL;
} /* from last loop */
OCCHECK(oc_dds_attr(conn,ocnode,j,&ocname,&ocetype,&nvalues,NULL));
if(nvalues > 0) {
values = (char**)malloc(sizeof(char*)*nvalues);
if(values == NULL) {ncstat = NC_ENOMEM; goto done;}
OCCHECK(oc_dds_attr(conn,ocnode,j,NULL,NULL,NULL,values));
}
ncstat = buildattribute(ocname,octypetonc(ocetype),nvalues,values,&att);
if(ncstat != NC_NOERR) goto done;
if(node->attributes == NULL)
node->attributes = nclistnew();
nclistpush(node->attributes,(void*)att);
if(strncmp(ocname,"DODS",strlen("DODS"))==0) {
att->invisible = 1;
/* Define extra semantics associated with
DODS and DODS_EXTRA attributes */
if(strcmp(ocname,"DODS.strlen")==0
|| strcmp(ocname,"DODS_EXTRA.strlen")==0) {
unsigned int maxstrlen = 0;
if(values != NULL) {
if(0==sscanf(values[0],"%u",&maxstrlen))
maxstrlen = 0;
}
node->dodsspecial.maxstrlen = maxstrlen;
#ifdef DEBUG
fprintf(stderr,"%s.maxstrlen=%d\n",node->ocname,(int)node->dodsspecial.maxstrlen);
#endif
} else if(strcmp(ocname,"DODS.dimName")==0
|| strcmp(ocname,"DODS_EXTRA.dimName")==0) {
if(values != NULL) {
node->dodsspecial.dimname = nulldup(values[0]);
#ifdef DEBUG
fprintf(stderr,"%s.dimname=%s\n",node->ocname,node->dodsspecial.dimname);
#endif
} else node->dodsspecial.dimname = NULL;
} else if(strcmp(ocname,"DODS.Unlimited_Dimension")==0
|| strcmp(ocname,"DODS_EXTRA.Unlimited_Dimension")==0) {
if(values != NULL) {
if(nccomm->cdf.recorddimname != NULL)
nclog(NCLOGWARN,"Duplicate DODS_EXTRA:Unlimited_Dimension specifications");
else
nccomm->cdf.recorddimname = nulldup(values[0]);
#ifdef DEBUG
fprintf(stderr,"%s.Unlimited_Dimension=%s\n",node->ocname,nccomm->cdf.recorddimname);
#endif
}
}
}
/* clean up */
if(values) {
oc_reclaim_strings(nvalues,values);
free(values);
values = NULL;
}
}
}
done:
if(values != NULL) free(values);
if(ocname != NULL) free(ocname);
if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
return THROW(ncstat);
}
/* Build an NCattribute */
2011-04-18 02:56:10 +08:00
static NCerror
buildattribute(char* name, nc_type ptype,
size_t nvalues, char** values, NCattribute** attp)
2011-04-18 02:56:10 +08:00
{
int i;
2011-04-18 02:56:10 +08:00
NCerror ncstat = NC_NOERR;
NCattribute* att = NULL;
2011-04-18 02:56:10 +08:00
att = (NCattribute*)calloc(1,sizeof(NCattribute));
MEMCHECK(att,NC_ENOMEM);
att->name = nulldup(name);
att->etype = ptype;
att->values = nclistnew();
for(i=0;i<nvalues;i++)
nclistpush(att->values,(void*)nulldup(values[i]));
2011-04-18 02:56:10 +08:00
if(attp) *attp = att;
else
free(att);
2011-04-18 02:56:10 +08:00
return THROW(ncstat);
}
#if 0
/*
Given a das attribute walk it to see if it
has at least 1 actual attribute (no recursion)
*/
static int
hasattribute(OClink conn, OCdasnode dasnode)
{
int i;
OCerror ocstat = OC_NOERR;
int tf = 0; /* assume false */
OCtype ocsubtype;
NClist* subnodes = nclistnew();
OCCHECK(oc_dds_octype(conn,dasnode,&ocsubtype));
if(ocsubtype == OC_Attribute) return 1; /* this is an attribute */
ASSERT((ocsubtype == OC_Attributeset));
OCCHECK(collect_subnodes(conn,dasnode,subnodes));
for(i=0;i<nclistlength(subnodes);i++) {
OCdasnode subnode = (OCdasnode)nclistget(subnodes,i);
OCCHECK(oc_dds_class(conn,subnode,&ocsubtype));
if(ocsubtype == OC_Attribute) {tf=1; break;}
}
done:
nclistfree(subnodes);
return tf;
}
2011-04-18 02:56:10 +08:00
int
dapmerge(NCDAPCOMMON* nccomm, CDFnode* ddsroot, OCddsnode dasroot)
2011-04-18 02:56:10 +08:00
{
unsigned int i,j;
NCerror ncerr = NC_NOERR;
OCerror ocstat = OC_NOERR;
OClink conn = nccomm->oc.conn;
size_t nsubnodes;
2011-04-18 02:56:10 +08:00
NClist* dasglobals = nclistnew();
NClist* dasnodes = nclistnew();
NClist* dodsextra = nclistnew();
2011-04-18 02:56:10 +08:00
NClist* varnodes = nclistnew();
NClist* alldasnodes = nclistnew();
2011-04-18 02:56:10 +08:00
if(ddsroot == NULL || dasroot == NULL) return NC_NOERR;
ocstat = collect_alldasnodes(conn,dasroot,alldasnodes);
2011-04-18 02:56:10 +08:00
/* 1. collect all the relevant DAS nodes;
namely those that contain at least one
attribute value.
Simultaneously look for potential ambiguities
if found; complain but continue: result are indeterminate.
also collect globals and DODS_EXTRA separately.
*/
for(i=0;i<nclistlength(alldasnodes);i++) {
OCddsnode das = (OCddsnode)nclistget(alldasnodes,i);
2011-04-18 02:56:10 +08:00
OCtype octype;
char* ocname = NULL;
int isglobal = 0;
int hasattributes = 0;
OCCHECK(oc_dds_class(conn,das,&octype));
2011-04-18 02:56:10 +08:00
if(octype == OC_Attribute) continue; /* ignore these for now*/
OCCHECK(oc_dds_name(conn,das,&ocname));
OCCHECK(oc_dds_nsubnodes(conn,das,&nsubnodes));
2011-04-18 02:56:10 +08:00
isglobal = (ocname == NULL ? 0 : isglobalname(ocname));
2011-04-18 02:56:10 +08:00
/* catch DODS_EXTRA */
if(isglobal && ocname != NULL && strcmp(ocname,"DODS_EXTRA")==0) {
nclistpush(dodsextra,(void*)das);
2011-04-18 02:56:10 +08:00
nullfree(ocname);
continue;
}
if(ocname == NULL || isglobal) {
nclistpush(dasglobals,(void*)das);
2011-04-18 02:56:10 +08:00
nullfree(ocname);
continue;
}
hasattributes = hasattribute(conn,das);
2011-04-18 02:56:10 +08:00
if(hasattributes) {
/* Look for previously collected nodes with same name*/
for(j=0;j<nclistlength(dasnodes);j++) {
OCddsnode das2 = (OCddsnode)nclistget(dasnodes,j);
2011-04-18 02:56:10 +08:00
char* ocname2;
OCCHECK(oc_dds_name(conn,das2,&ocname2));
2011-04-18 02:56:10 +08:00
if(ocname2 == NULL || ocname == NULL) goto loop;
if(strcmp(ocname2,"DODS")==0) goto loop;
if(strcmp(ocname,ocname2)==0)
nclog(NCLOGWARN,"nc_mergedas: potentially ambiguous DAS name: %s",ocname2);
loop:
nullfree(ocname2);
}
nclistpush(dasnodes,(void*)das);
2011-04-18 02:56:10 +08:00
}
nullfree(ocname);
}
/* 2. collect all the leaf DDS nodes (of type NC_Atomic)*/
ocstat = collect_leaves(link,ddsroot,varnodes);
2011-04-18 02:56:10 +08:00
/* 3. For each das node, locate matching DDS node(s) and attach
2011-04-18 02:56:10 +08:00
attributes to the DDS node(s).
Match means:
1. DAS->fullname :: DDS->fullname
2. DAS->name :: DDS->fullname (support DAS names with embedded '.'
3. DAS->name :: DDS->name
4. special case for DODS. Apply 1-3 on DODS parent.
2011-04-18 02:56:10 +08:00
*/
for(i=0;i<nclistlength(dasnodes);i++) {
OCddsnode das = (OCddsnode)nclistget(dasnodes,i);
2012-02-04 05:31:50 +08:00
char* ocfullname = NULL;
char* ocbasename = NULL;
if(das == NULL) continue;
OCCHECK(oc_dds_name(conn,das,&ocbasename));
if(strcmp(ocbasename,"DODS")==0) {
OCddsnode container;
OCCHECK(oc_dds_container(conn,das,&container));
ASSERT(container != NULL);
ocfullname = makeocpathstring(conn,container,".");
} else {
ocfullname = makeocpathstring(conn,das,".");
}
2011-04-18 02:56:10 +08:00
for(j=0;j<nclistlength(varnodes);j++) {
CDFnode* dds = (CDFnode*)nclistget(varnodes,j);
char* ddsfullname = makecdfpathstring(dds,".");
2011-04-18 02:56:10 +08:00
if(strcmp(ocfullname,ddsfullname)==0
|| strcmp(ocbasename,ddsfullname)==0
2011-11-14 12:20:19 +08:00
|| strcmp(ocbasename,dds->ocname)==0) {
mergedas1(nccomm,conn,dds,das);
2011-04-18 02:56:10 +08:00
/* remove from dasnodes list*/
nclistset(dasnodes,i,(void*)NULL);
2011-04-18 02:56:10 +08:00
}
nullfree(ddsfullname);
}
nullfree(ocfullname);
nullfree(ocbasename);
}
/* 4. Assign globals */
2011-04-18 02:56:10 +08:00
for(i=0;i<nclistlength(dasglobals);i++) {
OCddsnode das = (OCddsnode)nclistget(dasglobals,i);
mergedas1(nccomm,conn,ddsroot,das);
2011-04-18 02:56:10 +08:00
}
/* 5. Assign DOD_EXTRA */
for(i=0;i<nclistlength(dodsextra);i++) {
OCddsnode das = (OCddsnode)nclistget(dodsextra,i);
mergedas1(nccomm,conn,ddsroot,das);
}
2011-04-18 02:56:10 +08:00
done: /* cleanup*/
nclistfree(dasglobals);
nclistfree(dasnodes);
nclistfree(alldasnodes);
2011-04-18 02:56:10 +08:00
nclistfree(dodsextra);
nclistfree(varnodes);
if(ocstat != OC_NOERR)
ncerr = ocerrtoncerr(ocstat);
2011-04-18 02:56:10 +08:00
return THROW(ncerr);
}
static int
mergedas1(NCDAPCOMMON* nccomm, OClink conn, CDFnode* dds, OCddsnode das)
2011-04-18 02:56:10 +08:00
{
NCerror ncstat = NC_NOERR;
OCerror ocstat = OC_NOERR;
unsigned int i,j,k;
2011-04-18 02:56:10 +08:00
unsigned int nsubnodes;
OCobject* subnodes = NULL;
OCobject* dodsnodes = NULL;
unsigned int ndodsnodes;
if(dds == NULL || das == OCNULL) return NC_NOERR; /* nothing to do */
if(dds->attributes == NULL) dds->attributes = nclistnew();
/* assign the simple attributes in the das set to this dds node*/
OCCHECK(oc_inq_nsubnodes(conn,das,&nsubnodes));
OCCHECK(oc_inq_subnodes(conn,das,&subnodes));
2011-04-18 02:56:10 +08:00
for(i=0;i<nsubnodes;i++) {
OCobject attnode = subnodes[i];
OCtype octype, ocetype;
char* ocname = NULL;
unsigned int ocnvalues;
OCCHECK(oc_inq_name(conn,attnode,&ocname));
OCCHECK(oc_inq_class(conn,attnode,&octype));
2011-04-18 02:56:10 +08:00
if(octype == OC_Attribute) {
NCattribute* att = NULL;
NClist* stringvalues;
OCCHECK(oc_inq_primtype(conn,attnode,&ocetype));
OCCHECK(oc_inq_dasattr_nvalues(conn,attnode,&ocnvalues));
2011-04-18 02:56:10 +08:00
stringvalues = nclistnew();
for(j=0;j<ocnvalues;j++) {
char* stringval;
OCCHECK(oc_inq_dasattr(conn,attnode,j,&ocetype,&stringval));
nclistpush(stringvalues,(void*)stringval);
2011-04-18 02:56:10 +08:00
}
ncstat = buildattribute(ocname,
octypetonc(ocetype),
stringvalues,
&att);
if(ncstat) goto done;
nclistpush(dds->attributes,(void*)att);
} else if(octype == OC_Attributeset
&& (strcmp(ocname,"DODS")==0
|| strcmp(ocname,"DODS_EXTRA")==0)) {
/* Turn the DODS special attributes into into
special attributes for dds node */
OCCHECK(oc_inq_nsubnodes(conn,attnode,&ndodsnodes));
OCCHECK(oc_inq_subnodes(conn,attnode,&dodsnodes));
2011-04-18 02:56:10 +08:00
for(j=0;j<ndodsnodes;j++) {
char* dodsname = NULL;
char newname[4096];
OCobject attnode = dodsnodes[j];
NCattribute* att = NULL;
NClist* stringvalues;
OCCHECK(oc_inq_class(conn,attnode,&octype));
2011-04-18 02:56:10 +08:00
if(octype != OC_Attribute) continue;
OCCHECK(oc_inq_primtype(conn,attnode,&ocetype));
OCCHECK(oc_inq_dasattr_nvalues(conn,attnode,&ocnvalues));
stringvalues = nclistnew();
for(k=0;k<ocnvalues;k++) {
char* stringval;
OCCHECK(oc_inq_dasattr(conn,attnode,k,&ocetype,&stringval));
nclistpush(stringvalues,(void*)stringval);
}
OCCHECK(oc_inq_name(conn,attnode,&dodsname));
/* Compute new special name */
strcpy(newname,"_DODS_");
strcat(newname,dodsname);
ncstat = buildattribute(newname,
octypetonc(ocetype),
stringvalues,
&att);
if(ncstat) goto done;
att->invisible = 1;
nclistpush(dds->attributes,(void*)att);
/* Define extra semantics associated with DODS and DODS_EXTRA attribute */
2011-04-18 02:56:10 +08:00
if(strcmp(dodsname,"strlen")==0) {
unsigned int maxstrlen = 0;
if(nclistlength(stringvalues) > 0) {
char* stringval = (char*)nclistget(stringvalues,0);
2011-04-18 02:56:10 +08:00
if(0==sscanf(stringval,"%u",&maxstrlen)) maxstrlen = 0;
}
dds->dodsspecial.maxstrlen = maxstrlen;
#ifdef DEBUG
2011-11-14 12:20:19 +08:00
fprintf(stderr,"%s.maxstrlen=%d\n",dds->ocname,(int)dds->dodsspecial.maxstrlen);
2011-04-18 02:56:10 +08:00
#endif
} else if(strcmp(dodsname,"dimName")==0) {
if(nclistlength(stringvalues) > 0) {
char* stringval = (char*)nclistget(stringvalues,0);
dds->dodsspecial.dimname = nulldup(stringval);
2011-04-18 02:56:10 +08:00
#ifdef DEBUG
2011-11-14 12:20:19 +08:00
fprintf(stderr,"%s.dimname=%s\n",dds->ocname,dds->dodsspecial.dimname);
2011-04-18 02:56:10 +08:00
#endif
} else dds->dodsspecial.dimname = NULL;
} else if(strcmp(dodsname,"Unlimited_Dimension")==0) {
if(nccomm->cdf.recorddimname != NULL) {
nclog(NCLOGWARN,"Duplicate DODS_EXTRA:Unlimited_Dimension specifications");
} else if(nclistlength(stringvalues) > 0) {
char* stringval = (char*)nclistget(stringvalues,0);
nccomm->cdf.recorddimname = nulldup(stringval);
#ifdef DEBUG
fprintf(stderr,"%s.Unlimited_Dimension=%s\n",dds->ocname,nccomm->cdf.recorddimname);
#endif
}
2011-04-18 02:56:10 +08:00
} /* else ignore */
nullfree(dodsname);
}
nullfree(dodsnodes);
}
2011-04-18 02:56:10 +08:00
nullfree(ocname);
}
done:
nullfree(subnodes);
if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
return THROW(ncstat);
}
static int
isglobalname(char* name)
2011-04-18 02:56:10 +08:00
{
int len = strlen(name);
int glen = strlen("global");
char* p;
if(len < glen) return 0;
p = name + (len - glen);
if(strcasecmp(p,"global") != 0)
return 0;
return 1;
}
static OCerror
collect_alldasnodes(OClink link, OCddsnode dasnode, NClist* alldasnodes)
{
size_t nsubnodes,i;
OCerror ocstat = OC_NOERR;
nclistpush(alldasnodes,(void*)dasnode);
ocstat = oc_dds_nsubnodes(link,dasnode,&nsubnodes);
if(ocstat != OC_NOERR) goto done;
for(i=0;i<nsubnodes;i++) {
OCddsnode subnode;
ocstat = oc_dds_ithsubnode(link,dasnode,i,&subnode);
if(ocstat != OC_NOERR) goto done;
ocstat = collect_alldasnodes(link,subnode,alldasnodes);
if(ocstat != OC_NOERR) goto done;
}
done:
return ocstat;
}
static OCerror
collect_leaves(OClink link, OCddsnode ddsnode, NClist* leaves)
{
size_t nsubnodes,i;
OCerror ocstat = OC_NOERR;
OCtype octype;
ocstat = oc_dds_octype(link,ddsnode,&octype);
if(ocstat != OC_NOERR) goto done;
if(octype == OC_Atomic) {
nclistpush(leaves,(void*)ddsnode);
} else {
ocstat = oc_dds_nsubnodes(link,ddsnode,&nsubnodes);
if(ocstat != OC_NOERR) goto done;
for(i=0;i<nsubnodes;i++) {
OCddsnode subnode;
ocstat = oc_dds_ithsubnode(link,ddsnode,i,&subnode);
if(ocstat != OC_NOERR) goto done;
ocstat = collect_leaves(link,subnode,leaves);
if(ocstat != OC_NOERR) goto done;
}
}
done:
return ocstat;
}
static OCerror
collect_subnodes(OClink link, OCddsnode ddsnode, NClist* subnodes)
{
size_t nsubnodes,i;
OCerror ocstat = OC_NOERR;
ocstat = oc_dds_nsubnodes(link,ddsnode,&nsubnodes);
if(ocstat != OC_NOERR) goto done;
for(i=0;i<nsubnodes;i++) {
OCddsnode subnode;
ocstat = oc_dds_ithsubnode(link,ddsnode,i,&subnode);
if(ocstat != OC_NOERR) goto done;
nclistpush(subnodes,(void*)subnode);
}
done:
return ocstat;
}
#endif /*0*/