2011-04-18 02:56:10 +08:00
|
|
|
/*********************************************************************
|
|
|
|
* Copyright 1993, UCAR/Unidata
|
|
|
|
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
|
|
|
|
* $Header: /upc/share/CVS/netcdf-3/libncdap3/cdf3.c,v 1.33 2009/12/03 03:42:37 dmh Exp $
|
|
|
|
*********************************************************************/
|
|
|
|
|
|
|
|
#include "ncdap3.h"
|
|
|
|
#include "daputil.h"
|
|
|
|
#include "dapdump.h"
|
|
|
|
|
|
|
|
CDFnode* v4node = NULL;
|
|
|
|
|
|
|
|
/* Forward*/
|
|
|
|
static NCerror sequencecheck3r(CDFnode* node, NClist* vars, CDFnode* topseq);
|
2012-08-16 01:55:25 +08:00
|
|
|
static NCerror restruct3r(CDFnode*, CDFnode*);
|
|
|
|
static NCerror structwrap3(CDFnode*, CDFnode*, int, CDFnode*, int);
|
|
|
|
static CDFnode* makenewstruct3(CDFnode* node, CDFnode* template);
|
2011-09-16 00:57:16 +08:00
|
|
|
static NCerror mapnodes3r(CDFnode*, CDFnode*, int depth);
|
2011-11-14 12:20:19 +08:00
|
|
|
static NCerror mapfcn(CDFnode* dstnode, CDFnode* srcnode);
|
|
|
|
static NCerror definedimsetplus3(NCDAPCOMMON* nccomm, CDFnode* node);
|
|
|
|
static NCerror definedimsetall3(NCDAPCOMMON* nccomm, CDFnode* node);
|
2011-04-18 02:56:10 +08:00
|
|
|
|
|
|
|
/* Accumulate useful node sets */
|
|
|
|
NCerror
|
|
|
|
computecdfnodesets3(NCDAPCOMMON* nccomm)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
NClist* varnodes = nclistnew();
|
|
|
|
NClist* allnodes = nccomm->cdf.ddsroot->tree->nodes;
|
|
|
|
|
|
|
|
if(nccomm->cdf.seqnodes == NULL) nccomm->cdf.seqnodes = nclistnew();
|
|
|
|
if(nccomm->cdf.gridnodes == NULL) nccomm->cdf.gridnodes = nclistnew();
|
|
|
|
nclistclear(nccomm->cdf.seqnodes);
|
|
|
|
nclistclear(nccomm->cdf.gridnodes);
|
|
|
|
|
|
|
|
computevarnodes3(nccomm,allnodes,varnodes);
|
|
|
|
nclistfree(nccomm->cdf.varnodes);
|
|
|
|
nccomm->cdf.varnodes = varnodes;
|
|
|
|
|
|
|
|
/* Now compute other sets of interest */
|
|
|
|
for(i=0;i<nclistlength(allnodes);i++) {
|
|
|
|
CDFnode* node = (CDFnode*)nclistget(allnodes,i);
|
|
|
|
if(!node->visible) continue;
|
|
|
|
switch (node->nctype) {
|
|
|
|
case NC_Sequence:
|
2012-08-20 05:12:35 +08:00
|
|
|
nclistpush(nccomm->cdf.seqnodes,(void*)node);
|
2011-04-18 02:56:10 +08:00
|
|
|
break;
|
|
|
|
case NC_Grid:
|
2012-08-20 05:12:35 +08:00
|
|
|
nclistpush(nccomm->cdf.gridnodes,(void*)node);
|
2011-04-18 02:56:10 +08:00
|
|
|
break;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NC_NOERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
NCerror
|
|
|
|
computevarnodes3(NCDAPCOMMON* nccomm, NClist* allnodes, NClist* varnodes)
|
|
|
|
{
|
|
|
|
unsigned int i,len;
|
|
|
|
NClist* allvarnodes = nclistnew();
|
|
|
|
for(i=0;i<nclistlength(allnodes);i++) {
|
|
|
|
CDFnode* node = (CDFnode*)nclistget(allnodes,i);
|
2012-04-09 06:47:38 +08:00
|
|
|
/* If this node has a bad name, repair it */
|
|
|
|
if(dap_badname(node->ocname)) {
|
|
|
|
char* newname = dap_repairname(node->ocname);
|
|
|
|
nullfree(node->ocname);
|
|
|
|
node->ocname = newname;
|
|
|
|
}
|
2011-04-18 02:56:10 +08:00
|
|
|
if(!node->visible) continue;
|
2012-08-01 04:34:13 +08:00
|
|
|
if(node->nctype == NC_Atomic)
|
2012-08-20 05:12:35 +08:00
|
|
|
nclistpush(allvarnodes,(void*)node);
|
2011-04-18 02:56:10 +08:00
|
|
|
}
|
|
|
|
/* Further process the variable nodes to get the final set */
|
|
|
|
/* Use toplevel vars first */
|
|
|
|
len = nclistlength(allvarnodes);
|
|
|
|
for(i=0;i<len;i++) {
|
|
|
|
CDFnode* node = (CDFnode*)nclistget(allvarnodes,i);
|
|
|
|
if(node == NULL) continue;
|
|
|
|
if(daptoplevel(node)) {
|
2012-08-20 05:12:35 +08:00
|
|
|
nclistpush(varnodes,(void*)node);
|
|
|
|
nclistset(allvarnodes,i,(void*)NULL);
|
2011-04-18 02:56:10 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/*... then grid arrays and maps.
|
|
|
|
but exclude the coordinate variables if we are trying to
|
|
|
|
exactly mimic nc-dap
|
|
|
|
*/
|
|
|
|
for(i=0;i<len;i++) {
|
|
|
|
CDFnode* node = (CDFnode*)nclistget(allvarnodes,i);
|
|
|
|
if(node == NULL) continue;
|
|
|
|
if(dapgridarray(node)) {
|
2012-08-20 05:12:35 +08:00
|
|
|
nclistpush(varnodes,(void*)node);
|
|
|
|
nclistset(allvarnodes,i,(void*)NULL);
|
2011-04-18 02:56:10 +08:00
|
|
|
} else if(dapgridmap(node)) {
|
|
|
|
if(!FLAGSET(nccomm->controls,NCF_NCDAP))
|
2012-08-20 05:12:35 +08:00
|
|
|
nclistpush(varnodes,(void*)node);
|
|
|
|
nclistset(allvarnodes,i,(void*)NULL);
|
2011-04-18 02:56:10 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/*... then all others */
|
|
|
|
for(i=0;i<len;i++) {
|
|
|
|
CDFnode* node = (CDFnode*)nclistget(allvarnodes,i);
|
|
|
|
if(node == NULL) continue;
|
2012-08-20 05:12:35 +08:00
|
|
|
nclistpush(varnodes,(void*)node);
|
2011-04-18 02:56:10 +08:00
|
|
|
}
|
|
|
|
nclistfree(allvarnodes);
|
2012-02-04 05:31:50 +08:00
|
|
|
#ifdef DEBUG2
|
|
|
|
for(i=0;i<nclistlength(varnodes);i++) {
|
|
|
|
CDFnode* node = (CDFnode*)nclistget(varnodes,i);
|
|
|
|
if(node == NULL) continue;
|
|
|
|
fprintf(stderr,"computevarnodes: var: %s\n",makecdfpathstring3(node,"."));
|
|
|
|
}
|
|
|
|
#endif
|
2011-04-18 02:56:10 +08:00
|
|
|
return NC_NOERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
NCerror
|
|
|
|
fixgrids3(NCDAPCOMMON* nccomm)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
NClist* gridnodes = nccomm->cdf.gridnodes;
|
|
|
|
|
|
|
|
for(i=0;i<nclistlength(gridnodes);i++) {
|
|
|
|
CDFnode* grid = (CDFnode*)nclistget(gridnodes,i);
|
|
|
|
(void)fixgrid34(nccomm,grid);
|
|
|
|
/* Ignore mal-formed grids */
|
|
|
|
}
|
|
|
|
return NC_NOERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Figure out the names for variables.
|
|
|
|
*/
|
|
|
|
NCerror
|
|
|
|
computecdfvarnames3(NCDAPCOMMON* nccomm, CDFnode* root, NClist* varnodes)
|
|
|
|
{
|
|
|
|
unsigned int i,j,d;
|
|
|
|
|
|
|
|
/* clear all elided marks; except for dataset and grids */
|
|
|
|
for(i=0;i<nclistlength(root->tree->nodes);i++) {
|
|
|
|
CDFnode* node = (CDFnode*)nclistget(root->tree->nodes,i);
|
|
|
|
node->elided = 0;
|
|
|
|
if(node->nctype == NC_Grid || node->nctype == NC_Dataset)
|
|
|
|
node->elided = 1;
|
|
|
|
}
|
|
|
|
|
2011-11-14 12:20:19 +08:00
|
|
|
/* ensure all variables have an initial full name defined */
|
2011-04-18 02:56:10 +08:00
|
|
|
for(i=0;i<nclistlength(varnodes);i++) {
|
|
|
|
CDFnode* var = (CDFnode*)nclistget(varnodes,i);
|
|
|
|
nullfree(var->ncfullname);
|
|
|
|
var->ncfullname = makecdfpathstring3(var,nccomm->cdf.separator);
|
2012-02-04 05:31:50 +08:00
|
|
|
#ifdef DEBUG2
|
|
|
|
fprintf(stderr,"var names: %s %s %s\n",
|
|
|
|
var->ocname,var->ncbasename,var->ncfullname);
|
|
|
|
#endif
|
2011-04-18 02:56:10 +08:00
|
|
|
}
|
2011-11-14 12:20:19 +08:00
|
|
|
|
|
|
|
/* unify all variables with same fullname and dimensions
|
|
|
|
basevar fields says: "for duplicate grid variables";
|
|
|
|
when does this happen?
|
|
|
|
*/
|
2011-04-18 02:56:10 +08:00
|
|
|
if(FLAGSET(nccomm->controls,NCF_NC3)) {
|
|
|
|
for(i=0;i<nclistlength(varnodes);i++) {
|
|
|
|
int match;
|
|
|
|
CDFnode* var = (CDFnode*)nclistget(varnodes,i);
|
|
|
|
for(j=0;j<i;j++) {
|
|
|
|
CDFnode* testnode = (CDFnode*)nclistget(varnodes,j);
|
|
|
|
match = 1;
|
|
|
|
if(testnode->array.basevar != NULL)
|
|
|
|
continue; /* already processed */
|
|
|
|
if(strcmp(var->ncfullname,testnode->ncfullname) != 0)
|
|
|
|
match = 0;
|
2011-11-14 12:20:19 +08:00
|
|
|
else if(nclistlength(testnode->array.dimsetall)
|
|
|
|
!= nclistlength(var->array.dimsetall))
|
2011-04-18 02:56:10 +08:00
|
|
|
match = 0;
|
2011-11-14 12:20:19 +08:00
|
|
|
else for(d=0;d<nclistlength(testnode->array.dimsetall);d++) {
|
|
|
|
CDFnode* vdim = (CDFnode*)nclistget(var->array.dimsetall,d);
|
|
|
|
CDFnode* tdim = (CDFnode*)nclistget(testnode->array.dimsetall,d);
|
2011-04-18 02:56:10 +08:00
|
|
|
if(vdim->dim.declsize != tdim->dim.declsize) {
|
|
|
|
match = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(match) {
|
|
|
|
testnode->array.basevar = var;
|
2011-11-14 12:20:19 +08:00
|
|
|
fprintf(stderr,"basevar invoked: %s\n",var->ncfullname);
|
2011-04-18 02:56:10 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-02-04 05:31:50 +08:00
|
|
|
|
2011-04-18 02:56:10 +08:00
|
|
|
/* Finally, verify unique names */
|
|
|
|
for(i=0;i<nclistlength(varnodes);i++) {
|
|
|
|
CDFnode* var1 = (CDFnode*)nclistget(varnodes,i);
|
|
|
|
if(var1->array.basevar != NULL) continue;
|
|
|
|
for(j=0;j<i;j++) {
|
|
|
|
CDFnode* var2 = (CDFnode*)nclistget(varnodes,j);
|
|
|
|
if(var2->array.basevar != NULL) continue;
|
|
|
|
if(strcmp(var1->ncfullname,var2->ncfullname)==0) {
|
|
|
|
PANIC1("duplicate var names: %s",var1->ncfullname);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NC_NOERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-11-14 12:20:19 +08:00
|
|
|
/* locate and connect usable sequences and vars.
|
|
|
|
A sequence is usable iff:
|
|
|
|
1. it has a path from one of its subnodes to a leaf and that
|
|
|
|
path does not contain a sequence.
|
|
|
|
2. No parent container has dimensions.
|
|
|
|
*/
|
|
|
|
|
2011-04-18 02:56:10 +08:00
|
|
|
NCerror
|
|
|
|
sequencecheck3(NCDAPCOMMON* nccomm)
|
|
|
|
{
|
|
|
|
(void)sequencecheck3r(nccomm->cdf.ddsroot,nccomm->cdf.varnodes,NULL);
|
|
|
|
return NC_NOERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static NCerror
|
|
|
|
sequencecheck3r(CDFnode* node, NClist* vars, CDFnode* topseq)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
NCerror err = NC_NOERR;
|
|
|
|
int ok = 0;
|
2011-11-14 12:20:19 +08:00
|
|
|
if(topseq == NULL && nclistlength(node->array.dimset0) > 0) {
|
|
|
|
err = NC_EINVAL; /* This container has dimensions, so no sequence within it
|
|
|
|
can be usable */
|
2011-04-18 02:56:10 +08:00
|
|
|
} else if(node->nctype == NC_Sequence) {
|
2011-11-14 12:20:19 +08:00
|
|
|
/* Recursively walk the path for each subnode of this sequence node
|
|
|
|
looking for a path without any sequence */
|
2011-04-18 02:56:10 +08:00
|
|
|
for(i=0;i<nclistlength(node->subnodes);i++) {
|
|
|
|
CDFnode* sub = (CDFnode*)nclistget(node->subnodes,i);
|
|
|
|
err = sequencecheck3r(sub,vars,node);
|
|
|
|
if(err == NC_NOERR) ok = 1; /* there is at least 1 usable var below */
|
|
|
|
}
|
|
|
|
if(topseq == NULL && ok == 1) {
|
2011-11-14 12:20:19 +08:00
|
|
|
/* this sequence is usable because it has scalar container
|
|
|
|
(by construction) and has a path to a leaf without an intermediate
|
|
|
|
sequence. */
|
2011-04-18 02:56:10 +08:00
|
|
|
err = NC_NOERR;
|
|
|
|
node->usesequence = 1;
|
|
|
|
} else {
|
2011-11-14 12:20:19 +08:00
|
|
|
/* this sequence is unusable because it has no path
|
|
|
|
to a leaf without an intermediate sequence. */
|
2011-04-18 02:56:10 +08:00
|
|
|
node->usesequence = 0;
|
|
|
|
err = NC_EINVAL;
|
|
|
|
}
|
2012-08-20 05:12:35 +08:00
|
|
|
} else if(nclistcontains(vars,(void*)node)) {
|
2011-11-14 12:20:19 +08:00
|
|
|
/* If we reach a leaf, then topseq is usable, so save it */
|
2011-04-18 02:56:10 +08:00
|
|
|
node->array.sequence = topseq;
|
2011-11-14 12:20:19 +08:00
|
|
|
} else { /* Some kind of non-sequence container node with no dimensions */
|
2011-04-18 02:56:10 +08:00
|
|
|
/* recursively compute usability */
|
|
|
|
for(i=0;i<nclistlength(node->subnodes);i++) {
|
|
|
|
CDFnode* sub = (CDFnode*)nclistget(node->subnodes,i);
|
|
|
|
err = sequencecheck3r(sub,vars,topseq);
|
|
|
|
if(err == NC_NOERR) ok = 1;
|
|
|
|
}
|
|
|
|
err = (ok?NC_NOERR:NC_EINVAL);
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2011-11-14 12:20:19 +08:00
|
|
|
OPeNDAP is in the process of changing servers so that
|
|
|
|
partial grids are converted to structures. However, not all
|
2012-08-16 01:55:25 +08:00
|
|
|
servers do this, and not consistently.
|
|
|
|
The rules that most old-style servers appear to adhere to are these.
|
|
|
|
1. Asking for just a grid array or a single grid map
|
|
|
|
returns just the array not wrapped in a structure.
|
|
|
|
2. Asking for a subset of the fields (array plus map) of a grid
|
|
|
|
returns those fields wrapped in a structure.
|
|
|
|
3. However, there is an odd situation: asking for a grid array
|
|
|
|
plus any subset of maps that includes the last map in the grid
|
|
|
|
returns a malformed grid. This is clearly a bug.
|
|
|
|
|
|
|
|
For case 1, we insert a structure node so that case 1 is consistent
|
|
|
|
with case 2. Case 3 should cause an error with a malformed grid.
|
|
|
|
|
|
|
|
[Note: for some reason, this code has been difficult to get right;
|
|
|
|
I have rewritten 6 times and it probably is still not right.]
|
2011-11-14 12:20:19 +08:00
|
|
|
|
|
|
|
Input is
|
|
|
|
(1) the root of the dds that needs to be re-gridded
|
|
|
|
(2) the full datadds tree that defines where the grids are.
|
|
|
|
(3) the projections that were used to produce (1) from (2).
|
2012-08-16 01:55:25 +08:00
|
|
|
|
2011-04-18 02:56:10 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
NCerror
|
2012-08-16 01:55:25 +08:00
|
|
|
restruct3(CDFnode* ddsroot, CDFnode* template, NClist* projections)
|
2011-04-18 02:56:10 +08:00
|
|
|
{
|
|
|
|
NCerror ncstat = NC_NOERR;
|
|
|
|
|
2012-08-16 01:55:25 +08:00
|
|
|
/* The current restruct assumes that the ddsroot tree
|
2011-04-18 02:56:10 +08:00
|
|
|
has missing grids compared to the template.
|
|
|
|
It is also assumed that order of the nodes
|
|
|
|
in the ddsroot is the same as in the template.
|
|
|
|
*/
|
2012-08-16 01:55:25 +08:00
|
|
|
if(ddsroot->tree->restructed) return NC_NOERR;
|
2011-04-18 02:56:10 +08:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
2012-08-16 01:55:25 +08:00
|
|
|
fprintf(stderr,"restruct: ddsroot=%s\n",dumptree(ddsroot));
|
|
|
|
fprintf(stderr,"restruct: template=%s\n",dumptree(template));
|
2011-04-18 02:56:10 +08:00
|
|
|
#endif
|
|
|
|
|
2012-08-16 01:55:25 +08:00
|
|
|
/* Try to match this node against the template */
|
|
|
|
if(!simplenodematch34(ddsroot,template))
|
|
|
|
{ncstat = NC_EDATADDS; goto done;}
|
2011-04-18 02:56:10 +08:00
|
|
|
|
2012-08-16 01:55:25 +08:00
|
|
|
ncstat = restruct3r(ddsroot,template);
|
|
|
|
ddsroot->tree->restructed = 1;
|
2011-04-18 02:56:10 +08:00
|
|
|
|
2012-08-16 01:55:25 +08:00
|
|
|
done:
|
|
|
|
return THROW(ncstat);
|
2011-04-18 02:56:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-08-16 01:55:25 +08:00
|
|
|
Locate nodes in the tree rooted at node
|
|
|
|
that correspond to a single grid field in the template
|
|
|
|
when the template is a grid.
|
|
|
|
Wrap that grid field in a synthesized structure.
|
2011-04-18 02:56:10 +08:00
|
|
|
*/
|
|
|
|
static NCerror
|
2012-08-16 01:55:25 +08:00
|
|
|
restruct3r(CDFnode* node, CDFnode* template)
|
2011-04-18 02:56:10 +08:00
|
|
|
{
|
2012-08-16 01:55:25 +08:00
|
|
|
unsigned int inode, itemp, i;
|
2011-04-18 02:56:10 +08:00
|
|
|
NCerror ncstat = NC_NOERR;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2012-08-16 01:55:25 +08:00
|
|
|
fprintf(stderr,"restruct: matched: %s -> %s\n",
|
2011-11-14 12:20:19 +08:00
|
|
|
node->ocname,template->ocname);
|
2011-04-18 02:56:10 +08:00
|
|
|
#endif
|
2012-08-16 01:55:25 +08:00
|
|
|
|
|
|
|
/* this part is tricky; except for nodes needing
|
|
|
|
wrapping, the set of children of the node better
|
|
|
|
be a subset of the children in the template.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* walk each node child and locate its match
|
|
|
|
in the template's children; recurse on matches,
|
|
|
|
non-matches should be nodes needing wrapping.
|
|
|
|
*/
|
2011-04-18 02:56:10 +08:00
|
|
|
for(inode=0;inode<nclistlength(node->subnodes);inode++) {
|
|
|
|
CDFnode* subnode = (CDFnode*)nclistget(node->subnodes,inode);
|
2012-08-16 01:55:25 +08:00
|
|
|
CDFnode* wrap = NULL;
|
|
|
|
int wrapindex = 0;
|
2011-04-18 02:56:10 +08:00
|
|
|
int match = 0;
|
|
|
|
for(itemp=0;itemp<nclistlength(template->subnodes);itemp++) {
|
|
|
|
CDFnode* subtemp = (CDFnode*)nclistget(template->subnodes,itemp);
|
2012-08-16 01:55:25 +08:00
|
|
|
if(simplenodematch34(subnode,subtemp)) {
|
|
|
|
/* this subnode of the node matches the corresponding
|
|
|
|
node of the template, so it is ok =>
|
|
|
|
recurse looking for nested mis-matches
|
|
|
|
*/
|
|
|
|
ncstat = restruct3r(subnode,subtemp);
|
2011-04-18 02:56:10 +08:00
|
|
|
if(ncstat != NC_NOERR) return THROW(ncstat);
|
2012-08-16 01:55:25 +08:00
|
|
|
match = 1; /* indicate that we matched */
|
|
|
|
break;
|
|
|
|
} else if(subtemp->nctype == NC_Grid || subtemp->nctype == NC_Structure) {
|
|
|
|
/* See if we can match this subnode to a subnode
|
|
|
|
of the grid or structure */
|
|
|
|
for(i=0;i<nclistlength(subtemp->subnodes);i++) {
|
|
|
|
CDFnode* level2 = (CDFnode*)nclistget(subtemp->subnodes,i);
|
|
|
|
if(simplenodematch34(subnode,level2)) {
|
|
|
|
/* ASSUME that subnode needs rewrap wrt subtemp */
|
|
|
|
wrap = subtemp;
|
|
|
|
wrapindex = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-04-18 02:56:10 +08:00
|
|
|
}
|
2012-08-16 01:55:25 +08:00
|
|
|
if(!match && wrap == NULL) {
|
|
|
|
/* This should never occur */
|
|
|
|
ncstat = NC_EDATADDS; goto done;
|
|
|
|
}
|
|
|
|
if(wrap != NULL) { /* This subnode should need wrapping */
|
|
|
|
ASSERT(wrap->nctype == NC_Grid || wrap->nctype == NC_Structure);
|
|
|
|
ncstat = structwrap3(subnode,node,inode,wrap,wrapindex);
|
|
|
|
if(ncstat != NC_NOERR) goto done;
|
|
|
|
/* since grids are terminal, there will be no
|
|
|
|
need to continue the recursion */
|
|
|
|
}
|
2011-04-18 02:56:10 +08:00
|
|
|
}
|
2012-08-16 01:55:25 +08:00
|
|
|
done:
|
2011-04-18 02:56:10 +08:00
|
|
|
return THROW(ncstat);
|
2012-08-16 01:55:25 +08:00
|
|
|
|
2011-04-18 02:56:10 +08:00
|
|
|
}
|
|
|
|
|
2012-08-16 01:55:25 +08:00
|
|
|
/* Wrap the node wrt the template grid or template struct */
|
|
|
|
|
2011-04-18 02:56:10 +08:00
|
|
|
static NCerror
|
2012-08-16 01:55:25 +08:00
|
|
|
structwrap3(CDFnode* node, CDFnode* parent, int parentindex,
|
|
|
|
CDFnode* templategrid, int gridindex)
|
2011-04-18 02:56:10 +08:00
|
|
|
{
|
|
|
|
NCerror ncstat = NC_NOERR;
|
2012-08-16 01:55:25 +08:00
|
|
|
CDFnode* newstruct;
|
|
|
|
|
|
|
|
ASSERT((templategrid->nctype == NC_Grid || templategrid->nctype == NC_Structure));
|
|
|
|
newstruct = makenewstruct3(node,templategrid);
|
|
|
|
if(newstruct == NULL) {ncstat = NC_ENOMEM; goto done;}
|
|
|
|
/* replace the node with the new structure
|
|
|
|
in the parent's list of children*/
|
|
|
|
nclistremove(parent->subnodes,parentindex);
|
2012-08-20 05:12:35 +08:00
|
|
|
nclistinsert(parent->subnodes,parentindex,(void*)newstruct);
|
2012-08-16 01:55:25 +08:00
|
|
|
/* Update the list of all nodes in the tree */
|
2012-08-20 05:12:35 +08:00
|
|
|
nclistpush(node->root->tree->nodes,(void*)newstruct);
|
2012-08-16 01:55:25 +08:00
|
|
|
|
2011-04-18 02:56:10 +08:00
|
|
|
done:
|
|
|
|
return ncstat;
|
|
|
|
}
|
|
|
|
|
2012-08-16 01:55:25 +08:00
|
|
|
/* Create a structure to surround projected grid array or map;
|
|
|
|
this occurs because some servers (that means you ferret and you thredds!)
|
|
|
|
do not adhere to the DAP2 protocol spec.
|
|
|
|
*/
|
|
|
|
|
2011-04-18 02:56:10 +08:00
|
|
|
static CDFnode*
|
2012-08-16 01:55:25 +08:00
|
|
|
makenewstruct3(CDFnode* node, CDFnode* templatenode)
|
2011-04-18 02:56:10 +08:00
|
|
|
{
|
2012-08-16 01:55:25 +08:00
|
|
|
CDFnode* newstruct = (CDFnode*)calloc(1,sizeof(CDFnode));
|
|
|
|
if(newstruct == NULL) return NULL;
|
|
|
|
newstruct->nctype = NC_Structure;
|
2012-09-21 00:31:31 +08:00
|
|
|
newstruct->nc_virtual = 1;
|
2012-08-16 01:55:25 +08:00
|
|
|
newstruct->ocname = nulldup(templatenode->ocname);
|
|
|
|
newstruct->ocnode = templatenode->ocnode;
|
|
|
|
newstruct->ncbasename = nulldup(templatenode->ncbasename);
|
|
|
|
newstruct->subnodes = nclistnew();
|
|
|
|
newstruct->container = node->container;
|
|
|
|
newstruct->template = templatenode;
|
|
|
|
node->container = newstruct;
|
2012-08-20 05:12:35 +08:00
|
|
|
nclistpush(newstruct->subnodes,(void*)node);
|
2012-08-16 01:55:25 +08:00
|
|
|
return newstruct;
|
2011-04-18 02:56:10 +08:00
|
|
|
}
|
|
|
|
|
2011-09-16 00:57:16 +08:00
|
|
|
/**
|
|
|
|
Make the constrained dds nodes (root)
|
|
|
|
point to the corresponding unconstrained
|
2011-11-14 12:20:19 +08:00
|
|
|
dds nodes (fullroot).
|
2011-09-16 00:57:16 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
NCerror
|
|
|
|
mapnodes3(CDFnode* root, CDFnode* fullroot)
|
|
|
|
{
|
|
|
|
NCerror ncstat = NC_NOERR;
|
|
|
|
ASSERT(root != NULL && fullroot != NULL);
|
|
|
|
if(!simplenodematch34(root,fullroot))
|
|
|
|
{THROWCHK(ncstat=NC_EINVAL); goto done;}
|
|
|
|
/* clear out old associations*/
|
|
|
|
unmap3(root);
|
|
|
|
ncstat = mapnodes3r(root,fullroot,0);
|
|
|
|
done:
|
|
|
|
return ncstat;
|
|
|
|
}
|
|
|
|
|
|
|
|
static NCerror
|
|
|
|
mapnodes3r(CDFnode* connode, CDFnode* fullnode, int depth)
|
|
|
|
{
|
|
|
|
unsigned int i,j;
|
|
|
|
NCerror ncstat = NC_NOERR;
|
|
|
|
|
|
|
|
ASSERT((simplenodematch34(connode,fullnode)));
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2012-11-22 07:57:42 +08:00
|
|
|
{
|
2012-01-30 02:56:29 +08:00
|
|
|
char* path1 = makecdfpathstring3(fullnode,".");
|
|
|
|
char * path2 = makecdfpathstring3(connode,".");
|
|
|
|
fprintf(stderr,"mapnode: %s->%s\n",path1,path2);
|
|
|
|
nullfree(path1); nullfree(path2);
|
2012-11-22 07:57:42 +08:00
|
|
|
}
|
2011-09-16 00:57:16 +08:00
|
|
|
#endif
|
|
|
|
|
2011-11-14 12:20:19 +08:00
|
|
|
/* Map node */
|
|
|
|
mapfcn(connode,fullnode);
|
2011-09-16 00:57:16 +08:00
|
|
|
|
2012-11-22 07:57:42 +08:00
|
|
|
#if 0
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for(i=0;i<nclistlength(fullnode->subnodes);i++) {
|
|
|
|
CDFnode* n = (CDFnode*)nclistget(fullnode->subnodes,i);
|
|
|
|
fprintf(stderr,"fullnode.subnode[%d]: (%d) %s\n",i,n->nctype,n->ocname);
|
|
|
|
}
|
|
|
|
for(i=0;i<nclistlength(connode->subnodes);i++) {
|
|
|
|
CDFnode* n = (CDFnode*)nclistget(connode->subnodes,i);
|
|
|
|
fprintf(stderr,"connode.subnode[%d]: (%d) %s\n",i,n->nctype,n->ocname);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-09-16 00:57:16 +08:00
|
|
|
/* Try to match connode subnodes against fullnode subnodes */
|
|
|
|
ASSERT(nclistlength(connode->subnodes) <= nclistlength(fullnode->subnodes));
|
|
|
|
|
|
|
|
for(i=0;i<nclistlength(connode->subnodes);i++) {
|
|
|
|
CDFnode* consubnode = (CDFnode*)nclistget(connode->subnodes,i);
|
|
|
|
/* Search full subnodes for a matching subnode from con */
|
|
|
|
for(j=0;j<nclistlength(fullnode->subnodes);j++) {
|
|
|
|
CDFnode* fullsubnode = (CDFnode*)nclistget(fullnode->subnodes,j);
|
|
|
|
if(simplenodematch34(fullsubnode,consubnode)) {
|
|
|
|
ncstat = mapnodes3r(consubnode,fullsubnode,depth+1);
|
|
|
|
if(ncstat) goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
done:
|
|
|
|
return THROW(ncstat);
|
|
|
|
}
|
|
|
|
|
2011-11-14 12:20:19 +08:00
|
|
|
|
|
|
|
/* The specific actions of a map are defined
|
|
|
|
by this function.
|
|
|
|
*/
|
|
|
|
static NCerror
|
|
|
|
mapfcn(CDFnode* dstnode, CDFnode* srcnode)
|
|
|
|
{
|
|
|
|
/* Mark node as having been mapped */
|
|
|
|
dstnode->visible = 1;
|
|
|
|
dstnode->basenode = srcnode;
|
|
|
|
return NC_NOERR;
|
|
|
|
}
|
|
|
|
|
2011-09-16 00:57:16 +08:00
|
|
|
void
|
|
|
|
unmap3(CDFnode* root)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
CDFtree* tree = root->tree;
|
|
|
|
for(i=0;i<nclistlength(tree->nodes);i++) {
|
|
|
|
CDFnode* node = (CDFnode*)nclistget(tree->nodes,i);
|
|
|
|
node->basenode = NULL;
|
|
|
|
node->visible = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-18 02:56:10 +08:00
|
|
|
/*
|
2012-02-04 05:31:50 +08:00
|
|
|
Move dimension data from basenodes to nodes
|
2011-04-18 02:56:10 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
NCerror
|
2012-02-04 05:31:50 +08:00
|
|
|
dimimprint3(NCDAPCOMMON* nccomm)
|
2011-04-18 02:56:10 +08:00
|
|
|
{
|
|
|
|
NCerror ncstat = NC_NOERR;
|
2011-11-14 12:20:19 +08:00
|
|
|
NClist* allnodes;
|
|
|
|
int i,j;
|
|
|
|
CDFnode* basenode;
|
2011-04-18 02:56:10 +08:00
|
|
|
|
2011-11-14 12:20:19 +08:00
|
|
|
allnodes = nccomm->cdf.ddsroot->tree->nodes;
|
|
|
|
for(i=0;i<nclistlength(allnodes);i++) {
|
|
|
|
CDFnode* node = (CDFnode*)nclistget(allnodes,i);
|
|
|
|
int noderank, baserank;
|
|
|
|
/* Do dimension imprinting */
|
|
|
|
basenode = node->basenode;
|
|
|
|
if(basenode == NULL) continue;
|
|
|
|
noderank = nclistlength(node->array.dimset0);
|
|
|
|
baserank = nclistlength(basenode->array.dimset0);
|
|
|
|
if(noderank == 0) continue;
|
|
|
|
ASSERT(noderank == baserank);
|
|
|
|
#ifdef DEBUG
|
2012-02-04 05:31:50 +08:00
|
|
|
fprintf(stderr,"dimimprint %s/%d -> %s/%d\n",
|
2011-11-14 12:20:19 +08:00
|
|
|
makecdfpathstring3(basenode,"."),
|
|
|
|
noderank,
|
|
|
|
makecdfpathstring3(node,"."),
|
|
|
|
baserank);
|
|
|
|
#endif
|
|
|
|
for(j=0;j<noderank;j++) {
|
|
|
|
CDFnode* dim = (CDFnode*)nclistget(node->array.dimset0,j);
|
|
|
|
CDFnode* basedim = (CDFnode*)nclistget(basenode->array.dimset0,j);
|
|
|
|
dim->dim.declsize0 = basedim->dim.declsize;
|
|
|
|
#ifdef DEBUG
|
2012-02-04 05:31:50 +08:00
|
|
|
fprintf(stderr,"dimimprint: %d: %lu -> %lu\n",i,basedim->dim.declsize,dim->dim.declsize0);
|
2011-11-14 12:20:19 +08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
2011-04-18 02:56:10 +08:00
|
|
|
return ncstat;
|
|
|
|
}
|
|
|
|
|
2011-11-14 12:20:19 +08:00
|
|
|
static CDFnode*
|
|
|
|
clonedim(NCDAPCOMMON* nccomm, CDFnode* dim, CDFnode* var)
|
|
|
|
{
|
|
|
|
CDFnode* clone;
|
|
|
|
clone = makecdfnode34(nccomm,dim->ocname,OC_Dimension,
|
2012-08-01 04:34:13 +08:00
|
|
|
NULL,dim->container);
|
2011-11-14 12:20:19 +08:00
|
|
|
/* Record its existence */
|
2012-08-20 05:12:35 +08:00
|
|
|
nclistpush(dim->container->root->tree->nodes,(void*)clone);
|
2011-11-14 12:20:19 +08:00
|
|
|
clone->dim = dim->dim; /* copy most everything */
|
|
|
|
clone->dim.dimflags |= CDFDIMCLONE;
|
|
|
|
clone->dim.array = var;
|
|
|
|
return clone;
|
2011-04-18 02:56:10 +08:00
|
|
|
}
|
|
|
|
|
2011-11-14 12:20:19 +08:00
|
|
|
static NClist*
|
|
|
|
clonedimset3(NCDAPCOMMON* nccomm, NClist* dimset, CDFnode* var)
|
2011-04-18 02:56:10 +08:00
|
|
|
{
|
2011-11-14 12:20:19 +08:00
|
|
|
NClist* result = nclistnew();
|
|
|
|
int i;
|
|
|
|
for(i=0;i<nclistlength(dimset);i++) {
|
|
|
|
CDFnode* dim = (CDFnode*)nclistget(dimset,i);
|
2012-08-20 05:12:35 +08:00
|
|
|
nclistpush(result,(void*)clonedim(nccomm,dim,var));
|
2011-04-18 02:56:10 +08:00
|
|
|
}
|
2011-11-14 12:20:19 +08:00
|
|
|
return result;
|
2011-04-18 02:56:10 +08:00
|
|
|
}
|
|
|
|
|
2011-11-14 12:20:19 +08:00
|
|
|
/* Define the dimsetplus list for a node */
|
|
|
|
static NCerror
|
|
|
|
definedimsetplus3(NCDAPCOMMON* nccomm, CDFnode* node)
|
2011-04-18 02:56:10 +08:00
|
|
|
{
|
2011-11-14 12:20:19 +08:00
|
|
|
int ncstat = NC_NOERR;
|
|
|
|
NClist* dimset;
|
|
|
|
CDFnode* clone;
|
|
|
|
|
|
|
|
ASSERT(node->array.dimsetplus == NULL);
|
|
|
|
if(node->array.dimset0 == NULL)
|
|
|
|
dimset = nclistnew();
|
|
|
|
else { /* copy the dimset0 into dimset */
|
|
|
|
dimset = nclistclone(node->array.dimset0);
|
|
|
|
}
|
|
|
|
/* Insert the sequence or string dims */
|
|
|
|
if(node->array.stringdim != NULL) {
|
|
|
|
clone = node->array.stringdim;
|
2012-08-20 05:12:35 +08:00
|
|
|
nclistpush(dimset,(void*)clone);
|
2011-11-14 12:20:19 +08:00
|
|
|
}
|
|
|
|
if(node->array.seqdim != NULL) {
|
|
|
|
clone = node->array.seqdim;
|
2012-08-20 05:12:35 +08:00
|
|
|
nclistpush(dimset,(void*)clone);
|
2011-11-14 12:20:19 +08:00
|
|
|
}
|
|
|
|
node->array.dimsetplus = dimset;
|
|
|
|
return ncstat;
|
2011-04-18 02:56:10 +08:00
|
|
|
}
|
|
|
|
|
2011-11-14 12:20:19 +08:00
|
|
|
/* Define the dimsetall list for a node */
|
|
|
|
static NCerror
|
|
|
|
definedimsetall3(NCDAPCOMMON* nccomm, CDFnode* node)
|
2011-04-18 02:56:10 +08:00
|
|
|
{
|
2011-11-14 12:20:19 +08:00
|
|
|
int i;
|
|
|
|
int ncstat = NC_NOERR;
|
|
|
|
NClist* dimsetall;
|
|
|
|
|
2012-08-16 01:55:25 +08:00
|
|
|
/* Because of upward recursion (see below) the dimsetall may
|
|
|
|
already be defined */
|
|
|
|
if(node->array.dimsetall != NULL)
|
|
|
|
return ncstat;
|
2011-11-14 12:20:19 +08:00
|
|
|
if(node->container != NULL) {
|
|
|
|
if(node->container->array.dimsetall == NULL) {
|
|
|
|
#ifdef DEBUG1
|
2012-08-16 01:55:25 +08:00
|
|
|
fprintf(stderr,"dimsetall: recurse to container%s\n",node->container->ocname);
|
2011-11-14 12:20:19 +08:00
|
|
|
#endif
|
|
|
|
ncstat = definedimsetall3(nccomm,node->container);
|
|
|
|
if(ncstat != NC_NOERR) return ncstat;
|
|
|
|
}
|
|
|
|
/* We need to clone the parent dimensions because we will be assigning
|
|
|
|
indices vis-a-vis this variable */
|
|
|
|
dimsetall = clonedimset3(nccomm,node->container->array.dimsetall,node);
|
|
|
|
} else
|
|
|
|
dimsetall = nclistnew();
|
|
|
|
// concat parentall and dimset;
|
|
|
|
for(i=0;i<nclistlength(node->array.dimsetplus);i++) {
|
|
|
|
CDFnode* clone = (CDFnode*)nclistget(node->array.dimsetplus,i);
|
2012-08-20 05:12:35 +08:00
|
|
|
nclistpush(dimsetall,(void*)clone);
|
2011-11-14 12:20:19 +08:00
|
|
|
}
|
|
|
|
node->array.dimsetall = dimsetall;
|
|
|
|
#ifdef DEBUG1
|
|
|
|
fprintf(stderr,"dimsetall: |%s|=%d\n",node->ocname,nclistlength(dimsetall));
|
|
|
|
#endif
|
|
|
|
return ncstat;
|
2011-04-18 02:56:10 +08:00
|
|
|
}
|
|
|
|
|
2011-11-14 12:20:19 +08:00
|
|
|
/* Define the dimsetplus and dimsetall lists for
|
|
|
|
all nodes with dimensions
|
|
|
|
*/
|
2011-04-18 02:56:10 +08:00
|
|
|
NCerror
|
2011-11-14 12:20:19 +08:00
|
|
|
definedimsets3(NCDAPCOMMON* nccomm)
|
2011-04-18 02:56:10 +08:00
|
|
|
{
|
2011-11-14 12:20:19 +08:00
|
|
|
int i;
|
|
|
|
int ncstat = NC_NOERR;
|
|
|
|
NClist* allnodes = nccomm->cdf.ddsroot->tree->nodes;
|
|
|
|
|
|
|
|
for(i=0;i<nclistlength(allnodes);i++) {
|
|
|
|
CDFnode* rankednode = (CDFnode*)nclistget(allnodes,i);
|
|
|
|
if(rankednode->nctype == NC_Dimension) continue; //ignore
|
|
|
|
ASSERT((rankednode->array.dimsetplus == NULL));
|
|
|
|
ncstat = definedimsetplus3(nccomm,rankednode);
|
|
|
|
if(ncstat != NC_NOERR) return ncstat;
|
|
|
|
}
|
|
|
|
for(i=0;i<nclistlength(allnodes);i++) {
|
|
|
|
CDFnode* rankednode = (CDFnode*)nclistget(allnodes,i);
|
|
|
|
if(rankednode->nctype == NC_Dimension) continue; //ignore
|
|
|
|
ASSERT((rankednode->array.dimsetplus != NULL));
|
|
|
|
ncstat = definedimsetall3(nccomm,rankednode);
|
|
|
|
if(ncstat != NC_NOERR) return ncstat;
|
|
|
|
}
|
2011-04-18 02:56:10 +08:00
|
|
|
return NC_NOERR;
|
|
|
|
}
|
2011-11-14 12:20:19 +08:00
|
|
|
|