/***********************************************************************/ /* 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 "objectClass.h" #include "internals.h" /* * Tracing */ static int trace = 1; void _dxfTraceObjects(int d) { trace = d; } #if DEBUGGED static struct table { /* table of New/DXDelete per class */ lock_type lock; /* lock for the table */ struct counts { /* the counts */ struct object_class *class; /* class vector */ int new; /* how many created */ int deleted; /* how many deleted */ } counts[CLASS_MAX]; /* one per class, in global storage */ } *table; #define EVERY 500 /* how often to print out */ #endif #define BITS 24 /* this many bits in tag */ static int tag = 1; /* per-processor */ Error _dxf_initobjects(void) { #if DEBUGGED table = (struct table *) DXAllocateZero(sizeof(struct table)); if (!table) return NULL; DXcreate_lock(&table->lock, "object statistics table"); #endif return OK; } /* * */ #define PERMANENT 999999999 Object _dxf_SetPermanent(Object o) { o->count = PERMANENT; return o; } #if DEBUGGED #define ID DXProcessorId() #else #define ID 0 #endif Object DXReference(Object o) { if (!o) return NULL; if (o->count==PERMANENT) return o; /* lock & increment count */ DXfetch_and_add(&o->count, 1, &o->lock, ID); return o; } Error DXDelete(Object o) { int rc = 0, i, n; Class class; if (!o) return OK; if (o->count==PERMANENT) return OK; /* sanity checks - up thru dx 2.1.1, this was if DEBUGGED only */ if (o->count < 0) DXErrorReturn(ERROR_INVALID_DATA, "Object deleted too often! (or not an object)"); class = DXGetObjectClass(o); if ((int)class<=(int)CLASS_MIN || (int)class>=(int)CLASS_MAX) { DXSetError(ERROR_INVALID_DATA, "Deleting object of unknown class %d! (or not an object)", class); return ERROR; } /* lock & decrement count */ if (DXfetch_and_add(&o->count, -1, &o->lock, ID) > 1) return OK; #if DEBUGGED /* tracing */ if (trace>=2) DXDebug("Q","deleting object class %s at 0x%x", CLASS_NAME(o->class), o); if (trace>=1) { int n = (int) CLASS_CLASS(o->class); DXlock(&table->lock, 0); table->counts[n].deleted += 1; DXunlock(&table->lock, 0); } #endif /* * delete attributes * XXX - this should by in an _DeleteObject to be called by subclass * i.e. _Delete should be handled like New and DXCopy */ for (i=0, n=o->nattributes; icount != PERMANENT) DXDelete(o->attributes[i].value); if (o->attributes!=o->local) DXFree((Pointer)o->attributes); /* user deletion */ rc = _dxfDelete(o); /* in case we mistakenly delete this object again - same as above; * was only if DEBUGGED up through dx 2.1.1 */ o->class_id = CLASS_DELETED; o->count = -1; o->class = NULL; /* finish deleting our stuff */ DXdestroy_lock(&o->lock); DXFree((Pointer)o); return rc; } Error DXUnreference(Object o) { int rc = 0, i, n; Class class; if (!o) return NULL; if (o->count==PERMANENT || o->count==0) return OK; /* sanity checks - same comment as in DXDelete */ if (o->count < 0) DXErrorReturn(ERROR_INVALID_DATA, "Object deleted too often! (or not an object)"); class = DXGetObjectClass(o); if ((int)class<=(int)CLASS_MIN || (int)class>=(int)CLASS_MAX) { DXSetError(ERROR_INVALID_DATA, "Deleting object of unknown class %d! (or not an object)", class); return NULL; } /* lock & decrement count */ DXfetch_and_add(&o->count, -1, &o->lock, ID); return OK; } Object _dxf_NewObject(struct object_class *class) { Object o; o = (Object) DXAllocate(CLASS_SIZE(class)); if (!o) return NULL; #if DEBUGGED /* tracing */ if (trace>=2) DXDebug("Q", "creating object class %s at 0x%x", CLASS_NAME(class), o); if (trace>=1) { int n = (int) CLASS_CLASS(class); table->counts[n].class = class; DXlock(&table->lock, 0); table->counts[n].new += 1; if (table->counts[n].new%EVERY==0) DXDebug("O", "%d %s objects created, %d deleted, net %d", table->counts[n].new, CLASS_NAME(class), table->counts[n].deleted, table->counts[n].new-table->counts[n].deleted); DXunlock(&table->lock, 0); } #endif memset(o, 0, CLASS_SIZE(class)); o->class = class; o->class_id = CLASS_CLASS(class); DXcreate_lock(&o->lock, "object"); o->count = 0; o->tag = (DXProcessorId()<attributes = o->local; o->nattributes = 0; o->attr_alloc = NATTRIBUTES; return o; } /* * Tags */ int DXGetObjectTag(Object o) { if (!o) return 0; return o->tag; } Object DXSetObjectTag(Object o, int tag) { if (tag>=0) { DXSetError(ERROR_INTERNAL, "tag value %d is illegal: must be less than 0", tag); return NULL; } if (!o) return NULL; o->tag = tag; return o; } /* * Attributes */ Object DXSetAttribute(Object o, char *name, Object value) { int i, m, n = o->nattributes; struct attribute *a; if (!o) return NULL; if (!name) DXErrorReturn(ERROR_BAD_PARAMETER, "DXSetAttribute given null name"); /* don't do quick check: assume usually not there */ for (i=0, a=o->attributes; iname && strcmp(a->name, name)==0) break; /* attribute is not there - add it if we are setting a value, * or return ok if requesting to delete it. */ if (i >= n) { if (!value) return o; if (n >= o->attr_alloc) { if (o->attr_alloc==NATTRIBUTES) { m = 2*NATTRIBUTES; a = (struct attribute *) DXAllocate(m*sizeof(struct attribute)); if (a) memcpy(a, o->local, sizeof(o->local)); } else { m = o->attr_alloc*2 + 1; a = (struct attribute *) DXReAllocate((Pointer)o->attributes, m * sizeof(struct attribute)); } if (!a) return NULL; o->attributes = a; o->attr_alloc = m; } a = o->attributes + n; o->nattributes = n+1; a->name = _dxfstring(name, 1); a->value = NULL; } else if (!value) { /* copy remaining attributes down */ DXDelete(a->value); for (i=i+1; iattributes[i-1] = o->attributes[i]; o->nattributes -= 1; return o; } /* put value in */ if (value!=a->value) { /* MP performance */ DXReference(value); /* do first in case value==a->value */ DXDelete(a->value); a->value = value; } return o; } Object DXDeleteAttribute(Object o, char *name) { int i, m, n = o->nattributes; struct attribute *a; if (!o) return NULL; if (!name) DXErrorReturn(ERROR_BAD_PARAMETER, "DXDeleteAttribute given null name"); /* quick check for pointer equality */ for (i=0, a=o->attributes; iname==name) break; /* now check for string equality */ if (i >= n) for (i=0, a=o->attributes; iname && strcmp(a->name, name)==0) break; /* attribute not there, return ok */ if (i >= n) return o; /* copy remaining attributes down */ DXDelete(a->value); for (i=i+1; iattributes[i-1] = o->attributes[i]; o->nattributes -= 1; return o; } Object DXGetAttribute(Object o, char *name) { int i, n; struct attribute *a; if (!o) return NULL; if (!name) DXErrorReturn(ERROR_BAD_PARAMETER, "DXGetAttribute given null name"); /* quick check for pointer equality */ n = o->nattributes; for (i=0, a=o->attributes; iname==name) break; /* now check for string equality */ if (i >= n) for (i=0, a=o->attributes; iname && strcmp(a->name, name)==0) break; /* no */ if (i >= n) return NULL; /* yes */ return a->value; } Object DXGetEnumeratedAttribute(Object o, int n, char **name) { struct attribute *a; if (!o) return NULL; if (n >= o->nattributes) return NULL; a = o->attributes + n; if (name) *name = a->name; return a->value; } Object DXSetFloatAttribute(Object o, char *name, double x) { Array a; float *p; a = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 0); p = (float *)DXGetArrayData(DXAddArrayData(a, 0, 1, NULL)); if (!p) return NULL; *p = x; if (!DXSetAttribute(o, name, (Object)a)) { DXDelete((Object)a); return NULL; } return o; } Object DXSetIntegerAttribute(Object o, char *name, int x) { Array a; int *p; a = DXNewArray(TYPE_INT, CATEGORY_REAL, 0); p = (int *)DXGetArrayData(DXAddArrayData(a, 1, 0, NULL)); if (!p) return NULL; *p = x; if (!DXSetAttribute(o, name, (Object)a)) { DXDelete((Object)a); return NULL; } return o; } Object DXSetStringAttribute(Object o, char *name, char *x) { String s; s = DXNewString(x); if (!s) return NULL; if (!DXSetAttribute(o, name, (Object)s)) { DXDelete((Object)s); return NULL; } return o; } Object DXGetFloatAttribute(Object o, char *name, float *x) { Array a; float *p; if (!(a = (Array)DXGetAttribute(o, name))) return NULL; if (DXGetObjectClass((Object)a) != CLASS_ARRAY) return NULL; if (!DXTypeCheck(a, TYPE_FLOAT, CATEGORY_REAL, 0)) return NULL; if (!(p = (float *)DXGetArrayData(a))) return NULL; if (x) *x = *p; return o; } Object DXGetIntegerAttribute(Object o, char *name, int *x) { Array a; int *p; if (!(a = (Array)DXGetAttribute(o, name))) return NULL; if (DXGetObjectClass((Object)a) != CLASS_ARRAY) return NULL; if (!DXTypeCheck(a, TYPE_INT, CATEGORY_REAL, 0)) return NULL; if (!(p = (int *)DXGetArrayData(a))) return NULL; if (x) *x = *p; return o; } Object DXGetStringAttribute(Object o, char *name, char **x) { String s; if (!(s = (String)DXGetAttribute(o, name))) return NULL; if (DXGetObjectClass((Object)s) != CLASS_STRING) return NULL; if (x) *x = DXGetString(s); return o; } Object DXCopyAttributes(Object dst, Object src) { struct attribute *a; int i; if (!dst) return NULL; if (!src) return dst; for (i=0, a=src->attributes; inattributes; i++, a++) if (!DXSetAttribute(dst, a->name, a->value)) return NULL; return dst; } /* * Copying * XXX - why is copying attributes done both here and in DXCopyAttributes? */ Object _dxf_CopyObject(Object new, Object old, enum copy copy) { int i, n = old->nattributes; struct attribute *oa, *na; /* * DXCopy the attributes, no matter what the type of copy */ /* allocate attributes */ if (n<=NATTRIBUTES) { na = new->local; new->attr_alloc = NATTRIBUTES; } else { na = (struct attribute *) DXAllocate(n * sizeof(struct attribute)); if (!na) return NULL; new->attr_alloc = n; } new->attributes = na; new->nattributes = n; /* fill in attributes */ for (i=0, oa=old->attributes; iname = oa->name; na->value = DXReference(oa->value); } return new; } Object DXGetType(Object a, Type* b, Category* c, int* d, int* e) { return _dxfGetType((Object)a,b,c,d,e); } Object DXCopy(Object a, enum copy b) { return _dxfCopy((Object)a,b); } Error _dxfObject_Delete(Object o) { return OK; } Object _dxfObject_BoundingBox(Object o, Point *p, Matrix *m, int valid) { return NULL; } Error _dxfObject_Shade(Object o, struct shade *s) { DXSetError(ERROR_BAD_CLASS, "#13880", CLASS_NAME(o->class)); return ERROR; }