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