source: XIOS/dev/dev_olga/extern/src_netcdf4/common34.c @ 1620

Last change on this file since 1620 was 409, checked in by ymipsl, 11 years ago

Add improved nectdf internal library src

YM

  • Property svn:eol-style set to native
File size: 27.9 KB
Line 
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
19extern CDFnode* v4node;
20
21/* Define the set of protocols known to be constrainable */
22static char* constrainableprotocols[] = {"http", "https",NULL};
23static NCerror buildcdftree34r(NCDAPCOMMON*,OCobject,CDFnode*,CDFtree*,CDFnode**);
24static void defdimensions(OCobject, CDFnode*, NCDAPCOMMON*, CDFtree*);
25static NCerror  attachsubset34r(CDFnode*, CDFnode*);
26static 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. */
34static NCerror
35fix1node34(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
50NCerror
51fixnodes34(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
63NCerror
64fixgrid34(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;
122invalid:
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
132static void
133computedimindexanon3(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 */
147static void
148replacedims(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 */
165static int
166equivalentdim(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*/
179NCerror
180computecdfdimnames34(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
225fprintf(stderr,"assign: %s/%s -> %s/%s\n",
226basedim->dim.array->ocname,basedim->ocname,
227dupdim->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
249fprintf(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
339for(i=0;i<nclistlength(basedims);i++) {
340CDFnode* dim = (CDFnode*)nclistget(basedims,i);
341fprintf(stderr,"basedim: %s=%ld\n",dim->ncfullname,(long)dim->dim.declsize);
342 }
343#endif
344
345    return NC_NOERR;
346}
347
348NCerror
349makegetvar34(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
366int
367constrainable34(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
377CDFnode*
378makecdfnode34(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*/
410NCerror
411buildcdftree34(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
430static NCerror
431buildcdftree34r(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
480static void
481defdimensions(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
514NCerror
515applyclientparams34(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
624void
625freecdfroot34(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*/ 
648static void
649free1cdfnode34(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*/
682int
683nodematch34(CDFnode* node1, CDFnode* node2)
684{
685    return simplenodematch34(node1,node2);
686}
687
688int
689simplenodematch34(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/*
713Given DDS node, locate the node
714in a DATADDS that matches the DDS node.
715Return NULL if no node found
716*/
717
718void
719unattach34(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
730static void
731setattach(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
745static NCerror
746attachdims34(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
754fprintf(stderr,"attachdim: %s->%s\n",xdim->ocname,tdim->ocname);
755#endif
756    }
757    return NC_NOERR;
758}
759
760/*
761Match a DATADDS node to a DDS node.
762It is assumed that both trees have been regridded if necessary.
763*/
764
765static NCerror
766attach34r(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
781fprintf(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    }
812done:
813    return THROW(ncstat);
814}
815
816NCerror
817attach34(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);
829done:
830    nclistfree(templatepath);
831    return ncstat;
832}
833
834/*
835Match nodes in template tree to nodes in target tree;
836template tree is typically a structural superset of target tree.
837WARNING: Dimensions are not attached
838*/
839
840NCerror
841attachsubset34(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
848fprintf(stderr,"attachsubset: target=%s\n",dumptree(target));
849fprintf(stderr,"attachsubset: template=%s\n",dumptree(template));
850#endif
851    ncstat = attachsubset34r(target,template);
852done:
853    return ncstat;
854}
855
856static NCerror
857attachsubset34r(CDFnode* target, CDFnode* template)
858{
859    unsigned int i;
860    NCerror ncstat = NC_NOERR;
861    int fieldindex;
862
863#ifdef DEBUG2
864fprintf(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
879fprintf(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    }
886done:
887    return THROW(ncstat);
888}
889
890static void
891getalldims34a(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
898fprintf(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*/
909NClist*
910getalldims34(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}
Note: See TracBrowser for help on using the repository browser.