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