1 | /********************************************************************* |
---|
2 | * Copyright 1993, UCAR/Unidata |
---|
3 | * See netcdf/COPYRIGHT file for copying and redistribution conditions. |
---|
4 | * $Header: /upc/share/CVS/netcdf-3/libncdap3/ncdap3.c,v 1.94 2010/05/28 01:05:34 dmh Exp $ |
---|
5 | *********************************************************************/ |
---|
6 | |
---|
7 | #include "ncdap3.h" |
---|
8 | |
---|
9 | #ifdef HAVE_GETRLIMIT |
---|
10 | # ifdef HAVE_SYS_RESOURCE_H |
---|
11 | # include <sys/time.h> |
---|
12 | # endif |
---|
13 | # ifdef HAVE_SYS_RESOURCE_H |
---|
14 | # include <sys/resource.h> |
---|
15 | # endif |
---|
16 | #endif |
---|
17 | |
---|
18 | #include "nc3dispatch.h" |
---|
19 | #include "ncd3dispatch.h" |
---|
20 | #include "dapalign.h" |
---|
21 | #include "dapdump.h" |
---|
22 | |
---|
23 | static NCerror buildncstructures3(NCDAPCOMMON*); |
---|
24 | static NCerror builddims(NCDAPCOMMON*); |
---|
25 | static NCerror buildvars(NCDAPCOMMON*); |
---|
26 | static NCerror buildglobalattrs3(NCDAPCOMMON*,CDFnode* root); |
---|
27 | static NCerror buildattribute3a(NCDAPCOMMON*, NCattribute*, nc_type, int); |
---|
28 | |
---|
29 | |
---|
30 | static char* getdefinename(CDFnode* node); |
---|
31 | |
---|
32 | extern CDFnode* v4node; |
---|
33 | int nc3dinitialized = 0; |
---|
34 | |
---|
35 | /**************************************************/ |
---|
36 | /* Add an extra function whose sole purpose is to allow |
---|
37 | configure(.ac) to test for the presence of thiscode. |
---|
38 | */ |
---|
39 | int nc__opendap(void) {return 0;} |
---|
40 | |
---|
41 | /**************************************************/ |
---|
42 | /* Do local initialization */ |
---|
43 | |
---|
44 | int |
---|
45 | nc3dinitialize(void) |
---|
46 | { |
---|
47 | compute_nccalignments(); |
---|
48 | nc3dinitialized = 1; |
---|
49 | return NC_NOERR; |
---|
50 | } |
---|
51 | |
---|
52 | /**************************************************/ |
---|
53 | |
---|
54 | /* See ncd3dispatch.c for other version */ |
---|
55 | int |
---|
56 | NCD3_open(const char * path, int mode, |
---|
57 | int basepe, size_t *chunksizehintp, |
---|
58 | int useparallel, void* mpidata, |
---|
59 | NC_Dispatch* dispatch, NC** ncpp) |
---|
60 | { |
---|
61 | NCerror ncstat = NC_NOERR; |
---|
62 | OCerror ocstat = OC_NOERR; |
---|
63 | NC* drno = NULL; |
---|
64 | NCDAPCOMMON* dapcomm = NULL; |
---|
65 | const char* value; |
---|
66 | /* We will use a fake file descriptor as our internal in-memory filename */ |
---|
67 | char tmpname[32]; |
---|
68 | |
---|
69 | if(!nc3dinitialized) nc3dinitialize(); |
---|
70 | |
---|
71 | if(path == NULL) |
---|
72 | return NC_EDAPURL; |
---|
73 | if(dispatch == NULL) PANIC("NC3D_open: no dispatch table"); |
---|
74 | |
---|
75 | /* Setup our NC and NCDAPCOMMON state*/ |
---|
76 | drno = (NC*)calloc(1,sizeof(NC)); |
---|
77 | if(drno == NULL) {ncstat = NC_ENOMEM; goto done;} |
---|
78 | |
---|
79 | /* compute an ncid */ |
---|
80 | ncstat = add_to_NCList(drno); |
---|
81 | if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} |
---|
82 | |
---|
83 | dapcomm = (NCDAPCOMMON*)calloc(1,sizeof(NCDAPCOMMON)); |
---|
84 | if(dapcomm == NULL) {ncstat = NC_ENOMEM; goto done;} |
---|
85 | |
---|
86 | drno->dispatch = dispatch; |
---|
87 | drno->dispatchdata = dapcomm; |
---|
88 | drno->int_ncid = nc__pseudofd(); /* create a unique id */ |
---|
89 | dapcomm->controller = (NC*)drno; |
---|
90 | |
---|
91 | dapcomm->cdf.separator = "."; |
---|
92 | dapcomm->cdf.smallsizelimit = DFALTSMALLLIMIT; |
---|
93 | dapcomm->cdf.cache = createnccache(); |
---|
94 | |
---|
95 | #ifdef HAVE_GETRLIMIT |
---|
96 | { struct rlimit rl; |
---|
97 | if(getrlimit(RLIMIT_NOFILE, &rl) >= 0) { |
---|
98 | dapcomm->cdf.cache->cachecount = (size_t)(rl.rlim_cur / 2); |
---|
99 | } |
---|
100 | } |
---|
101 | #endif |
---|
102 | |
---|
103 | #ifdef OCCOMPILEBYDEFAULT |
---|
104 | /* set the compile flag by default */ |
---|
105 | dapcomm->oc.rawurltext = (char*)emalloc(strlen(path)+strlen("[compile]")+1); |
---|
106 | strcpy(dapcomm->oc.rawurltext,"[compile]"); |
---|
107 | strcat(dapcomm->oc.rawurltext, path); |
---|
108 | #else |
---|
109 | dapcomm->oc.rawurltext = strdup(path); |
---|
110 | #endif |
---|
111 | |
---|
112 | nc_uriparse(dapcomm->oc.rawurltext,&dapcomm->oc.url); |
---|
113 | |
---|
114 | /* parse the client parameters */ |
---|
115 | nc_uridecodeparams(dapcomm->oc.url); |
---|
116 | |
---|
117 | if(!constrainable34(dapcomm->oc.url)) |
---|
118 | SETFLAG(dapcomm->controls,NCF_UNCONSTRAINABLE); |
---|
119 | |
---|
120 | /* Use libsrc code for storing metadata */ |
---|
121 | |
---|
122 | snprintf(tmpname,sizeof(tmpname),"%d",drno->int_ncid); |
---|
123 | /* Now, use the file to create the netcdf file */ |
---|
124 | if(sizeof(size_t) == sizeof(unsigned int)) |
---|
125 | ncstat = nc_create(tmpname,NC_DISKLESS,&drno->substrate); |
---|
126 | else |
---|
127 | ncstat = nc_create(tmpname,NC_DISKLESS|NC_64BIT_OFFSET,&drno->substrate); |
---|
128 | if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} |
---|
129 | |
---|
130 | /* Avoid fill */ |
---|
131 | nc_set_fill(drno->substrate,NC_NOFILL,NULL); |
---|
132 | |
---|
133 | dapcomm->oc.dapconstraint = (DCEconstraint*)dcecreate(CES_CONSTRAINT); |
---|
134 | dapcomm->oc.dapconstraint->projections = nclistnew(); |
---|
135 | dapcomm->oc.dapconstraint->selections = nclistnew(); |
---|
136 | |
---|
137 | /* Parse constraints to make sure they are syntactically correct */ |
---|
138 | ncstat = parsedapconstraints(dapcomm,dapcomm->oc.url->constraint,dapcomm->oc.dapconstraint); |
---|
139 | if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} |
---|
140 | |
---|
141 | /* Complain if we are unconstrainable but have constraints */ |
---|
142 | if(FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE)) { |
---|
143 | if(dapcomm->oc.url->constraint != NULL |
---|
144 | && strlen(dapcomm->oc.url->constraint) > 0) { |
---|
145 | nclog(NCLOGWARN,"Attempt to constrain an unconstrainable data source: %s", |
---|
146 | dapcomm->oc.url->constraint); |
---|
147 | } |
---|
148 | } |
---|
149 | |
---|
150 | /* Construct a url for oc minus any parameters */ |
---|
151 | dapcomm->oc.urltext = nc_uribuild(dapcomm->oc.url,NULL,NULL, |
---|
152 | (NC_URIALL ^ NC_URICONSTRAINTS)); |
---|
153 | |
---|
154 | /* Pass to OC */ |
---|
155 | ocstat = oc_open(dapcomm->oc.urltext,&dapcomm->oc.conn); |
---|
156 | if(ocstat != OC_NOERR) {THROWCHK(ocstat); goto done;} |
---|
157 | |
---|
158 | nullfree(dapcomm->oc.urltext); /* clean up */ |
---|
159 | dapcomm->oc.urltext = NULL; |
---|
160 | |
---|
161 | /* process control client parameters */ |
---|
162 | applyclientparamcontrols3(dapcomm); |
---|
163 | |
---|
164 | /* Turn on logging; only do this after oc_open*/ |
---|
165 | if((value = paramvalue34(dapcomm,"log")) != NULL) { |
---|
166 | ncloginit(); |
---|
167 | ncsetlogging(1); |
---|
168 | nclogopen(value); |
---|
169 | oc_loginit(); |
---|
170 | oc_setlogging(1); |
---|
171 | oc_logopen(value); |
---|
172 | } |
---|
173 | |
---|
174 | /* fetch and build the (almost) unconstrained DDS for use as |
---|
175 | template */ |
---|
176 | ncstat = fetchtemplatemetadata3(dapcomm); |
---|
177 | if(ncstat != NC_NOERR) goto done; |
---|
178 | |
---|
179 | /* fetch and build the constrained DDS */ |
---|
180 | ncstat = fetchconstrainedmetadata3(dapcomm); |
---|
181 | if(ncstat != NC_NOERR) goto done; |
---|
182 | |
---|
183 | #ifdef DEBUG2 |
---|
184 | fprintf(stderr,"constrained dds: %s\n",dumptree(dapcomm->cdf.ddsroot)); |
---|
185 | #endif |
---|
186 | |
---|
187 | |
---|
188 | /* The following actions are (mostly) WRT to the constrained tree */ |
---|
189 | |
---|
190 | /* Accumulate useful nodes sets */ |
---|
191 | ncstat = computecdfnodesets3(dapcomm); |
---|
192 | if(ncstat) {THROWCHK(ncstat); goto done;} |
---|
193 | |
---|
194 | /* Fix grids */ |
---|
195 | ncstat = fixgrids3(dapcomm); |
---|
196 | if(ncstat) {THROWCHK(ncstat); goto done;} |
---|
197 | |
---|
198 | /* Locate and mark usable sequences */ |
---|
199 | ncstat = sequencecheck3(dapcomm); |
---|
200 | if(ncstat) {THROWCHK(ncstat); goto done;} |
---|
201 | |
---|
202 | /* suppress variables not in usable sequences */ |
---|
203 | ncstat = suppressunusablevars3(dapcomm); |
---|
204 | if(ncstat) {THROWCHK(ncstat); goto done;} |
---|
205 | |
---|
206 | /* apply client parameters */ |
---|
207 | ncstat = applyclientparams34(dapcomm); |
---|
208 | if(ncstat) {THROWCHK(ncstat); goto done;} |
---|
209 | |
---|
210 | /* Add (as needed) string dimensions*/ |
---|
211 | ncstat = addstringdims(dapcomm); |
---|
212 | if(ncstat) {THROWCHK(ncstat); goto done;} |
---|
213 | |
---|
214 | if(nclistlength(dapcomm->cdf.seqnodes) > 0) { |
---|
215 | /* Build the sequence related dimensions */ |
---|
216 | ncstat = defseqdims(dapcomm); |
---|
217 | if(ncstat) {THROWCHK(ncstat); goto done;} |
---|
218 | } |
---|
219 | |
---|
220 | /* Define the dimsetplus and dimsetall lists */ |
---|
221 | ncstat = definedimsets3(dapcomm); |
---|
222 | if(ncstat) {THROWCHK(ncstat); goto done;} |
---|
223 | |
---|
224 | /* Re-compute the dimension names*/ |
---|
225 | ncstat = computecdfdimnames34(dapcomm); |
---|
226 | if(ncstat) {THROWCHK(ncstat); goto done;} |
---|
227 | |
---|
228 | /* Deal with zero size dimensions */ |
---|
229 | ncstat = fixzerodims3(dapcomm); |
---|
230 | if(ncstat) {THROWCHK(ncstat); goto done;} |
---|
231 | |
---|
232 | /* Attempt to use the DODS_EXTRA info to turn |
---|
233 | one of the dimensions into unlimited. |
---|
234 | Assume computecdfdimnames34 has already been called. |
---|
235 | */ |
---|
236 | ncstat = defrecorddim3(dapcomm); |
---|
237 | if(ncstat) {THROWCHK(ncstat); goto done;} |
---|
238 | if(dapcomm->cdf.recorddimname != NULL |
---|
239 | && nclistlength(dapcomm->cdf.seqnodes) > 0) { |
---|
240 | /*nclog(NCLOGWARN,"unlimited dimension specified, but sequences exist in DDS");*/ |
---|
241 | PANIC("unlimited dimension specified, but sequences exist in DDS"); |
---|
242 | } |
---|
243 | |
---|
244 | /* Re-compute the var names*/ |
---|
245 | ncstat = computecdfvarnames3(dapcomm,dapcomm->cdf.ddsroot,dapcomm->cdf.varnodes); |
---|
246 | if(ncstat) {THROWCHK(ncstat); goto done;} |
---|
247 | |
---|
248 | /* Transfer data from the unconstrained DDS data to the unconstrained DDS */ |
---|
249 | ncstat = dimimprint3(dapcomm); |
---|
250 | if(ncstat) goto done; |
---|
251 | |
---|
252 | /* Process the constraints to map to the constrained CDF tree */ |
---|
253 | /* (must follow fixgrids3 */ |
---|
254 | ncstat = mapconstraints3(dapcomm->oc.dapconstraint,dapcomm->cdf.ddsroot); |
---|
255 | if(ncstat != NC_NOERR) goto done; |
---|
256 | |
---|
257 | /* Canonicalize the constraint */ |
---|
258 | ncstat = fixprojections(dapcomm->oc.dapconstraint->projections); |
---|
259 | if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} |
---|
260 | |
---|
261 | /* Fill in segment information */ |
---|
262 | ncstat = qualifyconstraints3(dapcomm->oc.dapconstraint); |
---|
263 | if(ncstat != NC_NOERR) goto done; |
---|
264 | |
---|
265 | /* using the modified constraint, rebuild the constraint string */ |
---|
266 | if(FLAGSET(dapcomm->controls,NCF_UNCONSTRAINABLE)) { |
---|
267 | /* ignore all constraints */ |
---|
268 | dapcomm->oc.urltext = nc_uribuild(dapcomm->oc.url,NULL,NULL,0); |
---|
269 | } else { |
---|
270 | char* constraintstring = buildconstraintstring3(dapcomm->oc.dapconstraint); |
---|
271 | nc_urisetconstraints(dapcomm->oc.url,constraintstring); |
---|
272 | nullfree(constraintstring); |
---|
273 | dapcomm->oc.urltext = nc_uribuild(dapcomm->oc.url,NULL,NULL,NC_URICONSTRAINTS); |
---|
274 | } |
---|
275 | |
---|
276 | #ifdef DEBUG |
---|
277 | fprintf(stderr,"ncdap3: final constraint: %s\n",dapcomm->oc.url->constraint); |
---|
278 | #endif |
---|
279 | |
---|
280 | /* Estimate the variable sizes */ |
---|
281 | estimatevarsizes3(dapcomm); |
---|
282 | |
---|
283 | /* Build the meta data */ |
---|
284 | ncstat = buildncstructures3(dapcomm); |
---|
285 | if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} |
---|
286 | |
---|
287 | /* Do any necessary data prefetch */ |
---|
288 | if(FLAGSET(dapcomm->controls,NCF_PREFETCH)) { |
---|
289 | ncstat = prefetchdata3(dapcomm); |
---|
290 | if(ncstat != NC_NOERR) { |
---|
291 | del_from_NCList((NC*)drno); /* undefine here */ |
---|
292 | {THROWCHK(ncstat); goto done;} |
---|
293 | } |
---|
294 | } |
---|
295 | |
---|
296 | #ifdef BUG |
---|
297 | /* The libsrc code (NC_begins) assumes that |
---|
298 | a created files is new and hence must have an |
---|
299 | unlimited dimension of 0 initially, which will |
---|
300 | wipe out the effect of the NC_set_numrecs in builddims. |
---|
301 | There is no easy workaround, so we suppress the call |
---|
302 | to nc_enddef |
---|
303 | */ |
---|
304 | ncstat = nc_enddef(drno->substrate); |
---|
305 | if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} |
---|
306 | #endif |
---|
307 | |
---|
308 | if(ncpp) *ncpp = (NC*)drno; |
---|
309 | |
---|
310 | return ncstat; |
---|
311 | |
---|
312 | done: |
---|
313 | if(drno != NULL) NCD3_close(drno->ext_ncid); |
---|
314 | if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat); |
---|
315 | return THROW(ncstat); |
---|
316 | } |
---|
317 | |
---|
318 | int |
---|
319 | NCD3_close(int ncid) |
---|
320 | { |
---|
321 | NC* drno; |
---|
322 | NCDAPCOMMON* dapcomm; |
---|
323 | int ncstatus = NC_NOERR; |
---|
324 | |
---|
325 | ncstatus = NC_check_id(ncid, (NC**)&drno); |
---|
326 | if(ncstatus != NC_NOERR) return THROW(ncstatus); |
---|
327 | |
---|
328 | dapcomm = (NCDAPCOMMON*)drno->dispatchdata; |
---|
329 | ncstatus = nc_abort(drno->substrate); |
---|
330 | |
---|
331 | /* remove ourselves from NClist */ |
---|
332 | del_from_NCList(drno); |
---|
333 | /* clean NC* */ |
---|
334 | freeNCDAPCOMMON(dapcomm); |
---|
335 | if(drno->path != NULL) free(drno->path); |
---|
336 | free(drno); |
---|
337 | return THROW(ncstatus); |
---|
338 | } |
---|
339 | |
---|
340 | /**************************************************/ |
---|
341 | static NCerror |
---|
342 | buildncstructures3(NCDAPCOMMON* dapcomm) |
---|
343 | { |
---|
344 | NCerror ncstat = NC_NOERR; |
---|
345 | CDFnode* dds = dapcomm->cdf.ddsroot; |
---|
346 | NC* ncsub; |
---|
347 | NC_check_id(dapcomm->controller->substrate,&ncsub); |
---|
348 | |
---|
349 | ncstat = buildglobalattrs3(dapcomm,dds); |
---|
350 | if(ncstat != NC_NOERR) goto done; |
---|
351 | |
---|
352 | ncstat = builddims(dapcomm); |
---|
353 | if(ncstat != NC_NOERR) goto done; |
---|
354 | |
---|
355 | ncstat = buildvars(dapcomm); |
---|
356 | if(ncstat != NC_NOERR) goto done; |
---|
357 | |
---|
358 | done: |
---|
359 | return THROW(ncstat); |
---|
360 | } |
---|
361 | |
---|
362 | static NCerror |
---|
363 | builddims(NCDAPCOMMON* dapcomm) |
---|
364 | { |
---|
365 | int i; |
---|
366 | NCerror ncstat = NC_NOERR; |
---|
367 | int dimid; |
---|
368 | NClist* dimset = NULL; |
---|
369 | NC* drno = dapcomm->controller; |
---|
370 | NC* ncsub; |
---|
371 | char* definename; |
---|
372 | |
---|
373 | /* collect all dimensions from variables */ |
---|
374 | dimset = dapcomm->cdf.dimnodes; |
---|
375 | |
---|
376 | /* Sort by fullname just for the fun of it */ |
---|
377 | for(;;) { |
---|
378 | int last = nclistlength(dimset) - 1; |
---|
379 | int swap = 0; |
---|
380 | for(i=0;i<last;i++) { |
---|
381 | CDFnode* dim1 = (CDFnode*)nclistget(dimset,i); |
---|
382 | CDFnode* dim2 = (CDFnode*)nclistget(dimset,i+1); |
---|
383 | if(strcmp(dim1->ncfullname,dim2->ncfullname) > 0) { |
---|
384 | nclistset(dimset,i,(ncelem)dim2); |
---|
385 | nclistset(dimset,i+1,(ncelem)dim1); |
---|
386 | swap = 1; |
---|
387 | break; |
---|
388 | } |
---|
389 | } |
---|
390 | if(!swap) break; |
---|
391 | } |
---|
392 | |
---|
393 | /* Define unlimited only if needed */ |
---|
394 | if(dapcomm->cdf.recorddim != NULL) { |
---|
395 | CDFnode* unlimited = dapcomm->cdf.recorddim; |
---|
396 | definename = getdefinename(unlimited); |
---|
397 | ncstat = nc_def_dim(drno->substrate, |
---|
398 | definename, |
---|
399 | NC_UNLIMITED, |
---|
400 | &unlimited->ncid); |
---|
401 | nullfree(definename); |
---|
402 | if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} |
---|
403 | |
---|
404 | /* get the id for the substrate */ |
---|
405 | ncstat = NC_check_id(drno->substrate,&ncsub); |
---|
406 | if(ncstat != NC_NOERR) {THROWCHK(ncstat); goto done;} |
---|
407 | |
---|
408 | /* Set the effective size of UNLIMITED; |
---|
409 | note that this cannot easily be done thru the normal API.*/ |
---|
410 | NC_set_numrecs(ncsub,unlimited->dim.declsize); |
---|
411 | } |
---|
412 | |
---|
413 | for(i=0;i<nclistlength(dimset);i++) { |
---|
414 | CDFnode* dim = (CDFnode*)nclistget(dimset,i); |
---|
415 | if(dim->dim.basedim != NULL) continue; /* handle below */ |
---|
416 | if(DIMFLAG(dim,CDFDIMRECORD)) continue; /* defined above */ |
---|
417 | #ifdef DEBUG1 |
---|
418 | fprintf(stderr,"define: dim: %s=%ld\n",dim->ncfullname,(long)dim->dim.declsize); |
---|
419 | #endif |
---|
420 | definename = getdefinename(dim); |
---|
421 | ncstat = nc_def_dim(drno->substrate,definename,dim->dim.declsize,&dimid); |
---|
422 | if(ncstat != NC_NOERR) { |
---|
423 | THROWCHK(ncstat); goto done; |
---|
424 | } |
---|
425 | nullfree(definename); |
---|
426 | dim->ncid = dimid; |
---|
427 | } |
---|
428 | |
---|
429 | /* Make all duplicate dims have same dimid as basedim*/ |
---|
430 | /* (see computecdfdimnames)*/ |
---|
431 | for(i=0;i<nclistlength(dimset);i++) { |
---|
432 | CDFnode* dim = (CDFnode*)nclistget(dimset,i); |
---|
433 | if(dim->dim.basedim != NULL) { |
---|
434 | dim->ncid = dim->dim.basedim->ncid; |
---|
435 | } |
---|
436 | } |
---|
437 | done: |
---|
438 | nclistfree(dimset); |
---|
439 | return THROW(ncstat); |
---|
440 | } |
---|
441 | |
---|
442 | /* Simultaneously build any associated attributes*/ |
---|
443 | /* and any necessary pseudo-dimensions for string types*/ |
---|
444 | static NCerror |
---|
445 | buildvars(NCDAPCOMMON* dapcomm) |
---|
446 | { |
---|
447 | int i,j; |
---|
448 | NCerror ncstat = NC_NOERR; |
---|
449 | int varid; |
---|
450 | NClist* varnodes = dapcomm->cdf.varnodes; |
---|
451 | NC* drno = dapcomm->controller; |
---|
452 | char* definename; |
---|
453 | |
---|
454 | ASSERT((varnodes != NULL)); |
---|
455 | for(i=0;i<nclistlength(varnodes);i++) { |
---|
456 | CDFnode* var = (CDFnode*)nclistget(varnodes,i); |
---|
457 | int dimids[NC_MAX_VAR_DIMS]; |
---|
458 | unsigned int ncrank; |
---|
459 | NClist* vardims = NULL; |
---|
460 | |
---|
461 | if(!var->visible) continue; |
---|
462 | if(var->array.basevar != NULL) continue; |
---|
463 | |
---|
464 | #ifdef DEBUG1 |
---|
465 | fprintf(stderr,"buildvars.candidate=|%s|\n",var->ncfullname); |
---|
466 | #endif |
---|
467 | |
---|
468 | vardims = var->array.dimsetall; |
---|
469 | ncrank = nclistlength(vardims); |
---|
470 | if(ncrank > 0) { |
---|
471 | for(j=0;j<ncrank;j++) { |
---|
472 | CDFnode* dim = (CDFnode*)nclistget(vardims,j); |
---|
473 | dimids[j] = dim->ncid; |
---|
474 | } |
---|
475 | } |
---|
476 | |
---|
477 | |
---|
478 | |
---|
479 | definename = getdefinename(var); |
---|
480 | |
---|
481 | #ifdef DEBUG1 |
---|
482 | fprintf(stderr,"define: var: %s/%s", |
---|
483 | definename,var->ocname); |
---|
484 | if(ncrank > 0) { |
---|
485 | int k; |
---|
486 | for(k=0;k<ncrank;k++) { |
---|
487 | CDFnode* dim = (CDFnode*)nclistget(vardims,k); |
---|
488 | fprintf(stderr,"[%ld]",dim->dim.declsize); |
---|
489 | } |
---|
490 | } |
---|
491 | fprintf(stderr,"\n"); |
---|
492 | #endif |
---|
493 | ncstat = nc_def_var(drno->substrate, |
---|
494 | definename, |
---|
495 | var->externaltype, |
---|
496 | ncrank, |
---|
497 | (ncrank==0?NULL:dimids), |
---|
498 | &varid); |
---|
499 | nullfree(definename); |
---|
500 | if(ncstat != NC_NOERR) { |
---|
501 | THROWCHK(ncstat); |
---|
502 | goto done; |
---|
503 | } |
---|
504 | var->ncid = varid; |
---|
505 | if(var->attributes != NULL) { |
---|
506 | for(j=0;j<nclistlength(var->attributes);j++) { |
---|
507 | NCattribute* att = (NCattribute*)nclistget(var->attributes,j); |
---|
508 | ncstat = buildattribute3a(dapcomm,att,var->etype,varid); |
---|
509 | if(ncstat != NC_NOERR) goto done; |
---|
510 | } |
---|
511 | } |
---|
512 | /* Tag the variable with its DAP path */ |
---|
513 | if(paramcheck34(dapcomm,"show","projection")) |
---|
514 | showprojection3(dapcomm,var); |
---|
515 | } |
---|
516 | done: |
---|
517 | return THROW(ncstat); |
---|
518 | } |
---|
519 | |
---|
520 | static NCerror |
---|
521 | buildglobalattrs3(NCDAPCOMMON* dapcomm, CDFnode* root) |
---|
522 | { |
---|
523 | int i; |
---|
524 | NCerror ncstat = NC_NOERR; |
---|
525 | const char* txt; |
---|
526 | char *nltxt, *p; |
---|
527 | NCbytes* buf = NULL; |
---|
528 | NClist* cdfnodes; |
---|
529 | NC* drno = dapcomm->controller; |
---|
530 | |
---|
531 | if(root->attributes != NULL) { |
---|
532 | for(i=0;i<nclistlength(root->attributes);i++) { |
---|
533 | NCattribute* att = (NCattribute*)nclistget(root->attributes,i); |
---|
534 | ncstat = buildattribute3a(dapcomm,att,NC_NAT,NC_GLOBAL); |
---|
535 | if(ncstat != NC_NOERR) goto done; |
---|
536 | } |
---|
537 | } |
---|
538 | |
---|
539 | /* Add global attribute identifying the sequence dimensions */ |
---|
540 | if(paramcheck34(dapcomm,"show","seqdims")) { |
---|
541 | buf = ncbytesnew(); |
---|
542 | cdfnodes = dapcomm->cdf.ddsroot->tree->nodes; |
---|
543 | for(i=0;i<nclistlength(cdfnodes);i++) { |
---|
544 | CDFnode* dim = (CDFnode*)nclistget(cdfnodes,i); |
---|
545 | if(dim->nctype != NC_Dimension) continue; |
---|
546 | if(DIMFLAG(dim,CDFDIMSEQ)) { |
---|
547 | char* cname = cdflegalname3(dim->ocname); |
---|
548 | if(ncbyteslength(buf) > 0) ncbytescat(buf,", "); |
---|
549 | ncbytescat(buf,cname); |
---|
550 | nullfree(cname); |
---|
551 | } |
---|
552 | } |
---|
553 | if(ncbyteslength(buf) > 0) { |
---|
554 | ncstat = nc_put_att_text(drno->substrate,NC_GLOBAL,"_sequence_dimensions", |
---|
555 | ncbyteslength(buf),ncbytescontents(buf)); |
---|
556 | } |
---|
557 | } |
---|
558 | |
---|
559 | /* Define some additional system global attributes |
---|
560 | depending on show= clientparams*/ |
---|
561 | /* Ignore failures*/ |
---|
562 | |
---|
563 | if(paramcheck34(dapcomm,"show","translate")) { |
---|
564 | /* Add a global attribute to show the translation */ |
---|
565 | ncstat = nc_put_att_text(drno->substrate,NC_GLOBAL,"_translate", |
---|
566 | strlen("netcdf-3"),"netcdf-3"); |
---|
567 | } |
---|
568 | if(paramcheck34(dapcomm,"show","url")) { |
---|
569 | if(dapcomm->oc.rawurltext != NULL) |
---|
570 | ncstat = nc_put_att_text(drno->substrate,NC_GLOBAL,"_url", |
---|
571 | strlen(dapcomm->oc.rawurltext),dapcomm->oc.rawurltext); |
---|
572 | } |
---|
573 | if(paramcheck34(dapcomm,"show","dds")) { |
---|
574 | txt = NULL; |
---|
575 | if(dapcomm->cdf.ddsroot != NULL) |
---|
576 | txt = oc_inq_text(dapcomm->oc.conn,dapcomm->cdf.ddsroot->ocnode); |
---|
577 | if(txt != NULL) { |
---|
578 | /* replace newlines with spaces*/ |
---|
579 | nltxt = nulldup(txt); |
---|
580 | for(p=nltxt;*p;p++) {if(*p == '\n' || *p == '\r' || *p == '\t') {*p = ' ';}}; |
---|
581 | ncstat = nc_put_att_text(drno->substrate,NC_GLOBAL,"_dds",strlen(nltxt),nltxt); |
---|
582 | nullfree(nltxt); |
---|
583 | } |
---|
584 | } |
---|
585 | if(paramcheck34(dapcomm,"show","das")) { |
---|
586 | txt = NULL; |
---|
587 | if(dapcomm->oc.ocdasroot != OCNULL) |
---|
588 | txt = oc_inq_text(dapcomm->oc.conn,dapcomm->oc.ocdasroot); |
---|
589 | if(txt != NULL) { |
---|
590 | nltxt = nulldup(txt); |
---|
591 | for(p=nltxt;*p;p++) {if(*p == '\n' || *p == '\r' || *p == '\t') {*p = ' ';}}; |
---|
592 | ncstat = nc_put_att_text(drno->substrate,NC_GLOBAL,"_das",strlen(nltxt),nltxt); |
---|
593 | nullfree(nltxt); |
---|
594 | } |
---|
595 | } |
---|
596 | |
---|
597 | done: |
---|
598 | ncbytesfree(buf); |
---|
599 | return THROW(ncstat); |
---|
600 | } |
---|
601 | |
---|
602 | static NCerror |
---|
603 | buildattribute3a(NCDAPCOMMON* dapcomm, NCattribute* att, nc_type vartype, int varid) |
---|
604 | { |
---|
605 | int i; |
---|
606 | NCerror ncstat = NC_NOERR; |
---|
607 | unsigned int nvalues = nclistlength(att->values); |
---|
608 | NC* drno = dapcomm->controller; |
---|
609 | |
---|
610 | /* If the type of the attribute is string, then we need*/ |
---|
611 | /* to convert to a single character string by concatenation. |
---|
612 | modified: 10/23/09 to insert newlines. |
---|
613 | modified: 10/28/09 to interpret escapes |
---|
614 | */ |
---|
615 | if(att->etype == NC_STRING || att->etype == NC_URL) { |
---|
616 | char* newstring; |
---|
617 | size_t newlen = 0; |
---|
618 | for(i=0;i<nvalues;i++) { |
---|
619 | char* s = (char*)nclistget(att->values,i); |
---|
620 | newlen += (1+strlen(s)); |
---|
621 | } |
---|
622 | newstring = (char*)malloc(newlen); |
---|
623 | MEMCHECK(newstring,NC_ENOMEM); |
---|
624 | newstring[0] = '\0'; |
---|
625 | for(i=0;i<nvalues;i++) { |
---|
626 | char* s = (char*)nclistget(att->values,i); |
---|
627 | if(i > 0) strcat(newstring,"\n"); |
---|
628 | strcat(newstring,s); |
---|
629 | } |
---|
630 | dapexpandescapes(newstring); |
---|
631 | if(newstring[0]=='\0') |
---|
632 | ncstat = nc_put_att_text(drno->substrate,varid,att->name,1,newstring); |
---|
633 | else |
---|
634 | ncstat = nc_put_att_text(drno->substrate,varid,att->name,strlen(newstring),newstring); |
---|
635 | free(newstring); |
---|
636 | } else { |
---|
637 | nc_type atype; |
---|
638 | unsigned int typesize; |
---|
639 | void* mem; |
---|
640 | /* It turns out that some servers upgrade the type |
---|
641 | of _FillValue in order to correctly preserve the |
---|
642 | original value. However, since the type of the |
---|
643 | underlying variable is not changes, we get a type |
---|
644 | mismatch. So, make sure the type of the fillvalue |
---|
645 | is the same as that of the controlling variable. |
---|
646 | */ |
---|
647 | if(varid != NC_GLOBAL && strcmp(att->name,"_FillValue")==0) |
---|
648 | atype = nctypeconvert(dapcomm,vartype); |
---|
649 | else |
---|
650 | atype = nctypeconvert(dapcomm,att->etype); |
---|
651 | typesize = nctypesizeof(atype); |
---|
652 | mem = malloc(typesize * nvalues); |
---|
653 | ncstat = dapcvtattrval3(atype,mem,att->values); |
---|
654 | ncstat = nc_put_att(drno->substrate,varid,att->name,atype,nvalues,mem); |
---|
655 | nullfree(mem); |
---|
656 | } |
---|
657 | return THROW(ncstat); |
---|
658 | } |
---|
659 | |
---|
660 | static char* |
---|
661 | getdefinename(CDFnode* node) |
---|
662 | { |
---|
663 | char* spath = NULL; |
---|
664 | NClist* path = NULL; |
---|
665 | |
---|
666 | switch (node->nctype) { |
---|
667 | case NC_Primitive: |
---|
668 | /* The define name is same as the fullname with elided nodes */ |
---|
669 | path = nclistnew(); |
---|
670 | collectnodepath3(node,path,!WITHDATASET); |
---|
671 | spath = makepathstring3(path,".",PATHNC|PATHELIDE); |
---|
672 | nclistfree(path); |
---|
673 | break; |
---|
674 | |
---|
675 | case NC_Dimension: |
---|
676 | /* Return just the node's ncname */ |
---|
677 | spath = nulldup(node->ncbasename); |
---|
678 | break; |
---|
679 | |
---|
680 | default: |
---|
681 | PANIC("unexpected nctype"); |
---|
682 | } |
---|
683 | return spath; |
---|
684 | } |
---|
685 | |
---|
686 | int |
---|
687 | NCDAP_ping(const char* url) |
---|
688 | { |
---|
689 | OCerror ocstat = OC_NOERR; |
---|
690 | ocstat = oc_ping(url); |
---|
691 | return ocerrtoncerr(ocstat); |
---|
692 | } |
---|