/*ScianFiles.c
  File reading routines for scian
  Eric Pepke
  August 17, 1990

  12/4/91	Fixed bug with colored polygons
  12/4/91	Made default file format work on command line
*/

#include "Scian.h"
#include "ScianTypes.h"
#include "ScianArrays.h"
#include "ScianIcons.h"
#include "ScianWindows.h"
#include "ScianObjWindows.h"
#include "ScianVisWindows.h"
#include "ScianVisObjects.h"
#include "ScianControls.h"
#include "ScianColors.h"
#include "ScianDialogs.h"
#include "ScianFiles.h"
#include "ScianFileSystem.h"
#include "ScianLists.h"
#include "ScianPictures.h"
#include "ScianErrors.h"
#include "ScianTimers.h"
#include "ScianDatasets.h"
#include "ScianFilters.h"
#include "ScianTextBoxes.h"
#include "ScianTitleBoxes.h"
#include "ScianButtons.h"
#include "ScianSliders.h"
#include "ScianScripts.h"
#include "ScianIDs.h"
#include "ScianVisContours.h"
#include "ScianStyle.h"
#include "ScianSpaces.h"
#include "ScianMethods.h"
#include "ScianObjFunctions.h"

char *curFileName = 0;			/*Current file name*/

#define SQUARE(x) ((x) * (x))
ObjPtr fileClass;			/*Class of files*/
ObjPtr fileReaderClass;
ObjPtr allFileReaders;
extern FILE *curScript;

#ifdef PROTO
ObjPtr ReadKJReflectivity(char *);
ObjPtr MakeDatasetName(char *);
#else
ObjPtr ReadKJReflectivity();
ObjPtr MakeDatasetName();
#endif

void SkipBlanks(file)
FILE *file;
/*Skips blanks in the file*/
{
    int c;
    while ((c = getc(file)) == ' ' || c == '\t');
    ungetc(c, file);
}

void SkipBlanksAndCommas(file)
FILE *file;
/*Skips blanks in the file*/
{
    int c;
    while ((c = getc(file)) == ' ' || c == '\t' || c == ',');
    ungetc(c, file);
}

void SkipNonBlanks(file)
FILE *file;
/*Skips non-blanks in the file*/
{
    int c;
    while ((c = getc(file)) != ' ' && c >= 0 && c != '\n');
    ungetc(c, file);
}

void ReadLn(file)
FILE *file;
/*Reads to next line in the file*/
{
    int c;
    while ((c = getc(file)) >= 0 && c != '\n');
}

void FileFormatError(routine, what)
char *routine, *what;
/*Reports a file format error*/
{
    ReportError(routine, what);
}

char *ShortNameOf(n)
char *n;
/*Returns the short file name of n*/
{
    char *t;
		
    /*Make name last file name in argument*/
    for (t = n; *t; ++t)
    {
	if (*t == '/') n = t + 1;
    }
    return n;
}

ObjPtr MakeDatasetName(s)
char *s;
/*Makes and returns a dataset name for file name s*/
{
    Bool hasExtension = false;
    Bool hasNumber = false;
    s = ShortNameOf(s);
    strcpy(tempStr, s);
    s = tempStr;

    /*Trim off anything non-numeric after a period*/
    while (*s)
    {
	if (*s == '.')
	{
	    hasNumber = true;
	}
	else if (hasNumber)
	{
	    if (*s <= '0' || *s >= '9')
	    {
		hasNumber = false;
		hasExtension = true;
	    }
	}
	++s;
    }
    if (hasExtension)
    {
	while (*s != '.') --s;
	*s = 0;
    }
    return NewString(tempStr);
}

#define ADDCOLORS	100


static ObjPtr ReadNFFXFile(name)
char *name;
/*Reads an extended NFF file from name*/
{
    ObjPtr picture, retVal;
    int c;
    real curTime = 0.0;
    ObjPtr timeSteps = NULLOBJ, timeData = NULLOBJ;
    Bool timeRead = false;
    ObjPtr eternalPicture = NULLOBJ;
    ObjPtr timedObj;
    char cmdStr[256];
    FILE *inFile;
    int whichStep = 0;
    real ox = 0.0, oy = 0.0, oz = 0.0;
    int curColorIndex = -2;
    int nextColorIndex = 2;
    long nColorsAllocated = 0;
    short3 *curColors;
    Bool *colorAllocated;		/*Flag to see if this color is allocated*/
    int k;				/*Counter*/
    int movingStart = -1;		/*Start of moving colors*/

    ObjPtr palette;

    inFile = fopen(name, "r");
    if (!inFile)
    {
	Error("ReadNFFXFile", OPENFILEERROR, name);
	return NULLOBJ;
    }

    nColorsAllocated = ADDCOLORS;
    curColors = (short3 *) malloc(nColorsAllocated * sizeof(short3));
    curColors[0][0] = 255;
    curColors[0][1] = 255;
    curColors[0][2] = 255;
    curColors[1][0] = 0;
    curColors[1][1] = 0;
    curColors[1][2] = 0;

    colorAllocated = (Bool *) malloc(nColorsAllocated * sizeof(Bool));
    for (k = 0; k < nColorsAllocated; ++k)
    {
	colorAllocated[k] = false;
    }

    picture = NewPicture();

    /*Read the picture in*/
    for (SkipBlanks(inFile); (c = getc(inFile)) >= 0; SkipBlanks(inFile))
    {
	ungetc(c, inFile);
	fgets(tempStr, 255, inFile);

	if (1 == sscanf(tempStr, "%s", cmdStr))
	{
	    if (*cmdStr == '#')
	    {
		/*It's a comment*/
	    }
	    else if (0 == strcmp(cmdStr, "t"))
	    {
		/*It's a time marker*/
		real nextTime;
		if (1 != sscanf(tempStr, "t %g", &nextTime))
		{
		    FileFormatError("ReadNFFXFile", "Bad time step");
		    continue;
		}
		if (!timeRead)
		{
		   timeRead = true;
		   timeSteps = NewList();
		   timeData = NewList();
		   eternalPicture = picture;
		   picture = NewPicture();
		}
		else if (picture)
		{
		    /*Got to spit out the old picture*/
		    PostfixList(timeSteps, NewReal(curTime));
		    PostfixList(timeData, picture);
		    picture = NewPicture();
		}

		if (movingStart < 0)
		{
		    /*First encounter with a time object*/
		    movingStart = nextColorIndex;
		    if (movingStart < 0) movingStart = 0;
		}
		else
		{
		    /*Not first encounter, erase colorAllocated*/
		    for (k = movingStart; k < nextColorIndex; ++k)
		    {
			colorAllocated[k] = false;
		    }
		}
		curTime = nextTime;
		SkipBlanks(inFile);
		continue;
	    }
	    else if (0 == strcmp(cmdStr, "f"))
	    {
		float r, g, b, d;
		if (8 == sscanf(tempStr, "f %g %g %g %g %g %g %g %g \n",
			&r, &g, &b, &d, &d, &d, &d, &d))
		{
		    short rs, gs, bs;

		    /*It's a valid color.*/
		    rs = r * 255.0;
		    gs = g * 255.0;
		    bs = b * 255.0;
		    if (movingStart >= 0)
		    {
			/*Already in moving portion.  Search for colors*/
			for (k = movingStart; k < nextColorIndex; ++k)
			{
			    if (!colorAllocated[k] &&
				curColors[k][0] == rs &&
				curColors[k][1] == gs &&
				curColors[k][2] == bs)
			    {
				curColorIndex = k - 2;
				colorAllocated[k] = true;
				goto foundColor;
			    }
			}
		    }
		    if (nextColorIndex >= nColorsAllocated)
		    {
			nColorsAllocated += ADDCOLORS;
			curColors = (short3 *) realloc(curColors,
				nColorsAllocated * sizeof(short3));
			colorAllocated = (Bool *) realloc(colorAllocated,
				nColorsAllocated * sizeof(Bool));
			for (k = nextColorIndex; k < nColorsAllocated; ++k);
			{
			    colorAllocated[k] = false;
			}
		    }
		    curColorIndex = nextColorIndex - 2;
		    curColors[nextColorIndex][0] = rs;
		    curColors[nextColorIndex][1] = gs;
		    curColors[nextColorIndex][2] = bs;
		    ++nextColorIndex;
		}
		else
		{
		    FileFormatError("ReadNFFXFile", "Bad color format statement");
		}
foundColor:;
	    }
	    else if (0 == strcmp(cmdStr, "s"))
	    {
		/*Sphere*/
		float center[3];
		float radius;
		if (4 == sscanf(tempStr, "s %g %g %g %g", 
			&(center[0]), &(center[1]), &(center[2]), &radius))
		{
		    center[0] += ox;
		    center[1] += oy;
		    center[2] += oz;
		    
		    AppendSphereToPicture(picture, center, radius, curColorIndex);
		}
		else
		{
		    FileFormatError("ReadNFFXFile", "Badly formatted sphere");
		}
	    }
	    else if (0 == strcmp(cmdStr, "o"))
	    {
		/*Origin*/
		sscanf(tempStr, "o %g %g %g", &ox, &oy, &oz);
	    }
	    else if (0 == strcmp(cmdStr, "pp"))
	    {
		int nVertices;
		Vertex *vertices;
		/*Smooth polygon*/
		if (1 == sscanf(tempStr, "pp %d", &nVertices))
		{
		    vertices = (Vertex *) malloc(nVertices * sizeof(Vertex));
		    if (vertices)
		    {
			int k;
			for (k = 0; k < nVertices; ++k)
			{
			    if (6 != fscanf(inFile, "%g %g %g %g %g %g",
				&(vertices[k] . position[0]),
				&(vertices[k] . position[1]),
				&(vertices[k] . position[2]),
				&(vertices[k] . normal[0]),
				&(vertices[k] . normal[1]),
				&(vertices[k] . normal[2])))
			    {
				FileFormatError("ReadNFFXFile", "Not enough numbers");
				break;
			    }
			    vertices[k] . position[0] += ox;
			    vertices[k] . position[1] += oy;
			    vertices[k] . position[2] += oz;
			    vertices[k] . colorIndex = curColorIndex;
			}
			if (k >= nVertices)
			{
			    AppendPolyToPicture(picture, nVertices, vertices);
			}
			free(vertices);
		    }
		    else
		    {
			OMErr();
		    }
		}
		else
		{
		    FileFormatError("ReadNFFXFile", "No vertices specified");
		    continue;
		}
	    }
	    else if (0 == strcmp(cmdStr, "c"))
	    {
		float end1[3], end2[3], rad1, rad2;
		/*It's a conical frustum*/
		if (4 != fscanf(inFile, "%g %g %g %g\n",
			&(end1[0]), &(end1[1]), &(end1[2]), &rad1))
		{
		    FileFormatError("ReadNFFXFile", "Badly formed frustum");
		    continue;
		}
		end1[0] += ox;
		end1[1] += oy;
		end1[2] += oz;
		if (4 != fscanf(inFile, "%g %g %g %g\n",
			&(end2[0]), &(end2[1]), &(end2[2]), &rad2))
		{
		    FileFormatError("ReadNFFXFile", "Badly formed frustum");
		    continue;
		}
		end2[0] += ox;
		end2[1] += oy;
		end2[2] += oz;
		AppendFrustumToPicture(picture, end1, rad1, end2, rad2, curColorIndex);
	    }
	    else if (0 == strcmp(cmdStr, "p"))
	    {
		int nVertices;
		Vertex *vertices;

		/*Polygon*/
		if (1 == sscanf(tempStr, "p %d", &nVertices))
		{
		    vertices = (Vertex *) malloc(nVertices * sizeof(Vertex));
		    if (vertices)
		    {
			int k;

			for (k = 0; k < nVertices; ++k)
			{
			    if (3 != fscanf(inFile, "%g %g %g \n",
				&(vertices[k] . position[0]),
				&(vertices[k] . position[1]),
				&(vertices[k] . position[2])))
			    {
				FileFormatError("ReadNFFXFile", "Not enough numbers");
			    }				
			    vertices[k] . position[0] += ox;
			    vertices[k] . position[1] += oy;
			    vertices[k] . position[2] += oz;
			    vertices[k] . colorIndex = curColorIndex;
			}
			if (k >= nVertices)
			{
			    float vec1[3], vec2[3], normal[3], length;

			    /*Derive normal*/
			    for (k = 0; k < 3; ++k)
			    {
				vec1[k] = vertices[1] . position[k] -
					  vertices[0] . position[k];
				vec2[k] = vertices[2] . position[k] -
					  vertices[1] . position[k];
			    }
			    normal[0] = vec1[1] * vec2[2] - vec1[2] * vec2[1];
			    normal[1] = vec1[2] * vec2[0] - vec1[0] * vec2[2];
			    normal[2] = vec1[0] * vec2[1] - vec1[1] * vec2[0];
			    length = sqrt((double)
					   normal[0] * normal[0] +
					   normal[1] * normal[1] +
					   normal[2] * normal[2]);
			    normal[0] /= length;
			    normal[1] /= length;
			    normal[2] /= length;

			    for (k = 0; k < nVertices; ++k)
			    {
				vertices[k] . normal[0] = normal[0];
				vertices[k] . normal[1] = normal[1];
				vertices[k] . normal[2] = normal[2];
			    }

			    /*Save the polygon*/
			    AppendPolyToPicture(picture, nVertices, vertices);
			}
			free(vertices);
		    }
		    else
		    {
			OMErr();
		    }
		}
		else
		{
		    FileFormatError("ReadNFFXFile", "No vertices specified");
		}
	    }
	    else if (0 == strcmp(cmdStr, "pl"))
	    {
		int nVertices;
		Vertex *vertices;

		/*Polyling*/
		if (1 == sscanf(tempStr, "pl %d", &nVertices))
		{
		    vertices = (Vertex *) malloc(nVertices * sizeof(Vertex));
		    if (vertices)
		    {
			int k;

			for (k = 0; k < nVertices; ++k)
			{
			    if (3 != fscanf(inFile, "%g %g %g \n",
				&(vertices[k] . position[0]),
				&(vertices[k] . position[1]),
				&(vertices[k] . position[2])))
			    {
				FileFormatError("ReadNFFXFile", "Not enough numbers");
			    }				
			    vertices[k] . position[0] += ox;
			    vertices[k] . position[1] += oy;
			    vertices[k] . position[2] += oz;
			    vertices[k] . normal[0] = 0.0;
			    vertices[k] . normal[1] = 0.0;
			    vertices[k] . normal[2] = 1.0;
			    vertices[k] . colorIndex = curColorIndex;
			}
			if (k >= nVertices)
			{
			    /*Save the polygon*/
			    AppendPolylineToPicture(picture, 1, 0, nVertices, vertices);
			}
			free(vertices);
		    }
		    else
		    {
			OMErr();
		    }
		}
		else
		{
		    FileFormatError("ReadNFFXFile", "No vertices specified");
		}
	    }
	    else
	    {
		char t, err[200];
		t = *tempStr;
		sprintf(err, "Bad object type: %c (%x)", t, t);
		FileFormatError("ReadNFFXFile", err);
	    }
	}
	else
	{
	    /*Blank line in file*/
	}
    }

    /*Now make the object*/
    retVal = NewObject(geometryClass, 0);
    if (picture)
    {
	if (timeRead)
	{
	    /*Got to spit out the old picture into the time var*/
	    PostfixList(timeSteps, NewReal(curTime));
	    PostfixList(timeData, picture);
	}
	else
	{
	    /*Just make it eternal*/
	    eternalPicture = picture;
	}
    }

    if (timeRead)
    {
	timedObj = NewTimedObject(timeSteps, timeData);
	SetVar(retVal, DATA, timedObj);
	SetVar(retVal, ETERNALPART, eternalPicture);
    }
    else
    {
	SetVar(retVal, DATA, eternalPicture);
    }
    SetVar(retVal, NAME, MakeDatasetName(name));

    /*Create a new palette*/
    curColors[nextColorIndex][0] = 255;
    curColors[nextColorIndex][1] = 255;
    curColors[nextColorIndex][2] = 255;
    ++nextColorIndex;
    palette = NewPalette(MAX(nextColorIndex, 5));
    FieldPaletteName(palette, retVal);
    CopyColorsToPalette(palette, curColors);
    free(curColors);
    free(colorAllocated);
    SetVar(retVal, CPALETTE, palette);

    fclose(inFile);
    RegisterDataset(retVal);
    return NULLOBJ;
}

static ObjPtr ReadJAKFile(name)
char *name;
/*Reads one of jay a kumar's files*/
{
    ObjPtr timeSteps, timeData;
    ObjPtr timedObj;
    FILE *inFile;
    int whichFrame;
    real dims[2];			/*The dimensions of the data, temp.*/
    real bounds[6];			/*The bounds of the data form*/
    long xSize, ySize;
    real dataMin, dataMax;
    real tempMin, tempMax;
    ObjPtr dataForm;
    ObjPtr dimsArray, boundsArray;
    ObjPtr retVal;

    inFile = fopen(name, "r");
    if (!inFile)
    {
	Error("ReadJAKFile", OPENFILEERROR, name);
	return NULLOBJ;
    }

    timeSteps = NewList();
    timeData = NewList();

    /*Read in the frames*/
    whichFrame = 0;
    while (fscanf(inFile, " %ld %ld", &xSize, &ySize) == 2)
    {
	ObjPtr data;
	int i, j;
	real *dataPtr;

	if (fscanf(inFile, " %g %g", &tempMin, &tempMax) != 2)
	{
	    char err[200];
	    sprintf(err, "Error reading minmax in frame %d", whichFrame);
	    FileFormatError("ReadJAKFile", err);
	    fclose(inFile);
	    return NULLOBJ;
	}

	if (whichFrame == 0)
	{
	    /*If it's the first frame, set sizes and minmax*/
	    dims[0] = xSize;
	    dims[1] = ySize;
	    dataMin = tempMin;
	    dataMax = tempMax;
	}
	else
	{
	    /*Enlarge minmax*/
	    if (tempMin < dataMin) dataMin = tempMin;
	    if (tempMax > dataMax) dataMax = tempMax;
	}

	data = NewRealArray(2, xSize, ySize);
	dataPtr = ArrayMeat(data) + (ySize - 1) * xSize;
	for (j = 0; j < ySize; ++j)
	{
	    for (i = 0; i < xSize; ++i)
	    {
		if (1 != fscanf(inFile, " %g", dataPtr))
		{
		    char err[200];
		    sprintf(err, "Error in frame %d at %d %d", whichFrame, i, j);
		    FileFormatError("ReadJAKFile", err);
		    fclose(inFile);
		    return NULLOBJ;
		}
		++dataPtr;
	    }
	    dataPtr -= 2 * xSize;
	}
	PostfixList(timeSteps, NewReal((real) whichFrame));
	PostfixList(timeData, data);
	++whichFrame;
    }

    fclose(inFile);

    /*Create the data form*/
    dataForm = NewObject(dataFormClass, 0);
    dimsArray = NewRealArray(1, (long) 2);
    
    /*Put in some dimensions*/
    CArray2Array(dimsArray, dims);
    SetVar(dataForm, DIMENSIONS, dimsArray); 

    /*Put in the bounds*/
    bounds[0] = 0.;
    bounds[1] = 1000.0;
    bounds[2] = 0.;
    bounds[3] = 1000.0;
    bounds[4] = dataMin;
    bounds[5] = dataMax;
    boundsArray = NewRealArray(1, (long) 6);
    CArray2Array(boundsArray, bounds);
    SetVar(dataForm, BOUNDS, boundsArray);

    /*Create the field*/
    retVal = NewObject(data2DScalar, 0);
    SetVar(retVal, DATA, NewTimedObject(timeSteps, timeData));
    SetVar(retVal, DATAFORM, dataForm);
    SetVar(retVal, NAME, MakeDatasetName(name));

    RegisterDataset(retVal);
    return NULLOBJ;
}

#define DS(k) \
    if (1 != fread(&dataSize, sizeof(long), 1, inFile) ||		\
	dataSize != k)							\
    {									\
	FileFormatError("ReadJAKFile", "Data length error"); 		\
	fclose(inFile);							\
	return NULLOBJ;							\
    }


static ObjPtr ReadJAKBFile(name)
char *name;
/*Reads one of jay a kumar's binary files*/
{
    ObjPtr timeSteps, timeData;
    ObjPtr timedObj;
    FILE *inFile;
    long whichFrame;
    real dims[2];			/*The dimensions of the data, temp.*/
    real bounds[6];			/*The bounds of the data form*/
    long xSize, ySize;
    long dataSize;			/*Dummy to hold size of data*/
    real dataMin, dataMax;
    ObjPtr dataForm;
    ObjPtr dimsArray, boundsArray;
    ObjPtr retVal;
    long nFrames;

    inFile = fopen(name, "r");
    if (!inFile)
    {
	Error("ReadJAKFile", OPENFILEERROR, name);
	return NULLOBJ;
    }

    timeSteps = NewList();
    timeData = NewList();

    whichFrame = 0;

    DS(4);
    if (1 != fread(&nFrames, sizeof(int), 1, inFile))
    {
	FileFormatError("ReadJAKFile", "Error reading nframes");
	fclose(inFile);
	return NULLOBJ;
    }
    DS(4);

    DS(8);
    if (1 != fread(&xSize, sizeof(int), 1, inFile))
    {
	FileFormatError("ReadJAKFile", "Error reading size");
	fclose(inFile);
	return NULLOBJ;
    }
    if (1 != fread(&ySize, sizeof(int), 1, inFile))
    {
	FileFormatError("ReadJAKFile", "Error reading size");
	fclose(inFile);
	return NULLOBJ;
    }
    DS(8);
    dims[0] = xSize;
    dims[1] = ySize;

    DS(8);
    if (1 != fread(&dataMin, sizeof(real), 1, inFile))
    {
	FileFormatError("ReadJAKFile", "Error reading size");
	fclose(inFile);
	return NULLOBJ;
    }
    if (1 != fread(&dataMax, sizeof(real), 1, inFile))
    {
	FileFormatError("ReadJAKFile", "Error reading size");
	fclose(inFile);
	return NULLOBJ;
    }
    DS(8);

	FileFormatError("ReadJAKFile", "Error reading size");

    /*Read in the frames*/

    while (1 == fread(&dataSize, sizeof(long), 1, inFile))	
    {
	ObjPtr data;
	int i, j;
	real *dataPtr;

	if (dataSize != 4)
	{
	    FileFormatError("ReadJAKFile", "Data length error"); 
	    fclose(inFile);
	    return NULLOBJ;
	}
	if (1 != fread(&whichFrame, sizeof(long), 1, inFile))
	{
	    char err[256];
	    sprintf(err, "Error reading frame #\n");
	    FileFormatError("ReadJAKFile", err);
	    fclose(inFile);
	    return NULLOBJ;
	}
	DS(4);

	data = NewRealArray(2, xSize, ySize);
	dataPtr = ArrayMeat(data) + (ySize - 1) * xSize;
	for (j = 0; j < ySize; ++j)
	{
	    DS(xSize * sizeof(real));
	    if (xSize != fread(dataPtr, sizeof(real), xSize, inFile))
	    {
		char err[200];
		sprintf(err, "Error reading frame %d", whichFrame);
		FileFormatError("ReadJAKBFile", err);
		fclose(inFile);
		return NULLOBJ;
	    }

	    DS(xSize * sizeof(real));
	    dataPtr -= xSize;
	}
	PostfixList(timeSteps, NewReal((real) whichFrame));
	PostfixList(timeData, data);
    }
    fclose(inFile);

    /*Create the data form*/
    dataForm = NewObject(dataFormClass, 0);
    dimsArray = NewRealArray(1, (long) 2);
    
    /*Put in some dimensions*/
    CArray2Array(dimsArray, dims);
    SetVar(dataForm, DIMENSIONS, dimsArray); 

    /*Put in the bounds*/
    bounds[0] = 0.;
    bounds[1] = 1000.0;
    bounds[2] = 0.;
    bounds[3] = 1000.0;
    bounds[4] = dataMin;
    bounds[5] = dataMax;
    boundsArray = NewRealArray(1, (long) 6);
    CArray2Array(boundsArray, bounds);
    SetVar(dataForm, BOUNDS, boundsArray);

    /*Create the field*/
    retVal = NewObject(data2DScalar, 0);

    SetVar(retVal, DATA, NewTimedObject(timeSteps, timeData));
    {
	ObjPtr minMaxArray;
	real minMax[2];
	minMax[0] = dataMin;
	minMax[1] = dataMax;
                minMaxArray = NewRealArray(1, 2L);
                    CArray2Array(minMaxArray, minMax);
                    SetVar(retVal, MINMAX, minMaxArray);
    }
    SetVar(retVal, DATAFORM, dataForm);
    SetVar(retVal, NAME, MakeDatasetName(name));

    RegisterDataset(retVal);
    return NULLOBJ;
}

static ObjPtr ReadKJFile(name)
char *name;
/*Reads one of Ken Johnson's fields from file inFile*/
{
    char mapDate[20], mapTime[20];
    char anType[2];
    int maxRadar;
    float xg, yg, z0;
    float dx, dy, dz;
    int lx, ly, lz;
    ObjPtr dataForm;			/*The grid holding the data*/
    ObjPtr boundsArray;			/*Array containing bounds of grid*/
    ObjPtr dimsArray;			/*Array containing dimensions of the data*/
    ObjPtr fieldData;			/*The array of data in the field*/
    real dims[3];			/*The dimensions of the data, temp.*/
    real bounds[6];			/*The bounds of the data form*/
    real *dataPtr;			/*The meat of the array*/
    int i, j, k;			/*Index into the grid*/
    ObjPtr retVal;			/*The field to return*/
    FILE *inFile;

    inFile = fopen(name, "r");
    if (!inFile)
    {
	Error("ReadKJFile", OPENFILEERROR, name);
	return NULLOBJ;
    }

    /*Read header line*/
    ReadLn(inFile);
    if (fscanf(inFile, "%s %s %1s %d %g %g %g %g %g %g %d %d %d",
		mapDate, mapTime, anType, &maxRadar, &xg, &yg, &z0,
		&dx, &dy, &dz, &lx, &ly, &lz)
	!= 13)
    {
	FileFormatError("ReadKJFile", "Error reading header");
    }
    /*Get over the rest of the line*/
    ReadLn(inFile);

    /*Create the data form*/
    dataForm = NewObject(dataFormClass, 0);
    dimsArray = NewRealArray(1, (long) 3);
    
    /*Put in some dimensions*/
    dims[0] = (real) lx;
    dims[1] = (real) ly;
    dims[2] = (real) lz;
    CArray2Array(dimsArray, dims);
    SetVar(dataForm, DIMENSIONS, dimsArray); 

    /*Put in the bounds*/
    bounds[0] = xg;
    bounds[1] = xg + (lx - 1) * dx;
    bounds[2] = yg;
    bounds[3] = yg + (ly - 1) * dy;
    bounds[4] = 3.255 + z0;
    bounds[5] = 3.255 + z0 + (lz - 1) * dz;
    boundsArray = NewRealArray(1, (long) 6);
    CArray2Array(boundsArray, bounds);
    SetVar(dataForm, BOUNDS, boundsArray);

    /*Read the data*/
    fieldData = NewRealArray(3, (long) lx, (long) ly, (long) lz);
    dataPtr = ArrayMeat(fieldData);

    for (k = 0; k < lz; ++k)
    {
	for (j = 0; j < ly; ++j)
	{
	    for (i = 0; i < lx; ++i)
	    {
		real curVal;
		if (1 != fscanf(inFile, "%g", &curVal))
		{
		    FileFormatError("Read KJFile", "Error reading data");
		    fclose(inFile);
		    return NULLOBJ;
		}
		*(dataPtr + i * ly * lz + j * lz + k) = (curVal == 999.0) ? missingData : curVal;
	    }
	}
    }

    /*Create the field*/
    retVal = NewObject(data3DScalar, 0);
    SetVar(retVal, DATA, fieldData);
    SetVar(retVal, DATAFORM, dataForm);
    SetVar(retVal, NAME, MakeDatasetName(name));

    fclose(inFile);
    RegisterDataset(retVal);
    return NULLOBJ;
}

static ObjPtr ReadSYFile(name)
char *name;
/*Reads one of Saul Youssef's fields from file name*/
{
    float dx, dy, dz;
    int lx, ly, lz;
    float minX, minY, minZ;
    float maxX, maxY, maxZ;
    ObjPtr dataForm;			/*The grid holding the data*/
    ObjPtr boundsArray;			/*Array containing bounds of grid*/
    ObjPtr dimsArray;			/*Array containing dimensions*/
    ObjPtr fieldData;			/*The array of data in the field*/
    real dims[3];			/*The dimensions of the data, temp.*/
    real bounds[6];			/*The bounds of the data form*/
    real *dataPtr;			/*The meat of the array*/
    int i, j, k;			/*Index into the grid*/
    ObjPtr retVal;			/*The field to return*/
    FILE *inFile;

    inFile = fopen(name, "r");
    if (!inFile)
    {
	Error("ReadSYFile", OPENFILEERROR, name);
	return NULLOBJ;
    }

    /*Read header*/
    if (fscanf(inFile, " %d %d %d %g %g %g %g %g %g",
		&lx, &ly, &lz, &minX, &maxX, &minY, &maxY, &minZ, &maxZ)
	!= 9) 
    {
	FileFormatError(ReadSYFile, "Error reading header");
    }

    /*Create the data form*/
    dataForm = NewObject(dataFormClass, 0);
    dimsArray = NewRealArray(1, (long) 3);
    
    /*Put in some dimensions*/
    dims[0] = (real) lx;
    dims[1] = (real) ly;
    dims[2] = (real) lz;
    CArray2Array(dimsArray, dims);
    SetVar(dataForm, DIMENSIONS, dimsArray); 

    /*Put in the bounds*/
    bounds[0] = minX;
    bounds[1] = maxX;
    bounds[2] = minY;
    bounds[3] = maxY;
    bounds[4] = minZ;
    bounds[5] = maxZ;
    boundsArray = NewRealArray(1, (long) 6);
    CArray2Array(boundsArray, bounds);
    SetVar(dataForm, BOUNDS, boundsArray);

    /*Read the data*/
    fieldData = NewRealArray(3, (long) lx, (long) ly, (long) lz);
    dataPtr = ArrayMeat(fieldData);

    for (k = 0; k < lz; ++k)
    {
	for (j = 0; j < ly; ++j)
	{
	    for (i = 0; i < lx; ++i)
	    {
		real curVal;
		if (1 != fscanf(inFile, " %g", &curVal))
		{
		    FileFormatError("ReadSYFile", "Error reading data");
		    fclose(inFile);
		    return NULLOBJ;
		}
		*(dataPtr + i * ly * lz + j * lz + k) = curVal;
	    }
	}
    }

    /*Create the field*/
    retVal = NewObject(data3DScalar, 0);
    SetVar(retVal, DATA, fieldData);
    SetVar(retVal, DATAFORM, dataForm);
    SetVar(retVal, NAME, MakeDatasetName(name));

    fclose(inFile);
    RegisterDataset(retVal);
    return NULLOBJ;
}

char *kjIndField[] =
	{
	    "u",
	    "v",
	    "w",
	    "vt",
	    "z",
	    "s"
	};
#define NKJFIELDS 6

static ObjPtr ReadKJ3File(name)
char *name;
/*Reads one of Ken Johnson's big files and generates a bunch 'o fields*/
{
    char mapDate[20], mapTime[20];
    char anType[2];
    int maxRadar;
    float xg, yg, z0;
    float dx, dy, dz;
    int lx, ly, lz;
    ObjPtr dataForm;			/*The grid holding the data*/
    ObjPtr boundsArray;			/*Array containing bounds of grid*/
    ObjPtr dimsArray;			/*Array containing dimensions of the data*/
    ObjPtr fieldData[NKJFIELDS];	/*The array of data in the field*/
    real dims[3];			/*The dimensions of the data, temp.*/
    real bounds[6];			/*The bounds of the data form*/
    real *dataPtr[NKJFIELDS];		/*The meat of the array*/
    int i, j, k;			/*Index into the grid*/
    ObjPtr field;			/*One field to return*/
    FILE *inFile;
    int whichField;			/*Which field we're reading*/

    inFile = fopen(name, "r");
    if (!inFile)
    {
	Error("ReadKJ3File", OPENFILEERROR, name);
	return NULLOBJ;
    }

    /*Read header line*/
    if (fscanf(inFile, "%s %s %1s %d %g %g %g %g %g %g %d %d %d",
		mapDate, mapTime, anType, &maxRadar, &xg, &yg, &z0,
		&dx, &dy, &dz, &lx, &ly, &lz)
	!= 13)
    {
	FileFormatError("ReadKJ3File", "Error reading header");
    }
    /*Get over the rest of the line*/
    ReadLn(inFile);

    /*Create the data form*/
    dataForm = NewObject(dataFormClass, 0);
    dimsArray = NewRealArray(1, (long) 3);
    
    /*Put in some dimensions*/
    dims[0] = (real) lx;
    dims[1] = (real) ly;
    dims[2] = (real) lz;
    CArray2Array(dimsArray, dims);
    SetVar(dataForm, DIMENSIONS, dimsArray); 

    /*Put in the bounds*/
    bounds[0] = xg;
    bounds[1] = xg + (lx - 1) * dx;
    bounds[2] = yg;
    bounds[3] = yg + (ly - 1) * dy;
    bounds[4] = 3.255 + z0;
    bounds[5] = 3.255 + z0 + (lz - 1) * dz;
    boundsArray = NewRealArray(1, (long) 6);
    CArray2Array(boundsArray, bounds);
    SetVar(dataForm, BOUNDS, boundsArray);

    /*Create the fields*/
    for (whichField = 0; whichField < NKJFIELDS; ++whichField)
    {
	fieldData[whichField] = NewRealArray(3, (long) lx, (long) ly, (long) lz);
	dataPtr[whichField] = ArrayMeat(fieldData[whichField]);
    }

    for (k = 0; k < lz; ++k)
    {
	for (whichField = 0; whichField < NKJFIELDS; ++whichField)
	{
	    for (j = 0; j < ly; ++j)
	    {
		for (i = 0; i < lx; ++i)
		{
		    real curVal;
		    if (1 != fscanf(inFile, "%g", &curVal))
		    {
			FileFormatError("ReadKJ3File", "Error reading data");
			fclose(inFile);
			return NULLOBJ;
		    }
		    *(dataPtr[whichField] + i * ly * lz + j * lz + k) = (curVal == 999.0) ? missingData : curVal;
		}
	    }
	}
    }

    for (whichField = 0; whichField < NKJFIELDS; ++whichField)
    {
	/*Create the field*/
	field = NewObject(data3DScalar, 0);
	SetVar(field, DATA, fieldData[whichField]);
	SetVar(field, DATAFORM, dataForm);
	strncpy(tempStr, ShortNameOf(name), TEMPSTRSIZE - 2);
	tempStr[TEMPSTRSIZE - 2] = 0;	
	strcat(tempStr, " ");
	strncat(tempStr, kjIndField[whichField], TEMPSTRSIZE - strlen(tempStr));
	tempStr[TEMPSTRSIZE] = 0;
	SetVar(field, NAME, NewString(tempStr));
	RegisterDataset(field);
    }

    fclose(inFile);
    return NULLOBJ;
}

static ObjPtr ReadKJ4File(name)
char *name;
/*Reads one of Ken Johnson's big time-dependent files and generates a 
  bunch 'o fields*/
{
    char mapDate[20];
    int mapTime;
    char anType[2];
    int maxRadar;
    float xg, yg, z0;
    float dx, dy, dz;
    int lx, ly, lz;
    ObjPtr dataForm;			/*The grid holding the data*/
    ObjPtr boundsArray;			/*Array containing bounds of grid*/
    ObjPtr dimsArray;			/*Array containing dimensions of the data*/
    ObjPtr fieldData[NKJFIELDS];	/*The array of data in the field*/
    real dims[3];			/*The dimensions of the data, temp.*/
    real bounds[6];			/*The bounds of the data form*/
    real *dataPtr[NKJFIELDS];		/*The meat of the array*/
    int i, j, k;			/*Index into the grid*/
    ObjPtr field;			/*One field to return*/
    FILE *inFile;
    int whichField;			/*Which field we're reading*/
    ObjPtr timeList;			/*List of times*/
    ObjPtr timeData[NKJFIELDS];		/*Data in fields over time*/
    ObjPtr timeBounds;			/*Bounds of data over time*/
    real cookedTime;			/*Cooked time in decimal format*/
    ObjPtr timedObj;			/*Timed object*/
    int wholePart;

    inFile = fopen(name, "r");
    if (!inFile)
    {
	Error("ReadKJ4File", OPENFILEERROR, name);
	return NULLOBJ;
    }

    /*Set up the lists*/
    timeList = NewList();
    timeBounds = NewList();
    for (k = 0; k < NKJFIELDS; ++k)
    {
	timeData[k] = NewList();
    }

    while (fscanf(inFile, "%s %d %1s %d %g %g %g %g %g %g %d %d %d",
		    mapDate, &mapTime, anType, &maxRadar, &xg, &yg, &z0,
		    &dx, &dy, &dz, &lx, &ly, &lz)
	    == 13)

    {
	/*Get over the rest of the line*/
	ReadLn(inFile);

	wholePart = mapTime / 10000;
	cookedTime = wholePart + ((((float) mapTime) / 10000.0) - (float) wholePart) / 0.6;

	PostfixList(timeList, NewReal(cookedTime));
	

	/*Create the data form*/
	dataForm = NewObject(dataFormClass, 0);
	dimsArray = NewRealArray(1, (long) 3);
	
	/*Put in some dimensions*/
	dims[0] = (real) lx;
	dims[1] = (real) ly;
	dims[2] = (real) lz;
	CArray2Array(dimsArray, dims);
	SetVar(dataForm, DIMENSIONS, dimsArray); 

	/*Put in the bounds*/
	bounds[0] = xg;
	bounds[1] = xg + (lx - 1) * dx;
	bounds[2] = yg;
	bounds[3] = yg + (ly - 1) * dy;
	bounds[4] = 3.255 + z0;
	bounds[5] = 3.255 + z0 + (lz - 1) * dz;
	boundsArray = NewRealArray(1, (long) 6);
	CArray2Array(boundsArray, bounds);
	PostfixList(timeBounds, boundsArray);

	/*Create the fields*/
	for (whichField = 0; whichField < NKJFIELDS; ++whichField)
	{
	    fieldData[whichField] = NewRealArray(3, (long) lx, (long) ly, (long) lz);
	    dataPtr[whichField] = ArrayMeat(fieldData[whichField]);
	}

	for (k = 0; k < lz; ++k)
	{
	    for (whichField = 0; whichField < NKJFIELDS; ++whichField)
	    {
		for (j = 0; j < ly; ++j)
		{
		    for (i = 0; i < lx; ++i)
		    {
			real curVal;
			if (1 != fscanf(inFile, "%g", &curVal))
			{
			    FileFormatError("ReadKJ4Data", "Error reading data.");
			    fclose(inFile);
			    return NULLOBJ;
			}
			*(dataPtr[whichField] + i * ly * lz + j * lz + k) = (curVal == 999.0) ? missingData : curVal;
		    }
		}
	    }
	}
	
	for (whichField = 0; whichField < NKJFIELDS; ++whichField)
	{
	    PostfixList(timeData[whichField], fieldData[whichField]);
	}
    }

    /*Set the timed bounds of the object*/
    timedObj = NewTimedObject(timeList, timeBounds);
    SetVar(dataForm, BOUNDS, timedObj);

    for (whichField = 0; whichField < NKJFIELDS; ++whichField)
    {
	/*Create the field*/
	field = NewObject(data3DScalar, 0);
	timedObj = NewTimedObject(timeList, timeData[whichField]);
	SetVar(field, DATA, timedObj);
	SetVar(field, DATAFORM, dataForm);
	strncpy(tempStr, ShortNameOf(name), TEMPSTRSIZE - 2);
	tempStr[TEMPSTRSIZE - 2] = 0;
	strcat(tempStr, " ");
	strncat(tempStr, kjIndField[whichField], TEMPSTRSIZE - strlen(tempStr));
	SetVar(field, NAME, NewString(tempStr));
	RegisterDataset(field);
   }

    fclose(inFile);
    return NULLOBJ;
}


static ObjPtr ReadKJ2File(name)
char *name;
/*Reads one of Ken Johnson's terrain fields from file inFile*/
{
    float xg = -16.5, yg = -16.5 - 3.25;
    float dx = 0.75, dy = 0.75;
    float zMin = 1E20, zMax = -1E20;	/*Min and max Z*/
    int lx = 45, ly = 45;
    ObjPtr dataForm;			/*The grid holding the data*/
    ObjPtr boundsArray;			/*Array containing bounds of grid*/
    ObjPtr dimsArray;			/*Array containing dimensions of the data*/
    ObjPtr fieldData;			/*The array of data in the field*/
    real dims[2];			/*The dimensions of the data, temp.*/
    long lDims[2];			/*Long dimensions*/
    real bounds[6];			/*The bounds of the data form*/
    real *dataPtr;			/*The meat of the array*/
    int i, j, k;			/*Index into the grid*/
    ObjPtr retVal;			/*The field to return*/
    FILE *inFile;

    inFile = fopen(name, "r");
    if (!inFile)
    {
	Error("ReadKJ2File", OPENFILEERROR, name);
	return NULLOBJ;
    }

    /*Read the data*/
    lDims[0] = lx;
    lDims[1] = ly;
    fieldData = NewArray(AT_REAL, 2, lDims);
    dataPtr = ArrayMeat(fieldData);

	for (j = 0; j < ly; ++j)
	{
	    for (i = 0; i < lx; ++i)
	    {
		real curVal;
		if (1 != fscanf(inFile, "%g", &curVal))
		{
		    FileFormatError("ReadKJ2File", "Error reading data");
		    fclose(inFile);
		    return NULLOBJ;
		}
		curVal /= 1000.0;	/*Meters to km*/
		if (curVal > zMax) zMax = curVal;
		if (curVal < zMin) zMin = curVal;
		*(dataPtr + i * ly + j) = curVal;
	    }
	}

    /*Create the data form*/
    dataForm = NewObject(dataFormClass, 0);
    dimsArray = NewRealArray(1, (long) 2);
    
    /*Put in some dimensions*/
    dims[0] = (real) lx;
    dims[1] = (real) ly;
    CArray2Array(dimsArray, dims);
    SetVar(dataForm, DIMENSIONS, dimsArray); 

    /*Put in the bounds*/
    bounds[0] = xg;
    bounds[1] = xg + (lx - 1) * dx;
    bounds[2] = yg;
    bounds[3] = yg + (ly - 1) * dy;
    bounds[4] = zMin;
    bounds[5] = zMax;
    boundsArray = NewRealArray(1, (long) 6);
    CArray2Array(boundsArray, bounds);
    SetVar(dataForm, BOUNDS, boundsArray);

    /*Create the field*/
    retVal = NewObject(data2DScalar, 0);
    SetVar(retVal, DATA, fieldData);
    SetVar(retVal, DATAFORM, dataForm);
    SetVar(retVal, NAME, MakeDatasetName(name));

    fclose(inFile);
    RegisterDataset(retVal);
    return NULLOBJ;
}

static ObjPtr ReadKJ5File(name)
char *name;
/*Reads one of Ken Johnson's terrain fields from file inFile*/
{
    float xg = -16.5, yg = -16.5 - 3.25;
    float dx = 1.0, dy = 1.0;
    float zMin = 1E20, zMax = -1E20;	/*Min and max Z*/
    int lx = 30, ly = 30;
    ObjPtr dataForm;			/*The grid holding the data*/
    ObjPtr boundsArray;			/*Array containing bounds of grid*/
    ObjPtr dimsArray;			/*Array containing dimensions of the data*/
    ObjPtr fieldData;			/*The array of data in the field*/
    real dims[2];			/*The dimensions of the data, temp.*/
    long lDims[2];			/*Long dimensions*/
    real bounds[6];			/*The bounds of the data form*/
    real *dataPtr;			/*The meat of the array*/
    int i, j, k;			/*Index into the grid*/
    ObjPtr retVal;			/*The field to return*/
    FILE *inFile;

    inFile = fopen(name, "r");
    if (!inFile)
    {
	Error("ReadKJ2File", OPENFILEERROR, name);
	return NULLOBJ;
    }

    /*Read the data*/
    lDims[0] = lx;
    lDims[1] = ly;
    fieldData = NewArray(AT_REAL, 2, lDims);
    dataPtr = ArrayMeat(fieldData);

	for (j = 0; j < ly; ++j)
	{
	    for (i = 0; i < lx; ++i)
	    {
		real curVal;
		if (1 != fscanf(inFile, "%g", &curVal))
		{
		    FileFormatError("ReadKJ2File", "Error reading data");
		    fclose(inFile);
		    return NULLOBJ;
		}
		curVal /= 1000.0;	/*Meters to km*/
		if (curVal > zMax) zMax = curVal;
		if (curVal < zMin) zMin = curVal;
		*(dataPtr + i * ly + j) = curVal;
	    }
	}

    /*Create the data form*/
    dataForm = NewObject(dataFormClass, 0);
    dimsArray = NewRealArray(1, (long) 2);
    
    /*Put in some dimensions*/
    dims[0] = (real) lx;
    dims[1] = (real) ly;
    CArray2Array(dimsArray, dims);
    SetVar(dataForm, DIMENSIONS, dimsArray); 

    /*Put in the bounds*/
    bounds[0] = xg;
    bounds[1] = xg + (lx - 1) * dx;
    bounds[2] = yg;
    bounds[3] = yg + (ly - 1) * dy;
    bounds[4] = zMin;
    bounds[5] = zMax;
    boundsArray = NewRealArray(1, (long) 6);
    CArray2Array(boundsArray, bounds);
    SetVar(dataForm, BOUNDS, boundsArray);

    /*Create the field*/
    retVal = NewObject(data2DScalar, 0);
    SetVar(retVal, DATA, fieldData);
    SetVar(retVal, DATAFORM, dataForm);
    SetVar(retVal, NAME, MakeDatasetName(name));

    fclose(inFile);
    RegisterDataset(retVal);
    return NULLOBJ;
}

#ifdef LORENZ
#define LRZNMAX 10

#ifdef FORTRAN_
extern void odeint_();
#else
extern void odeint();
#endif

static ObjPtr ReadLRZFile(name)
char *name;
/*Reads a Lorenz attractor initial value file*/
{
    float y[LRZNMAX];		/*3 initial values*/
    float dydx[LRZNMAX];
    int nstep, nskip;
    int nvar;
    float xstart;
    float eps, stpmin, stpsize, sig, b, r;
    real *dataPtr;
    ObjPtr theData, theClass, lrzObj;
    FILE *inFile;

    inFile = fopen(name, "r");
    if (!inFile)
    {
	Error("ReadLRZFile", OPENFILEERROR, name);
	return NULLOBJ;
    }

    /*Read the file*/
    if (11 != fscanf(inFile, " %f %f %f %f %d %d %f %f %f %f %f",
		&(y[0]), &(y[1]), &(y[2]), &stpsize, &nstep,
		&nskip, &eps, &stpmin, &sig, &b, &r))
    {
	FileFormatError("ReadLRZFile", "Cannot read parameter file");
	fclose(inFile);
	return NULLOBJ;
    }

    /*Now we know how big it is, make some data*/
    theData = NewRealArray(2, (long) nstep, (long) LRZNMAX);
    if (!theData)
    {
	fclose(inFile);
        return NULLOBJ;
    }
    dataPtr = ArrayMeat(theData);

    nvar = 3;
    xstart = 0.0;
#ifdef FORTRAN_ 
    odeint_
#else
    odeint
#endif
	(y, &nvar, &xstart, &nskip, &nstep, dataPtr,
	    &eps, &stpsize, &stpmin, &sig, &b, &r);

    /*Now create the data object*/
    theClass = NewObject(data1DVector, 0);
    lrzObj = NewObject(theClass, 0);
    SetVar(lrzObj, DATA, theData);
    SetVar(lrzObj, NAME, MakeDatasetName(name));

    fclose(inFile);
    RegisterDataset(lrzObj);
    return NULLOBJ;
}
#endif

#if 0
static ObjPtr ReadDDFile(name)
char *name;
/*Reads a Dennis Duke format file*/
{
    int idim, jdim;
    int c, k;
    real *dataPtr;
    ObjPtr theData, theClass, eegData;
    FILE *inFile;

    inFile = fopen(name, "r");
    if (!inFile)
    {
	Error("ReadDDFile", OPENFILEERROR, name);
	return NULLOBJ;
    }

    /*First determine idim and jdim*/
    idim = 0; jdim = 0;

    SkipBlanks(inFile);
    while ((c = getc(inFile)) >= 0)
    {
        ungetc(c, inFile);
        ++jdim;
        k = 0;
        while ((c = getc(inFile)) >= 0 && c != '\n')
        {
            ungetc(c, inFile);
            SkipNonBlanks(inFile);
            SkipBlanks(inFile);
            ++k;
        }
        if (idim > 0)
        {
            if (k != idim)
            {
		char err[200];
                sprintf(err,
                    "Error in %s line %d: bad number of items\n",
                    name, jdim);
		fclose(inFile);
		FileFormatError("ReadDDFile", err);
		return NULLOBJ;
            }
            else
            {
                idim = k;
            }
        }
        else
        {
            idim = k;
        }
        getc(inFile);
        SkipBlanks(inFile);
    }

    /*Now we know how big it is, make some data*/
    theData = NewRealArray(2, (long) jdim, (long) idim);
    if (!theData)
    {
	fclose(inFile);
        return NULLOBJ;
    }
    dataPtr = ArrayMeat(theData);

    /*Read in the data*/
    rewind(inFile);
    SkipBlanks(inFile);
    while ((c = getc(inFile)) >= 0)
    {
        ungetc(c, inFile);
        k = 0;
        while ((c = getc(inFile)) >= 0 && c != '\n')
        {
            ungetc(c, inFile);
            if (1 != fscanf(inFile, "%g", dataPtr))
	    {
		FileFormatError("ReadDDFile", "Bad number");
		fclose(inFile);
		return NULLOBJ;
	    }
	    ++dataPtr;
            SkipBlanksAndCommas(inFile);
        }
        getc(inFile);
        SkipBlanksAndCommas(inFile);
    }

    /*Now create the data object*/
    theClass = NewObject(data1DVector, 0);
    eegData = NewObject(theClass, 0);
    SetVar(eegData, DATA, theData);
    SetVar(eegData, NAME, MakeDatasetName(name));

    fclose(inFile);
    RegisterDataset(eegData);
    return NULLOBJ;
}
#else
static ObjPtr ReadDDFile(name)
char *name;
/*Reads a Dennis Duke format file*/
{
    long idim, jdim;
    int c, k;
    ObjPtr theData, theClass, eegData;
    FILE *inFile;
    long index[1];

    inFile = fopen(name, "r");
    if (!inFile)
    {
	Error("ReadDDFile", OPENFILEERROR, name);
	return NULLOBJ;
    }

    /*First determine idim and jdim*/
    idim = 0; jdim = 0;

    SkipBlanks(inFile);
    while ((c = getc(inFile)) >= 0)
    {
        ungetc(c, inFile);
        ++jdim;
        k = 0;
        while ((c = getc(inFile)) >= 0 && c != '\n')
        {
            ungetc(c, inFile);
            SkipNonBlanks(inFile);
            SkipBlanks(inFile);
            ++k;
        }
        if (idim > 0)
        {
            if (k != idim)
            {
		char err[200];
                sprintf(err,
                    "Error in %s line %d: bad number of items\n",
                    name, jdim);
		FileFormatError("ReadDDFile", err);
		fclose(inFile);
		return NULLOBJ;
            }
            else
            {
                idim = k;
            }
        }
        else
        {
            idim = k;
        }
        getc(inFile);
        SkipBlanks(inFile);
    }

    /*Now we know how big it is, make some data*/
    theData = NewArray(AT_OBJECT, 1, &idim);
    for (k = 0; k < idim; ++k)
    {
	((ObjPtr *) ELEMENTS(theData))[k] = NewRealArray(1, (long) jdim);
    }

    /*Now create the data object*/
    theClass = NewObject(data1DVector, 0);
    eegData = NewObject(theClass, 0);
    SetVar(eegData, DATA, theData);
    SetVar(eegData, NAME, MakeDatasetName(name));

    if (!SetCurField(FIELD1, eegData)) return NULLOBJ;

    /*Read in the data*/
    rewind(inFile);
    SkipBlanks(inFile);

    index[0] = 0;
    while ((c = getc(inFile)) >= 0)
    {
        ungetc(c, inFile);
        k = 0;
        while ((c = getc(inFile)) >= 0 && c != '\n')
        {
	    real data;
            ungetc(c, inFile);
            if (1 != fscanf(inFile, "%g", &data))
	    {
		FileFormatError("ReadDDFile", "Bad number");
		fclose(inFile);
		return NULLOBJ;
	    }
	    PutFieldComponent(FIELD1, k, index, data);

	    ++k;
	    if (k >= idim)
	    {
		k = 0;
		++index[0];
	    }
            SkipBlanksAndCommas(inFile);
        }
        getc(inFile);
        SkipBlanksAndCommas(inFile);
    }

    fclose(inFile);
    SetVar(eegData, NCOMPONENTS, NewInt(idim));
    RegisterDataset(eegData);
    return NULLOBJ;
}
#endif

static ObjPtr brainForm = 0;
long numNodes; 			/*Number of nodes in brain form*/

/*States for data form reading machine*/
#define S_READNODES	1
#define S_READEDGES	2
#define S_READCELLS	3
#define S_READPOLATIONS 4

#define DD2SECS		8.0
#define DD2SAMPLES	1024
#define DD2POINTS	19

#define NPOLATIONS	100
int pDerived[NPOLATIONS];
int pNear[NPOLATIONS];
int pFar[NPOLATIONS];
real pFac[NPOLATIONS];
int nPolations = 0;

static ObjPtr ReadDD2File(name)
char *name;
/*Reads a brain surface EEG file*/
{
    ObjPtr retVal;
    ObjPtr timeSteps;
    ObjPtr timeData;
    FILE *inFile;
    int sample;
    int k;
    real *data, dummy;
    real minMax[2];
    ObjPtr minMaxArray;

    if (!brainForm)
    {
	/*Must make the brain data form*/
	threeArray *nodeBuf;
	long nodeBufSize;
	twoArray *edgeBuf;
	long edgeBufSize;
	long numEdges;
	ObjPtr cellList;
	ObjPtr nodeArray;
	ObjPtr edgeArray;
	int state;
	char line[257];
	char token[257];
	char *s;
	real val;
	int lineNum;
	char pTypeChar;

	/*Open the file*/
	lineNum = 0;
	state = 0;
	inFile = fopen("brainform", "r");
	if (!inFile)
	{
	    FileFormatError("ReadDD2File", "File brainform was not found");
	    return NULLOBJ;
	}

	/*Create the buffers.  First the nodes*/
	numNodes = 0;
	nodeBufSize = 1000;
	nodeBuf = (threeArray *) malloc(nodeBufSize * 3 * sizeof(real));
	if (!nodeBuf)
	{
	    OMErr();
	    return NULLOBJ;
	}

	/*Then the edges*/
	numEdges = 0;
	edgeBufSize = 1000;
	edgeBuf = (twoArray *) malloc(edgeBufSize * 2 * sizeof(real));
	if (!edgeBuf)
	{
	    OMErr();
	    free(nodeBuf);
	    return NULLOBJ;
	}

	/*Now the cells*/
	cellList = NewList();
	if (!cellList)
	{
	    free(edgeBuf);
	    free(nodeBuf);
	    return NULLOBJ;
	}
	
	/*Make the brain form*/
	brainForm = NewObject(dataFormClass, 0);

	/*Now read the file*/
	while (++lineNum, fgets(line, 256, inFile))
	{
	    s = &(line[0]);

	    /*Get the first token*/
	    SHIFTNUM(token, s);
	    if (0 == strcmp2(token, "NODES"))
	    {
		state = S_READNODES;
	    }
	    else if (0 == strcmp2(token, "EDGES"))
	    {
		state = S_READEDGES;
	    }
	    else if (0 == strcmp2(token, "CELLS"))
	    {
		state = S_READCELLS;
	    }
	    else if (0 == strcmp2(token, "POLATIONS"))
	    {
		state = S_READPOLATIONS;
	    }
	    else if (1 == sscanf(token, "%g", &val))
	    {
		/*It's a number.  Do something based on the state*/
		switch(state)
		{
		    case S_READNODES:
			/*It must be the x of a node*/
			{
			    real x, y, z;
			    if (numNodes > nodeBufSize)
			    {
				/*Must expand the node buffer*/	
				nodeBufSize += 200;	
				nodeBuf = (threeArray *) realloc(nodeBuf, nodeBufSize * sizeof(threeArray));
				if (!nodeBuf)
				{
				    OMErr();	
				    free(edgeBuf);
				    return NULLOBJ;
				}
			    }
			    x = val;
			    SHIFTNUM(token, s);
			    if (1 != sscanf(token, "%g", &y))
			    {
				char err[200];
				sprintf(err, "Error in line %d of brainform: Missing y\n", lineNum);
				FileFormatError("ReadDD2File", err);
				break;
			    }
			    SHIFTNUM(token, s);
			    if (1 != sscanf(token, "%g", &z))
			    {
				char err[200];
				sprintf(err, "Error in line %d of brainform: Missing z\n", lineNum);
				FileFormatError("ReadDD2File", err);
				break;
			    }
			    nodeBuf[numNodes][0] = x;
			    nodeBuf[numNodes][1] = y;
			    nodeBuf[numNodes][2] = z;
			    ++numNodes;
			}
			break;
		    case S_READEDGES:
			/*It must be the first node of an edge*/
			{
			    real n1, n2;
			    if (numEdges > edgeBufSize)
			    {
				/*Must expand the node buffer*/	
				edgeBufSize += 200;	
				edgeBuf = (twoArray *) realloc(edgeBuf, edgeBufSize * sizeof(twoArray));
				if (!nodeBuf)
				{
				    OMErr();	
				    free(nodeBuf);
				    return NULLOBJ;
				}
			    }
			    n1 = val;
			    SHIFTNUM(token, s);
			    if (1 != sscanf(token, "%g", &n2))
			    {
				char err[200];
				sprintf(err, "Error in line %d of brainform: Missing second node\n", lineNum);
				FileFormatError("ReadDD2File", err);
				break;
			    }
			    edgeBuf[numEdges][0] = n1;
			    edgeBuf[numEdges][1] = n2;
			    ++numEdges;
			}
			break;
		    case S_READCELLS:
			/*It must be the first node of a cell*/
			{
			    real cellBuf[600];
			    ObjPtr cellArray;
			    long c;
			    c = 0;
			    do
			    {
				cellBuf[c++] = val;
				SHIFTNUM(token, s);
			    } while (1 == sscanf(token, "%g", &val)); 
			    cellArray = NewRealArray(1, c);
			    CArray2Array(cellArray, cellBuf);
			    PostfixList(cellList, cellArray);
			}
			break;
		    default:
			FileFormatError("ReadDD2File", "Error in brainform");
		}
	    }
	    else if (1 == sscanf(token, "%c", &pTypeChar))
	    {
		switch (state)
		{
		    case S_READPOLATIONS:
			SHIFTNUM(token, s);
	 		if (1 != sscanf(token, "%d", &(pDerived[nPolations])))
			{
			    FileFormatError("ReadDD2File", "Error in brainform");
			    break;
			}
			SHIFTNUM(token, s);
	 		if (1 != sscanf(token, "%d", &(pNear[nPolations])))
			{
			    FileFormatError("ReadDD2File", "Error in brainform");
			    break;
			}
			SHIFTNUM(token, s);
	 		if (1 != sscanf(token, "%d", &(pFar[nPolations])))
			{
			    FileFormatError("ReadDD2File", "Error in brainform");
			    break;
			}
			/*Calculate multiplying factor*/
			{
			    int n, f, d;
			    float d1, d2;
			    n = pNear[nPolations];
			    f = pFar[nPolations];
			    d = pDerived[nPolations];

			    d1 = sqrt(SQUARE(nodeBuf[f][0] - nodeBuf[n][0]) +
				      SQUARE(nodeBuf[f][1] - nodeBuf[n][1]) +
				      SQUARE(nodeBuf[f][2] - nodeBuf[n][2]));
			    d2 = sqrt(SQUARE(nodeBuf[d][0] - nodeBuf[n][0]) +
				      SQUARE(nodeBuf[d][1] - nodeBuf[n][1]) +
				      SQUARE(nodeBuf[d][2] - nodeBuf[n][2]));
			    if (pTypeChar == 'e' || pTypeChar == 'E')
			    {
				pFac[nPolations] = - d2 / d1;
			    }
			    else
			    {
				pFac[nPolations] = d2 / d1;
			    }
			}
			++nPolations;
			break;
		    default:
			FileFormatError("ReadDD2File", "Error in brainform");
		}
	    }
	    else
	    {
		FileFormatError("ReadDD2File", "Error in brainform");
	    }
	}
	fclose(inFile);

	/*Everything's been read.  Fill the data form*/
	nodeArray = NewRealArray(2, numNodes, 3L);
	if (!nodeArray)
	{
	    free(nodeBuf);
	    free(edgeBuf);
	    return NULLOBJ;
	}
	CArray2Array(nodeArray, nodeBuf);
	SetVar(brainForm, NODES, nodeArray);

	edgeArray = NewRealArray(2, numEdges, 2L);
	if (!edgeArray)
	{
	    free(nodeBuf);
	    free(edgeBuf);
	    return NULLOBJ;
	}
	CArray2Array(edgeArray, edgeBuf);
	SetVar(brainForm, EDGES, edgeArray);
	SetVar(brainForm, CELLS, cellList);
	free(nodeBuf);
	free(edgeBuf);
    }

    /*Get ready to read*/
    inFile = fopen(name, "r");
    if (!inFile)
    {
	Error("ReadDD2File", OPENFILEERROR, name);
	return NULLOBJ;
    }
    timeSteps = NewList();
    timeData = NewList();

    data = (real *) malloc(sizeof(real) * numNodes);

    for (sample = 0; sample < DD2SAMPLES; ++sample)
    {
	ObjPtr sampleArray;
	if (21 != fscanf(inFile, " %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g",
		&data[0],
		&dummy,
		&data[1],
		&data[2],
		&data[3],
		&data[4],
		&data[5],
		&data[6],
		&data[7],
		&data[8],
		&data[9],
		&data[10],
		&data[11],
		&data[12],
		&data[13],
		&data[14],
		&data[15],
		&data[16],
		&data[17],
		&dummy,
		&data[18]
	    ))
	{
	    
	    FileFormatError("ReadDD2File", "Not enough data", name);
	    fclose(inFile);
	    return NULLOBJ;
	}

	/*Fill in the polated data*/
        for (k = 0; k < nPolations; ++k)
	{
	    data[pDerived[k]] = data[pNear[k]] + 
		(data[pFar[k]] - data[pNear[k]]) * pFac[k];
	}

	sampleArray = NewRealArray(1, (long) numNodes);
	CArray2Array(sampleArray, data);
	PostfixList(timeData, sampleArray);
	PostfixList(timeSteps, NewReal(DD2SECS * ((real) sample) / ((real) DD2SAMPLES)));
    }

    free(data);
    fclose(inFile);

    retVal = NewObject(data3DUnstructSurface, 0);
    SetVar(retVal, DATA, NewTimedObject(timeSteps, timeData));
    SetVar(retVal, DATAFORM, brainForm);
    SetVar(brainForm, UNSTRUCTURED, ObjTrue);
    SetVar(retVal, NAME, MakeDatasetName(name));
    minMax[0] = -60.0;
    minMax[1] = 60.0;
    minMaxArray = NewRealArray(1, 2L);
    CArray2Array(minMaxArray, minMax);
    SetVar(retVal, MINMAX, minMaxArray);

    RegisterDataset(retVal);
    return NULLOBJ;
}

#define MAX_RANK 1024

#ifdef HDFDEF
ObjPtr ReadHDFDFile(reader, fileName)
ObjPtr reader;
char *fileName;
/*Reads an HDF scientific data set file.*/
{
    int nDataSets;		/*Number of data sets*/
    int whichSet;	/*Number of current data set*/
    char dimsLabel[256], dimsUnit[256], dimsFormat[256];
    ObjPtr outOfBoundsVar;
    int outOfBoundsAction;

#ifdef DEBUG
    printf("ReadHDFDFile: HDF filename = %s\n", fileName);
#endif

    nDataSets = DFSDnumber(fileName);

    if (nDataSets == -1)
    {
	char errMes[255];
	sprintf(errMes, "Cannot read HDF file %s.  The file is either missing or empty.\n", fileName);
        FileFormatError("ReadHDFDFile", errMes);
        return NULLOBJ;
    }

    
#ifdef DEBUG
    printf("ReadHDFDFile: nDataSets = %d\n", nDataSets);
#endif

    if (nDataSets == 0)
    {
        FileFormatError("ReadHDFDFile", "No datasets to read.");
        return NULLOBJ;
    }

    if ((outOfBoundsVar = GetIntVar("ReadHDFDFile", reader, OUTOFBOUNDS)) == NULLOBJ)
        outOfBoundsAction = 0;
    else
        outOfBoundsAction = GetInt(outOfBoundsVar);

    for (whichSet = 0; whichSet < nDataSets; ++whichSet)
    {
        int rank;
        int k;
        int dimSizes[MAX_RANK];
        long arraySize;			/*Total size of the array*/
        float min = PLUSINF, max = MINUSINF;
        real intMissing = missingData;		/*Internal missing data*/
        ObjPtr curField;
	Bool minMaxSet = false;
	Bool readVector = false;

        /*Start off with null field*/
        curField = 0;

        /*Get dimensions of data set*/

        if (-1 == DFSDgetdims(fileName, &rank, dimSizes, MAX_RANK))
        {
            FileFormatError("ReadHDFDFile", "Unable to get dimensions.");
            return NULLOBJ;
        }

#ifdef DEBUG
        {
            int i;

            printf("ReadHDFDFile: rank = %d\n", rank);
            for (i = 0; i < rank; ++i)
                printf("ReadHDFDFile: dimSizes[%d] = %d\n", i, dimSizes[i]);
        }
#endif

        /*See if there's a min and max*/
        if (0 == DFSDgetmaxmin(&max, &min))
        {
#ifdef DEBUG
    printf("ReadHDFDFile: max = %f, min = %f\n", max, min);
#endif
	    minMaxSet = true;
        }
        else
        {
#ifdef DEBUG
    printf("ReadHDFDFile: No min and max\n");
#endif
            min = MINUSINF; 
            max = PLUSINF;
	    minMaxSet = false;
        }

	readVector = GetPredicate(reader, READVECTOR);

        {
	    /*It's just a scalar field*/
            long *dims_L;
            real *dims;
            real *bounds;
            ObjPtr dataForm;
            ObjPtr dimsArray;
            ObjPtr fieldData;
            ObjPtr boundsArray;
            ObjPtr *scales;
            char label[256];
            char *s;		/*Temporary string pointer*/
            char dummy[256];
            real *dataMeat;
            ObjPtr vectorDataset, vectorField, *elements;
            long temp_long;
            ObjPtr indices;

            /*Make data form*/
            dataForm = NewObject(dataFormClass, 0);

            if (!(dims_L = malloc(sizeof(long) * rank)))
            {
                FileFormatError("ReadHDFDFile", "Can't allocate memory.");
                return NULLOBJ;
            }

            if (!(dims = malloc(sizeof(real) * rank)))
            {
                free(dims_L);
                FileFormatError("ReadHDFDFile", "Can't allocate memory.");
                return NULLOBJ;
            }

            if (!(bounds = malloc(sizeof(real) * rank * 2)))
            {
		free(dims);
                free(dims_L);
                FileFormatError("ReadHDFDFile", "Can't allocate memory.");
                return NULLOBJ;
            }

            if (!(scales = malloc(sizeof(ObjPtr) * rank)))
            {
                free(bounds);
		free(dims);
                free(dims_L);
                FileFormatError("ReadHDFDFile", "Can't allocate memory.");
                return NULLOBJ;
            }
		
            /*Find bounds for the file*/

            for (k = 0; k < rank; ++k)
            {
		if (DFSDgetdimstrs(k + 1, dimsLabel, dimsUnit, dimsFormat) != -1)
                {
#ifdef DEBUG
    printf("ReadHDFDFile: dimsLabel = %s, DimsUnit = %s, dimsFormat = %s\n", dimsLabel, dimsUnit, dimsFormat);
#endif
                }
                scales[k] = NewRealArray(1, (long) dimSizes[k]);

                if (DFSDgetdimscale(k + 1, dimSizes[k], ArrayMeat(scales[k])) != -1 &&
			*ArrayMeat(scales[k]) != *(ArrayMeat(scales[k]) + dimSizes[k] - 1))
                {
                    bounds[k * 2] = *ArrayMeat(scales[k]);
                    bounds[(k * 2) + 1] = *(ArrayMeat(scales[k]) + dimSizes[k] - 1);
                }
                else
                {
                    printf("ReadHDFFile: Guessing scale %d from %d to %d\n", k, 0, dimSizes[k] - 1);
                    bounds[k * 2] = 0.0;
                    bounds[(k * 2) + 1] = ((real) dimSizes[k]) - 1.0;

                    {
                        /*EMP fill in the scale*/
                        int i;
                        real *elements;
                        elements = ELEMENTS(scales[k]);
                        for (i = 0; i < dimSizes[k]; ++i)
                        {
                            elements[i] = (real) i;
                        }
                    }
                }
#ifdef DEBUG
                {
                    int i;
                    real *elements;

                    elements = ELEMENTS(scales[k]);

                    for (i = 0; i < dimSizes[k]; ++i)
                        printf("ReadHDFDFile: elements[%d][%d] = %f\n", k, i, elements[i]);
                }

    printf("ReadHDFDFile: lower bound = %f, upper bound = %f\n", bounds[k * 2], bounds[(k * 2) + 1]);
#endif
            }

	    /*See if it's a vector dataset or not*/
	    if (readVector &&
		(dimSizes[0] == 2 || dimSizes[0] == 3))
	    {
		long nComponents;
		float *tempData;
		long size;
		ObjPtr *elements;
		/*It's a vector dataset, all right*/

		/*Make DIMENSIONS (convert from int to long to real in the process)*/

		dimsArray = NewRealArray(1, (long) (rank - 1));
		for (k = 0; k < rank; ++k)
                    dims[k] = dims_L[k] = dimSizes[k];
		CArray2Array(dimsArray, dims + 1);
		SetVar(dataForm, DIMENSIONS, dimsArray);

		nComponents = dimSizes[0];

		boundsArray = NewRealArray(1, (long) ((rank - 1) * 2));
		CArray2Array(boundsArray, &(bounds[2]));
		SetVar(dataForm, BOUNDS, boundsArray);
		SetVar(dataForm, NCOMPONENTS, NewInt(rank - 1));

		label[0] = '\0';    /* Init label[] to null string */

		/*Get the name*/
		if ((-1 == DFSDgetdatastrs(label, dummy, dummy, dummy)) || (label[0] == '\0'))
		{
		    strcpy(label, fileName);
		}
		    
#ifdef     DEBUG
	printf("ReadHDFDFile: label = %s\n", label);
#endif
		/*Read in the data*/

		/*Find the size of the data*/
		size = 1;
		for (k = 0; k < rank; ++k)
		{
		    size *= dimSizes[k];
		}

		tempData = (float *) malloc(sizeof(float) * size);
		if (!tempData)
		{
		    OMErr();
		    free(bounds);
		    free(dims);
		    free(dims_L);
		    return NULLOBJ;
	        }
	
		if (-1 == DFSDgetdata(fileName, rank, dimSizes, tempData))
		{
		    FileFormatError("ReadHDFDFile", "Can't read field data.");
		    free(bounds);
		    free(dims);
		    free(dims_L);
		    return NULLOBJ;
	        }

		    arraySize = dimSizes[1];
		    if (rank > 2)
			for (k = 2; k < rank; ++k)
			    arraySize *= dimSizes[k];
		if (outOfBoundsAction < 2)
		{   /*Search for out of bounds data*/
		    dataMeat = tempData;
		    for (k = 0; k < size; ++k)
		    {
			if (*dataMeat < min)
			    *dataMeat = (outOfBoundsAction == 1) ? min : missingData;
			else
			    if (*dataMeat > max)
				*dataMeat = (outOfBoundsAction == 1) ? max : missingData;
			++dataMeat;
		    }
		}

		fieldData = NewArray(AT_OBJECT, 1, &nComponents);
		dataMeat = tempData;
		elements = ELEMENTS(fieldData);
		for (k = 0; k < nComponents; ++k)
		{
		    elements[k] = NULLOBJ;
		    elements[k] = NewArray(AT_REAL, rank - 1, dims_L + 1);
		    CArray2Array(elements[k], dataMeat);
		    dataMeat += arraySize;
		}

		free(tempData);

		/* Create "vector field" dataset of scales */

		temp_long = rank - 1;

		vectorDataset = NewObject(datasetClass, 0);
		vectorField = NewArray(AT_OBJECT, 1, &temp_long);

		elements = ELEMENTS(vectorField);
		for (k = 0; k < rank - 1; ++k)
		{
		    elements[k] = scales[k + 1];
		    indices = NewRealArray(1, 1L);
		    *(real *)ELEMENTS(indices) = k;
		    SetVar(scales[k + 1], INDICES, indices);
		}

		SetVar(vectorDataset, DATA, vectorField);
		SetVar(vectorDataset, NCOMPONENTS, NewInt(rank - 1));

		SetVar(dataForm, DATA, vectorDataset);

		/*Create the field*/

		curField = NewObject(datasetClass, 0);
		SetVar(curField, NCOMPONENTS, NewInt(nComponents));
		SetVar(curField, DATA, fieldData);
		SetVar(curField, DATAFORM, dataForm);
		switch (rank - 1)
		{
		    case 1:     SetVar(curField, DEFAULTICON, icon1DVector); break;
		    case 2:     SetVar(curField, DEFAULTICON, icon2DVector); break;
		    case 3:     SetVar(curField, DEFAULTICON, icon3DVector); break;
		    default:    SetVar(curField, DEFAULTICON, icon4DVector); break;
		}

		/*Remove leading blanks on label*/
		s = label;
		while (*s && *s == ' ') ++s;
		SetVar(curField, NAME, NewString(s));

		/*Set the min and max*/
		if (minMaxSet)
		{
		    real minMax[2];
		    ObjPtr minMaxArray;
		    minMax[0] = min;
		    minMax[1] = max;
		    minMaxArray = NewRealArray(1, 2L);
		    CArray2Array(minMaxArray, minMax);
		    SetVar(curField, MINMAX, minMaxArray);
		}

		free(bounds);
		free(dims);
		free(dims_L);
	    }
	    else
	    {
		/*Make DIMENSIONS (convert from int to long to real in the process)*/

		dimsArray = NewRealArray(1, (long) rank);
		for (k = 0; k < rank; ++k)
                    dims[k] = dims_L[k] = dimSizes[k];
		CArray2Array(dimsArray, dims);
		SetVar(dataForm, DIMENSIONS, dimsArray);

		boundsArray = NewRealArray(1, (long) (rank * 2));
		CArray2Array(boundsArray, bounds);
		SetVar(dataForm, BOUNDS, boundsArray);
		SetVar(dataForm, NCOMPONENTS, NewInt(rank));

		label[0] = '\0';    /* Init label[] to null string */

		/*Get the name*/
		if ((-1 == DFSDgetdatastrs(label, dummy, dummy, dummy)) || (label[0] == '\0'))
		{
		    strcpy(label, fileName);
		}
		    
#ifdef     DEBUG
	printf("ReadHDFDFile: label = %s\n", label);
#endif
		/*Read in the data*/
		fieldData = NewArray(AT_REAL, rank, dims_L);
		if (-1 == DFSDgetdata(fileName, rank, dimSizes, ArrayMeat(fieldData)))
		{
		    FileFormatError("ReadHDFDFile", "Can't read field data.");
		    free(bounds);
		    free(dims);
		    free(dims_L);
		    return NULLOBJ;
	       }

		if (outOfBoundsAction < 2)
		{   /*Search for out of bounds data*/
		    arraySize = dimSizes[0];
		    if (rank > 1)
			for (k = 1; k < rank; ++k)
			    arraySize *= dimSizes[k];
		    dataMeat = ArrayMeat(fieldData);
		    for (k = 0; k < arraySize; ++k)
		    {
			if (*dataMeat < min)
			    *dataMeat = (outOfBoundsAction == 1) ? min : missingData;
			else
			    if (*dataMeat > max)
				*dataMeat = (outOfBoundsAction == 1) ? max : missingData;
			++dataMeat;
		    }
		}

		/* Create "vector field" dataset of scales */

		temp_long = rank;

		vectorDataset = NewObject(datasetClass, 0);
		vectorField = NewArray(AT_OBJECT, 1, &temp_long);

		elements = ELEMENTS(vectorField);
		for (k = 0; k < rank; ++k)
		{
		    indices = NewRealArray(1, 1L);
		    *(real *)ELEMENTS(indices) = k;
		    SetVar(scales[k], INDICES, indices);

		    elements[k] = scales[k];
		}

		SetVar(vectorDataset, DATA, vectorField);
		SetVar(vectorDataset, NCOMPONENTS, NewInt(rank));

		SetVar(dataForm, DATA, vectorDataset);

		/*Create the field*/

		curField = NewObject(datasetClass, 0);
		SetVar(curField, DATA, fieldData);
		SetVar(curField, DATAFORM, dataForm);
		switch (rank)
		{
		    case 1:     SetVar(curField, DEFAULTICON, icon1DScalar); break;
		    case 2:     SetVar(curField, DEFAULTICON, icon2DScalar); break;
		    case 3:     SetVar(curField, DEFAULTICON, icon3DScalar); break;
		    default:    SetVar(curField, DEFAULTICON, icon4DScalar); break;
		}

		/*Remove leading blanks on label*/
		s = label;
		while (*s && *s == ' ') ++s;
		SetVar(curField, NAME, NewString(s));

		/*Set the min and max*/
		if (minMaxSet)
		{
		    real minMax[2];
		    ObjPtr minMaxArray;
		    minMax[0] = min;
		    minMax[1] = max;
		    minMaxArray = NewRealArray(1, 2L);
		    CArray2Array(minMaxArray, minMax);
		    SetVar(curField, MINMAX, minMaxArray);
		}

		free(bounds);
		free(dims);
		free(dims_L);
	    }
        }

        /*Add the current field*/
        if (curField)
        {
            RegisterDataset(curField);
        }
    }

    DFSDrestart();

    return NULLOBJ;
} /* ReadHDFDFile */
#endif


ObjPtr NewFileReader(char *name)
{
    ObjPtr fileReader;
    ThingListPtr runner;
    ObjPtr nameVar;

    fileReader = NewObject(fileReaderClass, 0);
    SetVar(fileReader, NAME, NewString(name));

    /*Find proper location for the new file reader*/
    runner = LISTOF(allFileReaders);

    if (runner &&
	(nameVar = GetStringVar("NewFileReader", runner -> thing, NAME)) &&
	strcmp2(name, GetString(nameVar)) < 0)
    {
	PrefixList(allFileReaders, fileReader);
    }
    else
    {
	while (runner && runner -> next)
	{
	    nameVar = GetStringVar("NewFileReader", runner -> next -> thing, NAME);
	    if (nameVar && strcmp2(name, GetString(nameVar)) < 0)
	    {
		break;
	    }
	    runner = runner -> next;
	}
	if (runner)
	{    	
	    InsertList(runner, fileReader);
	}
	else
	{
	    PostfixList(allFileReaders, fileReader);
	}
    }
    return fileReader;
}

void DefineFormat(name, extension, reader, writer)
char *name;
char *extension;
ObjPtr (*reader)();
Bool (*writer)();
/*Defines a format with name, reader, and writer*/
{
    ObjPtr fileReader;

    fileReader = NewFileReader(name);
    SetVar(fileReader, EXTENSION, NewString(extension));
    SetMethod(fileReader, OLDREAD, reader);
}

ObjPtr FindFormatReader(format)
char *format;
/*Finds the file reader named format*/
{
    ThingListPtr runner;
    runner = LISTOF(allFileReaders);
    while (runner)
    {
	ObjPtr string;
	string = GetStringVar("FindFormatReader", runner -> thing, NAME);
	if (string && 0 == strcmp2(format, GetString(string)))
	{
	    return runner -> thing;
	}
	runner = runner -> next;
    }
    return NULLOBJ;
}

ObjPtr FindExtensionReader(ext)
char *ext;
/*Finds the file reader for extension ext*/
{
    ThingListPtr runner;
    runner = LISTOF(allFileReaders);
    while (runner)
    {
	ObjPtr string;
	string = GetStringVar("FindFormatReader", runner -> thing, EXTENSION);
	if (string && 0 == strcmp2(ext, GetString(string)))
	{
	    return runner -> thing;
	}
	runner = runner -> next;
    }
    return NULLOBJ;
}

ObjPtr ReadFormattedFile(reader, name)
char *name;
ObjPtr reader;
/*Reads file name with reader.*/
{
    FuncTyp method;
    ObjPtr retVal;

    if (!reader) return ObjFalse;

    timedDatasets = GetPredicate(reader, TIMEDDATASETS) ? true : false;
    method = GetMethodSurely("ReadFormattedFile", reader, READALL);
    if (!method)
    {
	return ObjFalse;
    }

    /*Read the file*/
    curFileName = name;
    retVal = (*method)(reader, name);
    curFileName = 0;
    return retVal;
}

void ReadFile(name, format)
char *name;
char *format;
/*Reads a file from the current directory with name and format format.
  If format points to a null string, looks for a format*/
{
    ObjPtr reader;

    if (format[0])
    {
	/*There's a format specified*/
	reader = FindFormatReader(format);
	if (!reader)
	{
	    WinInfoPtr errWindow;
	    char err[200];
	    sprintf(err, "There is no format named %s\n", format);
	    errWindow = AlertUser(UIERRORALERT, (WinInfoPtr) 0, err, 0, 0, "yeah?");
	    SetVar((ObjPtr) errWindow, HELPSTRING,
		NewString("You have specified on the SciAn command line a format \
that does not exist, or you left out the format string entirely.  This has \
prevented SciAn from reading the file.  You can read it now using the \
file window, which you can show by choosing New File Window from the File menu."));
	    return;
        }
    }
    else
    {
	char *s;
	/*Must find a format*/

	s = name;
	while (*s) ++s;
	while (s >= name && *s != '.') --s;
	if (*s == '.')
	{
	    reader = FindExtensionReader(s + 1);
	}
	else
	{
	    reader = NULLOBJ;
	}
	if (!reader)
	{
	    WinInfoPtr errWindow;
	    char err[200];
	    sprintf(err, "There is no default format for file %s\n", name);
	    errWindow = AlertUser(UIERRORALERT, (WinInfoPtr) 0, err, 0, 0, "yeah?");
	    SetVar((ObjPtr) errWindow, HELPSTRING,
		NewString("You have specified on the SciAn command line a file \
whose format cannot be deduced from the name.  This has \
prevented SciAn from reading the file.  You can read it now using the \
file window, which you can show by choosing New File Window from the File menu."));
	    return;
        }
    }
    ReadFormattedFile(reader, name);
}

static ObjPtr HideFileReadersWindow(window)
ObjPtr window;
/*Hide a file readers window, just return OK*/
{
    return ObjTrue;
}

WinInfoPtr NewFileReadersWindow(void)
/*Create a new file readers window*/
{
    WinInfoPtr objWin;
    ThingListPtr runner;
    ObjPtr panel, contents, corral, button;
    int l, r, b, t;
    int bw;

    /*Create the window*/
    objWin = NewObjWindow(NULLOBJ, "File Readers", WINDBUF + WINRGB, FRWINWIDTH, FRWINHEIGHT, SCRWIDTH, SCRHEIGHT);
    GetWindowBounds(&l, &r, &b, &t);

    /*Set a null but successful HIDE routine*/
    SetMethod((ObjPtr) objWin, HIDE, HideFileReadersWindow);

    /*Add a help string*/
    SetVar((ObjPtr) objWin, HELPSTRING, 
	NewString("This window shows all the file readers in Scian."));

    /*Put in a panel*/
    panel = NewPanel(greyPanelClass, 0, r - l, 0, t - b);
    SetVar(panel, STICKINESS, NewInt(STICKYLEFT + STICKYRIGHT +
				     STICKYBOTTOM + STICKYTOP));

    contents = GetVar((ObjPtr) objWin, CONTENTS);
    PrefixList(contents, panel);
    SetVar(panel, PARENT, (ObjPtr) objWin);

    /*Put in buttons and an icon corral*/
    contents = GetListVar("NewDatasetsWindow", panel, CONTENTS);
    if (!contents)
    {
	return 0;
    }
    /*Make an icon corral*/
    corral = NewIconCorral(NULLOBJ, l + MINORBORDER, r - MINORBORDER, b + 2 * MINORBORDER + BUTTONHEIGHT, t - MINORBORDER, BARRIGHT + BARBOTTOM);
    SetVar(corral, STICKINESS, NewInt(STICKYLEFT + STICKYRIGHT +
				     STICKYBOTTOM + STICKYTOP));
    SetVar(corral, TOPDOWN, ObjTrue);
    SetVar(corral, NAME, NewString("File Readers Corral"));
    SetVar(corral, HELPSTRING,
	NewString("This corral contains icons for all the file readers in \
SciAn.  You can show the controls of any file readers by selecting \
the icons and pressing the Show Controls button at the bottom of the window.  \
You can delete \
file readers by selecting them and choosing Delete from the Object menu."));
    PrefixList(contents, corral);
    SetVar(corral, PARENT, panel);

    l += MINORBORDER;
    r -= MINORBORDER;
    b += MINORBORDER;
    t = b + BUTTONHEIGHT;
    bw = (r - l - MINORBORDER) / 2;

    /*Make a show info button*/
    button = NewFunctionButton(objWin,
		l, l + bw, 
		b, b + BUTTONHEIGHT, OF_SHOW_CONTROLS); 
    if (button)
    {
	SetVar(button, PARENT, panel);
	SetVar(button, STICKINESS, NewInt(STICKYBOTTOM + STICKYLEFT + FLOATINGRIGHT));
	PrefixList(contents, button);
    }

    /*Drop all the file readers into the window*/
    runner = LISTOF(allFileReaders);

    while(runner)
    {
	ObjPtr icon, name;
	FuncTyp method;
	
	icon = GetVar(runner -> thing, DEFAULTICON);
	if (!icon)
	{
	    icon = NewIcon(0, 0, ICONFILEREADER, "?");
	}
	else
	{
	    icon = NewObject(icon, 0L);
	}
	name = GetVar(runner -> thing, NAME);
	SetVar(icon, NAME, name);

	SetVar(icon, ICONLOC, NULLOBJ);
	SetVar(icon, REPOBJ, runner -> thing);
	SetVar(icon, CORRAL, corral);
	DropIconInCorral(corral, icon);

	runner = runner -> next;
    }


    return objWin;
}

WinInfoPtr FileReadersWindow()
/*Returns or creates a file readers window*/
{
    WinInfoPtr retVal;

    retVal = GetWinFromTitle("File Readers");
    if (!retVal)
    {
	retVal = NewFileReadersWindow();
    }
    return retVal;
}

static ObjPtr ReadOldFile(fileReader, name)
ObjPtr fileReader;
char *name;
/*Method to read a file using an old style file reader*/
{
    FuncTyp method;
    method = GetMethodSurely("ReadOldFile", fileReader, OLDREAD);
    if (!method)
    {
	return ObjFalse;
    }
    (*method)(name);
    return ObjTrue;
}

static ObjPtr ChangeDefaultExtension(textBox)
ObjPtr textBox;
/*Changes the default extension for the text box*/
{
    ObjPtr repObj;

    repObj = GetObjectVar("ChangeDefaultExtension", textBox, REPOBJ);
    if (!repObj)
    {
	return ObjFalse;
    }

    SetVar(repObj, EXTENSION, GetValue(textBox));
    return ObjTrue;
}

static ObjPtr ChangeTimedDatasets(checkBox)
ObjPtr checkBox;
/*Changes a file reader's timed datasets*/
{
    ObjPtr repObj;
    repObj = GetObjectVar("ChangeTimedDatasets", checkBox, REPOBJ);
    if (!repObj)
    {
	return ObjFalse;
    }
    SetVar(repObj, TIMEDDATASETS, GetValue(checkBox));
    return ObjTrue;
}

static ObjPtr ShowFileReaderControls(fileReader, windowName)
ObjPtr fileReader;
char *windowName;
/*Makes a new control window to control a file reader*/
{
    WinInfoPtr controlWindow;
    ObjPtr var;
    ObjPtr panel;
    ObjPtr contents;
    WinInfoPtr dialogExists;

    dialogExists = DialogExists((WinInfoPtr) fileReader, NewString("Controls"));
    if (!dialogExists)
    {
	ObjPtr textBox, checkBox;
	int contentsRight, contentsTop;
	int left, right, bottom, top, mid;
	ThingListPtr runner;
	FuncTyp method;

	/*Make the panel*/
	panel = NewPanel(greyPanelClass, 0, 10, 0, 10);
	if (!panel)
	{
	    return ObjFalse;
	}
	contents = GetVar(panel, CONTENTS);
	SetVar(contents, PARENT, panel);

	/*Give file reader chance to add controls*/
	method = GetMethod(fileReader, ADDCONTROLS);
	if (method)
	{
	    (*method)(fileReader, contents);
	}

	/*Calculate the bounds*/
	contentsRight = contentsTop = 0;
	runner = LISTOF(contents);
	while (runner)
	{
	    Get2DIntBounds(runner -> thing, &left, &right, &bottom, &top);
	    contentsRight = MAX(contentsRight, right);
	    contentsTop = MAX(contentsTop, top);
	    runner = runner -> next;
	}

	bottom = contentsTop + MAJORBORDER;
	left = MAJORBORDER;

	/*Create the check box for time dependency*/
	top = bottom + CHECKBOXHEIGHT;
	right = left + FRTIMEWIDTH;
	checkBox = NewCheckBox(left, right, bottom, top,
		"Use \"field@time\" format for time samples",
		GetPredicate(fileReader, TIMEDDATASETS));
	SetVar(checkBox, PARENT, panel);
	SetVar(checkBox, REPOBJ, fileReader);
	PrefixList(contents, checkBox);
	bottom = top + MINORBORDER;
	SetMethod(checkBox, CHANGEDVALUE, ChangeTimedDatasets);
	SetVar(checkBox, HELPSTRING, 
	    NewString("If this check box is checked, any dataset name of the \
form \"name@time\" will be interpreted as a sample of field name at time time.  \
The time string can be a single number, in which case it will be interpreted \
as seconds or timesteps, or it can be a string in the form hh:mm:ss, or clock \
format.  For example, a dataset named \"Z@12:04:00\" is a sample for the file \
Z taken at 12:04:00.  This feature provides an easy way to get time-dependent \
data from file formats that are only suited to static data.\n\
\n\
If this check box is not checked, dataset names will be used as they appear, \
even if they contain the \"@\" character.  Any inherent capability of the file \
reader to read time-dependent data will continue to work, of course."));

	/*Create the default file extension box*/
	top = bottom + EDITBOXHEIGHT;
	right = left + FREXTTITLEWIDTH;
	mid = (bottom + top) / 2;
	textBox = NewTextBox(left, right,
		mid - TEXTBOXHEIGHT / 2 + EDITBOXDOWN, 
		mid + TEXTBOXHEIGHT / 2 + EDITBOXDOWN,
		0, "Default Extension Text", "Default Extension:");
	SetVar(textBox, PARENT, panel);
	PrefixList(contents, textBox);

	/*Create the editable box*/
	left = right + MAJORBORDER;
	right = left + FREXTTEXTWIDTH;
	var = GetVar(fileReader, EXTENSION);
	textBox = NewTextBox(left, right,
		mid - EDITBOXHEIGHT / 2, 
		mid + EDITBOXHEIGHT / 2,
		EDITABLE + WITH_PIT + ONE_LINE, "Default Extension", var ? GetString(var) : "");
	SetVar(textBox, REPOBJ, fileReader);
	SetVar(textBox, PARENT, panel);
	PrefixList(contents, textBox);
	SetMethod(textBox, CHANGEDVALUE, ChangeDefaultExtension);
	SetVar(textBox, HELPSTRING, 
	   NewString("This text box shows the default file extension, or the portion \
of the file name after the last period, for files \
which use this format.  If you change it to another extension, the new extension \
will be used when you open new file windows.  The period is implied; do not include \
it in the new file extension."));

	left = bottom = 0;
	top += MAJORBORDER;
	right = MAX(MAJORBORDER + FROVERALLWIDTH, contentsRight) + MAJORBORDER;

	/*Finally, make the window around the panel*/
	Set2DIntBounds(panel, left, right, bottom, top);
	controlWindow = GetDialog((WinInfoPtr) fileReader, NewString("Controls"), windowName, 
	    right, top, right, top, WINDBUF + WINRGB + WINFIXEDSIZE);    
	contents = GetVar((ObjPtr) controlWindow, CONTENTS);
	PrefixList(contents, panel);
	SetVar(panel, PARENT, (ObjPtr) controlWindow);
	SetVar((ObjPtr) controlWindow, HELPSTRING, 
		NewString("This window shows controls for an individual file reader.  \
Use Help in Context to get help on each control."));

    }
}

static ObjPtr ChangeOutOfBounds(radio)
ObjPtr radio;
/*Changes the out of bounds in a radio's repobj*/
{
    ObjPtr repObj;
    repObj = GetObjectVar("ChangeOutOfBounds", radio, REPOBJ);
    if (!repObj)
    {
	return ObjFalse;
    }

    SetVar(repObj, OUTOFBOUNDS, GetValue(radio));

    return ObjTrue;
}

static ObjPtr ChangeReadVector(box)
ObjPtr box;
/*Changes the out of bounds from a check box*/
{
    ObjPtr repObj;
    repObj = GetObjectVar("ChangeReadVector", box, REPOBJ);
    if (!repObj)
    {
	return ObjFalse;
    }

    SetVar(repObj, READVECTOR, GetValue(box));

    return ObjTrue;
}

ObjPtr MakeReaderIconHelp(readerIcon, class)
ObjPtr readerIcon, class;
/*Makes help for a file reader icon*/
{
    ObjPtr retVal, additionalHelp;
    ObjPtr repObj;
    ObjPtr var;

    repObj = GetVar(readerIcon, REPOBJ);
    if (!repObj)
    {
	return NULLOBJ;
    }
    var = GetVar(repObj, NAME);

    sprintf(tempStr, "This icon represents the %s file reader.  ",
		var ? GetString(var) : "");
    retVal = NewString(tempStr);
    additionalHelp = GetVar(repObj, HELPSTRING);
    if (!additionalHelp)
    {
	additionalHelp = NewString("For more information on this file reader, see the User Manual.");
    }
    retVal = ConcatStrings(retVal, additionalHelp);
    SetVar(class, HELPSTRING, retVal);
    return retVal;
}

static ObjPtr AddHDFControls(fileReader, panelContents)
ObjPtr fileReader, panelContents;
/*Adds controls appropriate to an HDF fileReader*/
{
    ObjPtr titleBox, radio, checkBox, button;
    int left, right, bottom, top;
    ObjPtr var;

    left = MAJORBORDER;
    bottom = MAJORBORDER;

    /*Do the read vectors check box*/
    right = left + HDFVECTORWIDTH;
    top = bottom + CHECKBOXHEIGHT;

    checkBox = NewCheckBox(left, right, bottom, top, "Read 2- and 3-vector data",
		GetPredicate(fileReader, READVECTOR));
    PrefixList(panelContents, checkBox);
    SetVar(checkBox, PARENT, panelContents);
    SetVar(checkBox, REPOBJ, fileReader);
    SetVar(checkBox, HELPSTRING, NewString("This controls whether the HDF reader \
will automatically read vector data with 2 and 3 dimensions.  If it is checked, \
whenever the first or the last dimension of the dataset is either 2 or 3, it will \
be interpreted as containing 2- or 3-vector data.  The first component is in the X \
direction, the second in the Y direction, and the third in the Z direction.  \
If the box is not checked, the data will be read in as scalar data.\n\
\n\
For example, say you have a 3-D velocity field (40 by 50 by 60), where the velocity \
has three cartesian components.  Store it as an HDF dataset 40 by 50 by 60 by 3.  \
To store the velocity at (23, 37, 42), for example, put the X component at (23, \
37, 42, 1), the Y component at (23, 37, 42, 2), and the Z component at (23, 37, 42, 3).  \
(This example uses FORTRAN conventions; a C example would go from 0 to 2 instead.)  \
The vector dimension can also be the first instead of the last, i.e. 3 by 40 by 50 by 60."));
    SetMethod(checkBox, CHANGEDVALUE, ChangeReadVector);

    bottom = top + MINORBORDER;

    /*Do the title box around the radio group*/
    right = left + 2 * MINORBORDER + HDFRADIOWIDTH;
    top = bottom + 2 * MINORBORDER + 2 * CHECKBOXSPACING + 3 * CHECKBOXHEIGHT + TITLEBOXTOP;

    titleBox = NewTitleBox(left, right, bottom, top, "Handle Out-of-Bounds Data");
    PrefixList(panelContents, titleBox);
    SetVar(titleBox, PARENT, panelContents);

    /*Make the radio buttons*/
    radio = NewRadioButtonGroup("Out of Bounds Radio");
    SetVar(radio, PARENT, panelContents);
    SetVar(radio, REPOBJ, fileReader);
    PrefixList(panelContents, radio);

    left += MINORBORDER;
    right -= MINORBORDER;
    top -= TITLEBOXTOP + MINORBORDER;
    bottom = top - CHECKBOXHEIGHT;
    button = NewRadioButton(left, right, bottom, top, "Treat as missing");
    AddRadioButton(radio, button);
    SetVar(button, HELPSTRING, NewString("When this button is down, values in \
the dataset which are out of bounds are treated as missing data."));

    top = bottom - CHECKBOXSPACING;
    bottom = top - CHECKBOXHEIGHT;
    button = NewRadioButton(left, right, bottom, top, "Clip to bounds");
    AddRadioButton(radio, button);
    SetVar(button, HELPSTRING, NewString("When this button is down, values in \
the dataset which are out of bounds are clipped to the bounds."));

    top = bottom - CHECKBOXSPACING;
    bottom = top - CHECKBOXHEIGHT;
    button = NewRadioButton(left, right, bottom, top, "Use as is");
    AddRadioButton(radio, button);
    SetVar(button, HELPSTRING, NewString("When this button is down, values in \
the dataset which are out of bounds are used as ordinary data values."));

    var = GetIntVar("AddHDFControls", fileReader, OUTOFBOUNDS);
    if (var)
    {
	SetValue(radio, var);
    }
    else
    {
	SetValue(radio, NewInt(0));
    }
    SetVar(radio, HELPSTRING, NewString("This radio button group controls how values \
in the dataset which are out of bounds are treated.  A data value is considered \
out of bounds if it is outside the range given by the minimum and maximum, \
as specified by the DFSDSetMinMax HDF call.  If no minimum and maximum have \
been set, this radio button group has no effect."));
    SetMethod(radio, CHANGEDVALUE, ChangeOutOfBounds);

    return ObjTrue;
}

void ReadObjectControls(object, directory)
ObjPtr object, directory;
/*Sets an object's controls from a possibly existing file within directory*/
{
    char oldDir[401];
    ObjPtr name;
    char *runner;
    ObjPtr extension;
    FILE *oldCurScript;
    Bool oldRunningScript, oldAbortScript;
    FILE *temp;
    WinInfoPtr oldSelWinInfo;

    oldRunningScript = runningScript;
    oldAbortScript = abortScript;
    oldCurScript = curScript;
    oldSelWinInfo = selWinInfo;

    getcwd(oldDir, 400);
    if (directory)
    {
	chdir(GetString(directory));
    }
    name = GetVar(object, NAME);
    if (!name)
    {
	return;
    }
    strcpy(tempStr, GetString(name));

    /*Modify file name*/
    runner = tempStr;
    while (*runner)
    {
	if (*runner == ' ') *runner = '_';
	++runner;
    }
    extension = GetVar(object, EXTENSION);
    if (extension)
    {
	strcat(runner, ".");
	strcat(runner, GetString(extension));
    }

    SetVar(object, DIRECTORY, directory);

    if (temp = fopen(tempStr, "r"))
    {
	/*Read the file into the object's control panel*/
	Bool oldShowControlPanels;
	Bool oldSettingUp;
	ObjPtr controlWindow;
	WinInfoPtr oldScriptWindow;

	fclose(temp);

	InhibitLogging(true);
	oldSettingUp = settingUp;
	oldShowControlPanels = showControlPanels;
	oldScriptWindow = scriptWindow;

	settingUp = true;
	showControlPanels = false;

	/*Show and create the control panel*/
	scriptWindow = (WinInfoPtr) NewControlWindow(object);

	BeginScript(tempStr);
	while(ReadScriptLine());

	settingUp = oldSettingUp;
	showControlPanels = oldShowControlPanels;
	scriptWindow = oldScriptWindow;
	InhibitLogging(false);
    }
    curScript = oldCurScript;
    runningScript = oldRunningScript;
    abortScript = oldAbortScript;
    selWinInfo = oldSelWinInfo;

    chdir(oldDir);
}

void SaveObjectControls(object, directory)
ObjPtr object, directory;
/*Sets an object's controls from a possibly existing file within directory*/
{
    char oldDir[401], fileName[401];
    ObjPtr name;
    char *runner;
    ObjPtr extension;

    getcwd(oldDir, 400);
    if (directory)
    {
	chdir(GetString(directory));
    }
    name = GetVar(object, NAME);
    if (!name)
    {
	return;
    }
    strcpy(fileName, GetString(name));

    /*Modify file name*/
    runner = fileName;
    while (*runner)
    {
	if (*runner == ' ') *runner = '_';
	++runner;
    }
    extension = GetVar(object, EXTENSION);
    if (extension)
    {
	strcat(runner, ".");
	strcat(runner, GetString(extension));
    }

    InhibitLogging(true);
    if (OpenLogFile(fileName))
    {
	/*Read the file into the object's control panel*/
	FuncTyp method;
	Bool oldShowControlPanels, oldSettingUp;

	oldSettingUp = settingUp;
	oldShowControlPanels = showControlPanels;

	settingUp = true;
	showControlPanels = false;

	method = GetMethod(object, SAVEALLCONTROLS);
	if (method)
	{
	    (*method)(object);
	}
	showControlPanels = oldShowControlPanels;
	settingUp = oldSettingUp;

	CloseLogFile();
    }
    InhibitLogging(false);

    chdir(oldDir);
}

void DoSaveObject()
/*Saves the whose controls are on the top window*/
{
    if (selWinInfo)
    {
	ObjPtr repObj;
	repObj = GetVar((ObjPtr) selWinInfo, REPOBJ);
	if (repObj)
	{
	    Log("save controls");
	    DeferMessage(repObj, SAVECPANEL);
	}
    }
}

void InitFiles(void)
/*Initializes the file handling routines*/
{
    ObjPtr icon, fileReader;

    fileReaderClass = NewObject(NULLOBJ, 0);
    AddToReferenceList(fileReaderClass);
    SetMethod(fileReaderClass, READALL, ReadOldFile);
    SetMethod(fileReaderClass, NEWCTLWINDOW, ShowFileReaderControls);
    icon = NewIcon(0, 0, ICONFILEREADER, "?"); 
    SetVar(icon, ICONLOC, NULLOBJ);
    SetVar(icon, FORMAT, NewString("File Reader"));
    SetVar(fileReaderClass, DEFAULTICON, icon);
    SetVar(fileReaderClass, TIMEDDATASETS, ObjTrue);
    SetMethod(fileReaderClass, SHOWCONTROLS, NewControlWindow);
    SetVar(fileReaderClass, DOUBLECLICK, NewString(OF_SHOW_CONTROLS));
    SetMethod(icon, MAKE1HELPSTRING, MakeReaderIconHelp);

    allFileReaders = NewList();
    AddToReferenceList(allFileReaders);
    DefineFormat("KJ1", "kj1", ReadKJFile, 0);
    DefineFormat("DD", "dd", ReadDDFile, 0);
    DefineFormat("DD2", "dd2", ReadDD2File, 0);
    DefineFormat("KJ2", "kj2", ReadKJ2File, 0);
    DefineFormat("KJ3", "kj3", ReadKJ3File, 0);
    DefineFormat("KJ4", "kj4", ReadKJ4File, 0);
    DefineFormat("KJ5", "kj5", ReadKJ5File, 0);
    DefineFormat("NFF", "nff", ReadNFFXFile, 0);
    DefineFormat("SY", "sy", ReadSYFile, 0);
#ifdef LORENZ
    DefineFormat("LRZ", "lrz", ReadLRZFile, 0);
#endif
#ifdef HDFDEF

    fileReader = NewFileReader("HDF");
    SetVar(fileReader, EXTENSION, NewString("hdf"));
    SetVar(fileReader, OUTOFBOUNDS, NewInt(0));
    SetVar(fileReader, HELPSTRING,
	NewString("This file reader reads scientific datasets using the HDF data \
format, developed at the National Center for Supercomputing Applications.  Libraries \
for reading HDF files and documentation are available via anonymous ftp from \
ftp.ncsa.uiuc.edu."));
    SetVar(fileReader, READVECTOR, ObjTrue);
    SetMethod(fileReader, READALL, ReadHDFDFile);
    SetMethod(fileReader, ADDCONTROLS, AddHDFControls);

#endif
    DefineFormat("JAK", "", ReadJAKFile, 0);
    DefineFormat("JAKB", "", ReadJAKBFile, 0);
    fileClass = NewObject(NULLOBJ, 0);
    AddToReferenceList(fileClass);
    SetVar(fileClass, CLASSID, NewInt(CLASS_FILE));
    InitFileSystem();
}

void KillFiles(void)
/*Kills the file handling routines*/
{
    int k;
    DeleteThing(fileClass);
    DeleteThing(allFileReaders);
    DeleteThing(fileReaderClass);
}
