netcdf-c/libncdap4/ncdap4.c
2010-06-03 13:24:43 +00:00

819 lines
23 KiB
C

#include "ncdap4.h"
#ifdef HAVE_GETRLIMIT
#include <sys/time.h>
#include <sys/resource.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "dapdebug.h"
#include "dapalign.h"
#include "netcdf.h"
#include "nc4dispatch.h"
#include "ncd4dispatch.h"
#ifdef DEBUG
#include "dapdump.h"
#endif
#define DFALTMODELFLAGS (NCF_NC3|NCF_NCDAP)
/* Mnemonic */
#define getgrpid(nfi) ((nfi)->ext_ncid)
#define getncid(drno) (((NC_FILE_INFO_T*)((drno)->controller))->ext_ncid)
ptrdiff_t dapsinglestride4[NC_MAX_VAR_DIMS];
extern NC_FILE_INFO_T* nc_file;
extern NCerror freeNCDRNO4(NCDRNO* drno);
static void nc4dinitialize(void);
static NCerror buildnc4(NC_FILE_INFO_T* nfi);
static NCerror builddims4(NCDRNO*);
static NCerror buildtypes4(NCDRNO*);
static NCerror buildtypes4r(NCDRNO* drno, CDFnode* tnode);
static NCerror buildvars4(NCDRNO*);
static NCerror buildglobalattrs4(NCDRNO*, int, CDFnode* root);
static NCerror buildattribute4a(NCDRNO* drno, NCattribute* att, int varid, int ncid);
static NCerror showprojection4(NCDRNO* drno, CDFnode* var);
static size_t estimatesizes4r(NCDRNO* drno, CDFnode* node);
static void estimatesizes4(NCDRNO* drno);
static NCerror fixzerodims4(NCDRNO* drno);
static NCerror fixzerodims4r(NCDRNO* drno, CDFnode* node);
static NCerror cvtunlimiteddim(NCDRNO* drno, CDFnode* dim);
static void applyclientparamcontrols4(NCDRNO* drno);
static int nc4dinitialized = 0;
/* See ncd4dispatch.c for other version */
int
NCD4_open(const char * path, int mode,
int basepe, size_t *chunksizehintp,
int useparallel, void* mpidata,
NC_Dispatch* dispatch, NC** ncpp)
{
NCerror ncstat = NC_NOERR;
OCerror ocstat = OC_NOERR;
DAPURL tmpurl;
NCDRNO* drno = NULL; /* reuse the ncdap3 structure*/
NC_HDF5_FILE_INFO_T* h5 = NULL;
NC_FILE_INFO_T* nc = NULL;
NC_GRP_INFO_T *grp = NULL;
int ncid = -1;
char* modifiedpath = NULL;
const char* value;
#ifdef PSEUDOFILE
int fd;
char* tmpname = NULL;
#else
short fileid;
#endif
LOG((1, "nc_open_file: path %s mode %d", path, mode));
if(!nc4dinitialized) nc4dinitialize();
if(!dapurlparse(path,&tmpurl)) PANIC("libncdap4: non-url path");
dapurlclear(&tmpurl); /* no longer needed */
/* Check for legal mode flags */
if((mode & NC_WRITE) != 0) ncstat = NC_EINVAL;
else if(mode & (NC_WRITE|NC_CLOBBER)) ncstat = NC_EPERM;
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
mode = (mode & ~(NC_MPIIO | NC_MPIPOSIX));
/* Despite the above check, we want the file to be initially writable */
mode |= (NC_WRITE|NC_CLOBBER);
#ifdef DEBUG
extern int ocdebug;
ocdebug = 1;
#endif
#ifdef OCCOMPILEBYDEFAULT
/* set the compile flag by default */
modifiedpath = (char*)emalloc(strlen(path)+strlen("[compile]")+1);
strcpy(modifiedpath,"[compile]");
strcat(modifiedpath,path);
#else
modifiedpath = nulldup(path);
#endif
/* Setup tentative DRNO state*/
drno = (NCDRNO*)emalloc(sizeof(NCDRNO));
MEMCHECK(drno,NC_ENOMEM);
drno->dap.urltext = modifiedpath;
drno->cdf.separator = ".";
dapurlparse(drno->dap.urltext,&drno->dap.url);
if(!constrainable34(&drno->dap.url))
SETFLAG(drno,NCF_UNCONSTRAINABLE);
drno->cdf.smallsizelimit = DFALTSMALLLIMIT;
drno->cdf.smallsizelimit = DFALTSMALLLIMIT;
drno->cdf.cache.cachelimit = DFALTCACHELIMIT;
drno->cdf.cache.cachesize = 0;
drno->cdf.cache.nodes = nclistnew();
drno->cdf.cache.cachecount = DFALTCACHECOUNT;
#ifdef HAVE_GETRLIMIT
{ struct rlimit rl;
if(getrlimit(RLIMIT_NOFILE, &rl) >= 0) {
drno->cdf.cache.cachecount = (size_t)(rl.rlim_cur / 2);
}
}
#endif
/* Re-scan the client parameters */
applyclientparamcontrols4(drno);
#ifdef PSEUDOFILE
tmpname = nulldup(PSEUDOFILE);
fd = mkstemp(tmpname);
if(fd < 0) {THROWCHK(errno); goto fail;}
/* Now, use the file to create the hdf5 file */
ncstat = NC4_create(tmpname,NC_NETCDF4|NC_CLOBBER,
0,0,NULL,0,NULL,dispatch,(NC**)&nc);
ncid = nc->ext_ncid;
/* unlink the temp file so it will automatically be reclaimed */
unlink(tmpname);
efree(tmpname);
/* Avoid fill */
dispatch->set_fill(ncid,NC_NOFILL,NULL);
if(ncstat)
{THROWCHK(ncstat); goto fail;}
/* Find our metadata for this file. */
ncstat = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5);
if(ncstat)
{THROWCHK(ncstat); goto fail;}
#else /*!PSEUDOFILE*/
/* Allocate the storage for this file info struct, and fill it with zeros*/
/* WARNING: this stores struct ptr at front of global list "nc_file" */
fileid = drno_delta_file_id(1);
if((ncstat = nc4_file_list_add(fileid << ID_SHIFT)))
goto fail;
nc = nc_file;
nc->int_ncid = nc->ext_ncid;
ncid = nc->int_ncid;
/* Add necessary structs to hold netcdf-4 file data. */
if((ncstat = nc4_nc4f_list_add(nc, path, mode)))
{THROWCHK(ncstat); goto fail;}
ASSERT((nc->nc4_info && nc->nc4_info->root_grp));
/* get the h5 structure*/
h5 = nc->nc4_info;
/* Mark as indef state and writable */
h5->flags |= NC_INDEF;
h5->no_write = 0;
#endif
nc->drno = drno;
drno->controller = (void*)nc; /* cross link*/
nc->dispatch = dispatch;
if(ncpp) *ncpp = (NC*)nc;
ocstat = oc_open(drno->dap.urltext,&drno->dap.conn);
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
if(paramcheck34(drno,"show","fetch"))
drno->controls.flags |= NCF_SHOWFETCH;
/* Turn on logging */
value = oc_clientparam_get(drno->dap.conn,"log");
if(value != NULL) {
oc_loginit();
oc_setlogging(1);
oc_logopen(value);
}
/* fetch and build the unconstrained DDS */
ncstat = fetchtemplatemetadata3(drno);
if(ncstat != NC_NOERR) goto fail;
/* Processing the constraints is a multi-step action.
1. retrieve the dds
2. convert the nc constraint names to be dap constraint
names
3. parse and merge the dap and nc constraints
*/
ncstat = buildconstraints3(drno);
if(ncstat != NC_NOERR) goto fail;
/* fetch and build the constrained DDS */
ncstat = fetchconstrainedmetadata3(drno);
if(ncstat != NC_NOERR) goto fail;
/* The following actions are WRT to the
constrained tree */
/* Accumulate useful nodes sets */
ncstat = computecdfnodesets4(drno);
if(ncstat) {THROWCHK(ncstat); goto fail;}
/* Fix grids */
ncstat = fixgrids4(drno);
if(ncstat) {THROWCHK(ncstat); goto fail;}
/* apply client parameters (after computcdfinfo and computecdfvars)*/
ncstat = applyclientparams34(drno);
if(ncstat) {THROWCHK(ncstat); goto fail;}
/* Accumulate the nodes representing user types*/
ncstat = computeusertypes4(drno);
if(ncstat) {THROWCHK(ncstat); goto fail;}
/* Re-compute the type names*/
ncstat = shortentypenames4(drno);
if(ncstat) {THROWCHK(ncstat); goto fail;}
/* Re-compute the dimension names*/
ncstat = computecdfdimnames34(drno);
if(ncstat) {THROWCHK(ncstat); goto fail;}
/* deal with zero-size dimensions */
ncstat = fixzerodims4(drno);
if(ncstat) {THROWCHK(ncstat); goto fail;}
/* Estimate the variable sizes */
estimatesizes4(drno);
ncstat = buildnc4(nc);
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
/* Do any necessary data prefetch */
ncstat = prefetchdata3(drno);
if(ncstat != NC_NOERR)
{THROWCHK(ncstat); goto fail;}
/* Mark as no longer indef and no longer writable*/
h5->flags &= ~(NC_INDEF);
h5->no_write = 1;
return ncstat;
fail:
#ifdef PSEUDOFILE
if(nc != NULL) NC4_abort(nc->ext_ncid);
#else
if(nc != NULL) {
nc4_file_list_del(nc);
}
#endif
freeNCDRNO4(drno);
if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
return THROW(ncstat);
}
int
NCD4_close(int ncid)
{
NC_FILE_INFO_T *nc;
NC_GRP_INFO_T *grp;
NC_HDF5_FILE_INFO_T *h5;
NCDRNO* drno;
int ncstat = NC_NOERR;
LOG((1, "nc_close: ncid 0x%x", ncid));
/* Find our metadata for this file. */
ncstat = nc4_find_nc_grp_h5(ncid, &nc, &grp, &h5);
if(ncstat != NC_NOERR) return THROW(ncstat);
nc = grp->file;
ASSERT((nc));
/* This must be the root group. */
if (grp->parent) ncstat = NC_EBADGRPID;
oc_logclose();
/* Destroy/close the NCDRNO state */
drno = nc->drno;
freeNCDRNO4(drno);
nc->drno = NULL;
#ifdef PSEUDOFILE
NC4_abort(ncid);
#else
/* Invoke the relevant parts of close_netcdf4_file() */
nc4_rec_grp_del(&h5->root_grp, h5->root_grp);
/* Free the nc4_info struct. */
nc_free(h5);
/* Delete this entry from our list of open files. */
nc4_file_list_del(nc);
drno_delta_numfiles(-1);
#endif
return THROW(ncstat);
}
/**************************************************/
/* Auxilliary routines */
/**************************************************/
static void
nc4dinitialize()
{
nc3dinitialize();
nc4dinitialized = 1;
}
NCerror
freeNCDRNO4(NCDRNO* drno)
{
return freeNCDRNO3(drno);
}
/*
Note: never use any of the libncdap3 code to call
netcdf API functions because it will use the netcdf-3 API.
*/
static NCerror
buildnc4(NC_FILE_INFO_T* nfi)
{
NCerror ncstat = NC_NOERR;
NCDRNO* drno = nfi->drno;
CDFnode* dds = drno->cdf.ddsroot;
ncstat = buildglobalattrs4(drno,getncid(drno),dds);
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
ncstat = builddims4(drno);
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
ncstat = buildtypes4(drno);
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
ncstat = buildvars4(drno);
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
fail:
return THROW(ncstat);
}
/* Define dim info for top-level dims */
static NCerror
builddims4(NCDRNO* drno)
{
unsigned int i,j;
NCerror ncstat = NC_NOERR;
int dimid;
NC_FILE_INFO_T* nfi = (NC_FILE_INFO_T*)drno->controller;
int ncid = getgrpid(nfi);
NClist* dimset = nclistnew();
/* collect all dimensions from variables,
including duplicates; note we use array.dimensions
not array.ncdimensions.
*/
for(i=0;i<nclistlength(drno->cdf.varnodes);i++) {
CDFnode* var = (CDFnode*)nclistget(drno->cdf.varnodes,i);
if(!var->visible) continue;
nclistextend(dimset,nclistlength(var->array.dimensions));
for(j=0;j<nclistlength(var->array.dimensions);j++) {
CDFnode* dim = (CDFnode*)nclistget(var->array.dimensions,j);
int k,inserted = 0;
/* Sort by fullname just for the fun of it */
for(k=0;k<nclistlength(dimset);k++) {
CDFnode* kdim = (CDFnode*)nclistget(dimset,k);
if(strcmp(kdim->ncfullname,dim->ncfullname) > 0) {
nclistinsert(dimset,k,(ncelem)dim);
inserted = 1;
break;
}
}
if(!inserted) nclistpush(dimset,(ncelem)dim);
}
}
/* Define those top-level dims */
for(i=0;i<nclistlength(dimset);i++) {
CDFnode* dim = (CDFnode*)nclistget(dimset,i);
if(dim->dim.basedim != NULL) continue;
ncstat = nc_def_dim(ncid,dim->ncfullname,dim->dim.declsize,&dimid);
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
dim->ncid = dimid;
}
/* Make all duplicate dims have same dimid as basedim*/
/* (see computecdfdimnames)*/
for(i=0;i<nclistlength(dimset);i++) {
CDFnode* dim = (CDFnode*)nclistget(dimset,i);
if(dim->dim.basedim != NULL) {
dim->ncid = dim->dim.basedim->ncid;
}
}
/*ok:*/
fail:
nclistfree(dimset);
return THROW(ncstat);
}
static NCerror
buildtypes4(NCDRNO* drno)
{
unsigned int i;
NCerror ncstat = NC_NOERR;
/* Define user types in postorder */
for(i=0;i<nclistlength(drno->cdf.usertypes);i++) {
CDFnode* node = (CDFnode*)nclistget(drno->cdf.usertypes,i);
if(!node->visible) continue;
ncstat = buildtypes4r(drno,node);
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
}
fail:
return THROW(ncstat);
}
static NCerror
buildtypes4r(NCDRNO* drno, CDFnode* tnode)
{
unsigned int i,j;
int typeid;
NCerror ncstat = NC_NOERR;
if(!tnode->visible) goto done;
switch (tnode->nctype) {
case NC_Sequence:
/* Look for sequences that have a single field whose
type is primitive; for these, we will not generate
the compound type.
*/
if(tnode->singleton) {
/* ok, just generate the vlen type using the sequence's
singleton field */
/* Find the first primitive visible field */
CDFnode* prim = getsingletonfield(tnode->subnodes);
ASSERT((prim != NULL));
ncstat = nc_def_vlen(getncid(drno),tnode->vlenname,
prim->etype,&typeid);
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
tnode->basetypeid = prim->etype;
tnode->typeid = typeid;
break;
}
/* fall thru */
case NC_Grid:
case NC_Structure:
ncstat = nc_def_compound(getncid(drno),tnode->typesize.instance.size,
tnode->typename,&typeid);
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
tnode->typeid = typeid;
for(i=0;i<nclistlength(tnode->subnodes);i++) {
CDFnode* field = (CDFnode*)nclistget(tnode->subnodes,i);
if(!field->visible) continue;
if(nclistlength(field->array.dimensions) == 0) {
ncstat = nc_insert_compound(getncid(drno),typeid,
field->ncbasename,
field->typesize.field.offset,
field->typeid);
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
} else {
int dimsizes[NC_MAX_VAR_DIMS];
for(j=0;j<nclistlength(field->array.dimensions);j++) {
CDFnode* dim=(CDFnode*)nclistget(field->array.dimensions,j);
dimsizes[j] = dim->dim.declsize;
}
ncstat = nc_insert_array_compound(getncid(drno),typeid,
field->ncbasename,
field->typesize.field.offset,
field->typeid,
nclistlength(field->array.dimensions),
dimsizes);
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
}
}
/* If the node is a sequence, also define the corresponding vlen type*/
if(tnode->nctype == NC_Sequence) {
ncstat = nc_def_vlen(getncid(drno),tnode->vlenname,tnode->typeid,&typeid);
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
tnode->basetypeid = typeid;
tnode->typeid = typeid;
}
break;
case NC_Primitive:
break;
default: PANIC1("unexpected nctype: %d",tnode->nctype);
}
done:
return THROW(ncstat);
}
/* Simultaneously build any associated attributes */
static NCerror
buildvars4(NCDRNO* drno)
{
/* Variables (in this translation) are (mostly)
the direct fields of the Dataset*/
unsigned int i,j;
NCerror ncstat = NC_NOERR;
int varid;
NC_FILE_INFO_T* nfi = (NC_FILE_INFO_T*)drno->controller;
int ncid = getgrpid(nfi);
for(i=0;i<nclistlength(drno->cdf.varnodes);i++) {
CDFnode* var = (CDFnode*)nclistget(drno->cdf.varnodes,i);
NClist* vardims = var->array.dimensions;
int dimids[NC_MAX_VAR_DIMS];
int ncrank,dimindex=0;
if(!var->visible) continue;
ncrank = nclistlength(vardims);
if(ncrank > 0) {
dimindex = 0;
for(j=0;j<ncrank;j++) {
CDFnode* dim = (CDFnode*)nclistget(vardims,j);
dimids[dimindex++] = dim->ncid;
}
}
setvarbasetype(drno,var);
ASSERT((var->typeid > 0));
ncstat = nc_def_var(getncid(drno),var->ncfullname,
var->typeid,
nclistlength(var->array.dimensions),
(ncrank==0?NULL:dimids),
&varid);
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
var->ncid = varid;
if(var->attributes != NULL) {
for(j=0;j<nclistlength(var->attributes);j++) {
NCattribute* att = (NCattribute*)nclistget(var->attributes,j);
ncstat = buildattribute4a(drno,att,varid,ncid);
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
}
}
/* Tag the variable with its DAP path */
if(paramcheck34(drno,"show","projection"))
showprojection4(drno,var);
}
fail:
return THROW(ncstat);
}
static NCerror
buildglobalattrs4(NCDRNO* drno, int ncid, CDFnode* root)
{
int i;
const char* txt;
char *nltxt, *p;
NCerror ncstat = NC_NOERR;
if(root->attributes != NULL) {
for(i=0;i<nclistlength(root->attributes);i++) {
NCattribute* att = (NCattribute*)nclistget(root->attributes,i);
ncstat = buildattribute4a(drno,att,NC_GLOBAL,ncid);
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
}
}
/* Define some additional system global attributes depending
on show= clientparams*/
/* Ignore failures*/
if(paramcheck34(drno,"show","translate")) {
/* Add a global attribute to show the translation */
ncstat = nc_put_att_text(ncid,NC_GLOBAL,"_translate",
strlen("netcdf-4"),"netcdf-4");
}
if(paramcheck34(drno,"show","url")) {
if(drno->dap.urltext != NULL)
ncstat = nc_put_att_text(ncid,NC_GLOBAL,"_url",
strlen(drno->dap.urltext),drno->dap.urltext);
}
if(paramcheck34(drno,"show","dds")) {
txt = NULL;
if(drno->cdf.ddsroot != NULL)
txt = oc_inq_text(drno->dap.conn,drno->cdf.ddsroot->dds);
if(txt != NULL) {
/* replace newlines with spaces*/
nltxt = nulldup(txt);
for(p=nltxt;*p;p++) {if(*p == '\n' || *p == '\r' || *p == '\t') {*p = ' ';}};
ncstat = nc_put_att_text(ncid,NC_GLOBAL,"_DDS",strlen(nltxt),nltxt);
efree(nltxt);
}
}
if(paramcheck34(drno,"show","das")) {
txt = NULL;
if(drno->dap.ocdasroot != OCNULL)
txt = oc_inq_text(drno->dap.conn,drno->dap.ocdasroot);
if(txt != NULL) {
nltxt = nulldup(txt);
for(p=nltxt;*p;p++) {if(*p == '\n' || *p == '\r' || *p == '\t') {*p = ' ';}};
ncstat = nc_put_att_text(ncid,NC_GLOBAL,"_DAS",strlen(nltxt),nltxt);
efree(nltxt);
}
}
fail:
return THROW(ncstat);
}
static NCerror
buildattribute4a(NCDRNO* drno, NCattribute* att, int varid, int ncid)
{
NCerror ncstat = NC_NOERR;
char* cname = cdflegalname3(att->name);
unsigned int nvalues = nclistlength(att->values);
unsigned int typesize = nctypesizeof(att->etype);
void* mem = emalloc(typesize * nvalues);
ncstat = dapcvtattrval3(att->etype,mem,att->values);
ncstat = nc_put_att(ncid,varid,cname,att->etype,nvalues,mem);
if(att->etype == NC_STRING) {
int i;
for(i=0;i<nvalues;i++) efree(((char**)mem)[i]);
}
efree(mem);
free(cname);
return THROW(ncstat);
}
static NCerror
showprojection4(NCDRNO* drno, CDFnode* var)
{
int i,rank;
NCerror ncstat = NC_NOERR;
NCbytes* projection = ncbytesnew();
NClist* path = nclistnew();
/* If this is not a true leaf variable, then ignore it */
if(var->nctype == NC_Sequence) return NC_NOERR;
/* Collect the set of DDS node name forming the xpath */
collectnodepath3(var,path,WITHOUTDATASET);
for(i=0;i<nclistlength(path);i++) {
CDFnode* node = (CDFnode*)nclistget(path,i);
if(i > 0) ncbytescat(projection,".");
ncbytescat(projection,node->name);
}
/* Now, add the dimension info */
rank = nclistlength(var->array.dimensions);
for(i=0;i<rank;i++) {
CDFnode* dim = (CDFnode*)nclistget(var->array.dimensions,i);
char tmp[32];
ncbytescat(projection,"[");
snprintf(tmp,sizeof(tmp),"%lu",(unsigned long)dim->dim.declsize);
ncbytescat(projection,tmp);
ncbytescat(projection,"]");
}
/* Define the attribute */
ncstat = nc_put_att_text(getncid(drno),var->ncid,
"_projection",
ncbyteslength(projection),
ncbytescontents(projection));
return ncstat;
}
static unsigned long
cdftotalsize4(NClist* dimensions)
{
unsigned int i;
unsigned long total = 1;
if(dimensions != NULL) {
for(i=0;i<nclistlength(dimensions);i++) {
CDFnode* dim = (CDFnode*)nclistget(dimensions,i);
total *= dim->dim.declsize;
}
}
return total;
}
static size_t
estimatesizes4r(NCDRNO* drno, CDFnode* node)
{
int i;
size_t size = 0;
size_t totalsize = 0;
NClist* ncdims;
unsigned int rank;
unsigned long dimsize;
for(i=0;i<nclistlength(node->subnodes);i++) {
CDFnode* subnode = (CDFnode*)nclistget(node->subnodes,i);
size += estimatesizes4r(drno,subnode);
}
switch (node->nctype) {
case NC_Primitive:
node->estimatedsize = nctypesizeof(node->etype);
break;
case NC_Dataset:
case NC_Structure:
case NC_Sequence:
case NC_Grid:
node->estimatedsize = size;
break;
default:
PANIC1("Estimatesize: Unexpected node type: %d",node->nctype);
break;
}
/* Now, take dimensions into account */
ncdims = node->array.dimensions;
rank = nclistlength(ncdims);
dimsize = cdftotalsize4(ncdims);
totalsize = (dimsize * node->estimatedsize);
if(!node->visible) totalsize = 0;
#ifdef DEBUG
fprintf(stderr,"estimatedsize: %s%s/%u = %lu (= %lu = %lu * %lu)\n",
(node->visible?"":"*"),
node->name,rank,
totalsize,
node->estimatedsize,
size,dimsize);
#endif
node->estimatedsize = totalsize;
return totalsize;
}
static void
estimatesizes4(NCDRNO* drno)
{
size_t totalsize;
CDFnode* root = drno->cdf.ddsroot;
/* Recursively compute the sizes of each node */
totalsize = estimatesizes4r(drno,root);
}
/*
For variables which have a zero size dimension,
either use unlimited, or make them invisible.
*/
static NCerror
fixzerodims4(NCDRNO* drno)
{
int i;
NCerror ncstat = NC_NOERR;
for(i=0;i<nclistlength(drno->cdf.varnodes);i++) {
CDFnode* var = (CDFnode*)nclistget(drno->cdf.varnodes,i);
ncstat = fixzerodims4r(drno,var);
}
return ncstat;
}
static NCerror
fixzerodims4r(NCDRNO* drno, CDFnode* node)
{
int i;
NCerror ncstat = NC_NOERR;
if(nclistlength(node->array.dimensions) > 0) {
for(i=0;i<nclistlength(node->array.dimensions);i++) {
CDFnode* dim = (CDFnode*)nclistget(node->array.dimensions,i);
if(dim->dim.declsize == 0) {
if(node->container->nctype == NC_Dataset) { /* use unlimited */
ncstat = cvtunlimiteddim(drno,dim);
} else { /* make node invisible */
node->visible = 0;
node->zerodim = 1;
}
}
}
}
/* walk the subnodes */
for(i=0;i<nclistlength(node->subnodes);i++) {
CDFnode* subnode = (CDFnode*)nclistget(node->subnodes,i);
ncstat = fixzerodims4r(drno,subnode);
}
return ncstat;
}
/* Convert a dimension to unlimited */
static NCerror
cvtunlimiteddim(NCDRNO* drno, CDFnode* dim)
{
DIMFLAGSET(dim,CDFDIMUNLIM);
drno->cdf.unlimited = dim;
return NC_NOERR;
}
static void
applyclientparamcontrols4(NCDRNO* drno)
{
NClist* params = NULL;
const char* value;
/* Get client parameters */
params = dapparamdecode(drno->dap.url.params);
/* enable/disable caching */
value = dapparamlookup(params,"cache");
if(value == NULL)
drno->controls.flags |= DFALTCACHEFLAG;
else if(strlen(value) == 0)
drno->controls.flags |= NCF_CACHE;
else if(strcmp(value,"1")==0 || value[0] == 'y')
drno->controls.flags |= NCF_CACHE;
/* Set the translation base */
drno->controls.flags |= (NCF_NC4);
/* No longer need params */
dapparamfree(params);
}