int m_Normals (Object *in, Object *out) { char *method; out[0] = NULL; if (in[0] == NULL) { DXSetError(ERROR_BAD_PARAMETER, "#10000", "input"); goto error; } if (in[1]) { if (! DXExtractString(in[1], &method)) { DXSetError(ERROR_BAD_PARAMETER, "#10200", "method"); goto error; } } else method = "positions"; out[0] = _dxfNormals(in[0], method); if (out[0] == NULL || DXGetError() != ERROR_NONE) goto error; return OK; error: DXDelete(out[0]); return ERROR; }
static Error ExRunOnWorker (EXROJob job, int n) { DXResetError (); (* job->func) (job->arg); job->code = DXGetError (); job->emsg = _dxf_ExCopyString (DXGetErrorMessage ()); DXunlock(&job->done, exJID); return (OK); }
/* 0 = input * 1 = string flags: "structure", "details", "render", "all" * (default "all") * * which mean: tell me about the input structure * tell me about the geometry (positions, connections, bbox) * tell me about the renderability */ int m_Describe(Object *in, Object *out) { char *opt = "all"; if (!in[0]) { DescribeMsg("Object Description:"); DescribeMsg("No input object was specified, or the input object is NULL."); return OK; } if (in[1] && !DXExtractString(in[1], &opt)) { DXErrorReturn(ERROR_BAD_PARAMETER, "Options string must be one of 'structure', `details', `render', or `all'"); } /* ??? i should lcase opt, but have to make a copy first. */ if (strcmp(opt, "all") && strcmp(opt, "structure") && strcmp(opt, "details") && strcmp(opt, "render")) { DXErrorReturn(ERROR_BAD_PARAMETER, "Options string must be one of 'structure', `details', `render', or `all'"); } DXBeginLongMessage(); if (!strcmp(opt, "all")) DescribeMsg("Object Description:\n"); if (!strcmp(opt, "all") || !strcmp(opt, "structure")) { if (!strcmp(opt, "structure")) DescribeMsg("Object Structure:\n"); if (!saytype(in[0], opt)) goto done; } if (!strcmp(opt, "all") || !strcmp(opt, "details")) { if (!strcmp(opt, "details")) DescribeMsg("Object Details:\n"); if (!saydata(in[0], opt)) goto done; } if (!strcmp(opt, "all") || !strcmp(opt, "render")) { if (!strcmp(opt, "render")) DescribeMsg("Object Renderability:\n"); if (!sayrender(in[0], opt)) goto done; } DescribeMsg("\n"); DXEndLongMessage(); done: return (DXGetError()==ERROR_NONE ? OK : ERROR); }
int m_FaceNormals (Object *in, Object *out) { out[0] = NULL; if (in[0] == NULL) { DXSetError(ERROR_BAD_PARAMETER, "#10000", "input"); goto error; } out[0] = _dxfNormals(in[0], "connections"); if (out[0] == NULL || DXGetError() != ERROR_NONE) goto error; return OK; error: DXDelete(out[0]); return ERROR; }
static int doLeaf(Object *in, Object *out) { int result=0; Field field; Category category; Category lookup_category; int rank, shape[30]; char *cat_comp; char *data_comp; char *lookup_comp; char name_str[256]; char *opstr; int operation; int lookup_knt; int lookup_knt_provided = 0; Array cat_array = NULL; Array data_array = NULL; Array out_array = NULL; Array array = NULL; Array lookup_array = NULL; float *out_data; int data_knt, cat_knt; int out_knt=0; Type cat_type, data_type, lookup_type; float floatmax; ICH invalid; if (DXGetObjectClass(in[0]) == CLASS_FIELD) { field = (Field)in[0]; if (DXEmptyField(field)) return OK; } if (!DXExtractString((Object)in[1], &opstr)) opstr = STR_COUNT; if (!strcmp(opstr, STR_COUNT)) operation = STAT_COUNT; else if (!strcmp(opstr, STR_MEAN)) operation = STAT_MEAN; else if (!strcmp(opstr, STR_SD)) operation = STAT_SD; else if (!strcmp(opstr, STR_VAR)) operation = STAT_VAR; else if (!strcmp(opstr, STR_MIN)) operation = STAT_MIN; else if (!strcmp(opstr, STR_MAX)) operation = STAT_MAX; else if (!strcmp(opstr, STR_ACCUM)) operation = STAT_ACCUM; else operation = STAT_UNDEF; if (operation == STAT_UNDEF) { DXSetError(ERROR_BAD_PARAMETER, "statistics operation must be one of: count, mean, sd, var, min, max"); goto error; } if (!DXExtractString((Object)in[2], &cat_comp)) cat_comp = STR_DATA; if (!DXExtractString((Object)in[3], &data_comp)) data_comp = STR_DATA; if (in[0]) { if (DXGetObjectClass(in[0]) != CLASS_FIELD) { DXSetError(ERROR_BAD_CLASS, "\"input\" should be a field"); goto error; } cat_array = (Array)DXGetComponentValue((Field)in[0], cat_comp); if (! cat_array) { DXSetError(ERROR_MISSING_DATA, "\"input\" has no \"%s\" categorical component", cat_comp); goto error; } if (DXGetObjectClass((Object)cat_array) != CLASS_ARRAY) { DXSetError(ERROR_BAD_CLASS, "categorical component \"%s\" of \"input\" should be an array", cat_comp); goto error; } if (!HasInvalid((Field)in[0], cat_comp, &invalid)) { DXSetError(ERROR_INTERNAL, "Bad invalid component"); goto error; } if (invalid) { DXSetError(ERROR_DATA_INVALID, "categorical component must not contain invalid data"); goto error; } DXGetArrayInfo(cat_array, &cat_knt, &cat_type, &category, &rank, shape); if ( (cat_type != TYPE_BYTE && cat_type != TYPE_UBYTE && cat_type != TYPE_INT && cat_type != TYPE_UINT) || category != CATEGORY_REAL || !((rank == 0) || ((rank == 1)&&(shape[0] == 1)))) { DXSetError(ERROR_DATA_INVALID, "categorical component %s must be scalar non-float", cat_comp); goto error; } if (operation != STAT_COUNT) { data_array = (Array)DXGetComponentValue((Field)in[0], data_comp); if (! data_array) { DXSetError(ERROR_MISSING_DATA, "\"input\" has no \"%s\" data component", data_comp); goto error; } if (DXGetObjectClass((Object)data_array) != CLASS_ARRAY) { DXSetError(ERROR_BAD_CLASS, "data component \"%s\" of \"input\" should be an array", data_comp); goto error; } DXGetArrayInfo(data_array, &data_knt, &data_type, &category, &rank, shape); if ( (data_type != TYPE_BYTE && data_type != TYPE_UBYTE && data_type != TYPE_INT && data_type != TYPE_UINT && data_type != TYPE_FLOAT && data_type != TYPE_DOUBLE) || category != CATEGORY_REAL || !((rank == 0) || ((rank == 1)&&(shape[0] == 1)))) { DXSetError(ERROR_DATA_INVALID, "data component \"%s\" must be scalar", data_comp); goto error; } if (data_knt != cat_knt) { DXSetError(ERROR_DATA_INVALID, "category and data counts must be the same"); goto error; } } } if (in[4]) { if (DXExtractString((Object)in[4], &lookup_comp)) { lookup_array = (Array)DXGetComponentValue((Field)in[0], lookup_comp); if (!lookup_array) { DXSetError(ERROR_MISSING_DATA, "\"input\" has no \"%s\" lookup component", lookup_comp); goto error; } } else if (DXExtractInteger((Object)in[4], &lookup_knt)) { lookup_knt_provided = 1; out_knt = lookup_knt; } else if (DXGetObjectClass((Object)in[4]) == CLASS_ARRAY) { lookup_array = (Array)in[4]; sprintf(name_str, "%s lookup", cat_comp); lookup_comp = name_str; } else { DXSetError(ERROR_DATA_INVALID, "lookup component must be string, integer, or array"); goto error; } } else { sprintf(name_str, "%s lookup", cat_comp); lookup_comp = name_str; lookup_array = (Array)DXGetComponentValue((Field)in[0], lookup_comp); } if (lookup_array) { DXGetArrayInfo(lookup_array, &lookup_knt, &lookup_type, &lookup_category, &rank, shape); out_knt = lookup_knt; } else if (!lookup_knt_provided){ if (!DXStatistics((Object)in[0], cat_comp, NULL, &floatmax, NULL, NULL)) { DXSetError(ERROR_INTERNAL, "Bad statistics on categorical component"); goto error; } out_knt = (int)(floatmax+1.5); } out_array = DXNewArray(TYPE_FLOAT, CATEGORY_REAL, 0); if (! out_array) goto error; if (! DXSetAttribute((Object)out_array, "dep", (Object)DXNewString("positions"))) goto error; if (! DXAddArrayData(out_array, 0, out_knt, NULL)) goto error; if (out[0]) { if (DXGetObjectClass(out[0]) != CLASS_FIELD) { DXSetError(ERROR_INTERNAL, "non-field object found in output"); goto error; } if (DXGetComponentValue((Field)out[0], "data")) DXDeleteComponent((Field)out[0], "data"); if (! DXSetComponentValue((Field)out[0], "data", (Object)out_array)) goto error; if (lookup_array) { if (! DXSetComponentValue((Field)out[0], lookup_comp, (Object)lookup_array)) goto error; } } else { out[0] = (Object)DXNewField(); array = DXMakeGridPositions(1, out_knt, 0.0, 1.0); if (!array) goto error; DXSetComponentValue((Field)out[0], "positions", (Object)array); array = DXMakeGridConnections(1, out_knt); if (!array) goto error; DXSetComponentValue((Field)out[0], "connections", (Object)array); DXSetComponentValue((Field)out[0], "data", (Object)out_array); if (lookup_array) { if (! DXSetComponentValue((Field)out[0], lookup_comp, (Object)lookup_array)) goto error; } } out_data = DXGetArrayData(out_array); if (! out_data) goto error; result = CategoryStatistics_worker( out_data, cat_knt, out_knt, cat_array, data_array, cat_type, data_type, operation); if (! result) { if (DXGetError()==ERROR_NONE) DXSetError(ERROR_INTERNAL, "error return from user routine"); goto error; } result = (DXEndField((Field)out[0]) != NULL); error: return result; }
Error m_SXRegrid( Object *in, Object *out ){ /* *+ * Name: * SXRegrid * Purpose: * samples a field at positions defined by a another field * Language: * ANSI C * Syntax: * output = SXRegrid( input, grid, nearest, radius, scale, exponent, * coexp, type ); * Classification: * Realisation * Description: * The SXRegrid module samples the "data" component of the "input" * field at the positions held in the "positions" component of the * "grid" field. It is similar to the standard "Regrid" module, but * provides more versatility in assigning weights to each input position, * the option of returning the sums of the weights or the weighted sum * instead of the weighted mean, and seems to be much faster. Both * supplied fields can hold scattered or regularly gridded points, and * need not contain "connections" components. The "data" component in the * "input" field must depend on "positions". * * For each grid position, a set of near-by positions in the input * field are found (using "nearest" and "radius"). Each of these input * positions is given a weight dependant on its distance from the current * grid position. The output data value (defined at the grid position) can * be the weighted mean or weighted sum of these input data values, or * the sum of the weights (selected by "type"). * * The weight for each input position is of the form: * * (d/d0)**exponent * * where "d" is the distance from the current grid position to the * current input position. If a single value is given for "scale" then * that value is used for the d0 constant for all the near-by input * positions. If more than 1 value is given for "scale" then the first * value is used for the closest input position, the second value for the * next closest, etc. The last supplied value is used for any remaining * input positions. A value of zero for "scale" causes the * corresponding input position to be given zero weight. * * If "coexp" is not zero, then the above weights are modified to * become: * * exp( coexp*( (d/d0)**exponent ) ) * * If "nearest" is given an integer value, it specifies N, the maximum * number of near-by input positions to use for each output position. * The N input positions which are closest to the output position are * used. If the string "infinity" is given, then all input positions * closer than the distance given by "radius" are used. Using "radius", * you may specify a maximum radius (from the output position) within * which to find the near-by input positions. If the string "infinity" * is given for "radius" then no limit is placed on the radius. * Parameters: * input = field (Given) * field or group with positions to regrid [none] * grid = field (Given) * grid to use as template [none] * nearest = integer or string (Given) * number of nearest neighbours to use, or "infinity" [1] * radius = scalar or string (Given) * radius from grid point to consider, or "infinity" ["infinity"] * scale = scalar or vector or scalar list (Given) * scale lengths for weights [1.0] * exponent = scalar (Given) * weighting exponent [1.0] * coexp = scalar (Given) * exponential co-efficient for weights [0.0] * type = integer (Given) * type of output values required: 0 - weighted mean, 1 - weighted sum, * 2 - sum of weights [0] * output = field (Returned) * regridded field * Components: * All components except the "data" component are copied from the "grid" * field. The output "data" component added by this module depends on * "positions". An "invalid positions" component is added if any output * data values could not be calculated (e.g. if there are no near-by input * data values to define the weighted mean, or if the weights are too * large to be represented, or if the input grid position was invalid). * Examples: * This example maps the scattered data described in "CO2.general" onto a * regular grid, and displays it. SXRegrid is used to find the data value * at the nearest input position to each grid position. * * input = Import("/usr/lpp/dx/samples/data/CO2.general")$ * frame17 = Select(input,17); * camera = AutoCamera(frame17); * grid = Construct([-100,-170],deltas=[10,10],counts=[19,34]); * regrid = SXRegrid(frame17,grid); * coloured = AutoColor(regrid); * Display(coloured,camera); * * The next example produces a grid containing an estimate of the density * of the scattered points (i.e. the number of points per unit area). The * positions of the original scattered points are shown as dim grey * circles. SXRegrid finds the 5 closest input positions at each grid * position. Zero weight is given to the closest 3 positions. The fourth * position has a weight which is half the density of the points within the * circle passing through the fourth point (i.e. if the fourth point * is at a distance D from the current grid position, there are 3 points * within a circle of radius D, so the density within that circle is * 3/(PI*(D**2)) ). The fifth position has a weight which is half the * density of the points within the circle passing through the fifth * point. The output data value is the sum of the weights (because * "type" is set to 2), which is the mean of the densities within the * circles touching the fourth and fifth points. * * input = Import("/usr/lpp/dx/samples/data/CO2.general")$ * frame17 = Select(input,17); * camera = AutoCamera(frame17); * glyphs=AutoGlyph(frame17,scale=0.1,ratio=1); * glyphs=Color(glyphs,"dim grey"); * grid = Construct([-100,-170],deltas=[10,10],counts=[19,34]); * density=SXRegrid(frame17,grid,nearest=5,scale=[0,0,0,0.691,0.798], * exponent=-2,type=2); * coloured = AutoColor(density); * collected=Collect(coloured,glyphs); * Display(collected,camera); * See Also: * SXBin, ReGrid, Map, Construct * Returned Value: * OK, unless an error occurs in which case ERROR is returned and the * DX error code is set. * Copyright: * Copyright (C) 1995 Central Laboratory of the Research Councils. * All Rights Reserved. * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be * useful,but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David Berry (STARLINK) * {enter_new_authors_here} * History: * 3-OCT-1995 (DSB): * Original version * {enter_further_changes_here} * Bugs: * {note_any_bugs_here} *- */ /* Local Variables: */ Category cat; /* Array category type */ float coexp; /* Exponential co-efficient for weights */ Type dtype; /* Type of current input data array */ float ext; /* Amount by which to extend grid bounds */ int fld; /* Field counter */ Object grid; /* The grid object */ float *gridpos; /* Pointer to grid positions array */ int i; /* Loop count */ void *indata[MAXFLD];/* Pointer to input data array */ float *inpos; /* Pointer to input positions array */ Array inpos_array; /* Input positions array */ Object input; /* A copy of the input object */ int iopt; /* Index of selected option */ int j; /* Loop count */ float lbnd[3]; /* Lower bounds of grid */ char *opt; /* Textual option for a parameter value */ float radius; /* Max. radius for contributing input positions */ char more; /* Are there more input fields to do? */ int nearest; /* Max. no. of input positions which can contribute to an output position */ Fpair *next; /* The next Fpair structure in the linked list */ int ndim; /* No. of dimensions in grid positions array */ int nfld; /* No. of fields sharing current positions array */ int npos; /* No. of input positions */ int npindim; /* No. of dimensions in input positions array */ int nsamp; /* No. of grid positions */ int nscale; /* No. of scale distances supplied */ int outbad[MAXFLD];/* No. of invalid output positions in each field*/ void *outdata[MAXFLD];/* Pointers to output data arrays */ Array outdata_array;/* Output data array */ Object output; /* The output object */ int outtype; /* Type of output values required */ float exponent; /* Power for weights */ int rank; /* Array rank */ float rsc; /* Reciprocal squared scale distance*/ float *rscale; /* Scale distances for weights */ int tag; /* The tag for the current input positions array */ Type type; /* Array numeric type */ float ubnd[3]; /* Upper bounds of grid */ int veclen[MAXFLD];/* Dimensionality of each input data array */ /* Initialise all created objects so that they can safely be deleted if * an error occurs. */ input = NULL; output = NULL; grid = NULL; outdata_array = NULL; /* Check that the "input" object has been supplied. */ if( !in[0] ) { DXSetError( ERROR_BAD_PARAMETER, "missing parameter \"input\"." ); goto error; } /* Remove (cull) all invalid positions and connections from the input. It is * necessary to take a copy of the input first, because the input object * itself cannot be modified. */ input = DXCopy( in[0], COPY_STRUCTURE ); if( !DXCull( input ) ) goto error; /* Check that the "grid" object has been supplied. */ if( !in[1] ) { DXSetError( ERROR_BAD_PARAMETER, "missing parameter \"grid\"." ); goto error; } /* Get a pointer to an array holding the grid positions, and get the * size and shape of the grid. Any invalid positions are flagged with the * value FLT_MAX (defined in float.h). */ gridpos = SXGetGrid( in[1], &nsamp, &ndim, lbnd, ubnd, &grid ); if( !gridpos ) goto error; /* Get the number of input positions allowed to contribute to each * output position. */ if( !in[2] ){ nearest = 1; } else { opt = "infinity"; if( !SXGet0is( "nearest", in[2], INT_MAX, 1, 1, &opt, &nearest, &iopt ) ) goto error; if( iopt == 0 ) nearest = INT_MAX; } /* Get the maximum radius for input positions which contribute to each * output position. */ if( !in[3] ){ radius = FLT_MAX; } else { opt = "infinity"; if( !SXGet0rs( "radius", in[3], FLT_MAX, 0.0, 1, &opt, &radius, &iopt ) ) goto error; if( iopt == 0 ) radius = FLT_MAX; } /* If a maximum radius has been given, extend the bounds by one radius * at each end to catch some extra input positions. Otherwise, extend * the bounds by 10%. */ if( radius < FLT_MAX ){ for( j=0; j<ndim; j++ ){ lbnd[j] -= radius; ubnd[j] += radius; } } else { for( j=0; j<ndim; j++ ){ ext = 0.1*( ubnd[j] - lbnd[j] ); lbnd[j] -= ext; ubnd[j] += ext; } } /* Get the scale distances used to create weights for each input * position. Convert them to squared reciprocal scale distances. If * no value is supplied for the "scale" parameter, use a single scale * length of 1.0 */ if( !in[4] ){ rsc = 1.0; rscale = &rsc; nscale = 1; } else { rscale = SXGet1r( "scale", in[4], &nscale ); if( !rscale ) goto error; for( i=0; i<nscale; i++ ) { rsc = rscale[i]; if( rsc != 0.0 ){ rscale[i] = 1.0/(rsc*rsc); } else { rscale[i] = 0.0; } } } /* Get the exponent used to create weights for each input position. */ if( !in[5] ){ exponent = 1.0; } else { if( !SXGet0rs( "exponent", in[5], FLT_MAX, -FLT_MAX, 0, &opt, &exponent, &iopt ) ) goto error; } /* Get the co-efficient to used in the exponential when creating weights for * each input position. */ if( !in[6] ){ coexp = 0.0; } else { if( !SXGet0rs( "coexp", in[6], FLT_MAX, -FLT_MAX, 0, &opt, &coexp, &iopt ) ) goto error; } /* Get the type of output value required. */ if( !in[7] ){ outtype = 0; } else { if( !SXGet0is( "type", in[7], 2, 0, 0, &opt, &outtype, &iopt ) ) goto error; } /* Produce a copy of the "input" object to use as the output, replacing all * fields within it with the grid field. Also form a linked list of Fpair * structures describing the fields. */ output = SXMakeOut( input, (Field) grid, 1, 1, 3, "positions" ); if( !output ) goto error; /* Abort if no fields were found. */ if( !head ) { DXSetError( ERROR_DATA_INVALID, "no fields found in \"input\"." ); goto error; } /* Go through the list of fields looking for fields which share the same * positions component. */ more = 1; while( more ){ /* Find the first field with a non-zero positions tag. */ next = head; while( next && !next->postag ) next = next->next; /* If no non-zero positions tags were found, we've finished. */ if( !next ){ more = 0; break; } /* Find the input positions array. Get its shape, size and type. Check it is * usable. */ inpos_array = (Array) next->pos; if( !DXGetArrayInfo( inpos_array, &npos, &type, &cat, &rank, &npindim ) ) goto error; if( type != TYPE_FLOAT ){ DXSetError( ERROR_DATA_INVALID, "positions component in \"input\" is not of type FLOAT." ); goto error; } if( cat != CATEGORY_REAL ){ DXSetError( ERROR_DATA_INVALID, "positions component in \"input\" is not of category REAL." ); goto error; } if( rank > 1 ){ DXSetError( ERROR_DATA_INVALID, "rank %d positions component found in \"input\".", rank ); goto error; } if( rank == 0 ){ /* Scalar data is equivalent to 1-d vector data */ rank = 1; npindim = 1; } if( npindim != ndim ){ DXSetError( ERROR_DATA_INVALID, "dimensionality of \"input\" (%d) does not match \"grid\" (%d).", npindim, ndim ); goto error; } /* Get a pointer to the positions values. */ inpos = (float *) DXGetArrayData( inpos_array ); /* Find all fields which have the same positions tag and the same data * type. */ tag = next->postag; dtype = next->datatype; nfld = 0; while( next ){ if( next->postag == tag && next->datatype == dtype ){ /* Increment the number of fields found so far which share this * positions component. */ nfld++; if( nfld > MAXFLD ){ DXSetError( ERROR_MAX, "\"input\" has too many fields.", MAXFLD ); goto error; } /* Store a pointer to the input data array, and its dimensionality. */ indata[nfld-1] = (void *) DXGetArrayData( (Array) next->data ); veclen[nfld-1] = next->datalen; /* Make a new array to hold the output data values. The output data will * have the same dimensionality as the input data unless the required output * data is "sum of weights" (i.e. if parameter "type" is 2), in which case the * output data will be scalar. */ if( outtype == 2 ) veclen[nfld-1] = 1; outdata_array = DXNewArrayV( dtype, CATEGORY_REAL, 1, &veclen[nfld-1] ); if( !outdata_array ) goto error; if( !DXAddArrayData( outdata_array, 0, nsamp, NULL ) ) goto error; /* Get a pointer to the output data array. */ outdata[nfld-1] = (void *) DXGetArrayData( outdata_array ); if( !outdata[nfld-1] ) goto error; /* Place the new data component in the output field, and indicate that * it now does not need to be deleted explicitly in the event of an error. */ if( !DXSetComponentValue( next->outfld, "data", (Object) outdata_array ) ) goto error; outdata_array = NULL; /* Indicate that the data component of the output field has been * changed. */ DXChangedComponentValues( next->outfld, "data" ); /* Indicate that the data values are dependant on positions. */ if( !DXSetComponentAttribute( next->outfld, "data", "dep", (Object) DXNewString("positions")) ) goto error; } next = next->next; } /* Now sample the input data arrays at the output positions, storing the * resulting sample values in the output data arrays. */ if( dtype == TYPE_FLOAT ){ if( ! SXSampleF( nfld, ndim, veclen, npos, inpos, (float **)indata, nsamp, gridpos, (float **) outdata, lbnd, ubnd, nearest, radius, rscale, nscale, exponent, coexp, outtype, outbad ) ) goto error; } else { if( ! SXSampleD( nfld, ndim, veclen, npos, inpos, (double **)indata, nsamp, gridpos, (double **) outdata, lbnd, ubnd, nearest, radius, rscale, nscale, exponent, coexp, outtype, outbad ) ) goto error; } /* Loop round all the fields that have just been created. */ next = head; fld = 0; while( next ){ if( next->postag == tag ){ /* Create invalid positions components in each output field which have any * undefined data values */ if( outbad[fld] ){ if( dtype == TYPE_FLOAT ){ if( !SXSetInvPosF( (Object) next->outfld, nsamp, veclen[fld], (float *) outdata[fld], "positions" ) ) goto error; } else { if( !SXSetInvPosD( (Object) next->outfld, nsamp, veclen[fld], (double *) outdata[fld], "positions" ) ) goto error; } } /* Complete the construction of this output field. */ DXEndField( next->outfld ); /* Increment the field index, and indicate that this input field has * been done. */ fld++; next->postag = 0; } next = next->next; } } error: /* Free the storage used to hold the link list of Fpair structures * describing the fields in the "input" object. */ while( head ){ next = head->next; DXFree( (Pointer) head ); head = next; } /* Delete the copy of the input objects. Return the "output" object with a good status. */ DXDelete( grid ); DXDelete( input ); /* If all is OK, return the "output" object with a good status. */ if( DXGetError() == ERROR_NONE ){ out[0] = output; return( OK ); /* If an error has occurred, ensure temporary objects are deleted and return * with a bad status. */ } else { DXDelete( (Object) outdata_array ); DXDelete( output ); return( ERROR ); } }
static Error ExProcessTaskGroup (int sync) { Error ret = ERROR; EXTaskGroup tg; EXTask task; int i, j; int todo; #if 0 volatile int *count; /* task group counter */ #endif int totalTodo; #define NUM_TASKS_ALLOCED 256 Pointer _args[NUM_TASKS_ALLOCED]; PFI _funcs[NUM_TASKS_ALLOCED]; int _repeats[NUM_TASKS_ALLOCED]; Pointer *args = _args; PFI *funcs = _funcs; int *repeats = _repeats; int status; WorkIndex _ilist[NUM_TASKS_ALLOCED]; WorkIndex *ilist = _ilist; ErrorCode ecode; char *emsg; EXTask myTask = NULL; int myIter = 0; if (EMPTY) return (OK); POP (tg); if (tg->nused == 0) { ExDestroyTaskGroup (tg); return (OK); } DXMarkTime ("start parallel"); /* * Remember whether or not this is a syncronous task group. */ ecode = DXGetError (); emsg = DXGetErrorMessage (); if (ecode != ERROR_NONE || *emsg != '\0') { if (ecode != ERROR_NONE) DXWarning ("#4840"); else DXWarning ("#4850"); tg->error = ecode; tg->emsg = _dxf_ExCopyString (emsg); } tg->sync = sync; todo = tg->nused; status = get_status (); /* * Only bother to sort if the tasks actually have different cost * estimates associated with them. */ if (todo > NUM_TASKS_ALLOCED) { ilist = (WorkIndex *) DXAllocateLocal (todo * sizeof (WorkIndex)); if (ilist == NULL) goto error; } task = tg->tasks; for (i = 0; i < todo; ++i) { ilist[i].task = task + i; ilist[i].work = task[i].work; _dxfCopyContext(&(task[i].taskContext), _dxd_exContext); } if (tg->minwork != tg->maxwork) QUICKSORT (ilist, todo); #ifdef TASK_TIME DXMarkTimeLocal ("finish sort"); #endif /* * Schedule/Execute the tasks appropriately. */ if (todo > NUM_TASKS_ALLOCED) { funcs = (PFI *) DXAllocateLocal (todo * sizeof (PFI )); args = (Pointer *) DXAllocateLocal (todo * sizeof (Pointer)); repeats = (int *) DXAllocateLocal (todo * sizeof (int )); if (funcs == NULL || args == NULL || repeats == NULL) goto error; } /* Save a task for the executer to execute */ i = 0; if (sync) { myTask = ilist[i].task; myIter = ilist[i].task->repeat - 1; ilist[i].task->repeat--; if (ilist[i].task->repeat == 0) { i = 1; } } totalTodo = 1; for (j = 0; i < todo; j++, i++) { funcs[j] = ExProcessTask; args[j] = (Pointer) ilist[i].task; totalTodo += (repeats[j] = ilist[i].task->repeat); } tg->ntodo = totalTodo; if (ilist[0].task->repeat == 0) { --todo; } #ifdef TASK_TIME DXMarkTimeLocal ("queue all tasks"); #endif _dxf_ExRQEnqueueMany (todo, funcs, args, repeats, (long) tg, 0, FALSE); #ifdef TASK_TIME DXMarkTimeLocal ("queued all tasks"); #endif if (funcs != _funcs) DXFree ((Pointer)funcs); if (args != _args) DXFree ((Pointer)args); if (repeats != _repeats) DXFree ((Pointer)repeats); if (ilist != _ilist) DXFree ((Pointer)ilist); if (! sync) { ret = OK; } else { int knt; /* * This processor is now restricted to processing tasks in this * task group. Once it can no longer get a job in this task group * from the run queue then just spin and wait for all of the outstanding * tasks in the group to complete. */ #ifdef TASK_TIME DXMarkTimeLocal ("tasks enqueued"); #endif /* Do the task that I saved above as myTask */ if (myTask != NULL) ExProcessTask (myTask, myIter); #if 0 before the changes made to fix bugs found when debugging SMP linux -- gda count = &tg->ntodo; while (*count > 0) { if (! _dxf_ExRQDequeue ((long) tg)) break; } DXMarkTimeLocal ("waiting"); set_status (PS_JOINWAIT); /* Every 100 times of checking count, try to see if anyone added * on to the queue. */ while (*count > 0) { _dxf_ExRQDequeue ((long)tg); for (i = 0; *count && i < 100; ++i) ; } #else do { DXlock(&tg->lock, 0); knt = tg->ntodo; DXunlock(&tg->lock, 0); _dxf_ExRQDequeue ((long) tg); } while(knt); #endif DXMarkTimeLocal ("joining"); set_status (status); ret = (tg->error == ERROR_NONE) ? OK : ERROR; if (ret != OK) DXSetError (tg->error, tg->emsg? tg->emsg: "#8360"); ExDestroyTaskGroup (tg); } DXMarkTime ("end parallel"); return (ret); error: if (funcs != _funcs) DXFree ((Pointer) funcs); if (args != _args) DXFree ((Pointer) args); if (repeats != _repeats) DXFree ((Pointer) repeats); if (ilist != _ilist) DXFree ((Pointer) ilist); return (ret); }
static Error ExProcessTask (EXTask t, int iteration) { EXTaskGroup tg; Pointer arg; /* task argument pointer */ ErrorCode ecode; /* error code */ #if 0 int ntodo; /* number left in group */ #endif char *emsg; Error returnVal; int status; EXTaskGroup oldTG; Context savedContext; int lastTask; oldTG = runningTG; ecode = ERROR_NONE; emsg = NULL; runningTG = tg = t->tg; arg = (t->nocopy || t->arg) ? t->arg : (Pointer) t->data; DXResetError (); #if 0 savedContext = _dxd_exContext; /* save current context */ _dxd_exContext = t->taskContext; /* move task context to global context */ #endif _dxfCopyContext(&savedContext, _dxd_exContext); _dxfCopyContext(_dxd_exContext, &(t->taskContext)); status = get_status (); set_status (PS_RUN); DXMarkTimeLocal ("start task"); returnVal = (*t->func) (arg, iteration); #if 0 _dxd_exContext = savedContext; /* restore original context */ #endif _dxfCopyContext(_dxd_exContext, &savedContext); DXMarkTimeLocal ("end task"); set_status (status); /* * Check for errors, if we are running without waiting, skip * error checking. If the user didn't DXSetError and he didn't return * ERROR, no error checking. If we have had an error in the past, * don't bother getting the error stuff. */ if (! tg->sync) goto countdown; ecode = DXGetError (); if (ecode == ERROR_NONE && returnVal == OK) goto countdown; if (ecode != ERROR_NONE && returnVal == OK) { returnVal = ERROR; DXWarning ("#4720",t->taskContext.graphId, _dxf_ExGFuncPathToString(_dxd_exCurrentFunc)); } if (ecode == ERROR_NONE && returnVal == ERROR) { ecode = ERROR_INTERNAL; emsg = "#8350"; goto copymessage; } if (tg->error != ERROR_NONE) goto countdown; emsg = DXGetErrorMessage (); #define L_ERROR 2048 copymessage: if (emsg) { char lbuf[L_ERROR]; int len; len = strlen (emsg); len = len >= L_ERROR ? L_ERROR - 1 : len; strncpy (lbuf, emsg, len); lbuf[len] = 0; emsg = _dxf_ExCopyString (lbuf); } countdown: #if 0 before the changes made to fix bugs found when debugging SMP linux -- gda DXlock (&tg->lock, exJID); ntodo = --(tg->ntodo); if (ecode != ERROR_NONE && tg->error == ERROR_NONE) { tg->error = ecode; tg->emsg = emsg; emsg = NULL; } DXunlock (&tg->lock, exJID); DXFree ((Pointer) emsg); /* If this tg was run asyncronously and needs to be destroyed, schedule * the destruction on the creating processor. */ if ((ntodo == 0) && (! tg->sync)) _dxf_ExRQEnqueue (ExDestroyTaskGroup, (Pointer) tg, 1, 0, tg->procId, FALSE); #else /* * Decrement the task group task counter. Was this the last task? */ DXlock (&tg->lock, exJID); tg->ntodo --; lastTask = (tg->ntodo == 0); DXunlock (&tg->lock, exJID); if (tg->sync == 0) { /* * Its an asynchronous task group. * Forget about errors... no-one is waiting for them. */ DXFree ((Pointer) emsg); /* * If this was the last task in the task group then arrange for the * task group to be deleted. */ if (lastTask) _dxf_ExRQEnqueue (ExDestroyTaskGroup, (Pointer)tg, 1, 0, tg->procId, FALSE); } else { /* * A synchronous task group... the creator is waiting for * ntodo to go to zero (and the lock to be available). * If there's an error conditition with the current task and * there wasn't one stashed in the task group, then stash * this one. */ if (ecode != ERROR_NONE && tg->error == ERROR_NONE) { tg->error = ecode; tg->emsg = emsg; emsg = NULL; } } #endif if (t->exdelete) DXFree ((Pointer) t); runningTG = oldTG; return (ecode == ERROR_NONE ? OK : ERROR); }
Error m_SXBin( Object *in, Object *out ){ /* *+ * Name: * SXBin * Purpose: * bins a field into a grid defined by a another field * Language: * ANSI C * Syntax: * output = SXBin( input, grid, type ); * Classification: * Realization * Description: * The SXBin module bins the "data" component of the "input" field into * the bins defined by the "connections" component of the "grid" field. * The input field can hold scattered or regularly gridded points, but * the "data" component must depend on "positions". The "grid" field must * contain "connections" and "positions" components but need not contain * a "data" component. The input"data" component must be either TYPE_FLOAT * or TYPE_DOUBLE. * * The "data" component in the "output" field contains either the mean * or sum of the "input" data values falling within each connection, or * the number of data values falling within each connection, as specified * by "type". * * When binning a regular grid into another regular grid, beware of the * tendancy to produce artificial large scale structure representing the * "beat frequency" of the two grids. * Parameters: * input = field (Given) * field or group with positions to bin [none] * grid = field (Given) * grid to define the bins [none] * type = integer (Given) * type of output values required: 0 - mean, 1 - sum, * 2 - count [0] * output = field (Returned) * bined field * Components: * All components except the "data" component are copied from the "grid" * field. The output "data" component added by this module depends on * "connections". An "invalid connections" component is added if any output * data values could not be calculated (e.g. if the mean is required of an * empty bin). * Examples: * This example bins the scattered data described in "CO2.general" onto a * regular grid, and displays it. SXBin is used to find the mean data * value in each grid connection. * * input = Import("/usr/lpp/dx/samples/data/CO2.general")$ * frame17 = Select(input,17); * camera = AutoCamera(frame17); * grid = Construct([-100,-170],deltas=[10,10],counts=[19,34]); * bin = SXBin(frame17,grid); * coloured = AutoColor(bin); * Display(coloured,camera); * * This example produces a grid containing an estimate of the density of * the scattered points (i.e. the number of points per unit area). The * positions of the original scattered points are shown as dim grey * circles. SXBin finds the number of input positions in each bin, * Measure finds the area of each bin, and Compute divides the counts * by the areas to get the densities: * * input = Import("/usr/lpp/dx/samples/data/CO2.general")$ * frame17 = Select(input,17); * camera = AutoCamera(frame17); * glyphs = AutoGlyph(frame17,scale=0.1,ratio=1); * glyphs = Color(glyphs,"dim grey"); * grid = Construct([-100,-170],deltas=[40,40],counts=[6,10]); * counts = SXBin(frame17,grid,type=2); * areas = Measure(counts,"element"); * density = Compute("$0/$1",counts,areas); * coloured = AutoColor(density); * collected=Collect(coloured,glyphs); * Display(collected,camera); * See Also: * SXRegrid, Map, Construct, Measure * Returned Value: * OK, unless an error occurs in which case ERROR is returned and the * DX error code is set. * Copyright: * Copyright (C) 1995 Central Laboratory of the Research Councils. * All Rights Reserved. * Licence: * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be * useful,but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street,Fifth Floor, Boston, MA * 02110-1301, USA * Authors: * DSB: David Berry (STARLINK) * {enter_new_authors_here} * History: * 9-OCT-1995 (DSB): * Original version * {enter_further_changes_here} * Bugs: * {note_any_bugs_here} *- */ /* Local Variables: */ Array a; /* Array to hold reduced dimension positions */ float *a_ptr; /* Pointer to reduced dimension positions */ Category cat; /* Array category type */ Type dtype; /* Type of current input data array */ int fld; /* Field counter */ Object grid; /* The grid object */ int i; /* Loop count */ void *indata[MAXFLD];/* Pointer to input data array */ float *inpos; /* Pointer to input positions array */ Array inpos_array; /* Input positions array */ Object input; /* A copy of the input object */ Interpolator interp; /* Interpolator for grid */ int j; /* Loop count */ Array map; /* Map from input position to output bin number */ int *map_ptr; /* Pointer to map */ char more; /* Are there more input fields to do? */ Fpair *next; /* The next Fpair structure in the linked list */ int ndim; /* No. of dimensions in grid positions array */ int nfld; /* No. of fields sharing current positions array */ int npos; /* No. of input positions */ int npindim; /* No. of dimensions in input positions array */ int nbin; /* No. of grid positions */ int outbad[MAXFLD];/* No. of invalid output positions in each field*/ void *outdata[MAXFLD];/* Pointers to output data arrays */ Array outdata_array;/* Output data array */ Object output; /* The output object */ int outtype; /* Type of output values required */ float *pa; /* Pointer to next reduced dimension position */ float *pin; /* Pointer to next full dimension position */ int rank; /* Array rank */ int tag; /* The tag for the current input positions array */ Type type; /* Array numeric type */ int veclen[MAXFLD];/* Dimensionality of each input data array */ int *work; /* Pointer to work array */ /* Initialise all created objects so that they can safely be deleted if * an error occurs. */ input = NULL; output = NULL; grid = NULL; outdata_array = NULL; work = NULL; a = NULL; /* Check that the "input" object has been supplied. */ if( !in[0] ) { DXSetError( ERROR_BAD_PARAMETER, "missing parameter \"input\"." ); goto error; } /* Remove (cull) all invalid positions and connections from the input. It is * necessary to take a copy of the input first, because the input object * itself cannot be modified. */ input = DXCopy( in[0], COPY_STRUCTURE ); if( !DXCull( input ) ) goto error; /* Check that the "grid" object has been supplied. */ if( !in[1] ) { DXSetError( ERROR_BAD_PARAMETER, "missing parameter \"grid\"." ); goto error; } /* Create an interpolator which identifies the grid connection containing any * given position. */ interp = SXGetIntp( in[1], &nbin, &ndim, &grid ); if( !interp ) goto error; /* Allocate a work array for use by SXBinD or SXBinF. */ work = (int *) DXAllocate( sizeof( int )*nbin ); if( !work ) goto error; /* Get the type of output value required. */ if( !in[2] ){ outtype = 0; } else { if( !SXGet0is( "type", in[2], 2, 0, 0, NULL, &outtype, NULL ) ) goto error; } /* Produce a copy of the "input" object to use as the output, replacing all * fields within it with the grid field. Also form a linked list of Fpair * structures describing the fields. */ output = SXMakeOut( input, (Field) grid, 1, 1, 3, "positions" ); if( !output ) goto error; /* Abort if no fields were found. */ if( !head ) { DXSetError( ERROR_DATA_INVALID, "no fields found in \"input\"." ); goto error; } /* Go through the list of fields looking for fields which share the same * positions component. */ more = 1; while( more ){ /* Find the first field with a non-zero positions tag. */ next = head; while( next && !next->postag ) next = next->next; /* If no non-zero positions tags were found, we've finished. */ if( !next ){ more = 0; break; } /* Find the input positions array. Get its shape, size and type. Check it is * usable. */ inpos_array = (Array) next->pos; if( !DXGetArrayInfo( inpos_array, &npos, &type, &cat, &rank, &npindim ) ) goto error; if( type != TYPE_FLOAT ){ DXSetError( ERROR_DATA_INVALID, "positions component in \"input\" is not of type FLOAT." ); goto error; } if( cat != CATEGORY_REAL ){ DXSetError( ERROR_DATA_INVALID, "positions component in \"input\" is not of category REAL." ); goto error; } if( rank > 1 ){ DXSetError( ERROR_DATA_INVALID, "rank %d positions component found in \"input\".", rank ); goto error; } if( rank == 0 ){ /* Scalar data is equivalent to 1-d vector data */ rank = 1; npindim = 1; } if( npindim < ndim ){ DXSetError( ERROR_DATA_INVALID, "dimensionality of \"input\" (%d) is less than \"grid\" (%d).", npindim, ndim ); goto error; } /* Get a pointer to the positions values. */ inpos = (float *) DXGetArrayData( inpos_array ); /* If the number of dimensions in the input positions is greater than the * number of dimensions in the grid, remove trailing dimensions from the * input positions so that they match the dimensionality of the grid. */ if( npindim > ndim ){ a = DXNewArrayV( TYPE_FLOAT, CATEGORY_REAL, 1, &ndim ); if( !DXAddArrayData( a, 0, npos, NULL ) ) goto error; a_ptr = (float *) DXGetArrayData( a ); for( i=0; i<npos; i++ ){ pin = inpos + i*npindim; pa = a_ptr + i*ndim; for(j=0;j<ndim;j++) pa[j] = pin[j]; } inpos_array = a; } else { a = NULL; } /* Create an array of the same shape and size as the input positions * array, which holds integer identifiers for the grid connections * containing each input position. These identifiers start at 1 and * go upto nbin. Positions returned holding an identifier of zero do * not fall within the supplied grid. */ map = (Array) DXMap( (Object) inpos_array, (Object) interp, NULL, NULL ); map_ptr = (int *) DXGetArrayData( map ); /* Find all fields which have the same positions tag and the same data * type. */ tag = next->postag; dtype = next->datatype; nfld = 0; while( next ){ if( next->postag == tag && next->datatype == dtype ){ /* Increment the number of fields found so far which share this * positions component. */ nfld++; if( nfld > MAXFLD ){ DXSetError( ERROR_MAX, "\"input\" has too many fields.", MAXFLD ); goto error; } /* Store a pointer to the input data array, and its dimensionality. */ indata[nfld-1] = (void *) DXGetArrayData( (Array) next->data ); veclen[nfld-1] = next->datalen; /* Make a new array to hold the output data values. The output data will * have the same dimensionality as the input data unless the required output * data is "counts (i.e if parameter "type" is 2), in which case the * output data will be scalar. */ if( outtype == 2 ) veclen[nfld-1] = 1; outdata_array = DXNewArrayV( dtype, CATEGORY_REAL, 1, &veclen[nfld-1] ); if( !outdata_array ) goto error; if( !DXAddArrayData( outdata_array, 0, nbin, NULL ) ) goto error; /* Get a pointer to the output data array. */ outdata[nfld-1] = (void *) DXGetArrayData( outdata_array ); if( !outdata[nfld-1] ) goto error; /* Place the new data component in the output field, and indicate that * it now does not need to be deleted explicitly in the event of an error. */ if( !DXSetComponentValue( next->outfld, "data", (Object) outdata_array ) ) goto error; outdata_array = NULL; } next = next->next; } /* Now bin the input data arrays into the output connections, storing the * resulting bin values in the output data arrays. */ if( dtype == TYPE_FLOAT ){ if( ! SXBinF( nfld, veclen, npos, (float **)indata, nbin, (float **) outdata, map_ptr, work, outtype, outbad ) ) goto error; } else { if( ! SXBinD( nfld, veclen, npos, (double **)indata, nbin, (double **) outdata, map_ptr, work, outtype, outbad ) ) goto error; } /* Loop round all the fields that have just been created. */ next = head; fld = 0; while( next ){ if( next->postag == tag ){ /* Create invalid positions components in each output field which have any * undefined data values */ if( outbad[fld] ){ if( dtype == TYPE_FLOAT ){ if( !SXSetInvPosF( (Object) next->outfld, nbin, veclen[fld], (float *) outdata[fld], "connections" ) ) goto error; } else { if( !SXSetInvPosD( (Object) next->outfld, nbin, veclen[fld], (double *) outdata[fld], "connections" ) ) goto error; } } /* Indicate that the data values are dependant on connections. */ if( !DXSetComponentAttribute( next->outfld, "data", "dep", (Object) DXNewString("connections")) ) goto error; /* Indicate that the data component of the output field has been * changed. */ DXChangedComponentValues( next->outfld, "data" ); /* Complete the construction of this output field. */ DXEndField( next->outfld ); /* Increment the field index, and indicate that this input field has * been done. */ fld++; next->postag = 0; } next = next->next; } /* Delete the array used to store the reduced dimensionality input positions * (if used). */ if( a ) { DXDelete( (Object) a ); a = NULL; } } error: /* Free the storage used to hold the link list of Fpair structures * describing the fields in the "input" object. */ while( head ){ next = head->next; DXFree( (Pointer) head ); head = next; } /* Free the work array. */ if( work ) DXFree( (Pointer) work ); /* Delete the copy of the input and grid objects, and the array used to * store the reduced dimensionality input positions (if used). */ DXDelete( grid ); DXDelete( input ); if( a ) DXDelete( (Object) a ); /* If all is OK, return the "output" object with a good status. */ if( DXGetError() == ERROR_NONE ){ out[0] = output; return( OK ); /* If an error has occurred, ensure temporary objects are deleted and return * with a bad status. */ } else { DXDelete( (Object) outdata_array ); DXDelete( output ); return( ERROR ); } }
/* return outputs from module asynchronously */ Error DXSetOutputs(Object *olist, int dxfd) { static int firsttime = 1; Array oarr; Error ret = ERROR; ErrorCode ecode; Group iobj = NULL; Group oobj = NULL; Array code = NULL; String mess = NULL; int i; int count = 0; int one = 1; int zero = 0; if (firsttime && ! callsetup (dxfd)) { host_status = HOST_CLOSED; return ERROR; } ecode = DXGetError(); /* * 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 (DXGetErrorMessage ()); 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 (ecode == ERROR_NONE) { /* 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 < number_of_outputs; 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 < number_of_outputs; i++) { if (olist[i] == NULL) continue; if (! DXSetEnumeratedMember (oobj, count++, olist[i])) goto finish_up; } } /* if the exec isn't already sitting there waiting for results, * alert it that something is going to come back down the pipe, * wait for it to be called and eat the new inputs, and send * the new outputs. */ if (!in_module) { DXInternalReadyToRun(); iobj = (Group) _dxfImportBin_FP (dxfd); if (iobj == NULL) goto finish_up; DXDelete ((Object)iobj); } 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) oobj); in_module = 0; return ret; }
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; }