/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include #include #include #include "groupClass.h" static Group _CopyGroup(Group new, Group old, enum copy copy); #define RANKTEST(rval) \ if (rank>=100) { \ DXSetError(ERROR_INVALID_DATA, "cannot support rank >= 100"); \ return rval; \ } /* * XXX - create and move to util.c */ static char * CopyString(char *s) { if (s) { int n = strlen(s) + 1; char *c = DXAllocate(n); if (c) strcpy(c, s); return c; } else return NULL; } Group _dxf_NewGroup(struct group_class *class) { struct group *g = (Group) _dxf_NewObject((struct object_class *)class); if (!g) return NULL; if (!DXcreate_lock(&g->lock, "group")) return NULL; /* everything else is initialized to 0 */ return g; } Group DXNewGroup() { return _dxf_NewGroup(&_dxdgroup_class); } /* * DXCopy. DXWarning: this code is essentially the same as the * code for Series_Copy, until the loop at the end that does the copy. * If you change anything here, check that code also. */ Object _dxfGroup_Copy(Group old, enum copy copy) { Group new; new = DXNewGroup(); if (!new) return NULL; /* * XXX - copy the class here, so this routine suffices * for all subclasses. Is this really OK? */ new->object.class = old->object.class; new->object.class_id = old->object.class_id; /* XXX - check return code and delete new */ if (! _CopyGroup(new, old, copy)) { DXDelete((Object)new); return NULL; } return (Object)new; } static Group _CopyGroup(Group new, Group old, enum copy copy) { int i; char *name; Object val; /* copy superclass */ if (!_dxf_CopyObject((Object)new, (Object)old, copy)) return NULL; /* done? */ if (copy==COPY_ATTRIBUTES) return new; /* * XXX - should COPY_ATTRIBUTES copy the type also? Since * there is no way to reset it, it is inconvenient if it does so. * It seems unlikely that anyone would want to create an empty * group and copy the type. */ new->typed = old->typed; new->type = old->type; new->category = old->category; new->rank = old->rank; if (old->shape) { new->shape = (int *) DXAllocate(old->rank * sizeof(*(old->shape))); if (! new->shape) return NULL; for (i=0; irank; i++) new->shape[i] = old->shape[i]; } else new->shape = NULL; /* copy the members */ for (i=0; val = DXGetEnumeratedMember(old, i, &name); i++) { if (copy!=COPY_HEADER) { val = DXCopy(val, copy); if (!val) return NULL; } if (! DXSetMember(new, name, val)) return NULL; } return new; } static Error type_check(Group g, Object value) { Type type; Category category; int i, rank, shape[100]; if (!DXGetType(value, &type, &category, &rank, shape)) { if (DXGetError() != ERROR_NONE) return NULL; return OK; } RANKTEST(ERROR); if (type!=g->type || category!=g->category || rank!=g->rank) { DXSetError(ERROR_BAD_PARAMETER, "#11090"); return NULL; } for (i=0; ishape[i]) { DXSetError(ERROR_BAD_PARAMETER, "#11090"); return NULL; } return OK; } Group DXSetMember(Group g, char *name, Object value) { return _dxfSetMember(g, name, value); } Group _dxfGroup_SetMember(Group g, char *name, Object value) { int i, nmembers; struct member *m = NULL; CHECK(g, CLASS_GROUP); /* get the lock */ DXlock(&g->lock, 0); /* type check if appropriate */ if (g->typed && value && !type_check(g, value)) goto error; /* is member there? */ nmembers = g->nmembers; if (name) { for (i=0, m=g->members; iname && strcmp(m->name, name)==0) break; } else { /* null name => new member */ i = nmembers; } /* member is not there - add it */ if (i >= nmembers) { /* re-alloc if necessary */ if (nmembers >= g->alloc) { m = (struct member *) DXReAllocate((Pointer)g->members, (g->alloc=g->alloc*2+1) * sizeof(struct member)); if (!m) goto error; g->members = m; } m = g->members + nmembers; g->nmembers = ++nmembers; m->name = CopyString(name); m->value = NULL; } /* put value in */ DXReference(value); /* do first in case value==c->comp_value */ DXDelete(m->value); m->value = value; m->position = i; /* copy other members down if deleting */ if (!value) { for (i=i+1; imembers[i-1] = g->members[i]; g->nmembers = --nmembers; } DXunlock(&g->lock, 0); return g; error: DXunlock(&g->lock, 0); return NULL; } Object DXGetMember(Group g, char *name) { int i; struct member *m; CHECK(g, CLASS_GROUP); if (!name) DXErrorReturn(ERROR_BAD_PARAMETER, "DXGetMember given null name"); /* is member there? */ for (i=0, m=g->members; inmembers; i++, m++) if (m->name && strcmp(m->name, name)==0) break; /* no */ if (i >= g->nmembers) return NULL; /* yes */ return m->value; } Group DXGetMemberCount(Group g, int *n) { CHECK(g, CLASS_GROUP); if (n) *n = g->nmembers; return g; } Object _dxf_GetEnumeratedMember(Group g, int n, float *position, char **name) { CHECK(g, CLASS_GROUP); /* is member there? */ if (n < 0 || n >= g->nmembers) return NULL; /* yes */ if (position) *position = g->members[n].position; if (name) *name = g->members[n].name; return g->members[n].value; } Object DXGetEnumeratedMember(Group g, int n, char **name) { return _dxf_GetEnumeratedMember(g, n, NULL, name); } Group _dxf_SetEnumeratedMember(Group g, int i, double position, Object value) { int nmembers; CHECK(g, CLASS_GROUP); /* get the lock */ DXlock(&g->lock, 0); /* type check if appropriate */ if (g->typed && value && !type_check(g, value)) goto error; /* is member there? */ nmembers = g->nmembers; if (i > nmembers) DXErrorGoto(ERROR_BAD_PARAMETER, "Non-contiguous enumerated member"); /* if one past last member, add it */ if (i == nmembers) { if (nmembers >= g->alloc) { struct member *m = (struct member *)DXReAllocate((Pointer)g->members, (g->alloc=g->alloc*2+1) * sizeof(struct member)); if (!m) goto error; g->members = m; } g->nmembers = ++nmembers; g->members[i].name = NULL; g->members[i].value = NULL; } /* put value in */ DXReference(value); DXDelete(g->members[i].value); g->members[i].value = value; g->members[i].position = position; /* copy other members down if deleting */ if (!value) { for (i=i+1; imembers[i-1] = g->members[i]; g->nmembers = --nmembers; } DXunlock(&g->lock, 0); return g; error: DXunlock(&g->lock, 0); return NULL; } Group DXSetEnumeratedMember(Group g, int n, Object value) { return _dxfSetEnumeratedMember(g, n, value); } Group _dxfGroup_SetEnumeratedMember(Group g, int n, Object value) { return _dxf_SetEnumeratedMember(g, n, n, value); } /* * We lock the group in _SetType because it can be called from the * various DXSetMember/DXSetEnumeratedMember routines, which we wish to * support in parallel. Note that we check again after locking to see * if somebody else has beat us to setting the type. */ Error _dxf_SetType(Group g, Object o) { Type type; Category category; int rank, shape[100]; if (!DXGetType(o, &type, &category, &rank, shape)) { DXResetError(); return OK; } RANKTEST(ERROR); DXlock(&g->lock, 0); if (!g->typed) if (!DXSetGroupTypeV(g, type, category, rank, shape)) { DXunlock(&g->lock, 0); return ERROR; } DXunlock(&g->lock, 0); return OK; } /* * SetPartClass() is implemented by calling _SetPartClass(), which is * the same except the part number n is passed by reference. If * o has that many parts, the part is set and *n is set to -1. * Otherwise, *n is decremented by the number of parts that o has. * _SetPartClass(o,n,part,class) returns o if o is a group, or returns * part if o is a has class class. */ static Object _SetPartClass(Object o, int *n, Object part, Class class) { int i; Object new, m; if (DXGetObjectClass(o)==CLASS_GROUP) { Group g = (Group) o; for (i=0, new=NULL; *n>=0 && (m=DXGetEnumeratedMember(g, i, NULL)); i++) new = _SetPartClass(m, n, part, class); /* * _SetPartClass(m,n,part,class) will have returned part if member m * has class class, or m if m is a group, so that the following * statement does the right thing */ if (*n<0 && new==part) DXSetEnumeratedMember(g, i-1, new); /* sic - this is how we tell if o was a group */ return (Object)g; } else if (DXGetObjectClass(o)==class) { *n -= 1; return part; } else return NULL; } static Object SetPartClass(Object o, int n, Object part, Class class) { _SetPartClass(o, &n, part, class); if (n<0) return o; else DXErrorReturn(ERROR_BAD_PARAMETER, "DXSetPart of non-existent part"); } Object DXSetPart(Object o, int n, Field f) { return SetPartClass(o, n, (Object)f, CLASS_FIELD); } /* * DXGetPartClass() is implemented by calling _GetPartClass(), which is * the same except the part number n is passed by reference. If * o has that many parts, the part is returned and *n is set to -1. * Otherwise, *n is decremented by the number of parts that o has. */ static Object _GetPartClass(Object o, int *n, Class class) { int i; Object m, part; Class oclass = DXGetObjectClass(o); if (oclass==class) { if ((*n)-- == 0) return o; else return NULL; } else if (oclass==CLASS_GROUP) { part = NULL; for (i=0; *n>=0 && (m=DXGetEnumeratedMember((Group)o, i, NULL)); i++) part = _GetPartClass(m, n, class); return part; } else if (oclass==CLASS_XFORM) { DXGetXformInfo((Xform)o, &o, NULL); return _GetPartClass(o, n, class); } else if (oclass==CLASS_CLIPPED) { DXGetClippedInfo((Clipped)o, &o, NULL); return _GetPartClass(o, n, class); } else if (oclass==CLASS_SCREEN) { DXGetScreenInfo((Screen)o, &o, NULL, NULL); return _GetPartClass(o, n, class); } else return NULL; } Object DXGetPartClass(Object o, int n, Class class) { /* sigh - nn required to work around AIX 3.2 cc -O bug */ int nn = n; return _GetPartClass(o, &nn, class); } Field DXGetPart(Object o, int n) { return (Field) DXGetPartClass(o, n, CLASS_FIELD); } /* * DXDelete group */ int _dxfGroup_Delete(Group g) { int i; /* delete the members */ DXdestroy_lock(&g->lock); for (i=0; inmembers; i++) { DXFree(g->members[i].name); DXDelete(g->members[i].value); } DXFree((Pointer)g->members); DXFree((Pointer)g->shape); return OK; } Group DXSetGroupTypeV(Group g, Type t, Category c, int rank, int *shape) { int i; CHECK(g, CLASS_GROUP); /* record type */ g->typed = 1; g->type = t; g->category = c; g->rank = rank; DXFree((Pointer)g->shape); g->shape = (int *) DXAllocate(rank*sizeof(*shape)); if (!g->shape) return NULL; for (i=0; ishape[i] = shape[i]; /* check type of existing members */ for (i=0; inmembers; i++) if (!type_check(g, g->members[i].value)) return NULL; return g; } Group DXSetGroupType(Group g, Type t, Category c, int rank, ...) { int shape[100]; int i; va_list arg; RANKTEST(NULL); va_start(arg,rank); for (i=0; ityped = 0; DXFree((Pointer)g->shape); g->shape = NULL; return g; } Object _dxfGroup_GetType(Group g, Type *t, Category *c, int *rank, int *shape) { int i; CHECK(g, CLASS_GROUP); if (!g->typed) return NULL; if (t) *t = g->type; if (c) *c = g->category; if (rank) *rank = g->rank; if (shape) for (i=0; irank; i++) shape[i] = g->shape[i]; return (Object) g; }