dapattr3.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /*********************************************************************
  2. * Copyright 1993, UCAR/Unidata
  3. * See netcdf/COPYRIGHT file for copying and redistribution conditions.
  4. * $Header: /upc/share/CVS/netcdf-3/libncdap3/dapattr3.c,v 1.14 2009/12/03 03:42:38 dmh Exp $
  5. *********************************************************************/
  6. #include "ncdap3.h"
  7. #define OCHECK(exp) if((ocstat = (exp))) goto done;
  8. /* Forward */
  9. static NCerror buildattribute(char*,nc_type,NClist*,NCattribute**);
  10. static int mergedas1(NCDAPCOMMON*, OCconnection, CDFnode* dds, OCobject das);
  11. static int isglobalname3(char* name);
  12. static NCerror
  13. buildattribute(char* name, nc_type ptype,
  14. NClist* values, NCattribute** attp)
  15. {
  16. NCerror ncstat = NC_NOERR;
  17. NCattribute* att;
  18. att = (NCattribute*)calloc(1,sizeof(NCattribute));
  19. MEMCHECK(att,NC_ENOMEM);
  20. att->name = nulldup(name);
  21. att->etype = ptype;
  22. att->values = values;
  23. if(attp) *attp = att;
  24. return THROW(ncstat);
  25. }
  26. /*
  27. Given a das attribute walk it to see if it
  28. has at least 1 actual attribute (no recursion)
  29. */
  30. static int
  31. hasattribute3(OCconnection conn, OCobject dasnode)
  32. {
  33. int i;
  34. OCerror ocstat = OC_NOERR;
  35. int tf = 0; /* assume false */
  36. unsigned int nsubnodes;
  37. OCtype ocsubtype;
  38. OCobject* subnodes = NULL;
  39. OCHECK(oc_inq_class(conn,dasnode,&ocsubtype));
  40. if(ocsubtype == OC_Attribute) return 1; /* this is an attribute */
  41. ASSERT((ocsubtype == OC_Attributeset));
  42. OCHECK(oc_inq_nsubnodes(conn,dasnode,&nsubnodes));
  43. OCHECK(oc_inq_subnodes(conn,dasnode,&subnodes));
  44. for(i=0;i<nsubnodes;i++) {
  45. OCobject subnode = subnodes[i];
  46. OCHECK(oc_inq_class(conn,subnode,&ocsubtype));
  47. if(ocsubtype == OC_Attribute) {tf=1; break;}
  48. }
  49. done:
  50. nullfree(subnodes);
  51. return tf;
  52. }
  53. /*
  54. Duplicate the oc merge das and dds code, but
  55. modify to capture such things as "strlen" and "dimname".
  56. */
  57. int
  58. dapmerge3(NCDAPCOMMON* nccomm, CDFnode* ddsroot, OCobject dasroot)
  59. {
  60. unsigned int i,j;
  61. NCerror ncerr = NC_NOERR;
  62. OCerror ocstat = OC_NOERR;
  63. OCconnection conn = nccomm->oc.conn;
  64. unsigned int nsubnodes, nobjects;
  65. OCobject* dasobjects = NULL;
  66. NClist* dasglobals = nclistnew();
  67. NClist* dasnodes = nclistnew();
  68. NClist* dodsextra = nclistnew();
  69. NClist* varnodes = nclistnew();
  70. NClist* allddsnodes = ddsroot->tree->nodes;
  71. if(ddsroot == NULL || dasroot == NULL) return NC_NOERR;
  72. nobjects = oc_inq_nobjects(conn,dasroot);
  73. dasobjects = oc_inq_objects(conn,dasroot);
  74. /* 1. collect all the relevant DAS nodes;
  75. namely those that contain at least one
  76. attribute value.
  77. Simultaneously look for potential ambiguities
  78. if found; complain but continue: result are indeterminate.
  79. also collect globals and DODS_EXTRA separately.
  80. */
  81. for(i=0;i<nobjects;i++) {
  82. OCobject das = dasobjects[i];
  83. OCtype octype;
  84. char* ocname = NULL;
  85. int isglobal = 0;
  86. int hasattributes = 0;
  87. OCHECK(oc_inq_class(conn,das,&octype));
  88. if(octype == OC_Attribute) continue; /* ignore these for now*/
  89. OCHECK(oc_inq_name(conn,das,&ocname));
  90. OCHECK(oc_inq_nsubnodes(conn,das,&nsubnodes));
  91. isglobal = (ocname == NULL ? 0 : isglobalname3(ocname));
  92. /* catch DODS_EXTRA */
  93. if(isglobal && ocname != NULL && strcmp(ocname,"DODS_EXTRA")==0) {
  94. nclistpush(dodsextra,(ncelem)das);
  95. nullfree(ocname);
  96. continue;
  97. }
  98. if(ocname == NULL || isglobal) {
  99. nclistpush(dasglobals,(ncelem)das);
  100. nullfree(ocname);
  101. continue;
  102. }
  103. hasattributes = hasattribute3(conn,das);
  104. if(hasattributes) {
  105. /* Look for previously collected nodes with same name*/
  106. for(j=0;j<nclistlength(dasnodes);j++) {
  107. OCobject das2 = (OCobject)nclistget(dasnodes,j);
  108. char* ocname2;
  109. OCHECK(oc_inq_name(conn,das2,&ocname2));
  110. if(ocname2 == NULL || ocname == NULL) goto loop;
  111. if(strcmp(ocname2,"DODS")==0) goto loop;
  112. if(strcmp(ocname,ocname2)==0)
  113. nclog(NCLOGWARN,"nc_mergedas: potentially ambiguous DAS name: %s",ocname2);
  114. loop:
  115. nullfree(ocname2);
  116. }
  117. nclistpush(dasnodes,(ncelem)das);
  118. }
  119. nullfree(ocname);
  120. }
  121. /* 2. collect all the leaf DDS nodes (of type NC_Primitive)*/
  122. for(i=0;i<nclistlength(allddsnodes);i++) {
  123. CDFnode* dds = (CDFnode*)nclistget(allddsnodes,i);
  124. if(dds->nctype == NC_Primitive) nclistpush(varnodes,(ncelem)dds);
  125. }
  126. /* 3. For each das node, lncate matching DDS node(s) and attach
  127. attributes to the DDS node(s).
  128. Match means:
  129. 1. DAS->fullname :: DDS->fullname
  130. 2. DAS->name :: DDS->fullname (support DAS names with embedded '.'
  131. 3. DAS->name :: DDS->name
  132. 4. special case for DODS. Apply 1-3 on DODS parent.
  133. */
  134. for(i=0;i<nclistlength(dasnodes);i++) {
  135. OCobject das = (OCobject)nclistget(dasnodes,i);
  136. char* ocfullname = NULL;
  137. char* ocbasename = NULL;
  138. if(das == OCNULL) continue;
  139. OCHECK(oc_inq_name(conn,das,&ocbasename));
  140. if(strcmp(ocbasename,"DODS")==0) {
  141. OCobject container;
  142. OCHECK(oc_inq_container(conn,das,&container));
  143. if(container == OCNULL) {
  144. ASSERT(container != OCNULL);
  145. }
  146. ocfullname = makeocpathstring3(conn,container,".");
  147. } else {
  148. ocfullname = makeocpathstring3(conn,das,".");
  149. }
  150. for(j=0;j<nclistlength(varnodes);j++) {
  151. CDFnode* dds = (CDFnode*)nclistget(varnodes,j);
  152. char* ddsfullname = makecdfpathstring3(dds,".");
  153. if(strcmp(ocfullname,ddsfullname)==0
  154. || strcmp(ocbasename,ddsfullname)==0
  155. || strcmp(ocbasename,dds->ocname)==0) {
  156. mergedas1(nccomm,conn,dds,das);
  157. /* remove from dasnodes list*/
  158. nclistset(dasnodes,i,(ncelem)NULL);
  159. }
  160. nullfree(ddsfullname);
  161. }
  162. nullfree(ocfullname);
  163. nullfree(ocbasename);
  164. }
  165. /* 4. Assign globals */
  166. for(i=0;i<nclistlength(dasglobals);i++) {
  167. OCobject das = (OCobject)nclistget(dasglobals,i);
  168. mergedas1(nccomm,conn,ddsroot,das);
  169. }
  170. /* 5. Assign DOD_EXTRA */
  171. for(i=0;i<nclistlength(dodsextra);i++) {
  172. OCobject das = (OCobject)nclistget(dodsextra,i);
  173. mergedas1(nccomm,conn,ddsroot,das);
  174. }
  175. done: /* cleanup*/
  176. nullfree(dasobjects);
  177. nclistfree(dasglobals);
  178. nclistfree(dasnodes);
  179. nclistfree(dodsextra);
  180. nclistfree(varnodes);
  181. if(ocstat != OC_NOERR) ncerr = ocerrtoncerr(ocstat);
  182. return THROW(ncerr);
  183. }
  184. static int
  185. mergedas1(NCDAPCOMMON* nccomm, OCconnection conn, CDFnode* dds, OCobject das)
  186. {
  187. NCerror ncstat = NC_NOERR;
  188. OCerror ocstat = OC_NOERR;
  189. unsigned int i,j,k;
  190. unsigned int nsubnodes;
  191. OCobject* subnodes = NULL;
  192. OCobject* dodsnodes = NULL;
  193. unsigned int ndodsnodes;
  194. if(dds == NULL || das == OCNULL) return NC_NOERR; /* nothing to do */
  195. if(dds->attributes == NULL) dds->attributes = nclistnew();
  196. /* assign the simple attributes in the das set to this dds node*/
  197. OCHECK(oc_inq_nsubnodes(conn,das,&nsubnodes));
  198. OCHECK(oc_inq_subnodes(conn,das,&subnodes));
  199. for(i=0;i<nsubnodes;i++) {
  200. OCobject attnode = subnodes[i];
  201. OCtype octype, ocetype;
  202. char* ocname = NULL;
  203. unsigned int ocnvalues;
  204. OCHECK(oc_inq_name(conn,attnode,&ocname));
  205. OCHECK(oc_inq_class(conn,attnode,&octype));
  206. if(octype == OC_Attribute) {
  207. NCattribute* att = NULL;
  208. NClist* stringvalues;
  209. OCHECK(oc_inq_primtype(conn,attnode,&ocetype));
  210. OCHECK(oc_inq_dasattr_nvalues(conn,attnode,&ocnvalues));
  211. stringvalues = nclistnew();
  212. for(j=0;j<ocnvalues;j++) {
  213. char* stringval;
  214. OCHECK(oc_inq_dasattr(conn,attnode,j,&ocetype,&stringval));
  215. nclistpush(stringvalues,(ncelem)stringval);
  216. }
  217. ncstat = buildattribute(ocname,
  218. octypetonc(ocetype),
  219. stringvalues,
  220. &att);
  221. if(ncstat) goto done;
  222. nclistpush(dds->attributes,(ncelem)att);
  223. } else if(octype == OC_Attributeset
  224. && (strcmp(ocname,"DODS")==0
  225. || strcmp(ocname,"DODS_EXTRA")==0)) {
  226. /* Turn the DODS special attributes into into
  227. special attributes for dds node */
  228. OCHECK(oc_inq_nsubnodes(conn,attnode,&ndodsnodes));
  229. OCHECK(oc_inq_subnodes(conn,attnode,&dodsnodes));
  230. for(j=0;j<ndodsnodes;j++) {
  231. char* dodsname = NULL;
  232. char newname[4096];
  233. OCobject attnode = dodsnodes[j];
  234. NCattribute* att = NULL;
  235. NClist* stringvalues;
  236. OCHECK(oc_inq_class(conn,attnode,&octype));
  237. if(octype != OC_Attribute) continue;
  238. OCHECK(oc_inq_primtype(conn,attnode,&ocetype));
  239. OCHECK(oc_inq_dasattr_nvalues(conn,attnode,&ocnvalues));
  240. stringvalues = nclistnew();
  241. for(k=0;k<ocnvalues;k++) {
  242. char* stringval;
  243. OCHECK(oc_inq_dasattr(conn,attnode,k,&ocetype,&stringval));
  244. nclistpush(stringvalues,(ncelem)stringval);
  245. }
  246. OCHECK(oc_inq_name(conn,attnode,&dodsname));
  247. /* Compute new special name */
  248. strcpy(newname,"_DODS_");
  249. strcat(newname,dodsname);
  250. ncstat = buildattribute(newname,
  251. octypetonc(ocetype),
  252. stringvalues,
  253. &att);
  254. if(ncstat) goto done;
  255. att->invisible = 1;
  256. nclistpush(dds->attributes,(ncelem)att);
  257. /* Define extra semantics associated with DODS and DODS_EXTRA attribute */
  258. if(strcmp(dodsname,"strlen")==0) {
  259. unsigned int maxstrlen = 0;
  260. if(nclistlength(stringvalues) > 0) {
  261. char* stringval = (char*)nclistget(stringvalues,0);
  262. if(0==sscanf(stringval,"%u",&maxstrlen)) maxstrlen = 0;
  263. }
  264. dds->dodsspecial.maxstrlen = maxstrlen;
  265. #ifdef DEBUG
  266. fprintf(stderr,"%s.maxstrlen=%d\n",dds->ocname,(int)dds->dodsspecial.maxstrlen);
  267. #endif
  268. } else if(strcmp(dodsname,"dimName")==0) {
  269. if(nclistlength(stringvalues) > 0) {
  270. char* stringval = (char*)nclistget(stringvalues,0);
  271. dds->dodsspecial.dimname = nulldup(stringval);
  272. #ifdef DEBUG
  273. fprintf(stderr,"%s.dimname=%s\n",dds->ocname,dds->dodsspecial.dimname);
  274. #endif
  275. } else dds->dodsspecial.dimname = NULL;
  276. } else if(strcmp(dodsname,"Unlimited_Dimension")==0) {
  277. if(nccomm->cdf.recorddimname != NULL) {
  278. nclog(NCLOGWARN,"Duplicate DODS_EXTRA:Unlimited_Dimension specifications");
  279. } else if(nclistlength(stringvalues) > 0) {
  280. char* stringval = (char*)nclistget(stringvalues,0);
  281. nccomm->cdf.recorddimname = nulldup(stringval);
  282. #ifdef DEBUG
  283. fprintf(stderr,"%s.Unlimited_Dimension=%s\n",dds->ocname,nccomm->cdf.recorddimname);
  284. #endif
  285. }
  286. } /* else ignore */
  287. nullfree(dodsname);
  288. }
  289. nullfree(dodsnodes);
  290. }
  291. nullfree(ocname);
  292. }
  293. done:
  294. nullfree(subnodes);
  295. if(ocstat != OC_NOERR) ncstat = ocerrtoncerr(ocstat);
  296. return THROW(ncstat);
  297. }
  298. static int
  299. isglobalname3(char* name)
  300. {
  301. int len = strlen(name);
  302. int glen = strlen("global");
  303. char* p;
  304. if(len < glen) return 0;
  305. p = name + (len - glen);
  306. if(strcasecmp(p,"global") != 0)
  307. return 0;
  308. return 1;
  309. }