1 | /********************************************************************* |
---|
2 | * Copyright 1993, UCAR/Unidata |
---|
3 | * See netcdf/COPYRIGHT file for copying and redistribution conditions. |
---|
4 | * $Header: /upc/share/CVS/netcdf-3/libncdap3/common34.c,v 1.29 2010/05/25 13:53:02 ed Exp $ |
---|
5 | *********************************************************************/ |
---|
6 | |
---|
7 | #include "ncdap3.h" |
---|
8 | |
---|
9 | #ifdef HAVE_GETRLIMIT |
---|
10 | # ifdef HAVE_SYS_RESOURCE_H |
---|
11 | # include <sys/time.h> |
---|
12 | # endif |
---|
13 | # ifdef HAVE_SYS_RESOURCE_H |
---|
14 | # include <sys/resource.h> |
---|
15 | # endif |
---|
16 | #endif |
---|
17 | #include "dapdump.h" |
---|
18 | |
---|
19 | extern CDFnode* v4node; |
---|
20 | |
---|
21 | /* Define the set of protocols known to be constrainable */ |
---|
22 | static char* constrainableprotocols[] = {"http", "https",NULL}; |
---|
23 | static NCerror buildcdftree34r(NCDAPCOMMON*,OCobject,CDFnode*,CDFtree*,CDFnode**); |
---|
24 | static void defdimensions(OCobject, CDFnode*, NCDAPCOMMON*, CDFtree*); |
---|
25 | static NCerror attachsubset34r(CDFnode*, CDFnode*); |
---|
26 | static void free1cdfnode34(CDFnode* node); |
---|
27 | |
---|
28 | /* Define Procedures that are common to both |
---|
29 | libncdap3 and libncdap4 |
---|
30 | */ |
---|
31 | |
---|
32 | /* Ensure every node has an initial base name defined and fullname */ |
---|
33 | /* Exceptions: anonymous dimensions. */ |
---|
34 | static NCerror |
---|
35 | fix1node34(NCDAPCOMMON* nccomm, CDFnode* node) |
---|
36 | { |
---|
37 | if(node->nctype == NC_Dimension && node->ocname == NULL) return NC_NOERR; |
---|
38 | ASSERT((node->ocname != NULL)); |
---|
39 | nullfree(node->ncbasename); |
---|
40 | node->ncbasename = cdflegalname3(node->ocname); |
---|
41 | if(node->ncbasename == NULL) return NC_ENOMEM; |
---|
42 | nullfree(node->ncfullname); |
---|
43 | node->ncfullname = makecdfpathstring3(node,nccomm->cdf.separator); |
---|
44 | if(node->ncfullname == NULL) return NC_ENOMEM; |
---|
45 | if(node->nctype == NC_Primitive) |
---|
46 | node->externaltype = nctypeconvert(nccomm,node->etype); |
---|
47 | return NC_NOERR; |
---|
48 | } |
---|
49 | |
---|
50 | NCerror |
---|
51 | fixnodes34(NCDAPCOMMON* nccomm, NClist* cdfnodes) |
---|
52 | { |
---|
53 | int i; |
---|
54 | for(i=0;i<nclistlength(cdfnodes);i++) { |
---|
55 | CDFnode* node = (CDFnode*)nclistget(cdfnodes,i); |
---|
56 | NCerror err = fix1node34(nccomm,node); |
---|
57 | if(err) return err; |
---|
58 | } |
---|
59 | return NC_NOERR; |
---|
60 | } |
---|
61 | |
---|
62 | |
---|
63 | NCerror |
---|
64 | fixgrid34(NCDAPCOMMON* nccomm, CDFnode* grid) |
---|
65 | { |
---|
66 | unsigned int i,glen; |
---|
67 | CDFnode* array; |
---|
68 | |
---|
69 | glen = nclistlength(grid->subnodes); |
---|
70 | array = (CDFnode*)nclistget(grid->subnodes,0); |
---|
71 | if(nccomm->controls.flags & (NCF_NC3)) { |
---|
72 | /* Rename grid Array: variable, but leave its oc base name alone */ |
---|
73 | nullfree(array->ncbasename); |
---|
74 | array->ncbasename = nulldup(grid->ncbasename); |
---|
75 | if(!array->ncbasename) return NC_ENOMEM; |
---|
76 | } |
---|
77 | /* validate and modify the grid structure */ |
---|
78 | if((glen-1) != nclistlength(array->array.dimset0)) goto invalid; |
---|
79 | for(i=1;i<glen;i++) { |
---|
80 | CDFnode* arraydim = (CDFnode*)nclistget(array->array.dimset0,i-1); |
---|
81 | CDFnode* map = (CDFnode*)nclistget(grid->subnodes,i); |
---|
82 | CDFnode* mapdim; |
---|
83 | /* map must have 1 dimension */ |
---|
84 | if(nclistlength(map->array.dimset0) != 1) goto invalid; |
---|
85 | /* and the map name must match the ith array dimension */ |
---|
86 | if(arraydim->ocname != NULL && map->ocname != NULL |
---|
87 | && strcmp(arraydim->ocname,map->ocname) != 0) |
---|
88 | goto invalid; |
---|
89 | /* and the map name must match its dim name (if any) */ |
---|
90 | mapdim = (CDFnode*)nclistget(map->array.dimset0,0); |
---|
91 | if(mapdim->ocname != NULL && map->ocname != NULL |
---|
92 | && strcmp(mapdim->ocname,map->ocname) != 0) |
---|
93 | goto invalid; |
---|
94 | /* Add appropriate names for the anonymous dimensions */ |
---|
95 | /* Do the map name first, so the array dim may inherit */ |
---|
96 | if(mapdim->ocname == NULL) { |
---|
97 | nullfree(mapdim->ncbasename); |
---|
98 | mapdim->ocname = nulldup(map->ocname); |
---|
99 | if(!mapdim->ocname) return NC_ENOMEM; |
---|
100 | mapdim->ncbasename = cdflegalname3(mapdim->ocname); |
---|
101 | if(!mapdim->ncbasename) return NC_ENOMEM; |
---|
102 | } |
---|
103 | if(arraydim->ocname == NULL) { |
---|
104 | nullfree(arraydim->ncbasename); |
---|
105 | arraydim->ocname = nulldup(map->ocname); |
---|
106 | if(!arraydim->ocname) return NC_ENOMEM; |
---|
107 | arraydim->ncbasename = cdflegalname3(arraydim->ocname); |
---|
108 | if(!arraydim->ncbasename) return NC_ENOMEM; |
---|
109 | } |
---|
110 | if(FLAGSET(nccomm->controls,(NCF_NCDAP|NCF_NC3))) { |
---|
111 | char tmp[3*NC_MAX_NAME]; |
---|
112 | /* Add the grid name to the basename of the map */ |
---|
113 | snprintf(tmp,sizeof(tmp),"%s%s%s",map->container->ncbasename, |
---|
114 | nccomm->cdf.separator, |
---|
115 | map->ncbasename); |
---|
116 | nullfree(map->ncbasename); |
---|
117 | map->ncbasename = nulldup(tmp); |
---|
118 | if(!map->ncbasename) return NC_ENOMEM; |
---|
119 | } |
---|
120 | } |
---|
121 | return NC_NOERR; |
---|
122 | invalid: |
---|
123 | return NC_EINVAL; /* mal-formed grid */ |
---|
124 | } |
---|
125 | |
---|
126 | /** |
---|
127 | * Given an anonymous dimension, compute the |
---|
128 | * effective 0-based index wrt to the specified var. |
---|
129 | * The result should mimic the libnc-dap indices. |
---|
130 | */ |
---|
131 | |
---|
132 | static void |
---|
133 | computedimindexanon3(CDFnode* dim, CDFnode* var) |
---|
134 | { |
---|
135 | int i; |
---|
136 | NClist* dimset = var->array.dimsetall; |
---|
137 | for(i=0;i<nclistlength(dimset);i++) { |
---|
138 | CDFnode* candidate = (CDFnode*)nclistget(dimset,i); |
---|
139 | if(dim == candidate) { |
---|
140 | dim->dim.index1=i+1; |
---|
141 | return; |
---|
142 | } |
---|
143 | } |
---|
144 | } |
---|
145 | |
---|
146 | /* Replace dims in a list with their corresponding basedim */ |
---|
147 | static void |
---|
148 | replacedims(NClist* dims) |
---|
149 | { |
---|
150 | int i; |
---|
151 | for(i=0;i<nclistlength(dims);i++) { |
---|
152 | CDFnode* dim = (CDFnode*)nclistget(dims,i); |
---|
153 | CDFnode* basedim = dim->dim.basedim; |
---|
154 | if(basedim == NULL) continue; |
---|
155 | nclistset(dims,i,(ncelem)basedim); |
---|
156 | } |
---|
157 | } |
---|
158 | |
---|
159 | /** |
---|
160 | Two dimensions are equivalent if |
---|
161 | 1. they have the same size |
---|
162 | 2. neither are anonymous |
---|
163 | 3. they ave the same names. |
---|
164 | */ |
---|
165 | static int |
---|
166 | equivalentdim(CDFnode* basedim, CDFnode* dupdim) |
---|
167 | { |
---|
168 | if(dupdim->dim.declsize != basedim->dim.declsize) return 0; |
---|
169 | if(basedim->ocname == NULL && dupdim->ocname == NULL) return 0; |
---|
170 | if(basedim->ocname == NULL || dupdim->ocname == NULL) return 0; |
---|
171 | if(strcmp(dupdim->ocname,basedim->ocname) != 0) return 0; |
---|
172 | return 1; |
---|
173 | } |
---|
174 | |
---|
175 | /* |
---|
176 | Provide short and/or unified names for dimensions. |
---|
177 | This must mimic lib-ncdap, which is difficult. |
---|
178 | */ |
---|
179 | NCerror |
---|
180 | computecdfdimnames34(NCDAPCOMMON* nccomm) |
---|
181 | { |
---|
182 | int i,j; |
---|
183 | char tmp[NC_MAX_NAME*2]; |
---|
184 | NClist* conflicts = nclistnew(); |
---|
185 | NClist* varnodes = nccomm->cdf.varnodes; |
---|
186 | NClist* alldims; |
---|
187 | NClist* basedims; |
---|
188 | |
---|
189 | /* Collect all dimension nodes from dimsetall lists */ |
---|
190 | |
---|
191 | alldims = getalldims34(nccomm,0); |
---|
192 | |
---|
193 | /* Assign an index to all anonymous dimensions |
---|
194 | vis-a-vis its containing variable |
---|
195 | */ |
---|
196 | for(i=0;i<nclistlength(varnodes);i++) { |
---|
197 | CDFnode* var = (CDFnode*)nclistget(varnodes,i); |
---|
198 | for(j=0;j<nclistlength(var->array.dimsetall);j++) { |
---|
199 | CDFnode* dim = (CDFnode*)nclistget(var->array.dimsetall,j); |
---|
200 | if(dim->ocname != NULL) continue; /* not anonymous */ |
---|
201 | computedimindexanon3(dim,var); |
---|
202 | } |
---|
203 | } |
---|
204 | |
---|
205 | /* Unify dimensions by defining one dimension as the "base" |
---|
206 | dimension, and make all "equivalent" dimensions point to the |
---|
207 | base dimension. |
---|
208 | 1. Equivalent means: same size and both have identical non-null names. |
---|
209 | 2. Dims with same name but different sizes will be handled separately |
---|
210 | */ |
---|
211 | for(i=0;i<nclistlength(alldims);i++) { |
---|
212 | CDFnode* dupdim = NULL; |
---|
213 | CDFnode* basedim = (CDFnode*)nclistget(alldims,i); |
---|
214 | if(basedim == NULL) continue; |
---|
215 | if(basedim->dim.basedim != NULL) continue; /* already processed*/ |
---|
216 | for(j=i+1;j<nclistlength(alldims);j++) { /* Sigh, n**2 */ |
---|
217 | dupdim = (CDFnode*)nclistget(alldims,j); |
---|
218 | if(basedim == dupdim) continue; |
---|
219 | if(dupdim == NULL) continue; |
---|
220 | if(dupdim->dim.basedim != NULL) continue; /* already processed */ |
---|
221 | if(!equivalentdim(basedim,dupdim)) |
---|
222 | continue; |
---|
223 | dupdim->dim.basedim = basedim; /* equate */ |
---|
224 | #ifdef DEBUG1 |
---|
225 | fprintf(stderr,"assign: %s/%s -> %s/%s\n", |
---|
226 | basedim->dim.array->ocname,basedim->ocname, |
---|
227 | dupdim->dim.array->ocname,dupdim->ocname |
---|
228 | ); |
---|
229 | #endif |
---|
230 | } |
---|
231 | } |
---|
232 | |
---|
233 | /* Next case: same name and different sizes*/ |
---|
234 | /* => rename second dim */ |
---|
235 | |
---|
236 | for(i=0;i<nclistlength(alldims);i++) { |
---|
237 | CDFnode* basedim = (CDFnode*)nclistget(alldims,i); |
---|
238 | if(basedim->dim.basedim != NULL) continue; |
---|
239 | /* Collect all conflicting dimensions */ |
---|
240 | nclistclear(conflicts); |
---|
241 | for(j=i+1;j<nclistlength(alldims);j++) { |
---|
242 | CDFnode* dim = (CDFnode*)nclistget(alldims,j); |
---|
243 | if(dim->dim.basedim != NULL) continue; |
---|
244 | if(dim->ocname == NULL && basedim->ocname == NULL) continue; |
---|
245 | if(dim->ocname == NULL || basedim->ocname == NULL) continue; |
---|
246 | if(strcmp(dim->ocname,basedim->ocname)!=0) continue; |
---|
247 | if(dim->dim.declsize == basedim->dim.declsize) continue; |
---|
248 | #ifdef DEBUG2 |
---|
249 | fprintf(stderr,"conflict: %s[%lu] %s[%lu]\n", |
---|
250 | basedim->ncfullname,(unsigned long)basedim->dim.declsize, |
---|
251 | dim->ncfullname,(unsigned long)dim->dim.declsize); |
---|
252 | #endif |
---|
253 | nclistpush(conflicts,(ncelem)dim); |
---|
254 | } |
---|
255 | /* Give all the conflicting dimensions an index */ |
---|
256 | for(j=0;j<nclistlength(conflicts);j++) { |
---|
257 | CDFnode* dim = (CDFnode*)nclistget(conflicts,j); |
---|
258 | dim->dim.index1 = j+1; |
---|
259 | } |
---|
260 | } |
---|
261 | nclistfree(conflicts); |
---|
262 | |
---|
263 | /* Replace all non-base dimensions with their base dimension */ |
---|
264 | for(i=0;i<nclistlength(varnodes);i++) { |
---|
265 | CDFnode* node = (CDFnode*)nclistget(varnodes,i); |
---|
266 | replacedims(node->array.dimsetall); |
---|
267 | replacedims(node->array.dimsetplus); |
---|
268 | replacedims(node->array.dimset0); |
---|
269 | } |
---|
270 | |
---|
271 | /* Collect list of all basedims */ |
---|
272 | basedims = nclistnew(); |
---|
273 | for(i=0;i<nclistlength(alldims);i++) { |
---|
274 | CDFnode* dim = (CDFnode*)nclistget(alldims,i); |
---|
275 | if(dim->dim.basedim == NULL) { |
---|
276 | if(!nclistcontains(basedims,(ncelem)dim)) { |
---|
277 | nclistpush(basedims,(ncelem)dim); |
---|
278 | } |
---|
279 | } |
---|
280 | } |
---|
281 | |
---|
282 | nccomm->cdf.dimnodes = basedims; |
---|
283 | |
---|
284 | /* cleanup */ |
---|
285 | nclistfree(alldims); |
---|
286 | |
---|
287 | /* Assign ncbasenames and ncfullnames to base dimensions */ |
---|
288 | for(i=0;i<nclistlength(basedims);i++) { |
---|
289 | CDFnode* dim = (CDFnode*)nclistget(basedims,i); |
---|
290 | CDFnode* var = dim->dim.array; |
---|
291 | if(dim->dim.basedim != NULL) PANIC1("nonbase basedim: %s\n",dim->ocname); |
---|
292 | /* stringdim names are already assigned */ |
---|
293 | if(dim->ocname == NULL) { /* anonymous: use the index to compute the name */ |
---|
294 | snprintf(tmp,sizeof(tmp),"%s_%d", |
---|
295 | var->ncfullname,dim->dim.index1-1); |
---|
296 | nullfree(dim->ncbasename); |
---|
297 | dim->ncbasename = cdflegalname3(tmp); |
---|
298 | nullfree(dim->ncfullname); |
---|
299 | dim->ncfullname = nulldup(dim->ncbasename); |
---|
300 | } else { /* !anonymous; use index1 if defined */ |
---|
301 | char* legalname = cdflegalname3(dim->ocname); |
---|
302 | nullfree(dim->ncbasename); |
---|
303 | if(dim->dim.index1 > 0) {/* need to fix conflicting names (see above) */ |
---|
304 | char sindex[64]; |
---|
305 | snprintf(sindex,sizeof(sindex),"_%d",dim->dim.index1); |
---|
306 | dim->ncbasename = (char*)malloc(strlen(sindex)+strlen(legalname)+1); |
---|
307 | if(dim->ncbasename == NULL) return NC_ENOMEM; |
---|
308 | strcpy(dim->ncbasename,legalname); |
---|
309 | strcat(dim->ncbasename,sindex); |
---|
310 | nullfree(legalname); |
---|
311 | } else {/* standard case */ |
---|
312 | dim->ncbasename = legalname; |
---|
313 | } |
---|
314 | nullfree(dim->ncfullname); |
---|
315 | dim->ncfullname = nulldup(dim->ncbasename); |
---|
316 | } |
---|
317 | } |
---|
318 | |
---|
319 | /* Verify unique and defined names for dimensions*/ |
---|
320 | for(i=0;i<nclistlength(basedims);i++) { |
---|
321 | CDFnode* dim1 = (CDFnode*)nclistget(basedims,i); |
---|
322 | if(dim1->dim.basedim != NULL) PANIC1("nonbase basedim: %s\n",dim1->ncbasename); |
---|
323 | if(dim1->ncbasename == NULL || dim1->ncfullname == NULL) |
---|
324 | PANIC1("missing dim names: %s",dim1->ocname); |
---|
325 | /* search backward so we can delete duplicates */ |
---|
326 | for(j=nclistlength(basedims)-1;j>i;j--) { |
---|
327 | CDFnode* dim2 = (CDFnode*)nclistget(basedims,j); |
---|
328 | if(strcmp(dim1->ncfullname,dim2->ncfullname)==0) { |
---|
329 | /* complain and suppress one of them */ |
---|
330 | fprintf(stderr,"duplicate dim names: %s[%lu] %s[%lu]\n", |
---|
331 | dim1->ncfullname,(unsigned long)dim1->dim.declsize, |
---|
332 | dim2->ncfullname,(unsigned long)dim2->dim.declsize); |
---|
333 | nclistremove(basedims,j); |
---|
334 | } |
---|
335 | } |
---|
336 | } |
---|
337 | |
---|
338 | #ifdef DEBUG |
---|
339 | for(i=0;i<nclistlength(basedims);i++) { |
---|
340 | CDFnode* dim = (CDFnode*)nclistget(basedims,i); |
---|
341 | fprintf(stderr,"basedim: %s=%ld\n",dim->ncfullname,(long)dim->dim.declsize); |
---|
342 | } |
---|
343 | #endif |
---|
344 | |
---|
345 | return NC_NOERR; |
---|
346 | } |
---|
347 | |
---|
348 | NCerror |
---|
349 | makegetvar34(NCDAPCOMMON* nccomm, CDFnode* var, void* data, nc_type dsttype, Getvara** getvarp) |
---|
350 | { |
---|
351 | Getvara* getvar; |
---|
352 | NCerror ncstat = NC_NOERR; |
---|
353 | |
---|
354 | getvar = (Getvara*)calloc(1,sizeof(Getvara)); |
---|
355 | MEMCHECK(getvar,NC_ENOMEM); |
---|
356 | if(getvarp) *getvarp = getvar; |
---|
357 | |
---|
358 | getvar->target = var; |
---|
359 | getvar->memory = data; |
---|
360 | getvar->dsttype = dsttype; |
---|
361 | getvar->target = var; |
---|
362 | if(ncstat) nullfree(getvar); |
---|
363 | return ncstat; |
---|
364 | } |
---|
365 | |
---|
366 | int |
---|
367 | constrainable34(NC_URI* durl) |
---|
368 | { |
---|
369 | char** protocol = constrainableprotocols; |
---|
370 | for(;*protocol;protocol++) { |
---|
371 | if(strcmp(durl->protocol,*protocol)==0) |
---|
372 | return 1; |
---|
373 | } |
---|
374 | return 0; |
---|
375 | } |
---|
376 | |
---|
377 | CDFnode* |
---|
378 | makecdfnode34(NCDAPCOMMON* nccomm, char* name, OCtype octype, |
---|
379 | /*optional*/ OCobject ocnode, CDFnode* container) |
---|
380 | { |
---|
381 | CDFnode* node; |
---|
382 | assert(nccomm != NULL); |
---|
383 | node = (CDFnode*)calloc(1,sizeof(CDFnode)); |
---|
384 | if(node == NULL) return (CDFnode*)NULL; |
---|
385 | |
---|
386 | node->ocname = NULL; |
---|
387 | if(name) { |
---|
388 | size_t len = strlen(name); |
---|
389 | if(len >= NC_MAX_NAME) len = NC_MAX_NAME-1; |
---|
390 | node->ocname = (char*)malloc(len+1); |
---|
391 | if(node->ocname == NULL) return NULL; |
---|
392 | memcpy(node->ocname,name,len); |
---|
393 | node->ocname[len] = '\0'; |
---|
394 | } |
---|
395 | node->nctype = octypetonc(octype); |
---|
396 | node->ocnode = ocnode; |
---|
397 | node->subnodes = nclistnew(); |
---|
398 | node->container = container; |
---|
399 | if(ocnode != OCNULL) { |
---|
400 | oc_inq_primtype(nccomm->oc.conn,ocnode,&octype); |
---|
401 | node->etype = octypetonc(octype); |
---|
402 | } |
---|
403 | return node; |
---|
404 | } |
---|
405 | |
---|
406 | /* Given an OCnode tree, mimic it as a CDFnode tree; |
---|
407 | Add DAS attributes if DAS is available. Accumulate set |
---|
408 | of all nodes in preorder. |
---|
409 | */ |
---|
410 | NCerror |
---|
411 | buildcdftree34(NCDAPCOMMON* nccomm, OCobject ocroot, OCdxd occlass, CDFnode** cdfrootp) |
---|
412 | { |
---|
413 | CDFnode* root = NULL; |
---|
414 | CDFtree* tree = (CDFtree*)calloc(1,sizeof(CDFtree)); |
---|
415 | NCerror err = NC_NOERR; |
---|
416 | tree->ocroot = ocroot; |
---|
417 | tree->nodes = nclistnew(); |
---|
418 | tree->occlass = occlass; |
---|
419 | tree->owner = nccomm; |
---|
420 | |
---|
421 | err = buildcdftree34r(nccomm,ocroot,NULL,tree,&root); |
---|
422 | if(!err) { |
---|
423 | if(occlass != OCDAS) |
---|
424 | fixnodes34(nccomm,tree->nodes); |
---|
425 | if(cdfrootp) *cdfrootp = root; |
---|
426 | } |
---|
427 | return err; |
---|
428 | } |
---|
429 | |
---|
430 | static NCerror |
---|
431 | buildcdftree34r(NCDAPCOMMON* nccomm, OCobject ocnode, CDFnode* container, |
---|
432 | CDFtree* tree, CDFnode** cdfnodep) |
---|
433 | { |
---|
434 | unsigned int i,ocrank,ocnsubnodes; |
---|
435 | OCtype octype; |
---|
436 | char* ocname = NULL; |
---|
437 | NCerror ncerr = NC_NOERR; |
---|
438 | CDFnode* cdfnode; |
---|
439 | |
---|
440 | oc_inq_class(nccomm->oc.conn,ocnode,&octype); |
---|
441 | oc_inq_name(nccomm->oc.conn,ocnode,&ocname); |
---|
442 | oc_inq_rank(nccomm->oc.conn,ocnode,&ocrank); |
---|
443 | oc_inq_nsubnodes(nccomm->oc.conn,ocnode,&ocnsubnodes); |
---|
444 | |
---|
445 | switch (octype) { |
---|
446 | case OC_Dataset: |
---|
447 | case OC_Grid: |
---|
448 | case OC_Structure: |
---|
449 | case OC_Sequence: |
---|
450 | case OC_Primitive: |
---|
451 | cdfnode = makecdfnode34(nccomm,ocname,octype,ocnode,container); |
---|
452 | nclistpush(tree->nodes,(ncelem)cdfnode); |
---|
453 | if(tree->root == NULL) { |
---|
454 | tree->root = cdfnode; |
---|
455 | cdfnode->tree = tree; |
---|
456 | } |
---|
457 | break; |
---|
458 | |
---|
459 | case OC_Dimension: |
---|
460 | default: PANIC1("buildcdftree: unexpect OC node type: %d",(int)octype); |
---|
461 | |
---|
462 | } |
---|
463 | /* cross link */ |
---|
464 | cdfnode->root = tree->root; |
---|
465 | |
---|
466 | if(ocrank > 0) defdimensions(ocnode,cdfnode,nccomm,tree); |
---|
467 | for(i=0;i<ocnsubnodes;i++) { |
---|
468 | OCobject ocsubnode; |
---|
469 | CDFnode* subnode; |
---|
470 | oc_inq_ith(nccomm->oc.conn,ocnode,i,&ocsubnode); |
---|
471 | ncerr = buildcdftree34r(nccomm,ocsubnode,cdfnode,tree,&subnode); |
---|
472 | if(ncerr) return ncerr; |
---|
473 | nclistpush(cdfnode->subnodes,(ncelem)subnode); |
---|
474 | } |
---|
475 | nullfree(ocname); |
---|
476 | if(cdfnodep) *cdfnodep = cdfnode; |
---|
477 | return ncerr; |
---|
478 | } |
---|
479 | |
---|
480 | static void |
---|
481 | defdimensions(OCobject ocnode, CDFnode* cdfnode, NCDAPCOMMON* nccomm, CDFtree* tree) |
---|
482 | { |
---|
483 | unsigned int i,ocrank; |
---|
484 | |
---|
485 | oc_inq_rank(nccomm->oc.conn,ocnode,&ocrank); |
---|
486 | assert(ocrank > 0); |
---|
487 | for(i=0;i<ocrank;i++) { |
---|
488 | CDFnode* cdfdim; |
---|
489 | OCobject ocdim; |
---|
490 | char* ocname; |
---|
491 | size_t declsize; |
---|
492 | |
---|
493 | oc_inq_ithdim(nccomm->oc.conn,ocnode,i,&ocdim); |
---|
494 | oc_inq_dim(nccomm->oc.conn,ocdim,&declsize,&ocname); |
---|
495 | |
---|
496 | cdfdim = makecdfnode34(nccomm,ocname,OC_Dimension, |
---|
497 | ocdim,cdfnode->container); |
---|
498 | nullfree(ocname); |
---|
499 | nclistpush(tree->nodes,(ncelem)cdfdim); |
---|
500 | /* Initially, constrained and unconstrained are same */ |
---|
501 | cdfdim->dim.declsize = declsize; |
---|
502 | cdfdim->dim.array = cdfnode; |
---|
503 | if(cdfnode->array.dimset0 == NULL) |
---|
504 | cdfnode->array.dimset0 = nclistnew(); |
---|
505 | nclistpush(cdfnode->array.dimset0,(ncelem)cdfdim); |
---|
506 | } |
---|
507 | } |
---|
508 | |
---|
509 | /* Note: this routine only applies some common |
---|
510 | client parameters, other routines may apply |
---|
511 | specific ones. |
---|
512 | */ |
---|
513 | |
---|
514 | NCerror |
---|
515 | applyclientparams34(NCDAPCOMMON* nccomm) |
---|
516 | { |
---|
517 | int i,len; |
---|
518 | int dfaltstrlen = DEFAULTSTRINGLENGTH; |
---|
519 | int dfaltseqlim = DEFAULTSEQLIMIT; |
---|
520 | const char* value; |
---|
521 | char tmpname[NC_MAX_NAME+32]; |
---|
522 | char* pathstr; |
---|
523 | OCconnection conn = nccomm->oc.conn; |
---|
524 | unsigned long limit; |
---|
525 | |
---|
526 | ASSERT(nccomm->oc.url != NULL); |
---|
527 | |
---|
528 | nccomm->cdf.cache->cachelimit = DFALTCACHELIMIT; |
---|
529 | value = oc_clientparam_get(conn,"cachelimit"); |
---|
530 | limit = getlimitnumber(value); |
---|
531 | if(limit > 0) nccomm->cdf.cache->cachelimit = limit; |
---|
532 | |
---|
533 | nccomm->cdf.fetchlimit = DFALTFETCHLIMIT; |
---|
534 | value = oc_clientparam_get(conn,"fetchlimit"); |
---|
535 | limit = getlimitnumber(value); |
---|
536 | if(limit > 0) nccomm->cdf.fetchlimit = limit; |
---|
537 | |
---|
538 | nccomm->cdf.smallsizelimit = DFALTSMALLLIMIT; |
---|
539 | value = oc_clientparam_get(conn,"smallsizelimit"); |
---|
540 | limit = getlimitnumber(value); |
---|
541 | if(limit > 0) nccomm->cdf.smallsizelimit = limit; |
---|
542 | |
---|
543 | nccomm->cdf.cache->cachecount = DFALTCACHECOUNT; |
---|
544 | #ifdef HAVE_GETRLIMIT |
---|
545 | { struct rlimit rl; |
---|
546 | if(getrlimit(RLIMIT_NOFILE, &rl) >= 0) { |
---|
547 | nccomm->cdf.cache->cachecount = (size_t)(rl.rlim_cur / 2); |
---|
548 | } |
---|
549 | } |
---|
550 | #endif |
---|
551 | value = oc_clientparam_get(conn,"cachecount"); |
---|
552 | limit = getlimitnumber(value); |
---|
553 | if(limit > 0) nccomm->cdf.cache->cachecount = limit; |
---|
554 | /* Ignore limit if not caching */ |
---|
555 | if(!FLAGSET(nccomm->controls,NCF_CACHE)) |
---|
556 | nccomm->cdf.cache->cachecount = 0; |
---|
557 | |
---|
558 | if(oc_clientparam_get(conn,"nolimit") != NULL) |
---|
559 | dfaltseqlim = 0; |
---|
560 | value = oc_clientparam_get(conn,"limit"); |
---|
561 | if(value != NULL && strlen(value) != 0) { |
---|
562 | if(sscanf(value,"%d",&len) && len > 0) dfaltseqlim = len; |
---|
563 | } |
---|
564 | nccomm->cdf.defaultsequencelimit = dfaltseqlim; |
---|
565 | |
---|
566 | /* allow embedded _ */ |
---|
567 | value = oc_clientparam_get(conn,"stringlength"); |
---|
568 | if(value != NULL && strlen(value) != 0) { |
---|
569 | if(sscanf(value,"%d",&len) && len > 0) dfaltstrlen = len; |
---|
570 | } |
---|
571 | nccomm->cdf.defaultstringlength = dfaltstrlen; |
---|
572 | |
---|
573 | /* String dimension limits apply to variables */ |
---|
574 | for(i=0;i<nclistlength(nccomm->cdf.varnodes);i++) { |
---|
575 | CDFnode* var = (CDFnode*)nclistget(nccomm->cdf.varnodes,i); |
---|
576 | /* Define the client param stringlength for this variable*/ |
---|
577 | var->maxstringlength = 0; /* => use global dfalt */ |
---|
578 | strcpy(tmpname,"stringlength_"); |
---|
579 | pathstr = makeocpathstring3(conn,var->ocnode,"."); |
---|
580 | strcat(tmpname,pathstr); |
---|
581 | nullfree(pathstr); |
---|
582 | value = oc_clientparam_get(conn,tmpname); |
---|
583 | if(value != NULL && strlen(value) != 0) { |
---|
584 | if(sscanf(value,"%d",&len) && len > 0) var->maxstringlength = len; |
---|
585 | } |
---|
586 | } |
---|
587 | /* Sequence limits apply to sequences */ |
---|
588 | for(i=0;i<nclistlength(nccomm->cdf.ddsroot->tree->nodes);i++) { |
---|
589 | CDFnode* var = (CDFnode*)nclistget(nccomm->cdf.ddsroot->tree->nodes,i); |
---|
590 | if(var->nctype != NC_Sequence) continue; |
---|
591 | var->sequencelimit = dfaltseqlim; |
---|
592 | strcpy(tmpname,"nolimit_"); |
---|
593 | pathstr = makeocpathstring3(conn,var->ocnode,"."); |
---|
594 | strcat(tmpname,pathstr); |
---|
595 | if(oc_clientparam_get(conn,tmpname) != NULL) |
---|
596 | var->sequencelimit = 0; |
---|
597 | strcpy(tmpname,"limit_"); |
---|
598 | strcat(tmpname,pathstr); |
---|
599 | value = oc_clientparam_get(conn,tmpname); |
---|
600 | if(value != NULL && strlen(value) != 0) { |
---|
601 | if(sscanf(value,"%d",&len) && len > 0) |
---|
602 | var->sequencelimit = len; |
---|
603 | } |
---|
604 | nullfree(pathstr); |
---|
605 | } |
---|
606 | |
---|
607 | /* test for the appropriate fetch flags */ |
---|
608 | value = oc_clientparam_get(conn,"fetch"); |
---|
609 | if(value != NULL && strlen(value) > 0) { |
---|
610 | if(value[0] == 'd' || value[0] == 'D') { |
---|
611 | SETFLAG(nccomm->controls,NCF_ONDISK); |
---|
612 | } |
---|
613 | } |
---|
614 | |
---|
615 | /* test for the force-whole-var flag */ |
---|
616 | value = oc_clientparam_get(conn,"wholevar"); |
---|
617 | if(value != NULL) { |
---|
618 | SETFLAG(nccomm->controls,NCF_WHOLEVAR); |
---|
619 | } |
---|
620 | |
---|
621 | return NC_NOERR; |
---|
622 | } |
---|
623 | |
---|
624 | void |
---|
625 | freecdfroot34(CDFnode* root) |
---|
626 | { |
---|
627 | int i; |
---|
628 | CDFtree* tree; |
---|
629 | NCDAPCOMMON* nccomm; |
---|
630 | if(root == NULL) return; |
---|
631 | tree = root->tree; |
---|
632 | ASSERT((tree != NULL)); |
---|
633 | /* Explicitly FREE the ocroot */ |
---|
634 | nccomm = tree->owner; |
---|
635 | oc_root_free(nccomm->oc.conn,tree->ocroot); |
---|
636 | tree->ocroot = OCNULL; |
---|
637 | for(i=0;i<nclistlength(tree->nodes);i++) { |
---|
638 | CDFnode* node = (CDFnode*)nclistget(tree->nodes,i); |
---|
639 | free1cdfnode34(node); |
---|
640 | } |
---|
641 | nclistfree(tree->nodes); |
---|
642 | nullfree(tree); |
---|
643 | } |
---|
644 | |
---|
645 | /* Free up a single node, but not any |
---|
646 | nodes it points to. |
---|
647 | */ |
---|
648 | static void |
---|
649 | free1cdfnode34(CDFnode* node) |
---|
650 | { |
---|
651 | unsigned int j,k; |
---|
652 | if(node == NULL) return; |
---|
653 | nullfree(node->ocname); |
---|
654 | nullfree(node->ncbasename); |
---|
655 | nullfree(node->ncfullname); |
---|
656 | if(node->attributes != NULL) { |
---|
657 | for(j=0;j<nclistlength(node->attributes);j++) { |
---|
658 | NCattribute* att = (NCattribute*)nclistget(node->attributes,j); |
---|
659 | nullfree(att->name); |
---|
660 | for(k=0;k<nclistlength(att->values);k++) |
---|
661 | nullfree((char*)nclistget(att->values,k)); |
---|
662 | nclistfree(att->values); |
---|
663 | nullfree(att); |
---|
664 | } |
---|
665 | } |
---|
666 | nullfree(node->dodsspecial.dimname); |
---|
667 | nclistfree(node->subnodes); |
---|
668 | nclistfree(node->attributes); |
---|
669 | nclistfree(node->array.dimsetplus); |
---|
670 | nclistfree(node->array.dimsetall); |
---|
671 | nclistfree(node->array.dimset0); |
---|
672 | |
---|
673 | /* Clean up the ncdap4 fields also */ |
---|
674 | nullfree(node->typename); |
---|
675 | nullfree(node->vlenname); |
---|
676 | nullfree(node); |
---|
677 | } |
---|
678 | |
---|
679 | /* Return true if node and node1 appear to refer to the same thing; |
---|
680 | takes grid->structure changes into account. |
---|
681 | */ |
---|
682 | int |
---|
683 | nodematch34(CDFnode* node1, CDFnode* node2) |
---|
684 | { |
---|
685 | return simplenodematch34(node1,node2); |
---|
686 | } |
---|
687 | |
---|
688 | int |
---|
689 | simplenodematch34(CDFnode* node1, CDFnode* node2) |
---|
690 | { |
---|
691 | if(node1 == NULL) return (node2==NULL); |
---|
692 | if(node2 == NULL) return 0; |
---|
693 | if(node1->nctype != node2->nctype) { |
---|
694 | /* Check for Grid->Structure match */ |
---|
695 | if((node1->nctype == NC_Structure && node2->nctype == NC_Grid) |
---|
696 | || (node2->nctype == NC_Structure && node1->nctype == NC_Grid)){ |
---|
697 | if(node1->ocname == NULL || node2->ocname == NULL |
---|
698 | || strcmp(node1->ocname,node2->ocname) !=0) return 0; |
---|
699 | } else return 0; |
---|
700 | } |
---|
701 | /* Add hack to address the screwed up Columbia server */ |
---|
702 | if(node1->nctype == NC_Dataset) return 1; |
---|
703 | if(node1->nctype == NC_Primitive |
---|
704 | && node1->etype != node2->etype) return 0; |
---|
705 | if(node1->ocname != NULL && node2->ocname != NULL |
---|
706 | && strcmp(node1->ocname,node2->ocname)!=0) return 0; |
---|
707 | if(nclistlength(node1->array.dimset0) |
---|
708 | != nclistlength(node2->array.dimset0)) return 0; |
---|
709 | return 1; |
---|
710 | } |
---|
711 | |
---|
712 | /* |
---|
713 | Given DDS node, locate the node |
---|
714 | in a DATADDS that matches the DDS node. |
---|
715 | Return NULL if no node found |
---|
716 | */ |
---|
717 | |
---|
718 | void |
---|
719 | unattach34(CDFnode* root) |
---|
720 | { |
---|
721 | unsigned int i; |
---|
722 | CDFtree* xtree = root->tree; |
---|
723 | for(i=0;i<nclistlength(xtree->nodes);i++) { |
---|
724 | CDFnode* xnode = (CDFnode*)nclistget(xtree->nodes,i); |
---|
725 | /* break bi-directional link */ |
---|
726 | xnode->attachment = NULL; |
---|
727 | } |
---|
728 | } |
---|
729 | |
---|
730 | static void |
---|
731 | setattach(CDFnode* target, CDFnode* template) |
---|
732 | { |
---|
733 | target->attachment = template; |
---|
734 | template->attachment = target; |
---|
735 | /* Transfer important information */ |
---|
736 | target->externaltype = template->externaltype; |
---|
737 | target->maxstringlength = template->maxstringlength; |
---|
738 | target->sequencelimit = template->sequencelimit; |
---|
739 | target->ncid = template->ncid; |
---|
740 | /* also transfer libncdap4 info */ |
---|
741 | target->typeid = template->typeid; |
---|
742 | target->typesize = template->typesize; |
---|
743 | } |
---|
744 | |
---|
745 | static NCerror |
---|
746 | attachdims34(CDFnode* xnode, CDFnode* template) |
---|
747 | { |
---|
748 | unsigned int i; |
---|
749 | for(i=0;i<nclistlength(xnode->array.dimsetall);i++) { |
---|
750 | CDFnode* xdim = (CDFnode*)nclistget(xnode->array.dimsetall,i); |
---|
751 | CDFnode* tdim = (CDFnode*)nclistget(template->array.dimsetall,i); |
---|
752 | setattach(xdim,tdim); |
---|
753 | #ifdef DEBUG2 |
---|
754 | fprintf(stderr,"attachdim: %s->%s\n",xdim->ocname,tdim->ocname); |
---|
755 | #endif |
---|
756 | } |
---|
757 | return NC_NOERR; |
---|
758 | } |
---|
759 | |
---|
760 | /* |
---|
761 | Match a DATADDS node to a DDS node. |
---|
762 | It is assumed that both trees have been regridded if necessary. |
---|
763 | */ |
---|
764 | |
---|
765 | static NCerror |
---|
766 | attach34r(CDFnode* xnode, NClist* templatepath, int depth) |
---|
767 | { |
---|
768 | unsigned int i,plen,lastnode,gridable; |
---|
769 | NCerror ncstat = NC_NOERR; |
---|
770 | CDFnode* templatepathnode; |
---|
771 | CDFnode* templatepathnext; |
---|
772 | |
---|
773 | plen = nclistlength(templatepath); |
---|
774 | if(depth >= plen) {THROWCHK(ncstat=NC_EINVAL); goto done;} |
---|
775 | |
---|
776 | lastnode = (depth == (plen-1)); |
---|
777 | templatepathnode = (CDFnode*)nclistget(templatepath,depth); |
---|
778 | ASSERT((simplenodematch34(xnode,templatepathnode))); |
---|
779 | setattach(xnode,templatepathnode); |
---|
780 | #ifdef DEBUG2 |
---|
781 | fprintf(stderr,"attachnode: %s->%s\n",xnode->ocname,templatepathnode->ocname); |
---|
782 | #endif |
---|
783 | |
---|
784 | if(lastnode) goto done; /* We have the match and are done */ |
---|
785 | |
---|
786 | if(nclistlength(xnode->array.dimsetall) > 0) { |
---|
787 | attachdims34(xnode,templatepathnode); |
---|
788 | } |
---|
789 | |
---|
790 | ASSERT((!lastnode)); |
---|
791 | templatepathnext = (CDFnode*)nclistget(templatepath,depth+1); |
---|
792 | |
---|
793 | gridable = (templatepathnext->nctype == NC_Grid && depth+2 < plen); |
---|
794 | |
---|
795 | /* Try to find an xnode subnode that matches templatepathnext */ |
---|
796 | for(i=0;i<nclistlength(xnode->subnodes);i++) { |
---|
797 | CDFnode* xsubnode = (CDFnode*)nclistget(xnode->subnodes,i); |
---|
798 | if(simplenodematch34(xsubnode,templatepathnext)) { |
---|
799 | ncstat = attach34r(xsubnode,templatepath,depth+1); |
---|
800 | if(ncstat) goto done; |
---|
801 | } else if(gridable && xsubnode->nctype == NC_Primitive) { |
---|
802 | /* grids may or may not appear in the datadds; |
---|
803 | try to match the xnode subnodes against the parts of the grid |
---|
804 | */ |
---|
805 | CDFnode* templatepathnext2 = (CDFnode*)nclistget(templatepath,depth+2); |
---|
806 | if(simplenodematch34(xsubnode,templatepathnext2)) { |
---|
807 | ncstat = attach34r(xsubnode,templatepath,depth+2); |
---|
808 | if(ncstat) goto done; |
---|
809 | } |
---|
810 | } |
---|
811 | } |
---|
812 | done: |
---|
813 | return THROW(ncstat); |
---|
814 | } |
---|
815 | |
---|
816 | NCerror |
---|
817 | attach34(CDFnode* xroot, CDFnode* template) |
---|
818 | { |
---|
819 | NCerror ncstat = NC_NOERR; |
---|
820 | NClist* templatepath = nclistnew(); |
---|
821 | CDFnode* ddsroot = template->root; |
---|
822 | |
---|
823 | if(xroot->attachment) unattach34(xroot); |
---|
824 | if(ddsroot != NULL && ddsroot->attachment) unattach34(ddsroot); |
---|
825 | if(!simplenodematch34(xroot,ddsroot)) |
---|
826 | {THROWCHK(ncstat=NC_EINVAL); goto done;} |
---|
827 | collectnodepath3(template,templatepath,WITHDATASET); |
---|
828 | ncstat = attach34r(xroot,templatepath,0); |
---|
829 | done: |
---|
830 | nclistfree(templatepath); |
---|
831 | return ncstat; |
---|
832 | } |
---|
833 | |
---|
834 | /* |
---|
835 | Match nodes in template tree to nodes in target tree; |
---|
836 | template tree is typically a structural superset of target tree. |
---|
837 | WARNING: Dimensions are not attached |
---|
838 | */ |
---|
839 | |
---|
840 | NCerror |
---|
841 | attachsubset34(CDFnode* target, CDFnode* template) |
---|
842 | { |
---|
843 | NCerror ncstat = NC_NOERR; |
---|
844 | |
---|
845 | if(template == NULL) {THROWCHK(ncstat=NC_NOERR); goto done;} |
---|
846 | if(!nodematch34(target,template)) {THROWCHK(ncstat=NC_EINVAL); goto done;} |
---|
847 | #ifdef DEBUG2 |
---|
848 | fprintf(stderr,"attachsubset: target=%s\n",dumptree(target)); |
---|
849 | fprintf(stderr,"attachsubset: template=%s\n",dumptree(template)); |
---|
850 | #endif |
---|
851 | ncstat = attachsubset34r(target,template); |
---|
852 | done: |
---|
853 | return ncstat; |
---|
854 | } |
---|
855 | |
---|
856 | static NCerror |
---|
857 | attachsubset34r(CDFnode* target, CDFnode* template) |
---|
858 | { |
---|
859 | unsigned int i; |
---|
860 | NCerror ncstat = NC_NOERR; |
---|
861 | int fieldindex; |
---|
862 | |
---|
863 | #ifdef DEBUG2 |
---|
864 | fprintf(stderr,"attachsubsetr: attach: target=%s template=%s\n", |
---|
865 | target->ocname,template->ocname); |
---|
866 | #endif |
---|
867 | |
---|
868 | ASSERT((nodematch34(target,template))); |
---|
869 | setattach(target,template); |
---|
870 | |
---|
871 | /* Try to match target subnodes against template subnodes */ |
---|
872 | |
---|
873 | fieldindex = 0; |
---|
874 | for(fieldindex=0,i=0;i<nclistlength(template->subnodes) && fieldindex<nclistlength(target->subnodes);i++) { |
---|
875 | CDFnode* templatesubnode = (CDFnode*)nclistget(template->subnodes,i); |
---|
876 | CDFnode* targetsubnode = (CDFnode*)nclistget(target->subnodes,fieldindex); |
---|
877 | if(nodematch34(targetsubnode,templatesubnode)) { |
---|
878 | #ifdef DEBUG2 |
---|
879 | fprintf(stderr,"attachsubsetr: match: %s :: %s\n",targetsubnode->ocname,templatesubnode->ocname); |
---|
880 | #endif |
---|
881 | ncstat = attachsubset34r(targetsubnode,templatesubnode); |
---|
882 | if(ncstat) goto done; |
---|
883 | fieldindex++; |
---|
884 | } |
---|
885 | } |
---|
886 | done: |
---|
887 | return THROW(ncstat); |
---|
888 | } |
---|
889 | |
---|
890 | static void |
---|
891 | getalldims34a(NClist* dimset, NClist* alldims) |
---|
892 | { |
---|
893 | int i; |
---|
894 | for(i=0;i<nclistlength(dimset);i++) { |
---|
895 | CDFnode* dim = (CDFnode*)nclistget(dimset,i); |
---|
896 | if(!nclistcontains(alldims,(ncelem)dim)) { |
---|
897 | #ifdef DEBUG3 |
---|
898 | fprintf(stderr,"getalldims: %s[%lu]\n", |
---|
899 | dim->ncfullname,(unsigned long)dim->dim.declsize); |
---|
900 | #endif |
---|
901 | nclistpush(alldims,(ncelem)dim); |
---|
902 | } |
---|
903 | } |
---|
904 | } |
---|
905 | |
---|
906 | /* Accumulate a set of all the known dimensions |
---|
907 | vis-a-vis defined variables |
---|
908 | */ |
---|
909 | NClist* |
---|
910 | getalldims34(NCDAPCOMMON* nccomm, int visibleonly) |
---|
911 | { |
---|
912 | int i; |
---|
913 | NClist* alldims = nclistnew(); |
---|
914 | NClist* varnodes = nccomm->cdf.varnodes; |
---|
915 | |
---|
916 | /* get bag of all dimensions */ |
---|
917 | for(i=0;i<nclistlength(varnodes);i++) { |
---|
918 | CDFnode* node = (CDFnode*)nclistget(varnodes,i); |
---|
919 | if(!visibleonly || node->visible) { |
---|
920 | getalldims34a(node->array.dimsetall,alldims); |
---|
921 | } |
---|
922 | } |
---|
923 | return alldims; |
---|
924 | } |
---|