[409] | 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 | } |
---|