static Error atleast1image(Object o) { Object subo, old; int i; switch (DXGetObjectClass(o)) { case CLASS_FIELD: if (qimage(o)) return OK; break; case CLASS_GROUP: /* traverse members */ for (i=0; subo = DXGetEnumeratedMember((Group)o, i, NULL); i++) if (atleast1image(subo)) return OK; break; case CLASS_SCREEN: if (!DXGetScreenInfo((Screen)o, &subo, NULL, NULL)) return ERROR; return atleast1image(subo); case CLASS_XFORM: if (!DXGetXformInfo((Xform)o, &subo, NULL)) return ERROR; return atleast1image(subo); case CLASS_CLIPPED: if (!DXGetClippedInfo((Clipped)o, &subo, NULL)) return ERROR; return atleast1image(subo); default: break; } return ERROR; }
static Error atleast1contype(Object o, int n) { Object subo, old; int i; switch (DXGetObjectClass(o)) { case CLASS_FIELD: if (queryNDconnections((Field)o, n)) return OK; break; case CLASS_GROUP: /* traverse members */ for (i=0; subo = DXGetEnumeratedMember((Group)o, i, NULL); i++) if (atleast1contype(subo, n)) return OK; break; case CLASS_SCREEN: /* these don't act like other objs; don't count them for this */ break; case CLASS_XFORM: if (!DXGetXformInfo((Xform)o, &subo, NULL)) return ERROR; return atleast1contype(subo, n); case CLASS_CLIPPED: if (!DXGetClippedInfo((Clipped)o, &subo, NULL)) return ERROR; return atleast1contype(subo, n); default: break; } return ERROR; }
static int qimage(Object o) { int n; Array a; char *s; /* an image has got to be a field or a composite field */ if (DXGetObjectClass(o) != CLASS_FIELD) { if (DXGetObjectClass(o) != CLASS_GROUP) return 0; if (DXGetGroupClass((Group)o) != CLASS_COMPOSITEFIELD) return 0; o = DXGetEnumeratedMember((Group)o, 0, NULL); } /* check to see if it's the right shape, etc */ /* check positions */ a = (Array) DXGetComponentValue((Field)o, "positions"); if (!a || !DXQueryGridPositions(a, &n, NULL, NULL, NULL) || n!=2) return 0; /* check connections */ a = (Array) DXGetComponentValue((Field)o, "connections"); if (!a || !DXQueryGridConnections(a, &n, NULL) || n!=2) return 0; /* is there a colors component */ a = (Array) DXGetComponentValue((Field)o, "colors"); if (!a) return 0; /* check dep */ s = DXGetString((String)DXGetAttribute((Object)a, "dep")); if (s && strcmp(s, "positions")) return 0; return 1; }
static Error traverse(Object *in, Object *out) { switch(DXGetObjectClass(in[0])) { case CLASS_FIELD: /* case CLASS_ARRAY: */ if (! doLeaf(in, out)) return ERROR; return OK; #if 0 case CLASS_GROUP: { int i, j; int memknt; Class groupClass = DXGetGroupClass((Group)in[0]); DXGetMemberCount((Group)in[0], &memknt); for (i = 0; i < memknt; i++) { Object new_in[4], new_out[1]; if (in[0]) new_in[0] = DXGetEnumeratedMember((Group)in[0], i, NULL); else new_in[0] = NULL; new_in[1] = in[1]; new_in[2] = in[2]; new_in[3] = in[3]; new_out[0] = DXGetEnumeratedMember((Group)out[0], i, NULL); if (! traverse(new_in, new_out)) return ERROR; DXSetEnumeratedMember((Group)out[0], i, new_out[0]); } return OK; } case CLASS_XFORM: { int i, j; Object new_in[4], new_out[1]; if (in[0]) DXGetXformInfo((Xform)in[0], &new_in[0], NULL); else new_in[0] = NULL; new_in[1] = in[1]; new_in[2] = in[2]; new_in[3] = in[3]; DXGetXformInfo((Xform)out[0], &new_out[0], NULL); if (! traverse(new_in, new_out)) return ERROR; DXSetXformObject((Xform)out[0], new_out[0]); return OK; } case CLASS_SCREEN: { int i, j; Object new_in[4], new_out[1]; if (in[0]) DXGetScreenInfo((Screen)in[0], &new_in[0], NULL, NULL); else new_in[0] = NULL; new_in[1] = in[1]; new_in[2] = in[2]; new_in[3] = in[3]; DXGetScreenInfo((Screen)out[0], &new_out[0], NULL, NULL); if (! traverse(new_in, new_out)) return ERROR; DXSetScreenObject((Screen)out[0], new_out[0]); return OK; } case CLASS_CLIPPED: { int i, j; Object new_in[4], new_out[1]; if (in[0]) DXGetClippedInfo((Clipped)in[0], &new_in[0], NULL); else new_in[0] = NULL; new_in[1] = in[1]; new_in[2] = in[2]; new_in[3] = in[3]; DXGetClippedInfo((Clipped)out[0], &new_out[0], NULL); if (! traverse(new_in, new_out)) return ERROR; DXSetClippedObjects((Clipped)out[0], new_out[0], NULL); return OK; } #endif default: { DXSetError(ERROR_BAD_CLASS, "input must be Field"); return ERROR; } } }
static Error DoSXEnum( Object o, char *name, char *dep ){ Array a; int n, i, *to; Object oo; /* If the supplied object is a field... */ switch( DXGetObjectClass( o ) ){ case CLASS_FIELD: /* See how many items there are in the requested component. */ a = (Array) DXGetComponentValue( (Field) o, dep ); if( !a ) { DXSetError( ERROR_DATA_INVALID, "field has no \"%s\" component", dep ); return( ERROR ); } DXGetArrayInfo( a, &n, NULL, NULL, NULL, NULL ); /* Create a new array to hold the enumeration, and get a pointer to it. */ a = (Array) DXNewArray( TYPE_INT, CATEGORY_REAL, 0 ); if( !DXAddArrayData( a, 0, n, NULL ) ) return( ERROR ); to = (int *) DXGetArrayData( a ); /* Add this new array to the field. */ DXSetComponentValue( (Field) o, name, (Object) a ); /* Store a value for the "dep" attribute of the new array. */ DXSetComponentAttribute( (Field) o, name, "dep", (Object) DXNewString( dep ) ); /* Store the enumeration values. */ for( i=0; i<n; i++ ) *(to++) = i; /* Indicate that the component values have changed, and complete the * output field. */ DXChangedComponentValues( (Field) o, name ); if( !DXEndField( (Field) o ) ) return( ERROR ); break; /* If the supplied object is a group, call this function recursively for * each member of the group. */ case CLASS_GROUP: for( i=0; oo=(Object)DXGetEnumeratedMember((Group)o,i,NULL); i++ ){ if( !DoSXEnum( oo, name, dep ) ) return( ERROR ); } break; } return( OK ); }
static void Slide2DEndStroke(void *data, DXMouseEvent *event) { Slide2DData sdata = (Slide2DData)data; int b = WHICH_BUTTON(event); int dx, dy; Object member; char *name; Point corners[8]; int i; if (!sdata) return; sdata = (Slide2DData)data; if (! sdata) return; dx = sdata->buttonPosition[b].x - event->x; dy = -(sdata->buttonPosition[b].y - event->y); sdata->buttonPosition[b].x = event->x; sdata->buttonPosition[b].y = event->y; sdata->strokeStart = 1; /* * End stroke. If its the left button or up'n'downish right button, * we operate on a member of the scene group. If its a left'n'right * middle button, we operate on the camera */ if (b == 0 || ((b == 1) && (abs(dy) > abs(dx)))) { Group og = (Group)sdata->obj, ng; /* * Can't do anything if we don't have a scene object group or an * arg telling us what member to operate on */ if ((sdata->label == NULL && sdata->index == -1) || !sdata->obj) return; /* * Create a new group header. */ ng = (Group)DXCopy(sdata->obj, COPY_ATTRIBUTES); if (! ng) return; /* * Loop through the scene object group. For each member NOT matching * the argument, just copy it into the new group. Otherwise, twiddle * its transform matrix and put it there. */ i = 0; while (NULL != (member = DXGetEnumeratedMember((Group)og, i++, &name))) { if ((sdata->label && !strcmp(name, sdata->label)) || ((i-1) == sdata->index)) { Object attr; /* * This is the one to manipulate. It better be a * 'transformed object' type. */ attr = DXGetAttribute(member, "object type"); if (! attr) continue; if (strcmp(DXGetString((String)attr), "transformed object")) continue; if (b == 0) { Vector x; Xform oldx = (Xform)member; Matrix oldm, newm; Object xchild; /* * Its the left button. Determine the world space * vector corresponding to the screen-space stroke, and * concatenate it onto the matrix already associated with * the object, and create a new DX Transform object with * the old transforms child and the concatenated matrices. */ x.x = -(dx * sdata->gt); x.y = -(dy * sdata->gt); x.z = 0.0; DXGetXformInfo(oldx, &xchild, &oldm); newm = DXTranslate(x); newm = DXConcatenate(oldm, newm); member = (Object)DXNewXform(xchild, newm); DXSetAttribute(member, "object type", attr); } else if (DXBoundingBox(member, corners)) { Angle r; Xform oldx = (Xform)member; Matrix oldm, newm; Object xchild; Vector center; /* * Then its an up'n'down middle button stroke. Create * a matrix that transforms the object back to the origin, * rotates it, and then back to where it was. */ DXGetXformInfo(oldx, &xchild, &oldm); /* * Move the object so its center is at the origin */ center.x = -(corners[0].x + corners[7].x) / 2.0; center.y = -(corners[0].y + corners[7].y) / 2.0; center.z = -(corners[0].z + corners[7].z) / 2.0; newm = DXTranslate(center); oldm = DXConcatenate(oldm, newm); /* * Rotate */ r = dy * sdata->gr * (2*3.14159); newm = DXRotateZ(r); oldm = DXConcatenate(oldm, newm); /* * Move the object back to its original location */ center.x = -center.x; center.y = -center.y; center.z = -center.z; newm = DXTranslate(center); oldm = DXConcatenate(oldm, newm); member = (Object)DXNewXform(xchild, oldm); DXSetAttribute(member, "object type", attr); } } DXSetMember(ng, name, member); } DXDelete(sdata->obj); sdata->obj = DXReference((Object)ng); } else if ((b == 1) && (abs(dx) > abs(dy))) { /* * Its a left'n'right middle button. Alter the camera's width * parameter based on a scaled stroke dx. */ sdata->width += (sdata->width * dx)/sdata->w; } return; }
static Error ConvertFieldObject(Object out, char *strin) { Class cl; int i, rank, shape[30], numitems; Type type; Category category; Array data, new_data; RGBColor *dp_old, *dp_new; Object subo; float red, green, blue, hue, sat, val; if (!(cl = DXGetObjectClass(out))) return ERROR; switch (cl) { case CLASS_GROUP: for (i=0; (subo = DXGetEnumeratedMember((Group)out, i, NULL)); i++) { if (!ConvertFieldObject((Object)subo, strin)) return ERROR; } break; case CLASS_FIELD: if (DXEmptyField((Field)out)) return OK; data = (Array)DXGetComponentValue((Field)out,"data"); if (!data) { DXSetError(ERROR_MISSING_DATA,"#10240", "data"); return ERROR; } DXGetArrayInfo(data,&numitems,&type,&category,&rank,shape); if ((type != TYPE_FLOAT)||(category != CATEGORY_REAL)) { DXSetError(ERROR_DATA_INVALID,"#10331", "data"); return ERROR; } if ((rank != 1)||(shape[0] != 3)) { DXSetError(ERROR_DATA_INVALID,"#10331", "data"); return ERROR; } new_data = DXNewArray(TYPE_FLOAT,CATEGORY_REAL,1,3); new_data = DXAddArrayData(new_data, 0, numitems, NULL); dp_old = (RGBColor *)DXGetArrayData(data); dp_new = (RGBColor *)DXGetArrayData(new_data); if (!strcmp(strin,"hsv")) { for (i=0; i<numitems; i++) { if (!_dxfHSVtoRGB(dp_old[i].r, dp_old[i].g, dp_old[i].b, &red, &green, &blue)) return ERROR; dp_new[i] = DXRGB(red,green,blue); } } else { for (i=0; i<numitems; i++) { if (!_dxfRGBtoHSV(dp_old[i].r, dp_old[i].g, dp_old[i].b, &hue, &sat, &val)) return ERROR; dp_new[i] = DXRGB(hue, sat, val); } } DXSetComponentValue((Field)out, "data", (Object)new_data); DXChangedComponentValues((Field)out,"data"); DXEndField((Field)out); break; default: break; } return OK; }
static Error traverse(Object *in, Object *out) { switch(DXGetObjectClass(in[0])) { case CLASS_FIELD: case CLASS_ARRAY: /* * If we have made it to the leaf level, call the leaf handler. */ if (! doLeaf(in, out)) return ERROR; return OK; case CLASS_GROUP: { int i, j; int memknt; Class groupClass = DXGetGroupClass((Group)in[0]); DXGetMemberCount((Group)in[0], &memknt); /* * Create new in and out lists for each child * of the first input. */ for (i = 0; i < memknt; i++) { Object new_in[2], new_out[1]; /* * For all inputs that are Values, pass them to * child object list. For all that are Field/Group, get * the appropriate decendent and place it into the * child input object list. */ /* input "input" is Field/Group */ if (in[0]) new_in[0] = DXGetEnumeratedMember((Group)in[0], i, NULL); else new_in[0] = NULL; /* input "size" is Value */ new_in[1] = in[1]; /* * For all outputs that are Values, pass them to * child object list. For all that are Field/Group, get * the appropriate decendent and place it into the * child output object list. Note that none should * be NULL (unlike inputs, which can default). */ /* output "output" is Field/Group */ new_out[0] = DXGetEnumeratedMember((Group)out[0], i, NULL); if (! traverse(new_in, new_out)) return ERROR; /* * Now for each output that is not a Value, replace * the updated child into the object in the parent. */ /* output "output" is Field/Group */ DXSetEnumeratedMember((Group)out[0], i, new_out[0]); } return OK; } case CLASS_XFORM: { int i, j; Object new_in[2], new_out[1]; /* * Create new in and out lists for the decendent of the * first input. For inputs and outputs that are Values * copy them into the new in and out lists. Otherwise * get the corresponding decendents. */ /* input "input" is Field/Group */ if (in[0]) DXGetXformInfo((Xform)in[0], &new_in[0], NULL); else new_in[0] = NULL; /* input "size" is Value */ new_in[1] = in[1]; /* * For all outputs that are Values, copy them to * child object list. For all that are Field/Group, get * the appropriate decendent and place it into the * child output object list. Note that none should * be NULL (unlike inputs, which can default). */ /* output "output" is Field/Group */ DXGetXformInfo((Xform)out[0], &new_out[0], NULL); if (! traverse(new_in, new_out)) return ERROR; /* * Now for each output that is not a Value replace * the updated child into the object in the parent. */ /* output "output" is Field/Group */ DXSetXformObject((Xform)out[0], new_out[0]); return OK; } case CLASS_SCREEN: { int i, j; Object new_in[2], new_out[1]; /* * Create new in and out lists for the decendent of the * first input. For inputs and outputs that are Values * copy them into the new in and out lists. Otherwise * get the corresponding decendents. */ /* input "input" is Field/Group */ if (in[0]) DXGetScreenInfo((Screen)in[0], &new_in[0], NULL, NULL); else new_in[0] = NULL; /* input "size" is Value */ new_in[1] = in[1]; /* * For all outputs that are Values, copy them to * child object list. For all that are Field/Group, get * the appropriate decendent and place it into the * child output object list. Note that none should * be NULL (unlike inputs, which can default). */ /* output "output" is Field/Group */ DXGetScreenInfo((Screen)out[0], &new_out[0], NULL, NULL); if (! traverse(new_in, new_out)) return ERROR; /* * Now for each output that is not a Value, replace * the updated child into the object in the parent. */ /* output "output" is Field/Group */ DXSetScreenObject((Screen)out[0], new_out[0]); return OK; } case CLASS_CLIPPED: { int i, j; Object new_in[2], new_out[1]; /* input "input" is Field/Group */ if (in[0]) DXGetClippedInfo((Clipped)in[0], &new_in[0], NULL); else new_in[0] = NULL; /* input "size" is Value */ new_in[1] = in[1]; /* * For all outputs that are Values, copy them to * child object list. For all that are Field/Group, get * the appropriate decendent and place it into the * child output object list. Note that none should * be NULL (unlike inputs, which can default). */ /* output "output" is Field/Group */ DXGetClippedInfo((Clipped)out[0], &new_out[0], NULL); if (! traverse(new_in, new_out)) return ERROR; /* * Now for each output that is not a Value, replace * the updated child into the object in the parent. */ /* output "output" is Field/Group */ DXSetClippedObjects((Clipped)out[0], new_out[0], NULL); return OK; } default: { DXSetError(ERROR_BAD_CLASS, "encountered in object traversal"); return ERROR; } } }
/* print something about each member, up to MEMBERCOUNT items */ static Error saymembers(Group g) { int i, count; char *name; Object subo, firstsubo; int same; Class grouptype; float position; if (!DXGetMemberCount(g, &count)) return ERROR; /* no members, nothing to do here */ if (count <= 0) return OK; /* save group type; we'll use it later on */ grouptype = DXGetGroupClass(g); switch (grouptype) { case CLASS_GROUP: if (count <= MEMBERCOUNT) { for (i=0; i<count; i++) { if (!(subo = DXGetEnumeratedMember(g, i, &name))) return ERROR; if (name) DescribeMsg(" member %d is named %s\n", i, name); } } else { for (i=0; i<MEMBERCOUNT/2; i++) { if (!(subo = DXGetEnumeratedMember(g, i, &name))) return ERROR; if (name) DescribeMsg(" member %d is named %s\n", i, name); } DescribeMsg(" ...\n"); for (i=count-MEMBERCOUNT/2; i<count; i++) { if (!(subo = DXGetEnumeratedMember(g, i, &name))) return ERROR; if (name) DescribeMsg(" member %d is named %s\n", i, name); } } break; case CLASS_COMPOSITEFIELD: break; case CLASS_MULTIGRID: /* bbox? */ break; case CLASS_SERIES: if (count <= MEMBERCOUNT) { for (i=0; i<count; i++) { if (!(subo = DXGetSeriesMember((Series)g, i, &position))) return ERROR; DescribeMsg(" member %d is at position %g\n", i, position); } } else { for (i=0; i<MEMBERCOUNT/2; i++) { if (!(subo = DXGetSeriesMember((Series)g, i, &position))) return ERROR; DescribeMsg(" member %d is at position %g\n", i, position); } DescribeMsg(" ...\n"); for (i=count-MEMBERCOUNT/2; i<count; i++) { if (!(subo = DXGetSeriesMember((Series)g, i, &position))) return ERROR; DescribeMsg(" member %d is at position %g\n", i, position); } } break; default: break; } /* if only one member, say what it is and return */ if (count <= 1) { subo = DXGetEnumeratedMember(g, 0, NULL); return sayclass(subo, "The member", 0); } /* if there is more than one member of this group, check out * whether the group members are all the same type of object. * this has to be true for a composite field and should be true * for a multigrid, and usually for a series. */ same = 1; firstsubo = DXGetEnumeratedMember(g, 0, NULL); for (i=1; i<count; i++) { if (!(subo = DXGetEnumeratedMember(g, i, NULL))) return ERROR; if (DXGetObjectClass(firstsubo) != DXGetObjectClass(subo)) { same = 0; break; } } switch (grouptype) { case CLASS_GROUP: if (same) sayclass(firstsubo, "Each group member", 0); else DescribeMsg("The group contains members of different object types\n"); break; case CLASS_COMPOSITEFIELD: if (!same || (DXGetObjectClass(firstsubo) != CLASS_FIELD)) { DescribeMsg("This is not a well-formed Partitioned Field.\n"); DescribeMsg("Members should all be Field objects and they are not.\n"); if (!same) DescribeMsg("It contains members of more than one object type.\n"); if ((DXGetObjectClass(firstsubo) != CLASS_FIELD)) DescribeMsg("It contains members which are not Field objects.\n"); } break; case CLASS_MULTIGRID: /* what about partitioned members? i think they are ok */ break; #if 0 if (!same || (DXGetObjectClass(firstsubo) != CLASS_FIELD)) { DescribeMsg("This is not a well-formed MultiGrid Group.\n"); DescribeMsg("Members should all be Field objects and they are not.\n"); if (!same) DescribeMsg("It contains members of more than one object type.\n"); if ((DXGetObjectClass(firstsubo) != CLASS_FIELD)) DescribeMsg("It contains members which are not Field objects.\n"); } break; #endif case CLASS_SERIES: if (same) sayclass(firstsubo, "Each series member", 0); else DescribeMsg("The series contains members of different object types\n"); break; default: break; } return OK; }
/* accumulate info about what's what */ static Error traverse(Object o, struct info *ip, int nosee) { Object subo; Class curclass; int i; switch (curclass = DXGetObjectClass(o)) { case CLASS_FIELD: return validfield((Field)o, ip, nosee); case CLASS_GROUP: /* traverse members */ for (i=0; (subo = DXGetEnumeratedMember((Group)o, i, NULL)); i++) { if (!traverse(subo, ip, nosee)) return ERROR; } break; case CLASS_SCREEN: if (!DXGetScreenInfo((Screen)o, &subo, NULL, NULL)) return ERROR; return traverse(subo, ip, 1); case CLASS_XFORM: if (!DXGetXformInfo((Xform)o, &subo, NULL)) return ERROR; return traverse(subo, ip, nosee); case CLASS_CLIPPED: if (!DXGetClippedInfo((Clipped)o, &subo, NULL)) return ERROR; return traverse(subo, ip, nosee); /* is this right? */ case CLASS_LIGHT: ip->ri.nlights++; break; case CLASS_INTERPOLATOR: case CLASS_MAX: case CLASS_MIN: case CLASS_PRIVATE: case CLASS_DELETED: case CLASS_STRING: case CLASS_ARRAY: case CLASS_CAMERA: default: for (i=0; i<ip->ri.badobjs; i++) { if (ip->ri.badclass[i] == curclass) return OK; } ip->ri.badobjs++; ip->ri.badclass = (Class *)DXReAllocate((Pointer)ip->ri.badclass, sizeof(Class) * ip->ri.badobjs); ip->ri.badclass[ip->ri.badobjs - 1] = curclass; break; } return OK; }
Error DXGetInputs(Object *in, int dxfd) { static int firsttime = 1; int nin = 0; Group iobj = NULL; int i; int *iptr; int count = 0; if (firsttime && ! callsetup (dxfd)) { host_status = HOST_CLOSED; return ERROR; } /* * Import the remote object, extract the number of inputs and outputs, * and rip them apart appropriately. group members are: * input parm count, * input object list (the pointers values don't mean anything in this * address space; the interesting part is whether they are NULL or not), * the output parm count, * and then each input object which isn't null. */ iobj = (Group) _dxfImportBin_FP(dxfd); if(iobj == NULL) goto error; if (!DXExtractInteger (DXGetEnumeratedMember (iobj, 0, NULL), &nin)) goto error; memset(in, '\0', sizeof(Object)*nin); iptr = (int *)DXGetArrayData((Array)DXGetEnumeratedMember (iobj, 1, NULL)); /* was nout */ if (!DXExtractInteger (DXGetEnumeratedMember (iobj, 2, NULL), &number_of_outputs)) goto error; count = 3; for (i=0; i<nin; i++) { if (iptr[i] == (int)NULL) continue; in[i] = DXGetEnumeratedMember(iobj, count++, NULL); } /* when does iobj get freed? */ /* and how does nout get saved? */ last_inputs = (Object)iobj; in_module++; return OK; error: DXDelete ((Object) iobj); last_inputs = NULL; return ERROR; }
Error DXCallOutboard (PFE m, int dxfd) { static int firsttime = 1; Array oarr; int nin = 0; int nout = 0; Object *ilist = NULL; Object *olist = NULL; Error ret = ERROR; Error modret; ErrorCode ecode; char *emessptr = NULL; Group iobj = NULL; Group oobj = NULL; Array code = NULL; String mess = NULL; int i; int *iptr; int count = 0; int one = 1; int zero = 0; if (firsttime && ! callsetup (dxfd)) { host_status = HOST_CLOSED; return ERROR; } /* * Import the remote object, extract the number of inputs and outputs, * and rip them apart appropriately. group members are: * input parm count, * input object list (the pointers values don't mean anything in this * address space; the interesting part is whether they are NULL or not), * the output parm count, * and then each input object which isn't null. */ iobj = (Group) _dxfImportBin_FP(dxfd); if(iobj == NULL) goto finish_up; if (!DXExtractInteger (DXGetEnumeratedMember (iobj, 0, NULL), &nin)) goto finish_up; ilist = (Object *) DXAllocateZero(sizeof (Object) * nin); if (!ilist) goto finish_up; iptr = (int *)DXGetArrayData((Array)DXGetEnumeratedMember (iobj, 1, NULL)); if (!DXExtractInteger (DXGetEnumeratedMember (iobj, 2, NULL), &nout)) goto finish_up; count = 3; for (i=0; i<nin; i++) { if (iptr[i] == (int)NULL) continue; ilist[i] = DXGetEnumeratedMember(iobj, count++, NULL); } olist = (Object *) DXAllocateZero(sizeof (Object) * nout); if (!olist) goto finish_up; /* * Call the module, and save the error code if set. */ DXResetError(); _dxd_exOutboard = TRUE; modret = m (ilist, olist); _dxd_exOutboard = FALSE; /* * get these now, before we do something else which overwrites them. */ ecode = DXGetError (); emessptr = DXGetErrorMessage(); /* * now BEFORE we do anything which allocates memory or new objects * check the return objects for validity. we saw a case where the * object being returned was deleted, and then the DXNewGroup() * below got the exact same address allocated, so when we put the * group together we put a reference to the parent group into the * same group as a child. bad things followed... * * (the two calls above to geterror & geterrormsg don't allocate anything; * they return a value & ptr to a static respectively) */ for (i = 0; i < nout; i++) { if (olist[i] == NULL) continue; switch (DXGetObjectClass(olist[i])) { case CLASS_DELETED: case CLASS_MIN: case CLASS_MAX: if (ecode == ERROR_NONE) { DXSetError(ERROR_BAD_CLASS, "bad object returned as output %d from outboard module", i); ecode = DXGetError (); emessptr = DXGetErrorMessage(); } else DXAddMessage("bad object returned as output %d from outboard module", i); olist[i] = NULL; default: /* Lots of other classes */ break; } } /* * Set up for return, at least the return code and message. */ oobj = DXNewGroup (); if (oobj == NULL) goto finish_up; if (!(code = DXNewArray (TYPE_INT, CATEGORY_REAL, 0))) goto finish_up; if (! DXAddArrayData (code, 0, 1, (Pointer) &ecode)) goto finish_up; mess = DXNewString (emessptr); if (mess == NULL) goto finish_up; if (! DXSetEnumeratedMember (oobj, 0, (Object) code) || ! DXSetEnumeratedMember (oobj, 1, (Object) mess)) goto finish_up; /* * If everything is OK then go ahead and return any objects too. */ if (modret == OK) { /* send output list so the caller can tell which outputs * were set. only send the non-NULL ones. */ oarr = DXNewArray(TYPE_INT, CATEGORY_REAL, 0); if (!oarr) goto finish_up; for (i = 0; i < nout; i++) { if (! DXAddArrayData(oarr, i, 1, (olist+i) ? (Pointer)&one : (Pointer)&zero)) goto finish_up; } if (! DXSetEnumeratedMember(oobj, 2, (Object)oarr)) goto finish_up; count = 3; for (i = 0; i < nout; i++) { if (olist[i] == NULL) continue; if (! DXSetEnumeratedMember (oobj, count++, olist[i])) goto finish_up; } } if (!_dxfExportBin_FP ((Object)oobj, dxfd)) goto finish_up; /* * if you get to this point, there were no other errors. */ ret = OK; finish_up: /* * get rid of space not needed anymore. this doesn't matter for * one-shots, but for persistent modules we will run out of memory * eventually if these aren't deleted. */ DXDelete ((Object) iobj); DXDelete ((Object) oobj); DXFree ((Pointer) ilist); DXFree ((Pointer) olist); return ret; }