/* Parse incoming url constraints, if any, to check for syntactic correctness */ NCerror parsedapconstraints(NCDAPCOMMON* dapcomm, char* constraints, DCEconstraint* dceconstraint) { NCerror ncstat = NC_NOERR; char* errmsg; ASSERT(dceconstraint != NULL); nclistclear(dceconstraint->projections); nclistclear(dceconstraint->selections); ncstat = dapceparse(constraints,dceconstraint,&errmsg); if(ncstat) { nclog(NCLOGWARN,"DCE constraint parse failure: %s",errmsg); nullfree(errmsg); nclistclear(dceconstraint->projections); nclistclear(dceconstraint->selections); } else { #ifdef IGNORE int i; #ifdef DEBUG NClist* allnodes; fprintf(stderr,"constraint: %s",dumpconstraint(dceconstraint)); #endif /* Go thru each node and add annotation */ allnodes = dceallnodes((DCEnode*)dceconstraint,CES_NIL); for(i=0;i<nclistlength(allnodes);i++) { DCEnode* node = (DCEnode*)nclistget(allnodes,i); } #endif } return ncstat; }
/* Accumulate useful node sets */ NCerror computecdfnodesets3(NCDAPCOMMON* nccomm, CDFtree* tree) { unsigned int i; NClist* varnodes; NClist* allnodes; allnodes = tree->nodes; varnodes = nclistnew(); if(tree->seqnodes == NULL) tree->seqnodes = nclistnew(); if(tree->gridnodes == NULL) tree->gridnodes = nclistnew(); nclistclear(tree->seqnodes); nclistclear(tree->gridnodes); computevarnodes3(nccomm,allnodes,varnodes); nclistfree(tree->varnodes); tree->varnodes = varnodes; varnodes = NULL; /* Now compute other sets of interest */ for(i=0;i<nclistlength(allnodes);i++) { CDFnode* node = (CDFnode*)nclistget(allnodes,i); switch (node->nctype) { case NC_Sequence: nclistpush(tree->seqnodes,(void*)node); break; case NC_Grid: nclistpush(tree->gridnodes,(void*)node); break; default: break; } } return NC_NOERR; }
/* convert all names in selections to be fully qualified */ static NCerror qualifyselectionnames3(DCEselection* sel) { NCerror ncstat = NC_NOERR; int i; NClist* segments = NULL; NClist* fullpath = nclistnew(); ASSERT(sel->lhs->discrim == CES_VAR); collectnodepath3((CDFnode*)sel->lhs->var->annotation,fullpath,!WITHDATASET); #ifdef DEBUG fprintf(stderr,"qualify.sel: %s -> ", dumpselection(sel)); #endif /* Now add path nodes to create full path */ completesegments3(fullpath,sel->lhs->var->segments); for(i=0;i<nclistlength(sel->rhs);i++) { DCEvalue* value = (DCEvalue*)nclistget(sel->rhs,i); if(value->discrim != CES_VAR) continue; nclistclear(fullpath); collectnodepath3((CDFnode*)value->var->annotation,fullpath,!WITHDATASET); completesegments3(fullpath,value->var->segments); } nclistfree(segments); nclistfree(fullpath); return THROW(ncstat); }
/* Based on the tactic, determine the set of variables to add */ static void computevarset4(NCDRNO* drno, Getvara* getvar, NClist* varlist) { int i; nclistclear(varlist); for(i=0;i<nclistlength(drno->cdf.varnodes);i++) { CDFnode* var = (CDFnode*)nclistget(drno->cdf.varnodes,i); #ifdef IGNORE int ok = 1; for(j=0;j<nclistlength(var->array.ncdimensions);j++) { CDFnode* dim = (CDFnode*)nclistget(var->array.ncdimensions,j); if(dim->dim.declsize == NC_UNLIMITED) {ok = 0; break;} } if(!ok) continue; #endif switch (getvar->tactic->tactic) { case tactic_all: /* add all visible variables */ nclistpush(varlist,(ncelem)var); break; case tactic_partial: /* add only small variables + target */ if(var->estimatedsize < drno->cdf.smallsizelimit || getvar->target == var) { nclistpush(varlist,(ncelem)var); } break; case tactic_var: /* add only target var */ if(getvar->target == var) nclistpush(varlist,(ncelem)var); break; default: break; } } }
static NCerror fillsegmentpath(DCEprojection* p, NClist* nodes) { int i; NCerror ncstat = NC_NOERR; NClist* path = nclistnew(); ASSERT(p->discrim == CES_VAR); collectsegmentnames3(p->var->segments,path); ncstat = matchpartialname3(nodes,path,&p->var->cdfleaf); if(ncstat) goto done; /* Now complete the segment path */ nclistclear(path); collectnodepath3(p->var->cdfleaf,path,!WITHDATASET); if(nclistlength(path) != nclistlength(p->var->segments)) { ncstat = NC_EINVAL; goto done; } for(i=0;i<nclistlength(p->var->segments);i++) { DCEsegment* seg = (DCEsegment*)nclistget(p->var->segments,i); CDFnode* node = (CDFnode*)nclistget(path,i); seg->cdfnode = node; #ifdef DEBUG fprintf(stderr,"reref: %s -> %s\n",seg->name,node->name); #endif } done: nclistfree(path); return ncstat; }
/* Suppress variables not in usable sequences*/ NCerror suppressunusablevars3(NCDAPCOMMON* dapcomm) { int i,j; int found = 1; NClist* path = nclistnew(); while(found) { found = 0; /* Walk backwards to aid removal semantics */ for(i=nclistlength(dapcomm->cdf.ddsroot->tree->varnodes)-1;i>=0;i--) { CDFnode* var = (CDFnode*)nclistget(dapcomm->cdf.ddsroot->tree->varnodes,i); /* See if this var is under an unusable sequence */ nclistclear(path); collectnodepath3(var,path,WITHOUTDATASET); for(j=0;j<nclistlength(path);j++) { CDFnode* node = (CDFnode*)nclistget(path,j); if(node->nctype == NC_Sequence && !node->usesequence) { #ifdef DEBUG fprintf(stderr,"suppressing var in unusable sequence: %s.%s\n",node->ncfullname,var->ncbasename); #endif found = 1; break; } } if(found) break; } if(found) nclistremove(dapcomm->cdf.ddsroot->tree->varnodes,i); } nclistfree(path); return NC_NOERR; }
/* Parse incoming url constraints, if any, to check for syntactic correctness */ NCerror parsedapconstraints(NCDAPCOMMON* dapcomm, char* constraints, DCEconstraint* dceconstraint) { NCerror ncstat = NC_NOERR; char* errmsg; ASSERT(dceconstraint != NULL); nclistclear(dceconstraint->projections); nclistclear(dceconstraint->selections); ncstat = dapceparse(constraints,dceconstraint,&errmsg); if(ncstat) { nclog(NCLOGWARN,"DCE constraint parse failure: %s",errmsg); nullfree(errmsg); nclistclear(dceconstraint->projections); nclistclear(dceconstraint->selections); } return ncstat; }
/* Given two projection lists, merge src into dst taking overlapping projections into acct. Assume that name qualification has occured. Dst will be modified. */ NCerror mergeprojections3(NClist* dst, NClist* src) { int i; NClist* cat = nclistnew(); NCerror ncstat = NC_NOERR; #ifdef DEBUG fprintf(stderr,"mergeprojection: dst = %s\n",dumpprojections(dst)); fprintf(stderr,"mergeprojection: src = %s\n",dumpprojections(src)); #endif ASSERT(dst != NULL); /* 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); } if(src != NULL) 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(target->var->cdfleaf != p2->var->cdfleaf) continue; /* This entry matches our current target; merge */ ncstat = mergeprojection31(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; }
int dcemergeprojectionlists(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,(void*)p); } for(i=0;i<nclistlength(src);i++) { DCEprojection* p = (DCEprojection*)nclistget(src,i); nclistpush(cat,(void*)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 = dcemergeprojections(target,p2); /* null out this merged entry and release it */ nclistset(cat,i,(void*)NULL); dcefree((DCEnode*)p2); } /* Capture the clone */ nclistpush(dst,(void*)target); } nclistfree(cat); return ncstat; }
/* 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; }
NCerror fixprojections(NClist* list) { int i,j,k; NCerror ncstat = NC_NOERR; NClist* tmp = nclistnew(); /* misc. uses */ #ifdef DEBUG fprintf(stderr,"fixprojection: list = %s\n",dumpprojections(list)); #endif if(nclistlength(list) == 0) goto done; /* Step 1: remove duplicates and complain about slice mismatches */ for(i=0;i<nclistlength(list);i++) { DCEprojection* p1 = (DCEprojection*)nclistget(list,i); if(p1 == NULL) continue; if(p1->discrim != CES_VAR) continue; /* dont try to unify functions */ for(j=i;j<nclistlength(list);j++) { DCEprojection* p2 = (DCEprojection*)nclistget(list,j); if(p2 == NULL) continue; if(p1 == p2) continue; if(p2->discrim != CES_VAR) continue; if(p1->var->annotation != p2->var->annotation) continue; /* check for slice mismatches */ if(!slicematch(p1->var->segments,p2->var->segments)) { /* complain */ nclog(NCLOGWARN,"Malformed projection: same variable with different slicing"); } /* remove p32 */ nclistset(list,j,(ncelem)NULL); dcefree((DCEnode*)p2); } } /* Step 2: remove containers when a field is also present */ for(i=0;i<nclistlength(list);i++) { DCEprojection* p1 = (DCEprojection*)nclistget(list,i); if(p1 == NULL) continue; if(p1->discrim != CES_VAR) continue; /* dont try to unify functions */ if(!iscontainer((CDFnode*)p1->var->annotation)) continue; for(j=i;j<nclistlength(list);j++) { DCEprojection* p2 = (DCEprojection*)nclistget(list,j); if(p2 == NULL) continue; if(p2->discrim != CES_VAR) continue; nclistclear(tmp); collectnodepath3((CDFnode*)p2->var->annotation,tmp,WITHDATASET); for(k=0;k<nclistlength(tmp);k++) { void* candidate = (void*)nclistget(tmp,k); if(candidate == p1->var->annotation) { nclistset(list,i,(ncelem)NULL); dcefree((DCEnode*)p1); goto next; } } } next: continue; } /* Step 3: expand all containers recursively down to the leaf nodes */ for(;;) { nclistclear(tmp); for(i=0;i<nclistlength(list);i++) { DCEprojection* target = (DCEprojection*)nclistget(list,i); CDFnode* leaf; if(target == NULL) continue; if(target->discrim != CES_VAR) continue; /* dont try to unify functions */ leaf = (CDFnode*)target->var->annotation; ASSERT(leaf != NULL); if(iscontainer(leaf)) {/* capture container */ if(!nclistcontains(tmp,(ncelem)target)) nclistpush(tmp,(ncelem)target); nclistset(list,i,(ncelem)NULL); } } if(nclistlength(tmp) == 0) break; /*done*/ /* Now explode the containers */ for(i=0;i<nclistlength(tmp);i++) { DCEprojection* container = (DCEprojection*)nclistget(tmp,i); CDFnode* leaf = (CDFnode*)container->var->annotation; for(j=0;i<nclistlength(leaf->subnodes);j++) { CDFnode* field = (CDFnode*)nclistget(leaf->subnodes,j); /* Convert field node to a proper constraint */ DCEprojection* proj = projectify(field,container); nclistpush(list,(ncelem)proj); } /* reclaim the container */ dcefree((DCEnode*)container); } } /*for(;;)*/ /* remove all NULL elements */ for(i=nclistlength(list)-1;i>=0;i--) { DCEprojection* target = (DCEprojection*)nclistget(list,i); if(target == NULL) nclistremove(list,i); } done: #ifdef DEBUG fprintf(stderr,"fixprojection: exploded = %s\n",dumpprojections(list)); #endif nclistfree(tmp); return ncstat; }
static NCerror matchpartialname3(NClist* nodes, NClist* segments, CDFnode** nodep) { int i,nsegs; NCerror ncstat = NC_NOERR; DCEsegment* lastseg = NULL; NClist* namematches = nclistnew(); NClist* matches = nclistnew(); NClist* matchpath = nclistnew(); /* Locate all nodes with the same name as the last element in the segment path */ nsegs = nclistlength(segments); lastseg = (DCEsegment*)nclistget(segments,nsegs-1); for(i=0;i<nclistlength(nodes);i++) { CDFnode* node = (CDFnode*)nclistget(nodes,i); if(node->ocname == null) continue; /* Path names come from oc space */ if(strcmp(node->ocname,lastseg->name) != 0) continue; /* Only look at selected kinds of nodes */ if(node->nctype != NC_Sequence && node->nctype != NC_Structure && node->nctype != NC_Grid && node->nctype != NC_Primitive ) continue; nclistpush(namematches,(ncelem)node); } if(nclistlength(namematches)==0) { nclog(NCLOGERR,"No match for projection name: %s",lastseg->name); ncstat = NC_EDDS; goto done; } /* Now, collect and compare paths of the matching nodes */ for(i=0;i<nclistlength(namematches);i++) { CDFnode* matchnode = (CDFnode*)nclistget(namematches,i); nclistclear(matchpath); collectnodepath3(matchnode,matchpath,0); /* Do a suffix match */ if(matchsuffix3(matchpath,segments)) { nclistpush(matches,(ncelem)matchnode); #ifdef DEBUG fprintf(stderr,"matchpartialname: pathmatch: %s :: %s\n", matchnode->ncfullname,dumpsegments(segments)); #endif } } /* |matches|==0 => no match; |matches|>1 => ambiguity */ switch (nclistlength(matches)) { case 0: nclog(NCLOGERR,"No match for projection name: %s",lastseg->name); ncstat = NC_EDDS; break; case 1: if(nodep) *nodep = (CDFnode*)nclistget(matches,0); break; default: { CDFnode* minnode = NULL; int minpath = 0; int nmin = 0; /* to catch multiple ones with same short path */ /* ok, see if one of the matches has a path that is shorter then all the others */ for(i=0;i<nclistlength(matches);i++) { CDFnode* candidate = (CDFnode*)nclistget(matches,i); nclistclear(matchpath); collectnodepath3(candidate,matchpath,0); if(minpath == 0) { minpath = nclistlength(matchpath); minnode = candidate; } else if(nclistlength(matchpath) == minpath) { nmin++; } else if(nclistlength(matchpath) < minpath) { minpath = nclistlength(matchpath); minnode = candidate; nmin = 1; } } /*for*/ if(minnode == NULL || nmin > 1) { nclog(NCLOGERR,"Ambiguous match for projection name: %s", lastseg->name); ncstat = NC_EDDS; } else if(nodep) *nodep = minnode; } break; } #ifdef DEBUG fprintf(stderr,"matchpartialname: choice: %s %s for %s\n", (nclistlength(matches) > 1?"":"forced"), (*nodep)->ncfullname,dumpsegments(segments)); #endif done: return THROW(ncstat); }
/* See if we can unify sets of nodes to be projected into larger units. */ static NClist* unifyprojectionnodes3(NClist* varlist) { int i; NClist* nodeset = nclistnew(); NClist* containerset = nclistnew(); NClist* containernodes = nclistnew(); nclistsetalloc(nodeset,nclistlength(varlist)); nclistsetalloc(containerset,nclistlength(varlist)); /* Duplicate the varlist so we can modify it; simultaneously collect unique container set. */ for(i=0;i<nclistlength(varlist);i++) { CDFnode* var = (CDFnode*)nclistget(varlist,i); CDFnode* container = var->container; nclistpush(nodeset,(ncelem)var); switch (container->nctype) { case NC_Sequence: case NC_Structure: case NC_Grid: case NC_Dataset: /* add (uniquely) to container set */ if(!nclistcontains(containerset,(ncelem)container)) nclistpush(containerset,(ncelem)container); break; default: break; } } /* Now, try to find containers whose subnodes are all in the varlist; repeat until no more changes */ for(;;) { int changed = 0; for(i=0;i<nclistlength(containerset);i++) { int j, allfound; CDFnode* container = (CDFnode*)nclistget(containerset,i); if(container == NULL) continue; nclistclear(containernodes); for(allfound=1,j=0;j<nclistlength(container->subnodes);j++) { CDFnode* subnode = (CDFnode*)nclistget(container->subnodes,j); if(!nclistcontains(varlist,(ncelem)subnode)) {allfound=0;break;} nclistpush(containernodes,(ncelem)subnode); } if(allfound) { nclistpush(nodeset,(ncelem)container); nclistset(containerset,i,(ncelem)NULL); /* remove */ for(j=nclistlength(nodeset)-1;j>=0;j--) { /* walk backwards */ CDFnode* testnode = (CDFnode*)nclistget(nodeset,j); if(nclistcontains(containernodes,(ncelem)testnode)) nclistremove(nodeset,j);/* remove */ } changed = 1; } } if(!changed) break; /* apparently we have reached a stable situation */ } /* If there is only the dataset left as a projection, then remove it */ if(nclistlength(nodeset) == 1) { CDFnode* thenode = (CDFnode*)nclistget(nodeset,0); if(thenode->nctype == NC_Dataset) nclistclear(nodeset); } nclistfree(containerset); nclistfree(containernodes); return nodeset; }
void restrictprojection34(NClist* varlist, NClist* projections) { int i,j,len; #ifdef DEBUG fprintf(stderr,"restriction.before=|%s|\n", dumpprojections(projections)); #endif if(nclistlength(varlist) == 0) goto done; /* nothing to add or remove */ /* If the projection list is empty, then add a projection for every variable in varlist */ if(nclistlength(projections) == 0) { NClist* path = nclistnew(); NClist* nodeset = NULL; /* Attempt to unify the vars into larger units (like a complete grid) */ nodeset = unifyprojectionnodes3(varlist); for(i=0;i<nclistlength(nodeset);i++) { CDFnode* var = (CDFnode*)nclistget(nodeset,i); #ifdef DEBUG fprintf(stderr,"restriction.candidate=|%s|\n",var->ncfullname); #endif DCEprojection* newp = (DCEprojection*)dcecreate(CES_PROJECT); newp->discrim = CES_VAR; newp->var = (DCEvar*)dcecreate(CES_VAR); newp->var->cdfleaf = var; nclistclear(path); collectnodepath3(var,path,!WITHDATASET); newp->var->segments = nclistnew(); for(j=0;j<nclistlength(path);j++) { CDFnode* node = (CDFnode*)nclistget(path,j); DCEsegment* newseg = (DCEsegment*)dcecreate(CES_SEGMENT); newseg->name = nulldup(node->name); makewholesegment3(newseg,node);/*treat as simple projections*/ newseg->cdfnode = node; nclistpush(newp->var->segments,(ncelem)newseg); } nclistpush(projections,(ncelem)newp); } nclistfree(path); nclistfree(nodeset); } else { /* Otherwise, walk all the projections and see if they intersect any of the variables. If not, then remove from the projection list. */ len = nclistlength(projections); for(i=len-1;i>=0;i--) {/* Walk backward to facilitate removal*/ int intersect = 0; DCEprojection* proj = (DCEprojection*)nclistget(projections,i); if(proj->discrim != CES_VAR) continue; for(j=0;j<nclistlength(varlist);j++) { CDFnode* var = (CDFnode*)nclistget(varlist,j); /* Note that intersection could go either way */ if(treecontains3(var,proj->var->cdfleaf) || treecontains3(proj->var->cdfleaf,var)) {intersect = 1; break;} } if(!intersect) { /* suppress this projection */ DCEprojection* p = (DCEprojection*)nclistremove(projections,i); dcefree((DCEnode*)p); } } /* Now looks for containment between projections and only keep the more restrictive. Is this algorithm stable against reordering?. */ for(;;) { int removed = 0; for(i=0;i<nclistlength(projections);i++) { DCEprojection* pi = (DCEprojection*)nclistget(projections,i); if(pi->discrim != CES_VAR) continue; for(j=0;j<i;j++) { DCEprojection* pj = (DCEprojection*)nclistget(projections,j); if(pj->discrim != CES_VAR) continue; if(treecontains3(pi->var->cdfleaf,pj->var->cdfleaf)) { DCEprojection* p = (DCEprojection*)nclistremove(projections,j); dcefree((DCEnode*)p); removed = 1; break; } else if(treecontains3(pj->var->cdfleaf,pi->var->cdfleaf)) { DCEprojection* p = (DCEprojection*)nclistremove(projections,i); dcefree((DCEnode*)p); removed = 1; break; } } } if(!removed) break; } } done: #ifdef DEBUG fprintf(stderr,"restriction.after=|%s|\n", dumpprojections(projections)); #endif return; }
static NCerror matchpartialname3(NClist* nodes, NClist* segments, CDFnode** nodep) { int i,j,nsegs; NCerror ncstat = NC_NOERR; DCEsegment* lastseg = NULL; NClist* namematches = nclistnew(); NClist* matches = nclistnew(); NClist* matchpath = nclistnew(); /* Locate all nodes with the same name as the last element in the path */ nsegs = nclistlength(segments); lastseg = (DCEsegment*)nclistget(segments,nsegs-1); for(i=0;i<nclistlength(nodes);i++) { CDFnode* node = (CDFnode*)nclistget(nodes,i); if(node->nctype != NC_Sequence && node->nctype != NC_Structure && node->nctype != NC_Grid && node->nctype != NC_Primitive ) continue; if(strcmp(node->name,lastseg->name) != 0) continue; nclistpush(namematches,(ncelem)node); } if(nclistlength(namematches)==0) { nclog(NCLOGERR,"No match for projection name: %s",lastseg->name); ncstat = NC_EDDS; goto done; } /* Now, collect and compare paths of the matching nodes */ for(i=0;i<nclistlength(namematches);i++) { CDFnode* matchnode = (CDFnode*)nclistget(namematches,i); nclistclear(matchpath); collectnodepath3(matchnode,matchpath,0); /* Do a suffix match */ /* starting at each node in matchpath in the path in turn, try to suffix match */ for(j=0;j<nclistlength(matchpath);j++) { if(nclistlength(matchpath)- j < nsegs) continue; /* cannot match */ if(matchsuffix3(matchpath,segments,j)) { nclistpush(matches,(ncelem)matchnode); break; } } } /* |matches|==0 => no match; |matches|>1 => ambiguity */ switch (nclistlength(matches)) { case 0: nclog(NCLOGERR,"No match for projection name: %s",lastseg->name); ncstat = NC_EDDS; break; case 1: if(nodep) *nodep = (CDFnode*)nclistget(matches,0); break; default: { CDFnode* minnode = NULL; int minpath = 0; int nmin = 0; /* to catch multiple ones with same short path */ /* ok, see if one of the matches has a path that is shorter then all the others */ for(i=0;i<nclistlength(matches);i++) { CDFnode* candidate = (CDFnode*)nclistget(matches,i); nclistclear(matchpath); collectnodepath3(candidate,matchpath,0); if(minpath == 0) { minpath = nclistlength(matchpath); minnode = candidate; } else if(nclistlength(matchpath) == minpath) { nmin++; } else if(nclistlength(matchpath) < minpath) { minpath = nclistlength(matchpath); minnode = candidate; nmin = 1; } } /*for*/ if(minnode == NULL || nmin > 1) { nclog(NCLOGERR,"Ambiguous match for projection name: %s", lastseg->name); ncstat = NC_EDDS; } else if(nodep) *nodep = minnode; } break; } done: return THROW(ncstat); }