[1022] | 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 | |
---|