1 /*********************************************************************
2  *   Copyright 1993, UCAR/Unidata
3  *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
4  *********************************************************************/
5 
6 #include "dapincludes.h"
7 #include "daputil.h"
8 #include "dapdump.h"
9 
10 #ifdef DAPDEBUG
11 extern char* ocfqn(OCddsnode);
12 #endif
13 
14 CDFnode* v4node = NULL;
15 
16 /* Forward*/
17 static NCerror sequencecheckr(CDFnode* node, NClist* vars, CDFnode* topseq);
18 static NCerror restructr(NCDAPCOMMON*, CDFnode*, CDFnode*, NClist*);
19 static NCerror repairgrids(NCDAPCOMMON*, NClist*);
20 static NCerror structwrap(NCDAPCOMMON*, CDFnode*, CDFnode*, int, CDFnode*, int);
21 static int findin(CDFnode* parent, CDFnode* child);
22 static CDFnode* makenewstruct(NCDAPCOMMON*, CDFnode*, CDFnode*);
23 static NCerror mapnodesr(CDFnode*, CDFnode*, int depth);
24 static NCerror mapfcn(CDFnode* dstnode, CDFnode* srcnode);
25 static NCerror definedimsetplus(NCDAPCOMMON* nccomm, CDFnode* node);
26 static NCerror definedimsetall(NCDAPCOMMON* nccomm, CDFnode* node);
27 static NCerror definetransdimset(NCDAPCOMMON* nccomm, CDFnode* node);
28 static NCerror definedimsettransR(NCDAPCOMMON* nccomm, CDFnode* node);
29 static NCerror definedimsetsR(NCDAPCOMMON* nccomm, CDFnode* node);
30 static NCerror buildcdftreer(NCDAPCOMMON*, OCddsnode, CDFnode*, CDFtree*, CDFnode**);
31 static void free1cdfnode(CDFnode* node);
32 static NCerror fixnodes(NCDAPCOMMON*, NClist* cdfnodes);
33 static void defdimensions(OCddsnode ocnode, CDFnode* cdfnode, NCDAPCOMMON* nccomm, CDFtree* tree);
34 
35 /* Accumulate useful node sets  */
36 NCerror
computecdfnodesets(NCDAPCOMMON * nccomm,CDFtree * tree)37 computecdfnodesets(NCDAPCOMMON* nccomm, CDFtree* tree)
38 {
39     unsigned int i;
40     NClist* varnodes;
41     NClist* allnodes;
42 
43     allnodes = tree->nodes;
44     varnodes = nclistnew();
45 
46     if(tree->seqnodes == NULL) tree->seqnodes = nclistnew();
47     if(tree->gridnodes == NULL) tree->gridnodes = nclistnew();
48     nclistclear(tree->seqnodes);
49     nclistclear(tree->gridnodes);
50 
51     computevarnodes(nccomm,allnodes,varnodes);
52     nclistfree(tree->varnodes);
53     tree->varnodes = varnodes;
54     varnodes = NULL;
55 
56     /* Now compute other sets of interest */
57     for(i=0;i<nclistlength(allnodes);i++) {
58 	CDFnode* node = (CDFnode*)nclistget(allnodes,i);
59 	switch (node->nctype) {
60 	case NC_Sequence:
61 	    nclistpush(tree->seqnodes,(void*)node);
62 	    break;
63 	case NC_Grid:
64 	    nclistpush(tree->gridnodes,(void*)node);
65 	    break;
66 	default: break;
67 	}
68     }
69     return NC_NOERR;
70 }
71 
72 NCerror
computevarnodes(NCDAPCOMMON * nccomm,NClist * allnodes,NClist * varnodes)73 computevarnodes(NCDAPCOMMON* nccomm, NClist* allnodes, NClist* varnodes)
74 {
75     unsigned int i,len;
76     NClist* allvarnodes = nclistnew();
77     for(i=0;i<nclistlength(allnodes);i++) {
78 	CDFnode* node = (CDFnode*)nclistget(allnodes,i);
79 #if 0
80 	/* If this node has a bad name, repair it */
81 	if(dap_badname(node->ocname)) {
82 	    char* newname = dap_repairname(node->ocname);
83 	    nullfree(node->ocname);
84 	    node->ocname = newname;
85 	}
86 #endif
87 	if(node->nctype == NC_Atomic)
88 	    nclistpush(allvarnodes,(void*)node);
89     }
90     /* Further process the variable nodes to get the final set */
91     /* Use toplevel vars first */
92     len = nclistlength(allvarnodes);
93     for(i=0;i<len;i++) {
94 	CDFnode* node = (CDFnode*)nclistget(allvarnodes,i);
95 	if(node == NULL) continue;
96         if(daptoplevel(node)) {
97 	    nclistpush(varnodes,(void*)node);
98 	    nclistset(allvarnodes,i,(void*)NULL);
99 	}
100     }
101     /*... then grid arrays and maps.
102       but exclude the coordinate variables if we are trying to
103       exactly mimic nc-dap
104     */
105     for(i=0;i<len;i++) {
106 	CDFnode* node = (CDFnode*)nclistget(allvarnodes,i);
107 	if(node == NULL) continue;
108 	if(dapgridarray(node)) {
109 	    nclistpush(varnodes,(void*)node);
110 	    nclistset(allvarnodes,i,(void*)NULL);
111         } else if(dapgridmap(node)) {
112 	    if(!FLAGSET(nccomm->controls,NCF_NCDAP))
113 		nclistpush(varnodes,(void*)node);
114 	    nclistset(allvarnodes,i,(void*)NULL);
115 	}
116     }
117     /*... then all others */
118     for(i=0;i<len;i++) {
119 	CDFnode* node = (CDFnode*)nclistget(allvarnodes,i);
120 	if(node == NULL) continue;
121         nclistpush(varnodes,(void*)node);
122     }
123     nclistfree(allvarnodes);
124 #ifdef DEBUG2
125 for(i=0;i<nclistlength(varnodes);i++) {
126 CDFnode* node = (CDFnode*)nclistget(varnodes,i);
127 if(node == NULL) continue;
128 fprintf(stderr,"computevarnodes: var: %s\n",makecdfpathstring(node,"."));
129 }
130 #endif
131     return NC_NOERR;
132 }
133 
134 
135 
136 NCerror
fixgrid(NCDAPCOMMON * nccomm,CDFnode * grid)137 fixgrid(NCDAPCOMMON* nccomm, CDFnode* grid)
138 {
139     unsigned int i,glen;
140     CDFnode* array;
141 
142     glen = nclistlength(grid->subnodes);
143     array = (CDFnode*)nclistget(grid->subnodes,0);
144     if(nccomm->controls.flags & (NCF_NC3)) {
145         /* Rename grid Array: variable, but leave its oc base name alone */
146         nullfree(array->ncbasename);
147         array->ncbasename = nulldup(grid->ncbasename);
148         if(!array->ncbasename) return NC_ENOMEM;
149     }
150     /* validate and modify the grid structure */
151     if((glen-1) != nclistlength(array->array.dimset0)) goto invalid;
152     for(i=1;i<glen;i++) {
153 	CDFnode* arraydim = (CDFnode*)nclistget(array->array.dimset0,i-1);
154 	CDFnode* map = (CDFnode*)nclistget(grid->subnodes,i);
155 	CDFnode* mapdim;
156 	/* map must have 1 dimension */
157 	if(nclistlength(map->array.dimset0) != 1) goto invalid;
158 	/* and the map name must match the ith array dimension */
159 	if(arraydim->ocname != NULL && map->ocname != NULL
160 	   && strcmp(arraydim->ocname,map->ocname) != 0)
161 	    goto invalid;
162 	/* and the map name must match its dim name (if any) */
163 	mapdim = (CDFnode*)nclistget(map->array.dimset0,0);
164 	if(mapdim->ocname != NULL && map->ocname != NULL
165 	   && strcmp(mapdim->ocname,map->ocname) != 0)
166 	    goto invalid;
167 	/* Add appropriate names for the anonymous dimensions */
168 	/* Do the map name first, so the array dim may inherit */
169 	if(mapdim->ocname == NULL) {
170 	    nullfree(mapdim->ncbasename);
171 	    mapdim->ocname = nulldup(map->ocname);
172 	    if(!mapdim->ocname) return NC_ENOMEM;
173 	    mapdim->ncbasename = cdflegalname(mapdim->ocname);
174 	    if(!mapdim->ncbasename) return NC_ENOMEM;
175 	}
176 	if(arraydim->ocname == NULL) {
177 	    nullfree(arraydim->ncbasename);
178 	    arraydim->ocname = nulldup(map->ocname);
179 	    if(!arraydim->ocname) return NC_ENOMEM;
180 	    arraydim->ncbasename = cdflegalname(arraydim->ocname);
181 	    if(!arraydim->ncbasename) return NC_ENOMEM;
182 	}
183         if(FLAGSET(nccomm->controls,(NCF_NCDAP|NCF_NC3))) {
184 	    char tmp[3*NC_MAX_NAME];
185             /* Add the grid name to the basename of the map */
186 	    snprintf(tmp,sizeof(tmp),"%s%s%s",map->container->ncbasename,
187 					  nccomm->cdf.separator,
188 					  map->ncbasename);
189 	    nullfree(map->ncbasename);
190             map->ncbasename = nulldup(tmp);
191 	    if(!map->ncbasename) return NC_ENOMEM;
192 	}
193     }
194     return NC_NOERR;
195 invalid:
196     return NC_EINVAL; /* mal-formed grid */
197 }
198 
199 NCerror
fixgrids(NCDAPCOMMON * nccomm)200 fixgrids(NCDAPCOMMON* nccomm)
201 {
202     unsigned int i;
203     NClist* gridnodes = nccomm->cdf.ddsroot->tree->gridnodes;
204 
205     for(i=0;i<nclistlength(gridnodes);i++) {
206         CDFnode* grid = (CDFnode*)nclistget(gridnodes,i);
207         (void)fixgrid(nccomm,grid);
208 	/* Ignore mal-formed grids */
209     }
210     return NC_NOERR;
211 }
212 
213 /*
214 Figure out the names for variables.
215 */
216 NCerror
computecdfvarnames(NCDAPCOMMON * nccomm,CDFnode * root,NClist * varnodes)217 computecdfvarnames(NCDAPCOMMON* nccomm, CDFnode* root, NClist* varnodes)
218 {
219     unsigned int i,j,d;
220 
221     /* clear all elided marks; except for dataset and grids */
222     for(i=0;i<nclistlength(root->tree->nodes);i++) {
223 	CDFnode* node = (CDFnode*)nclistget(root->tree->nodes,i);
224 	node->elided = 0;
225 	if(node->nctype == NC_Grid || node->nctype == NC_Dataset)
226 	    node->elided = 1;
227     }
228 
229     /* ensure all variables have an initial full name defined */
230     for(i=0;i<nclistlength(varnodes);i++) {
231 	CDFnode* var = (CDFnode*)nclistget(varnodes,i);
232 	nullfree(var->ncfullname);
233 	var->ncfullname = makecdfpathstring(var,nccomm->cdf.separator);
234 #ifdef DEBUG2
235 fprintf(stderr,"var names: %s %s %s\n",
236 	var->ocname,var->ncbasename,var->ncfullname);
237 #endif
238     }
239 
240     /*  unify all variables with same fullname and dimensions
241 	basevar fields says: "for duplicate grid variables";
242         when does this happen?
243     */
244     if(FLAGSET(nccomm->controls,NCF_NC3)) {
245         for(i=0;i<nclistlength(varnodes);i++) {
246 	    int match;
247 	    CDFnode* var = (CDFnode*)nclistget(varnodes,i);
248 	    for(j=0;j<i;j++) {
249 	        CDFnode* testnode = (CDFnode*)nclistget(varnodes,j);
250 		match = 1;
251 	        if(testnode->array.basevar != NULL)
252 		    continue; /* already processed */
253 	        if(strcmp(var->ncfullname,testnode->ncfullname) != 0)
254 		    match = 0;
255 		else if(nclistlength(testnode->array.dimsetall)
256 			!= nclistlength(var->array.dimsetall))
257 		    match = 0;
258 	        else for(d=0;d<nclistlength(testnode->array.dimsetall);d++) {
259 		    CDFnode* vdim = (CDFnode*)nclistget(var->array.dimsetall,d);
260 		    CDFnode* tdim = (CDFnode*)nclistget(testnode->array.dimsetall,d);
261 	            if(vdim->dim.declsize != tdim->dim.declsize) {
262 		        match = 0;
263 			break;
264 		    }
265 		}
266 		if(match) {
267 		    testnode->array.basevar = var;
268 fprintf(stderr,"basevar invoked: %s\n",var->ncfullname);
269 		}
270 	    }
271 	}
272     }
273 
274     /* Finally, verify unique names */
275     for(i=0;i<nclistlength(varnodes);i++) {
276 	CDFnode* var1 = (CDFnode*)nclistget(varnodes,i);
277 	if(var1->array.basevar != NULL) continue;
278 	for(j=0;j<i;j++) {
279 	    CDFnode* var2 = (CDFnode*)nclistget(varnodes,j);
280 	    if(var2->array.basevar != NULL) continue;
281 	    if(strcmp(var1->ncfullname,var2->ncfullname)==0) {
282 		PANIC1("duplicate var names: %s",var1->ncfullname);
283 	    }
284 	}
285     }
286     return NC_NOERR;
287 }
288 
289 
290 /* locate and connect usable sequences and vars.
291 A sequence is usable iff:
292 1. it has a path from one of its subnodes to a leaf and that
293    path does not contain a sequence.
294 2. No parent container has dimensions.
295 */
296 
297 NCerror
sequencecheck(NCDAPCOMMON * nccomm)298 sequencecheck(NCDAPCOMMON* nccomm)
299 {
300     (void)sequencecheckr(nccomm->cdf.ddsroot,
301                           nccomm->cdf.ddsroot->tree->varnodes,NULL);
302     return NC_NOERR;
303 }
304 
305 
306 static NCerror
sequencecheckr(CDFnode * node,NClist * vars,CDFnode * topseq)307 sequencecheckr(CDFnode* node, NClist* vars, CDFnode* topseq)
308 {
309     unsigned int i;
310     NCerror err = NC_NOERR;
311     int ok = 0;
312     if(topseq == NULL && nclistlength(node->array.dimset0) > 0) {
313 	err = NC_EINVAL; /* This container has dimensions, so no sequence within it
314                             can be usable */
315     } else if(node->nctype == NC_Sequence) {
316 	/* Recursively walk the path for each subnode of this sequence node
317            looking for a path without any sequence */
318 	for(i=0;i<nclistlength(node->subnodes);i++) {
319 	    CDFnode* sub = (CDFnode*)nclistget(node->subnodes,i);
320 	    err = sequencecheckr(sub,vars,node);
321 	    if(err == NC_NOERR) ok = 1; /* there is at least 1 usable var below */
322 	}
323 	if(topseq == NULL && ok == 1) {
324 	    /* this sequence is usable because it has scalar container
325                (by construction) and has a path to a leaf without an intermediate
326                sequence. */
327 	    err = NC_NOERR;
328 	    node->usesequence = 1;
329 	} else {
330 	    /* this sequence is unusable because it has no path
331                to a leaf without an intermediate sequence. */
332 	    node->usesequence = 0;
333 	    err = NC_EINVAL;
334 	}
335     } else if(nclistcontains(vars,(void*)node)) {
336 	/* If we reach a leaf, then topseq is usable, so save it */
337 	node->array.sequence = topseq;
338     } else { /* Some kind of non-sequence container node with no dimensions */
339 	/* recursively compute usability */
340 	for(i=0;i<nclistlength(node->subnodes);i++) {
341 	    CDFnode* sub = (CDFnode*)nclistget(node->subnodes,i);
342 	    err = sequencecheckr(sub,vars,topseq);
343 	    if(err == NC_NOERR) ok = 1;
344 	}
345 	err = (ok?NC_NOERR:NC_EINVAL);
346     }
347     return err;
348 }
349 
350 /*
351 Originally, if one did a constraint on a Grid such that only
352 one array or map in the grid was returned, that element was
353 returned as a top level variable.  This is incorrect because
354 it loses the Grid scope information.
355 
356 Eventually, this behavior was changed so that such partial
357 grids are converted to structures where the structure name
358 is the grid name. This preserves the proper scoping.
359 However, it is still the case that some servers do the old
360 behavior.
361 
362 The rules that most old-style servers appear to adhere to are these.
363 1. Asking for just a grid array or a single grid map
364    returns just the array not wrapped in a structure.
365 2. Asking for a subset of the fields (array plus map) of a grid
366    returns those fields wrapped in a structure.
367 3. However, there is an odd situation: asking for a grid array
368    plus any subset of maps that includes the last map in the grid
369    returns a malformed grid. This is clearly a bug.
370 
371 For case 1, we insert a structure node so that case 1 is consistent
372 with case 2. Case 3 should cause an error with a malformed grid.
373 
374 [Note: for some reason, this code has been difficult to get right;
375 I have rewritten 6 times and it probably is still not right.]
376 [2/25/2013 Sigh! Previous fixes have introducted another bug,
377 so now we fix the fix.]
378 
379 Input is
380 (1) the root of the dds that needs to be re-gridded
381 (2) the full datadds tree that defines where the grids are.
382 (3) the projections that were used to produce (1) from (2).
383 
384 */
385 
386 NCerror
restruct(NCDAPCOMMON * ncc,CDFnode * ddsroot,CDFnode * patternroot,NClist * projections)387 restruct(NCDAPCOMMON* ncc, CDFnode* ddsroot, CDFnode* patternroot, NClist* projections)
388 {
389     NCerror ncstat = NC_NOERR;
390     NClist* repairs = nclistnew();
391 
392     /* The current restruct assumes that the ddsroot tree
393        has missing grids compared to the pattern.
394        It is also assumed that order of the nodes
395        in the ddsroot is the same as in the pattern.
396     */
397     if(ddsroot->tree->restructed) {
398       nclistfree(repairs);
399       return NC_NOERR;
400     }
401 
402 #ifdef DEBUG
403 fprintf(stderr,"restruct: ddsroot=%s\n",dumptree(ddsroot));
404 fprintf(stderr,"restruct: patternroot=%s\n",dumptree(patternroot));
405 #endif
406 
407     /* Match roots */
408     if(!simplenodematch(ddsroot,patternroot))
409 	ncstat = NC_EDATADDS;
410     else if(!restructr(ncc,ddsroot,patternroot,repairs))
411 	ncstat = NC_EDATADDS;
412     else if(nclistlength(repairs) > 0) {
413 	/* Do the repairs */
414 	ncstat = repairgrids(ncc, repairs);
415     }
416 
417     if(repairs)
418       nclistfree(repairs);
419 
420     return THROW(ncstat);
421 }
422 
423 /*
424 Locate nodes in the tree rooted at node
425 that correspond to a single grid field in the pattern
426 when the pattern is a grid.
427 Wrap that grid field in a synthesized structure.
428 
429 The key thing to look for is the case where
430 we have an atomic variable that appear where
431 we expected a grid.
432 
433 */
434 
435 static int
restructr(NCDAPCOMMON * ncc,CDFnode * dxdparent,CDFnode * patternparent,NClist * repairlist)436 restructr(NCDAPCOMMON* ncc, CDFnode* dxdparent, CDFnode* patternparent, NClist* repairlist)
437 {
438     int index, i, j, match;
439 
440 #ifdef DEBUG
441 fprintf(stderr,"restruct: matched: %s -> %s\n",
442 ocfqn(dxdparent->ocnode),ocfqn(patternparent->ocnode));
443 #endif
444 
445     /* walk each node child and locate its match
446        in the pattern's children; recurse on matches,
447        non-matches may be nodes needing wrapping.
448     */
449 
450     for(index=0;index<nclistlength(dxdparent->subnodes);index++) {
451         CDFnode* dxdsubnode = (CDFnode*)nclistget(dxdparent->subnodes,index);
452 	CDFnode* matchnode = NULL;
453 
454 	/* Look for a matching pattern node with same ocname */
455         for(i=0;i<nclistlength(patternparent->subnodes);i++) {
456             CDFnode* patternsubnode = (CDFnode*)nclistget(patternparent->subnodes,i);
457 	    if(strcmp(dxdsubnode->ocname,patternsubnode->ocname) == 0) {
458 		matchnode = patternsubnode;
459 		break;
460 	    }
461 	}
462 #ifdef DEBUG
463 fprintf(stderr,"restruct: candidate: %s -> %s\n",
464 ocfqn(dxdsubnode->ocnode),ocfqn(matchnode->ocnode));
465 #endif
466 	if(simplenodematch(dxdsubnode,matchnode)) {
467 	    /* this subnode of the node matches the corresponding
468                node of the pattern, so it is ok =>
469                recurse looking for nested mis-matches
470             */
471 	    if(!restructr(ncc,dxdsubnode,matchnode,repairlist))
472 		return 0;
473 	} else {
474             /* If we do not have a direct match, then we need to look
475                at all the grids to see if this node matches a field
476                in one of the grids
477             */
478             for(match=0,i=0;!match && i<nclistlength(patternparent->subnodes);i++) {
479                 CDFnode* subtemp = (CDFnode*)nclistget(patternparent->subnodes,i);
480                 if(subtemp->nctype == NC_Grid) {
481 		    /* look inside */
482                     for(j=0;j<nclistlength(patternparent->subnodes);j++) {
483                         CDFnode* gridfield = (CDFnode*)nclistget(subtemp->subnodes,j);
484                         if(simplenodematch(dxdsubnode,gridfield)) {
485                             /* We need to do this repair */
486                             nclistpush(repairlist,(void*)dxdsubnode);
487                             nclistpush(repairlist,(void*)gridfield);
488                             match = 1;
489                             break;
490                         }
491                     }
492                 }
493             }
494 	    if(!match) return 0; /* we failed */
495 	}
496     }
497     return 1; /* we matched everything at this level */
498 }
499 
500 /* Wrap the node wrt the pattern grid or pattern struct */
501 
502 static NCerror
repairgrids(NCDAPCOMMON * ncc,NClist * repairlist)503 repairgrids(NCDAPCOMMON* ncc, NClist* repairlist)
504 {
505     NCerror ncstat = NC_NOERR;
506     int i;
507     assert(nclistlength(repairlist) % 2 == 0);
508     for(i=0;i<nclistlength(repairlist);i+=2) {
509 	CDFnode* node = (CDFnode*)nclistget(repairlist,i);
510 	CDFnode* pattern = (CDFnode*)nclistget(repairlist,i+1);
511 	int index = findin(node->container,node);
512 	int tindex = findin(pattern->container,pattern);
513 	ncstat = structwrap(ncc, node,node->container,index,
514                              pattern->container,tindex);
515 #ifdef DEBUG
516 fprintf(stderr,"repairgrids: %s -> %s\n",
517 ocfqn(node->ocnode),ocfqn(pattern->ocnode));
518 #endif
519 
520     }
521     return ncstat;
522 }
523 
524 static NCerror
structwrap(NCDAPCOMMON * ncc,CDFnode * node,CDFnode * parent,int parentindex,CDFnode * patterngrid,int gridindex)525 structwrap(NCDAPCOMMON* ncc, CDFnode* node, CDFnode* parent, int parentindex,
526                            CDFnode* patterngrid, int gridindex)
527 {
528     CDFnode* newstruct;
529 
530     ASSERT((patterngrid->nctype == NC_Grid));
531     newstruct = makenewstruct(ncc, node,patterngrid);
532     if(newstruct == NULL) {return THROW(NC_ENOMEM);}
533 
534     /* replace the node with the new structure
535        in the parent's list of children*/
536     nclistset(parent->subnodes,parentindex,(void*)newstruct);
537 
538     /* Update the list of all nodes in the tree */
539     nclistpush(node->root->tree->nodes,(void*)newstruct);
540     return NC_NOERR;
541 }
542 
543 static int
findin(CDFnode * parent,CDFnode * child)544 findin(CDFnode* parent, CDFnode* child)
545 {
546     int i;
547     NClist* subnodes = parent->subnodes;
548     for(i=0;i<nclistlength(subnodes);i++) {
549 	if(nclistget(subnodes,i) == child)
550 	    return i;
551     }
552     return -1;
553 }
554 
555 /* Create a structure to surround projected grid array or map;
556    this occurs because some servers (that means you ferret and you thredds!)
557    do not adhere to the DAP2 protocol spec.
558 */
559 
560 static CDFnode*
makenewstruct(NCDAPCOMMON * ncc,CDFnode * node,CDFnode * patternnode)561 makenewstruct(NCDAPCOMMON* ncc, CDFnode* node, CDFnode* patternnode)
562 {
563     CDFnode* newstruct = makecdfnode(ncc,patternnode->ocname,OC_Structure,
564                                       patternnode->ocnode, node->container);
565     if(newstruct == NULL) return NULL;
566     newstruct->nc_virtual = 1;
567     newstruct->ncbasename = nulldup(patternnode->ncbasename);
568     newstruct->subnodes = nclistnew();
569     newstruct->pattern = patternnode;
570     node->container = newstruct;
571     nclistpush(newstruct->subnodes,(void*)node);
572     return newstruct;
573 }
574 
575 /**
576 Make the constrained dds nodes (root)
577 point to the corresponding unconstrained
578 dds nodes (fullroot).
579  */
580 
581 NCerror
mapnodes(CDFnode * root,CDFnode * fullroot)582 mapnodes(CDFnode* root, CDFnode* fullroot)
583 {
584     NCerror ncstat = NC_NOERR;
585     ASSERT(root != NULL && fullroot != NULL);
586     if(!simplenodematch(root,fullroot))
587 	{THROWCHK(ncstat=NC_EINVAL); goto done;}
588     /* clear out old associations*/
589     unmap(root);
590     ncstat = mapnodesr(root,fullroot,0);
591 done:
592     return ncstat;
593 }
594 
595 static NCerror
mapnodesr(CDFnode * connode,CDFnode * fullnode,int depth)596 mapnodesr(CDFnode* connode, CDFnode* fullnode, int depth)
597 {
598     unsigned int i,j;
599     NCerror ncstat = NC_NOERR;
600 
601     ASSERT((simplenodematch(connode,fullnode)));
602 
603 #ifdef DEBUG
604   {
605 char* path1 = makecdfpathstring(fullnode,".");
606 char* path2 = makecdfpathstring(connode,".");
607 fprintf(stderr,"mapnode: %s->%s\n",path1,path2);
608 nullfree(path1); nullfree(path2);
609   }
610 #endif
611 
612     /* Map node */
613     mapfcn(connode,fullnode);
614 
615 #if 0
616   {
617     int i;
618     for(i=0;i<nclistlength(fullnode->subnodes);i++) {
619 	CDFnode* n = (CDFnode*)nclistget(fullnode->subnodes,i);
620 	fprintf(stderr,"fullnode.subnode[%d]: (%d) %s\n",i,n->nctype,n->ocname);
621     }
622     for(i=0;i<nclistlength(connode->subnodes);i++) {
623 	CDFnode* n = (CDFnode*)nclistget(connode->subnodes,i);
624 	fprintf(stderr,"connode.subnode[%d]: (%d) %s\n",i,n->nctype,n->ocname);
625     }
626   }
627 #endif
628 
629     /* Try to match connode subnodes against fullnode subnodes */
630     ASSERT(nclistlength(connode->subnodes) <= nclistlength(fullnode->subnodes));
631 
632     for(i=0;i<nclistlength(connode->subnodes);i++) {
633         CDFnode* consubnode = (CDFnode*)nclistget(connode->subnodes,i);
634 	/* Search full subnodes for a matching subnode from con */
635         for(j=0;j<nclistlength(fullnode->subnodes);j++) {
636             CDFnode* fullsubnode = (CDFnode*)nclistget(fullnode->subnodes,j);
637             if(simplenodematch(fullsubnode,consubnode)) {
638                 ncstat = mapnodesr(consubnode,fullsubnode,depth+1);
639    	        if(ncstat) goto done;
640 	    }
641 	}
642     }
643 done:
644     return THROW(ncstat);
645 }
646 
647 
648 /* The specific actions of a map are defined
649    by this function.
650 */
651 static NCerror
mapfcn(CDFnode * dstnode,CDFnode * srcnode)652 mapfcn(CDFnode* dstnode, CDFnode* srcnode)
653 {
654     /* Mark node as having been mapped */
655     dstnode->basenode = srcnode;
656     return NC_NOERR;
657 }
658 
659 void
unmap(CDFnode * root)660 unmap(CDFnode* root)
661 {
662     unsigned int i;
663     CDFtree* tree = root->tree;
664     for(i=0;i<nclistlength(tree->nodes);i++) {
665 	CDFnode* node = (CDFnode*)nclistget(tree->nodes,i);
666 	node->basenode = NULL;
667     }
668 }
669 
670 /*
671 Move dimension data from basenodes to nodes
672 */
673 
674 NCerror
dimimprint(NCDAPCOMMON * nccomm)675 dimimprint(NCDAPCOMMON* nccomm)
676 {
677     NCerror ncstat = NC_NOERR;
678     NClist* allnodes;
679     int i,j;
680     CDFnode* basenode;
681 
682     allnodes = nccomm->cdf.ddsroot->tree->nodes;
683     for(i=0;i<nclistlength(allnodes);i++) {
684 	CDFnode* node = (CDFnode*)nclistget(allnodes,i);
685 	int noderank, baserank;
686         /* Do dimension imprinting */
687 	basenode = node->basenode;
688 	if(basenode == NULL) continue;
689 	noderank = nclistlength(node->array.dimset0);
690 	baserank = nclistlength(basenode->array.dimset0);
691 	if(noderank == 0) continue;
692         ASSERT(noderank == baserank);
693 #ifdef DEBUG
694 fprintf(stderr,"dimimprint %s/%d -> %s/%d\n",
695 	makecdfpathstring(basenode,"."),
696 	noderank,
697 	makecdfpathstring(node,"."),
698 	baserank);
699 #endif
700         for(j=0;j<noderank;j++) {
701 	    CDFnode* dim = (CDFnode*)nclistget(node->array.dimset0,j);
702 	    CDFnode* basedim = (CDFnode*)nclistget(basenode->array.dimset0,j);
703 	    dim->dim.declsize0 = basedim->dim.declsize;
704 #ifdef DEBUG
705 fprintf(stderr,"dimimprint: %d: %lu -> %lu\n",i,basedim->dim.declsize,dim->dim.declsize0);
706 #endif
707         }
708     }
709     return ncstat;
710 }
711 
712 static CDFnode*
clonedim(NCDAPCOMMON * nccomm,CDFnode * dim,CDFnode * var)713 clonedim(NCDAPCOMMON* nccomm, CDFnode* dim, CDFnode* var)
714 {
715     CDFnode* clone;
716     clone = makecdfnode(nccomm,dim->ocname,OC_Dimension,
717 			  NULL,dim->container);
718     /* Record its existence */
719     nclistpush(dim->container->root->tree->nodes,(void*)clone);
720     clone->dim = dim->dim; /* copy most everything */
721     clone->dim.dimflags |= CDFDIMCLONE;
722     clone->dim.array = var;
723     return clone;
724 }
725 
726 static NClist*
clonedimset(NCDAPCOMMON * nccomm,NClist * dimset,CDFnode * var)727 clonedimset(NCDAPCOMMON* nccomm, NClist* dimset, CDFnode* var)
728 {
729     NClist* result = NULL;
730     int i;
731 
732     for(i=0;i<nclistlength(dimset);i++) {
733         CDFnode *dim = NULL;
734         if(result == NULL)
735            result = nclistnew();
736 
737         dim = (CDFnode*)nclistget(dimset,i);
738         nclistpush(result,(void*)clonedim(nccomm,dim,var));
739     }
740     return result;
741 }
742 
743 /* Define the dimsetplus list for a node = dimset0+pseudo dims */
744 static NCerror
definedimsetplus(NCDAPCOMMON * nccomm,CDFnode * node)745 definedimsetplus(NCDAPCOMMON* nccomm/*notused*/, CDFnode* node)
746 {
747     int ncstat = NC_NOERR;
748     NClist* dimset = NULL;
749     CDFnode* clone = NULL;
750 
751     if(node->array.dimset0 != NULL)
752         /* copy the dimset0 into dimset */
753         dimset = nclistclone(node->array.dimset0);
754     /* Insert the sequence or string dims */
755     if(node->array.stringdim != NULL) {
756         if(dimset == NULL) dimset = nclistnew();
757 	clone = node->array.stringdim;
758         nclistpush(dimset,(void*)clone);
759     }
760     if(node->array.seqdim != NULL) {
761         if(dimset == NULL) dimset = nclistnew();
762 	clone = node->array.seqdim;
763         nclistpush(dimset,(void*)clone);
764     }
765     node->array.dimsetplus = dimset;
766     return ncstat;
767 }
768 
769 /* Define the dimsetall list for a node =  */
770 static NCerror
definedimsetall(NCDAPCOMMON * nccomm,CDFnode * node)771 definedimsetall(NCDAPCOMMON* nccomm/*notused*/, CDFnode* node)
772 {
773     int i;
774     int ncstat = NC_NOERR;
775     NClist* dimsetall = NULL;
776 
777     if(node->container != NULL) {
778 	/* We need to clone the parent dimensions because we will be assigning
779            indices vis-a-vis this variable */
780         dimsetall = clonedimset(nccomm,node->container->array.dimsetall,node);
781     }
782     /* append dimsetplus; */
783     for(i=0;i<nclistlength(node->array.dimsetplus);i++) {
784 		CDFnode* clone = NULL;
785         if(dimsetall == NULL) dimsetall = nclistnew();
786 		clone = (CDFnode*)nclistget(node->array.dimsetplus,i);
787 		nclistpush(dimsetall,(void*)clone);
788     }
789     node->array.dimsetall = dimsetall;
790 #ifdef DEBUG1
791 fprintf(stderr,"dimsetall: |%s|=%d\n",node->ocname,(int)nclistlength(dimsetall));
792 #endif
793     return ncstat;
794 }
795 
796 /* Define the dimsettrans list for a single node */
797 static NCerror
definetransdimset(NCDAPCOMMON * nccomm,CDFnode * node)798 definetransdimset(NCDAPCOMMON* nccomm/*notused*/, CDFnode* node)
799 {
800     int i;
801     int ncstat = NC_NOERR;
802     NClist* dimsettrans = NULL;
803 
804 #ifdef DEBUG1
805 fprintf(stderr,"dimsettrans3: node=%s/%d\n",node->ocname,nclistlength(node->array.dimset0));
806 #endif
807     if(node->container != NULL) {
808 	/* We need to clone the parent dimensions because we will be assigning
809            indices vis-a-vis this variable */
810         dimsettrans = clonedimset(nccomm,node->container->array.dimsettrans,node);
811     }
812     /* concat parent dimset0 and dimset;*/
813     if(dimsettrans == NULL)
814 	dimsettrans = nclistnew();
815     for(i=0;i<nclistlength(node->array.dimset0);i++) {
816 	CDFnode* clone = NULL;
817 	clone = (CDFnode*)nclistget(node->array.dimset0,i);
818 	nclistpush(dimsettrans,(void*)clone);
819     }
820     node->array.dimsettrans = dimsettrans;
821     dimsettrans = NULL;
822 #ifdef DEBUG1
823 fprintf(stderr,"dimsettrans: |%s|=%d\n",node->ocname,(int)nclistlength(dimsettrans));
824 #endif
825     return ncstat;
826 }
827 
828 /*
829 Recursively define the transitive closure of dimensions
830 (dimsettrans) based on the original dimension set (dimset0):
831 */
832 
833 NCerror
definedimsettrans(NCDAPCOMMON * nccomm,CDFtree * tree)834 definedimsettrans(NCDAPCOMMON* nccomm, CDFtree* tree)
835 {
836     /* recursively walk the tree */
837     definedimsettransR(nccomm, tree->root);
838     return NC_NOERR;
839 }
840 
841 /*
842 Recursive helper for definedimsettrans3
843 */
844 static NCerror
definedimsettransR(NCDAPCOMMON * nccomm,CDFnode * node)845 definedimsettransR(NCDAPCOMMON* nccomm, CDFnode* node)
846 {
847     int i;
848     int ncstat = NC_NOERR;
849 
850     definetransdimset(nccomm,node);
851     /* recurse */
852     for(i=0;i<nclistlength(node->subnodes);i++) {
853 	CDFnode* subnode = (CDFnode*)nclistget(node->subnodes,i);
854 	if(subnode->nctype == NC_Dimension) continue; /*ignore*/
855 	ASSERT((subnode->array.dimsettrans == NULL));
856 	ASSERT((subnode->array.dimsetplus == NULL));
857 	ASSERT((subnode->array.dimsetall == NULL));
858 	ncstat = definedimsettransR(nccomm,subnode);
859 	if(ncstat != NC_NOERR)
860 	    break;
861     }
862     return ncstat;
863 }
864 
865 
866 /*
867 Recursively define two dimension sets for each structural node
868 based on the original dimension set (dimset0):
869 1. dimsetplus = dimset0+pseudo-dimensions (string,sequence).
870 2. dimsetall = parent-dimsetall + dimsetplus
871 */
872 
873 NCerror
definedimsets(NCDAPCOMMON * nccomm,CDFtree * tree)874 definedimsets(NCDAPCOMMON* nccomm, CDFtree* tree)
875 {
876     /* recursively walk the tree */
877     definedimsetsR(nccomm, tree->root);
878     return NC_NOERR;
879 }
880 
881 /*
882 Recursive helper
883 */
884 static NCerror
definedimsetsR(NCDAPCOMMON * nccomm,CDFnode * node)885 definedimsetsR(NCDAPCOMMON* nccomm, CDFnode* node)
886 {
887     int i;
888     int ncstat = NC_NOERR;
889 
890     definedimsetplus(nccomm,node);
891     definedimsetall(nccomm,node);
892     /* recurse */
893     for(i=0;i<nclistlength(node->subnodes);i++) {
894 	CDFnode* subnode = (CDFnode*)nclistget(node->subnodes,i);
895 	if(subnode->nctype == NC_Dimension) continue; /*ignore*/
896 	ASSERT((subnode->array.dimsettrans == NULL));
897 	ASSERT((subnode->array.dimsetplus == NULL));
898 	ASSERT((subnode->array.dimsetall == NULL));
899 	ncstat = definedimsetsR(nccomm,subnode);
900 	if(ncstat != NC_NOERR)
901 	    break;
902     }
903     return ncstat;
904 }
905 
906 CDFnode*
makecdfnode(NCDAPCOMMON * nccomm,char * ocname,OCtype octype,OCddsnode ocnode,CDFnode * container)907 makecdfnode(NCDAPCOMMON* nccomm, char* ocname, OCtype octype,
908              /*optional*/ OCddsnode ocnode, CDFnode* container)
909 {
910     CDFnode* node;
911     assert(nccomm != NULL);
912     node = (CDFnode*)calloc(1,sizeof(CDFnode));
913     if(node == NULL) return (CDFnode*)NULL;
914 
915     node->ocname = NULL;
916     if(ocname) {
917         size_t len = strlen(ocname);
918         if(len >= NC_MAX_NAME) len = NC_MAX_NAME-1;
919         node->ocname = (char*)malloc(len+1);
920 	if(node->ocname == NULL) { nullfree(node); return NULL;}
921 	memcpy(node->ocname,ocname,len);
922 	node->ocname[len] = '\0';
923     }
924     node->nctype = octypetonc(octype);
925     node->ocnode = ocnode;
926     node->subnodes = nclistnew();
927     node->container = container;
928     if(ocnode != NULL) {
929 	oc_dds_atomictype(nccomm->oc.conn,ocnode,&octype);
930         node->etype = octypetonc(octype);
931     }
932     if(container != NULL)
933 	node->root = container->root;
934     else if(node->nctype == NC_Dataset)
935 	node->root = node;
936     return node;
937 }
938 
939 /* Given an OCnode tree, mimic it as a CDFnode tree;
940    Add DAS attributes if DAS is available. Accumulate set
941    of all nodes in preorder.
942 */
943 NCerror
buildcdftree(NCDAPCOMMON * nccomm,OCddsnode ocroot,OCdxd occlass,CDFnode ** cdfrootp)944 buildcdftree(NCDAPCOMMON* nccomm, OCddsnode ocroot, OCdxd occlass, CDFnode** cdfrootp)
945 {
946     CDFnode* root = NULL;
947     CDFtree* tree = (CDFtree*)calloc(1,sizeof(CDFtree));
948     NCerror err = NC_NOERR;
949     if(!tree)
950       return OC_ENOMEM;
951 
952     tree->ocroot = ocroot;
953     tree->nodes = nclistnew();
954     tree->occlass = occlass;
955     tree->owner = nccomm;
956 
957     err = buildcdftreer(nccomm,ocroot,NULL,tree,&root);
958     if(!err) {
959 	if(occlass != OCDAS)
960 	    fixnodes(nccomm,tree->nodes);
961 	if(cdfrootp) *cdfrootp = root;
962     }
963     return err;
964 }
965 
966 static NCerror
buildcdftreer(NCDAPCOMMON * nccomm,OCddsnode ocnode,CDFnode * container,CDFtree * tree,CDFnode ** cdfnodep)967 buildcdftreer(NCDAPCOMMON* nccomm, OCddsnode ocnode, CDFnode* container,
968                 CDFtree* tree, CDFnode** cdfnodep)
969 {
970     size_t i,ocrank,ocnsubnodes;
971     OCtype octype;
972     OCtype ocatomtype;
973     char* ocname = NULL;
974     NCerror ncerr = NC_NOERR;
975     CDFnode* cdfnode = NULL;
976 
977     oc_dds_class(nccomm->oc.conn,ocnode,&octype);
978     if(octype == OC_Atomic)
979 	oc_dds_atomictype(nccomm->oc.conn,ocnode,&ocatomtype);
980     else
981 	ocatomtype = OC_NAT;
982     oc_dds_name(nccomm->oc.conn,ocnode,&ocname);
983     oc_dds_rank(nccomm->oc.conn,ocnode,&ocrank);
984     oc_dds_nsubnodes(nccomm->oc.conn,ocnode,&ocnsubnodes);
985 
986 #ifdef DEBUG1
987     if(ocatomtype == OC_NAT)
988 	fprintf(stderr,"buildcdftree: connect: %s %s\n",oc_typetostring(octype),ocname);
989     else
990 	fprintf(stderr,"buildcdftree: connect: %s %s\n",oc_typetostring(ocatomtype),ocname);
991 #endif
992 
993     switch (octype) {
994     case OC_Dataset:
995 	cdfnode = makecdfnode(nccomm,ocname,octype,ocnode,container);
996 	nclistpush(tree->nodes,(void*)cdfnode);
997 	tree->root = cdfnode;
998 	cdfnode->tree = tree;
999 	break;
1000 
1001     case OC_Grid:
1002     case OC_Structure:
1003     case OC_Sequence:
1004 	cdfnode = makecdfnode(nccomm,ocname,octype,ocnode,container);
1005 	nclistpush(tree->nodes,(void*)cdfnode);
1006 #if 0
1007 	if(tree->root == NULL) {
1008 	    tree->root = cdfnode;
1009 	    cdfnode->tree = tree;
1010 	}
1011 #endif
1012 	break;
1013 
1014     case OC_Atomic:
1015 	cdfnode = makecdfnode(nccomm,ocname,octype,ocnode,container);
1016 	nclistpush(tree->nodes,(void*)cdfnode);
1017 #if 0
1018 	if(tree->root == NULL) {
1019 	    tree->root = cdfnode;
1020 	    cdfnode->tree = tree;
1021 	}
1022 #endif
1023 	break;
1024 
1025     case OC_Dimension:
1026     default: PANIC1("buildcdftree: unexpect OC node type: %d",(int)octype);
1027 
1028     }
1029     /* Avoid a rare but perhaps possible null-dereference
1030        of cdfnode. Not sure what error to throw, so using
1031        NC_EDAP: generic DAP error. */
1032     if(!cdfnode) {
1033       return NC_EDAP;
1034     }
1035 
1036 #if 0
1037     /* cross link */
1038     assert(tree->root != NULL);
1039     cdfnode->root = tree->root;
1040 #endif
1041 
1042     if(ocrank > 0) defdimensions(ocnode,cdfnode,nccomm,tree);
1043     for(i=0;i<ocnsubnodes;i++) {
1044 	OCddsnode ocsubnode;
1045 	CDFnode* subnode;
1046 	oc_dds_ithfield(nccomm->oc.conn,ocnode,i,&ocsubnode);
1047 	ncerr = buildcdftreer(nccomm,ocsubnode,cdfnode,tree,&subnode);
1048 	if(ncerr) {
1049 	  if(ocname) free(ocname);
1050 	  return ncerr;
1051 	}
1052 	nclistpush(cdfnode->subnodes,(void*)subnode);
1053     }
1054     nullfree(ocname);
1055     if(cdfnodep) *cdfnodep = cdfnode;
1056     return ncerr;
1057 }
1058 
1059 void
freecdfroot(CDFnode * root)1060 freecdfroot(CDFnode* root)
1061 {
1062     int i;
1063     CDFtree* tree;
1064     NCDAPCOMMON* nccomm;
1065     if(root == NULL) return;
1066     tree = root->tree;
1067     ASSERT((tree != NULL));
1068     /* Explicitly FREE the ocroot */
1069     nccomm = tree->owner;
1070     oc_root_free(nccomm->oc.conn,tree->ocroot);
1071     tree->ocroot = NULL;
1072     for(i=0;i<nclistlength(tree->nodes);i++) {
1073 	CDFnode* node = (CDFnode*)nclistget(tree->nodes,i);
1074 	free1cdfnode(node);
1075     }
1076     nclistfree(tree->nodes);
1077     nclistfree(tree->varnodes);
1078     nclistfree(tree->seqnodes);
1079     nclistfree(tree->gridnodes);
1080     nullfree(tree);
1081 }
1082 
1083 /* Free up a single node, but not any
1084    nodes it points to.
1085 */
1086 static void
free1cdfnode(CDFnode * node)1087 free1cdfnode(CDFnode* node)
1088 {
1089     unsigned int j,k;
1090     if(node == NULL) return;
1091     nullfree(node->ocname);
1092     nullfree(node->ncbasename);
1093     nullfree(node->ncfullname);
1094     if(node->attributes != NULL) {
1095 	for(j=0;j<nclistlength(node->attributes);j++) {
1096 	    NCattribute* att = (NCattribute*)nclistget(node->attributes,j);
1097 	    nullfree(att->name);
1098 	    for(k=0;k<nclistlength(att->values);k++)
1099 		nullfree((char*)nclistget(att->values,k));
1100 	    nclistfree(att->values);
1101 	    nullfree(att);
1102 	}
1103     }
1104     nullfree(node->dodsspecial.dimname);
1105     nclistfree(node->subnodes);
1106     nclistfree(node->attributes);
1107     nclistfree(node->array.dimsetplus);
1108     nclistfree(node->array.dimsetall);
1109     nclistfree(node->array.dimset0);
1110     nclistfree(node->array.dimsettrans);
1111 
1112     /* Clean up the ncdap4 fields also */
1113     nullfree(node->typename);
1114     nullfree(node->vlenname);
1115     nullfree(node);
1116 }
1117 
1118 
1119 
1120 /* Return true if node and node1 appear to refer to the same thing;
1121    takes grid->structure changes into account.
1122 */
1123 int
nodematch(CDFnode * node1,CDFnode * node2)1124 nodematch(CDFnode* node1, CDFnode* node2)
1125 {
1126     return simplenodematch(node1,node2);
1127 }
1128 
1129 /*
1130 Try to figure out if two nodes
1131 are the "related" =>
1132     same name && same nc_type and same arity
1133 but: Allow Grid == Structure
1134 */
1135 
1136 int
simplenodematch(CDFnode * node1,CDFnode * node2)1137 simplenodematch(CDFnode* node1, CDFnode* node2)
1138 {
1139     /* Test all the obvious stuff */
1140     if(node1 == NULL || node2 == NULL)
1141 	return 0;
1142 
1143     /* Add hack to address the screwed up Columbia server
1144        which returns different Dataset {...} names
1145        depending on the constraint.
1146     */
1147 
1148     if(FLAGSET(node1->root->tree->owner->controls,NCF_COLUMBIA)
1149        && node1->nctype == NC_Dataset) return 1;
1150 
1151     if(strcmp(node1->ocname,node2->ocname)!=0) /* same names */
1152 	return 0;
1153     if(nclistlength(node1->array.dimset0)
1154 	!= nclistlength(node2->array.dimset0)) /* same arity */
1155 	return 0;
1156 
1157     if(node1->nctype != node2->nctype) {
1158 	/* test for struct-grid match */
1159 	int structgrid = ((node1->nctype == NC_Grid && node2->nctype == NC_Structure)
1160                           || (node1->nctype == NC_Structure && node2->nctype == NC_Grid) ? 1 : 0);
1161 	if(!structgrid)
1162 	    return 0;
1163     }
1164 
1165     if(node1->nctype == NC_Atomic && node1->etype != node2->etype)
1166 	return 0;
1167 
1168     return 1;
1169 }
1170 
1171 /* Ensure every node has an initial base name defined and fullname */
1172 /* Exceptions: anonymous dimensions. */
1173 static NCerror
fix1node(NCDAPCOMMON * nccomm,CDFnode * node)1174 fix1node(NCDAPCOMMON* nccomm, CDFnode* node)
1175 {
1176     if(node->nctype == NC_Dimension && node->ocname == NULL) return NC_NOERR;
1177     ASSERT((node->ocname != NULL));
1178     nullfree(node->ncbasename);
1179     node->ncbasename = cdflegalname(node->ocname);
1180     if(node->ncbasename == NULL) return NC_ENOMEM;
1181     nullfree(node->ncfullname);
1182     node->ncfullname = makecdfpathstring(node,nccomm->cdf.separator);
1183     if(node->ncfullname == NULL) return NC_ENOMEM;
1184     if(node->nctype == NC_Atomic)
1185         node->externaltype = nctypeconvert(nccomm,node->etype);
1186     return NC_NOERR;
1187 }
1188 
1189 static NCerror
fixnodes(NCDAPCOMMON * nccomm,NClist * cdfnodes)1190 fixnodes(NCDAPCOMMON* nccomm, NClist* cdfnodes)
1191 {
1192     int i;
1193     for(i=0;i<nclistlength(cdfnodes);i++) {
1194 	CDFnode* node = (CDFnode*)nclistget(cdfnodes,i);
1195 	NCerror err = fix1node(nccomm,node);
1196 	if(err) return err;
1197     }
1198     return NC_NOERR;
1199 }
1200 
1201 static void
defdimensions(OCddsnode ocnode,CDFnode * cdfnode,NCDAPCOMMON * nccomm,CDFtree * tree)1202 defdimensions(OCddsnode ocnode, CDFnode* cdfnode, NCDAPCOMMON* nccomm, CDFtree* tree)
1203 {
1204     size_t i,ocrank;
1205 
1206     oc_dds_rank(nccomm->oc.conn,ocnode,&ocrank);
1207     assert(ocrank > 0);
1208     for(i=0;i<ocrank;i++) {
1209 	CDFnode* cdfdim;
1210 	OCddsnode ocdim;
1211 	char* ocname;
1212 	size_t declsize;
1213 
1214 	oc_dds_ithdimension(nccomm->oc.conn,ocnode,i,&ocdim);
1215 	oc_dimension_properties(nccomm->oc.conn,ocdim,&declsize,&ocname);
1216 
1217 	cdfdim = makecdfnode(nccomm,ocname,OC_Dimension,
1218                               ocdim,cdfnode->container);
1219 	nullfree(ocname);
1220 	nclistpush(tree->nodes,(void*)cdfdim);
1221 	/* Initially, constrained and unconstrained are same */
1222 	cdfdim->dim.declsize = declsize;
1223 	cdfdim->dim.array = cdfnode;
1224 	if(cdfnode->array.dimset0 == NULL)
1225 	    cdfnode->array.dimset0 = nclistnew();
1226 	nclistpush(cdfnode->array.dimset0,(void*)cdfdim);
1227     }
1228 }
1229