/* ----------------------------- MNI Header ----------------------------------- @NAME : get_volume_info @INPUT : infile - input file name @OUTPUT : volume_info - input volume information @RETURNS : Id of icv created @DESCRIPTION: Routine to read volume information for a file. @METHOD : @GLOBALS : @CALLS : @CREATED : August 22, 1993 (Peter Neelin) @MODIFIED : ---------------------------------------------------------------------------- */ static int get_volume_info(char *infile, Volume_Info *volume_info) { int icvid, mincid; /* Create and set up icv for input */ icvid = miicv_create(); setup_input_icv(icvid); /* Open the image file */ mincid = miopen(infile, NC_NOWRITE); /* Attach the icv to the file */ (void) miicv_attach(icvid, mincid, ncvarid(mincid, MIimage)); /* Get dimension information */ get_dimension_info(infile, icvid, volume_info); /* Get the volume min and max */ (void) miicv_inqdbl(icvid, MI_ICV_NORM_MIN, &volume_info->minimum); (void) miicv_inqdbl(icvid, MI_ICV_NORM_MAX, &volume_info->maximum); return icvid; }
/* ----------------------------- MNI Header ----------------------------------- @NAME : get_block_min_and_max @INPUT : reshape_info - information for reshaping volume block_start - start of current block block_count - count for current block minmax_buffer - buffer space for getting min and max values @OUTPUT : minimum - input minimum for block maximum - input maximum for block @RETURNS : (none) @DESCRIPTION: Gets the min and max for the input file for a given output block. @METHOD : @GLOBALS : @CALLS : @CREATED : October 25, 1994 (Peter Neelin) @MODIFIED : ---------------------------------------------------------------------------- */ static void get_block_min_and_max(Reshape_info *reshape_info, long *block_start, long *block_count, double *minmax_buffer, double *minimum, double *maximum) { int iloop; long num_min_values, num_max_values, ivalue; int inmincid, inimgid, varid, icvid; long minmax_start[MAX_VAR_DIMS], minmax_count[MAX_VAR_DIMS]; long input_block_start[MAX_VAR_DIMS], input_block_count[MAX_VAR_DIMS]; double *extreme; long num_values; char *varname; double sign, default_extreme; /* Get input minc id, image id and icv id*/ inmincid = reshape_info->inmincid; inimgid = ncvarid(inmincid, MIimage); icvid = reshape_info->icvid; /* Is the icv doing the normalization? */ if (reshape_info->do_icv_normalization) { (void) miicv_inqdbl(icvid, MI_ICV_NORM_MIN, minimum); (void) miicv_inqdbl(icvid, MI_ICV_NORM_MAX, maximum); return; } /* Translate output block count to input count */ translate_output_to_input(reshape_info, block_start, block_count, input_block_start, input_block_count); truncate_input_vectors(reshape_info, input_block_start, input_block_count); /* Get number of min and max values */ get_num_minmax_values(reshape_info, block_start, block_count, &num_min_values, &num_max_values); /* Loop over image-min and image-max getting block min and max */ for (iloop=0; iloop < 2; iloop++) { /* Get varid and pointer to min or max value */ switch (iloop) { case 0: num_values = num_min_values; varname = MIimagemin; extreme = minimum; sign = -1.0; default_extreme = 0.0; break; case 1: num_values = num_max_values; varname = MIimagemax; extreme = maximum; sign = +1.0; default_extreme = 1.0; break; } /* Get values from file */ if (num_values > 0) { varid = ncvarid(inmincid, varname); (void) mitranslate_coords(inmincid, inimgid, input_block_start, varid, minmax_start); (void) mitranslate_coords(inmincid, inimgid, input_block_count, varid, minmax_count); (void) mivarget(reshape_info->inmincid, varid, minmax_start, minmax_count, NC_DOUBLE, NULL, minmax_buffer); *extreme = minmax_buffer[0]; for (ivalue=1; ivalue < num_values; ivalue++) { if ((minmax_buffer[ivalue] * sign) > (*extreme * sign)) *extreme = minmax_buffer[ivalue]; } } else { *extreme = default_extreme; } if (reshape_info->need_fillvalue && (reshape_info->fillvalue == NOFILL) && (0.0 > (*extreme * sign))) *extreme = 0.0; } }
/* ----------------------------- MNI Header ----------------------------------- @NAME : handle_normalization @INPUT : reshape_info - information for reshaping volume block_start - start of current block block_count - count for current block minmax_buffer - buffer space for getting min and max values @OUTPUT : fillvalue - pixel fill value to use for this block @RETURNS : (none) @DESCRIPTION: Sets up icv for normalization to ensure that block is internally normalized. Output image-max and min are set. The appropriate pixel fill value is calculated for this min and max (applies to the whole block). @METHOD : @GLOBALS : @CALLS : @CREATED : October 25, 1994 (Peter Neelin) @MODIFIED : ---------------------------------------------------------------------------- */ static void handle_normalization(Reshape_info *reshape_info, long *block_start, long *block_count, double *minmax_buffer, double *fillvalue) { int iloop; int inmincid, inimgid, varid, icvid; long minmax_start[MAX_VAR_DIMS]; double minimum, maximum, *extreme, valid_min, valid_max, denom; char *varname; /* Get input minc id, image id and icv id*/ inmincid = reshape_info->inmincid; inimgid = ncvarid(inmincid, MIimage); icvid = reshape_info->icvid; /* Get input min and max for block */ get_block_min_and_max(reshape_info, block_start, block_count, minmax_buffer, &minimum, &maximum); /* Modify the icv if necessary */ if (reshape_info->do_block_normalization) { (void) miicv_detach(icvid); (void) miicv_setdbl(icvid, MI_ICV_IMAGE_MIN, minimum); (void) miicv_setdbl(icvid, MI_ICV_IMAGE_MAX, maximum); (void) miicv_setint(icvid, MI_ICV_USER_NORM, TRUE); (void) miicv_setint(icvid, MI_ICV_DO_NORM, TRUE); (void) miicv_attach(icvid, inmincid, inimgid); } /* Save the image max and min for the block */ for (iloop=0; iloop < 2; iloop++) { /* Get varid and pointer to min or max value */ switch (iloop) { case 0: varname = MIimagemin; extreme = &minimum; break; case 1: varname = MIimagemax; extreme = &maximum; break; } /* Save the value */ ncopts = 0; varid = ncvarid(reshape_info->outmincid, varname); ncopts = NCOPTS_DEFAULT; if (varid != MI_ERROR) { (void) mitranslate_coords(reshape_info->outmincid, reshape_info->outimgid, block_start, varid, minmax_start); (void) mivarput1(reshape_info->outmincid, varid, minmax_start, NC_DOUBLE, NULL, extreme); } } /* Calculate the pixel fill value */ *fillvalue = ((reshape_info->fillvalue == NOFILL) ? 0.0 : reshape_info->fillvalue); if ((reshape_info->output_datatype != NC_FLOAT) && (reshape_info->output_datatype != NC_DOUBLE) && (*fillvalue != FILL)) { (void) miicv_inqdbl(icvid, MI_ICV_VALID_MIN, &valid_min); (void) miicv_inqdbl(icvid, MI_ICV_VALID_MAX, &valid_max); denom = maximum - minimum; if (denom == 0.0) { *fillvalue = valid_min; } else { *fillvalue = (*fillvalue - minimum) * (valid_max - valid_min) / denom + valid_min; } } }
int main(int argc, char **argv) { int icv, cdfid, img, max, min, dimvar; static int dim[MAX_VAR_DIMS]; static struct { long len; char *name;} diminfo[] = { { 7, MIzspace }, { 9, MIyspace }, { 2, MIxspace } }; /* static struct { long len; char *name;} diminfo[]= {3, MIzspace, 4, MIyspace, 5, MIxspace}; */ static int numdims=sizeof(diminfo)/sizeof(diminfo[0]); static long coord[]={0,0,0}; static long count[]={3,4,5}; double dvalue; short int ivalue[]={ 111, 113, 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 311, 313, 315, 317, 319, 321, 323, 325, 327, 329, 331, 333, 335, 337, 339, 341, 343, 345, 347, 349 }; int i, j, k; int cflag = 0; #if MINC2 if (argc == 2 && !strcmp(argv[1], "-2")) { cflag = MI2_CREATE_V2; } #endif /* MINC2 */ icv=miicv_create(); miicv_setint(icv, MI_ICV_XDIM_DIR, MI_ICV_NEGATIVE); miicv_setint(icv, MI_ICV_YDIM_DIR, MI_ICV_NEGATIVE); miicv_setint(icv, MI_ICV_ZDIM_DIR, MI_ICV_NEGATIVE); miicv_setint(icv, MI_ICV_NUM_IMGDIMS, 3); miicv_setint(icv, MI_ICV_DIM_SIZE+0, 5); miicv_setint(icv, MI_ICV_DIM_SIZE+1, 4); miicv_setint(icv, MI_ICV_DIM_SIZE+2, 3); miicv_setint(icv, MI_ICV_DO_DIM_CONV, TRUE); miicv_setint(icv, MI_ICV_KEEP_ASPECT, FALSE); miicv_setint(icv, MI_ICV_DO_NORM, TRUE); cdfid=micreate("test.mnc", NC_CLOBBER | cflag); for (i=0; i<numdims; i++) { dim[i]=ncdimdef(cdfid, diminfo[i].name, diminfo[i].len); dimvar=micreate_std_variable(cdfid, diminfo[i].name, NC_DOUBLE, 0, &dim[i]); miattputdbl(cdfid, dimvar, MIstep, 0.8); miattputdbl(cdfid, dimvar, MIstart, 22.0); } img=micreate_std_variable(cdfid, MIimage, NC_SHORT, numdims, dim); max=micreate_std_variable(cdfid, MIimagemax, NC_DOUBLE, 1, dim); min=micreate_std_variable(cdfid, MIimagemin, NC_DOUBLE, 1, dim); ncendef(cdfid); for (i=0; i<diminfo[0].len; i++) { dvalue = 200; coord[0]=i; ncvarput1(cdfid, max, coord, &dvalue); dvalue = -dvalue; ncvarput1(cdfid, min, coord, &dvalue); } coord[0]=0; miicv_attach(icv, cdfid, img); miicv_inqdbl(icv, MI_ICV_ADIM_START, &dvalue); printf("adim start = %g", dvalue); miicv_inqdbl(icv, MI_ICV_ADIM_STEP, &dvalue); printf(", step = %g\n", dvalue); miicv_inqdbl(icv, MI_ICV_BDIM_START, &dvalue); printf("bdim start = %g", dvalue); miicv_inqdbl(icv, MI_ICV_BDIM_STEP, &dvalue); printf(", step = %g\n", dvalue); miicv_inqdbl(icv, MI_ICV_NORM_MAX, &dvalue); printf("norm : max = %g", dvalue); miicv_inqdbl(icv, MI_ICV_NORM_MIN, &dvalue); printf(", min = %g\n", dvalue); miicv_put(icv, coord, count, ivalue); miicv_get(icv, coord, count, ivalue); for (i=0; i<3; i++) { for (j=0; j<4; j++) { for (k=0; k<5; k++) { printf("%5d",ivalue[i*20+j*5+k]); } printf("\n"); } } miclose(cdfid); miicv_free(icv); return 0; }
/* ----------------------------- MNI Header ----------------------------------- @NAME : get_dimension_info @INPUT : infile - name of input file icvid - id of the image conversion variable @OUTPUT : volume - input volume data @RETURNS : (nothing) @DESCRIPTION: Routine to get dimension information from an input file. @METHOD : @GLOBALS : @CALLS : @CREATED : August 26, 1993 (Peter Neelin) @MODIFIED : ---------------------------------------------------------------------------- */ static void get_dimension_info(char *infile, int icvid, Volume_Info *volume_info) { int mincid, imgid, varid; int idim, ndims; int dim[MAX_VAR_DIMS]; long *dimlength; char *dimname; int offset; int missing_one_dimension; /* Get the minc file id and the image variable id */ (void) miicv_inqint(icvid, MI_ICV_CDFID, &mincid); (void) miicv_inqint(icvid, MI_ICV_VARID, &imgid); if ((mincid == MI_ERROR) || (imgid == MI_ERROR)) { (void) fprintf(stderr, "File %s is not attached to an icv!\n", infile); exit(EXIT_FAILURE); } /* Get the list of dimensions subscripting the image variable */ (void) ncvarinq(mincid, imgid, NULL, NULL, &ndims, dim, NULL); (void) miicv_inqint(icvid, MI_ICV_NUM_DIMS, &ndims); /* Check that we have two or three dimensions */ if ((ndims != NUMBER_OF_DIMENSIONS) && (ndims != NUMBER_OF_DIMENSIONS-1)) { (void) fprintf(stderr, "File %s does not have %d or %d dimensions\n", infile, NUMBER_OF_DIMENSIONS, NUMBER_OF_DIMENSIONS-1); exit(EXIT_FAILURE); } /* Pretend that we have three dimensions */ offset = ndims - NUMBER_OF_DIMENSIONS; missing_one_dimension = (offset < 0); ndims = NUMBER_OF_DIMENSIONS; /* Loop through dimensions, checking them and getting their sizes */ for (idim=0; idim<ndims; idim++) { /* Get pointers to the appropriate dimension size and name */ switch (idim) { case 0: dimlength = &(volume_info->nslices) ; break; case 1: dimlength = &(volume_info->nrows) ; break; case 2: dimlength = &(volume_info->ncolumns) ; break; } dimname = volume_info->dimension_names[idim]; /* Get dimension name and size */ if (missing_one_dimension && (idim==0)) { (void) strcpy(dimname, "unknown"); *dimlength = 1; } else { (void) ncdiminq(mincid, dim[idim+offset], dimname, dimlength); } } /* Get dimension step and start (defaults = 1 and 0). For slices, we read straight from the variable, but for image dimensions, we get the step and start from the icv. If we didn't have MI_ICV_DO_DIM_CONV set to TRUE, then we would have to get the image dimension step and start straight from the variables. */ for (idim=0; idim<ndims; idim++) { volume_info->step[idim] = 1.0; volume_info->start[idim] = 0.0; } ncopts = 0; (void) miicv_inqdbl(icvid, MI_ICV_ADIM_STEP, &volume_info->step[COLUMN]); (void) miicv_inqdbl(icvid, MI_ICV_ADIM_START, &volume_info->start[COLUMN]); (void) miicv_inqdbl(icvid, MI_ICV_BDIM_STEP, &volume_info->step[ROW]); (void) miicv_inqdbl(icvid, MI_ICV_BDIM_START, &volume_info->start[ROW]); if ((varid=ncvarid(mincid, volume_info->dimension_names[SLICE])) != MI_ERROR) { (void) miattget1(mincid, varid, MIstep, NC_DOUBLE, &volume_info->step[SLICE]); (void) miattget1(mincid, varid, MIstart, NC_DOUBLE, &volume_info->start[SLICE]); } ncopts = NC_OPTS_VAL; }
/* ----------------------------- MNI Header ----------------------------------- @NAME : get_dimension_info @INPUT : infile - name of input file icvid - id of the image conversion variable @OUTPUT : volume - input volume data @RETURNS : (nothing) @DESCRIPTION: Routine to get dimension information from an input file. @METHOD : @GLOBALS : @CALLS : @CREATED : August 26, 1993 (Peter Neelin) @MODIFIED : ---------------------------------------------------------------------------- */ void get_dimension_info(char *infile, int icvid, Volume_Info *volume_info) { int mincid, imgid, varid; int idim, ndims; int dim[MAX_VAR_DIMS]; long *dimlength; char *dimname; /* Get the minc file id and the image variable id */ (void) miicv_inqint(icvid, MI_ICV_CDFID, &mincid); (void) miicv_inqint(icvid, MI_ICV_VARID, &imgid); if ((mincid == MI_ERROR) || (imgid == MI_ERROR)) { (void) fprintf(stderr, "File %s is not attached to an icv!\n", infile); exit_xdisp(EXIT_FAILURE); } /* Get the list of dimensions subscripting the image variable */ (void) ncvarinq(mincid, imgid, NULL, NULL, &ndims, dim, NULL); (void) miicv_inqint(icvid, MI_ICV_NUM_DIMS, &ndims); volume_info->number_of_dimensions = ndims; /* Check that there are at least two dimensions */ if (ndims < 2 || ndims > MAX_VAR_DIMS) { (void) fprintf(stderr, "File %s requires at least two and at most %d dimensions\n", infile, MAX_VAR_DIMS); exit_xdisp(EXIT_FAILURE); } /* Initialize step and start to unknown values */ for (idim=0; idim<ndims; idim++){ volume_info->step[idim] = 0; volume_info->start[idim] = 0; } ncopts = 0; /* Loop through dimensions, checking them and getting their sizes */ for (idim=0; idim<ndims; idim++){ /* Get pointers to the appropriate dimension size and name */ dimname = volume_info->dimension_names[idim]; (void)ncdiminq(mincid,dim[idim],dimname,&(volume_info->length[idim])); /* Get step and start directly from the variables */ /* GBP: add direction_cosines and units */ if ((varid = ncvarid(mincid, volume_info->dimension_names[idim])) != MI_ERROR){ (void)miattget1(mincid, varid, MIstep, NC_DOUBLE, &(volume_info->step[idim])); (void)miattget1(mincid, varid, MIstart, NC_DOUBLE, &(volume_info->start[idim])); (void)miattget(mincid, varid, MIdirection_cosines, NC_DOUBLE, 3, &(volume_info->direction_cosines[idim]), NULL); (void)miattgetstr(mincid, varid, MIunits, 20, volume_info->dimension_units[idim]); } } /* get image plane start and step values */ /* A is fastest dimension (screen x) and B is next fastest (screen y) */ (void)miicv_inqdbl(icvid, MI_ICV_ADIM_START, &(volume_info->a_start)); (void)miicv_inqdbl(icvid, MI_ICV_ADIM_STEP, &(volume_info->a_step)); (void)miicv_inqdbl(icvid, MI_ICV_BDIM_START, &(volume_info->b_start)); (void)miicv_inqdbl(icvid, MI_ICV_BDIM_STEP, &(volume_info->b_step)); ncopts = NC_OPTS_VAL; }
void icv_tests(void) { /* Some random ICV tests */ int icv; int stat; int i; double min, max; icv = miicv_create(); if (icv < 0) { FUNC_ERROR("miicv_create"); } for (i = NC_BYTE; i <= NC_DOUBLE; i++) { stat = miicv_setint(icv, MI_ICV_TYPE, i); if (stat < 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_setstr(icv, MI_ICV_SIGN, MI_UNSIGNED); stat = miicv_inqdbl(icv, MI_ICV_VALID_MAX, &max); if (stat < 0) { FUNC_ERROR("miicv_inqdbl"); } stat = miicv_inqdbl(icv, MI_ICV_VALID_MIN, &min); if (stat < 0) { FUNC_ERROR("miicv_inqdbl"); } switch (i) { case NC_BYTE: if (min != 0 || max != UCHAR_MAX) { fprintf(stderr, "Type %d min %g max %g\n", i, min, max); errors++; } break; case NC_SHORT: if (min != 0 || max != USHRT_MAX) { fprintf(stderr, "Type %d min %g max %g\n", i, min, max); errors++; } break; case NC_INT: if (min != 0 || max != UINT_MAX) { fprintf(stderr, "Type %d min %g max %g\n", i, min, max); errors++; } break; case NC_FLOAT: if (min != -FLT_MAX || max != FLT_MAX) { fprintf(stderr, "Type %d min %g max %g, header min %g max %g\n", i, min, max, FLT_MIN, FLT_MAX); errors++; } break; case NC_DOUBLE: if (min != -DBL_MAX || max != DBL_MAX) { fprintf(stderr, "Type %d min %g max %g, header min %g max %g\n", i, min, max, DBL_MIN, DBL_MAX); errors++; } break; } stat = miicv_setstr(icv, MI_ICV_SIGN, MI_SIGNED); if (stat < 0) { FUNC_ERROR("miicv_setstr"); } stat = miicv_inqdbl(icv, MI_ICV_VALID_MAX, &max); if (stat < 0) { FUNC_ERROR("miicv_inqdbl"); } stat = miicv_inqdbl(icv, MI_ICV_VALID_MIN, &min); if (stat < 0) { FUNC_ERROR("miicv_inqdbl"); } switch (i) { case NC_BYTE: if (min != SCHAR_MIN || max != SCHAR_MAX) { fprintf(stderr, "Type %d min %g max %g\n", i, min, max); errors++; } break; case NC_SHORT: if (min != SHRT_MIN || max != SHRT_MAX) { fprintf(stderr, "Type %d min %g max %g\n", i, min, max); errors++; } break; case NC_INT: if (min != INT_MIN || max != INT_MAX) { fprintf(stderr, "Type %d min %g max %g\n", i, min, max); errors++; } break; case NC_FLOAT: if (min != -FLT_MAX || max != FLT_MAX) { fprintf(stderr, "Type %d min %g max %g\n", i, min, max); errors++; } break; case NC_DOUBLE: if (min != -DBL_MAX || max != DBL_MAX) { fprintf(stderr, "Type %d min %g max %g\n", i, min, max); errors++; } break; } } #if 0 /* For some reason we're allowed to set MI_ICV_TYPE to an illegal value. */ stat = miicv_setint(icv, MI_ICV_TYPE, 1000); if (stat < 0) { FUNC_ERROR("miicv_setint"); } #endif stat = miicv_setint(icv, MI_ICV_NUM_IMGDIMS, MI_MAX_IMGDIMS + 1); if (stat >= 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_setint(icv, MI_ICV_NUM_IMGDIMS, MI_MAX_IMGDIMS); if (stat < 0) { FUNC_ERROR("miicv_setint"); } miicv_free(icv); }
int test4(struct testinfo *ip, struct dimdef *dims, int ndims) { /* Get the same variable again, but this time use an ICV to scale it. */ size_t total; long coords[3]; long lengths[3]; double range[2]; void *buf_ptr; float *flt_ptr; int i, j, k; int stat; int icv; double dbl; total = 1; for (i = 0; i < ndims; i++) { total *= dims[i].length; } buf_ptr = malloc(total * sizeof (float)); if (buf_ptr == NULL) { fprintf(stderr, "Oops, malloc failed\n"); return (-1); } coords[TST_X] = 0; coords[TST_Y] = 0; coords[TST_Z] = 0; lengths[TST_X] = dims[TST_X].length; lengths[TST_Y] = dims[TST_Y].length; lengths[TST_Z] = dims[TST_Z].length; icv = miicv_create(); if (icv < 0) { FUNC_ERROR("miicv_create"); } stat = miicv_setint(icv, MI_ICV_TYPE, NC_FLOAT); if (stat < 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_setint(icv, MI_ICV_DO_NORM, 1); if (stat < 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_attach(icv, ip->fd, ip->imgid); if (stat < 0) { FUNC_ERROR("miicv_attach"); } /* This next call _should_ fail, since the ICV has been attached. */ stat = miicv_setint(icv, MI_ICV_DO_NORM, 0); if (stat >= 0) { FUNC_ERROR("miicv_setint"); } stat = miicv_inqdbl(icv, MI_ICV_DO_NORM, &dbl); if (stat < 0) { FUNC_ERROR("miicv_inqdbl"); } if (dbl != 1.0) { fprintf(stderr, "miicv_inqdbl: Bad value returned\n"); errors++; } stat = miicv_get(icv, coords, lengths, buf_ptr); if (stat < 0) { FUNC_ERROR("miicv_get"); } stat = miget_image_range(ip->fd, range); if (stat < 0) { FUNC_ERROR("miget_image_range"); } if (range[0] != -(XSIZE * 100000.0) || range[1] != (XSIZE * 100000.00)) { fprintf(stderr, "miget_image_range: bad result\n"); errors++; } stat = miget_valid_range(ip->fd, ip->imgid, range); if (stat < 0) { FUNC_ERROR("miget_valid_range"); } if (range[0] != -(XSIZE * 10000.0) || range[1] != (XSIZE * 10000.0)) { fprintf(stderr, "miget_valid_range: bad result\n"); errors++; } flt_ptr = (float *) buf_ptr; for (i = 0; i < dims[TST_X].length; i++) { for (j = 0; j < dims[TST_Y].length; j++) { for (k = 0; k < dims[TST_Z].length; k++) { float tmp = (i * 10000) + (j * 100) + k; if (*flt_ptr != (float) tmp * 10.0) { fprintf(stderr, "2. Data error at (%d,%d,%d) %f != %f\n", i,j,k, *flt_ptr, tmp); errors++; } flt_ptr++; } } } stat = miicv_detach(icv); if (stat < 0) { FUNC_ERROR("miicv_detach"); } /* Try it again, to make certain we fail gracefully. */ stat = miicv_detach(icv); if (stat < 0) { FUNC_ERROR("miicv_detach"); } /* Try to detach a completely random number. */ stat = miicv_detach(rand()); if (stat >= 0) { FUNC_ERROR("miicv_detach"); } stat = miicv_free(icv); if (stat < 0) { FUNC_ERROR("miicv_free"); } free(buf_ptr); return (0); }