1 /***********************************************************************/
2 /* Open Visualization Data Explorer                                    */
3 /* (C) Copyright IBM Corp. 1989,1999                                   */
4 /* ALL RIGHTS RESERVED                                                 */
5 /* This code licensed under the                                        */
6 /*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
7 /***********************************************************************/
8 
9 #include <dxconfig.h>
10 
11 
12 
13 #include <string.h>
14 #include <stdarg.h>
15 #include "groupClass.h"
16 
17 
18 static Group _CopyGroup(Group new, Group old, enum _dxd_copy copy);
19 
20 #define RANKTEST(rval) \
21     if (rank>=100) { \
22 	DXSetError(ERROR_DATA_INVALID, "cannot support rank >= 100"); \
23 	return rval; \
24     }
25 
26 /*
27  * XXX - create and move to util.c
28  */
29 
30 static
31 char *
CopyString(char * s)32 CopyString(char *s)
33 {
34     if (s) {
35 	int n = strlen(s) + 1;
36 	char *c = DXAllocate(n);
37 	if (c)
38 	    strcpy(c, s);
39 	return c;
40     } else
41 	return NULL;
42 }
43 
44 
45 Group
_dxf_NewGroup(struct group_class * class)46 _dxf_NewGroup(struct group_class *class)
47 {
48     struct group *g = (Group) _dxf_NewObject((struct object_class *)class);
49     if (!g)
50 	return NULL;
51     if (!DXcreate_lock(&g->lock, "group"))
52 	return NULL;
53     /* everything else is initialized to 0 */
54     return g;
55 }
56 
57 
58 Group
DXNewGroup(void)59 DXNewGroup(void)
60 {
61     return _dxf_NewGroup(&_dxdgroup_class);
62 }
63 
64 
65 /*
66  * DXCopy.  DXWarning: this code is essentially the same as the
67  * code for Series_Copy, until the loop at the end that does the copy.
68  * If you change anything here, check that code also.
69  */
70 
71 
72 Object
_dxfGroup_Copy(Group old,enum _dxd_copy copy)73 _dxfGroup_Copy(Group old, enum _dxd_copy copy)
74 {
75     Group new;
76 
77     new = DXNewGroup();
78     if (!new)
79 	return NULL;
80 
81     /*
82      * XXX - copy the class here, so this routine suffices
83      * for all subclasses.  Is this really OK?
84      */
85     new->object.class = old->object.class;
86     new->object.class_id = old->object.class_id;
87 
88     /* XXX - check return code and delete new */
89     if (! _CopyGroup(new, old, copy))
90     {
91 	DXDelete((Object)new);
92 	return NULL;
93     }
94 
95     return (Object)new;
96 }
97 
98 
99 static Group
_CopyGroup(Group new,Group old,enum _dxd_copy copy)100 _CopyGroup(Group new, Group old, enum _dxd_copy copy)
101 {
102     int i;
103     char *name;
104     Object val;
105 
106     /* copy superclass */
107     if (!_dxf_CopyObject((Object)new, (Object)old, copy))
108 	return NULL;
109 
110     /* done? */
111     if (copy==COPY_ATTRIBUTES)
112 	return new;
113 
114     /*
115      * XXX - should COPY_ATTRIBUTES copy the type also?  Since
116      * there is no way to reset it, it is inconvenient if it does so.
117      * It seems unlikely that anyone would want to create an empty
118      * group and copy the type.
119      */
120     new->typed = old->typed;
121     new->type = old->type;
122     new->category = old->category;
123     new->rank = old->rank;
124     if (old->shape) {
125 	new->shape = (int *) DXAllocate(old->rank * sizeof(*(old->shape)));
126 	if (! new->shape)
127 	    return NULL;
128 	for (i=0; i<old->rank; i++)
129 	    new->shape[i] = old->shape[i];
130     } else
131 	new->shape = NULL;
132 
133     /* copy the members */
134     for (i=0; (val = DXGetEnumeratedMember(old, i, &name)); i++) {
135 	if (copy!=COPY_HEADER) {
136 	    val = DXCopy(val, copy);
137 	    if (!val)
138 		return NULL;
139 	}
140 	if (! DXSetMember(new, name, val))
141 	    return NULL;
142     }
143     return new;
144 }
145 
146 
147 static
148 Error
type_check(Group g,Object value)149 type_check(Group g, Object value)
150 {
151     Type type;
152     Category category;
153     int i, rank, shape[100];
154 
155     if (!DXGetType(value, &type, &category, &rank, shape)) {
156 	if (DXGetError() != ERROR_NONE)
157 	    return ERROR;
158 	return OK;
159     }
160     RANKTEST(ERROR);
161     if (type!=g->type || category!=g->category || rank!=g->rank) {
162 	DXSetError(ERROR_BAD_PARAMETER, "#11090");
163 	return ERROR;
164     }
165     for (i=0; i<rank; i++)
166 	if (shape[i]!=g->shape[i]) {
167 	    DXSetError(ERROR_BAD_PARAMETER, "#11090");
168 	    return ERROR;
169 	}
170     return OK;
171 }
172 
173 Group
DXSetMember(Group g,char * name,Object value)174 DXSetMember(Group g, char *name, Object value)
175 {
176     return _dxfSetMember(g, name, value);
177 }
178 
179 
180 Group
_dxfGroup_SetMember(Group g,char * name,Object value)181 _dxfGroup_SetMember(Group g, char *name, Object value)
182 {
183     int i, nmembers;
184     struct member *m = NULL;
185 
186     CHECK(g, CLASS_GROUP);
187 
188     /* get the lock */
189     DXlock(&g->lock, 0);
190 
191     /* type check if appropriate */
192     if (g->typed && value && !type_check(g, value))
193 	goto error;
194 
195     /* is member there? */
196     nmembers = g->nmembers;
197     if (name) {
198 	for (i=0, m=g->members; i<nmembers; i++, m++)
199 	    if (m->name && strcmp(m->name, name)==0)
200 		break;
201     } else {
202 	/* null name => new member */
203 	i = nmembers;
204     }
205 
206     /* member is not there - add it */
207     if (i >= nmembers) {
208 	/* re-alloc if necessary */
209 	if (nmembers >= g->alloc) {
210 	    m = (struct member *) DXReAllocate((Pointer)g->members,
211 		(g->alloc=g->alloc*2+1) * sizeof(struct member));
212 	    if (!m)
213 		goto error;
214 	    g->members = m;
215 	}
216 	m = g->members + nmembers;
217 	g->nmembers = ++nmembers;
218 	m->name = CopyString(name);
219 	m->value = NULL;
220     }
221 
222     /* put value in */
223     DXReference(value);		/* do first in case value==c->comp_value */
224     DXDelete(m->value);
225     m->value = value;
226     m->position = i;
227 
228     /* copy other members down if deleting */
229     if (!value) {
230 	for (i=i+1; i<nmembers; i++)
231 	    g->members[i-1] = g->members[i];
232 	g->nmembers = --nmembers;
233     }
234 
235     DXunlock(&g->lock, 0);
236     return g;
237 
238 error:
239     DXunlock(&g->lock, 0);
240     return NULL;
241 }
242 
243 
244 Object
DXGetMember(Group g,char * name)245 DXGetMember(Group g, char *name)
246 {
247     int i;
248     struct member *m;
249 
250     CHECK(g, CLASS_GROUP);
251 
252     if (!name)
253 	DXErrorReturn(ERROR_BAD_PARAMETER, "DXGetMember given null name");
254 
255     /* is member there? */
256     for (i=0, m=g->members; i<g->nmembers; i++, m++)
257 	if (m->name && strcmp(m->name, name)==0)
258 	    break;
259 
260     /* no */
261     if (i >= g->nmembers)
262 	return NULL;
263 
264     /* yes */
265     return m->value;
266 }
267 
268 Group
DXGetMemberCount(Group g,int * n)269 DXGetMemberCount(Group g, int *n)
270 {
271     CHECK(g, CLASS_GROUP);
272     if (n)
273         *n = g->nmembers;
274     return g;
275 }
276 
277 
278 Object
_dxf_GetEnumeratedMember(Group g,int n,float * position,char ** name)279 _dxf_GetEnumeratedMember(Group g, int n, float *position, char **name)
280 {
281     CHECK(g, CLASS_GROUP);
282 
283     /* is member there? */
284     if (n < 0 || n >= g->nmembers)
285 	return NULL;
286 
287     /* yes */
288     if (position)
289 	*position = g->members[n].position;
290     if (name)
291 	*name = g->members[n].name;
292     return g->members[n].value;
293 }
294 
295 
296 Object
DXGetEnumeratedMember(Group g,int n,char ** name)297 DXGetEnumeratedMember(Group g, int n, char **name)
298 {
299     return _dxf_GetEnumeratedMember(g, n, NULL, name);
300 }
301 
302 
303 Group
_dxf_SetEnumeratedMember(Group g,int i,double position,Object value)304 _dxf_SetEnumeratedMember(Group g, int i, double position, Object value)
305 {
306     int nmembers;
307 
308     CHECK(g, CLASS_GROUP);
309 
310     /* get the lock */
311     DXlock(&g->lock, 0);
312 
313     /* type check if appropriate */
314     if (g->typed && value && !type_check(g, value))
315 	goto error;
316 
317     /* is member there? */
318     nmembers = g->nmembers;
319     if (i > nmembers)
320 	DXErrorGoto(ERROR_BAD_PARAMETER, "Non-contiguous enumerated member");
321 
322     /* if one past last member, add it */
323     if (i == nmembers) {
324 	if (nmembers >= g->alloc) {
325 	    struct member *m = (struct member *)DXReAllocate((Pointer)g->members,
326 		(g->alloc=g->alloc*2+1) * sizeof(struct member));
327 	    if (!m)
328 		goto error;
329 	    g->members = m;
330 	}
331 	g->nmembers = ++nmembers;
332 	g->members[i].name = NULL;
333 	g->members[i].value = NULL;
334     }
335 
336     /* put value in */
337     DXReference(value);
338     DXDelete(g->members[i].value);
339     g->members[i].value = value;
340     g->members[i].position = position;
341 
342     /* copy other members down if deleting */
343     if (!value) {
344 	for (i=i+1; i<nmembers; i++)
345 	    g->members[i-1] = g->members[i];
346 	g->nmembers = --nmembers;
347     }
348 
349     DXunlock(&g->lock, 0);
350     return g;
351 
352 error:
353     DXunlock(&g->lock, 0);
354     return NULL;
355 }
356 
357 Group
DXSetEnumeratedMember(Group g,int n,Object value)358 DXSetEnumeratedMember(Group g, int n, Object value)
359 {
360     return _dxfSetEnumeratedMember(g, n, value);
361 }
362 
363 Group
_dxfGroup_SetEnumeratedMember(Group g,int n,Object value)364 _dxfGroup_SetEnumeratedMember(Group g, int n, Object value)
365 {
366     return _dxf_SetEnumeratedMember(g, n, n, value);
367 }
368 
369 
370 /*
371  * We lock the group in _SetType because it can be called from the
372  * various DXSetMember/DXSetEnumeratedMember routines, which we wish to
373  * support in parallel.  Note that we check again after locking to see
374  * if somebody else has beat us to setting the type.
375  */
376 
377 Error
_dxf_SetType(Group g,Object o)378 _dxf_SetType(Group g, Object o)
379 {
380     Type type;
381     Category category;
382     int rank, shape[100];
383 
384     if (!DXGetType(o, &type, &category, &rank, shape)) {
385 	DXResetError();
386 	return OK;
387     }
388     RANKTEST(ERROR);
389 
390     DXlock(&g->lock, 0);
391     if (!g->typed)
392 	if (!DXSetGroupTypeV(g, type, category, rank, shape)) {
393 	    DXunlock(&g->lock, 0);
394 	    return ERROR;
395 	}
396     DXunlock(&g->lock, 0);
397     return OK;
398 }
399 
400 
401 /*
402  * SetPartClass() is implemented by calling _SetPartClass(), which is
403  * the same except the part number n is passed by reference.  If
404  * o has that many parts, the part is set and *n is set to -1.
405  * Otherwise, *n is decremented by the number of parts that o has.
406  * _SetPartClass(o,n,part,class) returns o if o is a group, or returns
407  * part if o is a has class class.
408  */
409 
410 static Object
_SetPartClass(Object o,int * n,Object part,Class class)411 _SetPartClass(Object o, int *n, Object part, Class class)
412 {
413     int i;
414     Object new, m;
415 
416     if (DXGetObjectClass(o)==CLASS_GROUP) {
417 
418 	Group g = (Group) o;
419 
420 	for (i=0, new=NULL; *n>=0 && (m=DXGetEnumeratedMember(g, i, NULL)); i++)
421 	    new = _SetPartClass(m, n, part, class);
422 
423 	/*
424 	 * _SetPartClass(m,n,part,class) will have returned part if member m
425 	 * has class class, or m if m is a group, so that the following
426 	 * statement does the right thing
427 	 */
428 	if (*n<0 && new==part)
429 	    DXSetEnumeratedMember(g, i-1, new);
430 
431 	/* sic - this is how we tell if o was a group */
432 	return (Object)g;
433 
434     } else if (DXGetObjectClass(o)==class) {
435 
436 	*n -= 1;
437 	return part;
438 
439     } else
440 	return NULL;
441 }
442 
443 
444 
445 static Object
SetPartClass(Object o,int n,Object part,Class class)446 SetPartClass(Object o, int n, Object part, Class class)
447 {
448     _SetPartClass(o, &n, part, class);
449     if (n<0)
450 	return o;
451     else
452 	DXErrorReturn(ERROR_BAD_PARAMETER, "DXSetPart of non-existent part");
453 }
454 
455 
456 Object
DXSetPart(Object o,int n,Field f)457 DXSetPart(Object o, int n, Field f)
458 {
459     return SetPartClass(o, n, (Object)f, CLASS_FIELD);
460 }
461 
462 
463 /*
464  * DXGetPartClass() is implemented by calling _GetPartClass(), which is
465  * the same except the part number n is passed by reference.  If
466  * o has that many parts, the part is returned and *n is set to -1.
467  * Otherwise, *n is decremented by the number of parts that o has.
468  */
469 
470 static Object
_GetPartClass(Object o,int * n,Class class)471 _GetPartClass(Object o, int *n, Class class)
472 {
473     int i;
474     Object m, part;
475     Class oclass = DXGetObjectClass(o);
476 
477     if (oclass==class) {
478 
479 	if ((*n)-- == 0)
480 	    return o;
481 	else
482 	    return NULL;
483 
484     } else if (oclass==CLASS_GROUP) {
485 
486 	part = NULL;
487 	for (i=0; *n>=0 && (m=DXGetEnumeratedMember((Group)o, i, NULL)); i++)
488 	    part = _GetPartClass(m, n, class);
489 	return part;
490 
491     } else if (oclass==CLASS_XFORM) {
492 
493 	DXGetXformInfo((Xform)o, &o, NULL);
494 	return _GetPartClass(o, n, class);
495 
496     } else if (oclass==CLASS_CLIPPED) {
497 
498 	DXGetClippedInfo((Clipped)o, &o, NULL);
499 	return _GetPartClass(o, n, class);
500 
501     } else if (oclass==CLASS_SCREEN) {
502 
503 	DXGetScreenInfo((Screen)o, &o, NULL, NULL);
504 	return _GetPartClass(o, n, class);
505 
506     } else
507 	return NULL;
508 
509 }
510 
511 
512 Object
DXGetPartClass(Object o,int n,Class class)513 DXGetPartClass(Object o, int n, Class class)
514 {
515     /* sigh - nn required to work around AIX 3.2 cc -O bug */
516     int nn = n;
517     return _GetPartClass(o, &nn, class);
518 }
519 
520 
521 Field
DXGetPart(Object o,int n)522 DXGetPart(Object o, int n)
523 {
524     return (Field) DXGetPartClass(o, n, CLASS_FIELD);
525 }
526 
527 
528 /*
529  * DXDelete group
530  */
531 
532 int
_dxfGroup_Delete(Group g)533 _dxfGroup_Delete(Group g)
534 {
535     int i;
536 
537     /* delete the members */
538     DXdestroy_lock(&g->lock);
539     for (i=0; i<g->nmembers; i++) {
540 	DXFree(g->members[i].name);
541 	DXDelete(g->members[i].value);
542     }
543     DXFree((Pointer)g->members);
544     DXFree((Pointer)g->shape);
545 
546     return OK;
547 }
548 
549 
550 Group
DXSetGroupTypeV(Group g,Type t,Category c,int rank,int * shape)551 DXSetGroupTypeV(Group g, Type t, Category c, int rank, int *shape)
552 {
553     int i;
554 
555     CHECK(g, CLASS_GROUP);
556 
557     /* record type */
558     g->typed = 1;
559     g->type = t;
560     g->category = c;
561     g->rank = rank;
562     DXFree((Pointer)g->shape);
563     g->shape = (int *) DXAllocate(rank*sizeof(*shape));
564     if (!g->shape)
565 	return NULL;
566     for (i=0; i<rank; i++)
567 	g->shape[i] = shape[i];
568 
569     /* check type of existing members */
570     for (i=0; i<g->nmembers; i++)
571 	if (!type_check(g, g->members[i].value))
572 	    return NULL;
573 
574     return g;
575 }
576 
577 
578 Group
DXSetGroupType(Group g,Type t,Category c,int rank,...)579 DXSetGroupType(Group g, Type t, Category c, int rank, ...)
580 {
581     int shape[100];
582     int i;
583     va_list arg;
584 
585     RANKTEST(NULL);
586 
587     va_start(arg,rank);
588     for (i=0; i<rank; i++)
589 	shape[i] = va_arg(arg, int);
590     va_end(arg);
591 
592     return DXSetGroupTypeV(g, t, c, rank, shape);
593 }
594 
595 
596 Group
DXUnsetGroupType(Group g)597 DXUnsetGroupType(Group g)
598 {
599     CHECK(g, CLASS_GROUP);
600 
601     g->typed = 0;
602 
603     DXFree((Pointer)g->shape);
604     g->shape = NULL;
605 
606     return g;
607 }
608 
609 
610 Object
_dxfGroup_GetType(Group g,Type * t,Category * c,int * rank,int * shape)611 _dxfGroup_GetType(Group g, Type *t, Category *c, int *rank, int *shape)
612 {
613     int i;
614 
615     CHECK(g, CLASS_GROUP);
616 
617     if (!g->typed)
618 	return NULL;
619 
620     if (t)
621 	*t = g->type;
622     if (c)
623 	*c = g->category;
624     if (rank)
625 	*rank = g->rank;
626     if (shape)
627 	for (i=0; i<g->rank; i++)
628 	    shape[i] = g->shape[i];
629 
630     return (Object) g;
631 }
632