common34.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924
  1. /*********************************************************************
  2. * Copyright 1993, UCAR/Unidata
  3. * See netcdf/COPYRIGHT file for copying and redistribution conditions.
  4. * $Header: /upc/share/CVS/netcdf-3/libncdap3/common34.c,v 1.29 2010/05/25 13:53:02 ed 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 "dapdump.h"
  16. extern CDFnode* v4node;
  17. /* Define the set of protocols known to be constrainable */
  18. static char* constrainableprotocols[] = {"http", "https",NULL};
  19. static NCerror buildcdftree34r(NCDAPCOMMON*,OCobject,CDFnode*,CDFtree*,CDFnode**);
  20. static void defdimensions(OCobject, CDFnode*, NCDAPCOMMON*, CDFtree*);
  21. static NCerror attachsubset34r(CDFnode*, CDFnode*);
  22. static void free1cdfnode34(CDFnode* node);
  23. /* Define Procedures that are common to both
  24. libncdap3 and libncdap4
  25. */
  26. /* Ensure every node has an initial base name defined and fullname */
  27. /* Exceptions: anonymous dimensions. */
  28. static NCerror
  29. fix1node34(NCDAPCOMMON* nccomm, CDFnode* node)
  30. {
  31. if(node->nctype == NC_Dimension && node->ocname == NULL) return NC_NOERR;
  32. ASSERT((node->ocname != NULL));
  33. nullfree(node->ncbasename);
  34. node->ncbasename = cdflegalname3(node->ocname);
  35. if(node->ncbasename == NULL) return NC_ENOMEM;
  36. nullfree(node->ncfullname);
  37. node->ncfullname = makecdfpathstring3(node,nccomm->cdf.separator);
  38. if(node->ncfullname == NULL) return NC_ENOMEM;
  39. if(node->nctype == NC_Primitive)
  40. node->externaltype = nctypeconvert(nccomm,node->etype);
  41. return NC_NOERR;
  42. }
  43. NCerror
  44. fixnodes34(NCDAPCOMMON* nccomm, NClist* cdfnodes)
  45. {
  46. int i;
  47. for(i=0;i<nclistlength(cdfnodes);i++) {
  48. CDFnode* node = (CDFnode*)nclistget(cdfnodes,i);
  49. NCerror err = fix1node34(nccomm,node);
  50. if(err) return err;
  51. }
  52. return NC_NOERR;
  53. }
  54. NCerror
  55. fixgrid34(NCDAPCOMMON* nccomm, CDFnode* grid)
  56. {
  57. unsigned int i,glen;
  58. CDFnode* array;
  59. glen = nclistlength(grid->subnodes);
  60. array = (CDFnode*)nclistget(grid->subnodes,0);
  61. if(nccomm->controls.flags & (NCF_NC3)) {
  62. /* Rename grid Array: variable, but leave its oc base name alone */
  63. nullfree(array->ncbasename);
  64. array->ncbasename = nulldup(grid->ncbasename);
  65. if(!array->ncbasename) return NC_ENOMEM;
  66. }
  67. /* validate and modify the grid structure */
  68. if((glen-1) != nclistlength(array->array.dimset0)) goto invalid;
  69. for(i=1;i<glen;i++) {
  70. CDFnode* arraydim = (CDFnode*)nclistget(array->array.dimset0,i-1);
  71. CDFnode* map = (CDFnode*)nclistget(grid->subnodes,i);
  72. CDFnode* mapdim;
  73. /* map must have 1 dimension */
  74. if(nclistlength(map->array.dimset0) != 1) goto invalid;
  75. /* and the map name must match the ith array dimension */
  76. if(arraydim->ocname != NULL && map->ocname != NULL
  77. && strcmp(arraydim->ocname,map->ocname) != 0)
  78. goto invalid;
  79. /* and the map name must match its dim name (if any) */
  80. mapdim = (CDFnode*)nclistget(map->array.dimset0,0);
  81. if(mapdim->ocname != NULL && map->ocname != NULL
  82. && strcmp(mapdim->ocname,map->ocname) != 0)
  83. goto invalid;
  84. /* Add appropriate names for the anonymous dimensions */
  85. /* Do the map name first, so the array dim may inherit */
  86. if(mapdim->ocname == NULL) {
  87. nullfree(mapdim->ncbasename);
  88. mapdim->ocname = nulldup(map->ocname);
  89. if(!mapdim->ocname) return NC_ENOMEM;
  90. mapdim->ncbasename = cdflegalname3(mapdim->ocname);
  91. if(!mapdim->ncbasename) return NC_ENOMEM;
  92. }
  93. if(arraydim->ocname == NULL) {
  94. nullfree(arraydim->ncbasename);
  95. arraydim->ocname = nulldup(map->ocname);
  96. if(!arraydim->ocname) return NC_ENOMEM;
  97. arraydim->ncbasename = cdflegalname3(arraydim->ocname);
  98. if(!arraydim->ncbasename) return NC_ENOMEM;
  99. }
  100. if(FLAGSET(nccomm->controls,(NCF_NCDAP|NCF_NC3))) {
  101. char tmp[3*NC_MAX_NAME];
  102. /* Add the grid name to the basename of the map */
  103. snprintf(tmp,sizeof(tmp),"%s%s%s",map->container->ncbasename,
  104. nccomm->cdf.separator,
  105. map->ncbasename);
  106. nullfree(map->ncbasename);
  107. map->ncbasename = nulldup(tmp);
  108. if(!map->ncbasename) return NC_ENOMEM;
  109. }
  110. }
  111. return NC_NOERR;
  112. invalid:
  113. return NC_EINVAL; /* mal-formed grid */
  114. }
  115. /**
  116. * Given an anonymous dimension, compute the
  117. * effective 0-based index wrt to the specified var.
  118. * The result should mimic the libnc-dap indices.
  119. */
  120. static void
  121. computedimindexanon3(CDFnode* dim, CDFnode* var)
  122. {
  123. int i;
  124. NClist* dimset = var->array.dimsetall;
  125. for(i=0;i<nclistlength(dimset);i++) {
  126. CDFnode* candidate = (CDFnode*)nclistget(dimset,i);
  127. if(dim == candidate) {
  128. dim->dim.index1=i+1;
  129. return;
  130. }
  131. }
  132. }
  133. /* Replace dims in a list with their corresponding basedim */
  134. static void
  135. replacedims(NClist* dims)
  136. {
  137. int i;
  138. for(i=0;i<nclistlength(dims);i++) {
  139. CDFnode* dim = (CDFnode*)nclistget(dims,i);
  140. CDFnode* basedim = dim->dim.basedim;
  141. if(basedim == NULL) continue;
  142. nclistset(dims,i,(ncelem)basedim);
  143. }
  144. }
  145. /**
  146. Two dimensions are equivalent if
  147. 1. they have the same size
  148. 2. neither are anonymous
  149. 3. they ave the same names.
  150. */
  151. static int
  152. equivalentdim(CDFnode* basedim, CDFnode* dupdim)
  153. {
  154. if(dupdim->dim.declsize != basedim->dim.declsize) return 0;
  155. if(basedim->ocname == NULL && dupdim->ocname == NULL) return 0;
  156. if(basedim->ocname == NULL || dupdim->ocname == NULL) return 0;
  157. if(strcmp(dupdim->ocname,basedim->ocname) != 0) return 0;
  158. return 1;
  159. }
  160. /*
  161. Provide short and/or unified names for dimensions.
  162. This must mimic lib-ncdap, which is difficult.
  163. */
  164. NCerror
  165. computecdfdimnames34(NCDAPCOMMON* nccomm)
  166. {
  167. int i,j;
  168. char tmp[NC_MAX_NAME*2];
  169. NClist* conflicts = nclistnew();
  170. NClist* varnodes = nccomm->cdf.varnodes;
  171. NClist* alldims;
  172. NClist* basedims;
  173. /* Collect all dimension nodes from dimsetall lists */
  174. alldims = getalldims34(nccomm,0);
  175. /* Assign an index to all anonymous dimensions
  176. vis-a-vis its containing variable
  177. */
  178. for(i=0;i<nclistlength(varnodes);i++) {
  179. CDFnode* var = (CDFnode*)nclistget(varnodes,i);
  180. for(j=0;j<nclistlength(var->array.dimsetall);j++) {
  181. CDFnode* dim = (CDFnode*)nclistget(var->array.dimsetall,j);
  182. if(dim->ocname != NULL) continue; /* not anonymous */
  183. computedimindexanon3(dim,var);
  184. }
  185. }
  186. /* Unify dimensions by defining one dimension as the "base"
  187. dimension, and make all "equivalent" dimensions point to the
  188. base dimension.
  189. 1. Equivalent means: same size and both have identical non-null names.
  190. 2. Dims with same name but different sizes will be handled separately
  191. */
  192. for(i=0;i<nclistlength(alldims);i++) {
  193. CDFnode* dupdim = NULL;
  194. CDFnode* basedim = (CDFnode*)nclistget(alldims,i);
  195. if(basedim == NULL) continue;
  196. if(basedim->dim.basedim != NULL) continue; /* already processed*/
  197. for(j=i+1;j<nclistlength(alldims);j++) { /* Sigh, n**2 */
  198. dupdim = (CDFnode*)nclistget(alldims,j);
  199. if(basedim == dupdim) continue;
  200. if(dupdim == NULL) continue;
  201. if(dupdim->dim.basedim != NULL) continue; /* already processed */
  202. if(!equivalentdim(basedim,dupdim))
  203. continue;
  204. dupdim->dim.basedim = basedim; /* equate */
  205. #ifdef DEBUG1
  206. fprintf(stderr,"assign: %s/%s -> %s/%s\n",
  207. basedim->dim.array->ocname,basedim->ocname,
  208. dupdim->dim.array->ocname,dupdim->ocname
  209. );
  210. #endif
  211. }
  212. }
  213. /* Next case: same name and different sizes*/
  214. /* => rename second dim */
  215. for(i=0;i<nclistlength(alldims);i++) {
  216. CDFnode* basedim = (CDFnode*)nclistget(alldims,i);
  217. if(basedim->dim.basedim != NULL) continue;
  218. /* Collect all conflicting dimensions */
  219. nclistclear(conflicts);
  220. for(j=i+1;j<nclistlength(alldims);j++) {
  221. CDFnode* dim = (CDFnode*)nclistget(alldims,j);
  222. if(dim->dim.basedim != NULL) continue;
  223. if(dim->ocname == NULL && basedim->ocname == NULL) continue;
  224. if(dim->ocname == NULL || basedim->ocname == NULL) continue;
  225. if(strcmp(dim->ocname,basedim->ocname)!=0) continue;
  226. if(dim->dim.declsize == basedim->dim.declsize) continue;
  227. #ifdef DEBUG2
  228. fprintf(stderr,"conflict: %s[%lu] %s[%lu]\n",
  229. basedim->ncfullname,(unsigned long)basedim->dim.declsize,
  230. dim->ncfullname,(unsigned long)dim->dim.declsize);
  231. #endif
  232. nclistpush(conflicts,(ncelem)dim);
  233. }
  234. /* Give all the conflicting dimensions an index */
  235. for(j=0;j<nclistlength(conflicts);j++) {
  236. CDFnode* dim = (CDFnode*)nclistget(conflicts,j);
  237. dim->dim.index1 = j+1;
  238. }
  239. }
  240. nclistfree(conflicts);
  241. /* Replace all non-base dimensions with their base dimension */
  242. for(i=0;i<nclistlength(varnodes);i++) {
  243. CDFnode* node = (CDFnode*)nclistget(varnodes,i);
  244. replacedims(node->array.dimsetall);
  245. replacedims(node->array.dimsetplus);
  246. replacedims(node->array.dimset0);
  247. }
  248. /* Collect list of all basedims */
  249. basedims = nclistnew();
  250. for(i=0;i<nclistlength(alldims);i++) {
  251. CDFnode* dim = (CDFnode*)nclistget(alldims,i);
  252. if(dim->dim.basedim == NULL) {
  253. if(!nclistcontains(basedims,(ncelem)dim)) {
  254. nclistpush(basedims,(ncelem)dim);
  255. }
  256. }
  257. }
  258. nccomm->cdf.dimnodes = basedims;
  259. /* cleanup */
  260. nclistfree(alldims);
  261. /* Assign ncbasenames and ncfullnames to base dimensions */
  262. for(i=0;i<nclistlength(basedims);i++) {
  263. CDFnode* dim = (CDFnode*)nclistget(basedims,i);
  264. CDFnode* var = dim->dim.array;
  265. if(dim->dim.basedim != NULL) PANIC1("nonbase basedim: %s\n",dim->ocname);
  266. /* stringdim names are already assigned */
  267. if(dim->ocname == NULL) { /* anonymous: use the index to compute the name */
  268. snprintf(tmp,sizeof(tmp),"%s_%d",
  269. var->ncfullname,dim->dim.index1-1);
  270. nullfree(dim->ncbasename);
  271. dim->ncbasename = cdflegalname3(tmp);
  272. nullfree(dim->ncfullname);
  273. dim->ncfullname = nulldup(dim->ncbasename);
  274. } else { /* !anonymous; use index1 if defined */
  275. char* legalname = cdflegalname3(dim->ocname);
  276. nullfree(dim->ncbasename);
  277. if(dim->dim.index1 > 0) {/* need to fix conflicting names (see above) */
  278. char sindex[64];
  279. snprintf(sindex,sizeof(sindex),"_%d",dim->dim.index1);
  280. dim->ncbasename = (char*)malloc(strlen(sindex)+strlen(legalname)+1);
  281. if(dim->ncbasename == NULL) return NC_ENOMEM;
  282. strcpy(dim->ncbasename,legalname);
  283. strcat(dim->ncbasename,sindex);
  284. nullfree(legalname);
  285. } else {/* standard case */
  286. dim->ncbasename = legalname;
  287. }
  288. nullfree(dim->ncfullname);
  289. dim->ncfullname = nulldup(dim->ncbasename);
  290. }
  291. }
  292. /* Verify unique and defined names for dimensions*/
  293. for(i=0;i<nclistlength(basedims);i++) {
  294. CDFnode* dim1 = (CDFnode*)nclistget(basedims,i);
  295. if(dim1->dim.basedim != NULL) PANIC1("nonbase basedim: %s\n",dim1->ncbasename);
  296. if(dim1->ncbasename == NULL || dim1->ncfullname == NULL)
  297. PANIC1("missing dim names: %s",dim1->ocname);
  298. /* search backward so we can delete duplicates */
  299. for(j=nclistlength(basedims)-1;j>i;j--) {
  300. CDFnode* dim2 = (CDFnode*)nclistget(basedims,j);
  301. if(strcmp(dim1->ncfullname,dim2->ncfullname)==0) {
  302. /* complain and suppress one of them */
  303. fprintf(stderr,"duplicate dim names: %s[%lu] %s[%lu]\n",
  304. dim1->ncfullname,(unsigned long)dim1->dim.declsize,
  305. dim2->ncfullname,(unsigned long)dim2->dim.declsize);
  306. nclistremove(basedims,j);
  307. }
  308. }
  309. }
  310. #ifdef DEBUG
  311. for(i=0;i<nclistlength(basedims);i++) {
  312. CDFnode* dim = (CDFnode*)nclistget(basedims,i);
  313. fprintf(stderr,"basedim: %s=%ld\n",dim->ncfullname,(long)dim->dim.declsize);
  314. }
  315. #endif
  316. return NC_NOERR;
  317. }
  318. NCerror
  319. makegetvar34(NCDAPCOMMON* nccomm, CDFnode* var, void* data, nc_type dsttype, Getvara** getvarp)
  320. {
  321. Getvara* getvar;
  322. NCerror ncstat = NC_NOERR;
  323. getvar = (Getvara*)calloc(1,sizeof(Getvara));
  324. MEMCHECK(getvar,NC_ENOMEM);
  325. if(getvarp) *getvarp = getvar;
  326. getvar->target = var;
  327. getvar->memory = data;
  328. getvar->dsttype = dsttype;
  329. getvar->target = var;
  330. if(ncstat) nullfree(getvar);
  331. return ncstat;
  332. }
  333. int
  334. constrainable34(NC_URI* durl)
  335. {
  336. char** protocol = constrainableprotocols;
  337. for(;*protocol;protocol++) {
  338. if(strcmp(durl->protocol,*protocol)==0)
  339. return 1;
  340. }
  341. return 0;
  342. }
  343. CDFnode*
  344. makecdfnode34(NCDAPCOMMON* nccomm, char* name, OCtype octype,
  345. /*optional*/ OCobject ocnode, CDFnode* container)
  346. {
  347. CDFnode* node;
  348. assert(nccomm != NULL);
  349. node = (CDFnode*)calloc(1,sizeof(CDFnode));
  350. if(node == NULL) return (CDFnode*)NULL;
  351. node->ocname = NULL;
  352. if(name) {
  353. size_t len = strlen(name);
  354. if(len >= NC_MAX_NAME) len = NC_MAX_NAME-1;
  355. node->ocname = (char*)malloc(len+1);
  356. if(node->ocname == NULL) return NULL;
  357. memcpy(node->ocname,name,len);
  358. node->ocname[len] = '\0';
  359. }
  360. node->nctype = octypetonc(octype);
  361. node->ocnode = ocnode;
  362. node->subnodes = nclistnew();
  363. node->container = container;
  364. if(ocnode != OCNULL) {
  365. oc_inq_primtype(nccomm->oc.conn,ocnode,&octype);
  366. node->etype = octypetonc(octype);
  367. }
  368. return node;
  369. }
  370. /* Given an OCnode tree, mimic it as a CDFnode tree;
  371. Add DAS attributes if DAS is available. Accumulate set
  372. of all nodes in preorder.
  373. */
  374. NCerror
  375. buildcdftree34(NCDAPCOMMON* nccomm, OCobject ocroot, OCdxd occlass, CDFnode** cdfrootp)
  376. {
  377. CDFnode* root = NULL;
  378. CDFtree* tree = (CDFtree*)calloc(1,sizeof(CDFtree));
  379. NCerror err = NC_NOERR;
  380. tree->ocroot = ocroot;
  381. tree->nodes = nclistnew();
  382. tree->occlass = occlass;
  383. tree->owner = nccomm;
  384. err = buildcdftree34r(nccomm,ocroot,NULL,tree,&root);
  385. if(!err) {
  386. if(occlass != OCDAS)
  387. fixnodes34(nccomm,tree->nodes);
  388. if(cdfrootp) *cdfrootp = root;
  389. }
  390. return err;
  391. }
  392. static NCerror
  393. buildcdftree34r(NCDAPCOMMON* nccomm, OCobject ocnode, CDFnode* container,
  394. CDFtree* tree, CDFnode** cdfnodep)
  395. {
  396. unsigned int i,ocrank,ocnsubnodes;
  397. OCtype octype;
  398. char* ocname = NULL;
  399. NCerror ncerr = NC_NOERR;
  400. CDFnode* cdfnode;
  401. oc_inq_class(nccomm->oc.conn,ocnode,&octype);
  402. oc_inq_name(nccomm->oc.conn,ocnode,&ocname);
  403. oc_inq_rank(nccomm->oc.conn,ocnode,&ocrank);
  404. oc_inq_nsubnodes(nccomm->oc.conn,ocnode,&ocnsubnodes);
  405. switch (octype) {
  406. case OC_Dataset:
  407. case OC_Grid:
  408. case OC_Structure:
  409. case OC_Sequence:
  410. case OC_Primitive:
  411. cdfnode = makecdfnode34(nccomm,ocname,octype,ocnode,container);
  412. nclistpush(tree->nodes,(ncelem)cdfnode);
  413. if(tree->root == NULL) {
  414. tree->root = cdfnode;
  415. cdfnode->tree = tree;
  416. }
  417. break;
  418. case OC_Dimension:
  419. default: PANIC1("buildcdftree: unexpect OC node type: %d",(int)octype);
  420. }
  421. /* cross link */
  422. cdfnode->root = tree->root;
  423. if(ocrank > 0) defdimensions(ocnode,cdfnode,nccomm,tree);
  424. for(i=0;i<ocnsubnodes;i++) {
  425. OCobject ocsubnode;
  426. CDFnode* subnode;
  427. oc_inq_ith(nccomm->oc.conn,ocnode,i,&ocsubnode);
  428. ncerr = buildcdftree34r(nccomm,ocsubnode,cdfnode,tree,&subnode);
  429. if(ncerr) return ncerr;
  430. nclistpush(cdfnode->subnodes,(ncelem)subnode);
  431. }
  432. nullfree(ocname);
  433. if(cdfnodep) *cdfnodep = cdfnode;
  434. return ncerr;
  435. }
  436. static void
  437. defdimensions(OCobject ocnode, CDFnode* cdfnode, NCDAPCOMMON* nccomm, CDFtree* tree)
  438. {
  439. unsigned int i,ocrank;
  440. oc_inq_rank(nccomm->oc.conn,ocnode,&ocrank);
  441. assert(ocrank > 0);
  442. for(i=0;i<ocrank;i++) {
  443. CDFnode* cdfdim;
  444. OCobject ocdim;
  445. char* ocname;
  446. size_t declsize;
  447. oc_inq_ithdim(nccomm->oc.conn,ocnode,i,&ocdim);
  448. oc_inq_dim(nccomm->oc.conn,ocdim,&declsize,&ocname);
  449. cdfdim = makecdfnode34(nccomm,ocname,OC_Dimension,
  450. ocdim,cdfnode->container);
  451. nullfree(ocname);
  452. nclistpush(tree->nodes,(ncelem)cdfdim);
  453. /* Initially, constrained and unconstrained are same */
  454. cdfdim->dim.declsize = declsize;
  455. cdfdim->dim.array = cdfnode;
  456. if(cdfnode->array.dimset0 == NULL)
  457. cdfnode->array.dimset0 = nclistnew();
  458. nclistpush(cdfnode->array.dimset0,(ncelem)cdfdim);
  459. }
  460. }
  461. /* Note: this routine only applies some common
  462. client parameters, other routines may apply
  463. specific ones.
  464. */
  465. NCerror
  466. applyclientparams34(NCDAPCOMMON* nccomm)
  467. {
  468. int i,len;
  469. int dfaltstrlen = DEFAULTSTRINGLENGTH;
  470. int dfaltseqlim = DEFAULTSEQLIMIT;
  471. const char* value;
  472. char tmpname[NC_MAX_NAME+32];
  473. char* pathstr;
  474. OCconnection conn = nccomm->oc.conn;
  475. unsigned long limit;
  476. ASSERT(nccomm->oc.url != NULL);
  477. nccomm->cdf.cache->cachelimit = DFALTCACHELIMIT;
  478. value = oc_clientparam_get(conn,"cachelimit");
  479. limit = getlimitnumber(value);
  480. if(limit > 0) nccomm->cdf.cache->cachelimit = limit;
  481. nccomm->cdf.fetchlimit = DFALTFETCHLIMIT;
  482. value = oc_clientparam_get(conn,"fetchlimit");
  483. limit = getlimitnumber(value);
  484. if(limit > 0) nccomm->cdf.fetchlimit = limit;
  485. nccomm->cdf.smallsizelimit = DFALTSMALLLIMIT;
  486. value = oc_clientparam_get(conn,"smallsizelimit");
  487. limit = getlimitnumber(value);
  488. if(limit > 0) nccomm->cdf.smallsizelimit = limit;
  489. nccomm->cdf.cache->cachecount = DFALTCACHECOUNT;
  490. #ifdef HAVE_GETRLIMIT
  491. { struct rlimit rl;
  492. if(getrlimit(RLIMIT_NOFILE, &rl) >= 0) {
  493. nccomm->cdf.cache->cachecount = (size_t)(rl.rlim_cur / 2);
  494. }
  495. }
  496. #endif
  497. value = oc_clientparam_get(conn,"cachecount");
  498. limit = getlimitnumber(value);
  499. if(limit > 0) nccomm->cdf.cache->cachecount = limit;
  500. /* Ignore limit if not caching */
  501. if(!FLAGSET(nccomm->controls,NCF_CACHE))
  502. nccomm->cdf.cache->cachecount = 0;
  503. if(oc_clientparam_get(conn,"nolimit") != NULL)
  504. dfaltseqlim = 0;
  505. value = oc_clientparam_get(conn,"limit");
  506. if(value != NULL && strlen(value) != 0) {
  507. if(sscanf(value,"%d",&len) && len > 0) dfaltseqlim = len;
  508. }
  509. nccomm->cdf.defaultsequencelimit = dfaltseqlim;
  510. /* allow embedded _ */
  511. value = oc_clientparam_get(conn,"stringlength");
  512. if(value != NULL && strlen(value) != 0) {
  513. if(sscanf(value,"%d",&len) && len > 0) dfaltstrlen = len;
  514. }
  515. nccomm->cdf.defaultstringlength = dfaltstrlen;
  516. /* String dimension limits apply to variables */
  517. for(i=0;i<nclistlength(nccomm->cdf.varnodes);i++) {
  518. CDFnode* var = (CDFnode*)nclistget(nccomm->cdf.varnodes,i);
  519. /* Define the client param stringlength for this variable*/
  520. var->maxstringlength = 0; /* => use global dfalt */
  521. strcpy(tmpname,"stringlength_");
  522. pathstr = makeocpathstring3(conn,var->ocnode,".");
  523. strcat(tmpname,pathstr);
  524. nullfree(pathstr);
  525. value = oc_clientparam_get(conn,tmpname);
  526. if(value != NULL && strlen(value) != 0) {
  527. if(sscanf(value,"%d",&len) && len > 0) var->maxstringlength = len;
  528. }
  529. }
  530. /* Sequence limits apply to sequences */
  531. for(i=0;i<nclistlength(nccomm->cdf.ddsroot->tree->nodes);i++) {
  532. CDFnode* var = (CDFnode*)nclistget(nccomm->cdf.ddsroot->tree->nodes,i);
  533. if(var->nctype != NC_Sequence) continue;
  534. var->sequencelimit = dfaltseqlim;
  535. strcpy(tmpname,"nolimit_");
  536. pathstr = makeocpathstring3(conn,var->ocnode,".");
  537. strcat(tmpname,pathstr);
  538. if(oc_clientparam_get(conn,tmpname) != NULL)
  539. var->sequencelimit = 0;
  540. strcpy(tmpname,"limit_");
  541. strcat(tmpname,pathstr);
  542. value = oc_clientparam_get(conn,tmpname);
  543. if(value != NULL && strlen(value) != 0) {
  544. if(sscanf(value,"%d",&len) && len > 0)
  545. var->sequencelimit = len;
  546. }
  547. nullfree(pathstr);
  548. }
  549. /* test for the appropriate fetch flags */
  550. value = oc_clientparam_get(conn,"fetch");
  551. if(value != NULL && strlen(value) > 0) {
  552. if(value[0] == 'd' || value[0] == 'D') {
  553. SETFLAG(nccomm->controls,NCF_ONDISK);
  554. }
  555. }
  556. /* test for the force-whole-var flag */
  557. value = oc_clientparam_get(conn,"wholevar");
  558. if(value != NULL) {
  559. SETFLAG(nccomm->controls,NCF_WHOLEVAR);
  560. }
  561. return NC_NOERR;
  562. }
  563. void
  564. freecdfroot34(CDFnode* root)
  565. {
  566. int i;
  567. CDFtree* tree;
  568. NCDAPCOMMON* nccomm;
  569. if(root == NULL) return;
  570. tree = root->tree;
  571. ASSERT((tree != NULL));
  572. /* Explicitly FREE the ocroot */
  573. nccomm = tree->owner;
  574. oc_root_free(nccomm->oc.conn,tree->ocroot);
  575. tree->ocroot = OCNULL;
  576. for(i=0;i<nclistlength(tree->nodes);i++) {
  577. CDFnode* node = (CDFnode*)nclistget(tree->nodes,i);
  578. free1cdfnode34(node);
  579. }
  580. nclistfree(tree->nodes);
  581. nullfree(tree);
  582. }
  583. /* Free up a single node, but not any
  584. nodes it points to.
  585. */
  586. static void
  587. free1cdfnode34(CDFnode* node)
  588. {
  589. unsigned int j,k;
  590. if(node == NULL) return;
  591. nullfree(node->ocname);
  592. nullfree(node->ncbasename);
  593. nullfree(node->ncfullname);
  594. if(node->attributes != NULL) {
  595. for(j=0;j<nclistlength(node->attributes);j++) {
  596. NCattribute* att = (NCattribute*)nclistget(node->attributes,j);
  597. nullfree(att->name);
  598. for(k=0;k<nclistlength(att->values);k++)
  599. nullfree((char*)nclistget(att->values,k));
  600. nclistfree(att->values);
  601. nullfree(att);
  602. }
  603. }
  604. nullfree(node->dodsspecial.dimname);
  605. nclistfree(node->subnodes);
  606. nclistfree(node->attributes);
  607. nclistfree(node->array.dimsetplus);
  608. nclistfree(node->array.dimsetall);
  609. nclistfree(node->array.dimset0);
  610. /* Clean up the ncdap4 fields also */
  611. nullfree(node->typename);
  612. nullfree(node->vlenname);
  613. nullfree(node);
  614. }
  615. /* Return true if node and node1 appear to refer to the same thing;
  616. takes grid->structure changes into account.
  617. */
  618. int
  619. nodematch34(CDFnode* node1, CDFnode* node2)
  620. {
  621. return simplenodematch34(node1,node2);
  622. }
  623. int
  624. simplenodematch34(CDFnode* node1, CDFnode* node2)
  625. {
  626. if(node1 == NULL) return (node2==NULL);
  627. if(node2 == NULL) return 0;
  628. if(node1->nctype != node2->nctype) {
  629. /* Check for Grid->Structure match */
  630. if((node1->nctype == NC_Structure && node2->nctype == NC_Grid)
  631. || (node2->nctype == NC_Structure && node1->nctype == NC_Grid)){
  632. if(node1->ocname == NULL || node2->ocname == NULL
  633. || strcmp(node1->ocname,node2->ocname) !=0) return 0;
  634. } else return 0;
  635. }
  636. /* Add hack to address the screwed up Columbia server */
  637. if(node1->nctype == NC_Dataset) return 1;
  638. if(node1->nctype == NC_Primitive
  639. && node1->etype != node2->etype) return 0;
  640. if(node1->ocname != NULL && node2->ocname != NULL
  641. && strcmp(node1->ocname,node2->ocname)!=0) return 0;
  642. if(nclistlength(node1->array.dimset0)
  643. != nclistlength(node2->array.dimset0)) return 0;
  644. return 1;
  645. }
  646. /*
  647. Given DDS node, locate the node
  648. in a DATADDS that matches the DDS node.
  649. Return NULL if no node found
  650. */
  651. void
  652. unattach34(CDFnode* root)
  653. {
  654. unsigned int i;
  655. CDFtree* xtree = root->tree;
  656. for(i=0;i<nclistlength(xtree->nodes);i++) {
  657. CDFnode* xnode = (CDFnode*)nclistget(xtree->nodes,i);
  658. /* break bi-directional link */
  659. xnode->attachment = NULL;
  660. }
  661. }
  662. static void
  663. setattach(CDFnode* target, CDFnode* template)
  664. {
  665. target->attachment = template;
  666. template->attachment = target;
  667. /* Transfer important information */
  668. target->externaltype = template->externaltype;
  669. target->maxstringlength = template->maxstringlength;
  670. target->sequencelimit = template->sequencelimit;
  671. target->ncid = template->ncid;
  672. /* also transfer libncdap4 info */
  673. target->typeid = template->typeid;
  674. target->typesize = template->typesize;
  675. }
  676. static NCerror
  677. attachdims34(CDFnode* xnode, CDFnode* template)
  678. {
  679. unsigned int i;
  680. for(i=0;i<nclistlength(xnode->array.dimsetall);i++) {
  681. CDFnode* xdim = (CDFnode*)nclistget(xnode->array.dimsetall,i);
  682. CDFnode* tdim = (CDFnode*)nclistget(template->array.dimsetall,i);
  683. setattach(xdim,tdim);
  684. #ifdef DEBUG2
  685. fprintf(stderr,"attachdim: %s->%s\n",xdim->ocname,tdim->ocname);
  686. #endif
  687. }
  688. return NC_NOERR;
  689. }
  690. /*
  691. Match a DATADDS node to a DDS node.
  692. It is assumed that both trees have been regridded if necessary.
  693. */
  694. static NCerror
  695. attach34r(CDFnode* xnode, NClist* templatepath, int depth)
  696. {
  697. unsigned int i,plen,lastnode,gridable;
  698. NCerror ncstat = NC_NOERR;
  699. CDFnode* templatepathnode;
  700. CDFnode* templatepathnext;
  701. plen = nclistlength(templatepath);
  702. if(depth >= plen) {THROWCHK(ncstat=NC_EINVAL); goto done;}
  703. lastnode = (depth == (plen-1));
  704. templatepathnode = (CDFnode*)nclistget(templatepath,depth);
  705. ASSERT((simplenodematch34(xnode,templatepathnode)));
  706. setattach(xnode,templatepathnode);
  707. #ifdef DEBUG2
  708. fprintf(stderr,"attachnode: %s->%s\n",xnode->ocname,templatepathnode->ocname);
  709. #endif
  710. if(lastnode) goto done; /* We have the match and are done */
  711. if(nclistlength(xnode->array.dimsetall) > 0) {
  712. attachdims34(xnode,templatepathnode);
  713. }
  714. ASSERT((!lastnode));
  715. templatepathnext = (CDFnode*)nclistget(templatepath,depth+1);
  716. gridable = (templatepathnext->nctype == NC_Grid && depth+2 < plen);
  717. /* Try to find an xnode subnode that matches templatepathnext */
  718. for(i=0;i<nclistlength(xnode->subnodes);i++) {
  719. CDFnode* xsubnode = (CDFnode*)nclistget(xnode->subnodes,i);
  720. if(simplenodematch34(xsubnode,templatepathnext)) {
  721. ncstat = attach34r(xsubnode,templatepath,depth+1);
  722. if(ncstat) goto done;
  723. } else if(gridable && xsubnode->nctype == NC_Primitive) {
  724. /* grids may or may not appear in the datadds;
  725. try to match the xnode subnodes against the parts of the grid
  726. */
  727. CDFnode* templatepathnext2 = (CDFnode*)nclistget(templatepath,depth+2);
  728. if(simplenodematch34(xsubnode,templatepathnext2)) {
  729. ncstat = attach34r(xsubnode,templatepath,depth+2);
  730. if(ncstat) goto done;
  731. }
  732. }
  733. }
  734. done:
  735. return THROW(ncstat);
  736. }
  737. NCerror
  738. attach34(CDFnode* xroot, CDFnode* template)
  739. {
  740. NCerror ncstat = NC_NOERR;
  741. NClist* templatepath = nclistnew();
  742. CDFnode* ddsroot = template->root;
  743. if(xroot->attachment) unattach34(xroot);
  744. if(ddsroot != NULL && ddsroot->attachment) unattach34(ddsroot);
  745. if(!simplenodematch34(xroot,ddsroot))
  746. {THROWCHK(ncstat=NC_EINVAL); goto done;}
  747. collectnodepath3(template,templatepath,WITHDATASET);
  748. ncstat = attach34r(xroot,templatepath,0);
  749. done:
  750. nclistfree(templatepath);
  751. return ncstat;
  752. }
  753. /*
  754. Match nodes in template tree to nodes in target tree;
  755. template tree is typically a structural superset of target tree.
  756. WARNING: Dimensions are not attached
  757. */
  758. NCerror
  759. attachsubset34(CDFnode* target, CDFnode* template)
  760. {
  761. NCerror ncstat = NC_NOERR;
  762. if(template == NULL) {THROWCHK(ncstat=NC_NOERR); goto done;}
  763. if(!nodematch34(target,template)) {THROWCHK(ncstat=NC_EINVAL); goto done;}
  764. #ifdef DEBUG2
  765. fprintf(stderr,"attachsubset: target=%s\n",dumptree(target));
  766. fprintf(stderr,"attachsubset: template=%s\n",dumptree(template));
  767. #endif
  768. ncstat = attachsubset34r(target,template);
  769. done:
  770. return ncstat;
  771. }
  772. static NCerror
  773. attachsubset34r(CDFnode* target, CDFnode* template)
  774. {
  775. unsigned int i;
  776. NCerror ncstat = NC_NOERR;
  777. int fieldindex;
  778. #ifdef DEBUG2
  779. fprintf(stderr,"attachsubsetr: attach: target=%s template=%s\n",
  780. target->ocname,template->ocname);
  781. #endif
  782. ASSERT((nodematch34(target,template)));
  783. setattach(target,template);
  784. /* Try to match target subnodes against template subnodes */
  785. fieldindex = 0;
  786. for(fieldindex=0,i=0;i<nclistlength(template->subnodes) && fieldindex<nclistlength(target->subnodes);i++) {
  787. CDFnode* templatesubnode = (CDFnode*)nclistget(template->subnodes,i);
  788. CDFnode* targetsubnode = (CDFnode*)nclistget(target->subnodes,fieldindex);
  789. if(nodematch34(targetsubnode,templatesubnode)) {
  790. #ifdef DEBUG2
  791. fprintf(stderr,"attachsubsetr: match: %s :: %s\n",targetsubnode->ocname,templatesubnode->ocname);
  792. #endif
  793. ncstat = attachsubset34r(targetsubnode,templatesubnode);
  794. if(ncstat) goto done;
  795. fieldindex++;
  796. }
  797. }
  798. done:
  799. return THROW(ncstat);
  800. }
  801. static void
  802. getalldims34a(NClist* dimset, NClist* alldims)
  803. {
  804. int i;
  805. for(i=0;i<nclistlength(dimset);i++) {
  806. CDFnode* dim = (CDFnode*)nclistget(dimset,i);
  807. if(!nclistcontains(alldims,(ncelem)dim)) {
  808. #ifdef DEBUG3
  809. fprintf(stderr,"getalldims: %s[%lu]\n",
  810. dim->ncfullname,(unsigned long)dim->dim.declsize);
  811. #endif
  812. nclistpush(alldims,(ncelem)dim);
  813. }
  814. }
  815. }
  816. /* Accumulate a set of all the known dimensions
  817. vis-a-vis defined variables
  818. */
  819. NClist*
  820. getalldims34(NCDAPCOMMON* nccomm, int visibleonly)
  821. {
  822. int i;
  823. NClist* alldims = nclistnew();
  824. NClist* varnodes = nccomm->cdf.varnodes;
  825. /* get bag of all dimensions */
  826. for(i=0;i<nclistlength(varnodes);i++) {
  827. CDFnode* node = (CDFnode*)nclistget(varnodes,i);
  828. if(!visibleonly || node->visible) {
  829. getalldims34a(node->array.dimsetall,alldims);
  830. }
  831. }
  832. return alldims;
  833. }