ncdap3.c 21 KB

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