mirror of
https://github.com/Unidata/netcdf-c.git
synced 2025-03-01 17:06:03 +08:00
error occurs after an "exit:" label. Corrected a dozen Coverity errors (mainly allocation issues, along with a few other things): 711711, 711802, 711803, 711905, 970825, 996123, 996124, 1025787, 1047274, 1130013, 1130014, 1139538 Refactored internal fill-value code to correctly handle string types, and especially to allow NULL pointers and null strings (ie. "") to be distinguished. The code now avoids partially aliasing the two together (which only happened on the 'write' side of things and wasn't reflected on the 'read' side, adding to the previous confusion). Probably still weak on handling fill-values of variable-length and compound datatypes. Refactored the recursive metadata reads a bit more, to process HDF5 named datatypes and datasets immediately, avoiding chewing up memory for those types of objects, etc. Finished uncommenting and updating the nc_test4/tst_fills2.c code (as I'm proceeding alphabetically through the nc_test4 code files).
969 lines
29 KiB
C
969 lines
29 KiB
C
/*********************************************************************
|
|
* Copyright 1993, UCAR/Unidata
|
|
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
|
|
* $Header: /upc/share/CVS/netcdf-3/libncdap3/common34.c,v 1.29 2010/05/25 13:53:02 ed Exp $
|
|
*********************************************************************/
|
|
|
|
#include "ncdap3.h"
|
|
|
|
#ifdef HAVE_GETRLIMIT
|
|
# ifdef HAVE_SYS_RESOURCE_H
|
|
# include <sys/time.h>
|
|
# endif
|
|
# ifdef HAVE_SYS_RESOURCE_H
|
|
# include <sys/resource.h>
|
|
# endif
|
|
#endif
|
|
#include "dapdump.h"
|
|
|
|
extern CDFnode* v4node;
|
|
|
|
/* Define the set of protocols known to be constrainable */
|
|
static char* constrainableprotocols[] = {"http", "https",NULL};
|
|
static NCerror buildcdftree34r(NCDAPCOMMON*,OCddsnode,CDFnode*,CDFtree*,CDFnode**);
|
|
static void defdimensions(OCddsnode, CDFnode*, NCDAPCOMMON*, CDFtree*);
|
|
static NCerror attachsubset34r(CDFnode*, CDFnode*);
|
|
static void free1cdfnode34(CDFnode* node);
|
|
|
|
/* Define Procedures that are common to both
|
|
libncdap3 and libncdap4
|
|
*/
|
|
|
|
/* Ensure every node has an initial base name defined and fullname */
|
|
/* Exceptions: anonymous dimensions. */
|
|
static NCerror
|
|
fix1node34(NCDAPCOMMON* nccomm, CDFnode* node)
|
|
{
|
|
if(node->nctype == NC_Dimension && node->ocname == NULL) return NC_NOERR;
|
|
ASSERT((node->ocname != NULL));
|
|
nullfree(node->ncbasename);
|
|
node->ncbasename = cdflegalname3(node->ocname);
|
|
if(node->ncbasename == NULL) return NC_ENOMEM;
|
|
nullfree(node->ncfullname);
|
|
node->ncfullname = makecdfpathstring3(node,nccomm->cdf.separator);
|
|
if(node->ncfullname == NULL) return NC_ENOMEM;
|
|
if(node->nctype == NC_Atomic)
|
|
node->externaltype = nctypeconvert(nccomm,node->etype);
|
|
return NC_NOERR;
|
|
}
|
|
|
|
NCerror
|
|
fixnodes34(NCDAPCOMMON* nccomm, NClist* cdfnodes)
|
|
{
|
|
int i;
|
|
for(i=0;i<nclistlength(cdfnodes);i++) {
|
|
CDFnode* node = (CDFnode*)nclistget(cdfnodes,i);
|
|
NCerror err = fix1node34(nccomm,node);
|
|
if(err) return err;
|
|
}
|
|
return NC_NOERR;
|
|
}
|
|
|
|
|
|
NCerror
|
|
fixgrid34(NCDAPCOMMON* nccomm, CDFnode* grid)
|
|
{
|
|
unsigned int i,glen;
|
|
CDFnode* array;
|
|
|
|
glen = nclistlength(grid->subnodes);
|
|
array = (CDFnode*)nclistget(grid->subnodes,0);
|
|
if(nccomm->controls.flags & (NCF_NC3)) {
|
|
/* Rename grid Array: variable, but leave its oc base name alone */
|
|
nullfree(array->ncbasename);
|
|
array->ncbasename = nulldup(grid->ncbasename);
|
|
if(!array->ncbasename) return NC_ENOMEM;
|
|
}
|
|
/* validate and modify the grid structure */
|
|
if((glen-1) != nclistlength(array->array.dimset0)) goto invalid;
|
|
for(i=1;i<glen;i++) {
|
|
CDFnode* arraydim = (CDFnode*)nclistget(array->array.dimset0,i-1);
|
|
CDFnode* map = (CDFnode*)nclistget(grid->subnodes,i);
|
|
CDFnode* mapdim;
|
|
/* map must have 1 dimension */
|
|
if(nclistlength(map->array.dimset0) != 1) goto invalid;
|
|
/* and the map name must match the ith array dimension */
|
|
if(arraydim->ocname != NULL && map->ocname != NULL
|
|
&& strcmp(arraydim->ocname,map->ocname) != 0)
|
|
goto invalid;
|
|
/* and the map name must match its dim name (if any) */
|
|
mapdim = (CDFnode*)nclistget(map->array.dimset0,0);
|
|
if(mapdim->ocname != NULL && map->ocname != NULL
|
|
&& strcmp(mapdim->ocname,map->ocname) != 0)
|
|
goto invalid;
|
|
/* Add appropriate names for the anonymous dimensions */
|
|
/* Do the map name first, so the array dim may inherit */
|
|
if(mapdim->ocname == NULL) {
|
|
nullfree(mapdim->ncbasename);
|
|
mapdim->ocname = nulldup(map->ocname);
|
|
if(!mapdim->ocname) return NC_ENOMEM;
|
|
mapdim->ncbasename = cdflegalname3(mapdim->ocname);
|
|
if(!mapdim->ncbasename) return NC_ENOMEM;
|
|
}
|
|
if(arraydim->ocname == NULL) {
|
|
nullfree(arraydim->ncbasename);
|
|
arraydim->ocname = nulldup(map->ocname);
|
|
if(!arraydim->ocname) return NC_ENOMEM;
|
|
arraydim->ncbasename = cdflegalname3(arraydim->ocname);
|
|
if(!arraydim->ncbasename) return NC_ENOMEM;
|
|
}
|
|
if(FLAGSET(nccomm->controls,(NCF_NCDAP|NCF_NC3))) {
|
|
char tmp[3*NC_MAX_NAME];
|
|
/* Add the grid name to the basename of the map */
|
|
snprintf(tmp,sizeof(tmp),"%s%s%s",map->container->ncbasename,
|
|
nccomm->cdf.separator,
|
|
map->ncbasename);
|
|
nullfree(map->ncbasename);
|
|
map->ncbasename = nulldup(tmp);
|
|
if(!map->ncbasename) return NC_ENOMEM;
|
|
}
|
|
}
|
|
return NC_NOERR;
|
|
invalid:
|
|
return NC_EINVAL; /* mal-formed grid */
|
|
}
|
|
|
|
/**
|
|
* Given an anonymous dimension, compute the
|
|
* effective 0-based index wrt to the specified var.
|
|
* The result should mimic the libnc-dap indices.
|
|
*/
|
|
|
|
static void
|
|
computedimindexanon3(CDFnode* dim, CDFnode* var)
|
|
{
|
|
int i;
|
|
NClist* dimset = var->array.dimsetall;
|
|
for(i=0;i<nclistlength(dimset);i++) {
|
|
CDFnode* candidate = (CDFnode*)nclistget(dimset,i);
|
|
if(dim == candidate) {
|
|
dim->dim.index1=i+1;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Replace dims in a list with their corresponding basedim */
|
|
static void
|
|
replacedims(NClist* dims)
|
|
{
|
|
int i;
|
|
for(i=0;i<nclistlength(dims);i++) {
|
|
CDFnode* dim = (CDFnode*)nclistget(dims,i);
|
|
CDFnode* basedim = dim->dim.basedim;
|
|
if(basedim == NULL) continue;
|
|
nclistset(dims,i,(void*)basedim);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Two dimensions are equivalent if
|
|
1. they have the same size
|
|
2. neither are anonymous
|
|
3. they ave the same names.
|
|
*/
|
|
static int
|
|
equivalentdim(CDFnode* basedim, CDFnode* dupdim)
|
|
{
|
|
if(dupdim->dim.declsize != basedim->dim.declsize) return 0;
|
|
if(basedim->ocname == NULL && dupdim->ocname == NULL) return 0;
|
|
if(basedim->ocname == NULL || dupdim->ocname == NULL) return 0;
|
|
if(strcmp(dupdim->ocname,basedim->ocname) != 0) return 0;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
Provide short and/or unified names for dimensions.
|
|
This must mimic lib-ncdap, which is difficult.
|
|
*/
|
|
NCerror
|
|
computecdfdimnames34(NCDAPCOMMON* nccomm)
|
|
{
|
|
int i,j;
|
|
char tmp[NC_MAX_NAME*2];
|
|
NClist* conflicts = nclistnew();
|
|
NClist* varnodes = nccomm->cdf.ddsroot->tree->varnodes;
|
|
NClist* alldims;
|
|
NClist* basedims;
|
|
|
|
/* Collect all dimension nodes from dimsetall lists */
|
|
|
|
alldims = getalldims34(nccomm,0);
|
|
|
|
/* Assign an index to all anonymous dimensions
|
|
vis-a-vis its containing variable
|
|
*/
|
|
for(i=0;i<nclistlength(varnodes);i++) {
|
|
CDFnode* var = (CDFnode*)nclistget(varnodes,i);
|
|
for(j=0;j<nclistlength(var->array.dimsetall);j++) {
|
|
CDFnode* dim = (CDFnode*)nclistget(var->array.dimsetall,j);
|
|
if(dim->ocname != NULL) continue; /* not anonymous */
|
|
computedimindexanon3(dim,var);
|
|
}
|
|
}
|
|
|
|
/* Unify dimensions by defining one dimension as the "base"
|
|
dimension, and make all "equivalent" dimensions point to the
|
|
base dimension.
|
|
1. Equivalent means: same size and both have identical non-null names.
|
|
2. Dims with same name but different sizes will be handled separately
|
|
*/
|
|
for(i=0;i<nclistlength(alldims);i++) {
|
|
CDFnode* dupdim = NULL;
|
|
CDFnode* basedim = (CDFnode*)nclistget(alldims,i);
|
|
if(basedim == NULL) continue;
|
|
if(basedim->dim.basedim != NULL) continue; /* already processed*/
|
|
for(j=i+1;j<nclistlength(alldims);j++) { /* Sigh, n**2 */
|
|
dupdim = (CDFnode*)nclistget(alldims,j);
|
|
if(basedim == dupdim) continue;
|
|
if(dupdim == NULL) continue;
|
|
if(dupdim->dim.basedim != NULL) continue; /* already processed */
|
|
if(!equivalentdim(basedim,dupdim))
|
|
continue;
|
|
dupdim->dim.basedim = basedim; /* equate */
|
|
#ifdef DEBUG1
|
|
fprintf(stderr,"assign: %s/%s -> %s/%s\n",
|
|
basedim->dim.array->ocname,basedim->ocname,
|
|
dupdim->dim.array->ocname,dupdim->ocname
|
|
);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* Next case: same name and different sizes*/
|
|
/* => rename second dim */
|
|
|
|
for(i=0;i<nclistlength(alldims);i++) {
|
|
CDFnode* basedim = (CDFnode*)nclistget(alldims,i);
|
|
if(basedim->dim.basedim != NULL) continue;
|
|
/* Collect all conflicting dimensions */
|
|
nclistclear(conflicts);
|
|
for(j=i+1;j<nclistlength(alldims);j++) {
|
|
CDFnode* dim = (CDFnode*)nclistget(alldims,j);
|
|
if(dim->dim.basedim != NULL) continue;
|
|
if(dim->ocname == NULL && basedim->ocname == NULL) continue;
|
|
if(dim->ocname == NULL || basedim->ocname == NULL) continue;
|
|
if(strcmp(dim->ocname,basedim->ocname)!=0) continue;
|
|
if(dim->dim.declsize == basedim->dim.declsize) continue;
|
|
#ifdef DEBUG2
|
|
fprintf(stderr,"conflict: %s[%lu] %s[%lu]\n",
|
|
basedim->ncfullname,(unsigned long)basedim->dim.declsize,
|
|
dim->ncfullname,(unsigned long)dim->dim.declsize);
|
|
#endif
|
|
nclistpush(conflicts,(void*)dim);
|
|
}
|
|
/* Give all the conflicting dimensions an index */
|
|
for(j=0;j<nclistlength(conflicts);j++) {
|
|
CDFnode* dim = (CDFnode*)nclistget(conflicts,j);
|
|
dim->dim.index1 = j+1;
|
|
}
|
|
}
|
|
nclistfree(conflicts);
|
|
|
|
/* Replace all non-base dimensions with their base dimension */
|
|
for(i=0;i<nclistlength(varnodes);i++) {
|
|
CDFnode* node = (CDFnode*)nclistget(varnodes,i);
|
|
replacedims(node->array.dimsetall);
|
|
replacedims(node->array.dimsetplus);
|
|
replacedims(node->array.dimset0);
|
|
}
|
|
|
|
/* Collect list of all basedims */
|
|
basedims = nclistnew();
|
|
for(i=0;i<nclistlength(alldims);i++) {
|
|
CDFnode* dim = (CDFnode*)nclistget(alldims,i);
|
|
if(dim->dim.basedim == NULL) {
|
|
if(!nclistcontains(basedims,(void*)dim)) {
|
|
nclistpush(basedims,(void*)dim);
|
|
}
|
|
}
|
|
}
|
|
|
|
nccomm->cdf.ddsroot->tree->dimnodes = basedims;
|
|
|
|
/* cleanup */
|
|
nclistfree(alldims);
|
|
|
|
/* Assign ncbasenames and ncfullnames to base dimensions */
|
|
for(i=0;i<nclistlength(basedims);i++) {
|
|
CDFnode* dim = (CDFnode*)nclistget(basedims,i);
|
|
CDFnode* var = dim->dim.array;
|
|
if(dim->dim.basedim != NULL) PANIC1("nonbase basedim: %s\n",dim->ocname);
|
|
/* stringdim names are already assigned */
|
|
if(dim->ocname == NULL) { /* anonymous: use the index to compute the name */
|
|
snprintf(tmp,sizeof(tmp),"%s_%d",
|
|
var->ncfullname,dim->dim.index1-1);
|
|
nullfree(dim->ncbasename);
|
|
dim->ncbasename = cdflegalname3(tmp);
|
|
nullfree(dim->ncfullname);
|
|
dim->ncfullname = nulldup(dim->ncbasename);
|
|
} else { /* !anonymous; use index1 if defined */
|
|
char* legalname = cdflegalname3(dim->ocname);
|
|
nullfree(dim->ncbasename);
|
|
if(dim->dim.index1 > 0) {/* need to fix conflicting names (see above) */
|
|
char sindex[64];
|
|
snprintf(sindex,sizeof(sindex),"_%d",dim->dim.index1);
|
|
dim->ncbasename = (char*)malloc(strlen(sindex)+strlen(legalname)+1);
|
|
if(dim->ncbasename == NULL) {nullfree(legalname); return NC_ENOMEM;}
|
|
strcpy(dim->ncbasename,legalname);
|
|
strcat(dim->ncbasename,sindex);
|
|
nullfree(legalname);
|
|
} else {/* standard case */
|
|
dim->ncbasename = legalname;
|
|
}
|
|
nullfree(dim->ncfullname);
|
|
dim->ncfullname = nulldup(dim->ncbasename);
|
|
}
|
|
}
|
|
|
|
/* Verify unique and defined names for dimensions*/
|
|
for(i=0;i<nclistlength(basedims);i++) {
|
|
CDFnode* dim1 = (CDFnode*)nclistget(basedims,i);
|
|
if(dim1->dim.basedim != NULL) PANIC1("nonbase basedim: %s\n",dim1->ncbasename);
|
|
if(dim1->ncbasename == NULL || dim1->ncfullname == NULL)
|
|
PANIC1("missing dim names: %s",dim1->ocname);
|
|
/* search backward so we can delete duplicates */
|
|
for(j=nclistlength(basedims)-1;j>i;j--) {
|
|
CDFnode* dim2 = (CDFnode*)nclistget(basedims,j);
|
|
if(strcmp(dim1->ncfullname,dim2->ncfullname)==0) {
|
|
/* complain and suppress one of them */
|
|
fprintf(stderr,"duplicate dim names: %s[%lu] %s[%lu]\n",
|
|
dim1->ncfullname,(unsigned long)dim1->dim.declsize,
|
|
dim2->ncfullname,(unsigned long)dim2->dim.declsize);
|
|
nclistremove(basedims,j);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
for(i=0;i<nclistlength(basedims);i++) {
|
|
CDFnode* dim = (CDFnode*)nclistget(basedims,i);
|
|
fprintf(stderr,"basedim: %s=%ld\n",dim->ncfullname,(long)dim->dim.declsize);
|
|
}
|
|
#endif
|
|
|
|
return NC_NOERR;
|
|
}
|
|
|
|
NCerror
|
|
makegetvar34(NCDAPCOMMON* nccomm, CDFnode* var, void* data, nc_type dsttype, Getvara** getvarp)
|
|
{
|
|
NCerror ncstat = NC_NOERR;
|
|
|
|
if(getvarp)
|
|
{
|
|
Getvara* getvar;
|
|
|
|
getvar = (Getvara*)calloc(1,sizeof(Getvara));
|
|
MEMCHECK(getvar,NC_ENOMEM);
|
|
|
|
getvar->target = var;
|
|
getvar->memory = data;
|
|
getvar->dsttype = dsttype;
|
|
|
|
*getvarp = getvar;
|
|
}
|
|
return ncstat;
|
|
}
|
|
|
|
int
|
|
constrainable34(NCURI* durl)
|
|
{
|
|
char** protocol = constrainableprotocols;
|
|
for(;*protocol;protocol++) {
|
|
if(strcmp(durl->protocol,*protocol)==0)
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
CDFnode*
|
|
makecdfnode34(NCDAPCOMMON* nccomm, char* ocname, OCtype octype,
|
|
/*optional*/ OCddsnode ocnode, CDFnode* container)
|
|
{
|
|
CDFnode* node;
|
|
assert(nccomm != NULL);
|
|
node = (CDFnode*)calloc(1,sizeof(CDFnode));
|
|
if(node == NULL) return (CDFnode*)NULL;
|
|
|
|
node->ocname = NULL;
|
|
if(ocname) {
|
|
size_t len = strlen(ocname);
|
|
if(len >= NC_MAX_NAME) len = NC_MAX_NAME-1;
|
|
node->ocname = (char*)malloc(len+1);
|
|
if(node->ocname == NULL) { nullfree(node); return NULL;}
|
|
memcpy(node->ocname,ocname,len);
|
|
node->ocname[len] = '\0';
|
|
}
|
|
node->nctype = octypetonc(octype);
|
|
node->ocnode = ocnode;
|
|
node->subnodes = nclistnew();
|
|
node->container = container;
|
|
if(ocnode != NULL) {
|
|
oc_dds_atomictype(nccomm->oc.conn,ocnode,&octype);
|
|
node->etype = octypetonc(octype);
|
|
}
|
|
return node;
|
|
}
|
|
|
|
/* Given an OCnode tree, mimic it as a CDFnode tree;
|
|
Add DAS attributes if DAS is available. Accumulate set
|
|
of all nodes in preorder.
|
|
*/
|
|
NCerror
|
|
buildcdftree34(NCDAPCOMMON* nccomm, OCddsnode ocroot, OCdxd occlass, CDFnode** cdfrootp)
|
|
{
|
|
CDFnode* root = NULL;
|
|
CDFtree* tree = (CDFtree*)calloc(1,sizeof(CDFtree));
|
|
NCerror err = NC_NOERR;
|
|
tree->ocroot = ocroot;
|
|
tree->nodes = nclistnew();
|
|
tree->occlass = occlass;
|
|
tree->owner = nccomm;
|
|
|
|
err = buildcdftree34r(nccomm,ocroot,NULL,tree,&root);
|
|
if(!err) {
|
|
if(occlass != OCDAS)
|
|
fixnodes34(nccomm,tree->nodes);
|
|
if(cdfrootp) *cdfrootp = root;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
static NCerror
|
|
buildcdftree34r(NCDAPCOMMON* nccomm, OCddsnode ocnode, CDFnode* container,
|
|
CDFtree* tree, CDFnode** cdfnodep)
|
|
{
|
|
size_t i,ocrank,ocnsubnodes;
|
|
OCtype octype;
|
|
OCtype ocatomtype;
|
|
char* ocname = NULL;
|
|
NCerror ncerr = NC_NOERR;
|
|
CDFnode* cdfnode;
|
|
|
|
oc_dds_class(nccomm->oc.conn,ocnode,&octype);
|
|
if(octype == OC_Atomic)
|
|
oc_dds_atomictype(nccomm->oc.conn,ocnode,&ocatomtype);
|
|
else
|
|
ocatomtype = OC_NAT;
|
|
oc_dds_name(nccomm->oc.conn,ocnode,&ocname);
|
|
oc_dds_rank(nccomm->oc.conn,ocnode,&ocrank);
|
|
oc_dds_nsubnodes(nccomm->oc.conn,ocnode,&ocnsubnodes);
|
|
|
|
#ifdef DEBUG1
|
|
if(ocatomtype == OC_NAT)
|
|
fprintf(stderr,"buildcdftree: connect: %s %s\n",oc_typetostring(octype),ocname);
|
|
else
|
|
fprintf(stderr,"buildcdftree: connect: %s %s\n",oc_typetostring(ocatomtype),ocname);
|
|
#endif
|
|
|
|
switch (octype) {
|
|
case OC_Dataset:
|
|
case OC_Grid:
|
|
case OC_Structure:
|
|
case OC_Sequence:
|
|
cdfnode = makecdfnode34(nccomm,ocname,octype,ocnode,container);
|
|
nclistpush(tree->nodes,(void*)cdfnode);
|
|
if(tree->root == NULL) {
|
|
tree->root = cdfnode;
|
|
cdfnode->tree = tree;
|
|
}
|
|
break;
|
|
|
|
case OC_Atomic:
|
|
cdfnode = makecdfnode34(nccomm,ocname,octype,ocnode,container);
|
|
nclistpush(tree->nodes,(void*)cdfnode);
|
|
if(tree->root == NULL) {
|
|
tree->root = cdfnode;
|
|
cdfnode->tree = tree;
|
|
}
|
|
break;
|
|
|
|
case OC_Dimension:
|
|
default: PANIC1("buildcdftree: unexpect OC node type: %d",(int)octype);
|
|
|
|
}
|
|
/* cross link */
|
|
cdfnode->root = tree->root;
|
|
|
|
if(ocrank > 0) defdimensions(ocnode,cdfnode,nccomm,tree);
|
|
for(i=0;i<ocnsubnodes;i++) {
|
|
OCddsnode ocsubnode;
|
|
CDFnode* subnode;
|
|
oc_dds_ithfield(nccomm->oc.conn,ocnode,i,&ocsubnode);
|
|
ncerr = buildcdftree34r(nccomm,ocsubnode,cdfnode,tree,&subnode);
|
|
if(ncerr) return ncerr;
|
|
nclistpush(cdfnode->subnodes,(void*)subnode);
|
|
}
|
|
nullfree(ocname);
|
|
if(cdfnodep) *cdfnodep = cdfnode;
|
|
return ncerr;
|
|
}
|
|
|
|
static void
|
|
defdimensions(OCddsnode ocnode, CDFnode* cdfnode, NCDAPCOMMON* nccomm, CDFtree* tree)
|
|
{
|
|
size_t i,ocrank;
|
|
|
|
oc_dds_rank(nccomm->oc.conn,ocnode,&ocrank);
|
|
assert(ocrank > 0);
|
|
for(i=0;i<ocrank;i++) {
|
|
CDFnode* cdfdim;
|
|
OCddsnode ocdim;
|
|
char* ocname;
|
|
size_t declsize;
|
|
|
|
oc_dds_ithdimension(nccomm->oc.conn,ocnode,i,&ocdim);
|
|
oc_dimension_properties(nccomm->oc.conn,ocdim,&declsize,&ocname);
|
|
|
|
cdfdim = makecdfnode34(nccomm,ocname,OC_Dimension,
|
|
ocdim,cdfnode->container);
|
|
nullfree(ocname);
|
|
nclistpush(tree->nodes,(void*)cdfdim);
|
|
/* Initially, constrained and unconstrained are same */
|
|
cdfdim->dim.declsize = declsize;
|
|
cdfdim->dim.array = cdfnode;
|
|
if(cdfnode->array.dimset0 == NULL)
|
|
cdfnode->array.dimset0 = nclistnew();
|
|
nclistpush(cdfnode->array.dimset0,(void*)cdfdim);
|
|
}
|
|
}
|
|
|
|
/* Note: this routine only applies some common
|
|
client parameters, other routines may apply
|
|
specific ones.
|
|
*/
|
|
|
|
NCerror
|
|
applyclientparams34(NCDAPCOMMON* nccomm)
|
|
{
|
|
int i,len;
|
|
int dfaltstrlen = DEFAULTSTRINGLENGTH;
|
|
int dfaltseqlim = DEFAULTSEQLIMIT;
|
|
const char* value;
|
|
char tmpname[NC_MAX_NAME+32];
|
|
char* pathstr;
|
|
OClink conn = nccomm->oc.conn;
|
|
unsigned long limit;
|
|
|
|
ASSERT(nccomm->oc.url != NULL);
|
|
|
|
nccomm->cdf.cache->cachelimit = DFALTCACHELIMIT;
|
|
value = oc_clientparam_get(conn,"cachelimit");
|
|
limit = getlimitnumber(value);
|
|
if(limit > 0) nccomm->cdf.cache->cachelimit = limit;
|
|
|
|
nccomm->cdf.fetchlimit = DFALTFETCHLIMIT;
|
|
value = oc_clientparam_get(conn,"fetchlimit");
|
|
limit = getlimitnumber(value);
|
|
if(limit > 0) nccomm->cdf.fetchlimit = limit;
|
|
|
|
nccomm->cdf.smallsizelimit = DFALTSMALLLIMIT;
|
|
value = oc_clientparam_get(conn,"smallsizelimit");
|
|
limit = getlimitnumber(value);
|
|
if(limit > 0) nccomm->cdf.smallsizelimit = limit;
|
|
|
|
nccomm->cdf.cache->cachecount = DFALTCACHECOUNT;
|
|
#ifdef HAVE_GETRLIMIT
|
|
{ struct rlimit rl;
|
|
if(getrlimit(RLIMIT_NOFILE, &rl) >= 0) {
|
|
nccomm->cdf.cache->cachecount = (size_t)(rl.rlim_cur / 2);
|
|
}
|
|
}
|
|
#endif
|
|
value = oc_clientparam_get(conn,"cachecount");
|
|
limit = getlimitnumber(value);
|
|
if(limit > 0) nccomm->cdf.cache->cachecount = limit;
|
|
/* Ignore limit if not caching */
|
|
if(!FLAGSET(nccomm->controls,NCF_CACHE))
|
|
nccomm->cdf.cache->cachecount = 0;
|
|
|
|
if(oc_clientparam_get(conn,"nolimit") != NULL)
|
|
dfaltseqlim = 0;
|
|
value = oc_clientparam_get(conn,"limit");
|
|
if(value != NULL && strlen(value) != 0) {
|
|
if(sscanf(value,"%d",&len) && len > 0) dfaltseqlim = len;
|
|
}
|
|
nccomm->cdf.defaultsequencelimit = dfaltseqlim;
|
|
|
|
/* allow embedded _ */
|
|
value = oc_clientparam_get(conn,"stringlength");
|
|
if(value != NULL && strlen(value) != 0) {
|
|
if(sscanf(value,"%d",&len) && len > 0) dfaltstrlen = len;
|
|
}
|
|
nccomm->cdf.defaultstringlength = dfaltstrlen;
|
|
|
|
/* String dimension limits apply to variables */
|
|
for(i=0;i<nclistlength(nccomm->cdf.ddsroot->tree->varnodes);i++) {
|
|
CDFnode* var = (CDFnode*)nclistget(nccomm->cdf.ddsroot->tree->varnodes,i);
|
|
/* Define the client param stringlength for this variable*/
|
|
var->maxstringlength = 0; /* => use global dfalt */
|
|
strcpy(tmpname,"stringlength_");
|
|
pathstr = makeocpathstring3(conn,var->ocnode,".");
|
|
strncat(tmpname,pathstr,NC_MAX_NAME);
|
|
nullfree(pathstr);
|
|
value = oc_clientparam_get(conn,tmpname);
|
|
if(value != NULL && strlen(value) != 0) {
|
|
if(sscanf(value,"%d",&len) && len > 0) var->maxstringlength = len;
|
|
}
|
|
}
|
|
/* Sequence limits apply to sequences */
|
|
for(i=0;i<nclistlength(nccomm->cdf.ddsroot->tree->nodes);i++) {
|
|
CDFnode* var = (CDFnode*)nclistget(nccomm->cdf.ddsroot->tree->nodes,i);
|
|
if(var->nctype != NC_Sequence) continue;
|
|
var->sequencelimit = dfaltseqlim;
|
|
strcpy(tmpname,"nolimit_");
|
|
pathstr = makeocpathstring3(conn,var->ocnode,".");
|
|
strncat(tmpname,pathstr,NC_MAX_NAME);
|
|
if(oc_clientparam_get(conn,tmpname) != NULL)
|
|
var->sequencelimit = 0;
|
|
strcpy(tmpname,"limit_");
|
|
strncat(tmpname,pathstr,NC_MAX_NAME);
|
|
value = oc_clientparam_get(conn,tmpname);
|
|
if(value != NULL && strlen(value) != 0) {
|
|
if(sscanf(value,"%d",&len) && len > 0)
|
|
var->sequencelimit = len;
|
|
}
|
|
nullfree(pathstr);
|
|
}
|
|
|
|
/* test for the appropriate fetch flags */
|
|
value = oc_clientparam_get(conn,"fetch");
|
|
if(value != NULL && strlen(value) > 0) {
|
|
if(value[0] == 'd' || value[0] == 'D') {
|
|
SETFLAG(nccomm->controls,NCF_ONDISK);
|
|
}
|
|
}
|
|
|
|
/* test for the force-whole-var flag */
|
|
value = oc_clientparam_get(conn,"wholevar");
|
|
if(value != NULL) {
|
|
SETFLAG(nccomm->controls,NCF_WHOLEVAR);
|
|
}
|
|
|
|
return NC_NOERR;
|
|
}
|
|
|
|
void
|
|
freecdfroot34(CDFnode* root)
|
|
{
|
|
int i;
|
|
CDFtree* tree;
|
|
NCDAPCOMMON* nccomm;
|
|
if(root == NULL) return;
|
|
tree = root->tree;
|
|
ASSERT((tree != NULL));
|
|
/* Explicitly FREE the ocroot */
|
|
nccomm = tree->owner;
|
|
oc_root_free(nccomm->oc.conn,tree->ocroot);
|
|
tree->ocroot = NULL;
|
|
for(i=0;i<nclistlength(tree->nodes);i++) {
|
|
CDFnode* node = (CDFnode*)nclistget(tree->nodes,i);
|
|
free1cdfnode34(node);
|
|
}
|
|
nclistfree(tree->nodes);
|
|
nclistfree(tree->varnodes);
|
|
nclistfree(tree->seqnodes);
|
|
nclistfree(tree->gridnodes);
|
|
nullfree(tree);
|
|
}
|
|
|
|
/* Free up a single node, but not any
|
|
nodes it points to.
|
|
*/
|
|
static void
|
|
free1cdfnode34(CDFnode* node)
|
|
{
|
|
unsigned int j,k;
|
|
if(node == NULL) return;
|
|
nullfree(node->ocname);
|
|
nullfree(node->ncbasename);
|
|
nullfree(node->ncfullname);
|
|
if(node->attributes != NULL) {
|
|
for(j=0;j<nclistlength(node->attributes);j++) {
|
|
NCattribute* att = (NCattribute*)nclistget(node->attributes,j);
|
|
nullfree(att->name);
|
|
for(k=0;k<nclistlength(att->values);k++)
|
|
nullfree((char*)nclistget(att->values,k));
|
|
nclistfree(att->values);
|
|
nullfree(att);
|
|
}
|
|
}
|
|
nullfree(node->dodsspecial.dimname);
|
|
nclistfree(node->subnodes);
|
|
nclistfree(node->attributes);
|
|
nclistfree(node->array.dimsetplus);
|
|
nclistfree(node->array.dimsetall);
|
|
nclistfree(node->array.dimset0);
|
|
|
|
/* Clean up the ncdap4 fields also */
|
|
nullfree(node->typename);
|
|
nullfree(node->vlenname);
|
|
nullfree(node);
|
|
}
|
|
|
|
/* Return true if node and node1 appear to refer to the same thing;
|
|
takes grid->structure changes into account.
|
|
*/
|
|
int
|
|
nodematch34(CDFnode* node1, CDFnode* node2)
|
|
{
|
|
return simplenodematch34(node1,node2);
|
|
}
|
|
|
|
/*
|
|
Try to figure out if two nodes
|
|
are the "related" =>
|
|
same name && same nc_type and same arity
|
|
but: Allow Grid == Structure
|
|
*/
|
|
|
|
int
|
|
simplenodematch34(CDFnode* node1, CDFnode* node2)
|
|
{
|
|
/* Test all the obvious stuff */
|
|
if(node1 == NULL || node2 == NULL)
|
|
return 0;
|
|
|
|
/* Add hack to address the screwed up Columbia server
|
|
which returns different Dataset {...} names
|
|
depending on the constraint.
|
|
*/
|
|
if(FLAGSET(node1->root->tree->owner->controls,NCF_COLUMBIA)
|
|
&& node1->nctype == NC_Dataset) return 1;
|
|
|
|
if(strcmp(node1->ocname,node2->ocname)!=0) /* same names */
|
|
return 0;
|
|
if(nclistlength(node1->array.dimset0)
|
|
!= nclistlength(node2->array.dimset0)) /* same arity */
|
|
return 0;
|
|
|
|
if(node1->nctype != node2->nctype) {
|
|
/* test for struct-grid match */
|
|
int structgrid = ((node1->nctype == NC_Grid && node2->nctype == NC_Structure)
|
|
|| (node1->nctype == NC_Structure && node2->nctype == NC_Grid) ? 1 : 0);
|
|
if(!structgrid)
|
|
return 0;
|
|
}
|
|
|
|
if(node1->nctype == NC_Atomic && node1->etype != node2->etype)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
Given DDS node, locate the node
|
|
in a DATADDS that matches the DDS node.
|
|
Return NULL if no node found
|
|
*/
|
|
|
|
void
|
|
unattach34(CDFnode* root)
|
|
{
|
|
unsigned int i;
|
|
CDFtree* xtree = root->tree;
|
|
for(i=0;i<nclistlength(xtree->nodes);i++) {
|
|
CDFnode* xnode = (CDFnode*)nclistget(xtree->nodes,i);
|
|
/* break bi-directional link */
|
|
xnode->attachment = NULL;
|
|
}
|
|
}
|
|
|
|
static void
|
|
setattach(CDFnode* target, CDFnode* template)
|
|
{
|
|
target->attachment = template;
|
|
template->attachment = target;
|
|
/* Transfer important information */
|
|
target->externaltype = template->externaltype;
|
|
target->maxstringlength = template->maxstringlength;
|
|
target->sequencelimit = template->sequencelimit;
|
|
target->ncid = template->ncid;
|
|
/* also transfer libncdap4 info */
|
|
target->typeid = template->typeid;
|
|
target->typesize = template->typesize;
|
|
}
|
|
|
|
static NCerror
|
|
attachdims34(CDFnode* xnode, CDFnode* template)
|
|
{
|
|
unsigned int i;
|
|
for(i=0;i<nclistlength(xnode->array.dimsetall);i++) {
|
|
CDFnode* xdim = (CDFnode*)nclistget(xnode->array.dimsetall,i);
|
|
CDFnode* tdim = (CDFnode*)nclistget(template->array.dimsetall,i);
|
|
setattach(xdim,tdim);
|
|
#ifdef DEBUG2
|
|
fprintf(stderr,"attachdim: %s->%s\n",xdim->ocname,tdim->ocname);
|
|
#endif
|
|
}
|
|
return NC_NOERR;
|
|
}
|
|
|
|
/*
|
|
Match a DATADDS node to a DDS node.
|
|
It is assumed that both trees have been re-struct'ed if necessary.
|
|
*/
|
|
|
|
static NCerror
|
|
attach34r(CDFnode* xnode, NClist* templatepath, int depth)
|
|
{
|
|
unsigned int i,plen,lastnode,gridable;
|
|
NCerror ncstat = NC_NOERR;
|
|
CDFnode* templatepathnode;
|
|
CDFnode* templatepathnext;
|
|
|
|
plen = nclistlength(templatepath);
|
|
if(depth >= plen) {THROWCHK(ncstat=NC_EINVAL); goto done;}
|
|
|
|
lastnode = (depth == (plen-1));
|
|
templatepathnode = (CDFnode*)nclistget(templatepath,depth);
|
|
ASSERT((simplenodematch34(xnode,templatepathnode)));
|
|
setattach(xnode,templatepathnode);
|
|
#ifdef DEBUG2
|
|
fprintf(stderr,"attachnode: %s->%s\n",xnode->ocname,templatepathnode->ocname);
|
|
#endif
|
|
|
|
if(lastnode) goto done; /* We have the match and are done */
|
|
|
|
if(nclistlength(xnode->array.dimsetall) > 0) {
|
|
attachdims34(xnode,templatepathnode);
|
|
}
|
|
|
|
ASSERT((!lastnode));
|
|
templatepathnext = (CDFnode*)nclistget(templatepath,depth+1);
|
|
|
|
gridable = (templatepathnext->nctype == NC_Grid && depth+2 < plen);
|
|
|
|
/* Try to find an xnode subnode that matches templatepathnext */
|
|
for(i=0;i<nclistlength(xnode->subnodes);i++) {
|
|
CDFnode* xsubnode = (CDFnode*)nclistget(xnode->subnodes,i);
|
|
if(simplenodematch34(xsubnode,templatepathnext)) {
|
|
ncstat = attach34r(xsubnode,templatepath,depth+1);
|
|
if(ncstat) goto done;
|
|
} else if(gridable && xsubnode->nctype == NC_Atomic) {
|
|
/* grids may or may not appear in the datadds;
|
|
try to match the xnode subnodes against the parts of the grid
|
|
*/
|
|
CDFnode* templatepathnext2 = (CDFnode*)nclistget(templatepath,depth+2);
|
|
if(simplenodematch34(xsubnode,templatepathnext2)) {
|
|
ncstat = attach34r(xsubnode,templatepath,depth+2);
|
|
if(ncstat) goto done;
|
|
}
|
|
}
|
|
}
|
|
done:
|
|
return THROW(ncstat);
|
|
}
|
|
|
|
NCerror
|
|
attach34(CDFnode* xroot, CDFnode* template)
|
|
{
|
|
NCerror ncstat = NC_NOERR;
|
|
NClist* templatepath = nclistnew();
|
|
CDFnode* ddsroot = template->root;
|
|
|
|
if(xroot->attachment) unattach34(xroot);
|
|
if(ddsroot != NULL && ddsroot->attachment) unattach34(ddsroot);
|
|
if(!simplenodematch34(xroot,ddsroot))
|
|
{THROWCHK(ncstat=NC_EINVAL); goto done;}
|
|
collectnodepath3(template,templatepath,WITHDATASET);
|
|
ncstat = attach34r(xroot,templatepath,0);
|
|
done:
|
|
nclistfree(templatepath);
|
|
return ncstat;
|
|
}
|
|
|
|
/*
|
|
Match nodes in template tree to nodes in target tree;
|
|
template tree is typically a structural superset of target tree.
|
|
WARNING: Dimensions are not attached
|
|
*/
|
|
|
|
NCerror
|
|
attachsubset34(CDFnode* target, CDFnode* template)
|
|
{
|
|
NCerror ncstat = NC_NOERR;
|
|
|
|
if(template == NULL) {THROWCHK(ncstat=NC_NOERR); goto done;}
|
|
if(!nodematch34(target,template)) {THROWCHK(ncstat=NC_EINVAL); goto done;}
|
|
#ifdef DEBUG2
|
|
fprintf(stderr,"attachsubset: target=%s\n",dumptree(target));
|
|
fprintf(stderr,"attachsubset: template=%s\n",dumptree(template));
|
|
#endif
|
|
ncstat = attachsubset34r(target,template);
|
|
done:
|
|
return ncstat;
|
|
}
|
|
|
|
static NCerror
|
|
attachsubset34r(CDFnode* target, CDFnode* template)
|
|
{
|
|
unsigned int i;
|
|
NCerror ncstat = NC_NOERR;
|
|
int fieldindex;
|
|
|
|
#ifdef DEBUG2
|
|
fprintf(stderr,"attachsubsetr: attach: target=%s template=%s\n",
|
|
target->ocname,template->ocname);
|
|
#endif
|
|
|
|
ASSERT((nodematch34(target,template)));
|
|
setattach(target,template);
|
|
|
|
/* Try to match target subnodes against template subnodes */
|
|
|
|
fieldindex = 0;
|
|
for(fieldindex=0,i=0;i<nclistlength(template->subnodes) && fieldindex<nclistlength(target->subnodes);i++) {
|
|
CDFnode* templatesubnode = (CDFnode*)nclistget(template->subnodes,i);
|
|
CDFnode* targetsubnode = (CDFnode*)nclistget(target->subnodes,fieldindex);
|
|
if(nodematch34(targetsubnode,templatesubnode)) {
|
|
#ifdef DEBUG2
|
|
fprintf(stderr,"attachsubsetr: match: %s :: %s\n",targetsubnode->ocname,templatesubnode->ocname);
|
|
#endif
|
|
ncstat = attachsubset34r(targetsubnode,templatesubnode);
|
|
if(ncstat) goto done;
|
|
fieldindex++;
|
|
}
|
|
}
|
|
done:
|
|
return THROW(ncstat);
|
|
}
|
|
|
|
static void
|
|
getalldims34a(NClist* dimset, NClist* alldims)
|
|
{
|
|
int i;
|
|
for(i=0;i<nclistlength(dimset);i++) {
|
|
CDFnode* dim = (CDFnode*)nclistget(dimset,i);
|
|
if(!nclistcontains(alldims,(void*)dim)) {
|
|
#ifdef DEBUG3
|
|
fprintf(stderr,"getalldims: %s[%lu]\n",
|
|
dim->ncfullname,(unsigned long)dim->dim.declsize);
|
|
#endif
|
|
nclistpush(alldims,(void*)dim);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Accumulate a set of all the known dimensions
|
|
vis-a-vis defined variables
|
|
*/
|
|
NClist*
|
|
getalldims34(NCDAPCOMMON* nccomm, int visibleonly)
|
|
{
|
|
int i;
|
|
NClist* alldims = nclistnew();
|
|
NClist* varnodes = nccomm->cdf.ddsroot->tree->varnodes;
|
|
|
|
/* get bag of all dimensions */
|
|
for(i=0;i<nclistlength(varnodes);i++) {
|
|
CDFnode* node = (CDFnode*)nclistget(varnodes,i);
|
|
if(!visibleonly || !node->invisible) {
|
|
getalldims34a(node->array.dimsetall,alldims);
|
|
}
|
|
}
|
|
return alldims;
|
|
}
|