/* Given two projection lists, merge src into dst taking overlapping projections into acct. */ int dapmergeprojections(NClist* dst, NClist* src) { int i; NClist* cat = nclistnew(); int ncstat = NC_NOERR; #ifdef DEBUG fprintf(stderr,"dapmergeprojection: dst = %s\n",dcetostring((DCEnode*)dst)); fprintf(stderr,"dapmergeprojection: src = %s\n",dcetostring((DCEnode*)src)); #endif /* get dst concat clone(src) */ nclistsetalloc(cat,nclistlength(dst)+nclistlength(src)); for(i=0;i<nclistlength(dst);i++) { DCEprojection* p = (DCEprojection*)nclistget(dst,i); nclistpush(cat,(ncelem)p); } for(i=0;i<nclistlength(src);i++) { DCEprojection* p = (DCEprojection*)nclistget(src,i); nclistpush(cat,(ncelem)dceclone((DCEnode*)p)); } nclistclear(dst); /* Repeatedly pull elements from the concat, merge with all duplicates, and stick into the dst */ while(nclistlength(cat) > 0) { DCEprojection* target = (DCEprojection*)nclistremove(cat,0); if(target == NULL) continue; if(target->discrim != CES_VAR) continue; for(i=0;i<nclistlength(cat);i++) { DCEprojection* p2 = (DCEprojection*)nclistget(cat,i); if(p2 == NULL) continue; if(p2->discrim != CES_VAR) continue; if(dcesamepath(target->var->segments, p2->var->segments)!=0) continue; /* This entry matches our current target; merge */ ncstat = mergeprojection(target,p2); /* null out this merged entry and release it */ nclistset(cat,i,(ncelem)NULL); dcefree((DCEnode*)p2); } /* Capture the clone */ nclistpush(dst,(ncelem)target); } nclistfree(cat); return ncstat; }
/* Wrapper for ceparse */ int dapceparse(char* input, DCEconstraint* constraint, char** errmsgp) { DCEparsestate* state; int errcode = 0; #ifdef PARSEDEBUG dcedebug = 1; #endif if(input != NULL) { #ifdef DEBUG fprintf(stderr,"dceeparse: input=%s\n",input); #endif state = ce_parse_init(input,constraint); if(dceparse(state) == 0) { #ifdef DEBUG if(nclistlength(constraint->projections) > 0) fprintf(stderr,"dceeparse: projections=%s\n", dcetostring((DCEnode*)constraint->projections)); #endif #ifdef DEBUG if(nclistlength(constraint->selections) > 0) fprintf(stderr,"dceeparse: selections=%s\n", dumpselections(constraint->selections)); #endif } else { if(errmsgp) *errmsgp = nulldup(state->errorbuf); } errcode = state->errorcode; dce_parse_cleanup(state); } return errcode; }
char* dumpconstraint(DCEconstraint* con) { char* tmp; int v = dceverbose; dceverbose = 1; tmp = dcetostring((DCEnode*)con); dceverbose = v; return tmp; }
char* dumpprojection(DCEprojection* proj) { char* tmp; int v = dceverbose; dceverbose = 1; tmp = dcetostring((DCEnode*)proj); dceverbose = v; return tmp; }
void selections(DCEparsestate* state, Object list0) { NClist* list = (NClist*)list0; if(list != NULL) { nclistfree(state->constraint->selections); state->constraint->selections = list; } #ifdef DEBUG fprintf(stderr," ce.selections: %s\n", dcetostring((DCEnode*)state->constraint->selections)); #endif }
static void slicedump(const char* prefix, DCEslice* s) { #if 1 int v = dceverbose; dceverbose = 1; fprintf(stderr,"%s: %s\n",prefix,dcetostring((DCEnode*)s)); dceverbose = v; #else size_t last = (s->first+s->length)-1; fprintf(stderr,"%s: [%lu:%lu:%lu p=%lu l=%lu c=%lu]\n", prefix,s->first,s->stride,last,s->stop,s->length,s->count); #endif }
Object projection(DCEparsestate* state, Object varorfcn) { DCEprojection* p = (DCEprojection*)dcecreate(CES_PROJECT); CEsort tag = *(CEsort*)varorfcn; if(tag == CES_FCN) p->fcn = varorfcn; else p->var = varorfcn; p->discrim = tag; #ifdef DEBUG fprintf(stderr," ce.projection: %s\n", dcetostring((DCEnode*)p)); #endif return p; }
/* Parse incoming url constraints, if any, to check for syntactic correctness */ int dapparseconstraints(char* constraints, DCEconstraint* dapconstraint) { int ncstat = NC_NOERR; char* errmsg; assert(dapconstraint != NULL); nclistclear(dapconstraint->projections); nclistclear(dapconstraint->selections); ncstat = dapceparse(constraints,dapconstraint,&errmsg); if(ncstat) { nclog(NCLOGWARN,"DAP constraint parse failure: %s",errmsg); if(errmsg) free(errmsg); nclistclear(dapconstraint->projections); nclistclear(dapconstraint->selections); } #ifdef DEBUG fprintf(stderr,"constraint: %s",dcetostring((DCEnode*)dapconstraint)); #endif return ncstat; }
/* This should be consistent with makeslicestring3 in constraints3.c */ char* dumpslice(DCEslice* slice) { return dcetostring((DCEnode*)slice); }
char* dumpconstraint(DCEconstraint* con) { return dcetostring((DCEnode*)con); }
char* dumpselection(DCEselection* sel) { return dcetostring((DCEnode*)sel); }
char* dumpprojection(DCEprojection* proj) { return dcetostring((DCEnode*)proj); }
/* We are at a primitive variable or scalar that has no string dimensions. Extract the data. (This is way too complicated) */ static int extract( NCDAPCOMMON* nccomm, Getvara* xgetvar, CDFnode* xnode, DCEsegment* segment, size_t dimindex,/*notused*/ OClink conn, OCdatanode currentcontent, struct NCMEMORY* memory ) { OCerror ocstat = OC_NOERR; NCerror ncstat = NC_NOERR; size_t count,rank0; Dapodometer* odom = NULL; size_t externtypesize; size_t interntypesize; int requireconversion; char value[16]; ASSERT((segment != NULL)); requireconversion = conversionrequired(xgetvar->dsttype,xnode->etype); ASSERT(xgetvar->cache != NULL); externtypesize = nctypesizeof(xgetvar->dsttype); interntypesize = nctypesizeof(xnode->etype); rank0 = nclistlength(xnode->array.dimset0); #ifdef DEBUG2 fprintf(stderr,"moveto: primitive: segment=%s", dcetostring((DCEnode*)segment)); fprintf(stderr," iswholevariable=%d",xgetvar->cache->wholevariable); fprintf(stderr,"\n"); #endif if(rank0 == 0) {/* scalar */ char* mem = (requireconversion?value:memory->next); ASSERT(externtypesize <= sizeof(value)); /* Read the whole scalar directly into memory */ ocstat = oc_data_readscalar(conn,currentcontent,externtypesize,mem); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} if(requireconversion) { /* convert the value to external type */ ncstat = dapconvert3(xnode->etype,xgetvar->dsttype,memory->next,value,1); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} } memory->next += (externtypesize); } else if(xgetvar->cache->wholevariable) {/* && rank0 > 0 */ /* There are multiple cases, assuming no conversion required. 1) client is asking for whole variable => start=0, count=totalsize, stride=1 => read whole thing at one shot 2) client is asking for non-strided subset and edges are maximal => start=x, count=y, stride=1 => read whole subset at one shot 3) client is asking for strided subset or edges are not maximal => start=x, count=y, stride=s => we have to use odometer on leading prefix. If conversion required, then read one-by-one */ int safeindex = dcesafeindex(segment,0,rank0); assert(safeindex >= 0 && safeindex <= rank0); if(!requireconversion && safeindex == 0) { /* can read whole thing */ size_t internlen; count = dcesegmentsize(segment,0,rank0); /* how many to read */ internlen = interntypesize*count; /* Read the whole variable directly into memory.*/ ocstat = oc_data_readn(conn,currentcontent,dap_zero,count,internlen,memory->next); /* bump memory pointer */ memory->next += internlen; if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} } else if(!requireconversion && safeindex > 0 && safeindex < rank0) { size_t internlen; /* We need to build an odometer for the unsafe prefix of the slices */ odom = dapodom_fromsegment(segment,0,safeindex); count = dcesegmentsize(segment,safeindex,rank0); /* read in count chunks */ internlen = interntypesize*count; while(dapodom_more(odom)) { ocstat = oc_data_readn(conn,currentcontent,odom->index,count,internlen,memory->next); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} memory->next += internlen; dapodom_next(odom); } dapodom_free(odom); } else { /* Cover following cases, all of which require reading values one-by-one: 1. requireconversion 2. !requireconversion but safeindex == rank0 =>no safe indices Note that in case 2, we will do a no-op conversion. */ odom = dapodom_fromsegment(segment,0,rank0); while(dapodom_more(odom)) { char value[16]; /* Big enough to hold any numeric value */ ocstat = oc_data_readn(conn,currentcontent,odom->index,1,interntypesize,value); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} ncstat = dapconvert3(xnode->etype,xgetvar->dsttype,memory->next,value,1); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} memory->next += (externtypesize); dapodom_next(odom); } dapodom_free(odom); } } else { /* !xgetvar->cache->wholevariable && rank0 > 0 */ /* This is the case where the constraint was applied by the server, so we just read it in, possibly with conversion */ if(requireconversion) { /* read one-by-one */ odom = dapodom_fromsegment(segment,0,rank0); while(dapodom_more(odom)) { char value[16]; /* Big enough to hold any numeric value */ ocstat = oc_data_readn(conn,currentcontent,odom->index,1,interntypesize,value); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} ncstat = dapconvert3(xnode->etype,xgetvar->dsttype,memory->next,value,1); if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} memory->next += (externtypesize); dapodom_next(odom); } dapodom_free(odom); } else {/* Read straight to memory */ size_t internlen; count = dcesegmentsize(segment,0,rank0); /* how many to read */ internlen = interntypesize*count; ocstat = oc_data_readn(conn,currentcontent,dap_zero,count,internlen,memory->next); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} } } done: return THROW(ncstat); }
static NCerror movetor(NCDAPCOMMON* nccomm, OCdatanode currentcontent, NClist* path, int depth, /* depth is position in segment list*/ Getvara* xgetvar, size_t dimindex, /* dimindex is position in xgetvar->slices*/ struct NCMEMORY* memory, NClist* segments) { OCerror ocstat = OC_NOERR; NCerror ncstat = NC_NOERR; OClink conn = nccomm->oc.conn; CDFnode* xnode = (CDFnode*)nclistget(path,depth); OCdatanode reccontent = NULL; OCdatanode dimcontent = NULL; OCdatanode fieldcontent = NULL; Dapodometer* odom = NULL; int hasstringdim = 0; DCEsegment* segment; OCDT mode; /* Note that we use depth-1 because the path contains the DATASET but the segment list does not */ segment = (DCEsegment*)nclistget(segments,depth-1); /*may be NULL*/ if(xnode->etype == NC_STRING || xnode->etype == NC_URL) hasstringdim = 1; /* Get the mode */ mode = oc_data_mode(conn,currentcontent); #ifdef DEBUG2 fprintf(stderr,"moveto: nctype=%d depth=%d dimindex=%d mode=%s", xnode->nctype, depth,dimindex,oc_data_modestring(mode)); fprintf(stderr," segment=%s hasstringdim=%d\n", dcetostring((DCEnode*)segment),hasstringdim); #endif switch (xnode->nctype) { #if 0 #define OCDT_FIELD ((OCDT)(1)) /* field of a container */ #define OCDT_ELEMENT ((OCDT)(2)) /* element of a structure array */ #define OCDT_RECORD ((OCDT)(4)) /* record of a sequence */ #define OCDT_ARRAY ((OCDT)(8)) /* is structure array */ #define OCDT_SEQUENCE ((OCDT)(16)) /* is sequence */ #define OCDT_ATOMIC ((OCDT)(32)) /* is atomic leaf */ #endif default: goto done; case NC_Grid: case NC_Dataset: case NC_Structure: /* Separate out the case where structure is dimensioned */ if(oc_data_indexable(conn,currentcontent)) { /* => dimensioned structure */ /* The current segment should reflect the proper parts of the nc_get_vara argument */ /* Create odometer for this structure's part of the projection */ odom = dapodom_fromsegment(segment,0,segment->rank); while(dapodom_more(odom)) { /* Compute which instance to move to*/ ocstat = oc_data_ithelement(conn,currentcontent, odom->index,&dimcontent); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} ASSERT(oc_data_indexed(conn,dimcontent)); ncstat = movetor(nccomm,dimcontent, path,depth,/*keep same depth*/ xgetvar,dimindex+segment->rank, memory,segments); dapodom_next(odom); } dapodom_free(odom); } else {/* scalar instance */ ncstat = movetofield(nccomm,currentcontent,path,depth,xgetvar,dimindex,memory,segments); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} } break; case NC_Sequence: if(fIsSet(mode,OCDT_SEQUENCE)) { ASSERT((xnode->attachment != NULL)); ASSERT((segment != NULL)); ASSERT((segment->rank == 1)); /* Build an odometer for walking the sequence, however, watch out for the case when the user set a limit and that limit is not actually reached in this request. */ /* By construction, this sequence represents the first (and only) dimension of this segment */ odom = dapodom_fromsegment(segment,0,1); while(dapodom_more(odom)) { size_t recordindex = dapodom_count(odom); ocstat = oc_data_ithrecord(conn,currentcontent, recordindex,&reccontent); if(ocstat != OC_NOERR) { if(ocstat == OC_EINDEX) ocstat = OC_EINVALCOORDS; THROWCHK(ocstat); goto done; } ncstat = movetor(nccomm,reccontent, path,depth, xgetvar,dimindex+1, memory,segments); if(ncstat != OC_NOERR) {THROWCHK(ncstat); goto done;} dapodom_next(odom); } } else if(fIsSet(mode,OCDT_RECORD)) { /* Treat like structure */ /* currentcontent points to the record instance */ ncstat = movetofield(nccomm,currentcontent,path,depth,xgetvar,dimindex,memory,segments); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} } break; case NC_Atomic: if(hasstringdim) ncstat = extractstring(nccomm, xgetvar, xnode, segment, dimindex, conn, currentcontent, memory); else ncstat = extract(nccomm, xgetvar, xnode, segment, dimindex, conn, currentcontent, memory); break; } done: 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 movetor(NCDAPCOMMON* nccomm, OCdata currentcontent, NClist* path, int depth, /* depth is position in segment list*/ Getvara* xgetvar, int dimindex, /* dimindex is position in xgetvar->slices*/ struct NCMEMORY* memory, NClist* segments) { int i; OCerror ocstat = OC_NOERR; NCerror ncstat = NC_NOERR; size_t fieldindex,gridindex,rank; OCconnection conn = nccomm->oc.conn; CDFnode* xnode = (CDFnode*)nclistget(path,depth); OCdata reccontent = OCNULL; OCdata dimcontent = OCNULL; OCdata fieldcontent = OCNULL; Dapodometer* odom = OCNULL; OCmode currentmode = OCNULLMODE; CDFnode* xnext; int hasstringdim = 0; size_t dimoffset; DCEsegment* segment; int newdepth; int caching = FLAGSET(nccomm->controls,NCF_CACHE); int unconstrainable = FLAGSET(nccomm->controls,NCF_UNCONSTRAINABLE); /* Note that we use depth-1 because the path contains the DATASET but the segment list does not */ segment = (DCEsegment*)nclistget(segments,depth-1); /*may be NULL*/ if(xnode->etype == NC_STRING || xnode->etype == NC_URL) hasstringdim = 1; ocstat = oc_data_mode(conn,currentcontent,¤tmode); #ifdef DEBUG2 fprintf(stderr,"moveto: nctype=%d currentmode=%d depth=%d dimindex=%d", xnode->nctype, currentmode, depth,dimindex); fprintf(stderr," segment=%s hasstringdim=%d\n", dcetostring((DCEnode*)segment),hasstringdim); #endif /* Switch on the combination of nctype and mode */ #define CASE(nc1,nc2) (nc1*1024+nc2) /* This must be consistent with the oc mode transition function */ switch (CASE(xnode->nctype,currentmode)) { default: PANIC2("Illegal combination: nctype=%d mode=%d", (int)xnode->nctype,(int)currentmode); break; case CASE(NC_Sequence,OCFIELDMODE): case CASE(NC_Dataset,OCFIELDMODE): case CASE(NC_Grid,OCFIELDMODE): case CASE(NC_Structure,OCFIELDMODE): /* currentcontent points to the grid/dataset/structure instance */ xnext = (CDFnode*)nclistget(path,depth+1); ASSERT((xnext != NULL)); fieldindex = findfield(xnode,xnext); /* If the next node is a virtual node, then we need to effectively ignore it and use the appropriate subnode. If the next node is a structuregrid node, then use it as is. */ if(xnext->virtual) { CDFnode* xgrid = xnext; xnext = (CDFnode*)nclistget(path,depth+2); /* real node */ gridindex = fieldindex; fieldindex = findfield(xgrid,xnext); fieldindex += gridindex; newdepth = depth+2; } else { newdepth = depth+1; } fieldcontent = oc_data_new(conn); ocstat = oc_data_ith(conn,currentcontent,fieldindex,fieldcontent); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;} ncstat = movetor(nccomm,fieldcontent, path,newdepth,xgetvar,dimindex,memory, segments); break; case CASE(NC_Sequence,OCARRAYMODE): /* will actually always be scalar, but will have rank == 1 to account for the sequence dim */ case CASE(NC_Grid,OCARRAYMODE): /* will actually always be scalar */ case CASE(NC_Structure,OCARRAYMODE): /* figure out which slices refer to this node: dimindex upto dimindex+rank; */ ASSERT((segment != NULL)); rank = segment->rank; if(xnode->nctype == NC_Sequence) rank--; /* ignore the sequence dim */ if(rank == 0) { odom = newdapodometer1(1); } else if(caching || unconstrainable) { odom = newdapodometer(segment->slices,0,rank); } else { /*Since vara was projected out, build a simple odometer*/ odom = newsimpledapodometer(segment,rank); } while(dapodometermore(odom)) { OCmode mode; /* Compute which instance to move to*/ dimoffset = dapodometercount(odom); dimcontent = oc_data_new(conn); ocstat = oc_data_ith(conn,currentcontent,dimoffset,dimcontent); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;} ocstat = oc_data_mode(conn,dimcontent,&mode); ASSERT((mode == OCFIELDMODE || (mode == OCSEQUENCEMODE && xnode->nctype == NC_Sequence))); ncstat = movetor(nccomm,dimcontent, path,depth, xgetvar,dimindex+rank, memory,segments); dapodometerincr(odom); } freedapodometer(odom); break; case CASE(NC_Sequence,OCSEQUENCEMODE): { DCEslice* uslice; ASSERT((segment != NULL)); /* Get and check the corresponding sequence dimension from DDS */ ASSERT((xnode->attachment != NULL)); /* use uslice to walk the sequence; however, watch out for the case when the user set a limit and that limit is not actually reached in this request. */ /* By construction, this sequence represents the first (and only) dimension of this segment */ uslice = &segment->slices[0]; reccontent = oc_data_new(conn); for(i=uslice->first;i<uslice->stop;i+=uslice->stride) { OCmode eos; ocstat = oc_data_ith(conn,currentcontent,i,reccontent); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;} ocstat = oc_data_mode(conn,reccontent,&eos); if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto fail;} if(eos == OCNULLMODE) { /* We asked for too much */ ncstat = THROW(NC_EINVALCOORDS); goto fail; } ncstat = movetor(nccomm,reccontent, path,depth, xgetvar,dimindex+1, memory,segments); if(ncstat != OC_NOERR) {THROWCHK(ncstat); goto fail;} } } break; case CASE(NC_Primitive,OCPRIMITIVEMODE): if(hasstringdim) ncstat = extractstring(nccomm, xgetvar, xnode, segment, conn, currentcontent, memory); else ncstat = extract(nccomm, xgetvar, xnode, segment, conn, currentcontent, memory); break; }