netcdf-c/libdap2/obsolete/getvara4.c
Dennis Heimbigner 6934aa2e8b Thread safety: step 1: cleanup
re: https://github.com/Unidata/netcdf-c/issues/1373 (partial)

* Mark some global constants be const to indicate to make them easier to track.
* Hide direct access to the ncrc_globalstate behind a function call.
* Convert dispatch tables to constants (except the user defined ones)
  This has some consequences in terms of function arguments needing to be marked
  as const also.
* Remove some no longer needed global fields
* Aggregate all the globals in nclog.c
* Uniformly replace nc_sizevector{0,1} with NC_coord_{zero,one}
* Uniformly replace nc_ptrdffvector1 with NC_stride_one
* Remove some obsolete code
2019-03-30 14:06:20 -06:00

899 lines
29 KiB
C

#include "ncdap4.h"
#include "dapodom.h"
#include "dapalign.h"
#ifdef DEBUG
#include "dapdump.h"
#endif
#include "ncd3dispatch.h"
static NCerror getcontent4(NCDAPCOMMON*, Getvara*, CDFnode* rootnode, void* data);
static NCerror getcontent4r(NCDAPCOMMON*, Getvara*, CDFnode* tnode, OCdata, NCbytes*);
static NCerror getcontent4prim(NCDAPCOMMON* dapcomm, Getvara*, CDFnode* tnode, DCEsegment*,
OCdata currentcontent, NCbytes* memory);
static int findfield(CDFnode* node, CDFnode* subnode);
static int contiguousdims(Dapodometer* odom);
static NCerror ncdap4convert(nc_type srctype, nc_type dsttype, char* memory, char* value, size_t);
static void makewholesegment4(DCEsegment* seg, NClist* dimset);
/*
See the comment preceding nc3d_getvarx
to understand how constraints are handled.
*/
int
NCD4_get_vara(int ncid, int varid,
const size_t* startp,
const size_t* countp,
const ptrdiff_t* stridep,
void* data,
nc_type externaltype0)
{
unsigned int i;
NCerror ncstat = NC_NOERR;
OCerror ocstat = OC_NOERR;
NC* drno;
NCDAPCOMMON* dapcomm;
CDFnode* cdfvar; /* cdf node mapping to var*/
NClist* varnodes;
Getvara* varainfo = NULL;
CDFnode* xtarget = NULL;
CDFnode* target = NULL;
DCEprojection* varaprojection = NULL;
NCcachenode* cachenode = NULL;
nc_type externaltype = externaltype0;
size_t localcount[NC_MAX_VAR_DIMS];
NClist* ncdimsall;
size_t ncrank;
NClist* vars = NULL;
DCEconstraint* fetchconstraint = NULL;
DCEprojection* fetchprojection = NULL;
DCEprojection* walkprojection = NULL;
int state;
#define FETCHWHOLE 1 /* fetch whole data set */
#define FETCHPART 2 /* fetch constrained variable */
#define CACHED 4 /* whole variable is already in the cache */
LOG((2, "nc_get_vara: ncid 0x%x varid %d", ncid, varid));
ncstat = NC_check_id(ncid, (NC**)&drno);
if(ncstat != NC_NOERR) goto fail;
dapcomm = (NCDAPCOMMON*)drno->dispatchdata;
/* Find cdfnode corresponding to the var.*/
varnodes = dapcomm->cdf.varnodes;
cdfvar = NULL;
for(i=0;i<nclistlength(varnodes);i++) {
CDFnode* node = (CDFnode*)nclistget(varnodes,i);
if(node->ncid == varid) {
cdfvar = node;
break;
}
}
ASSERT((cdfvar != NULL));
/* Get the dimension info */
ncdimsall = cdfvar->array.dimset0;
ncrank = nclistlength(ncdimsall);
#ifdef DEBUG
{
int i;
fprintf(stderr,"getvarx: %s",cdfvar->ncfullname);
for(i=0;i<ncrank;i++)
fprintf(stderr,"[%ld:%ld:%ld]",
(long)startp[i],
(long)countp[i],
(long)stridep[i]
);
fprintf(stderr,"\n");
}
#endif
/* Fill in missing arguments */
if(startp == NULL)
startp = NC_coord_zero;
if(countp == NULL) {
/* Accumulate the dimension sizes */
for(i=0;i<ncrank;i++) {
CDFnode* dim = (CDFnode*)nclistget(ncdimsall,i);
localcount[i] = dim->dim.declsize;
}
countp = localcount;
}
if(stridep == NULL)
stridep = NC_stride_one;
/* Validate the dimension sizes */
for(i=0;i<ncrank;i++) {
CDFnode* dim = (CDFnode*)nclistget(ncdimsall,i);
if(startp[i] > dim->dim.declsize
|| startp[i]+countp[i] > dim->dim.declsize) {
ncstat = NC_EINVALCOORDS;
goto fail;
}
}
#ifdef DEBUG
{ NClist* dims = cdfvar->array.dimset0;
fprintf(stderr,"getvarx: %s/%d",cdfvar->ncfullname,(int)nclistlength(dims));
if(nclistlength(dims) > 0) {int i;
for(i=0;i<nclistlength(dims);i++)
fprintf(stderr,"[%lu:%lu:%lu]",(unsigned long)startp[i],(unsigned long)countp[i],(unsigned long)stridep[i]);
fprintf(stderr," -> ");
for(i=0;i<nclistlength(dims);i++)
if(stridep[i]==1)
fprintf(stderr,"[%lu:%lu]",(unsigned long)startp[i],(unsigned long)((startp[i]+countp[i])-1));
else
fprintf(stderr,"[%lu:%lu:%lu]",
(unsigned long)startp[i],
(unsigned long)stridep[i],
(unsigned long)(((startp[i]+countp[i])*stridep[i])-1));
}
fprintf(stderr,"\n");
}
#endif
/* Default to using the var type */
if(externaltype == NC_NAT) externaltype = cdfvar->externaltype;
/* Validate any implied type conversion*/
if(cdfvar->nctype == NC_Primitive
&& cdfvar->etype != externaltype && externaltype == NC_CHAR) {
/* The only disallowed conversion is to/from char and non-byte
numeric types*/
switch (cdfvar->etype) {
case NC_STRING: case NC_URL:
case NC_CHAR: case NC_BYTE: case NC_UBYTE:
break;
default:
THROWCHK(NC_ECHAR);
goto fail;
}
}
ncstat = makegetvar34(dapcomm,cdfvar,data,externaltype,&varainfo);
if(ncstat) {THROWCHK(NC_ENOMEM); goto fail;}
state = 0;
if(FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE)) {
state = FETCHWHOLE;
cachenode = dapcomm->cdf.cache->prefetch;
ASSERT((cachenode != NULL));
#ifdef DEBUG
fprintf(stderr,"Unconstrained: reusing prefetch\n");
#endif
#ifdef IGNORE
} else if(iscached(dapcomm,cdfvar,&cachenode)) {
#else
} else if(iscached(dapcomm,cdfvar,&cachenode)) {
#endif
/* If it is cached, then it is a whole variable but may still
need to apply constraints */
#ifdef DEBUG
fprintf(stderr,"Reusing cache\n");
#endif
ASSERT(cachenode->wholevariable); /* by construction */
state = CACHED;
} else {/* load using constraints */
state = FETCHPART;
}
ASSERT(state != 0);
ncstat = buildvaraprojection3(varainfo,
startp,countp,nc_ptrdiffvector1,
&varaprojection);
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
/* In all cases, we need to construct the single projection
as the merge of the url projections and the vara projection.
*/
/* Convert the start/stop/stride info into a projection */
ncstat = buildvaraprojection3(varainfo,
startp,countp,stridep,
&varaprojection);
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
fetchprojection = NULL;
walkprojection = NULL;
if(state == FETCHPART) {
/* Create a merge of the url projections and the vara projection */
ncstat = daprestrictprojection(dapcomm->oc.dapconstraint->projections,
varaprojection,&fetchprojection);
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
/* Clone the projection for use with the walk */
walkprojection = (DCEprojection*)dceclone((DCEnode*)fetchprojection);
/* We might still end up with a whole variable */
if(dceiswholeprojection(fetchprojection))
state = FETCHWHOLE;
/* Build the complete constraint to use in the fetch */
fetchconstraint = (DCEconstraint*)dcecreate(CES_CONSTRAINT);
/* merged constraint just uses the url constraint selection */
fetchconstraint->selections = dceclonelist(dapcomm->oc.dapconstraint->selections);
fetchconstraint->projections = nclistnew();
nclistpush(fetchconstraint->projections,(ncelem)fetchprojection);
#ifdef DEBUG
fprintf(stderr,"getvarx: fetchconstraint: %s\n",dumpconstraint(fetchconstraint));
#endif
/* buildcachenode3 will create a new cachenode and
will also fetch the corresponding datadds */
vars = nclistnew();
nclistpush(vars,(ncelem)varainfo->target);
ncstat = buildcachenode34(dapcomm,fetchconstraint,vars,&cachenode,0);
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
} else if(state == FETCHWHOLE) {
/* buildcachenode3 will create a new cachenode and
will also fetch the corresponding datadds */
vars = nclistnew();
nclistpush(vars,(ncelem)varainfo->target);
/* Build the complete constraint to use in the fetch */
fetchconstraint = (DCEconstraint*)dcecreate(CES_CONSTRAINT);
/* merged constraint just uses the url constraint selection */
fetchconstraint->selections = dceclonelist(dapcomm->oc.dapconstraint->selections);
/* Use no projections */
fetchconstraint->projections = nclistnew();
ncstat = buildcachenode34(dapcomm,fetchconstraint,vars,&cachenode,0);
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
}
ASSERT(cachenode != NULL);
#ifdef DEBUG
fprintf(stderr,"cache.datadds=%s\n",dumptree(cachenode->datadds));
#endif
/* attach DATADDS to DDS */
unattach34(dapcomm->cdf.ddsroot);
ncstat = attachsubset34(cachenode->datadds,dapcomm->cdf.ddsroot);
if(ncstat) goto fail;
/* Now, walk to the relevant instance */
switch (state) {
case FETCHWHOLE: case CACHED:
/* Create a merge of the url projections and the vara projection */
ncstat = daprestrictprojection(dapcomm->oc.dapconstraint->projections,
varaprojection,&walkprojection);
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
break;
case FETCHPART:
/* Derive the proper walk projection from the
fetchprojection (actually the clone created above) */
ncstat = dapshiftprojection(walkprojection);/*arg will be modified */
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
break;
default: PANIC("illegal getvarx state");
}
#ifdef DEBUG
fprintf(stderr,"getvarx: walkprojection: %s\n",dumpprojection(walkprojection));
#endif
/* Fix up varainfo to use the cache */
varainfo->cache = cachenode;
varainfo->varaprojection = walkprojection;
walkprojection = NULL;
/* Get the var correlate from the datadds */
target = varainfo->target;
/* xtarget is in the datadds space */
xtarget = target->attachment;
if(xtarget == NULL)
{THROWCHK(ncstat=NC_ENODATA); goto fail;}
/* Switch to datadds tree space*/
varainfo->target = xtarget;
ncstat = getcontent4(dapcomm,varainfo,cachenode->datadds,data);
if(ncstat != OC_NOERR) {THROWCHK(ncstat); goto fail;}
goto ok;
fail:
if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
ok:
nclistfree(vars);
dcefree((DCEnode*)fetchconstraint);
dcefree((DCEnode*)varaprojection);
freegetvara(varainfo);
return THROW(ncstat);
}
static NCerror
getcontent4(NCDAPCOMMON* dapcomm, Getvara* xgetvar, CDFnode* xroot, void* data)
{
NCerror ncstat = NC_NOERR;
OCerror ocstat = OC_NOERR;
NCbytes* memory;
size_t alloc;
int fieldindex;
CDFnode* tnode = xgetvar->target;
OCconnection conn = dapcomm->oc.conn;
OCdata rootcontent = OCNULL;
OCdata fieldcontent = OCNULL;
OCdata dimcontent = OCNULL;
OCdata seqcontent = OCNULL;
OCdata gridcontent = OCNULL;
Dapodometer* odom = NULL;
OCobject ocroot = OCNULL;
int caching = FLAGSET(dapcomm->controls,NCF_CACHE);
int unconstrainable = FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE);
nc_type externaltype = xgetvar->dsttype;
/* is var from a toplevel grid? */
int virtual = tnode->virtual;
/* is var a toplevel Sequence? */
int seqvar = daptopseq(tnode);
if(seqvar) {
alloc = sizeof(nc_vlen_t);
} if(tnode->nctype == NC_Primitive) {
/* compute the # elements */
size_t nelems = dimproduct3(tnode->array.dimset0);
/* Pull the field size from the externaltype. */
alloc = (nctypesizeof(externaltype)*nelems);
} else {
ASSERT((tnode->attachment != NULL));
/* Pull the field size from the node type size. */
alloc = (size_t)(tnode->attachment->typesize.field.size);
}
#ifdef READCHECK
fprintf(stderr,"getcontent4: |%s| = %lu\n",tnode->name,alloc);
#endif
memory = ncbytesnew();
ncbytessetcontents(memory,data,alloc);
/* Get the root content*/
ocroot = xroot->tree->ocroot;
rootcontent = oc_data_new(conn);
ocstat = oc_data_root(conn,ocroot,rootcontent);
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
/* Move to the field for this var;
handle grid vars separately */
if(virtual) {
int gridindex;
/* Get index of the grid node wrt to the root node */
gridindex = findfield(xroot,tnode->container);
if(gridindex < 0) {ncstat = NC_ENOTVAR; goto fail;}
gridcontent = oc_data_new(conn);
ocstat = oc_data_ith(conn,rootcontent,gridindex,gridcontent);
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
/* Now move to the relevant grid field */
fieldindex = findfield(tnode->container,tnode);
if(fieldindex < 0) {ncstat = NC_ENOTVAR; goto fail;}
fieldcontent = oc_data_new(conn);
ocstat = oc_data_ith(conn,gridcontent,fieldindex,fieldcontent);
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
} else if(seqvar) { /* Move to the seq data */
int seqindex = findfield(xroot,tnode);
if(seqindex < 0) {ncstat = NC_ENOTVAR; goto fail;}
seqcontent = oc_data_new(conn);
ocstat = oc_data_ith(conn,rootcontent,seqindex,seqcontent);
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
} else {
fieldindex = findfield(xroot,tnode);
if(fieldindex < 0) {ncstat = NC_ENOTVAR; goto fail;}
if(tnode->virtual) {
int structindex;
/* Get index of the struct node wrt to the root node */
structindex = findfield(xroot,tnode->container);
if(structindex < 0) {ncstat = NC_ENOTVAR; goto fail;}
/* Get index of the structure field wrt to the virtual struct */
fieldindex = findfield(tnode->container,tnode);
if(fieldindex < 0) {ncstat = NC_ENOTVAR; goto fail;}
/* Actual field is structindex + fieldindex */
fieldindex += structindex;
fieldcontent = oc_data_new(conn);
ocstat = oc_data_ith(conn,fieldcontent,fieldindex,fieldcontent);
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
} else {
fieldcontent = oc_data_new(conn);
ocstat = oc_data_ith(conn,rootcontent,fieldindex,fieldcontent);
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
}
}
if(seqvar) {
ASSERT((seqcontent != OCNULL));
ncstat=getcontent4r(dapcomm,xgetvar,tnode,seqcontent,memory);
} else if(tnode->nctype == NC_Primitive) {
/* Stride the dimensions and get the instances */
DCEsegment* segment = NULL;
ASSERT((nclistlength(xgetvar->varaprojection->var->segments)==1));
segment = (DCEsegment*)nclistget(xgetvar->varaprojection->var->segments,0);
ASSERT((fieldcontent != OCNULL));
ncstat = getcontent4prim(dapcomm,xgetvar,tnode,segment,fieldcontent,memory);
} else if(nclistlength(tnode->array.dimset0) > 0) {
/* Stride the dimensions and get the instances */
DCEsegment* segment = NULL;
ASSERT((nclistlength(xgetvar->varaprojection->var->segments)==1));
segment = (DCEsegment*)nclistget(xgetvar->varaprojection->var->segments,0);
if(caching || unconstrainable) {
odom = newdapodometer(segment->slices,0,segment->rank);
} else { /*Since vara was projected out, build a simple odometer*/
odom = newsimpledapodometer(segment,segment->rank);
}
while(dapodometermore(odom)) {
/* Compute which instance to move to*/
unsigned int dimoffset = dapodometercount(odom);
dimcontent = oc_data_new(conn);
ocstat = oc_data_ith(conn,fieldcontent,dimoffset,dimcontent);
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
ncstat = getcontent4r(dapcomm,xgetvar,tnode,dimcontent,memory);
dapodometerincr(odom);
}
freedapodometer(odom);
} else {
ncstat=getcontent4r(dapcomm,xgetvar,tnode,fieldcontent,memory);
}
/*ok:*/
fail:
oc_data_free(conn,gridcontent);
oc_data_free(conn,seqcontent);
oc_data_free(conn,dimcontent);
oc_data_free(conn,fieldcontent);
oc_data_free(conn,rootcontent);
ncbytesfree(memory);/* leaves contents untouched */
if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
return THROW(ncstat);
}
/* Recursive walker part of getcontent */
static NCerror
getcontent4r(NCDAPCOMMON* dapcomm,
Getvara* xgetvar,
CDFnode* tnode, /* type definition */
OCdata currentcontent,
NCbytes* memory)
{
unsigned int i;
OCerror ocstat = OC_NOERR;
NCerror ncstat = NC_NOERR;
OCmode mode;
OCconnection conn = dapcomm->oc.conn;
OCdata reccontent = OCNULL;
OCdata fieldcontent = OCNULL;
OCdata dimcontent = OCNULL;
Dapodometer* odom = NULL;
NCbytes* vlenmemory = NULL;
nc_vlen_t vlenref = {0,NULL};
int caching = FLAGSET(dapcomm->controls,NCF_CACHE);
int unconstrainable = FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE);
oc_data_mode(conn,currentcontent,&mode);
#ifdef READCHECK
{
int rank = nclistlength(tnode->array.dimset0);
fprintf(stderr,"getcontent4r: rank=%lu mode=%d nctype=%s\n",
(unsigned long)rank,mode,nctypetostring(tnode->nctype));
}
#endif
if(tnode->nctype == NC_Primitive) {
DCEsegment seg; /* temporary */
seg.name = tnode->ocname;
seg.cdfnode = tnode;
makewholesegment4(&seg,tnode->array.dimset0);
ncstat = getcontent4prim(dapcomm,xgetvar,tnode,&seg,currentcontent,memory);
goto done;
}
if(tnode->virtual) {
fprintf(stderr,"VIRTUAL ENCOUNTER\n");
abort();
}
switch (mode) {
case OCARRAYMODE: {
unsigned int rank = nclistlength(tnode->array.dimset0);
DCEsegment seg; /* temporary */
ASSERT((tnode->nctype == NC_Structure));
seg.name = tnode->ocname;
seg.cdfnode = tnode;
makewholesegment4(&seg,tnode->array.dimset0);
/* The goal here is to walk the indices (if any)
and extract each instance */
ASSERT((rank > 0));
if(caching || unconstrainable) {
odom = newdapodometer(seg.slices,0,rank);
} else { /*Since vara was projected out, build a simple odometer*/
odom = newsimpledapodometer(&seg,rank);
}
dimcontent = oc_data_new(conn);
while(dapodometermore(odom)) {
/* Compute which instance to move to*/
unsigned int dimoffset = dapodometercount(odom);
ocstat = oc_data_ith(conn,currentcontent,dimoffset,dimcontent);
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
ncstat = getcontent4r(dapcomm,xgetvar,tnode,dimcontent,memory);
}
} break;
case OCFIELDMODE: /* Walk each field in turn */
/* Align the buffer to struct boundary*/
alignbuffer3(memory,tnode->typesize.instance.alignment);
fieldcontent = oc_data_new(conn);
for(i=0;i<nclistlength(tnode->subnodes);i++) {
CDFnode* subnode = (CDFnode*)nclistget(tnode->subnodes,i);
ocstat = oc_data_ith(conn,currentcontent,i,fieldcontent);
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
ncstat = getcontent4r(dapcomm,xgetvar,subnode,fieldcontent,memory);
}
break;
case OCSEQUENCEMODE:
/* Collect the set of records as a separate memory structure */
vlenmemory = ncbytesnew();
ncbytessetalloc(vlenmemory,4096);
#ifdef READCHECK
fprintf(stderr,"getcontent4r: record: vlenmemory=%lx\n",
(unsigned long)ncbytescontents(vlenmemory));
#endif
reccontent = oc_data_new(conn);
for(i=0;;i++) {
ocstat = oc_data_ith(conn,currentcontent,i,reccontent);
if(ocstat == OC_EINVALCOORDS) {ocstat=OC_NOERR; break;} /* no more records */
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
ncstat = getcontent4r(dapcomm,xgetvar,tnode,reccontent,vlenmemory);
}
vlenref.len = i;
vlenref.p = ncbytesextract(vlenmemory);
#ifdef READCHECK
fprintf(stderr,"getcontent4r: record: vlen.p=%lx\n",
(unsigned long)vlenref.p);
#endif
/* Now put an nc_vlen_t into our buffer */
alignbuffer3(memory,tnode->typesize.field.alignment);
ncbytesappendn(memory,(char*)&vlenref,sizeof(vlenref));
#ifdef READCHECK
fprintf(stderr,"getcontent4r: record: memory=%lx |memory|=%lu\n",
(unsigned long)ncbytescontents(memory),(unsigned long)ncbyteslength(memory));
#endif
break;
default: ncstat = NC_EINVAL; {THROWCHK(ncstat); goto fail;}
}
done:
fail:
ncbytesfree(vlenmemory);
oc_data_free(conn,dimcontent);
oc_data_free(conn,fieldcontent);
oc_data_free(conn,reccontent);
if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
return THROW(ncstat);
}
static NCerror
getcontent4prim(NCDAPCOMMON* dapcomm,
Getvara* xgetvar,
CDFnode* tnode,
DCEsegment* segment,
OCdata currentcontent,
NCbytes* memory)
{
OCerror ocstat = OC_NOERR;
NCerror ncstat = NC_NOERR;
unsigned int rank;
OCconnection conn = dapcomm->oc.conn;
Dapodometer* odom = NULL;
unsigned int memoffset;
DCEslice* slices = segment->slices;
int caching = FLAGSET(dapcomm->controls,NCF_CACHE);
int unconstrainable = FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE);
size_t internaltypesize, externaltypesize;
nc_type internaltype = segment->cdfnode->etype;
nc_type externaltype = xgetvar->dsttype;
int bit8type; /* is this an 8 bit type? */
if(externaltype == NC_NAT) externaltype = internaltype;
internaltypesize = nctypesizeof(internaltype);
externaltypesize = nctypesizeof(externaltype);
switch (internaltype) {
case NC_CHAR: case NC_BYTE: case NC_UBYTE: bit8type = 1; break;
default: bit8type = 0; break;
}
rank = nclistlength(tnode->array.dimset0);
ASSERT((rank == segment->rank));
#ifdef READCHECK
fprintf(stderr,"getcontent4prim: tnode=%s/%d segment=%s internaltype=%s externaltype=%s memory=%lx internaltypesize=%lu externaltypesize=%lu\n",
tnode->name,rank,dumpsegment(segment),
nctypetostring(internaltype),nctypetostring(externaltype),
(unsigned long)ncbytescontents(memory),
(unsigned long)internaltypesize,
(unsigned long)externaltypesize);
#endif
alignbuffer3(memory,ncctypealignment(externaltype)); /* Align to the proper boundary */
memoffset = ncbyteslength(memory);
#ifdef READCHECK
fprintf(stderr,"getcontent4prim: alignment=%d memory.after=%lx\n",
ncctypealignment(externaltype),(unsigned long)ncbytescontents(memory));
#endif
if(rank == 0) { /* singleton data item*/
char value[32]; /* big enough to hold any single primitive value*/
void* memdata;
ASSERT((internaltypesize <= sizeof(value)));
if(!ncbytessetlength(memory,memoffset+externaltypesize))
return NC_ENOMEM;
#ifdef READCHECK
fprintf(stderr,"getcontent4prim: scalar: memory=%lx |memory|=%lu\n",
(unsigned long)ncbytescontents(memory),(unsigned long)ncbyteslength(memory));
#endif
memdata = ncbytescontents(memory)+memoffset;
#ifdef READCHECK
fprintf(stderr,"getcontent4prim: scalar: memdata=%lx\n",(unsigned long)memdata);
#endif
ocstat = oc_data_get(conn,currentcontent,value,sizeof(value),0,1);
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
ncstat = ncdap4convert(internaltype,externaltype,memdata,value,1);
if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
} else { /* rank > 0 */
size_t requested, arraysize;
char* memdata;
int contiguous;
if(caching || unconstrainable) {
odom = newdapodometer(slices,0,rank);
} else {
odom = newsimpledapodometer(segment,rank);
}
/* Compute the actual # of values requested by the caller */
requested = dapodometerpoints(odom);
if(bit8type && externaltype == NC_STRING) { /* special case */
arraysize = nctypesizeof(NC_STRING); /* allocate a single string */
} else
arraysize = externaltypesize*requested;
if(!ncbytessetlength(memory,memoffset+arraysize)) return NC_ENOMEM;
memdata = ncbytescontents(memory)+memoffset;
#ifdef TEST
{
size_t dimcount;
oc_data_count(conn,currentcontent,&dimcount);
printf("read: %s: memoffset=%lu externaltypesize=%lu dimcount=%lu requested=%lu arraysize=%lu\n",
tnode->name,(unsigned long)memoffset,(unsigned long)externaltypesize,
(unsigned long)dimcount,(unsigned long)requested,arraysize);
fflush(stdout);
}
#endif
/* Optimize off the use of the odometer by checking the slicing
to locate the largest possible suffix of dimensions that
represent a contiguous chunk; However do not do this if
external type conversion is needed.
*/
contiguous = contiguousdims(odom);
if(contiguous < odom->rank && internaltype == externaltype) {
/* Compute the chunk size */
size_t chunkcount;
ASSERT((odom->rank != 1 || contiguous == 0));
chunkcount = dapodometerspace(odom,contiguous);
if(contiguous == 0) {
/* The whole vara slice is usable:
read the whole chunk at one shot.
*/
/* copy the data locally before conversion */
ocstat = oc_data_get(conn,currentcontent,memdata,
arraysize,0,chunkcount);
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
} else { /* odom->rank > 1 && contiguous > 0 */
size_t memchunk = (externaltypesize * chunkcount);
/* Use the odometer to find each contiguous chunk. */
odom->rank = contiguous; /* move in chunksize chunks */
while(dapodometermore(odom)) {
size_t nchunks = dapodometercount(odom);
size_t chunkoffset = nchunks * chunkcount;
ocstat = oc_data_get(conn,currentcontent,memdata,
arraysize,chunkoffset,chunkcount);
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
memdata += memchunk;
arraysize -= memchunk;
dapodometerincr(odom);
}
}
} else if(bit8type && externaltype == NC_STRING) {
/* special case conversion */
char* s = (char*)malloc(requested+1); /* bytes will go into a single string */
char** sp = (char**)memdata;
ocstat = oc_data_get(conn,currentcontent,s,requested,0,requested);
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
*sp = s;
memdata += externaltypesize;
} else { /*Oh well,use the odometer to walk to the appropriate fields*/
char value[32]; /* to hold any value*/
while(dapodometermore(odom)) {
size_t dimoffset = dapodometercount(odom);
ocstat = oc_data_get(conn,currentcontent,value,sizeof(value),dimoffset,1);
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
ocstat = ncdap4convert(internaltype,externaltype,memdata,value,1);
if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;}
memdata += externaltypesize;
dapodometerincr(odom);
}
}
}
/*ok:*/
fail:
freedapodometer(odom);
if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
return THROW(ncstat);
}
static int
findfield(CDFnode* node, CDFnode* subnode)
{
size_t i;
for(i=0;i<nclistlength(node->subnodes);i++) {
CDFnode* test = (CDFnode*)nclistget(node->subnodes,i);
if(test == subnode) return i;
}
return -1;
}
/*
Find the largest prefix of n dimensions such that:
n .. odom.rank are complete: they have start of 0,
stride of 1 and count == dimensions size.
*/
static int
contiguousdims(Dapodometer* odom)
{
unsigned int i;
int mark = 0;
if(odom->rank <= 1) return 0;
for(i=0;i<odom->rank;i++) {
ASSERT((odom->slices[i].declsize != 0));
if(odom->slices[i].stride != 1
|| odom->slices[i].first > 0
|| odom->slices[i].length != odom->slices[i].declsize)
mark=i;
}
return mark+1;
}
static NCerror
ncdap4convert(nc_type srctype, nc_type dsttype, char* memory, char* value, size_t count)
{
NCerror ncstat = NC_NOERR;
size_t i;
#define CASE(nc1,nc2) (nc1*256+nc2)
switch (CASE(srctype,dsttype)) {
/* the NC_STRING/URL case is only used by ncdap4 */
case CASE(NC_STRING,NC_STRING):
case CASE(NC_STRING,NC_URL):
case CASE(NC_URL,NC_STRING):
case CASE(NC_URL,NC_URL):
for(i=0;i<count;i++) {
*((char**)memory) = (char*) *(char**)value;
memory += nctypesizeof(dsttype);
}
break;
/* conversion of string/url to char is illegal
because caller will not know size
*/
case CASE(NC_STRING,NC_CHAR):
case CASE(NC_URL,NC_CHAR):
ncstat = NC_EINVAL;
break;
/* convert char/byte/ubyte to string by creating a single string;
not clear this is correct
*/
case CASE(NC_BYTE,NC_STRING):
case CASE(NC_UBYTE,NC_STRING):
case CASE(NC_CHAR,NC_STRING): {
char* s = (char*)malloc(count+1);
char** smem = (char**)memory;
memcpy((void*)s,value,count);
s[count] = '\0';
*smem = s;
memory += nctypesizeof(dsttype);
} break;
default:
ncstat = dapconvert3(srctype,dsttype,memory,value,count);
break;
}
/*ok:*/
return THROW(ncstat);
}
#ifdef IGNORE
/* In order to construct the projection,
we need to make sure to match the relevant dimensions
against the relevant nodes in which the ultimate target
is contained.
*/
static NCerror
buildvaraprojection4(NCDAPCOMMON* dapcomm, Getvara* getvar, NCbytes* buf)
{
int i, dimdex;
CDFnode* node;
CDFnode* target = getvar->target;
NClist* path = NULL;
#ifdef DEBUG
fprintf(stderr,"vara: %s\n",getvaraprint(getvar));
#endif
if(!getvar->projected) return NC_NOERR;
path = nclistnew();
collectnodepath3(target,path,WITHOUTDATASET);
if(nclistlength(path) == 0) return NC_NOERR;
ncbytesclear(buf);
for(dimdex=0,i=0;i<nclistlength(path);i++) {
node = (CDFnode*)nclistget(path,i);
if(i>0) ncbytescat(buf,"."); /* we are past the first projection*/
ncbytescat(buf,node->name);
#ifdef IGNORE
if(node->nctype == NC_Sequence) {
ASSERT((node->usesequence == 1));
dimdex++;
} else if(nclistlength(node->array.dimset0) > 0) {
makevarprojection3(getvar->slices,dimdex,nclistlength(node->array.dimset0),buf);
dimdex += nclistlength(node->array.dimset0);
}
#endif
}
#ifdef DEBUG
fprintf(stderr,"projection=|%s|",ncbytescontents(buf)); fflush(stderr);
#endif
nclistfree(path);
return NC_NOERR;
}
static void
makevarprojection3(NCslice* slices, int dimdex, int ndims, NCbytes* buf)
{
int i;
char tmp[1024];
NCslice* slice = slices+dimdex;
for(i=0;i<ndims;i++,slice++) {
snprintf(tmp,sizeof(tmp),"[%lu:%lu:%lu]",
(unsigned long)slice->first,
(unsigned long)slice->stride,
(unsigned long)(slice->stop - 1));
ncbytescat(buf,tmp);
}
}
#endif
static void
makewholesegment4(DCEsegment* seg, NClist* dimset)
{
int i;
unsigned int rank;
rank = nclistlength(dimset);
seg->rank = rank;
for(i=0;i<rank;i++) {
CDFnode* dim = (CDFnode*)nclistget(dimset,i);
dcemakewholeslice(&seg->slices[i],dim->dim.declsize);
}
seg->slicesdefined = 1;
seg->slicesdeclized = 1;
}