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