#ifdef SCCS
static char sccsid[]="@(#)rf_read_fld.c	8.1.1.1 Stardent 93/05/12";
#endif
/*
			Copyright (c) 1989 by
			Stardent Computer Inc.
			All Rights Reserved
	
	This software comprises unpublished confidential information of
	Stardent Computer Inc. and may not be used, copied or made
	available to anyone, except in accordance with the license
	under which it is furnished.
	
	This file is under sccs control at Stardent in:
	/nfs/caffeine/root/src1/sccs/avs/rflib/s.rf_read_fld.c
*/
#include <limits.h>

#include <string.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#if _CRAY			/* Workaround until UNICOS 6.0 */
#define __TYPES__ 1
#endif
#include <rpc/types.h>
#include <rpc/xdr.h>

#include <avs/avs.h>
#include <avs/field.h>
#include <avs/flow.h>
#include "rf.h"


#include <avs/port.h>

#ifdef USE_FILE_UTILS
#include "avsnames.h"
#include "file_utils.h"
#endif



/* Data sizes */
/* First subscript is 0=Native, 1=XDR. */

static int FieldTypeSizes[2][5] = {
   { sizeof(char), sizeof(int), sizeof(float), sizeof(double), sizeof(short) },
   { 1, 4, 4, 8, 2 }
  };

static int read_stuff ();


/* external variables shared with parser. */

extern FILE *rf_yyin;
extern int rf_yylineno;

/* These are all set by the parser. */

extern struct rf_parse_results rf_global;

/* internal variables */
static int DEBUG = 0;


/* Used for AVSmessage() */
static char file_version[] = "@(#)main.c	5.7 Stellar 90/09/06";

/******************************************************************************/
#define READ_ERROR(string)                                                    \
  {                                                                           \
      AVSmessage(file_version, AVS_Error, AVSmodule, "read_field_compute",    \
		 "Ok", "Error reading field file:\n%s.\n%s %d.", 	      \
		 string, "Error on (or after) line", rf_yylineno);            \
      return(0);                                                              \
  }
	
/******************************************************************************/

/*----------------------------------------------------------------------------
 *
 * static void fix_filename (ref_filename, fld_filename)
 * char **ref_filename;
 * char *fld_filename;
 *
 * Fix up any relative file names found in the description file.
 *
 * Inputs:	*ref_filename	- File name found in the description file.
 *		fld_filename	- Name of description file.
 *
 * Outputs:	*ref_filename	- Modified if not an absolute path.
 *				  (See description, below, for example.)
 *				  Previous content is freed and new
 *				  storage is malloced.
 *
 * Returns:	None.
 *
 * Description:	Here is a sample file (/usr/avs/data/field/hydrogen.fld)
 *		shipped with AVS 3:
 *
 *		
 *		# AVS field file
 *		# this is a header file for a field to be
 *		# used in conjunction with the  build a field module of AVS
 *		#
 *		ndim=3                          # number of dimensions in the field
 *		nspace=3                        # number of physical coordinates
 *		dim1=64                         # dimension of axis 1
 *		dim2=64                         # dimension of axis 2
 *		dim3=64                         # dimension of axis 2
 *		data=byte                       # data type (byte, integer, float, double)
 *		variable 1 file=/usr/avs/data/volume/hydrogen.dat filetype=binary skip=3
 *
 *		The problem is that sites with secure systems (e.g. Cray machines)
 *		are not receptive to creating a /usr/avs directory.  
 *
 *		A solution is to use relative paths in the file.  Note that these are
 *		relative to the position of the .fld file, not the current working
 *		directory.
 *
 *		For example, the last line of the file above would be:
 *
 *              variable 1 file=../volume/hydrogen.dat filetype=binary skip=3
 *
 *		This will work when the avs file structure is installed somewhere
 *		else.  It is also handy when moving groups related files around.
 *
 * Example:	Suppose the root of the AVS file system was /usr/johnl.
 *		The sample field file would be /usr/john/usr/avs/data/field/hydrogen.dat.
 *
 *		Input arguments would be:
 *
 *			ref_filename = ../volume/hydrogen.dat
 *			fld_filename = /usr/john/usr/avs/data/field/hydrogen.dat
 *
 *		If ref_filename is absolute, it is left alone.
 *		Otherwise it is combined with the directory part of fld_filename.
 *		In this case:
 *
 *			ref_filename = /usr/john/usr/avs/data/field/../volume/hydrogen.dat
 *
 *----------------------------------------------------------------------------*/

static void fix_filename (ref_filename, fld_filename)
char **ref_filename;
char *fld_filename;
{

	char s_temp[1024];
	char *p;


#ifdef USE_FILE_UTILS
	/* Do nothing if ref_filename is absolute. */
	if (FILEis_path_absolute(*ref_filename))
		return;

        /* Extract directory part of fld_filename. */
	if ( (p=FILEget_dir_name(fld_filename,0)) == NULL )
		return;

        /* Stick it in front of referenced file name. */
	FILEconcat_dir_and_file(p,*ref_filename,s_temp);
#else
	/* Do nothing if ref_filename is absolute. */

	if (*ref_filename[0] == '/' || *ref_filename[0] == '@') 
		return;

	/* Extract directory part of fld_filename. */
	/* We really should have common utility routines for */
	/* this sort of thing. */

	strcpy (s_temp, fld_filename);
	p = strrchr (s_temp, '/');
	if (p == NULL)
		return;

	/* Stick it in front of referenced file name. */

	p[1] = '\0';
	strcat (s_temp, *ref_filename);
#endif

	free (*ref_filename);
	*ref_filename = strdup(s_temp);
}


/*----------------------------------------------------------------------------
 *
 * int rf_read_field(out_field, fp, status_flag, fld_filename, portable)
 * AVSfield **out_field;
 * FILE *fp;
 * int status_flag;
 * char *fld_filename;
 * int portable;
 *
 * Read a field (.fld) file.
 * This does most of the work of the read field module and is in 
 * subroutine form so it can be used other places.
 *
 * Inputs:	fp		- File pointer to already open field file.
 *		status_flag	- If TRUE, user is given a status display of
 *				  the progress.
 *		fld_filename	- Name of field file.  Note that the caller
 *				  has already opened it but this is useful for
 *				  error messages and relative file paths.
 *		portable	- If TRUE perform conversion from XDR to 
 *				  native format.
 *				  If FALSE, perform conversion only if 
 *				  the data type has an "xdr_" prefix.
 *
 * Outputs:	out_field	- A pointer to an AVS field will be placed in 
 *				  *out_field.
 *
 * Returns:	1 for success.
 *		0 for failure.
 *
 * Errors:	Bad header (first line must begin with "# AVS").
 *		Can't open files refered to by first file.
 *		Read errors (e.g. file shorter than expected).
 *
 *		In all cases AVSmessage is called.
 *
 * Side Effects: If *out_field is not NULL, AVSfield_free will
 *               will be called to get rid of an old field.
 *
 *---------------------------------------------------------------------------*/

int rf_read_field(out_field, fp, status_flag, fld_filename, portable)
  AVSfield **out_field;
  FILE *fp;
  int status_flag;
  char *fld_filename;
  int portable;
{
    AVSfield *field;
    FILE      *df, *pf;
    char      buf[256], label[2048];
    int       i, j, k, tmp_int;
    int       size, full_size, npoints, nread, rect_off, ten_percent;
    float     temp;
    XDR	      xdrs;

    rf_yyin = fp;
    
    /* Free old memory */
    if (*out_field) {
      AVSfield_free(*out_field);
      *out_field = NULL;
    }

    /* Read the key */
    fgets(buf, 256, fp);
    if (memcmp(buf, "# AVS", 5)) {
	/* Bad header */
	AVSmessage(file_version, AVS_Warning, AVSmodule, "read_field_compute",
		   "Ok", "File is not an AVS field file (needs \"# AVS\" in first line)");
	return(0);
    }  /* end if */
    
    /**************************************************/
    /* initialize state 			      */
    /**************************************************/
    rf_global.data_in_file = rf_global.points_in_file = rf_global.template.veclen = 1;
    rf_global.template.uniform = UNIFORM;
    rf_global.template.ndim = rf_global.template.nspace = rf_global.template.type = -1;
    rf_global.flag = rf_global.name_list_count = rf_global.unit_list_count = 0;
    rf_global.portable = FALSE;
    for(i=0; i<MAXVECLEN; i++) {
	rf_global.labels[i] = NULL;
        rf_global.units[i] = NULL;
	rf_global.min_val[i] = rf_global.max_val[i] = -1;
	rf_global.data[i].stride = 1;
	rf_global.data[i].skip = 0;
	rf_global.data[i].type = -1;
	rf_global.data[i].filename = NULL;
    }
    for(i=0; i<MAXDIM; i++) {
	rf_global.min_ext[i] = rf_global.max_ext[i] = -1;
	rf_global.points[i].stride = 1;
	rf_global.points[i].skip = 0;
	rf_global.points[i].type = -1;
	rf_global.points[i].filename = NULL;
    }
    
    /**************************************************/
    /* Parse the header 			      */
    /**************************************************/
    rf_yylineno = 2;
    if (status_flag) 
      AVSmodify_parameter("Read Status", AVS_VALUE, 
			  "Read Status:\nParsing Header\n", NULL, NULL);

    i=rf_yyparse();			/* do that lex/yacc thang! */

    if (i == -2) 
	READ_ERROR(rf_global.error_str);

    if (rf_global.portable)
	portable = TRUE;

    if ((rf_global.template.ndim < 0) || (rf_global.template.veclen < 0) || (rf_global.template.nspace < 0) ||
	(rf_global.template.type < 0) || (rf_global.template.uniform <0))
	READ_ERROR("invalid header specification: not enough information!");

    for(i=0; i<rf_global.template.ndim; i++)
      if (rf_global.dims[i] < 0)
	READ_ERROR("invalid header specification: not enough information!");
    rf_global.template.flags = rf_global.flag;
    rf_global.template.points = NULL;
    
    /* allocate the field */
    if (!(field  = (AVSfield *) AVSfield_alloc(&rf_global.template, rf_global.dims))) 
      READ_ERROR("couldn't allocate field");

    if (rf_global.flag & AVS_VALID_LABELS) {		/* set labels */
	label[0] = '\0';
	if (rf_global.name_list_count != field->veclen)
	  READ_ERROR("there are not VECLEN LABELS defined!");
	strcpy(label, rf_global.labels[0]);
	for(i=1; i<field->veclen; i++) {
	    sprintf(label, "%s;%s", label, rf_global.labels[i]);
	    free(rf_global.labels[i]);
	    rf_global.labels[i] = NULL;
        }
	sprintf(label, "%s;", label);
	if (DEBUG) printf("Labels: %s\n", label);
	AVSfield_set_labels(field, label, ";");
    }

    if (rf_global.flag & AVS_VALID_UNITS) {		/* set units */
	label[0] = '\0';
	if (rf_global.unit_list_count != field->veclen)
	  READ_ERROR("there are not VECLEN UNITS defined!");
	strcpy(label, rf_global.units[0]);
	for(i=1; i<field->veclen; i++) {
	    sprintf(label, "%s;%s", label, rf_global.units[i]);
	    free(rf_global.units[i]);
	    rf_global.units[i] = NULL;
	}
	sprintf(label, "%s;", label);
	if (DEBUG) printf("Units: %s\n", label);
	AVSfield_set_units(field, label, ";");
    }

    if (rf_global.flag & AVS_VALID_EXTENT) {		/* set extents */
	for (i=0; i<field->nspace; i++) {
	  if (rf_global.max_ext[i] < rf_global.min_ext[i]) {	/* reverse order, if necessary */
	      temp = rf_global.max_ext[i];
	      rf_global.max_ext[i] = rf_global.min_ext[i];
	      rf_global.min_ext[i] = temp;
	  }
        }
	AVSfield_set_extent(field, rf_global.min_ext, rf_global.max_ext);
    }

    if (rf_global.flag & AVS_VALID_MINMAX) {
	if (DEBUG) printf("MIN/MAX: ");
      for(i=0; i<field->veclen; i++) {
	  if (DEBUG) printf("%5.2f %5.2f : ", rf_global.min_val[i], rf_global.max_val[i]);
	  switch(field->type) {
	    case AVS_TYPE_BYTE:
	      field->min_data[i] = (unsigned char) rf_global.min_val[i];
	      field->max_data[i] = (unsigned char) rf_global.max_val[i];
	      break;
	    case AVS_TYPE_INTEGER:
	      field->min_data_int[i] = (int) rf_global.min_val[i];
	      field->max_data_int[i] = (int) rf_global.max_val[i];
	      break;
	    case AVS_TYPE_REAL:
	      field->min_data_float[i] = (float) rf_global.min_val[i];
	      field->max_data_float[i] = (float) rf_global.max_val[i];
	      break;
	    case AVS_TYPE_DOUBLE:
	      field->min_data_double[i] = (double) rf_global.min_val[i];
	      field->max_data_double[i] = (double) rf_global.max_val[i];
	      break;
	    case AVS_TYPE_SHORT:
	      field->min_data_short[i] = (short) rf_global.min_val[i];
	      field->max_data_short[i] = (short) rf_global.max_val[i];
	      break;
	  }
      }
	field->flags |= AVS_VALID_MINMAX;
      if (DEBUG) printf("\n");
    }


    /********************************************/
    /* Read the data 				*/
    /********************************************/
    xdrstdio_create (&xdrs, fp, XDR_DECODE);
    if (status_flag) 
      AVSmodify_parameter("Read Status", AVS_VALUE, 
			  "Read Status:\nReading Data\n", NULL, NULL);
    size = AVSfield_prod(field->ndim, field->dimensions);
    full_size = size * field->veclen;
    if (rf_global.data_in_file) {
	if ( ! read_stuff (fp, &xdrs, field->type, field->field_data, full_size, portable)) {
	      READ_ERROR("couldn't read field data");
	}  
    } else {			/* read data out of external file(s) */
	for(i=0; i<field->veclen; i++) {
	    if (rf_global.data[i].filename == NULL) {
	      sprintf(label, "there are not %d data blocks specified", 
		      field->veclen);
	      READ_ERROR(label);
	    }
	    if (DEBUG) printf("data: %s %d ( %d %d )\n", rf_global.data[i].filename,
			      rf_global.data[i].type, rf_global.data[i].skip, rf_global.data[i].stride);

	    switch (rf_global.data[i].type) {
	      case TYPE_ASCII:
		ten_percent = size / 10;
		fix_filename (&rf_global.data[i].filename, fld_filename);
		if ((df = fopen( rf_global.data[i].filename, "r")) == NULL) {
		  sprintf(label, "cannot open file %s", rf_global.data[i].filename);
		  READ_ERROR(label);
	        }
		xdrstdio_create (&xdrs, df, XDR_DECODE);
		
		for (j=0; j<rf_global.data[i].skip; j++) 		/* skip rf_global.data[i].skip lines */
		  fgets(label, 1024, df);
		for (k=0; k<rf_global.data[i].offset; k++)	/* skip over offset items */
		  fscanf(df, "%*s");

		/* read each element for each vector */
		switch(field->type) {
		  case AVS_TYPE_BYTE:
		    for(j=0; j<size; j++) {
			if ( status_flag && j>ten_percent) {
			    sprintf(label, "Read Status:\n%3d%% done reading component %d...\n", 
				    100 *j/size, i+1);
			    AVSmodify_parameter("Read Status", AVS_VALUE, label, NULL, NULL);
			    ten_percent += (size/10);
			}
			if ((k=fscanf(df, "%d", &tmp_int)) != 1) {
			    sprintf(label, "Invalid byte number: component %d, item %d",
				    i, j);
			    READ_ERROR(label);
			}

			field->field_data[j*field->veclen+i] = (unsigned char)tmp_int;
			for(k=0; k<rf_global.data[i].stride-1; k++)		/* skip over stride items */
			  fscanf(df, "%*s");
		    }
		    break;
		  case AVS_TYPE_INTEGER:
		    for(j=0; j<size; j++) {
			if (status_flag && j>ten_percent) {
			    sprintf(label, "Read Status:\n%3d%% done reading component %d...\n", 
				    100 *j/size, i+1);
			    AVSmodify_parameter("Read Status", AVS_VALUE, label, NULL, NULL);
			    ten_percent += (size/10);
			}
			if ((tmp_int=
			     fscanf(df, "%d", &field->field_data_int[j*field->veclen+i])) != 1) {
			    sprintf(label, "Invalid integer number: component %d, item %d",
				    i, j);
			    READ_ERROR(label);
			}

			for(k=0; k<rf_global.data[i].stride-1; k++)		/* skip over stride items */
			  fscanf(df, "%*s");
		    }
		    break;
		  case AVS_TYPE_REAL:
		    for(j=0; j<size; j++) {
			if (status_flag && j>ten_percent) {
			    sprintf(label, "Read Status:\n%3d%% done reading component %d...\n", 
				    100 *j/size, i+1);
			    AVSmodify_parameter("Read Status", AVS_VALUE, label, NULL, NULL);
			    ten_percent += (size/10);
			}
			if ((tmp_int = 
			     fscanf(df, "%e", &field->field_data_float[j*field->veclen+i]))
			    != 1) {
			    sprintf(label, "Invalid floating point number: component %d, item %d",
				    i, j);
			    READ_ERROR(label);
			}
			for(k=0; k<rf_global.data[i].stride-1; k++)		/* skip over stride items */
			  fscanf(df, "%*s");
		    }
		    break;
		  case AVS_TYPE_DOUBLE:
		    for(j=0; j<size; j++) {
			if (status_flag && j>ten_percent) {
			    sprintf(label, "Read Status:\n%3d%% done reading component %d...\n", 
				    100 *j/size, i+1);
			    AVSmodify_parameter("Read Status", AVS_VALUE, label, NULL, NULL);
			    ten_percent += (size/10);
			}
			if ((tmp_int = 
			     fscanf(df, "%E", &field->field_data_double[j*field->veclen+i])) != 1) {
			    sprintf(label, "Invalid double number: component %d, item %d",
				    i, j);
			    READ_ERROR(label);
			}
			for(k=0; k<rf_global.data[i].stride-1; k++)		/* skip over stride items */
			  fscanf(df, "%*s");
		    }
		    break;
		  case AVS_TYPE_SHORT:
		    for(j=0; j<size; j++) {
			if (status_flag && j>ten_percent) {
			    sprintf(label, "Read Status:\n%3d%% done reading component %d...\n", 
				    100 *j/size, i+1);
			    AVSmodify_parameter("Read Status", AVS_VALUE, label, NULL, NULL);
			    ten_percent += (size/10);
			}
			if ((tmp_int=
			     fscanf(df, "%hd", &field->field_data_short[j*field->veclen+i])) != 1) {
			    sprintf(label, "Invalid short number: component %d, item %d",
				    i, j);
			    READ_ERROR(label);
			}

			for(k=0; k<rf_global.data[i].stride-1; k++)		/* skip over stride items */
			  fscanf(df, "%*s");
		    }
		    break;
		}    		/* end switch (field->type) */
	        fclose (df);
		break;
	      case TYPE_UNFORMATTED:
	      case TYPE_BINARY:
		ten_percent = size / 10;
		fix_filename (&rf_global.data[i].filename, fld_filename);
		if ((df = fopen( rf_global.data[i].filename, "r")) == NULL) {
		  sprintf(label, "cannot open file %s", rf_global.data[i].filename);
		  READ_ERROR(label);
	        }
		xdrstdio_create (&xdrs, df, XDR_DECODE);
		
		if (rf_global.data[i].type == TYPE_BINARY)
		  fseek(df, rf_global.data[i].skip, 0);
		else 
		  fseek(df, rf_global.data[i].skip+4, 0);

		if (rf_global.data[i].stride == 1 && field->veclen == 1) {
		    /* contiguous block read */
		    read_stuff (df, &xdrs, field->type, field->field_data, full_size, portable);
		} else {
		    /* read each element for each vector */
			for(j=0; j<size; j++) {
			    if (status_flag && j>ten_percent) {
				sprintf(label, "Read Status:\n%3d%% done reading component %d...\n", 
					100 *j/size, i+1);
				AVSmodify_parameter("Read Status", AVS_VALUE, label, NULL, NULL);
				ten_percent += (size/10);
			    }

			    read_stuff (df, &xdrs, field->type, 
					field->field_data + field->size *
						(j*field->veclen+i),
					1, portable);

		            if (rf_global.data[i].stride != 1)
			       relfseek(df, (rf_global.data[i].stride-1)*
					FieldTypeSizes[portable][field->type]);
			}
	        }			/* end if (contiguous read) */
	        fclose (df);
		break;
	    }				/* end switch (rf_global.data[i].type) */
	    if (rf_global.data[i].filename != NULL) {
		free(rf_global.data[i].filename);
		rf_global.data[i].filename = NULL;
	    }
	}				/* end for(i=0; i<field->veclen; i++) */
    }					/* end read out of files */
	
    /********************************************/
    /* Read the points 				*/
    /********************************************/
    if (status_flag) 
      AVSmodify_parameter("Read Status", AVS_VALUE, 
			  "Read Status:\nReading Points\n", NULL, NULL);
    switch(field->uniform) {
      case UNIFORM:
	npoints = 2 * field->ndim;
	break;
      case RECTILINEAR:
	for (npoints = 0, i = 0; i < field->ndim; 
	     npoints+=field->dimensions[i++]);
	break;
      case IRREGULAR:
	npoints = AVSfield_prod(field->ndim, field->dimensions);
	break;
    }

    if (rf_global.points_in_file) {		/* read the points out of the current file */
	npoints = AVSfield_points_array_size (field->uniform, field->ndim,
				field->nspace, field->dimensions);

	    if ( ! read_stuff (fp, &xdrs, AVS_TYPE_REAL, field->points, npoints, portable)) {
	      if (field->uniform == UNIFORM)  {
	        /* points can't be read so set them to 0.0 */
	        for (i = 0; i < field->ndim; i++) {
		  field->points[2*i] = 0.0;
		  field->points[2*i+1] = field->dimensions[i] - 1.0;
		}
	      }
	      else {
	        READ_ERROR("couldn't read points data");

	      }
	    }
    } else {		/* read points out of external file(s) */
	for(i=0; i<field->nspace; i++) {
	    if (rf_global.points[i].filename == NULL) {
	      sprintf(label, "there are not %d points blocks specified", 
		      field->nspace);
	      READ_ERROR(label);
	    }
	    if (DEBUG) printf("points: %s %d ( %d %d )\n", rf_global.points[i].filename,
			      rf_global.points[i].type, rf_global.points[i].skip, rf_global.points[i].stride);

	    switch (rf_global.points[i].type) {
	      case TYPE_ASCII:
		ten_percent = npoints / 10;
		fix_filename (&rf_global.points[i].filename, fld_filename);
		if ((pf = fopen( rf_global.points[i].filename, "r")) == NULL) {
		  sprintf(label, "cannot open file %s", rf_global.points[i].filename);
		  READ_ERROR(label);
	        }
		xdrstdio_create (&xdrs, pf, XDR_DECODE);

		for (j=0; j<rf_global.points[i].skip; j++)	/* skip rf_global.points[i].skip lines */
		  fgets(label, 1024, pf);
		for (k=0; k<rf_global.points[i].offset; k++)	/* skip over offset items */
		  fscanf(pf, "%*s");

		switch(field->uniform) {
		  case UNIFORM:
		    nread = 2;
		    break;
		  case RECTILINEAR:
		    nread = field->dimensions[i];
		    rect_off = 0;                      
		    for(j=0; j<i; j++)
		      rect_off += field->dimensions[j];
		    break;
		  case IRREGULAR:
		    nread = npoints;
		    break;
		}

		for(j=0; j<nread; j++) {
		    if (status_flag && j>ten_percent) {
			sprintf(label, "Read Status:\n%3d%% done reading points %d...\n", 
				100 *j/npoints, i+1);
			AVSmodify_parameter("Read Status", AVS_VALUE, label, NULL, NULL);
			ten_percent += (npoints/10);
		    }
		    switch(field->uniform) {
		      case UNIFORM:
			fscanf(pf, "%e", &field->points[j+(2*i)]);
			break;
		      case RECTILINEAR:
			fscanf(pf, "%e", &field->points[j+rect_off]);
			break;
		      case IRREGULAR:
			fscanf(pf, "%e", &field->points[j+(i*npoints)]);
			break;
		    }
		    for(k=0; k<rf_global.points[i].stride-1; k++)		/* skip over stride items */
		      fscanf(pf, "%*s");
		}
	        fclose (pf);
		break;
	      case TYPE_UNFORMATTED:
	      case TYPE_BINARY:
		ten_percent = npoints / 10;
		fix_filename (&rf_global.points[i].filename, fld_filename);
		if ((pf = fopen( rf_global.points[i].filename, "r")) == NULL) {
		  sprintf(label, "cannot open file %s", rf_global.points[i].filename);
		  READ_ERROR(label);
		}
	       	xdrstdio_create (&xdrs, pf, XDR_DECODE);

		if (rf_global.points[i].type == TYPE_BINARY)
		  fseek(pf, rf_global.points[i].skip, 0);
		else 
		  fseek(pf, rf_global.points[i].skip+4, 0);
		if (rf_global.points[i].stride == 1) {   /* contiguous read */
		    switch(field->uniform) {
		      case UNIFORM:
			read_stuff (pf, &xdrs, AVS_TYPE_REAL, &field->points[i*npoints],
				    npoints, portable);
			break;
		      case RECTILINEAR:
			rect_off = 0;                      
			for(j=0; j<i; j++)
			  rect_off += field->dimensions[j];
			read_stuff (pf, &xdrs, AVS_TYPE_REAL, &field->points[rect_off],
				    field->dimensions[i], portable);
			break;
		      case IRREGULAR:
			read_stuff (pf, &xdrs, AVS_TYPE_REAL, &field->points[i*npoints],
				    npoints, portable);
			break;
		    }
		} else {		       /* read each element for each vector */

		    switch(field->uniform) {
		      case UNIFORM:
			nread = 2;
			break;
		      case RECTILINEAR:
			nread = field->dimensions[i];
			rect_off = 0;                      
			for(j=0; j<i; j++)
			  rect_off += field->dimensions[j];
			break;
		      case IRREGULAR:
			nread = npoints;
			break;
		    }

		    for(j=0; j<nread; j++) {
			if (status_flag && j>ten_percent) {
			    sprintf(label, "Read Status:\n%3d%% done reading points %d...\n", 
				100 *j/npoints, i+1);
			    AVSmodify_parameter("Read Status", AVS_VALUE, label, NULL, NULL);
			    ten_percent += (npoints/10);
			}
			switch(field->uniform) {


			  /*********  THIS DOESN'T LOOK RIGHT  ***********/
			  /*********  A MIXTURE OF fscanf AND fread  *****/

			  case UNIFORM:
			    fscanf(pf, "%e", &field->points[j+(2*i)]);
			    break;
			  case RECTILINEAR:
			    fscanf(pf, "%e", &field->points[j+rect_off]);
			    break;
			  case IRREGULAR:
			    fread(&field->points[j+(i*npoints)], sizeof(float), 1, pf);
			    break;
			}

			relfseek(pf, (rf_global.points[i].stride-1)*sizeof(float));
		    }
		}
	        fclose (pf);
		break;
	    }				/* end switch (rf_global.points[i].type) */
	    if (rf_global.points[i].filename != NULL) {
		free(rf_global.points[i].filename);
		rf_global.points[i].filename = NULL;
	    }
	}				/* end for(i=0; i<field->veclen; i++) */
    }
    
    AVSfield_get_extent(field, rf_global.min_ext, rf_global.max_ext);
    if (status_flag) 
      AVSmodify_parameter("Read Status", AVS_VALUE, 
			  "Read Status:\nInactive\n", NULL, NULL);

    /* Set the input pointer */
    *out_field = field;
    
    /* Indicate success */
    return(1);

}

/******************************************************************************/

/*
 * This point here is that on many systems, the "fseek" library routine
 * makes a system call and flushes the buffer even if we are only seeking
 * ahead a few bytes in the stdio buffer.  This routine tries to optimize
 * those cases by using "fread" instead.
 * 
 * Note that it only implements the "relative" seek case, not the absolute.
 */
static
relfseek(fp,offset)
FILE *fp;
int offset;
{
   char buff[1024];
   if (offset > 1024 || offset < 0) fseek(fp,offset,1);
   else fread(buff,sizeof(char),offset,fp);
}


/**************************************************************************/
/*
 * Read specified type and number of items in portable or native format.
 *
 * Inputs:	fp	- File pointer.
 *		type	- One of the AVS data types.
 *		addr	- Where to start storing data.
 *		num	- Number of items to read.
 *		portable - Perform conversion from XDR?
 *
 * Returns:	TRUE for success.  FALSE for failure.
 *
 */

static int read_stuff (fp, xdrs, type, addr, num, portable)
FILE *fp;
XDR *xdrs;
int type;
char *addr;
int num;
int portable;
{
	int n;

/*
 * For native mode, just slop it into memory.
 */
	if ( ( ! portable ) || ( type == AVS_TYPE_BYTE ) ) {
		n = num * FieldTypeSizes[0][type];
		return (fread (addr, 1, n, fp) == n);
	}

/*
 * This is more interesting.
 */
	switch (type) {
	    case AVS_TYPE_INTEGER:
		for (n=0; n<num; n++) {
			if ( ! xdr_int (xdrs, addr))
				return (FALSE);
			addr += FieldTypeSizes[1][AVS_TYPE_INTEGER];
		}
		break;
	    case AVS_TYPE_REAL:
		for (n=0; n<num; n++) {
			if ( ! xdr_float (xdrs, addr))
				return (FALSE);
			addr += FieldTypeSizes[1][AVS_TYPE_REAL];
		}
		break;
	    case AVS_TYPE_DOUBLE:
		for (n=0; n<num; n++) {
			if ( ! xdr_double (xdrs, addr))
				return (FALSE);
			addr += FieldTypeSizes[1][AVS_TYPE_DOUBLE];
		}
		break;
	    case AVS_TYPE_SHORT:
		for (n=0; n<num; n++) {
			/* Don't be tempted to use xdr_short because */
			/* it pads up to a boundary of 4. */

			unsigned char hi, lo;
			int result;

			if (fread (&hi, 1, 1, fp) != 1) return (FALSE);
			if (fread (&lo, 1, 1, fp) != 1) return (FALSE);

			/* Short is not necessarily two bytes!!!! */
			/* Might have to sign extend it. */

			result = (hi << 8) | lo;
			if (result & 0x8000)
				result |= ~ 0xffff;

			*(short *)addr = result;
			addr += FieldTypeSizes[1][AVS_TYPE_SHORT];
		}
		break;
	    default:
		fprintf (stderr, "rf_read_field: read_stuff: bad type\n");
		return (FALSE);
	}
	return (TRUE);
}

