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