1 /* Copyright 2018, UCAR/Unidata and OPeNDAP, Inc.
2 See the COPYRIGHT file for more information. */
3
4 #include "config.h"
5 #include "ocinternal.h"
6 #include "occompile.h"
7 #include "ocdebug.h"
8
9 static OCerror mergedas1(OCnode* dds, OCnode* das);
10 static OCerror mergedods1(OCnode* dds, OCnode* das);
11 static OCerror mergeother1(OCnode* root, OCnode* das);
12 static char* pathtostring(NClist* path, char* separator);
13 static void computefullname(OCnode* node);
14 static OCerror mergeother1(OCnode* root, OCnode* das);
15 static OCerror mergeother(OCnode* ddsroot, NClist* dasnodes);
16
17 /* Process ocnodes to fix various semantic issues*/
18 void
occomputesemantics(NClist * ocnodes)19 occomputesemantics(NClist* ocnodes)
20 {
21 unsigned int i,j;
22 OCASSERT((ocnodes != NULL));
23 for(i=0;i<nclistlength(ocnodes);i++) {
24 OCnode* node = (OCnode*)nclistget(ocnodes,i);
25 /* set the container for dims*/
26 if(node->octype == OC_Dimension && node->dim.array != NULL) {
27 node->container = node->dim.array->container;
28 }
29 }
30 /* Fill in array.sizes */
31 for(i=0;i<nclistlength(ocnodes);i++) {
32 OCnode* node = (OCnode*)nclistget(ocnodes,i);
33 if(node->array.rank > 0) {
34 node->array.sizes = (size_t*)malloc(node->array.rank*sizeof(size_t));
35 for(j=0;j<node->array.rank;j++) {
36 OCnode* dim = (OCnode*)nclistget(node->array.dimensions,j);
37 node->array.sizes[j] = dim->dim.declsize;
38 }
39 }
40 }
41 }
42
43 void
occomputefullnames(OCnode * root)44 occomputefullnames(OCnode* root)
45 {
46 unsigned int i;
47 if(root->name != NULL) computefullname(root);
48 if(root->subnodes != NULL) { /* recurse*/
49 for(i=0;i<nclistlength(root->subnodes);i++) {
50 OCnode* node = (OCnode*)nclistget(root->subnodes,i);
51 occomputefullnames(node);
52 }
53 }
54 }
55
56 static void
computefullname(OCnode * node)57 computefullname(OCnode* node)
58 {
59 char* tmp;
60 char* fullname;
61 NClist* path;
62
63 OCASSERT((node->name != NULL));
64 if(node->fullname != NULL)
65 return;
66 path = nclistnew();
67 occollectpathtonode(node,path);
68 tmp = pathtostring(path,PATHSEPARATOR);
69 if(tmp == NULL) {
70 fullname = nulldup(node->name);
71 } else {
72 fullname = tmp;
73 }
74 node->fullname = fullname;
75 nclistfree(path);
76 }
77
78 /* Convert path to a string */
79 static char*
pathtostring(NClist * path,char * separator)80 pathtostring(NClist* path, char* separator)
81 {
82 int slen,i,len;
83 char* pathname;
84 if(path == NULL) return NULL;
85 len = nclistlength(path);
86 if(len == 0) return NULL;
87 for(i=0,slen=0;i<len;i++) {
88 OCnode* node = (OCnode*)nclistget(path,(size_t)i);
89 if(node->container == NULL || node->name == NULL) continue;
90 slen += strlen(node->name);
91 }
92 slen += ((len-1)*strlen(separator));
93 slen += 1; /* for null terminator*/
94 pathname = (char*)ocmalloc((size_t)slen);
95 MEMCHECK(pathname,NULL);
96 pathname[0] = '\0';
97 for(i=0;i<len;i++) {
98 OCnode* node = (OCnode*)nclistget(path,(size_t)i);
99 if(node->container == NULL || node->name == NULL) continue;
100 if(strlen(pathname) > 0) strcat(pathname,separator);
101 strcat(pathname,node->name);
102 }
103 return pathname;
104 }
105
106 /* Collect the set of nodes ending in "node"*/
107 void
occollectpathtonode(OCnode * node,NClist * path)108 occollectpathtonode(OCnode* node, NClist* path)
109 {
110 if(node == NULL) return;
111 occollectpathtonode(node->container,path);
112 nclistpush(path,(void*)node);
113 }
114
115 OCnode*
ocnode_new(char * name,OCtype ptype,OCnode * root)116 ocnode_new(char* name, OCtype ptype, OCnode* root)
117 {
118 OCnode* cdf = (OCnode*)ocmalloc(sizeof(OCnode));
119 MEMCHECK(cdf,(OCnode*)NULL);
120 memset((void*)cdf,0,sizeof(OCnode));
121 cdf->header.magic = OCMAGIC;
122 cdf->header.occlass = OC_Node;
123 cdf->name = (name?nulldup(name):NULL);
124 cdf->octype = ptype;
125 cdf->array.dimensions = NULL;
126 cdf->root = root;
127 return cdf;
128 }
129
130 static OCattribute*
makeattribute(char * name,OCtype ptype,NClist * values)131 makeattribute(char* name, OCtype ptype, NClist* values)
132 {
133 OCattribute* att = (OCattribute*)ocmalloc(sizeof(OCattribute)); /* ocmalloc zeros*/
134 MEMCHECK(att,(OCattribute*)NULL);
135 att->name = nulldup(name);
136 att->etype = ptype;
137 att->nvalues = nclistlength(values);
138 att->values = NULL;
139 if(att->nvalues > 0) {
140 int i;
141 att->values = (char**)ocmalloc(sizeof(char*)*att->nvalues);
142 for(i=0;i<att->nvalues;i++)
143 att->values[i] = nulldup((char*)nclistget(values,(size_t)i));
144 }
145 return att;
146 }
147
148 void
ocroot_free(OCnode * root)149 ocroot_free(OCnode* root)
150 {
151 OCtree* tree;
152 OCstate* state;
153 int i;
154
155 if(root == NULL || root->tree == NULL) return;
156
157 tree = root->tree;
158 state = tree->state;
159
160 /* Free up the OCDATA instance, if any */
161 if(tree->data.data != NULL)
162 ocdata_free(state,tree->data.data);
163
164 for(i=0;i<nclistlength(state->trees);i++) {
165 OCnode* node = (OCnode*)nclistget(state->trees,(size_t)i);
166 if(root == node)
167 nclistremove(state->trees,(size_t)i);
168 }
169 /* Note: it is ok if state->trees does not contain this root */
170 octree_free(tree);
171 }
172
173 void
octree_free(OCtree * tree)174 octree_free(OCtree* tree)
175 {
176 if(tree == NULL) return;
177 ocnodes_free(tree->nodes);
178 ocfree(tree->constraint);
179 ocfree(tree->text);
180 if(tree->data.xdrs != NULL) {
181 xxdr_free(tree->data.xdrs);
182 }
183 ocfree(tree->data.filename); /* may be null */
184 if(tree->data.file != NULL) fclose(tree->data.file);
185 ocfree(tree->data.memory);
186 ocfree(tree);
187 }
188
189 void
ocnodes_free(NClist * nodes)190 ocnodes_free(NClist* nodes)
191 {
192 unsigned int i,j;
193 for(i=0;i<nclistlength(nodes);i++) {
194 OCnode* node = (OCnode*)nclistget(nodes,i);
195 ocfree(node->name);
196 ocfree(node->fullname);
197 while(nclistlength(node->att.values) > 0) {
198 char* value = (char*)nclistpop(node->att.values);
199 ocfree(value);
200 }
201 while(nclistlength(node->attributes) > 0) {
202 OCattribute* attr = (OCattribute*)nclistpop(node->attributes);
203 ocfree(attr->name);
204 #if 0
205 /* If the attribute type is string, then we need to free them*/
206 all values are strings now
207 if(attr->etype == OC_String || attr->etype == OC_URL)
208 #endif
209 {
210 char** strings = (char**)attr->values;
211 for(j=0;j<attr->nvalues;j++) {ocfree(*strings); strings++;}
212 }
213 ocfree(attr->values);
214 ocfree(attr);
215 }
216 if(node->array.dimensions != NULL) nclistfree(node->array.dimensions);
217 if(node->subnodes != NULL) nclistfree(node->subnodes);
218 if(node->att.values != NULL) nclistfree(node->att.values);
219 if(node->attributes != NULL) nclistfree(node->attributes);
220 if(node->array.sizes != NULL) free(node->array.sizes);
221 ocfree(node);
222 }
223 nclistfree(nodes);
224 }
225
226 /*
227 In order to be as compatible as possible with libdap,
228 we try to use the same algorithm for DAS->DDS matching.
229 As described there, the algorithm is as follows.
230 If the [attribute] name contains one or
231 more field separators then look for a [DDS]variable whose
232 name matches exactly. If the name contains no field separators then
233 the look first in the top level [of the DDS] and then in all subsequent
234 levels and return the first occurrence found. In general, this
235 searches constructor types in the order in which they appear
236 in the DDS, but there is no requirement that it do so.
237
238 Note: If a dataset contains two constructor types which have field names
239 that are the same (say point.x and pair.x) one should use fully qualified
240 names to get each of those variables.
241
242 */
243
244 OCerror
ocddsdasmerge(OCstate * state,OCnode * dasroot,OCnode * ddsroot)245 ocddsdasmerge(OCstate* state, OCnode* dasroot, OCnode* ddsroot)
246 {
247 OCerror stat = OC_NOERR;
248 NClist* dasglobals = nclistnew();
249 NClist* dodsglobals = nclistnew(); /* top-level DODS_XXX {...} */
250 NClist* dasnodes = nclistnew();
251 NClist* varnodes = nclistnew();
252 NClist* ddsnodes;
253 unsigned int i,j;
254
255 if(dasroot->tree == NULL || dasroot->tree->dxdclass != OCDAS)
256 {stat = OCTHROW(OC_EINVAL); goto done;}
257 if(ddsroot->tree == NULL || (ddsroot->tree->dxdclass != OCDDS
258 && ddsroot->tree->dxdclass != OCDATADDS))
259 {stat = OCTHROW(OC_EINVAL); goto done;}
260
261 ddsnodes = ddsroot->tree->nodes;
262
263 /* 1. collect all the relevant DAS nodes;
264 namely those that contain at least one
265 attribute value, not including the leaf attributes.
266 Simultaneously look for potential ambiguities
267 if found; complain but continue: result are indeterminate.
268 also collect globals separately*/
269 for(i=0;i<nclistlength(dasroot->tree->nodes);i++) {
270 OCnode* das = (OCnode*)nclistget(dasroot->tree->nodes,i);
271 int hasattributes = 0;
272 if(das->octype == OC_Attribute) continue; /* ignore these for now*/
273 if(das->name == NULL || das->att.isglobal) {
274 nclistpush(dasglobals,(void*)das);
275 continue;
276 }
277 if(das->att.isdods) {
278 nclistpush(dodsglobals,(void*)das);
279 continue;
280 }
281 for(j=0;j<nclistlength(das->subnodes);j++) {
282 OCnode* subnode = (OCnode*)nclistget(das->subnodes,j);
283 if(subnode->octype == OC_Attribute) {hasattributes = 1; break;}
284 }
285 if(hasattributes) {
286 /* Look for previously collected nodes with same name*/
287 for(j=0;j<nclistlength(dasnodes);j++) {
288 OCnode* das2 = (OCnode*)nclistget(dasnodes,j);
289 if(das->name == NULL || das2->name == NULL) continue;
290 if(strcmp(das->name,das2->name)==0) {
291 nclog(NCLOGWARN,"oc_mergedas: potentially ambiguous DAS name: %s",das->name);
292 }
293 }
294 nclistpush(dasnodes,(void*)das);
295 }
296 }
297
298 /* 2. collect all the leaf DDS nodes (of type OC_Atomic)*/
299 for(i=0;i<nclistlength(ddsnodes);i++) {
300 OCnode* dds = (OCnode*)nclistget(ddsnodes,i);
301 if(dds->octype == OC_Atomic) nclistpush(varnodes,(void*)dds);
302 }
303
304 /* 3. For each das node, locate matching DDS node(s) and attach
305 attributes to the DDS node(s).
306 Match means:
307 1. DAS->fullname :: DDS->fullname
308 2. DAS->name :: DDS->fullname (support DAS names with embedded '.')
309 3. DAS->name :: DDS->name
310 */
311 for(i=0;i<nclistlength(dasnodes);i++) {
312 OCnode* das = (OCnode*)nclistget(dasnodes,i);
313 for(j=0;j<nclistlength(varnodes);j++) {
314 OCnode* dds = (OCnode*)nclistget(varnodes,j);
315 if(strcmp(das->fullname,dds->fullname)==0
316 || strcmp(das->name,dds->fullname)==0
317 || strcmp(das->name,dds->name)==0) {
318 mergedas1(dds,das);
319 /* remove from dasnodes list*/
320 nclistset(dasnodes,i,(void*)NULL);
321 }
322 }
323 }
324
325 /* 4. Assign globals*/
326 for(i=0;i<nclistlength(dasglobals);i++) {
327 OCnode* das = (OCnode*)nclistget(dasglobals,i);
328 if(das == NULL) continue;
329 mergedas1(ddsroot,das);
330 }
331 /* 5. Assign DODS_*/
332 for(i=0;i<nclistlength(dodsglobals);i++) {
333 OCnode* das = (OCnode*)nclistget(dodsglobals,i);
334 if(das == NULL) continue;
335 mergedods1(ddsroot,das);
336 }
337
338 /* 6. Assign other orphan attributes, which means
339 construct their full name and assign as a global attribute.
340 This is complicated because some servers (e.g. thredds) returns
341 attributes for variables that were not referenced in the DDS.
342 These we continue to suppress.
343 */
344 mergeother(ddsroot,dasnodes);
345
346 done:
347 /* cleanup*/
348 nclistfree(dasglobals);
349 nclistfree(dodsglobals);
350 nclistfree(dasnodes);
351 nclistfree(varnodes);
352 return OCTHROW(stat);
353 }
354
355 static OCerror
mergedas1(OCnode * dds,OCnode * das)356 mergedas1(OCnode* dds, OCnode* das)
357 {
358 unsigned int i;
359 OCerror stat = OC_NOERR;
360 if(das == NULL) return OC_NOERR; /* nothing to do */
361 if(dds->attributes == NULL) dds->attributes = nclistnew();
362 /* assign the simple attributes in the das set to this dds node*/
363 for(i=0;i<nclistlength(das->subnodes);i++) {
364 OCnode* attnode = (OCnode*)nclistget(das->subnodes,i);
365 if(attnode->octype == OC_Attribute) {
366 OCattribute* att;
367 if(dds->octype == OC_Atomic
368 || dds->octype == OC_Sequence
369 || dds->octype == OC_Structure
370 || dds->octype == OC_Grid)
371 attnode->att.var = dds;
372 att = makeattribute(attnode->name,
373 attnode->etype,
374 attnode->att.values);
375 nclistpush(dds->attributes,(void*)att);
376 }
377 }
378 return OCTHROW(stat);
379 }
380
381 static OCerror
mergedods1(OCnode * dds,OCnode * dods)382 mergedods1(OCnode* dds, OCnode* dods)
383 {
384 unsigned int i;
385 OCerror stat = OC_NOERR;
386 if(dods == NULL) return OC_NOERR; /* nothing to do */
387 OCASSERT(dods->octype == OC_Attributeset);
388 if(dds->attributes == NULL) dds->attributes = nclistnew();
389 /* assign the simple attributes in the das set to this dds node
390 with renaming to tag as DODS_
391 */
392 for(i=0;i<nclistlength(dods->subnodes);i++) {
393 OCnode* attnode = (OCnode*)nclistget(dods->subnodes,i);
394 if(attnode->octype == OC_Attribute) {
395 OCattribute* att;
396 /* prefix the attribute name with the name of the attribute
397 set plus "."
398 */
399 size_t len = strlen(attnode->name)
400 + strlen(dods->name)
401 + strlen(".");
402 len++; /*strlcat nul*/
403 char* newname = (char*)malloc(len+1);
404 if(newname == NULL) return OC_ENOMEM;
405 strncpy(newname,dods->name,len);
406 strlcat(newname,".",len);
407 strlcat(newname,attnode->name,len);
408 att = makeattribute(newname,attnode->etype,attnode->att.values);
409 free(newname);
410 nclistpush(dds->attributes,(void*)att);
411 }
412 }
413 return OCTHROW(stat);
414 }
415
416 static OCerror
mergeother(OCnode * ddsroot,NClist * dasnodes)417 mergeother(OCnode* ddsroot, NClist* dasnodes)
418 {
419 OCerror stat = OC_NOERR;
420 int i;
421 for(i=0;i<nclistlength(dasnodes);i++) {
422 OCnode* das = (OCnode*)nclistget(dasnodes,i);
423 if(das == NULL) continue;
424 if((stat = mergeother1(ddsroot, das))) break;
425 }
426 return stat;
427 }
428
429 static OCerror
mergeother1(OCnode * root,OCnode * das)430 mergeother1(OCnode* root, OCnode* das)
431 {
432 OCerror stat = OC_NOERR;
433 OCattribute* att = NULL;
434
435 OCASSERT(root != NULL);
436 if(root->attributes == NULL) root->attributes = nclistnew();
437
438 /* Only include if this is not connected to a variable */
439 if(das->att.var != NULL) goto done;
440
441 if(das->octype == OC_Attribute) {
442 /* compute the full name of this attribute */
443 computefullname(das);
444 /* create attribute */
445 att = makeattribute(das->fullname,das->etype,das->att.values);
446 nclistpush(root->attributes,(void*)att);
447 } else if(das->octype == OC_Attributeset) {
448 int i;
449 /* Recurse */
450 for(i=0;i<nclistlength(das->subnodes);i++) {
451 OCnode* sub = (OCnode*)nclistget(das->subnodes,i);
452 if(sub == NULL) continue;
453 mergeother1(root,sub);
454 }
455 } else
456 stat = OC_EDAS;
457 done:
458 return OCTHROW(stat);
459 }
460
461 static void
ocuncorrelate(OCnode * root)462 ocuncorrelate(OCnode* root)
463 {
464 OCtree* tree = root->tree;
465 unsigned int i;
466 if(tree == NULL) return;
467 for(i=0;i<nclistlength(tree->nodes);i++) {
468 OCnode* node = (OCnode*)nclistget(tree->nodes,i);
469 node->datadds = NULL;
470 }
471 }
472
473 static OCerror
occorrelater(OCnode * dds,OCnode * dxd)474 occorrelater(OCnode* dds, OCnode* dxd)
475 {
476 int i,j;
477 OCerror ocstat = OC_NOERR;
478
479 if(dds->octype != dxd->octype) {
480 OCTHROWCHK((ocstat = OC_EINVAL)); goto fail;
481 }
482 if(dxd->name != NULL && dxd->name != NULL
483 && strcmp(dxd->name,dds->name) != 0) {
484 OCTHROWCHK((ocstat = OC_EINVAL)); goto fail;
485 } else if(dxd->name != dds->name) { /* test NULL==NULL */
486 OCTHROWCHK((ocstat = OC_EINVAL)); goto fail;
487 }
488
489 if(dxd->array.rank != dds->array.rank) {
490 OCTHROWCHK((ocstat = OC_EINVAL)); goto fail;
491 }
492
493 dds->datadds = dxd;
494
495 switch (dds->octype) {
496 case OC_Dataset:
497 case OC_Structure:
498 case OC_Grid:
499 case OC_Sequence:
500 /* Remember: there may be fewer datadds fields than dds fields */
501 for(i=0;i<nclistlength(dxd->subnodes);i++) {
502 OCnode* dxd1 = (OCnode*)nclistget(dxd->subnodes,(size_t)i);
503 for(j=0;j<nclistlength(dds->subnodes);j++) {
504 OCnode* dds1 = (OCnode*)nclistget(dds->subnodes,(size_t)j);
505 if(strcmp(dxd1->name,dds1->name) == 0) {
506 ocstat = occorrelater(dds1,dxd1);
507 if(ocstat != OC_NOERR) {OCTHROWCHK(ocstat); goto fail;}
508 break;
509 }
510 }
511 }
512 break;
513 case OC_Dimension:
514 case OC_Atomic:
515 break;
516 default: OCPANIC1("unexpected node type: %d",dds->octype);
517 }
518 /* Correlate the dimensions */
519 if(dds->array.rank > 0) {
520 for(i=0;i<nclistlength(dxd->subnodes);i++) {
521 OCnode* ddsdim = (OCnode*)nclistget(dds->array.dimensions,(size_t)i);
522 OCnode* dxddim = (OCnode*)nclistget(dxd->array.dimensions,(size_t)i);
523 ocstat = occorrelater(ddsdim,dxddim);
524 if(!ocstat) goto fail;
525 }
526 }
527
528 fail:
529 return OCTHROW(ocstat);
530
531 }
532
533 OCerror
occorrelate(OCnode * dds,OCnode * dxd)534 occorrelate(OCnode* dds, OCnode* dxd)
535 {
536 if(dds == NULL || dxd == NULL) return OCTHROW(OC_EINVAL);
537 ocuncorrelate(dds);
538 return occorrelater(dds,dxd);
539 }
540
541 /*
542 Mark cacheable those atomic String/URL typed nodes
543 that are contained only in structures with rank > 0.
544 */
545 void
ocmarkcacheable(OCstate * state,OCnode * ddsroot)546 ocmarkcacheable(OCstate* state, OCnode* ddsroot)
547 {
548 int i,j;
549 #if 0
550 int ok;
551 #endif
552 NClist* treenodes = ddsroot->tree->nodes;
553 NClist* path = nclistnew();
554 for(i=0;i<nclistlength(treenodes);i++) {
555 OCnode* node = (OCnode*)nclistget(treenodes,(size_t)i);
556 if(node->octype != OC_Atomic) continue;
557 if(node->etype != OC_String && node->etype != OC_URL) continue;
558 /* collect node path */
559 nclistclear(path);
560 occollectpathtonode(node,path);
561 #if 0
562 ok = 1;
563 #endif
564 for(j=1;j<nclistlength(path)-1;j++) {/* skip top level dataset and node itself*/
565 OCnode* pathnode = (OCnode*)nclistget(path,(size_t)j);
566 if(pathnode->octype != OC_Structure
567 || pathnode->array.rank > 0) {
568 #if 0
569 ok=0;
570 #endif
571 break;
572 }
573 }
574 #if 0
575 if(ok) {
576 node->cache.cacheable = 1;
577 node->cache.valid = 0;
578 }
579 #endif
580 }
581 nclistfree(path);
582 }
583
584 #if 0
585
586 OCerror
587 ocddsdasmerge(OCstate* state, OCnode* ddsroot, OCnode* dasroot)
588 {
589 int i,j;
590 OCerror stat = OC_NOERR;
591 NClist* globals = nclistnew();
592 if(dasroot == NULL) return OCTHROW(stat);
593 /* Start by looking for global attributes*/
594 for(i=0;i<nclistlength(dasroot->subnodes);i++) {
595 OCnode* node = (OCnode*)nclistget(dasroot->subnodes,i);
596 if(node->att.isglobal) {
597 for(j=0;j<nclistlength(node->subnodes);j++) {
598 OCnode* attnode = (OCnode*)nclistget(node->subnodes,j);
599 Attribute* att = makeattribute(attnode->name,
600 attnode->etype,
601 attnode->att.values);
602 nclistpush(globals,(void*)att);
603 }
604 }
605 }
606 ddsroot->attributes = globals;
607 /* Now try to match subnode names with attribute set names*/
608 for(i=0;i<nclistlength(dasroot->subnodes);i++) {
609 OCnode* das = (OCnode*)nclistget(dasroot->subnodes,i);
610 int match = 0;
611 if(das->att.isglobal) continue;
612 if(das->octype == OC_Attributeset) {
613 for(j=0;j<nclistlength(ddsroot->subnodes) && !match;j++) {
614 OCnode* dds = (OCnode*)nclistget(ddsroot->subnodes,j);
615 if(strcmp(das->name,dds->name) == 0) {
616 match = 1;
617 stat = mergedas1(dds,das);
618 if(stat != OC_NOERR) break;
619 }
620 }
621 }
622 if(!match) {marklostattribute(das);}
623 }
624 if(stat == OC_NOERR) ddsroot->attributed = 1;
625 return OCTHROW(stat);
626 }
627
628 /* Merge das attributes into the dds node*/
629
630 static int
631 mergedas1(OCnode* dds, OCnode* das)
632 {
633 int i,j;
634 int stat = OC_NOERR;
635 if(dds->attributes == NULL) dds->attributes = nclistnew();
636 /* assign the simple attributes in the das set to this dds node*/
637 for(i=0;i<nclistlength(das->subnodes);i++) {
638 OCnode* attnode = (OCnode*)nclistget(das->subnodes,i);
639 if(attnode->octype == OC_Attribute) {
640 Attribute* att = makeattribute(attnode->name,
641 attnode->etype,
642 attnode->att.values);
643 nclistpush(dds->attributes,(void*)att);
644 }
645 }
646 /* Try to merge any enclosed sets with subnodes of dds*/
647 for(i=0;i<nclistlength(das->subnodes);i++) {
648 OCnode* dasnode = (OCnode*)nclistget(das->subnodes,i);
649 int match = 0;
650 if(dasnode->octype == OC_Attribute) continue; /* already dealt with above*/
651 for(j=0;j<nclistlength(dds->subnodes) && !match;j++) {
652 OCnode* ddsnode = (OCnode*)nclistget(dds->subnodes,j);
653 if(strcmp(dasnode->name,ddsnode->name) == 0) {
654 match = 1;
655 stat = mergedas1(ddsnode,dasnode);
656 if(stat != OC_NOERR) break;
657 }
658 }
659 if(!match) {marklostattribute(dasnode);}
660 }
661 return OCTHROW(stat);
662 }
663
664 void*
665 oclinearize(OCtype etype, unsigned int nstrings, char** strings)
666 {
667 int i;
668 size_t typesize;
669 char* memp;
670 char* memory;
671
672 if(nstrings == 0) return NULL;
673 typesize = octypesize(etype);
674 memory = (char*)ocmalloc(nstrings*typesize);
675 MEMCHECK(memory,NULL);
676 memp = memory;
677 for(i=0;i<nstrings;i++) {
678 char* value = strings[i];
679 converttype(etype,value,memp);
680 memp += typesize;
681 }
682 return memory;
683 }
684
685 static int
686 converttype(OCtype etype, char* value, char* memory)
687 {
688 long iv;
689 unsigned long uiv;
690 double dv;
691 char c[1];
692 int outofrange = 0;
693 #ifdef HAVE_LONG_LONG_INT
694 long long llv;
695 unsigned long long ullv;
696 #endif
697
698 switch (etype) {
699 case OC_Char:
700 if(sscanf(value,"%c",c) != 1) goto fail;
701 *((char*)memory) = c[0];
702 break;
703 case OC_Byte:
704 if(sscanf(value,"%ld",&iv) != 1) goto fail;
705 else if(iv > OC_BYTE_MAX || iv < OC_BYTE_MIN) {iv = OC_BYTE_MAX; outofrange = 1;}
706 *((signed char*)memory) = (signed char)iv;
707 break;
708 case OC_UByte:
709 if(sscanf(value,"%lu",&uiv) != 1) goto fail;
710 else if(uiv > OC_UBYTE_MAX) {uiv = OC_UBYTE_MAX; outofrange = 1;}
711 *((unsigned char*)memory) = (unsigned char)uiv;
712 break;
713 case OC_Int16:
714 if(sscanf(value,"%ld",&iv) != 1) goto fail;
715 else if(iv > OC_INT16_MAX || iv < OC_INT16_MIN) {iv = OC_INT16_MAX; outofrange = 1;}
716 *((signed short*)memory) = (signed short)iv;
717 break;
718 case OC_UInt16:
719 if(sscanf(value,"%lu",&uiv) != 1) goto fail;
720 else if(uiv > OC_UINT16_MAX) {uiv = OC_UINT16_MAX; outofrange = 1;}
721 *((unsigned short*)memory) = (unsigned short)uiv;
722 break;
723 case OC_Int32:
724 if(sscanf(value,"%ld",&iv) != 1) goto fail;
725 else if(iv > OC_INT32_MAX || iv < OC_INT32_MIN) {iv = OC_INT32_MAX; outofrange = 1;}
726 *((signed int*)memory) = (signed int)iv;
727 break;
728 case OC_UInt32:
729 if(sscanf(value,"%lu",&uiv) != 1) goto fail;
730 else if(uiv > OC_UINT32_MAX) {uiv = OC_UINT32_MAX; outofrange = 1;}
731 *((unsigned char*)memory) = (unsigned int)uiv;
732 break;
733 #ifdef HAVE_LONG_LONG_INT
734 case OC_Int64:
735 if(sscanf(value,"%lld",&llv) != 1) goto fail;
736 /*else if(iv > OC_INT64_MAX || iv < OC_INT64_MIN) goto fail;*/
737 *((signed long long*)memory) = (signed long long)llv;
738 break;
739 case OC_UInt64:
740 if(sscanf(value,"%llu",&ullv) != 1) goto fail;
741 *((unsigned long long*)memory) = (unsigned long long)ullv;
742 break;
743 #endif
744 case OC_Float32:
745 if(sscanf(value,"%lf",&dv) != 1) goto fail;
746 *((float*)memory) = (float)dv;
747 break;
748 case OC_Float64:
749 if(sscanf(value,"%lf",&dv) != 1) goto fail;
750 *((double*)memory) = (double)dv;
751 break;
752 case OC_String: case OC_URL:
753 *((char**)memory) = nulldup(value);
754 break;
755 default:
756 goto fail;
757 }
758 if(outofrange)
759 oc_log(LOGWARN,"converttype range failure: %d: %s",etype,value);
760 return 1;
761 fail:
762 oc_log(LOGERR,"converttype bad value: %d: %s",etype,value);
763 return 0;
764 }
765 #endif /*0*/
766