1/*********************************************************************
2 *   Copyright 1993, UCAR/Unidata
3 *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
4 *********************************************************************/
5
6#include "ncdap.h"
7#include "ncd2dispatch.h"
8#include "dapalign.h"
9
10#ifdef _MSC_VER
11#include <crtdbg.h>
12#endif
13
14#define NCRCFILE "NCRCFILE"
15
16#ifdef HAVE_GETRLIMIT
17#  ifdef HAVE_SYS_RESOURCE_H
18#    include <sys/time.h>
19#  endif
20#  ifdef HAVE_SYS_RESOURCE_H
21#    include <sys/resource.h>
22#  endif
23#endif
24
25/* Define the set of protocols known to be constrainable */
26static char* constrainableprotocols[] = {"http", "https",NULL};
27
28static int ncd2initialized = 0;
29
30size_t dap_one[NC_MAX_VAR_DIMS];
31size_t dap_zero[NC_MAX_VAR_DIMS];
32
33/* Forward */
34static NCerror buildncstructures(NCDAPCOMMON*);
35static NCerror builddims(NCDAPCOMMON*);
36static char* getdefinename(CDFnodenode);
37static NCerror buildvars(NCDAPCOMMON*);
38static NCerror buildglobalattrs(NCDAPCOMMON*, CDFnoderoot);
39static NCerror buildattribute(NCDAPCOMMON*, NCattribute*, nc_type, int);
40static void computedimindexanon(CDFnodedimCDFnodevar);
41static void replacedims(NClistdims);
42static int equivalentdim(CDFnodebasedimCDFnodedupdim);
43static NCerror addstringdims(NCDAPCOMMON*);
44static NCerror defrecorddim(NCDAPCOMMON*);
45static NCerror defseqdims(NCDAPCOMMON*);
46static NCerror showprojection(NCDAPCOMMON*, CDFnodevar);
47static NCerror getseqdimsize(NCDAPCOMMON*, CDFnodeseq, size_t* sizep);
48static NCerror makeseqdim(NCDAPCOMMON*, CDFnodeseq, size_t countCDFnode** sqdimp);
49static NCerror countsequence(NCDAPCOMMON*, CDFnodexseq, size_t* sizep);
50static NCerror freeNCDAPCOMMON(NCDAPCOMMON*);
51static NCerror fetchpatternmetadata(NCDAPCOMMON*);
52static size_t fieldindex(CDFnodeparentCDFnodechild);
53static NCerror computeseqcountconstraints(NCDAPCOMMON*, CDFnode*, NCbytes*);
54static void computeseqcountconstraintsr(NCDAPCOMMON*, CDFnode*, CDFnode**);
55static void estimatevarsizes(NCDAPCOMMON*);
56static NCerror fetchconstrainedmetadata(NCDAPCOMMON*);
57static NCerror suppressunusablevars(NCDAPCOMMON*);
58static NCerror fixzerodims(NCDAPCOMMON*);
59static void applyclientparamcontrols(NCDAPCOMMON*);
60static NCerror applyclientparams(NCDAPCOMMON*);
61
62/**************************************************/
63
64static int
65NCD2_create(const char *path, int cmode,
66           size_t initialsz, int basepe, size_t *chunksizehintp,
67    int use_parallel, void* mpidata,
68           NC_Dispatch*,NCncp);
69
70static int NCD2_redef(int ncid);
71static int NCD2__enddef(int ncid, size_t h_minfree, size_t v_align, size_t v_minfree, size_t r_align);
72static int NCD2_sync(int ncid);
73static int NCD2_abort(int ncid);
74
75static int NCD2_put_vara(int ncid, int varid,
76     const size_t *start, const size_t *edges0,
77            const void *value0,
78     nc_type memtype);
79
80static int NCD2_get_vara(int ncid, int varid,
81     const size_t *start, const size_t *edges,
82            void *value,
83     nc_type memtype);
84
85static int NCD2_put_vars(int ncid, int varid,
86     const size_t *start, const size_t *edges, const ptrdiff_tstride,
87            const void *value0nc_type memtype);
88
89static int NCD2_get_vars(int ncid, int varid,
90     const size_t *start, const size_t *edges, const ptrdiff_tstride,
91            void *valuenc_type memtype);
92
93static NC_Dispatch NCD2_dispatch_base = {
94
95NC_FORMATX_DAP2,
96
97NCD2_create,
98NCD2_open,
99
100NCD2_redef,
101NCD2__enddef,
102NCD2_sync,
103NCD2_abort,
104NCD2_close,
105NCD2_set_fill,
106NCD2_inq_base_pe,
107NCD2_set_base_pe,
108NCD2_inq_format,
109NCD2_inq_format_extended, /*inq_format_extended*/
110
111NCD2_inq,
112NCD2_inq_type,
113
114NCD2_def_dim,
115NCD2_inq_dimid,
116NCD2_inq_dim,
117NCD2_inq_unlimdim,
118NCD2_rename_dim,
119
120NCD2_inq_att,
121NCD2_inq_attid,
122NCD2_inq_attname,
123NCD2_rename_att,
124NCD2_del_att,
125NCD2_get_att,
126NCD2_put_att,
127
128NCD2_def_var,
129NCD2_inq_varid,
130NCD2_rename_var,
131NCD2_get_vara,
132NCD2_put_vara,
133NCD2_get_vars,
134NCD2_put_vars,
135NCDEFAULT_get_varm,
136NCDEFAULT_put_varm,
137
138NCD2_inq_var_all,
139
140NCD2_var_par_access,
141
142#ifdef USE_NETCDF4
143NCD2_show_metadata,
144NCD2_inq_unlimdims,
145NCD2_inq_ncid,
146NCD2_inq_grps,
147NCD2_inq_grpname,
148NCD2_inq_grpname_full,
149NCD2_inq_grp_parent,
150NCD2_inq_grp_full_ncid,
151NCD2_inq_varids,
152NCD2_inq_dimids,
153NCD2_inq_typeids,
154NCD2_inq_type_equal,
155NCD2_def_grp,
156NCD2_rename_grp,
157NCD2_inq_user_type,
158NCD2_inq_typeid,
159
160NCD2_def_compound,
161NCD2_insert_compound,
162NCD2_insert_array_compound,
163NCD2_inq_compound_field,
164NCD2_inq_compound_fieldindex,
165NCD2_def_vlen,
166NCD2_put_vlen_element,
167NCD2_get_vlen_element,
168NCD2_def_enum,
169NCD2_insert_enum,
170NCD2_inq_enum_member,
171NCD2_inq_enum_ident,
172NCD2_def_opaque,
173NCD2_def_var_deflate,
174NCD2_def_var_fletcher32,
175NCD2_def_var_chunking,
176NCD2_def_var_fill,
177NCD2_def_var_endian,
178NCD2_set_var_chunk_cache,
179NCD2_get_var_chunk_cache,
180
181#endif /*USE_NETCDF4*/
182
183};
184
185NC_DispatchNCD2_dispatch_table = NULL; /* moved here from ddispatch.c */
186
187static NC_Dispatch NCD2_dispatcher;
188
189int
190NCD2_initialize(void)
191{
192    int i;
193
194    NCD2_dispatch_table = &NCD2_dispatch_base;
195    /* Local Initialization */
196    compute_nccalignments();
197    for(i=0;i<NC_MAX_VAR_DIMS;i++) {
198 dap_one[i] = 1;
199 dap_zero[i] = 0;
200    }
201    ncd2initialized = 1;
202#ifdef DEBUG
203    /* force logging to go to stderr */
204    nclogclose();
205    if(nclogopen(NULL))
206        ncsetlogging(1); /* turn it on */
207#endif
208    /* Look at env vars for rc file location */
209    if(getenv(NCRCFILE) != NULL) {
210 const char* ncrcfile = getenv(NCRCFILE);
211 if(oc_set_rcfile(ncrcfile) != OC_NOERR)
212     return NC_EAUTH;
213    }
214    return NC_NOERR;
215}
216
217int
218NCD2_finalize(void)
219{
220    return NC_NOERR;
221}
222
223static int
224NCD2_redef(int ncid)
225{
226    return (NC_EPERM);
227}
228
229static int
230NCD2__enddef(int ncid, size_t h_minfree, size_t v_align, size_t v_minfree, size_t r_align)
231{
232    return (NC_EPERM);
233}
234
235static int
236NCD2_sync(int ncid)
237{
238    return (NC_EINVAL);
239}
240
241static int
242NCD2_abort(int ncid)
243{
244    return NCD2_close(ncid);
245}
246
247static int
248NCD2_create(const char *path, int cmode,
249           size_t initialsz, int basepe, size_t *chunksizehintp,
250    int use_parallel, void* mpidata,
251           NC_DispatchdispatchNCncp)
252{
253   return NC_EPERM;
254}
255
256static int
257NCD2_put_vara(int ncid, int varid,
258     const size_t *start, const size_t *edges,
259            const void *value,
260     nc_type memtype)
261{
262    return NC_EPERM;
263}
264
265static int
266NCD2_get_vara(int ncid, int varid,
267     const size_t *start, const size_t *edges,
268            void *value,
269     nc_type memtype)
270{
271    int stat = nc3d_getvarx(ncidvaridstartedgesnc_ptrdiffvector1value,memtype);
272    return stat;
273}
274
275static int
276NCD2_put_vars(int ncid, int varid,
277     const size_t *start, const size_t *edges, const ptrdiff_tstride,
278            const void *value0nc_type memtype)
279{
280    return NC_EPERM;
281}
282
283static int
284NCD2_get_vars(int ncid, int varid,
285     const size_t *start, const size_t *edges, const ptrdiff_tstride,
286            void *valuenc_type memtype)
287{
288    int stat = nc3d_getvarx(ncidvaridstartedgesstridevaluememtype);
289    return stat;
290}
291
292/* See ncd2dispatch.c for other version */
293int
294NCD2_open(const char * path, int mode,
295               int basepe, size_t *chunksizehintp,
296         int useparallel, void* mpidata,
297               NC_DispatchdispatchNCdrno)
298{
299    NCerror ncstat = NC_NOERR;
300    OCerror ocstat = OC_NOERR;
301    NCDAPCOMMONdapcomm = NULL;
302    const char* value;
303    int nc3id = -1;
304
305    if(path == NULL)
306 return NC_EDAPURL;
307    if(dispatch == NULLPANIC("NC3D_open: no dispatch table");
308
309    /* Setup our NC and NCDAPCOMMON state*/
310
311    dapcomm = (NCDAPCOMMON*)calloc(1,sizeof(NCDAPCOMMON));
312    if(dapcomm == NULL) {ncstat = NC_ENOMEM; goto done;}
313
314    NCD2_DATA_SET(drno,dapcomm);
315    drno->int_ncid = nc__pseudofd(); /* create a unique id */
316    dapcomm->controller = (NC*)drno;
317
318    dapcomm->cdf.separator = ".";
319    dapcomm->cdf.smallsizelimit = DFALTSMALLLIMIT;
320    dapcomm->cdf.cache = createnccache();
321
322#ifdef HAVE_GETRLIMIT
323    { struct rlimit rl;
324      if(getrlimit(RLIMIT_NOFILE, &rl) >= 0) {
325 dapcomm->cdf.cache->cachecount = (size_t)(rl.rlim_cur / 2);
326      }
327    }
328#endif
329
330#ifdef OCCOMPILEBYDEFAULT
331    /* set the compile flag by default */
332    dapcomm->oc.rawurltext = (char*)emalloc(strlen(path)+strlen("[compile]")+1);
333    strcpy(dapcomm->oc.rawurltext,"[compile]");
334    strcat(dapcomm->oc.rawurltextpath);
335#else
336    dapcomm->oc.rawurltext = strdup(path);
337#endif
338
339    ncuriparse(dapcomm->oc.rawurltext,&dapcomm->oc.url);
340
341    /* parse the client parameters */
342    ncuridecodeparams(dapcomm->oc.url);
343
344    if(!constrainable(dapcomm->oc.url))
345 SETFLAG(dapcomm->controls,NCF_UNCONSTRAINABLE);
346
347#ifdef COLUMBIA_HACK
348    {
349 const char* p;
350 /* Does this url look like it is from columbia? */
351 if(dapcomm->oc.url->host != NULL) {
352     for(p=dapcomm->oc.url->host;*p;p++) {
353         if(strncmp(p,COLUMBIA_HACK,strlen(COLUMBIA_HACK))==0)
354     SETFLAG(dapcomm->controls,NCF_COLUMBIA);
355     }
356 }
357    }
358#endif
359
360    /* fail if we are unconstrainable but have constraints */
361    if(FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE)) {
362 if(dapcomm->oc.url->constraint != NULL) {
363     nclog(NCLOGWARN,"Attempt to constrain an unconstrainable data source: %s",
364    dapcomm->oc.url->constraint);
365     ncstat = THROW(NC_EDAPCONSTRAINT);
366     goto done;
367 }
368    }
369
370    /* Use libsrc code (netcdf-3) for storing metadata */
371    {
372 char tmpname[32];
373
374        /* Create fake file name: exact name must be unique,
375           but is otherwise irrelevant because we are using NC_DISKLESS
376        */
377        snprintf(tmpname,sizeof(tmpname),"%d",drno->int_ncid);
378
379        /* Now, use the file to create the hidden, in-memory netcdf file.
380    We want this hidden file to always be NC_CLASSIC, so we need to
381           force default format temporarily in case user changed it.
382 */
383 {
384     int new = NC_CLASSIC_MODEL;
385     int old = 0;
386     nc_set_default_format(new,&old); /* save and change */
387            ncstat = nc_create(tmpname,NC_DISKLESS|NC_CLASSIC_MODEL,&nc3id);
388     nc_set_default_format(old,&new); /* restore */
389 }
390        if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
391 dapcomm->nc3id = nc3id;
392 /* Avoid fill */
393 nc_set_fill(nc3id,NC_NOFILL,NULL);
394
395    }
396
397    dapcomm->oc.dapconstraint = (DCEconstraint*)dcecreate(CES_CONSTRAINT);
398    dapcomm->oc.dapconstraint->projections = nclistnew();
399    dapcomm->oc.dapconstraint->selections = nclistnew();
400
401     /* Parse constraints to make sure they are syntactically correct */
402     ncstat = dapparsedapconstraints(dapcomm,dapcomm->oc.url->constraint,dapcomm->oc.dapconstraint);
403     if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
404
405    /* Construct a url for oc minus any constraint and params*/
406    dapcomm->oc.urltext = ncuribuild(dapcomm->oc.url,NULL,NULL,
407       (NCURISTD ^ NCURICONSTRAINTS));
408
409    /* Pass to OC */
410    ocstat = oc_open(dapcomm->oc.urltext,&dapcomm->oc.conn);
411    if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;}
412
413#ifdef DEBUG1
414    (void)oc_trace_curl(dapcomm->oc.conn);
415#endif
416
417    nullfree(dapcomm->oc.urltext); /* clean up */
418    dapcomm->oc.urltext = NULL;
419
420    /* process control client parameters */
421    applyclientparamcontrols(dapcomm);
422
423    /* Turn on logging; only do this after oc_open*/
424    if((value = dapparamvalue(dapcomm,"log")) != NULL) {
425 ncloginit();
426        if(nclogopen(value))
427     ncsetlogging(1);
428 ncloginit();
429        if(nclogopen(value))
430     ncsetlogging(1);
431    }
432
433    /* fetch and build the unconstrained DDS for use as
434       pattern */
435    ncstat = fetchpatternmetadata(dapcomm);
436    if(ncstat != NC_NOERR) goto done;
437
438    /* Operations on the pattern tree */
439
440    /* Accumulate useful nodes sets  */
441    ncstat = computecdfnodesets(dapcomm,dapcomm->cdf.fullddsroot->tree);
442    if(ncstat) {THROWCHK(ncstat); goto done;}
443
444    /* Define the dimsettrans list */
445    ncstat = definedimsettrans(dapcomm,dapcomm->cdf.fullddsroot->tree);
446    if(ncstat) {THROWCHK(ncstat); goto done;}
447
448    /* Mark the nodes of the pattern that are eligible for prefetch */
449    ncstat = markprefetch(dapcomm);
450
451    /* fetch and build the constrained DDS */
452    ncstat = fetchconstrainedmetadata(dapcomm);
453    if(ncstat != NC_NOERR) goto done;
454
455#ifdef DEBUG2
456fprintf(stderr,"constrained dds: %s\n",dumptree(dapcomm->cdf.ddsroot));
457#endif
458
459    /* Operations on the constrained tree */
460
461    /* Accumulate useful nodes sets  */
462    ncstat = computecdfnodesets(dapcomm,dapcomm->cdf.ddsroot->tree);
463    if(ncstat) {THROWCHK(ncstat); goto done;}
464
465    /* Fix grids */
466    ncstat = fixgrids(dapcomm);
467    if(ncstat) {THROWCHK(ncstat); goto done;}
468
469    /* Locate and mark usable sequences */
470    ncstat = sequencecheck(dapcomm);
471    if(ncstat) {THROWCHK(ncstat); goto done;}
472
473    /* suppress variables not in usable sequences */
474    ncstat = suppressunusablevars(dapcomm);
475    if(ncstat) {THROWCHK(ncstat); goto done;}
476
477    /* apply client parameters */
478    ncstat = applyclientparams(dapcomm);
479    if(ncstat) {THROWCHK(ncstat); goto done;}
480
481    /* Add (as needed) string dimensions*/
482    ncstat = addstringdims(dapcomm);
483    if(ncstat) {THROWCHK(ncstat); goto done;}
484
485    if(nclistlength(dapcomm->cdf.ddsroot->tree->seqnodes) > 0) {
486 /* Build the sequence related dimensions */
487        ncstat = defseqdims(dapcomm);
488        if(ncstat) {THROWCHK(ncstat); goto done;}
489    }
490
491    /* Define the dimsetplus and dimsetall lists */
492    ncstat = definedimsets(dapcomm,dapcomm->cdf.ddsroot->tree);
493    if(ncstat) {THROWCHK(ncstat); goto done;}
494
495    /* Re-compute the dimension names*/
496    ncstat = computecdfdimnames(dapcomm);
497    if(ncstat) {THROWCHK(ncstat); goto done;}
498
499    /* Deal with zero size dimensions */
500    ncstat = fixzerodims(dapcomm);
501    if(ncstat) {THROWCHK(ncstat); goto done;}
502
503    /* Attempt to use the DODS_EXTRA info to turn
504       one of the dimensions into unlimited.
505       Assume computecdfdimnames34 has already been called.
506    */
507    ncstat = defrecorddim(dapcomm);
508    if(ncstat) {THROWCHK(ncstat); goto done;}
509    if(dapcomm->cdf.recorddimname != NULL
510       && nclistlength(dapcomm->cdf.ddsroot->tree->seqnodes) > 0) {
511 /*nclog(NCLOGWARN,"unlimited dimension specified, but sequences exist in DDS");*/
512 PANIC("unlimited dimension specified, but sequences exist in DDS");
513    }
514
515    /* Re-compute the var names*/
516    ncstat = computecdfvarnames(dapcomm,
517  dapcomm->cdf.ddsroot,
518  dapcomm->cdf.ddsroot->tree->varnodes);
519    if(ncstat) {THROWCHK(ncstat); goto done;}
520
521    /* Transfer data from the unconstrained DDS data to the unconstrained DDS */
522    ncstat = dimimprint(dapcomm);
523    if(ncstat) goto done;
524
525    /* Process the constraints to map to the constrained CDF tree */
526    /* (must follow fixgrids3) */
527    ncstat = dapmapconstraints(dapcomm->oc.dapconstraint,dapcomm->cdf.ddsroot);
528    if(ncstat != NC_NOERR) goto done;
529
530    /* Canonicalize the constraint */
531    ncstat = dapfixprojections(dapcomm->oc.dapconstraint->projections);
532    if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
533
534    /* Fill in segment information */
535    ncstat = dapqualifyconstraints(dapcomm->oc.dapconstraint);
536    if(ncstat != NC_NOERR) goto done;
537
538    /* Accumulate set of variables in the constraint's projections */
539    ncstat = dapcomputeprojectedvars(dapcomm,dapcomm->oc.dapconstraint);
540    if(ncstat) {THROWCHK(ncstat); goto done;}
541
542    /* using the modified constraint, rebuild the constraint string */
543    if(FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE)) {
544 /* ignore all constraints */
545 dapcomm->oc.urltext = ncuribuild(dapcomm->oc.url,NULL,NULL,0);
546    } else {
547 char* constraintstring = dcebuildconstraintstring(dapcomm->oc.dapconstraint);
548        ncurisetconstraints(dapcomm->oc.url,constraintstring);
549 nullfree(constraintstring);
550        dapcomm->oc.urltext = ncuribuild(dapcomm->oc.url,NULL,NULL,NCURICONSTRAINTS);
551    }
552
553#ifdef DEBUG
554fprintf(stderr,"ncdap3: final constraint: %s\n",dapcomm->oc.url->constraint);
555#endif
556
557    /* Estimate the variable sizes */
558    estimatevarsizes(dapcomm);
559
560    /* Build the meta data */
561    ncstat = buildncstructures(dapcomm);
562    if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
563
564    /* Explicitly do not call enddef because it will complain
565       about variables that are too large.
566    */
567#if 0
568    ncstat = nc_endef(nc3id,NC_NOFILL,NULL);
569    if(ncstat != NC_NOERR && ncstat != NC_EVARSIZE)
570        {THROWCHK(ncstat); goto done;}
571#endif
572
573    { /* (for now) break abstractions*/
574     NCncsub;
575     NC3_INFOnc3i;
576     CDFnodeunlimited = dapcomm->cdf.recorddim;
577            /* get the dispatch data for the substrate */
578            ncstat = NC_check_id(nc3id,&ncsub);
579     if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
580     nc3i = (NC3_INFO*)ncsub->dispatchdata;
581     /* This must be checked after all dds and data processing
582               so we can figure out the value of numrecs.
583     */
584            if(unlimited != NULL) { /* Set the effective size of UNLIMITED */
585                NC_set_numrecs(nc3i,unlimited->dim.declsize);
586     }
587            /* Pretend the substrate is read-only */
588     NC_set_readonly(nc3i);
589    }
590
591    /* Do any necessary data prefetch */
592    if(FLAGSET(dapcomm->controls,NCF_PREFETCH)
593       && FLAGSET(dapcomm->controls,NCF_PREFETCH_EAGER)) {
594        ncstat = prefetchdata(dapcomm);
595        if(ncstat != NC_NOERR) {
596            del_from_NCList((NC*)drno); /* undefine here */
597     {THROWCHK(ncstat); goto done;}
598 }
599    }
600
601    return ncstat;
602
603done:
604    if(drno != NULLNCD2_close(drno->ext_ncid);
605    if(ocstat != OC_NOERRncstat = ocerrtoncerr(ocstat);
606    return THROW(ncstat);
607}
608
609int
610NCD2_close(int ncid)
611{
612    NCdrno;
613    NCDAPCOMMONdapcomm;
614    int ncstatus = NC_NOERR;
615
616    ncstatus = NC_check_id(ncid, (NC**)&drno);
617    if(ncstatus != NC_NOERR) return THROW(ncstatus);
618    dapcomm = (NCDAPCOMMON*)drno->dispatchdata;
619
620    /* We call abort rather than close to avoid
621       trying to write anything or try to pad file length
622     */
623    ncstatus = nc_abort(getnc3id(drno));
624
625    /* clean NC* */
626    freeNCDAPCOMMON(dapcomm);
627
628    return THROW(ncstatus);
629}
630
631/**************************************************/
632
633static NCerror
634buildncstructures(NCDAPCOMMONdapcomm)
635{
636    NCerror ncstat = NC_NOERR;
637    CDFnodedds = dapcomm->cdf.ddsroot;
638    NCncsub;
639
640    ncstat = buildglobalattrs(dapcomm,dds);
641    if(ncstat != NC_NOERR) goto done;
642
643    ncstat = builddims(dapcomm);
644    if(ncstat != NC_NOERR) goto done;
645
646    ncstat = buildvars(dapcomm);
647    if(ncstat != NC_NOERR) goto done;
648
649done:
650    return THROW(ncstat);
651}
652
653static NCerror
654builddims(NCDAPCOMMONdapcomm)
655{
656    int i;
657    NCerror ncstat = NC_NOERR;
658    int dimid;
659    NClistdimset = NULL;
660    NCdrno = dapcomm->controller;
661    NCncsub;
662    char* definename;
663
664    /* collect all dimensions from variables */
665    dimset = dapcomm->cdf.ddsroot->tree->dimnodes;
666
667    /* Sort by fullname just for the fun of it */
668    for(;;) {
669 int last = nclistlength(dimset) - 1;
670 int swap = 0;
671        for(i=0;i<last;i++) {
672     CDFnodedim1 = (CDFnode*)nclistget(dimset,i);
673     CDFnodedim2 = (CDFnode*)nclistget(dimset,i+1);
674        if(strcmp(dim1->ncfullname,dim2->ncfullname) > 0) {
675 nclistset(dimset,i,(void*)dim2);
676 nclistset(dimset,i+1,(void*)dim1);
677 swap = 1;
678 break;
679     }
680 }
681 if(!swap) break;
682    }
683
684    /* Define unlimited only if needed */
685    if(dapcomm->cdf.recorddim != NULL) {
686 CDFnodeunlimited = dapcomm->cdf.recorddim;
687 definename = getdefinename(unlimited);
688        ncstat = nc_def_dim(dapcomm->nc3id,
689 definename,
690 NC_UNLIMITED,
691 &unlimited->ncid);
692 nullfree(definename);
693        if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
694
695        /* get the id for the substrate */
696        ncstat = NC_check_id(dapcomm->nc3id,&ncsub);
697        if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
698#if 0
699 nc3sub = (NC3_INFO*)&ncsub->dispatchdata;
700        /* Set the effective size of UNLIMITED;
701           note that this cannot easily be done thru the normal API.*/
702        NC_set_numrecs(nc3sub,unlimited->dim.declsize);
703#endif
704
705    }
706
707    for(i=0;i<nclistlength(dimset);i++) {
708 CDFnodedim = (CDFnode*)nclistget(dimset,i);
709        if(dim->dim.basedim != NULL) continue; /* handle below */
710 if(DIMFLAG(dim,CDFDIMRECORD)) continue; /* defined above */
711#ifdef DEBUG1
712fprintf(stderr,"define: dim: %s=%ld\n",dim->ncfullname,(long)dim->dim.declsize);
713#endif
714 definename = getdefinename(dim);
715        ncstat = nc_def_dim(dapcomm->nc3id,definename,dim->dim.declsize,&dimid);
716        if(ncstat != NC_NOERR) {
717          THROWCHK(ncstat); nullfree(definename); goto done;
718 }
719 nullfree(definename);
720        dim->ncid = dimid;
721    }
722
723    /* Make all duplicate dims have same dimid as basedim*/
724    /* (see computecdfdimnames)*/
725    for(i=0;i<nclistlength(dimset);i++) {
726 CDFnodedim = (CDFnode*)nclistget(dimset,i);
727        if(dim->dim.basedim != NULL) {
728     dim->ncid = dim->dim.basedim->ncid;
729 }
730    }
731done:
732    nclistfree(dimset);
733    return THROW(ncstat);
734}
735
736/* Simultaneously build any associated attributes*/
737/* and any necessary pseudo-dimensions for string types*/
738static NCerror
739buildvars(NCDAPCOMMONdapcomm)
740{
741    int i,j;
742    NCerror ncstat = NC_NOERR;
743    int varid;
744    NClistvarnodes = dapcomm->cdf.ddsroot->tree->varnodes;
745    NCdrno = dapcomm->controller;
746    char* definename;
747
748    ASSERT((varnodes != NULL));
749    for(i=0;i<nclistlength(varnodes);i++) {
750 CDFnodevar = (CDFnode*)nclistget(varnodes,i);
751        int dimids[NC_MAX_VAR_DIMS];
752 unsigned int ncrank;
753        NClistvardims = NULL;
754
755 if(var->invisible) continue;
756 if(var->array.basevar != NULL) continue;
757
758#ifdef DEBUG1
759fprintf(stderr,"buildvars.candidate=|%s|\n",var->ncfullname);
760#endif
761
762 vardims = var->array.dimsetall;
763 ncrank = nclistlength(vardims);
764 if(ncrank > 0) {
765            for(j=0;j<ncrank;j++) {
766                CDFnodedim = (CDFnode*)nclistget(vardims,j);
767                dimids[j] = dim->ncid;
768      }
769        }
770
771
772
773 definename = getdefinename(var);
774
775#ifdef DEBUG1
776fprintf(stderr,"define: var: %s/%s",
777 definename,var->ocname);
778if(ncrank > 0) {
779int k;
780for(k=0;k<ncrank;k++) {
781CDFnodedim = (CDFnode*)nclistget(vardims,k);
782fprintf(stderr,"[%ld]",dim->dim.declsize);
783 }
784 }
785fprintf(stderr,"\n");
786#endif
787        ncstat = nc_def_var(dapcomm->nc3id,
788         definename,
789                        var->externaltype,
790                        ncrank,
791                        (ncrank==0?NULL:dimids),
792                        &varid);
793 nullfree(definename);
794        if(ncstat != NC_NOERR) {
795     THROWCHK(ncstat);
796     goto done;
797 }
798        var->ncid = varid;
799 if(var->attributes != NULL) {
800     for(j=0;j<nclistlength(var->attributes);j++) {
801 NCattributeatt = (NCattribute*)nclistget(var->attributes,j);
802 ncstat = buildattribute(dapcomm,att,var->etype,varid);
803         if(ncstat != NC_NOERR) goto done;
804     }
805 }
806 /* Tag the variable with its DAP path */
807 if(dapparamcheck(dapcomm,"show","projection"))
808     showprojection(dapcomm,var);
809    }
810done:
811    return THROW(ncstat);
812}
813
814static NCerror
815buildglobalattrs(NCDAPCOMMONdapcommCDFnoderoot)
816{
817    int i;
818    NCerror ncstat = NC_NOERR;
819    const char* txt;
820    char *nltxt, *p;
821    NCbytesbuf = NULL;
822    NClistcdfnodes;
823    NCdrno = dapcomm->controller;
824
825    if(root->attributes != NULL) {
826        for(i=0;i<nclistlength(root->attributes);i++) {
827        NCattributeatt = (NCattribute*)nclistget(root->attributes,i);
828     ncstat = buildattribute(dapcomm,att,NC_NAT,NC_GLOBAL);
829            if(ncstat != NC_NOERR) goto done;
830 }
831    }
832
833    /* Add global attribute identifying the sequence dimensions */
834    if(dapparamcheck(dapcomm,"show","seqdims")) {
835        buf = ncbytesnew();
836        cdfnodes = dapcomm->cdf.ddsroot->tree->nodes;
837        for(i=0;i<nclistlength(cdfnodes);i++) {
838     CDFnodedim = (CDFnode*)nclistget(cdfnodes,i);
839     if(dim->nctype != NC_Dimension) continue;
840     if(DIMFLAG(dim,CDFDIMSEQ)) {
841         char* cname = cdflegalname(dim->ocname);
842         if(ncbyteslength(buf) > 0) ncbytescat(buf,", ");
843         ncbytescat(buf,cname);
844         nullfree(cname);
845     }
846 }
847        if(ncbyteslength(buf) > 0) {
848            ncstat = nc_put_att_text(dapcomm->nc3id,NC_GLOBAL,"_sequence_dimensions",
849            ncbyteslength(buf),ncbytescontents(buf));
850 }
851    }
852
853    /* Define some additional system global attributes
854       depending on show= clientparams*/
855    /* Ignore failures*/
856
857    if(dapparamcheck(dapcomm,"show","translate")) {
858        /* Add a global attribute to show the translation */
859        ncstat = nc_put_att_text(dapcomm->nc3id,NC_GLOBAL,"_translate",
860            strlen("netcdf-3"),"netcdf-3");
861    }
862    if(dapparamcheck(dapcomm,"show","url")) {
863 if(dapcomm->oc.rawurltext != NULL)
864            ncstat = nc_put_att_text(dapcomm->nc3id,NC_GLOBAL,"_url",
865        strlen(dapcomm->oc.rawurltext),dapcomm->oc.rawurltext);
866    }
867    if(dapparamcheck(dapcomm,"show","dds")) {
868 txt = NULL;
869 if(dapcomm->cdf.ddsroot != NULL)
870       txt = oc_tree_text(dapcomm->oc.conn,dapcomm->cdf.ddsroot->ocnode);
871 if(txt != NULL) {
872     /* replace newlines with spaces*/
873     nltxt = nulldup(txt);
874     for(p=nltxt;*p;p++) {if(*p == '\n' || *p == '\r' || *p == '\t') {*p = ' ';}};
875            ncstat = nc_put_att_text(dapcomm->nc3id,NC_GLOBAL,"_dds",strlen(nltxt),nltxt);
876     nullfree(nltxt);
877 }
878    }
879    if(dapparamcheck(dapcomm,"show","das")) {
880 txt = NULL;
881 if(dapcomm->oc.ocdasroot != NULL)
882     txt = oc_tree_text(dapcomm->oc.conn,dapcomm->oc.ocdasroot);
883 if(txt != NULL) {
884     nltxt = nulldup(txt);
885     for(p=nltxt;*p;p++) {if(*p == '\n' || *p == '\r' || *p == '\t') {*p = ' ';}};
886            ncstat = nc_put_att_text(dapcomm->nc3id,NC_GLOBAL,"_das",strlen(nltxt),nltxt);
887     nullfree(nltxt);
888 }
889    }
890
891done:
892    ncbytesfree(buf);
893    return THROW(ncstat);
894}
895
896static NCerror
897buildattribute(NCDAPCOMMONdapcommNCattributeattnc_type vartype, int varid)
898{
899    int i;
900    NCerror ncstat = NC_NOERR;
901    unsigned int nvalues = nclistlength(att->values);
902    NCdrno = dapcomm->controller;
903
904    /* If the type of the attribute is string, then we need*/
905    /* to convert to a single character string by concatenation.
906 modified: 10/23/09 to insert newlines.
907 modified: 10/28/09 to interpret escapes
908    */
909    if(att->etype == NC_STRING || att->etype == NC_URL) {
910 char* newstring = NULL;
911 size_t newlen = 0;
912 for(i=0;i<nvalues;i++) {
913     char* s = (char*)nclistget(att->values,i);
914     newlen += (1+strlen(s));
915 }
916    if(newlen > 0)
917      newstring = (char*)malloc(newlen);
918
919    MEMCHECK(newstring,NC_ENOMEM);
920 newstring[0] = '\0';
921 for(i=0;i<nvalues;i++) {
922     char* s = (char*)nclistget(att->values,i);
923     if(i > 0) strcat(newstring,"\n");
924     strcat(newstring,s);
925 }
926        dapexpandescapes(newstring);
927 if(newstring[0]=='\0')
928     ncstat = nc_put_att_text(dapcomm->nc3id,varid,att->name,1,newstring);
929 else
930     ncstat = nc_put_att_text(dapcomm->nc3id,varid,att->name,strlen(newstring),newstring);
931 free(newstring);
932        if(ncstat) goto done;
933    } else {
934 nc_type atype;
935 unsigned int typesize;
936 void* mem = NULL;
937 /* It turns out that some servers upgrade the type
938           of _FillValue in order to correctly preserve the
939           original value. However, since the type of the
940           underlying variable is not changes, we get a type
941           mismatch. So, make sure the type of the fillvalue
942           is the same as that of the controlling variable.
943 */
944        if(varid != NC_GLOBAL && strcmp(att->name,"_FillValue")==0)
945     atype = nctypeconvert(dapcomm,vartype);
946 else
947     atype = nctypeconvert(dapcomm,att->etype);
948 typesize = nctypesizeof(atype);
949 if (nvalues > 0) {
950 mem = malloc(typesize * nvalues);
951#ifdef _MSC_VER
952 _ASSERTE(_CrtCheckMemory());
953#endif
954 }
955    ncstat = dapcvtattrval(atype,mem,att->values);
956#ifdef _MSC_VER
957 _ASSERTE(_CrtCheckMemory());
958#endif
959    if(ncstat) {nullfree(mem); goto done;}
960    ncstat = nc_put_att(dapcomm->nc3id,varid,att->name,atype,nvalues,mem);
961#ifdef _MSC_VER
962 _ASSERTE(_CrtCheckMemory());
963#endif
964    if(ncstat) {nullfree(mem); goto done;}
965    }
966done:
967    return THROW(ncstat);
968}
969
970static char*
971getdefinename(CDFnodenode)
972{
973    char* spath = NULL;
974    NClistpath = NULL;
975
976    switch (node->nctype) {
977    case NC_Atomic:
978 /* The define name is same as the fullname with elided nodes */
979 path = nclistnew();
980        collectnodepath(node,path,!WITHDATASET);
981        spath = makepathstring(path,".",PATHNC|PATHELIDE);
982        nclistfree(path);
983 break;
984
985    case NC_Dimension:
986 /* Return just the node's ncname */
987 spath = nulldup(node->ncbasename);
988 break;
989
990    default:
991 PANIC("unexpected nctype");
992    }
993    return spath;
994}
995
996int
997NCDAP_ping(const char* url)
998{
999    OCerror ocstat = OC_NOERR;
1000    ocstat = oc_ping(url);
1001    return ocerrtoncerr(ocstat);
1002}
1003
1004int
1005NCD2_inq_format_extended(int ncid, int* formatp, int* modep)
1006{
1007    NCnc;
1008    int ncstatus = NC_check_id(ncid, (NC**)&nc);
1009    if(ncstatus != NC_NOERR) return THROW(ncstatus);
1010    if(modep) *modep = nc->mode;
1011    if(formatp) *formatp = NC_FORMATX_DAP2;
1012    return NC_NOERR;
1013}
1014
1015/**************************************************/
1016/* Support functions */
1017
1018/*
1019   Provide short and/or unified names for dimensions.
1020   This must mimic lib-ncdap, which is difficult.
1021*/
1022NCerror
1023computecdfdimnames(NCDAPCOMMONnccomm)
1024{
1025    int i,j;
1026    char tmp[NC_MAX_NAME*2];
1027    NClistconflicts = nclistnew();
1028    NClistvarnodes = nccomm->cdf.ddsroot->tree->varnodes;
1029    NClistalldims;
1030    NClistbasedims;
1031
1032    /* Collect all dimension nodes from dimsetall lists */
1033
1034    alldims = getalldims(nccomm,0);
1035
1036    /* Assign an index to all anonymous dimensions
1037       vis-a-vis its containing variable
1038    */
1039    for(i=0;i<nclistlength(varnodes);i++) {
1040 CDFnodevar = (CDFnode*)nclistget(varnodes,i);
1041        for(j=0;j<nclistlength(var->array.dimsetall);j++) {
1042     CDFnodedim = (CDFnode*)nclistget(var->array.dimsetall,j);
1043     if(dim->ocname != NULL) continue; /* not anonymous */
1044      computedimindexanon(dim,var);
1045 }
1046    }
1047
1048    /* Unify dimensions by defining one dimension as the "base"
1049       dimension, and make all "equivalent" dimensions point to the
1050       base dimension.
1051 1. Equivalent means: same size and both have identical non-null names.
1052 2. Dims with same name but different sizes will be handled separately
1053    */
1054    for(i=0;i<nclistlength(alldims);i++) {
1055 CDFnodedupdim = NULL;
1056 CDFnodebasedim = (CDFnode*)nclistget(alldims,i);
1057 if(basedim == NULL) continue;
1058 if(basedim->dim.basedim != NULL) continue; /* already processed*/
1059 for(j=i+1;j<nclistlength(alldims);j++) { /* Sigh, n**2 */
1060     dupdim = (CDFnode*)nclistget(alldims,j);
1061     if(basedim == dupdim) continue;
1062     if(dupdim == NULL) continue;
1063     if(dupdim->dim.basedim != NULL) continue; /* already processed */
1064     if(!equivalentdim(basedim,dupdim))
1065 continue;
1066            dupdim->dim.basedim = basedim; /* equate */
1067#ifdef DEBUG1
1068fprintf(stderr,"assign: %s/%s -> %s/%s\n",
1069basedim->dim.array->ocname,basedim->ocname,
1070dupdim->dim.array->ocname,dupdim->ocname
1071);
1072#endif
1073 }
1074    }
1075
1076    /* Next case: same name and different sizes*/
1077    /* => rename second dim */
1078
1079    for(i=0;i<nclistlength(alldims);i++) {
1080 CDFnodebasedim = (CDFnode*)nclistget(alldims,i);
1081 if(basedim->dim.basedim != NULL) continue;
1082 /* Collect all conflicting dimensions */
1083 nclistclear(conflicts);
1084        for(j=i+1;j<nclistlength(alldims);j++) {
1085     CDFnodedim = (CDFnode*)nclistget(alldims,j);
1086     if(dim->dim.basedim != NULL) continue;
1087     if(dim->ocname == NULL && basedim->ocname == NULL) continue;
1088     if(dim->ocname == NULL || basedim->ocname == NULL) continue;
1089     if(strcmp(dim->ocname,basedim->ocname)!=0) continue;
1090     if(dim->dim.declsize == basedim->dim.declsize) continue;
1091#ifdef DEBUG2
1092fprintf(stderr,"conflict: %s[%lu] %s[%lu]\n",
1093 basedim->ncfullname,(unsigned long)basedim->dim.declsize,
1094 dim->ncfullname,(unsigned long)dim->dim.declsize);
1095#endif
1096     nclistpush(conflicts,(void*)dim);
1097 }
1098 /* Give  all the conflicting dimensions an index */
1099 for(j=0;j<nclistlength(conflicts);j++) {
1100     CDFnodedim = (CDFnode*)nclistget(conflicts,j);
1101     dim->dim.index1 = j+1;
1102 }
1103    }
1104    nclistfree(conflicts);
1105
1106    /* Replace all non-base dimensions with their base dimension */
1107    for(i=0;i<nclistlength(varnodes);i++) {
1108 CDFnodenode = (CDFnode*)nclistget(varnodes,i);
1109 replacedims(node->array.dimsetall);
1110 replacedims(node->array.dimsetplus);
1111 replacedims(node->array.dimset0);
1112    }
1113
1114    /* Collect list of all basedims */
1115    basedims = nclistnew();
1116    for(i=0;i<nclistlength(alldims);i++) {
1117 CDFnodedim = (CDFnode*)nclistget(alldims,i);
1118 if(dim->dim.basedim == NULL) {
1119     if(!nclistcontains(basedims,(void*)dim)) {
1120 nclistpush(basedims,(void*)dim);
1121     }
1122 }
1123    }
1124
1125    nccomm->cdf.ddsroot->tree->dimnodes = basedims;
1126
1127    /* cleanup */
1128    nclistfree(alldims);
1129
1130    /* Assign ncbasenames and ncfullnames to base dimensions */
1131    for(i=0;i<nclistlength(basedims);i++) {
1132 CDFnodedim = (CDFnode*)nclistget(basedims,i);
1133 CDFnodevar = dim->dim.array;
1134 if(dim->dim.basedim != NULLPANIC1("nonbase basedim: %s\n",dim->ocname);
1135 /* stringdim names are already assigned */
1136 if(dim->ocname == NULL) { /* anonymous: use the index to compute the name */
1137            snprintf(tmp,sizeof(tmp),"%s_%d",
1138                            var->ncfullname,dim->dim.index1-1);
1139            nullfree(dim->ncbasename);
1140            dim->ncbasename = cdflegalname(tmp);
1141            nullfree(dim->ncfullname);
1142            dim->ncfullname = nulldup(dim->ncbasename);
1143     } else { /* !anonymous; use index1 if defined */
1144        char* legalname = cdflegalname(dim->ocname);
1145     nullfree(dim->ncbasename);
1146     if(dim->dim.index1 > 0) {/* need to fix conflicting names (see above) */
1147         char sindex[64];
1148 snprintf(sindex,sizeof(sindex),"_%d",dim->dim.index1);
1149 dim->ncbasename = (char*)malloc(strlen(sindex)+strlen(legalname)+1);
1150 if(dim->ncbasename == NULL) {nullfree(legalname); return NC_ENOMEM;}
1151 strcpy(dim->ncbasename,legalname);
1152 strcat(dim->ncbasename,sindex);
1153 nullfree(legalname);
1154     } else {/* standard case */
1155         dim->ncbasename = legalname;
1156     }
1157         nullfree(dim->ncfullname);
1158     dim->ncfullname = nulldup(dim->ncbasename);
1159 }
1160     }
1161
1162    /* Verify unique and defined names for dimensions*/
1163    for(i=0;i<nclistlength(basedims);i++) {
1164 CDFnodedim1 = (CDFnode*)nclistget(basedims,i);
1165        CDFnodedim2 = NULL;
1166 if(dim1->dim.basedim != NULLPANIC1("nonbase basedim: %s\n",dim1->ncbasename);
1167 if(dim1->ncbasename == NULL || dim1->ncfullname == NULL)
1168     PANIC1("missing dim names: %s",dim1->ocname);
1169 /* search backward so we can delete duplicates */
1170 for(j=nclistlength(basedims)-1;j>i;j--) {
1171      if(!dim1->ncfullname) continue;
1172      dim2 = (CDFnode*)nclistget(basedims,j);
1173      if(strcmp(dim1->ncfullname,dim2->ncfullname)==0) {
1174 /* complain and suppress one of them */
1175 fprintf(stderr,"duplicate dim names: %s[%lu] %s[%lu]\n",
1176                dim1->ncfullname,(unsigned long)dim1->dim.declsize,
1177                dim2->ncfullname,(unsigned long)dim2->dim.declsize);
1178 nclistremove(basedims,j);
1179      }
1180 }
1181    }
1182
1183#ifdef DEBUG
1184for(i=0;i<nclistlength(basedims);i++) {
1185CDFnodedim = (CDFnode*)nclistget(basedims,i);
1186fprintf(stderr,"basedim: %s=%ld\n",dim->ncfullname,(long)dim->dim.declsize);
1187 }
1188#endif
1189
1190    return NC_NOERR;
1191}
1192
1193int
1194constrainable(NCURIdurl)
1195{
1196   char** protocol = constrainableprotocols;
1197   for(;*protocol;protocol++) {
1198 if(strcmp(durl->protocol,*protocol)==0)
1199     return 1;
1200   }
1201   return 0;
1202}
1203
1204/* Note: this routine only applies some common
1205   client parameters, other routines may apply
1206   specific ones.
1207*/
1208
1209static NCerror
1210applyclientparams(NCDAPCOMMONnccomm)
1211{
1212    int i,len;
1213    int dfaltstrlen = DEFAULTSTRINGLENGTH;
1214    int dfaltseqlim = DEFAULTSEQLIMIT;
1215    const char* value;
1216    char tmpname[NC_MAX_NAME+32];
1217    char* pathstr;
1218    OClink conn = nccomm->oc.conn;
1219    unsigned long limit;
1220
1221    ASSERT(nccomm->oc.url != NULL);
1222
1223    nccomm->cdf.cache->cachelimit = DFALTCACHELIMIT;
1224    value = oc_clientparam_get(conn,"cachelimit");
1225    limit = getlimitnumber(value);
1226    if(limit > 0) nccomm->cdf.cache->cachelimit = limit;
1227
1228    nccomm->cdf.fetchlimit = DFALTFETCHLIMIT;
1229    value = oc_clientparam_get(conn,"fetchlimit");
1230    limit = getlimitnumber(value);
1231    if(limit > 0) nccomm->cdf.fetchlimit = limit;
1232
1233    nccomm->cdf.smallsizelimit = DFALTSMALLLIMIT;
1234    value = oc_clientparam_get(conn,"smallsizelimit");
1235    limit = getlimitnumber(value);
1236    if(limit > 0) nccomm->cdf.smallsizelimit = limit;
1237
1238    nccomm->cdf.cache->cachecount = DFALTCACHECOUNT;
1239#ifdef HAVE_GETRLIMIT
1240    { struct rlimit rl;
1241      if(getrlimit(RLIMIT_NOFILE, &rl) >= 0) {
1242 nccomm->cdf.cache->cachecount = (size_t)(rl.rlim_cur / 2);
1243      }
1244    }
1245#endif
1246    value = oc_clientparam_get(conn,"cachecount");
1247    limit = getlimitnumber(value);
1248    if(limit > 0) nccomm->cdf.cache->cachecount = limit;
1249    /* Ignore limit if not caching */
1250    if(!FLAGSET(nccomm->controls,NCF_CACHE))
1251        nccomm->cdf.cache->cachecount = 0;
1252
1253    if(oc_clientparam_get(conn,"nolimit") != NULL)
1254 dfaltseqlim = 0;
1255    value = oc_clientparam_get(conn,"limit");
1256    if(value != NULL && strlen(value) != 0) {
1257        if(sscanf(value,"%d",&len) && len > 0) dfaltseqlim = len;
1258    }
1259    nccomm->cdf.defaultsequencelimit = dfaltseqlim;
1260
1261    /* allow embedded _ */
1262    value = oc_clientparam_get(conn,"stringlength");
1263    if(value != NULL && strlen(value) != 0) {
1264        if(sscanf(value,"%d",&len) && len > 0) dfaltstrlen = len;
1265    }
1266    nccomm->cdf.defaultstringlength = dfaltstrlen;
1267
1268    /* String dimension limits apply to variables */
1269    for(i=0;i<nclistlength(nccomm->cdf.ddsroot->tree->varnodes);i++) {
1270 CDFnodevar = (CDFnode*)nclistget(nccomm->cdf.ddsroot->tree->varnodes,i);
1271 /* Define the client param stringlength for this variable*/
1272 var->maxstringlength = 0; /* => use global dfalt */
1273 strcpy(tmpname,"stringlength_");
1274 pathstr = makeocpathstring(conn,var->ocnode,".");
1275 strncat(tmpname,pathstr,NC_MAX_NAME);
1276 nullfree(pathstr);
1277 value = oc_clientparam_get(conn,tmpname);
1278        if(value != NULL && strlen(value) != 0) {
1279            if(sscanf(value,"%d",&len) && len > 0) var->maxstringlength = len;
1280 }
1281    }
1282    /* Sequence limits apply to sequences */
1283    for(i=0;i<nclistlength(nccomm->cdf.ddsroot->tree->nodes);i++) {
1284 CDFnodevar = (CDFnode*)nclistget(nccomm->cdf.ddsroot->tree->nodes,i);
1285 if(var->nctype != NC_Sequence) continue;
1286 var->sequencelimit = dfaltseqlim;
1287 strcpy(tmpname,"nolimit_");
1288 pathstr = makeocpathstring(conn,var->ocnode,".");
1289 strncat(tmpname,pathstr,NC_MAX_NAME);
1290 if(oc_clientparam_get(conn,tmpname) != NULL)
1291     var->sequencelimit = 0;
1292 strcpy(tmpname,"limit_");
1293 strncat(tmpname,pathstr,NC_MAX_NAME);
1294 value = oc_clientparam_get(conn,tmpname);
1295        if(value != NULL && strlen(value) != 0) {
1296            if(sscanf(value,"%d",&len) && len > 0)
1297 var->sequencelimit = len;
1298 }
1299 nullfree(pathstr);
1300    }
1301
1302    /* test for the appropriate fetch flags */
1303    value = oc_clientparam_get(conn,"fetch");
1304    if(value != NULL && strlen(value) > 0) {
1305 if(value[0] == 'd' || value[0] == 'D') {
1306            SETFLAG(nccomm->controls,NCF_ONDISK);
1307 }
1308    }
1309
1310    /* test for the force-whole-var flag */
1311    value = oc_clientparam_get(conn,"wholevar");
1312    if(value != NULL) {
1313        SETFLAG(nccomm->controls,NCF_WHOLEVAR);
1314    }
1315
1316    return NC_NOERR;
1317}
1318
1319/**
1320 *  Given an anonymous dimension, compute the
1321 *  effective 0-based index wrt to the specified var.
1322 *  The result should mimic the libnc-dap indices.
1323 */
1324
1325static void
1326computedimindexanon(CDFnodedimCDFnodevar)
1327{
1328    int i;
1329    NClistdimset = var->array.dimsetall;
1330    for(i=0;i<nclistlength(dimset);i++) {
1331 CDFnodecandidate = (CDFnode*)nclistget(dimset,i);
1332        if(dim == candidate) {
1333    dim->dim.index1=i+1;
1334    return;
1335 }
1336    }
1337}
1338
1339/* Replace dims in a list with their corresponding basedim */
1340static void
1341replacedims(NClistdims)
1342{
1343    int i;
1344    for(i=0;i<nclistlength(dims);i++) {
1345        CDFnodedim = (CDFnode*)nclistget(dims,i);
1346 CDFnodebasedim = dim->dim.basedim;
1347 if(basedim == NULL) continue;
1348 nclistset(dims,i,(void*)basedim);
1349    }
1350}
1351
1352/**
1353 Two dimensions are equivalent if
1354 1. they have the same size
1355 2. neither are anonymous
1356 3. they ave the same names.
1357 */
1358static int
1359equivalentdim(CDFnodebasedimCDFnodedupdim)
1360{
1361    if(dupdim->dim.declsize != basedim->dim.declsize) return 0;
1362    if(basedim->ocname == NULL && dupdim->ocname == NULL) return 0;
1363    if(basedim->ocname == NULL || dupdim->ocname == NULL) return 0;
1364    if(strcmp(dupdim->ocname,basedim->ocname) != 0) return 0;
1365    return 1;
1366}
1367
1368static void
1369getalldimsa(NClistdimsetNClistalldims)
1370{
1371    int i;
1372    for(i=0;i<nclistlength(dimset);i++) {
1373 CDFnodedim = (CDFnode*)nclistget(dimset,i);
1374 if(!nclistcontains(alldims,(void*)dim)) {
1375#ifdef DEBUG3
1376fprintf(stderr,"getalldims: %s[%lu]\n",
1377 dim->ncfullname,(unsigned long)dim->dim.declsize);
1378#endif
1379     nclistpush(alldims,(void*)dim);
1380 }
1381    }
1382}
1383
1384/* Accumulate a set of all the known dimensions
1385   vis-a-vis defined variables
1386*/
1387NClist*
1388getalldims(NCDAPCOMMONnccomm, int visibleonly)
1389{
1390    int i;
1391    NClistalldims = nclistnew();
1392    NClistvarnodes = nccomm->cdf.ddsroot->tree->varnodes;
1393
1394    /* get bag of all dimensions */
1395    for(i=0;i<nclistlength(varnodes);i++) {
1396 CDFnodenode = (CDFnode*)nclistget(varnodes,i);
1397 if(!visibleonly || !node->invisible) {
1398     getalldimsa(node->array.dimsetall,alldims);
1399 }
1400    }
1401    return alldims;
1402}
1403
1404
1405static NCerror
1406addstringdims(NCDAPCOMMONdapcomm)
1407{
1408    /* for all variables of string type, we will need another dimension
1409       to represent the string; Accumulate the needed sizes and create
1410       the dimensions with a specific name: either as specified
1411       in DODS{...} attribute set or defaulting to the variable name.
1412       All such dimensions are global.
1413    */
1414    int i;
1415    NClistvarnodes = dapcomm->cdf.ddsroot->tree->varnodes;
1416    CDFnodeglobalsdim = NULL;
1417    char dimname[4096];
1418    size_t dimsize;
1419
1420    /* Start by creating the global string dimension */
1421    snprintf(dimname,sizeof(dimname),"maxStrlen%lu",
1422     (unsigned long)dapcomm->cdf.defaultstringlength);
1423    globalsdim = makecdfnode(dapcommdimnameOC_DimensionNULL,
1424                                 dapcomm->cdf.ddsroot);
1425    nclistpush(dapcomm->cdf.ddsroot->tree->nodes,(void*)globalsdim);
1426    DIMFLAGSET(globalsdim,CDFDIMSTRING);
1427    globalsdim->dim.declsize = dapcomm->cdf.defaultstringlength;
1428    globalsdim->dim.declsize0 = globalsdim->dim.declsize;
1429    globalsdim->dim.array = dapcomm->cdf.ddsroot;
1430    globalsdim->ncbasename = cdflegalname(dimname);
1431    globalsdim->ncfullname = nulldup(globalsdim->ncbasename);
1432    dapcomm->cdf.globalstringdim = globalsdim;
1433
1434    for(i=0;i<nclistlength(varnodes);i++) {
1435 CDFnodevar = (CDFnode*)nclistget(varnodes,i);
1436 CDFnodesdim = NULL;
1437
1438 /* Does this node need a string dim? */
1439 if(var->etype != NC_STRING && var->etype != NC_URL) continue;
1440
1441 dimsize = 0;
1442 if(var->dodsspecial.maxstrlen > 0)
1443     dimsize = var->dodsspecial.maxstrlen;
1444 else
1445     dimsize = var->maxstringlength;
1446
1447 /* check is a variable-specific string length was specified */
1448 if(dimsize == 0)
1449     sdim = dapcomm->cdf.globalstringdim; /* use default */
1450 else {
1451     /* create a psuedo dimension for the charification of the string*/
1452     if(var->dodsspecial.dimname != NULL) {
1453         strncpy(dimname,var->dodsspecial.dimname,sizeof(dimname));
1454         dimname[sizeof(dimname)-1] = '\0';
1455     } else
1456         snprintf(dimname,sizeof(dimname),"maxStrlen%lu",
1457  (unsigned long)dimsize);
1458     sdim = makecdfnode(dapcommdimnameOC_DimensionNULL,
1459                                 dapcomm->cdf.ddsroot);
1460     if(sdim == NULL) return THROW(NC_ENOMEM);
1461     nclistpush(dapcomm->cdf.ddsroot->tree->nodes,(void*)sdim);
1462     DIMFLAGSET(sdim,CDFDIMSTRING);
1463     sdim->dim.declsize = dimsize;
1464     sdim->dim.declsize0 = dimsize;
1465     sdim->dim.array = var;
1466     sdim->ncbasename = cdflegalname(sdim->ocname);
1467     sdim->ncfullname = nulldup(sdim->ncbasename);
1468 }
1469 /* tag the variable with its string dimension*/
1470 var->array.stringdim = sdim;
1471    }
1472    return NC_NOERR;
1473}
1474
1475static NCerror
1476defrecorddim(NCDAPCOMMONdapcomm)
1477{
1478    unsigned int i;
1479    NCerror ncstat = NC_NOERR;
1480    NClistbasedims;
1481
1482    if(dapcomm->cdf.recorddimname == NULL) return NC_NOERR; /* ignore */
1483    /* Locate the base dimension matching the record dim */
1484    basedims = dapcomm->cdf.ddsroot->tree->dimnodes;
1485    for(i=0;i<nclistlength(basedims);i++) {
1486        CDFnodedim = (CDFnode*)nclistget(basedims,i);
1487 if(strcmp(dim->ocname,dapcomm->cdf.recorddimname) != 0) continue;
1488        DIMFLAGSET(dim,CDFDIMRECORD);
1489 dapcomm->cdf.recorddim = dim;
1490 break;
1491    }
1492
1493    return ncstat;
1494}
1495
1496static NCerror
1497defseqdims(NCDAPCOMMONdapcomm)
1498{
1499    unsigned int i = 0;
1500    NCerror ncstat = NC_NOERR;
1501    int seqdims = 1; /* default is to compute seq dims counts */
1502
1503    /* Does the user want to compute actual sequence sizes? */
1504    if(dapparamvalue(dapcomm,"noseqdims")) seqdims = 0;
1505
1506    /*
1507 Compute and define pseudo dimensions for sequences
1508 meeting the following qualifications:
1509 1. all parents (transitively) of the sequence must
1510           be either a dataset or a scalar structure.
1511 2. it must be possible to find a usable sequence constraint.
1512 All other sequences will be ignored.
1513    */
1514
1515    for(i=0;i<nclistlength(dapcomm->cdf.ddsroot->tree->seqnodes);i++) {
1516        CDFnodeseq = (CDFnode*)nclistget(dapcomm->cdf.ddsroot->tree->seqnodes,i);
1517 size_t seqsize = 0;
1518 CDFnodesqdim = NULL;
1519 CDFnodecontainer;
1520 /* Does this sequence match the requirements for use ? */
1521 seq->usesequence = 1; /* assume */
1522 for(container=seq->container;container != NULL;container=container->container) {
1523     if(container->nctype == NC_Dataset) break;
1524     if(container->nctype != NC_Structure
1525        || nclistlength(container->array.dimset0) > 0)
1526 {seq->usesequence = 0; break;}/* no good */
1527 }
1528 /* Does the user want us to compute the actual sequence dim size? */
1529 if(seq->usesequence && seqdims) {
1530     ncstat = getseqdimsize(dapcomm,seq,&seqsize);
1531     if(ncstat != NC_NOERR) {
1532                /* Cannot read sequence; mark as unusable */
1533         seq->usesequence = 0;
1534     }
1535 } else { /* !seqdims default to size = 1 */
1536     seqsize = 1;
1537 }
1538 if(seq->usesequence) {
1539     /* Note: we are making the dimension in the dds root tree */
1540            ncstat = makeseqdim(dapcomm,seq,seqsize,&sqdim);
1541            if(ncstat) goto fail;
1542            seq->array.seqdim = sqdim;
1543 } else
1544            seq->array.seqdim = NULL;
1545    }
1546
1547fail:
1548    return ncstat;
1549}
1550
1551static NCerror
1552showprojection(NCDAPCOMMONdapcommCDFnodevar)
1553{
1554    int i,rank;
1555    NCerror ncstat = NC_NOERR;
1556    NCbytesprojection = ncbytesnew();
1557    NClistpath = nclistnew();
1558    NCdrno = dapcomm->controller;
1559
1560    /* Collect the set of DDS node name forming the xpath */
1561    collectnodepath(var,path,WITHOUTDATASET);
1562    for(i=0;i<nclistlength(path);i++) {
1563        CDFnodenode = (CDFnode*)nclistget(path,i);
1564 if(i > 0) ncbytescat(projection,".");
1565 ncbytescat(projection,node->ocname);
1566    }
1567    nclistfree(path);
1568    /* Now, add the dimension info */
1569    rank = nclistlength(var->array.dimset0);
1570    for(i=0;i<rank;i++) {
1571 CDFnodedim = (CDFnode*)nclistget(var->array.dimset0,i);
1572 char tmp[32];
1573 ncbytescat(projection,"[");
1574 snprintf(tmp,sizeof(tmp),"%lu",(unsigned long)dim->dim.declsize);
1575 ncbytescat(projection,tmp);
1576 ncbytescat(projection,"]");
1577    }
1578    /* Define the attribute */
1579    ncstat = nc_put_att_text(getncid(drno),var->ncid,
1580                               "_projection",
1581                ncbyteslength(projection),
1582        ncbytescontents(projection));
1583    ncbytesfree(projection);
1584    return ncstat;
1585}
1586
1587static NCerror
1588getseqdimsize(NCDAPCOMMONdapcommCDFnodeseq, size_t* sizep)
1589{
1590    NCerror ncstat = NC_NOERR;
1591    OCerror ocstat = OC_NOERR;
1592    OClink conn = dapcomm->oc.conn;
1593    OCdatanode rootcontent = NULL;
1594    OCddsnode ocroot;
1595    CDFnodedxdroot;
1596    CDFnodexseq;
1597    NCbytesseqcountconstraints = ncbytesnew();
1598    size_t seqsize = 0;
1599
1600    /* Read the minimal amount of data in order to get the count */
1601    /* If the url is unconstrainable, then get the whole thing */
1602    computeseqcountconstraints(dapcomm,seq,seqcountconstraints);
1603#ifdef DEBUG
1604fprintf(stderr,"seqcountconstraints: %s\n",ncbytescontents(seqcountconstraints));
1605#endif
1606
1607    /* Fetch the minimal data */
1608    if(FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE))
1609        ncstat = dap_fetch(dapcomm,conn,NULL,OCDATADDS,&ocroot);
1610    else
1611        ncstat = dap_fetch(dapcomm,conn,ncbytescontents(seqcountconstraints),OCDATADDS,&ocroot);
1612    if(ncstat) goto fail;
1613
1614    ncstat = buildcdftree(dapcomm,ocroot,OCDATA,&dxdroot);
1615    if(ncstat) goto fail;
1616    /* attach DATADDS to DDS */
1617    ncstat = attach(dxdroot,seq);
1618    if(ncstat) goto fail;
1619
1620    /* WARNING: we are now switching to datadds tree */
1621    xseq = seq->attachment;
1622    ncstat = countsequence(dapcomm,xseq,&seqsize);
1623    if(ncstat != NC_NOERR) goto fail;
1624
1625#ifdef DEBUG
1626fprintf(stderr,"sequencesize: %s = %lu\n",seq->ocname,(unsigned long)seqsize);
1627#endif
1628
1629    /* throw away the fetch'd trees */
1630    unattach(dapcomm->cdf.ddsroot);
1631    freecdfroot(dxdroot);
1632#if 1
1633/*Note sure what this is doing?*/
1634    if(ncstat != NC_NOERR) {
1635        /* Cannot get DATADDDS*/
1636 char* code;
1637 char* msg;
1638 long httperr;
1639 oc_svcerrordata(dapcomm->oc.conn,&code,&msg,&httperr);
1640 if(code != NULL) {
1641     nclog(NCLOGERR,"oc_fetch_datadds failed: %s %s %l",
1642 code,msg,httperr);
1643 }
1644 ocstat = OC_NOERR;
1645    }
1646#endif
1647
1648    if(sizep) *sizep = seqsize;
1649
1650fail:
1651    ncbytesfree(seqcountconstraints);
1652    oc_data_free(conn,rootcontent);
1653    if(ocstat != OC_NOERRncstat = ocerrtoncerr(ocstat);
1654    return ncstat;
1655}
1656
1657static NCerror
1658makeseqdim(NCDAPCOMMONdapcommCDFnodeseq, size_t countCDFnode** sqdimp)
1659{
1660    CDFnodesqdim;
1661    CDFnoderoot = seq->root;
1662    CDFtreetree = root->tree;
1663
1664    /* build the dimension with given size; keep the dimension anonymous */
1665    sqdim = makecdfnode(dapcomm,seq->ocname,OC_Dimension,NULL,root);
1666    if(sqdim == NULL) return THROW(NC_ENOMEM);
1667    nclistpush(tree->nodes,(void*)sqdim);
1668    /* Assign a name to the sequence node */
1669    sqdim->ncbasename = cdflegalname(seq->ocname);
1670    sqdim->ncfullname = nulldup(sqdim->ncbasename);
1671    DIMFLAGSET(sqdim,CDFDIMSEQ);
1672    sqdim->dim.declsize = count;
1673    sqdim->dim.declsize0 = count;
1674    sqdim->dim.array = seq;
1675    if(sqdimp) *sqdimp = sqdim;
1676    return NC_NOERR;
1677}
1678
1679static NCerror
1680countsequence(NCDAPCOMMONdapcommCDFnodexseq, size_t* sizep)
1681{
1682    unsigned int i;
1683    NClistpath = nclistnew();
1684    int index;
1685    OCerror ocstat = OC_NOERR;
1686    NCerror ncstat = NC_NOERR;
1687    OClink conn = dapcomm->oc.conn;
1688    size_t recordcount;
1689    CDFnodexroot;
1690    OCdatanode data = NULL;
1691
1692    ASSERT((xseq->nctype == NC_Sequence));
1693
1694    /* collect the path to the sequence node */
1695    collectnodepath(xseq,path,WITHDATASET);
1696
1697    /* Get tree root */
1698    ASSERT(xseq->root == (CDFnode*)nclistget(path,0));
1699    xroot = xseq->root;
1700    ocstat = oc_data_getroot(conn,xroot->tree->ocroot,&data);
1701    if(ocstat) goto done;
1702
1703    /* Basically we use the path to walk the data instances to reach
1704       the sequence instance
1705    */
1706    for(i=0;i<nclistlength(path);i++) {
1707        CDFnodecurrent = (CDFnode*)nclistget(path,i);
1708 OCdatanode nextdata = NULL;
1709 CDFnodenext = NULL;
1710
1711 /* invariant: current = ith node in path; data = corresponding
1712           datanode
1713        */
1714
1715 /* get next node in next and next instance in nextdata */
1716 if(current->nctype == NC_Structure
1717    || current->nctype == NC_Dataset) {
1718     if(nclistlength(current->array.dimset0) > 0) {
1719 /* Cannot handle this case */
1720 ncstat = THROW(NC_EDDS);
1721 goto done;
1722     }
1723     /* get next node in path; structure/dataset => exists */
1724     next = (CDFnode*)nclistget(path,i+1);
1725     index = fieldindex(current,next);
1726            /* Move to appropriate field */
1727     ocstat = oc_data_ithfield(conn,data,index,&nextdata);
1728     if(ocstat) goto done;
1729     oc_data_free(conn,data);
1730     data = nextdata; /* set up for next loop iteration */
1731 } else if(current->nctype ==  NC_Sequence) {
1732     /* Check for nested Sequences */
1733     if(current != xseq) {
1734 /* Cannot handle this case */
1735 ncstat = THROW(NC_EDDS);
1736 goto done;
1737     }
1738     /* Get the record count */
1739     ocstat = oc_data_recordcount(conn,data,&recordcount);
1740         if(sizep) *sizep = recordcount;
1741     oc_data_free(conn,data); /* reclaim */
1742     break; /* leave the loop */
1743 } else {
1744     PANIC("unexpected mode");
1745     return NC_EINVAL;
1746        }
1747    }
1748
1749done:
1750    nclistfree(path);
1751    if(ocstat != OC_NOERRncstat = ocerrtoncerr(ocstat);
1752    return THROW(ncstat);
1753}
1754
1755static NCerror
1756freeNCDAPCOMMON(NCDAPCOMMONdapcomm)
1757{
1758    freenccache(dapcomm,dapcomm->cdf.cache);
1759    nclistfree(dapcomm->cdf.projectedvars);
1760    nullfree(dapcomm->cdf.recorddimname);
1761
1762    /* free the trees */
1763    freecdfroot(dapcomm->cdf.ddsroot);
1764    dapcomm->cdf.ddsroot = NULL;
1765    freecdfroot(dapcomm->cdf.fullddsroot);
1766    dapcomm->cdf.fullddsroot = NULL;
1767    if(dapcomm->oc.ocdasroot != NULL)
1768        oc_root_free(dapcomm->oc.conn,dapcomm->oc.ocdasroot);
1769    dapcomm->oc.ocdasroot = NULL;
1770    oc_close(dapcomm->oc.conn); /* also reclaims remaining OC trees */
1771    ncurifree(dapcomm->oc.url);
1772    nullfree(dapcomm->oc.urltext);
1773    nullfree(dapcomm->oc.rawurltext);
1774
1775    dcefree((DCEnode*)dapcomm->oc.dapconstraint);
1776    dapcomm->oc.dapconstraint = NULL;
1777
1778    free(dapcomm);
1779
1780    return NC_NOERR;
1781}
1782
1783static size_t
1784fieldindex(CDFnodeparentCDFnodechild)
1785{
1786    unsigned int i;
1787    for(i=0;i<nclistlength(parent->subnodes);i++) {
1788 CDFnodenode = (CDFnode*)nclistget(parent->subnodes,i);
1789 if(node == child) return i;
1790    }
1791    return -1;
1792}
1793
1794/*
1795This is more complex than one might think. We want to find
1796a path to a variable inside the given node so that we can
1797ask for a single instance of that variable to minimize the
1798amount of data we retrieve. However, we want to avoid passing
1799through any nested sequence. This is possible because of the way
1800that sequencecheck() works.
1801TODO: some servers will not accept an unconstrained fetch, so
1802make sure we always have a constraint.
1803*/
1804
1805static NCerror
1806computeseqcountconstraints(NCDAPCOMMONdapcommCDFnodeseqNCbytesseqcountconstraints)
1807{
1808    int i,j;
1809    NClistpath = NULL;
1810    CDFnodevar = NULL;
1811
1812    ASSERT(seq->nctype == NC_Sequence);
1813    computeseqcountconstraintsr(dapcomm,seq,&var);
1814
1815    ASSERT((var != NULL));
1816
1817    /* Compute var path */
1818    path = nclistnew();
1819    collectnodepath(var,path,WITHOUTDATASET);
1820
1821    /* construct the projection path using minimal index values */
1822    for(i=0;i<nclistlength(path);i++) {
1823 CDFnodenode = (CDFnode*)nclistget(path,i);
1824 if(i > 0) ncbytescat(seqcountconstraints,".");
1825 ncbytescat(seqcountconstraints,node->ocname);
1826 if(node == seq) {
1827     /* Use the limit */
1828     if(node->sequencelimit > 0) {
1829 char tmp[64];
1830 snprintf(tmp,sizeof(tmp),"[0:%lu]",
1831          (unsigned long)(node->sequencelimit - 1));
1832 ncbytescat(seqcountconstraints,tmp);
1833     }
1834 } else if(nclistlength(node->array.dimset0) > 0) {
1835     int ndims = nclistlength(node->array.dimset0);
1836     for(j=0;j<ndims;j++) {
1837 CDFnodedim = (CDFnode*)nclistget(node->array.dimset0,j);
1838 if(DIMFLAG(dim,CDFDIMSTRING)) {
1839     ASSERT((j == (ndims - 1)));
1840     break;
1841 }
1842 ncbytescat(seqcountconstraints,"[0]");
1843     }
1844 }
1845    }
1846    /* Finally, add in any selection from the original URL */
1847    if(dapcomm->oc.url->selection != NULL)
1848        ncbytescat(seqcountconstraints,dapcomm->oc.url->selection);
1849    nclistfree(path);
1850    return NC_NOERR;
1851}
1852
1853
1854/* Given an existing candidate, see if we prefer newchoice */
1855static CDFnode*
1856prefer(CDFnodecandidateCDFnodenewchoice)
1857{
1858    nc_type newtyp;
1859    nc_type cantyp;
1860    int newisstring;
1861    int canisstring;
1862    int newisscalar;
1863    int canisscalar;
1864
1865    /* always choose !null over null */
1866    if(newchoice == NULL)
1867 return candidate;
1868    if(candidate == NULL)
1869 return newchoice;
1870
1871    newtyp = newchoice->etype;
1872    cantyp = candidate->etype;
1873    newisstring = (newtyp == NC_STRING || newtyp == NC_URL);
1874    canisstring = (cantyp == NC_STRING || cantyp == NC_URL);
1875    newisscalar = (nclistlength(newchoice->array.dimset0) == 0);
1876    canisscalar = (nclistlength(candidate->array.dimset0) == 0);
1877
1878    ASSERT(candidate->nctype == NC_Atomic && newchoice->nctype == NC_Atomic);
1879
1880    /* choose non-string over string */
1881    if(canisstring && !newisstring)
1882 return newchoice;
1883    if(!canisstring && newisstring)
1884 return candidate;
1885
1886    /* choose scalar over array */
1887    if(canisscalar && !newisscalar)
1888 return candidate;
1889    if(!canisscalar && newisscalar)
1890 return candidate;
1891
1892    /* otherwise choose existing candidate */
1893    return candidate;
1894}
1895
1896/* computeseqcountconstraints recursive helper function */
1897static void
1898computeseqcountconstraintsr(NCDAPCOMMONdapcommCDFnodenodeCDFnode** candidatep)
1899{
1900    CDFnodecandidate;
1901    CDFnodecompound;
1902    unsigned int i;
1903
1904    candidate = NULL;
1905    compound = NULL;
1906    if(node == NULL)
1907      return;
1908    for(i=0;i<nclistlength(node->subnodes);i++) {
1909        CDFnodesubnode = (CDFnode*)nclistget(node->subnodes,i);
1910        if(subnode->nctype == NC_Structure || subnode->nctype == NC_Grid)
1911     compound = subnode; /* save for later recursion */
1912 else if(subnode->nctype == NC_Atomic)
1913     candidate = prefer(candidate,subnode);
1914    }
1915    if(candidate == NULL && compound == NULL) {
1916 PANIC("cannot find candidate for seqcountconstraints for a sequence");
1917    } else if(candidate != NULL && candidatep != NULL) {
1918 *candidatep = candidate;
1919    } else { /* compound != NULL by construction */
1920 /* recurse on a nested grids or strucures */
1921        computeseqcountconstraintsr(dapcomm,compound,candidatep);
1922    }
1923}
1924
1925
1926static unsigned long
1927cdftotalsize(NClistdimensions)
1928{
1929    unsigned int i;
1930    unsigned long total = 1;
1931    if(dimensions != NULL) {
1932 for(i=0;i<nclistlength(dimensions);i++) {
1933     CDFnodedim = (CDFnode*)nclistget(dimensions,i);
1934     total *= dim->dim.declsize;
1935 }
1936    }
1937    return total;
1938}
1939
1940/* Estimate variables sizes and then resort the variable list
1941   by that size
1942*/
1943static void
1944estimatevarsizes(NCDAPCOMMONdapcomm)
1945{
1946    int ivar;
1947    unsigned int rank;
1948    size_t totalsize = 0;
1949
1950    for(ivar=0;ivar<nclistlength(dapcomm->cdf.ddsroot->tree->varnodes);ivar++) {
1951        CDFnodevar = (CDFnode*)nclistget(dapcomm->cdf.ddsroot->tree->varnodes,ivar);
1952 NClistncdims = var->array.dimset0;
1953 rank = nclistlength(ncdims);
1954 if(rank == 0) { /* use instance size of the type */
1955     var->estimatedsize = nctypesizeof(var->etype);
1956#ifdef DEBUG1
1957fprintf(stderr,"scalar %s.estimatedsize = %lu\n",
1958 makecdfpathstring(var,"."),var->estimatedsize);
1959#endif
1960 } else {
1961     unsigned long size = cdftotalsize(ncdims);
1962     size *= nctypesizeof(var->etype);
1963#ifdef DEBUG1
1964fprintf(stderr,"array %s(%u).estimatedsize = %lu\n",
1965 makecdfpathstring(var,"."),rank,size);
1966#endif
1967     var->estimatedsize = size;
1968 }
1969 totalsize += var->estimatedsize;
1970    }
1971#ifdef DEBUG1
1972fprintf(stderr,"total estimatedsize = %lu\n",totalsize);
1973#endif
1974    dapcomm->cdf.totalestimatedsize = totalsize;
1975}
1976
1977static NCerror
1978fetchpatternmetadata(NCDAPCOMMONdapcomm)
1979{
1980    NCerror ncstat = NC_NOERR;
1981    OCerror ocstat = OC_NOERR;
1982    OCddsnode ocroot = NULL;
1983    CDFnodeddsroot = NULL;
1984    char* ce = NULL;
1985
1986    /* Temporary hack: we need to get the selection string
1987       from the url
1988    */
1989    /* Get (almost) unconstrained DDS; In order to handle functions
1990       correctly, those selections must always be included
1991    */
1992    if(FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE))
1993 ce = NULL;
1994    else
1995        ce = nulldup(dapcomm->oc.url->selection);
1996
1997    /* Get selection constrained DDS */
1998    ncstat = dap_fetch(dapcomm,dapcomm->oc.conn,ce,OCDDS,&ocroot);
1999    if(ncstat != NC_NOERR) {
2000 /* Special Hack. If the protocol is file, then see if
2001           we can get the dds from the .dods file
2002        */
2003 if(strcmp(dapcomm->oc.url->protocol,"file") != 0) {
2004     THROWCHK(ocstat); goto done;
2005 }
2006 /* Fetch the data dds */
2007        ncstat = dap_fetch(dapcomm,dapcomm->oc.conn,ce,OCDATADDS,&ocroot);
2008        if(ncstat != NC_NOERR) {
2009     THROWCHK(ncstat); goto done;
2010 }
2011 /* Note what we did */
2012 nclog(NCLOGWARN,"Cannot locate .dds file, using .dods file");
2013    }
2014
2015    /* Get selection constrained DAS */
2016    ncstat = dap_fetch(dapcomm,dapcomm->oc.conn,ce,OCDAS,&dapcomm->oc.ocdasroot);
2017    if(ncstat != NC_NOERR) {
2018 /* Ignore but complain */
2019 nclog(NCLOGWARN,"Could not read DAS; ignored");
2020        dapcomm->oc.ocdasroot = NULL;
2021 ncstat = NC_NOERR;
2022    }
2023
2024    /* Construct the netcdf cdf tree corresponding to the dds tree*/
2025    ncstat = buildcdftree(dapcomm,ocroot,OCDDS,&ddsroot);
2026    if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
2027    dapcomm->cdf.fullddsroot = ddsroot;
2028    ddsroot = NULL; /* avoid double reclaim */
2029
2030    /* Combine DDS and DAS */
2031    if(dapcomm->oc.ocdasroot != NULL) {
2032 ncstat = dapmerge(dapcomm,dapcomm->cdf.fullddsroot,
2033                           dapcomm->oc.ocdasroot);
2034        if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;}
2035    }
2036
2037#ifdef DEBUG
2038fprintf(stderr,"full pattern:\n%s",dumptree(dapcomm->cdf.fullddsroot));
2039#endif
2040
2041done:
2042    nullfree(ce);
2043    if(ocstat != OC_NOERRncstat = ocerrtoncerr(ocstat);
2044    return ncstat;
2045}
2046
2047static NCerror
2048fetchconstrainedmetadata(NCDAPCOMMONdapcomm)
2049{
2050    NCerror ncstat = NC_NOERR;
2051    OCerror ocstat = OC_NOERR;
2052    OCddsnode ocroot;
2053    CDFnodeddsroot; /* constrained */
2054    char* ce = NULL;
2055
2056    if(FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE))
2057 ce = NULL;
2058    else
2059        ce = dcebuildconstraintstring(dapcomm->oc.dapconstraint);
2060    {
2061        ncstat = dap_fetch(dapcomm,dapcomm->oc.conn,ce,OCDDS,&ocroot);
2062        if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
2063
2064        /* Construct our parallel dds tree; including attributes*/
2065        ncstat = buildcdftree(dapcomm,ocroot,OCDDS,&ddsroot);
2066        if(ncstat) goto fail;
2067 ocroot = NULL; /* avoid duplicate reclaim */
2068
2069 dapcomm->cdf.ddsroot = ddsroot;
2070 ddsroot = NULL; /* to avoid double reclamation */
2071
2072        if(!FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE)) {
2073            /* fix DAP server problem by adding back any inserting needed structure nodes */
2074            ncstat = restruct(dapcommdapcomm->cdf.ddsroot,dapcomm->cdf.fullddsroot,dapcomm->oc.dapconstraint->projections);
2075            if(ncstat) goto fail;
2076 }
2077
2078#ifdef DEBUG
2079fprintf(stderr,"constrained:\n%s",dumptree(dapcomm->cdf.ddsroot));
2080#endif
2081
2082        /* Combine DDS and DAS */
2083 if(dapcomm->oc.ocdasroot != NULL) {
2084            ncstat = dapmerge(dapcomm,dapcomm->cdf.ddsroot,
2085                               dapcomm->oc.ocdasroot);
2086            if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto fail;}
2087 }
2088
2089        /* map the constrained DDS to the unconstrained DDS */
2090        ncstat = mapnodes(dapcomm->cdf.ddsroot,dapcomm->cdf.fullddsroot);
2091        if(ncstat) goto fail;
2092
2093    }
2094
2095fail:
2096    nullfree(ce);
2097    if(ocstat != OC_NOERRncstat = ocerrtoncerr(ocstat);
2098    return ncstat;
2099}
2100
2101/* Suppress variables not in usable sequences*/
2102static NCerror
2103suppressunusablevars(NCDAPCOMMONdapcomm)
2104{
2105    int i,j;
2106    int found = 1;
2107    NClistpath = nclistnew();
2108
2109    while(found) {
2110 found = 0;
2111 /* Walk backwards to aid removal semantics */
2112 for(i=nclistlength(dapcomm->cdf.ddsroot->tree->varnodes)-1;i>=0;i--) {
2113     CDFnodevar = (CDFnode*)nclistget(dapcomm->cdf.ddsroot->tree->varnodes,i);
2114     /* See if this var is under an unusable sequence */
2115     nclistclear(path);
2116     collectnodepath(var,path,WITHOUTDATASET);
2117     for(j=0;j<nclistlength(path);j++) {
2118 CDFnodenode = (CDFnode*)nclistget(path,j);
2119 if(node->nctype == NC_Sequence
2120    && !node->usesequence) {
2121#ifdef DEBUG
2122fprintf(stderr,"suppressing var in unusable sequence: %s.%s\n",node->ncfullname,var->ncbasename);
2123#endif
2124     found = 1;
2125     break;
2126 }
2127     }
2128     if(found) break;
2129 }
2130        if(foundnclistremove(dapcomm->cdf.ddsroot->tree->varnodes,i);
2131    }
2132    nclistfree(path);
2133    return NC_NOERR;
2134}
2135
2136
2137/*
2138For variables which have a zero size dimension,
2139make them invisible.
2140*/
2141static NCerror
2142fixzerodims(NCDAPCOMMONdapcomm)
2143{
2144    int i,j;
2145    for(i=0;i<nclistlength(dapcomm->cdf.ddsroot->tree->varnodes);i++) {
2146 CDFnodevar = (CDFnode*)nclistget(dapcomm->cdf.ddsroot->tree->varnodes,i);
2147        NClistncdims = var->array.dimsetplus;
2148 if(nclistlength(ncdims) == 0) continue;
2149        for(j=0;j<nclistlength(ncdims);j++) {
2150     CDFnodedim = (CDFnode*)nclistget(ncdims,j);
2151     if(dim->dim.declsize == 0) {
2152   /* make node invisible */
2153 var->invisible = 1;
2154 var->zerodim = 1;
2155     }
2156 }
2157    }
2158    return NC_NOERR;
2159}
2160
2161static void
2162applyclientparamcontrols(NCDAPCOMMONdapcomm)
2163{
2164    /* clear the flags */
2165    CLRFLAG(dapcomm->controls,NCF_CACHE);
2166    CLRFLAG(dapcomm->controls,NCF_SHOWFETCH);
2167    CLRFLAG(dapcomm->controls,NCF_NC3);
2168    CLRFLAG(dapcomm->controls,NCF_NCDAP);
2169    CLRFLAG(dapcomm->controls,NCF_PREFETCH);
2170    CLRFLAG(dapcomm->controls,NCF_PREFETCH_EAGER);
2171
2172    /* Turn on any default on flags */
2173    SETFLAG(dapcomm->controls,DFALT_ON_FLAGS);
2174    SETFLAG(dapcomm->controls,(NCF_NC3|NCF_NCDAP));
2175
2176    /* enable/disable caching */
2177    if(dapparamcheck(dapcomm,"cache",NULL))
2178 SETFLAG(dapcomm->controls,NCF_CACHE);
2179    else if(dapparamcheck(dapcomm,"nocache",NULL))
2180 CLRFLAG(dapcomm->controls,NCF_CACHE);
2181
2182    /* enable/disable cache prefetch and lazy vs eager*/
2183    if(dapparamcheck(dapcomm,"prefetch","eager")) {
2184        SETFLAG(dapcomm->controls,NCF_PREFETCH);
2185        SETFLAG(dapcomm->controls,NCF_PREFETCH_EAGER);
2186    } else if(dapparamcheck(dapcomm,"prefetch","lazy")
2187              || dapparamcheck(dapcomm,"prefetch",NULL)) {
2188        SETFLAG(dapcomm->controls,NCF_PREFETCH);
2189        CLRFLAG(dapcomm->controls,NCF_PREFETCH_EAGER);
2190    } else if(dapparamcheck(dapcomm,"noprefetch",NULL))
2191        CLRFLAG(dapcomm->controls,NCF_PREFETCH);
2192
2193    if(FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE))
2194 SETFLAG(dapcomm->controls,NCF_CACHE);
2195
2196    if(dapparamcheck(dapcomm,"show","fetch"))
2197 SETFLAG(dapcomm->controls,NCF_SHOWFETCH);
2198
2199    nclog(NCLOGNOTE,"Caching=%d",FLAGSET(dapcomm->controls,NCF_CACHE));
2200
2201}
2202
2203/*
2204Force dap2 access to be read-only
2205*/
2206int
2207NCD2_set_fill(int ncid, int fillmode, int* old_modep)
2208{
2209    return THROW(NC_EPERM);
2210}
2211
2212int
2213NCD2_set_base_pe(int ncid, int pe)
2214{
2215    return THROW(NC_EPERM);
2216}
2217
2218int
2219NCD2_def_dim(int ncid, const char* name, size_t len, int* idp)
2220{
2221    return THROW(NC_EPERM);
2222}
2223
2224int
2225NCD2_put_att(int ncid, int varid, const char* namenc_type datatype,
2226    size_t len, const void* valuenc_type t)
2227{
2228    return THROW(NC_EPERM);
2229}
2230
2231int
2232NCD2_def_var(int ncid, const char *name,
2233        nc_type xtype, int ndims, const int *dimidsp, int *varidp)
2234{
2235    return THROW(NC_EPERM);
2236}
2237
2238/*
2239Following functions basically return the netcdf-3 value WRT to the nc3id.
2240*/
2241
2242int
2243NCD2_inq_base_pe(int ncid, int* pe)
2244{
2245    NCdrno;
2246    int ret;
2247    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2248    ret = nc_inq_base_pe(getnc3id(drno), pe);
2249    return THROW(ret);
2250}
2251
2252int
2253NCD2_inq_format(int ncid, int* formatp)
2254{
2255    NCdrno;
2256    int ret = NC_NOERR;
2257    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2258    ret = nc_inq_format(getnc3id(drno), formatp);
2259    return THROW(ret);
2260}
2261
2262int
2263NCD2_inq(int ncid, int* ndimsp, int* nvarsp, int* nattsp, int* unlimdimidp)
2264{
2265    NCdrno;
2266    int ret;
2267    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2268    ret = nc_inq(getnc3id(drno), ndimspnvarspnattspunlimdimidp);
2269    return THROW(ret);
2270}
2271
2272int
2273NCD2_inq_type(int ncidnc_type p2, char* p3, size_t* p4)
2274{
2275    NCdrno;
2276    int ret;
2277    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2278    ret = nc_inq_type(getnc3id(drno), p2p3p4);
2279    return THROW(ret);
2280}
2281
2282int
2283NCD2_inq_dimid(int ncid, const char* name, int* idp)
2284{
2285    NCdrno;
2286    int ret;
2287    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2288    ret = nc_inq_dimid(getnc3id(drno), nameidp);
2289    return THROW(ret);
2290}
2291
2292int
2293NCD2_inq_dim(int ncid, int dimid, char* name, size_t* lenp)
2294{
2295    NCdrno;
2296    int ret;
2297    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2298    ret = nc_inq_dim(getnc3id(drno), dimidnamelenp);
2299    return THROW(ret);
2300}
2301
2302int
2303NCD2_inq_unlimdim(int ncid, int* unlimdimidp)
2304{
2305    NCdrno;
2306    int ret;
2307    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2308    ret = nc_inq_unlimdim(getnc3id(drno), unlimdimidp);
2309    return THROW(ret);
2310}
2311
2312int
2313NCD2_rename_dim(int ncid, int dimid, const char* name)
2314{
2315    NCdrno;
2316    int ret;
2317    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2318    ret = nc_rename_dim(getnc3id(drno), dimidname);
2319    return THROW(ret);
2320}
2321
2322int
2323NCD2_inq_att(int ncid, int varid, const char* name,
2324     nc_typextypep, size_t* lenp)
2325{
2326    NCdrno;
2327    int ret;
2328    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2329    ret = nc_inq_att(getnc3id(drno), varidnamextypeplenp);
2330    return THROW(ret);
2331}
2332
2333int
2334NCD2_inq_attid(int ncid, int varid, const char *name, int *idp)
2335{
2336    NCdrno;
2337    int ret;
2338    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2339    ret = nc_inq_attid(getnc3id(drno), varidnameidp);
2340    return THROW(ret);
2341}
2342
2343int
2344NCD2_inq_attname(int ncid, int varid, int attnum, char* name)
2345{
2346    NCdrno;
2347    int ret;
2348    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2349    ret = nc_inq_attname(getnc3id(drno), varidattnumname);
2350    return THROW(ret);
2351}
2352
2353int
2354NCD2_rename_att(int ncid, int varid, const char* name, const char* newname)
2355{
2356    NCdrno;
2357    int ret;
2358    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2359    ret = nc_rename_att(getnc3id(drno), varidnamenewname);
2360    return THROW(ret);
2361}
2362
2363int
2364NCD2_del_att(int ncid, int varid, const char* p3)
2365{
2366    NCdrno;
2367    int ret;
2368    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2369    ret = nc_del_att(getnc3id(drno), varidp3);
2370    return THROW(ret);
2371}
2372
2373int
2374NCD2_get_att(int ncid, int varid, const char* name, void* valuenc_type t)
2375{
2376    NCdrno;
2377    int ret;
2378    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2379    ret = NCDISPATCH_get_att(getnc3id(drno), varidnamevaluet);
2380    return THROW(ret);
2381}
2382
2383int
2384NCD2_inq_var_all(int ncid, int varid, char *namenc_typextypep,
2385               int* ndimsp, int* dimidsp, int* nattsp,
2386               int* shufflep, int* deflatep, int* deflate_levelp,
2387               int* fletcher32p, int* contiguousp, size_t* chunksizesp,
2388               int* no_fill, void* fill_valuep, int* endiannessp,
2389        int* options_maskp, int* pixels_per_blockp)
2390{
2391    NCdrno;
2392    int ret;
2393    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2394    ret = NCDISPATCH_inq_var_all(getnc3id(drno), varidnamextypep,
2395               ndimspdimidspnattsp,
2396               shufflepdeflatepdeflate_levelp,
2397               fletcher32pcontiguouspchunksizesp,
2398               no_fillfill_valuependiannessp,
2399        options_maskppixels_per_blockp);
2400    return THROW(ret);
2401}
2402
2403int
2404NCD2_inq_varid(int ncid, const char *name, int *varidp)
2405{
2406    NCdrno;
2407    int ret;
2408    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2409    ret = nc_inq_varid(getnc3id(drno),name,varidp);
2410    return THROW(ret);
2411}
2412
2413int
2414NCD2_rename_var(int ncid, int varid, const char* name)
2415{
2416    NCdrno;
2417    int ret;
2418    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2419    ret = nc_rename_var(getnc3id(drno), varidname);
2420    return THROW(ret);
2421}
2422
2423int
2424NCD2_var_par_access(int ncid, int p2, int p3)
2425{
2426    return THROW(NC_ENOPAR);
2427}
2428
2429
2430#ifdef USE_NETCDF4
2431
2432int
2433NCD2_inq_ncid(int ncid, const char* name, int* grp_ncid)
2434{
2435    NCdrno;
2436    int ret;
2437    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2438    ret = nc_inq_ncid(getnc3id(drno), namegrp_ncid);
2439    return THROW(ret);
2440}
2441
2442int
2443NCD2_show_metadata(int ncid)
2444{
2445    NCdrno;
2446    int ret;
2447    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2448    ret = nc_show_metadata(getnc3id(drno));
2449    return THROW(ret);
2450}
2451
2452int
2453NCD2_inq_grps(int ncid, int* p2, int* p3)
2454{
2455    NCdrno;
2456    int ret;
2457    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2458    ret = nc_inq_grps(getnc3id(drno), p2p3);
2459    return THROW(ret);
2460}
2461
2462int
2463NCD2_inq_grpname(int ncid, char* p)
2464{
2465    NCdrno;
2466    int ret;
2467    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2468    ret = nc_inq_grpname(getnc3id(drno), p);
2469    return THROW(ret);
2470}
2471
2472
2473int
2474NCD2_inq_unlimdims(int ncid, int* p2, int* p3)
2475{
2476    NCdrno;
2477    int ret;
2478    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2479    ret = nc_inq_unlimdims(getnc3id(drno), p2p3);
2480    return THROW(ret);
2481}
2482
2483int
2484NCD2_inq_grpname_full(int ncid, size_t* p2, char* p3)
2485{
2486    NCdrno;
2487    int ret;
2488    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2489    ret = nc_inq_grpname_full(getnc3id(drno), p2p3);
2490    return THROW(ret);
2491}
2492
2493int
2494NCD2_inq_grp_parent(int ncid, int* p)
2495{
2496    NCdrno;
2497    int ret;
2498    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2499    ret = nc_inq_grp_parent(getnc3id(drno), p);
2500    return THROW(ret);
2501}
2502
2503int
2504NCD2_inq_grp_full_ncid(int ncid, const char* p2, int* p3)
2505{
2506    NCdrno;
2507    int ret;
2508    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2509    ret = nc_inq_grp_full_ncid(getnc3id(drno), p2p3);
2510    return THROW(ret);
2511}
2512
2513int
2514NCD2_inq_varids(int ncid, int* nvars, int* p)
2515{
2516    NCdrno;
2517    int ret;
2518    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2519    ret = nc_inq_varids(getnc3id(drno), nvarsp);
2520    return THROW(ret);
2521}
2522
2523int
2524NCD2_inq_dimids(int ncid, int* ndims, int* p3, int p4)
2525{
2526    NCdrno;
2527    int ret;
2528    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2529    ret = nc_inq_dimids(getnc3id(drno), ndimsp3p4);
2530    return THROW(ret);
2531}
2532
2533int
2534NCD2_inq_typeids(int ncid, int*  ntypes, int* p)
2535{
2536    NCdrno;
2537    int ret;
2538    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2539    ret = nc_inq_typeids(getnc3id(drno), ntypesp);
2540    return THROW(ret);
2541}
2542
2543int
2544NCD2_inq_type_equal(int ncidnc_type t1, int p3nc_type t2, int* p5)
2545{
2546    NCdrno;
2547    int ret;
2548    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2549    ret = nc_inq_type_equal(getnc3id(drno), t1p3t2p5);
2550    return THROW(ret);
2551}
2552
2553int
2554NCD2_inq_user_type(int ncidnc_type t, char* p3, size_t* p4nc_typep5,
2555                   size_t* p6, int* p7)
2556{
2557    NCdrno;
2558    int ret;
2559    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2560    ret = nc_inq_user_type(getnc3id(drno), tp3p4p5p6p7);
2561    return THROW(ret);
2562}
2563
2564int
2565NCD2_inq_typeid(int ncid, const char* namenc_typet)
2566{
2567    NCdrno;
2568    int ret;
2569    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2570    ret = nc_inq_typeid(getnc3id(drno), namet);
2571    return THROW(ret);
2572}
2573
2574int
2575NCD2_def_grp(int ncid, const char* p2, int* p3)
2576{
2577    NCdrno;
2578    int ret;
2579    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2580    ret = nc_def_grp(getnc3id(drno), p2p3);
2581    return THROW(ret);
2582}
2583
2584int
2585NCD2_rename_grp(int ncid, const char* p)
2586{
2587    NCdrno;
2588    int ret;
2589    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2590    ret = nc_rename_grp(getnc3id(drno), p);
2591    return THROW(ret);
2592}
2593
2594int
2595NCD2_def_compound(int ncid, size_t p2, const char* p3nc_typet)
2596{
2597    NCdrno;
2598    int ret;
2599    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2600    ret = nc_def_compound(getnc3id(drno), p2p3t);
2601    return THROW(ret);
2602}
2603
2604int
2605NCD2_insert_compound(int ncidnc_type t1, const char* p3, size_t p4nc_type t2)
2606{
2607    NCdrno;
2608    int ret;
2609    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2610    ret = nc_insert_compound(getnc3id(drno), t1p3p4t2);
2611    return THROW(ret);
2612}
2613
2614int
2615NCD2_insert_array_compound(int ncidnc_type t1, const char* p3, size_t p4,
2616   nc_type t2, int p6, const int* p7)
2617{
2618    NCdrno;
2619    int ret;
2620    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2621    ret = nc_insert_array_compound(getnc3id(drno), t1p3p4,  t2p6p7);
2622    return THROW(ret);
2623}
2624
2625int
2626NCD2_inq_compound_field(int ncidnc_type xtype, int fieldid, char *name,
2627       size_t *offsetpnc_typefield_typeidp, int *ndimsp,
2628       int *dim_sizesp)
2629{
2630    NCdrno;
2631    int ret;
2632    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2633    ret = nc_inq_compound_field(getnc3id(drno), xtypefieldidnameoffsetpfield_typeidpndimspdim_sizesp);
2634    return THROW(ret);
2635}
2636
2637int
2638NCD2_inq_compound_fieldindex(int ncidnc_type xtype, const char *name,
2639    int *fieldidp)
2640{
2641    NCdrno;
2642    int ret;
2643    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2644    ret = nc_inq_compound_fieldindex(getnc3id(drno), xtypenamefieldidp);
2645    return THROW(ret);
2646}
2647
2648int
2649NCD2_def_vlen(int ncid, const char* p2nc_type base_typeidnc_typet)
2650{
2651    NCdrno;
2652    int ret;
2653    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2654    ret = nc_def_vlen(getnc3id(drno), p2base_typeidt);
2655    return THROW(ret);
2656}
2657
2658int
2659NCD2_put_vlen_element(int ncid, int p2, void* p3, size_t p4, const void* p5)
2660{
2661    NCdrno;
2662    int ret;
2663    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2664    ret = nc_put_vlen_element(getnc3id(drno), p2p3p4p5);
2665    return THROW(ret);
2666}
2667
2668int
2669NCD2_get_vlen_element(int ncid, int p2, const void* p3, size_t* p4, void* p5)
2670{
2671    NCdrno;
2672    int ret;
2673    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2674    ret = nc_get_vlen_element(getnc3id(drno), p2p3p4p5);
2675    return THROW(ret);
2676}
2677
2678int
2679NCD2_def_enum(int ncidnc_type t1, const char* p3nc_typet)
2680{
2681    NCdrno;
2682    int ret;
2683    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2684    ret = nc_def_enum(getnc3id(drno), t1p3t);
2685    return THROW(ret);
2686}
2687
2688int
2689NCD2_insert_enum(int ncidnc_type t1, const char* p3, const void* p4)
2690{
2691    NCdrno;
2692    int ret;
2693    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2694    ret = nc_insert_enum(getnc3id(drno), t1p3p4);
2695    return THROW(ret);
2696}
2697
2698int
2699NCD2_inq_enum_member(int ncidnc_type t1, int p3, char* p4, void* p5)
2700{
2701    NCdrno;
2702    int ret;
2703    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2704    ret = nc_inq_enum_member(getnc3id(drno), t1p3p4p5);
2705    return THROW(ret);
2706}
2707
2708int
2709NCD2_inq_enum_ident(int ncidnc_type t1, long long p3, char* p4)
2710{
2711    NCdrno;
2712    int ret;
2713    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2714    ret = nc_inq_enum_ident(getnc3id(drno), t1p3p4);
2715    return THROW(ret);
2716}
2717
2718int
2719NCD2_def_opaque(int ncid, size_t p2, const char* p3nc_typet)
2720{
2721    NCdrno;
2722    int ret;
2723    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2724    ret = nc_def_opaque(getnc3id(drno), p2p3t);
2725    return THROW(ret);
2726}
2727
2728int
2729NCD2_def_var_deflate(int ncid, int p2, int p3, int p4, int p5)
2730{
2731    NCdrno;
2732    int ret;
2733    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2734    ret = nc_def_var_deflate(getnc3id(drno), p2p3p4p5);
2735    return THROW(ret);
2736}
2737
2738int
2739NCD2_def_var_fletcher32(int ncid, int p2, int p3)
2740{
2741    NCdrno;
2742    int ret;
2743    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2744    ret = nc_def_var_fletcher32(getnc3id(drno), p2p3);
2745    return THROW(ret);
2746}
2747
2748int
2749NCD2_def_var_chunking(int ncid, int p2, int p3, const size_t* p4)
2750{
2751    NCdrno;
2752    int ret;
2753    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2754    ret = nc_def_var_chunking(getnc3id(drno), p2p3p4);
2755    return THROW(ret);
2756}
2757
2758int
2759NCD2_def_var_fill(int ncid, int p2, int p3, const void* p4)
2760{
2761    NCdrno;
2762    int ret;
2763    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2764    ret = nc_def_var_fill(getnc3id(drno), p2p3p4);
2765    return THROW(ret);
2766}
2767
2768int
2769NCD2_def_var_endian(int ncid, int p2, int p3)
2770{
2771    NCdrno;
2772    int ret;
2773    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2774    ret = nc_def_var_endian(getnc3id(drno), p2p3);
2775    return THROW(ret);
2776}
2777
2778int
2779NCD2_set_var_chunk_cache(int ncid, int p2, size_t p3, size_t p4, float p5)
2780{
2781    NCdrno;
2782    int ret;
2783    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2784    ret = nc_set_var_chunk_cache(getnc3id(drno), p2p3p4p5);
2785    return THROW(ret);
2786}
2787
2788int
2789NCD2_get_var_chunk_cache(int ncid, int p2, size_t* p3, size_t* p4, float* p5)
2790{
2791    NCdrno;
2792    int ret;
2793    if((ret = NC_check_id(ncid, (NC**)&drno)) != NC_NOERR) return THROW(ret);
2794    ret = nc_get_var_chunk_cache(getnc3id(drno), p2p3p4p5);
2795    return THROW(ret);
2796}
2797
2798#endif // USE_NETCDF4


HyperKWIC - Version 7.20DA executed at 11:37 on 27 Oct 2017 | Polyhedron Solutions - INTERNAL USE | COMMERCIAL (Any O/S) SN 4AKIed