/*******************************************************************************/
/********************************STF READER ************************************/
/*******************************************************************************/
/*
  10/26/1992
  ScianHwuFiles.c
  ReadSTFFile routine

  Tzong-Yow Hwu

  The file format is:
  
      RANK <rank>
      DIMENSIONS <xdim> <ydim> ....
      SCALAR|VECTOR <nComponents>
      [ BOUNDS     <xmin> <xmax> <ymin> <ymax> .... ] {required when no grid}
      [ INTERLACED|NONINTERLACED ]  { default is INTERLACED }  
      [ ORDER COLUMN|ROW ]          { defalut is COLUMN major }
      [ NAME <datasetName> ]
      [ TIME <time> ]
      DATA
      <values> ......
      .
      .
      .
      VECTOR <nComponents>
      [INTERLACED|NONINTERLACED] { takes previous spec as default }
      [ ORDER COLUMN|ROW ]       { takes previous spec as default }
      GRID
      <values> ......
      .
      .
      .
      END    { the default is reset to INTERLACED and COLUMN major when 
	       anther datasets begin }
      .
      .
      .
      .

  Grid is optional for any dataset, if a grid is not present then regular
  dataform is assumed.  The order of grid and data for a dataset is 
  arbitrary in the data file.  However, rank and dimensions are required 
  before either value is processed and the rank must precede dimensions. 
  If no grid is specified, then bounds is required.  
  If no order is specified for a set of values, then the default of 
  column major is assumed.
  If no dataset name is specified for the dataset, then it inherits from the
  previous dataset in the file.  If this happens to the first dataset, then
  it takes the name of the file.
*/
#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"
#include "ScianHwuFiles.h"

#define STF_MAXHEADER 9
#define STF_MAXNAMELEN 256

/* field type */
#define STF_SCALAR 0
#define STF_VECTOR 1

/* vector field data permutation type */
#define STF_NONINTERLACED 0
#define STF_INTERLACED 1

#define STF_COLUMNMAJOR 0
#define STF_ROWMAJOR 1

/* for datasetType */
#define STF_ERROR -1
#define STF_END 0
#define STF_DATA 1
#define STF_GRID 2

/* for specFlag */
#define STF_ISTYPE 1
#define STF_ISDIMS 2
#define STF_ISBOUNDS 4
#define STF_ISNAME 8
#define STF_ISORDER 16
#define STF_ISRANK 32 
#define STF_ISPERMUTATION 64 
#define STF_ISTIME 128

typedef struct  {
     int fieldType;   /* SCALAR or VECTOR */
     long *dimensions; /* xdim, ydim, zdim .... */
     real *bounds;  /* bounds array */
     int nBounds; /* number of bounds provided by the user if any */
     char datasetName[STF_MAXNAMELEN];
     int order; /* COLUMNMAJOR(default) or ROWMAJOR */
     int rank;
     int permutation; /* INTERLACED or NONINTERLACED */
     int nComponents;  /* number of components for vector data set */
     real time;
     } STF_spec;

#ifdef PROTO
static int parseHeader(FILE *inFile, int *specFlag, STF_spec *datasetSpec)
#else
static int parseHeader(inFile, specFlag, datasetSpec)
FILE *inFile;
int *specFlag;
STF_spec *datasetSpec;
#endif
{
  int datasetType = STF_END; /* DATA, GRID, ERROR, or END */
  int headerLine = 0;
  char dirStr[360]; 
  int counter;
  int c;

  for (SkipBlanks(inFile); (c = getc(inFile)) >= 0 && headerLine < STF_MAXHEADER;
       SkipBlanks(inFile))
  {
    ungetc(c, inFile);

    if (1 == fscanf(inFile, "%s", dirStr))
      {
        if (dirStr[0] == '#')
          {
            /* a comment */
            ReadLn(inFile);
            continue;
          }

        if (0 == strcmp2(dirStr, "RANK"))
          {
            if ( *specFlag & STF_ISRANK )
              {
                FileFormatError("ReadSTFFile", "Error reading header: double RANKs");
                datasetType = STF_ERROR;
                break;
              }
            SkipBlanks(inFile);
            if ( 1 != fscanf( inFile, "%d", &(datasetSpec->rank) ) )
              {
                FileFormatError("ReadSTFFile", "Error reading header: RANK value");
                datasetType = STF_ERROR;
                break;
              }
            if ( datasetSpec->rank < 1  )
              /* rank must be greater than or equal to 1 */
              {
                FileFormatError("ReadSTFFile", "Error reading header: invalid RANK value");
                datasetType = STF_ERROR;
                break;
              }
             ReadLn(inFile);
             headerLine++;
             *specFlag |= STF_ISRANK;
             continue; 
           }

        if (0 == strcmp2(dirStr, "TIME"))
          {
            if ( *specFlag & STF_ISTIME )
              {
                FileFormatError("ReadSTFFile", "Error reading header: double TIMEs");
                datasetType = STF_ERROR;
                break;
              }
            SkipBlanks(inFile);
            if ( 1 != fscanf( inFile, "%g", (float *) &(datasetSpec->time) ) )
              {
                FileFormatError("ReadSTFFile", "Error reading header: invalid TIME value");
                datasetType = STF_ERROR;
                break;
              }

             ReadLn(inFile);
             headerLine++;
             *specFlag |= STF_ISTIME;
             continue; 
           }

         if (0 == strcmp2(dirStr, "SCALAR"))
           {
             if ( *specFlag & STF_ISTYPE )
               {
                 FileFormatError("ReadSTFFile", "Error reading header: double field types");
                 datasetType = STF_ERROR;
                 break;
               }
             headerLine++;
             ReadLn(inFile);
             datasetSpec->fieldType = STF_SCALAR;
             datasetSpec->nComponents = 0;
             *specFlag |= STF_ISTYPE;     
             continue;
           }

         if (0 == strcmp2(dirStr, "VECTOR"))
           {
             if ( *specFlag & STF_ISTYPE )
               {
                 FileFormatError("ReadSTFFile", "Error reading header: double field types");
                 datasetType = STF_ERROR;
                 break;
               }

             SkipBlanks(inFile);
             if ( 1 != fscanf(inFile, "%d", &(datasetSpec->nComponents)) )
               {
                 FileFormatError("ReadSTFFile", "Error reading header: vector component number missing");
                 datasetType = STF_ERROR;
                 break;
               }
             if ( datasetSpec->nComponents < 1 )
               {
                 FileFormatError("ReadSTFFile", "Error reading header: invalid vector component value");
                 datasetType = STF_ERROR;
                 break;
               }

             headerLine++;

             ReadLn(inFile);
             datasetSpec->fieldType = STF_VECTOR;
             *specFlag |= STF_ISTYPE;     
             continue;
           }

         if (0 == strcmp2(dirStr, "INTERLACED"))
           {
             if ( *specFlag & STF_ISPERMUTATION )
               {
                 FileFormatError("ReadSTFFile", "Error reading header: double INTERLACED/NONINTERLACED spec.");
                 datasetType = STF_ERROR;
                 break;
               }

             headerLine++;
             ReadLn(inFile);
             datasetSpec->permutation = STF_INTERLACED;
             *specFlag |= STF_ISPERMUTATION;
             continue;
           }

         if (0 == strcmp2(dirStr, "NONINTERLACED"))
           {
             if ( *specFlag & STF_ISPERMUTATION )
               {
                 FileFormatError("ReadSTFFile", "Error reading header: double INTERLACED/NONINTERLACED spec.");
                 datasetType = STF_ERROR;
                 break;
               }

              headerLine++;
              ReadLn(inFile);
              datasetSpec->permutation = STF_NONINTERLACED;
              *specFlag |= STF_ISPERMUTATION;
              continue;
           }

         if (0 == strcmp2(dirStr, "NAME"))
           {
             if ( *specFlag & STF_ISNAME )
               {
                 FileFormatError("ReadSTFFile", "Error reading header: double NAME");
                 datasetType = STF_ERROR;
                 break;
               }

             headerLine++;
             SkipBlanks(inFile);

             if ( 1 != fscanf(inFile, "%s", datasetSpec->datasetName))
               {
                 FileFormatError("ReadSTFFile", "Error reading header: NAME format");
                 datasetType = STF_ERROR;
                 break;
               }
             ReadLn(inFile);
             *specFlag |= STF_ISNAME;
             continue;
           }

         if (0 == strcmp2(dirStr, "ORDER"))
           {
             if ( *specFlag & STF_ISORDER )
               {
                 FileFormatError("ReadSTFFile", "Error reading header: double ORDER");
                 datasetType = STF_ERROR;
                 break;
               }

             headerLine++;
             SkipBlanks(inFile);

             if ( 1 != fscanf(inFile, "%s", dirStr))
               {
                 FileFormatError("ReadSTFFile", "Error reading header: ORDER format");
                 datasetType = STF_ERROR;
                 break;
               }
             if ( 0 == strcmp2(dirStr, "COLUMN") )
               {
                 datasetSpec->order = STF_COLUMNMAJOR;
               }
             else if ( 0 == strcmp2(dirStr, "ROW") )
               {
                 datasetSpec->order = STF_ROWMAJOR;
               }
             else
               {
                 FileFormatError("ReadSTFFile", "Error reading header: ORDER format");
                 datasetType = STF_ERROR;
                 break;
               }

             ReadLn(inFile);
             *specFlag |= STF_ISORDER;
             continue;
           }

         if (0 == strcmp2(dirStr, "DIMENSIONS"))
           {
             if ( !(*specFlag & STF_ISRANK) )
               {
                 FileFormatError("ReadSTFFile", "Error reading header: RANK must precede DIMENSIONS");
                 datasetType = STF_ERROR;
                 break;
               }
                 
             if ( *specFlag & STF_ISDIMS )
               {
                 FileFormatError("ReadSTFFile", "Error reading header: double DIMENSIONS");
                 datasetType = STF_ERROR;
                 break;
               }

             headerLine++;

            /* allocate storage for dimensions*/
            if ( !(datasetSpec->dimensions = (long *) malloc(datasetSpec->rank * sizeof(long))) )
              {
                FileFormatError("ReadSTFFile", "Unable to allocate memory");
                datasetType = STF_ERROR;
                break;
              }

             *specFlag |= STF_ISDIMS;

             /* read all the dimensions */
             for(counter = 0; counter < datasetSpec->rank; counter++)
                {
                  SkipBlanks(inFile);
                  if ( 1 != fscanf(inFile, "%ld", datasetSpec->dimensions + counter) )
                    {
                      FileFormatError("ReadSTFFile", "Error reading header: DIMENSIONS format");
                      datasetType = STF_ERROR;
                      break;
                    }
                }

             if (datasetType == STF_ERROR)
               break;

             ReadLn(inFile);
             continue;
           }

         if (0 == strcmp2(dirStr, "BOUNDS"))
           {
             if ( *specFlag & STF_ISBOUNDS )
               {
                 FileFormatError("ReadSTFFile", "Error reading header: double BOUNDS");
                 datasetType = STF_ERROR;
                 break;
               }

             headerLine++;

             /* allocate storage for bounds*/
             if ( !(datasetSpec->bounds = (real *) malloc(sizeof(real))) )
               {
                 FileFormatError("ReadSTFFile", "Unable to allocate memory");
                 datasetType = STF_ERROR;
                 break;
               }

             *specFlag |= STF_ISBOUNDS;

             /* read all the bounds */
             for( counter = 0, SkipBlanks(inFile);
                  (c = getc(inFile))!= '\n' && c >= 0;
                  counter++, SkipBlanks(inFile)
                )
                {
                  ungetc(c, inFile);
                  if ( !( datasetSpec->bounds = (real *) realloc(datasetSpec->bounds, (counter+1)*sizeof(real))) )
                    {
                      FileFormatError("ReadSTFFile", "Unable to allocate memory");
                      datasetType = STF_ERROR;
                      break;
                    }
                  if ( 1 != fscanf(inFile, "%f", (float *) (datasetSpec->bounds + counter)) )
                    {
                      FileFormatError("ReadSTFFile", "Error reading header: BOUNDS format");
                      datasetType = STF_ERROR;
                      break;
                    }
                 }
             
             if (datasetType == STF_ERROR)
               /* this break gets out of the outer for loop */
               break;

             /* the number of bounds must be an even number */
             if ( counter == 0 || counter % 2 != 0 )
               {
                 FileFormatError("ReadSTFFile", "Error reading header: BOUNDS format");
                 datasetType = STF_ERROR;
                 break;
               }

             datasetSpec->nBounds = counter;
             continue;
           }

         if (0 == strcmp2(dirStr, "DATA"))
           {
             headerLine++;
             ReadLn(inFile);
             datasetType = STF_DATA;
             break;
           }

         if (0 == strcmp2(dirStr, "GRID"))
           {
             headerLine++;
             ReadLn(inFile);
             datasetType = STF_GRID;
             break;
           }

         if (0 == strcmp2(dirStr, "END"))
           {
             ReadLn(inFile);
             break;
           }

         FileFormatError("ReadSTFFile, unknown spec", dirStr);
         datasetType = STF_ERROR;
         break;
       }
     else
       {
         /* a blank line*/
         ReadLn(inFile);
         continue;
       }
  }

  if ( datasetType == STF_END )
    {
      if ( headerLine != 0 )
        {
          FileFormatError("ReadSTFFile",
          "Error reading header: Incomplete header spec for dataset");
          datasetType = STF_ERROR;
        }
      else
        {
          return datasetType; 
        }
    }

  if ( 
       (datasetType == STF_ERROR) || 

       /* rank and dimensions are always required */
       ( !(*specFlag & STF_ISRANK) || !(*specFlag & STF_ISDIMS) ) ||

       /* for grid data set, fieldtype is required */
       /* and its fieldtype must be vector */
       ( (datasetType == STF_GRID) && (!(*specFlag & STF_ISTYPE) || (datasetSpec->fieldType != STF_VECTOR) ) ) ||
       
       /* for field data set, fieldtype is required */
       /* and for vector dataset, permutation is required */
       ( (datasetType == STF_DATA) && (!(*specFlag & STF_ISTYPE)) ) 
     )
    {
      switch ( datasetType )
        {
          case STF_ERROR:
            /* error message was broadcasted */
            break;
          case STF_DATA:
            if ( !(*specFlag & STF_ISRANK) )
              {
                FileFormatError("ReadSTFFile",
                "Error reading header: RANK missing before DATA");
              }
            else if ( !(*specFlag & STF_ISDIMS) )
              {
                FileFormatError("ReadSTFFile",
                "Error reading header: DIMENSIONS missing before DATA");
              }
            else if ( !(*specFlag & STF_ISTYPE) )
              {
                FileFormatError("ReadSTFFile",
                "Error reading header: TYPE missing before DATA");
              }
            break;
          case STF_GRID:
            if ( !(*specFlag & STF_ISRANK) )
              {
                FileFormatError("ReadSTFFile",
                "Error reading header: RANK missing before GRID");
              }
            else if ( !(*specFlag & STF_ISDIMS) )
              {
                FileFormatError("ReadSTFFile",
                "Error reading header: DIMENSIONS missing before GRID");
              }
            else if ( !(*specFlag & STF_ISTYPE) )
              {
                FileFormatError("ReadSTFFile",
                "Error reading header: TYPE missing before GRID");
              }
            else if ( datasetSpec->fieldType != STF_VECTOR )
              {
                FileFormatError("ReadSTFFile",
                "Error reading header: GRID must be vector type");
              }
            break;
          default:
              FileFormatError("ReadSTFFile",
              "Error reading header: header format error");
            break;
        }
      datasetType = STF_ERROR;
    }
  return datasetType;
} /* parseHeader */

#ifdef PROTO
static int getStr(FILE *inFile, char *token)
#else
static int getStr(inFile, token) 
FILE *inFile;
char *token;
#endif
{
  int i;
  int c;

  do 
    {
      while((c = fgetc(inFile)) != EOF && (c == ' ' || c == '\t'))
         ;
      if (c == '#')
        while((c = fgetc(inFile)) != EOF && c != '\n')
           ;
    } while(c == '\n');

  for (i = 0; c != EOF && c != ' ' && c != '\t' && c != '\n'; i++)
    {
      token[i] = c;
      c = fgetc(inFile);
    }

  if (c != EOF)
    {
      ungetc(c, inFile);
    }
      
  token[i] = '\0';
  return i;
} /* getStr */ 


#ifdef PROTO
static real *readValue(FILE *inFile, STF_spec *datasetSpec, ObjPtr dataset)
#else
static real *readValue(inFile, datasetSpec, dataset)
FILE *inFile;
STF_spec *datasetSpec;
ObjPtr dataset;
#endif
/* return pointer to bounds of the dataset just read */
/* return null if an error occurred */
{

  real *bounds;
  long *index;
  int counter;
  int nComponents;

  
  /* determine number of components first */
  if ( datasetSpec->fieldType == STF_SCALAR )
    {
      nComponents = 1;
    }
  else
    {
      nComponents = datasetSpec->nComponents;
    }



  /* alloc bounds array and init it to contain 0 values */
  if ( !(bounds = (real *) malloc( 2*nComponents*sizeof(real) )) )
    {
      FileFormatError("ReadSTFFile", "Unable to allocate memory");
      return NULL;
    }
  for ( counter = 0; counter < 2*nComponents; counter++)
     {
       bounds[counter] = 0.0;
     }


  /* alloc index array and init it to contain 0 values */
  if ( !(index = (long *) malloc( datasetSpec->rank*sizeof(long) )) )
    {
      FileFormatError("ReadSTFFile", "Unable to allocate memory");
      return 0;
    }
  for ( counter = 0; counter < datasetSpec->rank; counter++)
     {
       index[counter] = 0L;
     }


    /* prepare to read in the field values from file */
    if ( !SetCurField(FIELD1, dataset) ) 
      {
        free(index);
        free(bounds);
        return NULL;
      }

    /* adjust the index and read in the corresponding field value */ 
    {
      real curData;
      char dataStr[32];
      int n; /* counter */
      
      counter = 0;

      if ( datasetSpec->fieldType == STF_SCALAR ||
                   datasetSpec->permutation == STF_NONINTERLACED )
        {
         for ( n = 0; n < nComponents; n++ )
           {
             counter = 0;
             while(getStr(inFile, dataStr)) 
             {
                int first = 1;
                int j;

                if ( !ParseReal( &curData, dataStr ) )
                  {
                    FileFormatError("ReadSTFFile", "Invalid numeric Value");
                    /* clean up and return an NULL ptr */
                    free(index);
                    free(bounds);
                    return NULL;
                  }

                PutFieldComponent(FIELD1, n, index, (real) curData);

                for (j = 0; first && j < datasetSpec->rank; j++)
                   first = index[j] == 0;
                if (first)
                  {
                    bounds[2 * n] = curData;
                    bounds[2 * n + 1] = curData;
                  }
                else
                  {
                    /* looking for bounds */
                    if ( curData < bounds[2*n] )
                      {
                        bounds[2*n] = curData;
                      }
                    else if ( curData > bounds[2*n+1] )
                      {
                        bounds[2*n+1] = curData;
                      }
                  }

                /* adjust the index according to column or row major */
                if( datasetSpec->order == STF_COLUMNMAJOR)
                  {
                    for(counter = 0; counter < datasetSpec->rank; counter++)
                      {
                        index[counter]++;
                        if (index[counter] == datasetSpec->dimensions[counter])
                          {
                           index[counter] = 0;
                           continue;
                          }
                        break;
                      }
                    if (counter == datasetSpec->rank)
                      {
                        /* This signifies the nth component data is all read */
                        break;
                      }
                  }
                else
                  {
                    for(counter = datasetSpec->rank - 1; counter > -1 ; counter--)
                      {
                        index[counter]++;
                        if (index[counter] == datasetSpec->dimensions[counter])
                          {
                           index[counter] = 0;
                           continue;
                          }
                        break;
                      }
                    if (counter == -1)
                      {
                        /* This signifies the nth component value is all read */
                        break;
                      }
                  }

             } /* while */

           }  /* for ( n = 0; n < nComponents; n++ ) */

         /* this indicates that the data number is less than dimensions */
         if ( ( datasetSpec->fieldType == STF_VECTOR && n != nComponents) ||
              ( datasetSpec->order == STF_COLUMNMAJOR && counter != datasetSpec->rank )||
              ( datasetSpec->order == STF_ROWMAJOR && counter != -1 ) )
           {
            FileFormatError("ReadSTFFile", "Inconsistent Data File, number of data values is less than that specified by dimensions");
            free(index);
            free(bounds);
            return NULL;
           }

        } /* if fieldType == STF_SCALAR || permutation == STF_NONINTERLACED */
      else /* fieldType is VECTOR and permutation is INTERLACED */ 
        {
           n = 0;
           counter = 0;
           while(getStr(inFile, dataStr))
           {
             int first = 1;
             int j;

              if ( !ParseReal( &curData, dataStr ) )
                {
                  FileFormatError("ReadSTFFile", "Invalid numeric Value");
                  /* clean up and return NULL */
                  free(index);
                  free(bounds);
                  return NULL;
                }

              PutFieldComponent(FIELD1, n, index, (real) curData);

              for (j = 0; first && j < datasetSpec->rank; j++)
                 first = index[j] == 0;
              if (first)
                {
                  bounds[2 * n] = curData;
                  bounds[2 * n + 1] = curData;
                }
              else
                {
                  /* looking for bounds */
                  if ( curData < bounds[2*n] )
                    {
                      bounds[2*n] = curData;
                    }
                  else if ( curData > bounds[2*n+1] )
                    {
                      bounds[2*n+1] = curData;
                    }
                 }

              n++;

              if ( n == nComponents ) /* time to update index */
                {
                 /* adjust the index according to column or row major */
                 if( datasetSpec->order == STF_COLUMNMAJOR)
                   {
                     for(counter = 0; counter < datasetSpec->rank; counter++)
                       {
                         index[counter]++;
                         if (index[counter] == datasetSpec->dimensions[counter])
                           {
                            index[counter] = 0;
                            continue;
                           }
                         break;
                       }
                     if (counter == datasetSpec->rank)
                       {
                         /* This signifies the field data is all read */
                         break;
                       }
                   }
                 else
                   {
                     for(counter = datasetSpec->rank - 1; counter > -1 ; counter--)
                       {
                         index[counter]++;
                         if (index[counter] == datasetSpec->dimensions[counter])
                           {
                            index[counter] = 0;
                            continue;
                           }
                         break;
                       }
                     if (counter == -1)
                       {
                         /* This signifies the field data is all read */
                         break;
                       }
                   }
 
                 n = 0;

                } /* if n == nComponents */

             } /* for fscanf */

         /* this indicates that the data number is less than dimensions */
         if ( ( datasetSpec->order == STF_COLUMNMAJOR && counter != datasetSpec->rank )||
              ( datasetSpec->order == STF_ROWMAJOR && counter != -1 ) )
           {
            FileFormatError("ReadSTFFile", "Inconsistent Data File, number of data values is less than that specified by dimensions");
            free(index);
            free(bounds);
            return NULL;
           }

        } /* else where fieldType is VECTOR and INTERLACED */


    }

    free(index);
    return bounds;

}/* readValue */


#ifdef PROTO
static ObjPtr ReadSTFFile(char *name)
#else
static ObjPtr ReadSTFFile(name)
char *name;
#endif
{
    int datasetType; /* DATA, GRID, END or ERROR */
    STF_spec datasetSpec;
    int specFlag = 0;

    FILE *inFile;

    real *gridBounds = NULL;
    real *dataMinmaxes = NULL;

    int isGrid = 0, isData = 0;
    int gridComponents; /* the number of components for the grid if any */
    int counter;
    int more = 1;

    ObjPtr dataForm;
    ObjPtr gridDataset;
    ObjPtr retVal;

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

    /* set default dataset specs */
    datasetSpec.rank = 0;
    datasetSpec.nComponents = 0;
    datasetSpec.order = STF_COLUMNMAJOR;
    datasetSpec.permutation = STF_INTERLACED;
    strcpy(datasetSpec.datasetName, name);



    while( more ) 
      {
        /* parse header lines */
        datasetType = parseHeader(inFile, &specFlag, &datasetSpec);

        switch ( datasetType )
          {
            case STF_ERROR: 
               FileFormatError("Error in dataset", datasetSpec.datasetName);
               more = 0;
               break;
            case STF_GRID:
               /* if isGrid then error, double grid */
               if ( isGrid )
                 {
                   FileFormatError("ReadSTFFile", "Multiple Grid Spec");
                   FileFormatError("Error in dataset", datasetSpec.datasetName);
                   more = 0;
                   break;
                 }

               gridComponents = datasetSpec.nComponents;

               /* create the grid dataset */
               gridDataset = NewStructuredDataset(datasetSpec.datasetName, datasetSpec.rank, datasetSpec.dimensions, gridComponents);

               /* something wrong with grid value format */
               if ( !(gridBounds = readValue( inFile, &datasetSpec, gridDataset)))
                 {
                   FileFormatError("Error in dataset", datasetSpec.datasetName);
                   more = 0;
                   break;
                 }

               /* reset specFlag */
               specFlag &= (~STF_ISTYPE & ~STF_ISPERMUTATION & ~STF_ISORDER);
               isGrid = 1;
               break;
            case STF_DATA:
               /* if isData then error, double data */
               if ( isData )
                 {
                   FileFormatError("ReadSTFFile", "Multiple Data Spec");
                   FileFormatError("Error in dataset", datasetSpec.datasetName);
                   more = 0;
                   break;
                 }

               /* create the dataset */
               retVal = NewStructuredDataset(datasetSpec.datasetName, datasetSpec.rank, datasetSpec.dimensions, datasetSpec.nComponents);

               /* something wrong with data value format */
               if ( !(dataMinmaxes = readValue( inFile, &datasetSpec, retVal)) )
                 {
                   FileFormatError("Error in dataset", datasetSpec.datasetName);
                   more = 0;
                   break;
                 }
               else
                 {
                   /* has no use with dataMinmaxes */
                   free(dataMinmaxes);
                 }

               /* reset specFlag */
               specFlag &= (~STF_ISTYPE & ~STF_ISPERMUTATION & ~STF_ISORDER);
               isData = 1;
               break;
            case STF_END:
               /* if isData && isGrid then use curvilinear dataForm */
               /* if isData && !isGrid then regular dataForm */
               /* for this case, the bounds are required, error if no */
               /* if !isData && isGrid the error */
               /* if !isData && !isGrid then means end of file */
                       
               if ( !isData && !isGrid )
                 /* end of dataset file reached */
                 {
                   more = 0;
                   break;
                 }

               if ( !isData && isGrid )
                 {
                   FileFormatError("ReadSTFFile", "NO DATA");
                   FileFormatError("Error in dataset", datasetSpec.datasetName);
                   more = 0;
                   break;
                 }

               if ( specFlag & STF_ISBOUNDS )
                 {
                   int nBounds; /* number of bounds */

                   /* get rid of calculated grid bounds if any and 
                      use the bounds provided by the user */
                   /* determine the number of bounds */
                   if ( isGrid )
                     {
                       free(gridBounds);
                       gridBounds = NULL;
                       nBounds = 2 * gridComponents;
                     }
                   else
                     {
                       nBounds = 2 * datasetSpec.rank;
                     }

                   /* test if the user provide correct bounds */
                   if ( nBounds != datasetSpec.nBounds )
                     {
                       FileFormatError("ReadSTFFile", "BOUNDS format error");
                       FileFormatError("Error in dataset", datasetSpec.datasetName);
                       more = 0;
                       break;
                     }

                   gridBounds = datasetSpec.bounds;
                 }


               if ( isData && isGrid )
                 /* for this case, bounds are optional */
                 {
                   dataForm = NewCurvilinearDataForm(datasetSpec.datasetName, datasetSpec.rank, datasetSpec.dimensions, gridBounds, gridDataset);
                 }
               else
                 {
                   /* isData && !isGrid */      
                   /* for this case bounds are required */
                   if ( !(specFlag & STF_ISBOUNDS) )
                     {
                       FileFormatError("ReadSTFFile", "BOUNDS required for dataset with no grid");
                       FileFormatError("Error in dataset", datasetSpec.datasetName);
                       more = 0;
                       break;
                     }
                   dataForm = NewRegularDataForm(datasetSpec.datasetName, datasetSpec.rank, datasetSpec.dimensions, gridBounds);
                 }

               SetDatasetForm(retVal, dataForm);
               if ( specFlag & STF_ISTIME )
                 {
                   RegisterTimeDataset(retVal, datasetSpec.time);
                 }
               else
                 {
                   RegisterDataset(retVal);
                 }

               isGrid = 0;
               isData = 0;
               specFlag = 0;
               free(datasetSpec.dimensions);
               free(gridBounds);
               gridBounds = NULL;

               /* set default dataset specs */
               datasetSpec.rank = 0;
               datasetSpec.nComponents = 0;
               datasetSpec.order = STF_COLUMNMAJOR;
	       datasetSpec.permutation = STF_INTERLACED;

               break;
            default:     
               /* dummy case */
               break;
          } /* switch */
      } /* while */

   if ( specFlag & STF_ISDIMS )
     {
       free(datasetSpec.dimensions);
     }

   if ( specFlag & STF_ISBOUNDS )
     {
       free(datasetSpec.bounds);
     }
   if ( isGrid )
     {
       free(gridBounds);
     }
   fclose(inFile);
   return NULLOBJ;
}


/*******************************************************************************/
/********************************P3D READER ************************************/
/*******************************************************************************/
/* Tzong-Yow Hwu */
/* 10/26/1992 */
/* plot3d file reader */

/* file types */
#define P3D_GRID        0
#define P3D_FUNC        1
#define P3D_Q           2

/* file format types, default on IRIS 4D is unformatted and on UNIX is binary */
/* for both grid and Q files */
#define P3D_DAT         0  
#define P3D_BIN         1  /* default */
#define P3D_FMT         2

/* data permutation method, default is the whole */
/* PLANES has no effect on reading other than 3D dataset */
#define P3D_WHOLE       0   /* default */   /* the whole dataset at once */
#define P3D_PLANE       1   /* one plane at a time */

/* Control over default checking of Q data, default is to check */
/* for Q files only */
#define P3D_CHECK       0  /* default */
#define P3D_NOCHECK     1


/* Jacobian control */
/* for Q files only */
#define P3D_NOJACOBIAN  0 /* default */
#define P3D_JACOBIAN    1 

/* IBLANK control */
/* for grid files only */
#define P3D_NOBLANK     0
#define P3D_BLANK       1

#define MAXNAMELEN 1800 

typedef struct P3D_grid
{
  char name[MAXNAMELEN];
  int fileType;
  int permutation;
  int blank;
} p3d_grid;

typedef struct P3D_q
{
  char name[MAXNAMELEN];
  int isMDataset;
  int fileType;
  int permutation;
  int check;
  int jacobian;
} p3d_q;

typedef struct P3D_func
{
  char name[MAXNAMELEN];
  int fileType;
  int permutation;
} p3d_func;

/* a p3d set consist of a grid spec and several Q spec's and func spec's */
/* remember to get rid of initialization for this typedef */
typedef struct P3D_set
   {
     int ndim;
     int isMGrid;  /* 0 for no and 1 for yes */
     int isGrid;         /* is the grid present */
     p3d_grid *grid;  /* pointer to the grid spec */
     int nQ;    /* number of Q files for this p3d set */
     p3d_q *qlist;   /* pointer to an array of Q spec */
     int nFunc; /* number of func files for this p3d set */
     p3d_func *funclist; /* pointer to an array of func spec */
   } p3d_set;

/*
   1. getToken read to next occurrence of slash '/' or eof, and pass
      the string back, return 0 if end of file is encountered, -1 
      if error format, otherwise the number of chars in token.
   2.  only process READ commands 
   3. newline without preceding '-' is treated as command terminator
*/
#ifdef PROTO
static int getToken(FILE *inFile, char *token)
#else
static int getToken(inFile, token) 
FILE *inFile;
char *token;
#endif
{
  int i;
  int c;
  int inQuotes = 0;

  for( i = 0; ( c = fgetc(inFile) ) != EOF ; i++ ) 
     {
       if (c == ' ' || c == '\t')
         {
          i--;
          continue;
         }
       else if (c == '\n')
         {
           if (i > 0 && token[i - 1] == '-')
             /* if continuation on next line */
             {
               i -= 2;
               continue;
             }
           else if (inQuotes)
             {
               fprintf(stderr, "File format error, unbalanced quote\n");
               return -1;
             }
           else if (i == 0)
             /* skip blank lines */
             {
               i--;
               continue;
             }
           else
             {
               break;
             }
         }
       else if (c == '\"')
         {
           /* flip inQuotes flag */
           inQuotes = !inQuotes;
           /* discard the '"' char */
           i--;
           continue;
         }
       else if (c == '/')
         {
           if (!inQuotes)
             {
               break;
             }
           /* otherwise, fall through to get the char */
         }
       token[i] = c;
     }
  
  if ( i == 0 )
    if ( c == EOF )
      {
        /* end of file reached */
        return 0;
      }
    else
      {
        /* error file formate */
        /* call ERROR routine */
        fprintf(stderr, "File format error\n");
        return -1;
      }

  token[i] = '\0';
  return i;
} /* getToken */ 

/* getvalue return the number of values repeated in the form
   of num*val and returns 0 if error or EOF encountered */
#ifdef PROTO
static int getValue(FILE *inFile, double *val)
#else
static int getValue(inFile, val)
FILE *inFile;
double *val;
#endif
{
  int c;
  int count;
  char s[180];
  char *end, *newstr;

  /* skip blanks and commas */
  while(isspace(c = fgetc(inFile)) || c == ',')
     ;
  if (c != EOF)
    ungetc(c, inFile);
  else
    return EOF;

  /* get the numerical string */
  if (fscanf(inFile, "%s", s) != 1)
    {
      return 0;
    }
  *val = strtod(s, &end);
  if (end == s)
    {
      /* nothing is converted */
      return 0;
    }
  if (end[0] == '\0' || (end[0] == ',' && end[1] == '\0'))
    {
      return 1;
    }
  else if (*end == '*')
    {
      count = (int) *val;
      newstr = end + 1;
      *val = strtod(newstr, &end);
      if (end == newstr || !(*end == '\0' || (*end = ',' && *(end + 1) == '\0')))
        {
          /* nothing is converted || format error */
          return 0;
        }
      return count;
    }
  else
    {
      return 0;
    }
} /* getValue */

/* strncmp2 compares two string for n chars, case insensitive */
#ifdef PROTO
static int strncmp2(char *s, char *t, int n)
#else
static int strncmp2(s, t, n)
char *s;
char *t;
int n;
#endif
{
  int i;

  for (i = 0; i < n && toupper(s[i]) == toupper(t[i]); i++)
     {
       if (s[i] == '\0')
         return 0;
     }

  if (i == n)
    return 0;
  else
    return (s[i] - t[i]);
}

#ifdef PROTO
static void cleanup(int nSets, p3d_set *sets)
#else
static void cleanup(nSets, sets) 
int nSets;
p3d_set *sets;
#endif
/* cleanup free the memory alloced in the program */
{
  int i;

  if (!sets)
    return;

  for (i = 0; i < nSets; i++)
     {
       if ((sets + i)->nQ)
          {
            free((sets + i)->qlist);
          }
       if ((sets + i)->nFunc)
          {
            free((sets + i)->funclist);
          }
       if ((sets + i)->isGrid)
         {
            free((sets + i)->grid);
         }
     }

  free(sets);

  return;
} /* cleanup */ 

#ifdef PROTO
static void compress(int *nSets, p3d_set **sets)
#else
static void compress(nSets, sets) 
int *nSets;
p3d_set **sets;
#endif
/* compress deals with the sets read */
/* for now it only outputs what is read */
{
  int i, j;

  /* now, sort the sets according to their grid filename first */
  for (i = 1; i < *nSets; i++)
    {
     p3d_set temp;

     temp = (*sets)[i];
     /* filename is case sensitive, so use strcmp not strcmp2 */
     for (j = i - 1; j >= 0 && strcmp((*sets)[j].grid->name,
                                       temp.grid->name) > 0; j--)
        {
          (*sets)[j + 1] = (*sets)[j];
        }
     (*sets)[j + 1] = temp;
    }

  /* second compress the sets, so that if any of these sets use the
     same grid file, making them as the same set.
  */
  {
    p3d_set *last = *sets;
    p3d_set *temp;

    for (i = 1, j = 1; i < *nSets; i++)
      {
        p3d_set *curset = *sets + i;

        if (!strcmp(curset->grid->name, last->grid->name))
          {
            /* combine this set into last set */
            if (curset->nQ > 0)
              {
                int k;

                if (!(last->qlist = (p3d_q *) realloc(last->qlist, 
                                  (last->nQ + curset->nQ) * sizeof(p3d_q))))
                  {
                    fprintf(stderr, "Unable to alloc memory, aborted\n");
                    return;
                  }
                for (k = 0; k < curset->nQ; k++)
                  {
                    last->qlist[last->nQ + k] = curset->qlist[k];
                  }
                free(curset->qlist);
                curset->qlist = NULL;
                last->nQ += curset->nQ;
              }

            if (curset->nFunc > 0)
              {
                int k;

                if (!(last->funclist = (p3d_func *) realloc(last->funclist, 
                            (last->nFunc + curset->nFunc) * sizeof(p3d_func))))
                  {
                    fprintf(stderr, "Unable to alloc memory, aborted\n");
                    return;
                  }
                for (k = 0; k < curset->nFunc; k++)
                  {
                    last->funclist[last->nFunc + k] = curset->funclist[k];
                  }
                free(curset->funclist);
                curset->funclist = NULL;
                last->nFunc += curset->nFunc;
              }
            
            /* mark this set has been combined */
            free(curset->grid);
            curset->grid = NULL;
          }
        else
          {
            last[j++] = *curset; 
          }
      } /* for */
      

    /* reset sets and nSets */
    /* cannot use realloc for *sets, since if it fails, then the q and 
       func lists is unaccessible and becomes garbages occupying
       the memory */
    if (!(temp = (p3d_set *) malloc(j * sizeof(p3d_set))))
      {
        fprintf(stderr, "Unable to alloc memory, aborted\n");
        return;
      }
    for (i = 0; i < j; i++)
      {
        temp[i] = (*sets)[i];
      }
    free(*sets); 
    *sets = temp;
    *nSets = j;
  }

#ifdef DEBUG

  for (i = 0; i < *nSets; i++)
    {

      p3d_set *curset = *sets + i;
      int isGrid = curset->isGrid;
      p3d_grid *grid = curset->grid;
      int nQ = curset->nQ;
      p3d_q *qlist = curset->qlist;
      int nFunc = curset->nFunc;
      p3d_func *funclist = curset->funclist;
      int j;

      printf("READ");
      /* ndim */
      if (curset->ndim == 1)
        {
          printf("/1D"); 
        }
      else if (curset->ndim == 2)
        {
          printf("/2D");
        }
      else if (curset->ndim == 3)
        {
          printf("/3D");
        }
    
      /* MGRID */
      if (curset->isMGrid)
        {
          printf("/MGRID");
        }

      /* process the XYZ file */
      if (isGrid)
        {
          /* file format */
          if (grid->fileType == P3D_DAT)
            {
              printf("/UNFORMATTED");
            }
          else if (grid->fileType == P3D_BIN)
            {
              printf("/BINARY");
            }
          else if (grid->fileType == P3D_FMT)
            {
              printf("/FORMATTED");
            }

          /* permutation */
          if (grid->permutation == P3D_WHOLE)
            {
              printf("/WHOLE");
            }
          else if (grid->permutation == P3D_PLANE)
            {
              printf("/PLANES");
            }

          /* BLANK */
          if (grid->permutation == P3D_BLANK)
            {
              printf("/BLANK");
            }
          else if (grid->permutation == P3D_NOBLANK)
            {
              printf("/NOBLANK");
            }

          printf("/XYZ=%s", grid->name);
        }
      else
         /* should not be the case */
        {
          fprintf(stderr, "XYZ file missing\n");
          continue;  /* do nothing for this set */
        }

      /* process the Q files */
      for (j = 0; j < nQ; j++)
        {
          /* MDATASET */
          if (qlist[j].isMDataset)
            {
              printf("/MDATASET");
            }

          /* file format */
          if (qlist[j].fileType == P3D_DAT)
            {
              printf("/UNFORMATTED");
            }
          else if (qlist[j].fileType == P3D_BIN)
            {
              printf("/BINARY");
            }
          else if (qlist[j].fileType == P3D_FMT)
            {
              printf("/FORMATTED");
            }

          /* permutation */
          if (qlist[j].permutation == P3D_WHOLE)
            {
              printf("/WHOLE");
            }
          else if (qlist[j].permutation == P3D_PLANE)
            {
              printf("/PLANES");
            }

          /* CHECK */
          if (qlist[j].check)
            {
              printf("/CHECK");
            }
          else
            {
              printf("/NOCHECK");
            }

          /* JACOBIAN */
          if (qlist[j].jacobian)
            {
              printf("/JACOBIAN");
              printf("\nsorry, jacobian is not implemented\n");
            }
          else
            {
              printf("/NOJACOBIAN");
            }

          printf("/Q=%s", qlist[j].name);
        }

      /* process the FUNCTION files */
      for (j = 0; j < nFunc; j++)
        {
          /* file format */
          if (funclist[j].fileType == P3D_DAT)
            {
              printf("/UNFORMATTED");
            }
          else if (funclist[j].fileType == P3D_BIN)
            {
              printf("/BINARY");
            }
          else if (funclist[j].fileType == P3D_FMT)
            {
              printf("/FORMATTED");
            }

          /* permutation */
          if (funclist[j].permutation == P3D_WHOLE)
            {
              printf("/WHOLE");
            }
          else if (funclist[j].permutation == P3D_PLANE)
            {
              printf("/PLANES");
            }

          printf("/FUNCTION=%s", funclist[j].name);
        }

      printf("\n");
    } /* outter for */

#endif   /* for ifdef DEBUG */

  return;
} /* compress */ 


/* return 0 on failure */
#ifdef PROTO
static int parseP3DMeta(char *p3dname, int *nSets, p3d_set **sets)
#else
static int parseP3DMeta(p3dname, nSets, sets)
char *p3dname;
int *nSets;
p3d_set **sets;
#endif
{

  FILE *inFile;
  char token[MAXNAMELEN];
  int isNdim = 0, ndim = 3;  /* default is 3D */
  int isMDataset = 0;  /* time dependent datasets */
  int isMGrid = 0;    /* multiple grid files */  /* How do deal with it in Scian? */
  int isFileType = 0, fileType = P3D_BIN; /* file type, default is BINARY on IRIS*/
  int isPermutation = 0, permutation = P3D_WHOLE; /* data permutation way */
  int isCheck = 0, check = P3D_NOCHECK;  /* check control for Q file */
  int isJacobian = 0, jacobian = P3D_NOJACOBIAN;  /* jacobian control for grid file*/
  int isBlank = 0, blank = P3D_NOBLANK;  /* blank control for grid file*/
  int status;
  int valid = 1; /* if this file format is valid */


  if ( !(inFile = fopen(p3dname, "r")) )
    {
      fprintf(stderr, "ReadP3DFile: %s\n", p3dname);
      return 0;
    }

  /* the first thing the .p3d file should be READ */
  if ((status = getToken(inFile, token)) <= 0 || strcmp2(token, "READ"))
    { 
      fprintf(stderr, "ReadP3DFile: %s, file format error\n", p3dname);
      fclose(inFile);
      return 0;
    }


  /* now since we know that this is plot 3d file, lets process it */
  /* alloc memory for the first p3d set */
  if (!(*sets = (p3d_set *) malloc(sizeof(p3d_set))))
    {
      fprintf(stderr, "Unable to alloc memory, aborted\n");
      fclose(inFile);
      return 0;
    }
  (*sets)->ndim = 3;
  (*sets)->isMGrid = 0;
  (*sets)->isGrid = 0;
  (*sets)->grid = NULL;
  (*sets)->nQ = 0;
  (*sets)->qlist = NULL;
  (*sets)->nFunc = 0;
  (*sets)->funclist = NULL;
  *nSets = 1;

  while ( (status = getToken(inFile, token)) > 0 )
    {
       /* for dimensions */
       if (!strcmp2(token, "1D") || !strcmp2(token, "1") ||
           !strcmp2(token, "2D") || !strcmp2(token, "2") ||
           !strcmp2(token, "3D") || !strcmp2(token, "3"))
         {
           p3d_set *curset = *sets + *nSets - 1;

           /* all number of dimensions for the same set must be consistent */
           if (isNdim && ndim != token[0] - '0')
             {
               fprintf(stderr, "ReadP3DFile: %s, inconsistent dim spec.\n", p3dname);
               valid = 0;
               break; /* get out of the while loop */ 
             }

           isNdim = 1;
           ndim = token[0] - '0';
           continue;
         }

       /* for MDATASET */
       if (!strcmp2(token, "MD") || !strcmp2(token, "MDA") ||
           !strcmp2(token, "MDAT") || !strcmp2(token, "MDATA") ||
           !strcmp2(token, "MDATAS") || !strcmp2(token, "MDATASE") ||
           !strcmp2(token, "MDATASET"))
         {
           isMDataset = 1;
           continue;
         }

       /* for MGRID */
       if (!strcmp2(token, "MG") || !strcmp2(token, "MGR") ||
           !strcmp2(token, "MGRI") || !strcmp2(token, "MGRID"))
         {
           /* all files for this set must be specified as mgrid */
           isMGrid = 1;
           continue;
         }

       /* for file format */
       if (!strcmp2(token, "FO") || !strcmp2(token, "FOR") ||
           !strcmp2(token, "FORM") || !strcmp2(token, "FORMA") || 
           !strcmp2(token, "FORMAT") || !strcmp2(token, "FORMATT") || 
           !strcmp2(token, "FORMATTE") || !strcmp2(token, "FORMATTED"))

         {
           if (isFileType && fileType != P3D_FMT)
             {
                fprintf(stderr, "ReadP3DFile: %s, double file format spec.\n", p3dname);
                valid = 0;
                break; /* get out of the while loop */ 
             }
           isFileType = 1;
           fileType = P3D_FMT;
           continue;
         }
       if (!strcmp2(token, "U") || !strcmp2(token, "UN") ||
           !strcmp2(token, "UNF") || !strcmp2(token, "UNFO") ||
           !strcmp2(token, "UNFOR") || !strcmp2(token, "UNFORM") ||
           !strcmp2(token, "UNFORMA") || !strcmp2(token, "UNFORMAT") ||
           !strcmp2(token, "UNFORMATT") || !strcmp2(token, "UNFORMATTE") ||
           !strcmp2(token, "UNFORMATTED"))
         {
           if (isFileType && fileType != P3D_DAT)
             {
                fprintf(stderr, "ReadP3DFile: %s, double file format spec.\n", p3dname);
                valid = 0;
                break; /* get out of the while loop */ 
             }
           isFileType = 1;
           fileType = P3D_DAT;
           continue;
         }
       if (!strcmp2(token, "BI") || !strcmp2(token, "BIN") ||
           !strcmp2(token, "BINA") || !strcmp2(token, "BINAR") ||
           !strcmp2(token, "BINARY"))
         {
           if (isFileType && fileType != P3D_BIN)
             {
                fprintf(stderr, "ReadP3DFile: %s, double file format spec.\n", p3dname);
                valid = 0;
                break; /* get out of the while loop */ 
             }
           isFileType = 1;
           fileType = P3D_BIN;
           continue;
         }


       /* for data permutation */
       if (!strcmp2(token, "P") || !strcmp2(token, "PL") ||
           !strcmp2(token, "PLA") || !strcmp2(token, "PLAN") ||
           !strcmp2(token, "PLANE") || !strcmp2(token, "PLANES"))
         {
           if (isPermutation && permutation != P3D_PLANE)
             {
                fprintf(stderr, "ReadP3DFile: %s, double permutation spec.\n", p3dname);
                valid = 0;
                break; /* get out of the while loop */ 
             }
           isPermutation = 1;
           permutation = P3D_PLANE;
           continue;
         }
       if (!strcmp2(token, "W") || !strcmp2(token, "WH") ||
           !strcmp2(token, "WHO") || !strcmp2(token, "WHOL") ||
           !strcmp2(token, "WHOLE"))
         {
           if (isPermutation && permutation != P3D_WHOLE)
             {
                fprintf(stderr, "ReadP3DFile: %s, double permutation spec.\n", p3dname);
                valid = 0;
                break; /* get out of the while loop */ 
             }
           isPermutation = 1;
           permutation = P3D_WHOLE;
           continue;
         }

       /* for CHECK or not */
       if (!strcmp2(token, "C") || !strcmp2(token, "CH") ||
           !strcmp2(token, "CHE") || !strcmp2(token, "CHEC") ||
           !strcmp2(token, "CHECK"))
         {
           if (isCheck && check != P3D_CHECK)
             {
                fprintf(stderr, "ReadP3DFile: %s, double check spec.\n", p3dname);
                valid = 0;
                break; /* get out of the while loop */ 
             }
           isCheck = 1;
           check = P3D_CHECK;
           continue;
         }
       if (!strcmp2(token, "NOC") || !strcmp2(token, "NOCH") ||
           !strcmp2(token, "NOCHE") || !strcmp2(token, "NOCHEC") ||
           !strcmp2(token, "NOCHECK"))
         {
           if (isCheck && check != P3D_NOCHECK)
             {
                fprintf(stderr, "ReadP3DFile: %s, double check spec.\n", p3dname);
                valid = 0;
                break; /* get out of the while loop */ 
             }
           isCheck = 1;
           check = P3D_NOCHECK;
           continue;
         }

       /* for Jacobian spec */
           /* jacobian is not implemented */
       if (!strcmp2(token, "J") || !strcmp2(token, "JA") ||
           !strcmp2(token, "JAC") || !strcmp2(token, "JACO") ||
           !strcmp2(token, "JACOB") || !strcmp2(token, "JACOBI") ||
           !strcmp2(token, "JACOBIA") || !strcmp2(token, "JACOBIAN"))
         {
           /* 
           isJacobian = 1;
           check = P3D_JACOBIAN;
           continue;
           */
           fprintf(stderr, "ReadP3DFile: %s, Jacobian is unimplemented\n", p3dname);
           valid = 0;
           break;
         }
       if (!strcmp2(token, "NOJ") || !strcmp2(token, "NOJA") ||
           !strcmp2(token, "NOJAC") || !strcmp2(token, "NOJACO") ||
           !strcmp2(token, "NOJACOB") || !strcmp2(token, "NOJACOBI") ||
           !strcmp2(token, "NOJACOBIA") || !strcmp2(token, "NOJACOBIAN"))
         {
           /*
           if (isJacobian)
             {
                fprintf(stderr, "ReadP3DFile: %s, double Jacobian spec.\n", p3dname);
                valid = 0;
                break; 
             }
           isJacobian = 1;
           check = P3D_NOJACOBIAN;
           */
           /* this is default */
           continue;
         }

       /* for blank spec */
       if (!strcmp2(token, "BL") || !strcmp2(token, "BLA") ||
           !strcmp2(token, "BLAN") || !strcmp2(token, "BLANK"))
         {
           if (isBlank && blank != P3D_BLANK)
             {
                fprintf(stderr, "ReadP3DFile: %s, double Blank spec.\n", p3dname);
                valid = 0;
                break; /* get out of the while loop */ 
             }
           isBlank = 1;
           blank = P3D_BLANK;
           continue;
         }
       if (!strcmp2(token, "NOB") || !strcmp2(token, "NOBL") ||
           !strcmp2(token, "NOBLA") || !strcmp2(token, "NOBLAN") ||
           !strcmp2(token, "NOBLANK"))
         {
           if (isBlank && blank != P3D_NOBLANK)
             {
                fprintf(stderr, "ReadP3DFile: %s, double Blank spec.\n", p3dname);
                valid = 0;
                break; /* get out of the while loop */ 
             }
           isBlank = 1;
           blank = P3D_NOBLANK;
           continue;
         }

       /* for Q file */
       if ( !strncmp2(token, "Q=", 2) )
         {
           p3d_set *curset = *sets + *nSets - 1; /* points to the current set */
           int nQ = curset->nQ; /* the number of Q files so far */
           p3d_q **qlistptr = &(curset->qlist); /* points to the qlist */

           /* if there is a filename */
           if (!token[2])
             {
                fprintf(stderr, "ReadP3DFile: %s, missing Q file name.\n", p3dname);
                valid = 0;
                break; /* get out of the while loop */ 
             }
           
           /* alloc a storage for qlist and update the values */
           /* reset the array of qlist */
           if (nQ == 0)
             {
               *qlistptr = (p3d_q *) malloc(sizeof(p3d_q));
             }
           else
             {
               *qlistptr = (p3d_q *) realloc(*qlistptr, (nQ + 1) * sizeof(p3d_q));
             }

           /* if memory alloc is OK, then */
           if (!qlistptr)
             {
               fprintf(stderr, "unable to alloc memory\n");
               valid = 0;
               break;
             }

           /* use the old nQ value for array index */
           /* process the Q file spec */
           strcpy((*qlistptr)[nQ].name, token+2);
           (*qlistptr)[nQ].isMDataset = isMDataset;
           (*qlistptr)[nQ].fileType = fileType;
           (*qlistptr)[nQ].permutation = permutation; 
           (*qlistptr)[nQ].check = check;
           (*qlistptr)[nQ].jacobian = jacobian;

           /* increment the number of q file for the current p3d set */
           (curset->nQ)++;

           /* reset the flags exclusive to Q files */
           isFileType = 0;
           isPermutation = 0;
           isCheck = 0;
           isJacobian = 0;

           continue;
         }

       /* for FUNCTION file */
       if (!strncmp2(token, "F=", 2) || !strncmp2(token, "FU=", 3) ||
           !strncmp2(token, "FUN=", 4) || !strncmp2(token, "FUNC=", 5) ||
           !strncmp2(token, "FUNCT=", 6) || !strncmp2(token, "FUNCTI=", 7) ||
           !strncmp2(token, "FUNCTIO=", 8) || !strncmp2(token, "FUNCTION=", 9))
         {
           p3d_set *curset = *sets + *nSets - 1; /* points to the current set */
           int nFunc = curset->nFunc; /* the number of func files so far */
           p3d_func **funclistptr = &(curset->funclist); /* points to the funclist */
           int i = 0;

           /* search for the index of the file name */
           while(token[i++] != '=')
               ;
           /* if there is a filename */
           if (!token[i])
             {
                fprintf(stderr, "ReadP3DFile: %s, missing FUNCTION file name.\n",
                         p3dname);
                valid = 0;
                break; /* get out of the while loop */ 
             }
           
           /* alloc a storage for qlist and update the values */
           /* reset the array of qlist */
           if (nFunc == 0)
             {
               *funclistptr = (p3d_func *) malloc(sizeof(p3d_func));
             }
           else
             {
               *funclistptr = (p3d_func *) realloc(*funclistptr,
                                      (nFunc + 1) * sizeof(p3d_func));
             }

           /* if memory alloc is OK, then */
           if (!funclistptr)
             {
               fprintf(stderr, "unable to alloc memory\n");
               valid = 0;
               break;
             }

           /* use the old nFunc value for array index */
           /* process the function file spec */
           strcpy((*funclistptr)[nFunc].name, token+i);
           (*funclistptr)[nFunc].fileType = fileType;
           (*funclistptr)[nFunc].permutation = permutation; 

           /* increment the number of function file for the current p3d set */
           (curset->nFunc)++;

           /* reset default values */
           isFileType = 0;
           isPermutation = 0;

           continue;
         }


       /* for GRID file */
       if (!strncmp2(token, "X=", 2) || !strncmp2(token, "XY=", 3) ||
           !strncmp2(token, "XYZ=", 4))
         {
           p3d_set *curset = *sets + *nSets - 1; /* points to the current set */
           p3d_grid **gridptr = &(curset->grid); /* points to the grid spec */
           int i = 0;

           while(token[i++] != '=')
               ;

           /* if there is a filename */
           if (!token[i])
             {
               fprintf(stderr, "ReadP3DFile: %s, missing XYZ file name.\n", p3dname);
               valid = 0;
               break; /* get out of the while loop */ 
             }

           /* it's an error to specify double XYZ for a single set */
           if (curset->isGrid)
             {
               fprintf(stderr, "ReadP3DFile: %s, double XYZ file spec.\n", p3dname);
               valid = 0;
               break; /* get out of the while loop */ 
             }

           /* alloc memory for grid file spec */
           *gridptr = (p3d_grid *) malloc(sizeof(p3d_grid));

           /* if memory alloc is OK. then turn on the isGrid */
           if (!gridptr)
             {
               fprintf(stderr, "unable to alloc memory\n");
               valid = 0;
               break;
             }

           curset->isGrid = 1;

           /* process the grid file spec */
           strcpy((*gridptr)->name, token + i);
           (*gridptr)->fileType = fileType;
           (*gridptr)->permutation = permutation; 
           (*gridptr)->blank = blank;

           /* reset default values */
           isFileType = 0;
           isPermutation = 0;
           isBlank = 0;

           continue;
         }

       if (!strcmp2(token, "READ"))
         {
           p3d_set *curset = *sets + *nSets - 1;
           p3d_set *temp;
           int k;

           /* check the set processed so far */
           if (!curset->isGrid)
             {
               fprintf(stderr, "ReadP3DFile: in %s XYZ file missing.\n", p3dname);
               valid = 0;
               break;
             }
           else if(!curset->nQ && !curset->nFunc)
             {
               fprintf(stderr, "ReadP3DFile: %s, no Q or function file.\n", p3dname);
               valid = 0;
               break;
             }

           curset->ndim = ndim;
           curset->isMGrid = isMGrid;

           /* another set begins here */
           if (!(temp = (p3d_set *) malloc(sizeof(p3d_set) * (*nSets + 1))))
             {
               fprintf(stderr, "Unable to alloc memory, aborted\n");
               valid = 0;
               break; /* get out of the while loop */ 
             }
           for (k = 0; k < *nSets; k++)
             {
               temp[k] = (*sets)[k];
             }
           free(*sets); 
           *sets = temp;
           (*nSets)++;
           curset = *sets + *nSets - 1;

           /* initialize some values */
           curset->ndim = 3;
           curset->isMGrid = 0;
           curset->isGrid = 0;
           curset->grid = NULL;
           curset->nQ = 0;
           curset->qlist = NULL;
           curset->nFunc = 0;
           curset->funclist = NULL;

           /* reset default values */
           isNdim = 0, ndim = 3;
           isMDataset = 0;
           isMGrid = 0;
           isFileType = 0, fileType = P3D_BIN;
           isPermutation = 0, permutation = P3D_WHOLE;
           isCheck = 0, check = P3D_NOCHECK;
           isJacobian = 0, jacobian = P3D_NOJACOBIAN;
           isBlank = 0, blank = P3D_NOBLANK;

           continue;
         }
       
       fprintf(stderr, "ReadP3DFile: %s, unknown spec %s.\n", p3dname, token);
       valid = 0;
       break; /* get out of the while loop */ 
    } /* while */

   fclose(inFile);

   if (!valid || status == -1)
     {
       fprintf(stderr, "ReadP3DFile: %s, file format error.\n", p3dname);
       return 0;
     }

   /* also, check current set, about nQ, nFunc, and isGrid, to see
      if there is any error */
   if ((*sets + *nSets - 1)->isGrid == 0)
     {
       fprintf(stderr, "ReadP3DFile: %s, XYZ missing in number %d read command.\n", p3dname, *nSets);
       return 0;
     }
   else if((*sets + *nSets - 1)->nQ == 0 && (*sets + *nSets - 1)->nFunc == 0)
     {
       fprintf(stderr, "ReadP3DFile: %s, no Q or function file.\n", p3dname);
       return 0;
     }
   else
     {
       (*sets + *nSets - 1)->ndim = ndim;
       (*sets + *nSets - 1)->isMGrid = isMGrid;
     }

   return 1;
} /* parseP3DMeta */

/* using row major order arrangement */
#ifdef PROTO
static void putIblank(int iblank, int **ipp, long *indices, long *dims,
        int ndim, int igrid) 
#else
static void putIblank(iblank, ipp, indices, dims, ndim, igrid) 
int iblank;
int **ipp;
long *indices;
long *dims;
int ndim;  /* rank */
int igrid;
#endif
/* return 0 when failed */
{
  int i;
  long offset;

  offset = indices[ndim - 1];
  for (i = ndim - 1; i > 0; i--)
     {
       offset = offset * dims[i - 1] + indices[i - 1];
     }
  ipp[igrid][offset] = iblank;

  return;
} /* putIblank */

#ifdef PROTO
static void getIblank(int *iblank, int **ipp, long *indices,
                                  long *dims, int ndim, int igrid) 
#else
static void getIblank(iblank, ipp, indices, dims, ndim, igrid)
int *iblank;
int **ipp;
long *indices;
long *dims;
int ndim;
int igrid;
#endif
/* returns 0 when failed */
{
  int i;
  long offset;

  offset = indices[ndim - 1];
  for (i = ndim - 1; i > 0; i--)
     {
       offset = offset * dims[i - 1] + indices[i - 1];
     }
  *iblank = ipp[igrid][offset];

  return;
} /* getIblank */

#ifdef PROTO
static void freeiblank(int ngrid, int **ipp)
#else
static void freeiblank(ngrid, ipp)
int ngrid;
int **ipp;
#endif
{
  int i;

  for (i = 0; i < ngrid; i++)
     free(ipp[i]);
  free(ipp);

  return;
}

#ifdef PROTO
static void freedims(int ngrid, long **dimsptr)
#else
static void freedims(ngrid, dimsptr)
int ngrid;
long **dimsptr;
#endif
{
  int i;

  for (i = 0; i < ngrid; i++)
     free(dimsptr[i]);
  free(dimsptr);

  return;
}

#ifdef PROTO
static int RdFmtXYZ(int ndim, int isMGrid, long ***dimsptr,
                               p3d_grid *gridptr, ObjPtr **formptr, int ***ipp)
#else
static int RdFmtXYZ(ndim, isMGrid, dimsptr, gridptr, formptr, ipp)
int ndim;
int isMGrid;
long ***dimsptr;
p3d_grid *gridptr;
ObjPtr **formptr;
int ***ipp;
#endif
{
  FILE *inFile;
  int ngrid;     /* number of grids */
  long *indices;
  real *bounds;
  int i, j;
  int n;
  char *name;  /* dataset name starting point */
  int namelen;
  int repeat;
  double dval;

  if (!(inFile = fopen(gridptr->name, "r")))
    {
      fprintf(stderr, "Unable to open %s, aborted\n", gridptr->name);
      return 0;
    }

  /* determine the dataset name now */
  for (i = (int) strlen(gridptr->name) - 1; i >= 0 && gridptr->name[i] != '/'; i--)
     ;
  if (i == -1 || gridptr->name[i] == '/')
    i++;
  name = gridptr->name + i;
  for (namelen = 0; name[namelen] != '\0' && name[namelen] != '.'; namelen++)
     ;

  if (isMGrid)
    {
      SkipBlanksAndCommas(inFile);
      if (fscanf(inFile, "%d", &ngrid) != 1 || ngrid <= 0)
        {
          fprintf(stderr, "%s format error, invalid NGRID value\n", gridptr->name);
          fclose(inFile);
          return 0;
        } 
    }
  else
    {
      ngrid = 1;
    }
  
  /* alloc dimsptr and indices storage */
  if (!(indices = (long *) malloc(ndim * sizeof(long))))
    {
      fprintf(stderr, "Unable to alloc memory\n");
      fclose(inFile);
      return 0;
    }
  if (!(*dimsptr = (long **) malloc(ngrid * sizeof(long *))))
    {
      fprintf(stderr, "Unable to alloc memory\n");
      free(indices);
      fclose(inFile);
      return 0;
    }
  repeat = 0;
  for (i = 0; i < ngrid; i++)
    {
      if (!((*dimsptr)[i] = (long *) malloc(ndim * sizeof(long))))
        {
          fprintf(stderr, "Unable to alloc memory\n");
          free(indices);
          freedims(i, *dimsptr);
          fclose(inFile);
          return 0;
        }

      for (j = 0; j < ndim; j++)
         {
           if (!repeat)
             {
                if ((repeat = getValue(inFile, &dval)) <= 0 || (int) dval <= 0)
                  {
                    fprintf(stderr, "Invalid dimension value in %s\n",
                            gridptr->name);
                    free(indices);
                    freedims(i, *dimsptr);
                    fclose(inFile);
                    return 0;
                  }
             }
           repeat--;
           *((*dimsptr)[i] + j) = (long) dval; 
         }
    }

  /* alloc strorage for pointer to bounds */
  if (!(bounds = (real *) malloc(ndim * 2 * sizeof(real))))
    {
      fprintf(stderr, "Unable to alloc memory\n");
      free(indices);
      freedims(ngrid, *dimsptr);
      fclose(inFile);
      return 0;
    }
  /* alloc storage for pointers to dataforms */
  if (!(*formptr = (ObjPtr *) malloc(ngrid * sizeof(ObjPtr))))
    {
      fprintf(stderr, "Unable to alloc memory\n");
      free(indices);
      free(bounds);
      freedims(ngrid, *dimsptr);
      fclose(inFile);
      return 0;
    }

  /* alloc iblankptr if IBLANK */
  if (gridptr->blank == P3D_BLANK)
    {
      if (!(*ipp = (int **) malloc(ngrid * sizeof(int *))))
        {
          fprintf(stderr, "Unable to alloc memory\n");
          free(indices);
          free(bounds);
          free(*formptr);
          freedims(ngrid, *dimsptr);
          fclose(inFile);
          return 0;
        }

    }

  repeat = 0;
  for (n = 0; n < ngrid; n++)
    {
      long size, count; /* number of grid values promised */
      ObjPtr dataset;
      char datasetname[MAXNAMELEN];
      int whichcomponent;

      strncpy(datasetname, name, namelen);
      datasetname[namelen] = '\0';
      if (isMGrid)
        {
          sprintf(datasetname + namelen, "%d", n);
        }

      /* setup a dataset for the grid data */
      dataset = NewStructuredDataset(datasetname, ndim, (*dimsptr)[n], ndim);
      if (!SetCurField(FIELD1, dataset))
        {
          fprintf(stderr, "Unable to SetCurField\n");
          free(indices);
          free(bounds);
          free(*formptr);
          freedims(ngrid, *dimsptr);
          if (gridptr->blank == P3D_BLANK)
            {
              freeiblank(n-1, *ipp);
            }
          fclose(inFile);
          return 0;
        }

      size = 1;
      for (i = 0; i < ndim; i++)
         {
           size *= (*dimsptr)[n][i];
         }
      size *= (long)(ndim + (gridptr->blank == P3D_BLANK));

      if (gridptr->blank == P3D_BLANK)
        {
          /* alloc storage for the iblank arrays */
          if (!((*ipp)[n] = (int *) malloc(size * sizeof(int))))
            {
              fprintf(stderr, "Unable to alloc memory\n");
              freeiblank(n, *ipp);
              free(indices);
              free(bounds);
              free(*formptr);
              freedims(ngrid, *dimsptr);
              fclose(inFile);
              return 0;
            }
        }

      for (i = 0; i < ndim; i++)
         {
           indices[i] = 0;
         }
      whichcomponent = 0;
      /* read in all the grid values */
      for (count = 0; count < size; count++)
        {
          int first = 1;

          if (!repeat)
            {
              if ((repeat = getValue(inFile, &dval)) <= 0)
                {
                  fprintf(stderr, "Error reading %s, invalid numeric value\n",
                           gridptr->name);
                  free(indices);
                  free(bounds);
                  free(*formptr);
                  freedims(ngrid, *dimsptr);
                  if (gridptr->blank == P3D_BLANK)
                    {
                      freeiblank(n + 1, *ipp);
                    }
                  fclose(inFile);
                  return 0;
                }
            }

          repeat--;
          if (whichcomponent < ndim) /* read grid values */
            {
              PutFieldComponent(FIELD1, whichcomponent, indices, (real) dval);  
              for (j = 0; first && j < ndim; j++)
                 first = indices[j] == 0;

              if (first)
                {
                  bounds[whichcomponent * 2] = (real) dval;
                  bounds[whichcomponent * 2 + 1] = (real) dval;
                }
              else
                {
                  if (dval < bounds[whichcomponent * 2])
                    bounds[whichcomponent * 2] = (real) dval;
                  else if (dval > bounds[whichcomponent * 2 + 1])
                    bounds[whichcomponent * 2 + 1] = (real) dval;
                }
            }
          else /* read iblank values */
            {
              putIblank((int) dval, *ipp, indices, (*dimsptr)[n], ndim, n);
            }
          /* adjust the indices and whichcomponent */
          if (gridptr->permutation == P3D_WHOLE)
            {
              for (j = 0; j < ndim; j++)
                 {
                   indices[j]++;
                   if (indices[j] == (*dimsptr)[n][j])
                     {
                       indices[j] = 0;
                       continue;
                     }
                   break;
                 }
              if (j == ndim) /* all indices are set to zero now */ 
                {
                  whichcomponent++;
                }
            }
          else  /* P3D_PLANE */
            {
              for (j = 0; j < ndim - 1; j++)
                 {
                   indices[j]++;
                   if (indices[j] == (*dimsptr)[n][j])
                     {
                       indices[j] = 0;
                       continue;
                     }
                   break;
                 }
              if (j == ndim - 1)  
                {
                  whichcomponent++;
                  if ((gridptr->blank == P3D_BLANK) ? 
                     (whichcomponent == ndim + 1) : (whichcomponent == ndim))
                  /* leave a space for reading iblanks */
                    {
                      whichcomponent = 0;
                      indices[j]++;
                    }
                }
            }
        } /* for read grid values */

     (*formptr)[n] = NewCurvilinearDataForm(datasetname, ndim, (*dimsptr)[n],
                    bounds, dataset);

    } /* outer for */

  /* indices and bounds are no longer of any use */
  free(indices);
  free(bounds);
  fclose(inFile);
  return n;
} /* RdFmtXYZ */

#ifdef PROTO
static int RdFmtSol(int ndim, int isMGrid, int ngrid, int blank,
                 long **dimsptr, p3d_q *qptr, ObjPtr *formptr, int **ipp)
#else
static int RdFmtSol(ndim, isMGrid, ngrid, blank, dimsptr, qptr, formptr, ipp)
int ndim;
int isMGrid;
int ngrid;
int blank;
long **dimsptr;
p3d_q *qptr;
ObjPtr *formptr;
int **ipp;
#endif
{
  FILE *inFile;
  int i, j, n;
  char *name;
  long *indices;
  int numsets; /* number of datasets read so far, for multiple datasets in a file*/
  int namelen; /* the length of dataset name going to be used */
  int repeat;  /* to deal with <num>*<value> format */
  double dval;

  if (!(inFile = fopen(qptr->name, "r")))
    {
      fprintf(stderr, "Unable to open %s, aborted\n", qptr->name);
      return 0;
    }

  if (!(indices = (long *) malloc(ndim * sizeof(long))))
    {
      fprintf(stderr, "Unable to alloc memory, aborted\n");
      fclose(inFile);
      return 0;
    }

  /* determine the dataset name from the file name */
  for (i = (int) strlen(qptr->name) - 1; i >= 0 && qptr->name[i] != '/'; i--)
     ;
  if (i == -1 || qptr->name[i] == '/')
    i++;
  name = qptr->name + i;
  for (namelen = 0; name[namelen] != '\0' && name[namelen] != '.'; namelen++)
     ;

  numsets = 0;

  do
    {
      repeat = 0;
      /* get ngrid value if it is a MGRID q file */
      if (isMGrid)
        {
           repeat = getValue(inFile, &dval);
           if (repeat == EOF)
             {
              if (numsets == 0)
                 {
                  fprintf(stderr, "Error in %s: empty file\n", qptr->name);
                 }
              fclose(inFile);
              free(indices);
              return (numsets ? ngrid : 0);
             }
          else if (repeat == 0 || (n = (int) dval) <= 0)
             {
              fprintf(stderr, "Error in %s: Invalid NGRID spec.\n", qptr->name);
              fclose(inFile);
              free(indices);
              return 0;
             }
          repeat--;
        }
      else
        {
          n = 1;
        }

      /* if ngrid != this file's ngrid then error */
      if (ngrid != n)
        {
          fprintf(stderr, "Error in %s: NGRID value does not match its grid\n",
                                                             qptr->name);
          fclose(inFile);
          free(indices);
          return 0;
          
        }
      /* if dims does not match the dims read in XYZ file then error */
      for (n = 0; n < ngrid; n++)
        {
          for (i = 0; i < ndim; i++)
            {
              if (!repeat)
                {
                  if ((repeat = getValue(inFile, &dval)) <= 0)
                    {
                      /* if this is not multiple grid, then the first
                      dimension value is used to indicate whether there is
                      more datasets or not */
                      if (!isMGrid && i == 0 && repeat == EOF)
                        {
                         if (numsets == 0)
                           {
                            fprintf(stderr, "Error in %s: empty file\n", qptr->name);
                           }
                          fclose(inFile);
                          free(indices);
                          return (numsets ? ngrid : 0);
                        }
                      fprintf(stderr, "Invalid dimension value in %s\n", qptr->name);
                      fclose(inFile);
                      free(indices);
                      return 0;
                    }
                }
              repeat--;
              if ((long) dval != dimsptr[n][i])
                {
                  fprintf(stderr,
                  "Dimensions mismatch between %s and its XYZ file\n", qptr->name);
                  fclose(inFile);
                  free(indices);
                  return 0;
                }
            }
        }
    
      for (n = 0; n < ngrid; n++)
        {
          long size, count; /* number of data values promised */
          ObjPtr density, pressure, dataset;
          char datasetname[MAXNAMELEN];
          char densityname[MAXNAMELEN];
          char pressurename[MAXNAMELEN];
          double time;
          int whichcomponent;
          ObjPtr whichdataset;
    
          /* process the FAMACH..TIME line */
          for (i = 1; i <= 4; i++)
            {
              if (!repeat)
                {
                  if ((repeat = getValue(inFile, &dval)) <= 0)
                    {
                     fprintf(stderr,
                     "Error in %s: invalid FSMACH,ALPHA,RE,TIME line\n", qptr->name);
                     free(indices);
                     fclose(inFile);
                     return 0;
                    }
                }
              repeat--;
              if (i == 4)
                {
                  time = dval;
                }
            }
    
          /* setup datasets */
          strncpy(datasetname, name, namelen);
          datasetname[namelen] = '\0';
          if (isMGrid)
            {
              sprintf(datasetname + namelen, "%d", n);
            }
          sprintf(densityname, "%s%s", datasetname, " Density");
          sprintf(pressurename, "%s%s", datasetname, " Pressure");
          density = NewStructuredDataset(densityname, ndim, dimsptr[n], 0);
          pressure = NewStructuredDataset(pressurename, ndim, dimsptr[n], 0);
          dataset = NewStructuredDataset(datasetname, ndim, dimsptr[n], ndim);

          size = 1;
          for (i = 0; i < ndim; i++)
             size *= dimsptr[n][i];
          size *= ndim + 2;  /* includes density and pressure */
          for (i = 0; i < ndim; i++)
             {
               indices[i] = 0;
             }
          whichcomponent = 0;
          whichdataset = density;
    
          /* read in all the q values */
          for (count = 0; count < size; count++)
            {
              int iblank = 1;
    
              if (!repeat)
                {
                  if ((repeat = getValue(inFile, &dval)) <= 0)
                    {
                      fprintf(stderr, "Error reading %s, invalid numeric value\n",
                                  qptr->name);
                      free(indices);
                      fclose(inFile);
                      return 0;
                    }
                }
              repeat--;
              /* do check of density and pressure, and iblanks here */
              if (qptr->check == P3D_CHECK && (whichdataset == pressure ||
                  whichdataset == density))
                {
                  if (dval < 0.0)
                    dval = 0.0;
                }
              if (blank == P3D_BLANK)
                {
                   getIblank(&iblank, ipp, indices, dimsptr[n], ndim, n);
                }
    
              if (!SetCurField(FIELD1, whichdataset))
                {
                  fprintf(stderr, "Unable to SetCurField\n");
                  free(indices);
                  fclose(inFile);
                  return 0;
                }
    
              PutFieldComponent(FIELD1, whichcomponent, indices, 
                          iblank == 0 ? (real) missingData : (real) dval);  
    
              /* adjust the indices, whichdataset, and whichcomponent */
              if (qptr->permutation == P3D_WHOLE)
                {
                  for (j = 0; j < ndim; j++)
                     {
                       indices[j]++;
                       if (indices[j] == dimsptr[n][j])
                         {
                           indices[j] = 0;
                           continue;
                         }
                       break;
                     }
                  if (j == ndim) /* all indices are set to zero now */ 
                    {
                      if (whichdataset == dataset)
                        {
                          whichcomponent++;
                        }
                      else
                        {
                          if (whichdataset == density)
                            whichdataset = pressure;
                          else
                            whichdataset = dataset;
                        }
                    }
                }
              else  /* P3D_PLANE */
                {
                  for (j = 0; j < ndim - 1; j++)
                     {
                       indices[j]++;
                       if (indices[j] == dimsptr[n][j])
                         {
                           indices[j] = 0;
                           continue;
                         }
                       break;
                     }
                  if (j == ndim - 1)  
                    {
                      if (whichdataset == density)
                        whichdataset = pressure;
                      else if (whichdataset == pressure)
                        whichdataset = dataset;
                      else /* whichdataset == dataset */
                        {
                          whichcomponent++;
                          if (whichcomponent == ndim)
                            {
                              whichdataset = density;
                              whichcomponent = 0;
                              indices[j]++;
                            }
                        }
                    }
                }
            } 
    
          SetDatasetForm(density, formptr[n]);
          SetDatasetForm(pressure, formptr[n]);
          SetDatasetForm(dataset, formptr[n]);
          if (qptr->isMDataset)
            {
              RegisterTimeDataset(density, (real) time);
              RegisterTimeDataset(pressure, (real) time);
              RegisterTimeDataset(dataset, (real) time);
            }
          else
            {
              RegisterDataset(density);
              RegisterDataset(pressure);
              RegisterDataset(dataset);
            }
        } /* outer for */
      numsets++;
    } while(qptr->isMDataset);

  free(indices);
  fclose(inFile);
  return ngrid;
} /* RdFmtSol */

#ifdef PROTO
static int RdFmtFun(int ndim, int isMGrid, int ngrid, int blank,
                long **dimsptr, p3d_func *funcptr, ObjPtr *formptr, int **ipp)
#else
static int RdFmtFun(ndim, isMGrid, ngrid, blank, 
                              dimsptr, funcptr, formptr, ipp)
int ndim;
int isMGrid;
int ngrid;
int blank;
long **dimsptr;
p3d_func *funcptr;
ObjPtr *formptr;
int **ipp;
#endif
{
  FILE *inFile;/* the current function file being processed */
  int i, j, n;
  char *name; /* points to the portion of function file name after the last / */
  long *indices;
  int *nvar;  /* number of variables of this function */
  int namelen;
  int repeat;
  double dval;

  if (!(inFile = fopen(funcptr->name, "r")))
    {
      fprintf(stderr, "Unable to open %s, aborted\n", funcptr->name);
      return 0;
    }
  if (isMGrid)
    {
      SkipBlanksAndCommas(inFile);
      if (fscanf(inFile, "%d", &n) != 1 || n <= 0)
        {
          fprintf(stderr, "Error in %s: invalid NGRID value\n", funcptr->name);
          fclose(inFile);
          return 0;
        }
    }
  else
    {
      n = 1;
    }
  /* if ngrid != this file's ngrid then error */
  if (ngrid != n)
    {
      fprintf(stderr, "Error in %s: NGRID value does not match its grid\n",
                                                                 funcptr->name);
      fclose(inFile);
      return 0;
    }
  if (!(indices = (long *) malloc(ndim * sizeof(long))))
    {
      fprintf(stderr, "Unable to alloc memory, aborted\n");
      fclose(inFile);
      return 0;
    }
  if (!(nvar = (int *) malloc(ngrid * sizeof(int))))
    {
      fprintf(stderr, "Unable to alloc memory, aborted\n");
      free(indices);
      fclose(inFile);
      return 0;
    }

  /* if dims does not match the dims read in XYZ file then error */
  repeat = 0;
  for (n = 0; n < ngrid; n++)
    {
      for (i = 0; i < ndim + 1; i++) /* nvar follows dimension spec's */
        {
          if (!repeat)
            {
              if ((repeat = getValue(inFile, &dval)) <= 0)
                {
                  fprintf(stderr, "Invalid dim/nvar value in %s\n", funcptr->name);
                  free(indices);
                  free(nvar);
                  fclose(inFile);
                  return 0;
                }
            }
          repeat--;
          if (i < ndim)  /* the value is dimension */
            {
              if ((long) dval != dimsptr[n][i])
                {
                  fprintf(stderr, "Dimensions mismatch between %s"
                                      " and its XYZ file\n", funcptr->name);
                  free(indices);
                  free(nvar);
                  fclose(inFile);
                  return 0;
                }
            }
          else /* i = ndim, the value is of nvar */
            {
              nvar[n] = (int) dval;
            }
        }
    }

  /* determine the dataset name */
  for (i = (int) strlen(funcptr->name) - 1; i >= 0 && funcptr->name[i] != '/'; i--)
     ;
  if (i == -1 || funcptr->name[i] == '/')
    i++;
  name = funcptr->name + i;
  for (namelen = 0; name[namelen] != '\0' && name[namelen] != '.'; namelen++)
     ;

  repeat = 0;
  for (n = 0; n < ngrid; n++)
    {
      long size, count; /* number of data values promised */
      ObjPtr dataset;
      char datasetname[MAXNAMELEN];
      int whichcomponent;

      strncpy(datasetname, name, namelen);
      datasetname[namelen] = '\0';
      if (isMGrid)
        {
          sprintf(datasetname + namelen, "%d", n);
        }

      size = 1;
      for (i = 0; i < ndim; i++)
         size *= dimsptr[n][i];
      size *= nvar[n];
      for (i = 0; i < ndim; i++)
         {
           indices[i] = 0;
         }

      /* setup datasets */
      dataset = NewStructuredDataset(datasetname, ndim, dimsptr[n],
                                              nvar[n] == 1 ? 0 : nvar[n]);
      if (!SetCurField(FIELD1, dataset))
        {
          fprintf(stderr, "Unable to SetCurField\n");
          free(indices);
          free(nvar);
          fclose(inFile);
          return 0;
        }
      whichcomponent = 0;

      /* read in all the func values */
      for (count = 0; count < size; count++)
        {
          int iblank = 1;
     
          if (!repeat)
            {
              if ((repeat = getValue(inFile, &dval)) <= 0)
                {
                  fprintf(stderr, "Error reading %s, invalid numeric value\n",
                                funcptr->name);
                  free(indices);
                  free(nvar);
                  fclose(inFile);
                  return 0;
                }
            }
          repeat--;
          if (blank == P3D_BLANK)
            {
               getIblank(&iblank, ipp, indices, dimsptr[n], ndim, n);
            }
    
          PutFieldComponent(FIELD1, whichcomponent, indices, 
                  iblank == 0 ? (real) missingData : (real) dval);  

          /* adjust the indices and whichcomponent */
          if (funcptr->permutation == P3D_WHOLE)
            {
              for (j = 0; j < ndim; j++)
                {
                  indices[j]++;
                  if (indices[j] == dimsptr[n][j])
                    {
                      indices[j] = 0;
                      continue;
                    }
                  break;
                }
              if (j == ndim) /* all indices are set to zero now */
                {
                  whichcomponent++;
                }
            }
          else  /* P3D_PLANE */
            {
              for (j = 0; j < ndim - 1; j++)
                {
                  indices[j]++;
                  if (indices[j] == dimsptr[n][j])
                    {
                      indices[j] = 0;
                      continue;
                    }
                  break;
                }
              if (j == ndim - 1 && ++whichcomponent == nvar[n])
                {
                  indices[j]++;
                  whichcomponent = 0;
                }
            }
        }     /* for size */

      SetDatasetForm(dataset, formptr[n]);
      RegisterDataset(dataset);
    } /* outer for */

  free(indices);
  free(nvar);
  fclose(inFile);
  return ngrid;
} /* RdFmtFun */

/*********************unformatted p3d reading routines, start *********************/
/* only available when there's fortran compiler */

#ifdef FORTRAN

#ifdef PROTO
static int RdUnfmtXYZ(int ndim, int isMGrid, long ***dimsptr,
                      p3d_grid *gridptr, ObjPtr **formptr, int ***ipp);
static int RdUnfmtSol(int ndim, int isMGrid, int ngrid, int blank, long **dimsptr,
		      p3d_q *qptr, ObjPtr *formptr, int **ipp);
static int RdUnfmtFun(int ndim, int isMGrid, int ngrid, int blank, long **dimsptr,
		      p3d_func *funcptr, ObjPtr *formptr, int **ipp);
#ifdef FORTRAN_
/* fortran subroutines */
extern void foropn_(int *lun, int intname[], int *length, int *opstat);
extern void forcls_(int *lun);
extern void rngrid_(int *lun, int *ngrid, int *opstat);
extern void rddims_(int *lun, int *ndim, int *ngrid, int *indims, int *opstat);
extern void rdgrid_(int *lun, int *ndim, int *indims, int *isiblk, int *iblank,
		    int *iperm, float *gdvals, long *size, int *opstat); 
extern void rdsolu_(int *lun, int *ndim, int *indims, int *iperm, 
		     float *slvals, long *size, int *opstat);
extern void rdtime_(int *lun, float *time, int *opstat);
extern void rdfunc_(int *lun, int *ndim, int *indims, int *nvar, int *iperm,
		    float *fnvals, long *size, int *opstat); 
#else
/* fortran subroutines */
extern void foropn(int *lun, int iname[], int *length, int *opstat);
extern void forcls(int *lun);
extern void rngrid(int *lun, int *ngrid, int *opstat);
extern void rddims(int *lun, int *ndim, int *ngrid, int *indims, int *opstat);
extern void rdgrid(int *lun, int *ndim, int *indims, int *isiblk, int *iblank,
		   int *iperm, float *gdvals, long *size, int *opstat); 
extern void rdsolu(int *lun, int *ndim, int *indims, int *iperm, 
		    float *slvals, long *size, int *opstat);
extern void rdtime(int *lun, float *time, int *opstat);
extern void rdfunc(int *lun, int *ndim, int *indims, int *nvar, int *iperm,
		   float *fnvals, long *size, int *opstat); 
#endif

#else

static int RdUnfmtXYZ();
static int RdUnfmtSol();
static int RdUnfmtFun();
#ifdef FORTRAN_
/* fortran subroutines */
extern void foropn_();
extern void forcls_();
extern void rngrid_();
extern void rddims_();
extern void rdgrid_();
extern void rdsolu_();
extern void rdtime_();
extern void rdfunc_();
#else
/* fortran subroutines */
extern void foropn();
extern void forcls();
extern void rngrid();
extern void rddims();
extern void rdgrid();
extern void rdsolu();
extern void rdtime();
extern void rdfunc();
#endif
#endif


/* for reading fortran unformatted grid file */
#ifdef PROTO
static int RdUnfmtXYZ(int ndim, int isMGrid, long ***dimsptr,
                               p3d_grid *gridptr, ObjPtr **formptr, int ***ipp)
#else
static int rdUnfmtXYZ(ndim, isMGrid, dimsptr, gridptr, formptr, ipp)
int ndim;
int isMGrid;
long ***dimsptr;
p3d_grid *gridptr;
ObjPtr **formptr;
int ***ipp;
#endif
{
  int ins[MAXNAMELEN]; /* ascii coding of file name */
  int namelen;         /* file name length */
  int lun = 2;         /* logical unit number of fortran opened file */
  int opstat=0;        /* operation status of fortran file op subroutine */
  int *indims, ngrid;
  int i, j;
  
/* try to open the xyz file, ascii coding of the xyz file name */
  namelen = (int) strlen(gridptr->name);
  for (i = 0; i <= namelen; i++)
     {
       ins[i] = gridptr->name[i];
     }
/* open file with fortran subroutine */
#ifdef FORTRAN_
  foropn_(&lun, ins, &namelen, &opstat);
#else
  foropn(&lun, ins, &namelen, &opstat);
#endif

  if (!opstat)
    {
      fprintf(stderr, "Unable to open file %s, aborted\n", gridptr->name);
      return 0;
    }

/* reading ngrid */
  if (isMGrid)
    {
      opstat = 0;
#ifdef FORTRAN_
      rngrid_(&lun, &ngrid, &opstat);
#else
      rngrid(&lun, &ngrid, &opstat);
#endif
      if (opstat <= 0 || ngrid <=0)
        {
	  fprintf(stderr, "%s format error, invalid NGRID value\n",
	  gridptr->name);
#ifdef FORTRAN_
          forcls_(&lun);
#else
          forcls(&lun);
#endif
	  return 0;
        }
    }
  else
    {
      ngrid = 1;
    }

/* reading dimensions */
  indims = (int *) 0;
  *dimsptr = (long **) 0;
  if (!(indims = (int *) malloc(ndim*ngrid*sizeof(int))) ||
      !(*dimsptr = (long **) malloc(ndim * sizeof(long *))))
    {
      fprintf(stderr, "Unable to alloc mem, aborted\n");
#ifdef FORTRAN_
          forcls_(&lun);
#else
          forcls(&lun);
#endif
      free(indims);
      return 0;
    }
  opstat=0;
#ifdef FORTRAN_
  rddims_(&lun, &ndim, &ngrid, indims, &opstat);
#else
  rddims(&lun, &ndim, &ngrid, indims, &opstat);
#endif
  if (opstat > 0)
    {
      for (i = 0; i < ngrid; i++)
	 {
           if (!((*dimsptr)[i] = (long *) malloc(ndim * sizeof(long))))
	     {
	       fprintf(stderr, "Unable to alloc memory, aborted\n");
	       i--;
	       opstat = 0;  /* turn off opstat to indicate failure */
	       break;
             }
	   for (j = 0; j < ndim; j++)
             {
	       *((*dimsptr)[i]+j)= (long) indims[i*ndim + j];
             }
         }
    }
  if (opstat <= 0)
    {
      fprintf(stderr, "Unable to Read Dimension Values in %s\n",
	      gridptr->name);
#ifdef FORTRAN_
          forcls_(&lun);
#else
          forcls(&lun);
#endif
      freedims(i, *dimsptr);
      free(indims);
      return 0;
    }

/* reading grid values*/
    {
      long *indices;
      real *bounds;
      char *name;   /* dataset name, extracted from file name */

      /* extracting the dataset name from file name */
      for(i = namelen -1;
	  i >= 0 && gridptr->name[i] != '/';
	  i--) ;
      if (i == -1 || gridptr->name[i] == '/')
	i++;
      name = gridptr->name + i;
      for (namelen = 0; 
	   name[namelen] != '\0' && name[namelen] != '.';
	   namelen++) ;
         
      /* memory allocation for indices, bounds, formptr, ipp  */
      indices = (long *) 0;
      bounds = (real *) 0;
      *formptr = (ObjPtr *) 0;
      *ipp = (int **) 0;
      if ( !(indices = (long *) malloc(ndim * sizeof(long))) ||
	   !(bounds = (real *) malloc(ndim * 2 * sizeof(real))) ||
	   !(*formptr = (ObjPtr *) malloc(ngrid * sizeof(ObjPtr))) ||
	   !(*ipp = (int **) malloc(ngrid *sizeof(int *))) )
           /* alloc *ipp regardless of the value of gridptr->blank, but
	      remember to free it if it is of no use */
        {
          fprintf(stderr, "Unable to alloc mem, aborted\n");
#ifdef FORTRAN_
          forcls_(&lun);
#else
          forcls(&lun);
#endif
          free(indims);
	  freedims(ngrid, *dimsptr);
	  free(*formptr);
	  free(*ipp);
	  free(indices);
	  free(bounds);
          return 0;
	}

      for(i = 0; i < ngrid; i++)
	{
          long size, count;
          float *gdvals;
	  ObjPtr dataset;
	  char datasetname[MAXNAMELEN];

	  /* create a dataset for the grid to be read in */
          strncpy(datasetname, name, namelen);
	  datasetname[namelen] = '\0';
	  if (isMGrid)
	    sprintf(datasetname + namelen, "%d", i);
          dataset=NewStructuredDataset(datasetname, ndim, (*dimsptr)[i], ndim);
	  if (!SetCurField(FIELD1, dataset))
	    {
                 fprintf(stderr, "Unable to SETCURFIELD, aborted\n");
#ifdef FORTRAN_
                 forcls_(&lun);
#else
                 forcls(&lun);
#endif
                 free(indims);
	         freedims(ngrid, *dimsptr);
		 if (gridptr->blank == P3D_BLANK)
		   {
	             freeiblank(i-1, *ipp);
		   }
                 else
		   {
		     free(*ipp);
		   }
	         free(*formptr);
	         free(indices);
	         free(bounds);
                 return 0;
	    }

          /* calculate size of one component */
          size=1;
          for(j = 0; j < ndim; j++)
           {
             size *= (*dimsptr)[i][j];
           }
	  (*ipp)[i] = (int *) 0;
          if (gridptr->blank == P3D_BLANK)
	    {
	      if (!((*ipp)[i] = (int *) malloc(size*sizeof(int))))
		{
                 fprintf(stderr, "Unable to alloc mem, aborted\n");
#ifdef FORTRAN_
                 forcls_(&lun);
#else
                 forcls(&lun);
#endif
                 free(indims);
	         freedims(ngrid, *dimsptr);
	         freeiblank(i, *ipp);
	         free(indices);
	         free(bounds);
	         free(*formptr);
                 return 0;
                }
	    }

	  /* read in grid values */
          if (!(gdvals = (float *) malloc(ndim*size*sizeof(float))))
	    {
                 fprintf(stderr, "Unable to alloc mem, aborted\n");
#ifdef FORTRAN_
                 forcls_(&lun);
#else
                 forcls(&lun);
#endif
                 free(indims);
	         freedims(ngrid, *dimsptr);
		 if (gridptr->blank == P3D_BLANK)
		   {
	             freeiblank(i, *ipp);
		   }
                 else
		   {
		     free(*ipp);
		   }
	         free(indices);
	         free(bounds);
	         free(*formptr);
                 return 0;
	    }
	  opstat=0;
#ifdef FORTRAN_
          rdgrid_(&lun, &ndim, indims+i*ndim, &gridptr->blank, (*ipp)[i],
		  &(gridptr->permutation), gdvals, &size, &opstat);
#else
          rdgrid(&lun, &ndim, indims+i*ndim, &gridptr->blank, (*ipp)[i],
		  &(gridptr->permutation), gdvals, &size, &opstat);
#endif
          if (!opstat)
	    {
	      fprintf(stderr, "Read error on %d grid of file %s\n", 
		       i, gridptr->name);
#ifdef FORTRAN_
              forcls_(&lun);
#else
              forcls(&lun);
#endif
              free(indims);
	      freedims(ngrid, *dimsptr);
	      if (gridptr->blank == P3D_BLANK)
	        {
	          freeiblank(i, *ipp);
		}
              else
	        {
		  free(*ipp);
		}
	      free(indices);
	      free(bounds);
	      free(*formptr);
	      free(gdvals);
              return 0;
	    }


	  /* assign gdvals to dataset and calculate bounds here */
          for(j = 0; j < ndim; j++)
	    {
	      indices[j] = 0;
	      /* give bounds initial values */
	      bounds[j*2] = bounds[j*2 + 1] = gdvals[j*size];
            }
          for(count = 0; count < size; count++)
	    {
	      int k, whichcomponent;

	      /* assign grid values */
	      for(whichcomponent = 0; whichcomponent < ndim; whichcomponent++)
		{
		  real rval;

		  rval = (real) gdvals[whichcomponent*size + count];
		  PutFieldComponent(FIELD1, whichcomponent, indices, rval);
                  if (rval < bounds[whichcomponent*2])
		    bounds[whichcomponent*2] = rval;
                  else if (rval > bounds[whichcomponent*2 + 1])
		    bounds[whichcomponent*2 + 1] = rval;
		}
	      /* update indices */
	      /* row major */
              for(k = ndim - 1; k >= 0; k--)
		{
		  indices[k]++;
		  if (indices[k] == (*dimsptr)[i][k])
		    {
		      indices[k] = 0;
		      continue;
		    }
		  break;
		}
	    }

          free(gdvals);
	  (*formptr)[i]=NewCurvilinearDataForm(datasetname, ndim,
	                           (*dimsptr)[i], bounds, dataset);
	}
      free(indices);
      free(bounds);
    }

/* close file with fortran subroutine */
#ifdef FORTRAN_
  forcls_(&lun);
#else
  forcls(&lun);
#endif

  free(indims); 
  if (gridptr->blank != P3D_BLANK)
    free(*ipp);
  return i;
} /* RdUnfmtXYZ */


/* for reading fortran unformatted solution file */
#ifdef PROTO
static int RdUnfmtSol(int ndim, int isMGrid, int ngrid, int blank, long **dimsptr,
		      p3d_q *qptr, ObjPtr *formptr, int **ipp)
#else
static int RdUnfmtSol(ndim, isMGrid, ngrid, blank, dimsptr, qptr, formptr, ipp)
int ndim;
int isMGrid;
int ngrid;
int blank;
long **dimsptr;
p3d_q *qptr;
ObjPtr *formptr;
int **ipp;
#endif
{
  int ins[MAXNAMELEN]; /* ascii coding of file name */
  int namelen;         /* file name length */
  int lun = 2;         /* logical unit number of fortran opened file */
  int opstat=0;        /* operation status of fortran file op subroutine */
  int *indims;
  int numsets;         /* number of datasets read so far */
  int i, j;
  int myngrid;         /* the ngrid read from the solution file */
  long *indices;
  char *name;   /* dataset name, extracted from file name */


/* try to open the solution file, ascii coding of the solution file name */
  namelen = (int) strlen(qptr->name);
  for (i = 0; i <= namelen; i++)
     {
       ins[i] = qptr->name[i];
     }
/* open file with fortran subroutine */
#ifdef FORTRAN_
  foropn_(&lun, ins, &namelen, &opstat);
#else
  foropn(&lun, ins, &namelen, &opstat);
#endif
  if (!opstat)
    {
      fprintf(stderr, "Unable to open file %s, aborted\n", qptr->name);
      return 0;
    }

  /* extracting the dataset name from file name */
  for(i = namelen -1; i >= 0 && qptr->name[i] != '/'; i--)
    ;
  if (i == -1 || qptr->name[i] == '/')
    i++;
  name = qptr->name + i;

  for (namelen = 0; 
       name[namelen] != '\0' && name[namelen] != '.';
       namelen++) ;

  /* allocate storage for indices */
  if (!(indices = (long *) malloc(ndim*sizeof(long))))
    {
      fprintf(stderr, "Unable to alloc memory, aborted\n");
#ifdef FORTRAN_
      forcls_(&lun);
#else
      forcls(&lun);
#endif
      return 0;
    }

  /* 0 dataset read so far */
  numsets = 0;

/* do multiple datasets starting here */
  do
    {
      /* reading myngrid */
      if (isMGrid)
        {
          opstat = 0;
#ifdef FORTRAN_
          rngrid_(&lun, &myngrid, &opstat);
#else
          rngrid(&lun, &myngrid, &opstat);
#endif
          if (opstat == EOF)
    	{
    	  if (numsets == 0)
    	    {
    	      fprintf(stderr, "Error in %s: Empty file\n", qptr->name);
    	    }
#ifdef FORTRAN_
              forcls_(&lun);
#else
              forcls(&lun);
#endif
              free(indices);
    	  /* if numsets >= 1 then this is an EOF, else error */
    	  return (numsets ? ngrid : 0);
    	}
          else if (!opstat || myngrid <=0)
            {
    	  fprintf(stderr, "%s format error, invalid NGRID value\n", qptr->name);
#ifdef FORTRAN_
              forcls_(&lun);
#else
              forcls(&lun);
#endif
              free(indices);
    	  return 0;
            }
        }
      else
        {
          myngrid = 1;
        }
    
      /* if myngrid is not the same as ngrid then error */
      if (myngrid != ngrid)
        {
          fprintf(stderr, "Error in %s: NGRID value does not match that"
    	      "of its XYZ file\n", qptr->name);
#ifdef FORTRAN_
          forcls_(&lun);
#else
          forcls(&lun);
#endif
          free(indices);
          return 0;
        }
    
       /* reading dimensions */
      indims = (int *) 0;
      if (!(indims = (int *) malloc(ndim*myngrid*sizeof(int))))
        {
          fprintf(stderr, "Unable to alloc mem, aborted\n");
#ifdef FORTRAN_
          forcls_(&lun);
#else
          forcls(&lun);
#endif
          free(indices);
          return 0;
        }
      opstat=0;
#ifdef FORTRAN_
      rddims_(&lun, &ndim, &ngrid, indims, &opstat);
#else
      rddims(&lun, &ndim, &ngrid, indims, &opstat);
#endif
      if (opstat == EOF && !isMGrid)
        {
          if (numsets == 0)
    	{
    	  fprintf(stderr, "Error in %s: Empty file\n", qptr->name);
    	}
#ifdef FORTRAN_
          forcls_(&lun);
#else
          forcls(&lun);
#endif
          free(indices);
          free(indims);
          return (numsets ? ngrid : 0);
        }
      else if (opstat > 0)
        {
          /* Check dimension consistency with dims read from XYZ file */
          for (i = 0; i < ngrid; i++)
    	 {
    	   for (j = 0; j < ndim; j++)
                 {
    	       if (dimsptr[i][j] != (long) indims[i*ndim + j])
    		 {
    		   fprintf(stderr, "Dimensions mismatch between %s "
    		   "and its XYZ file\n", qptr->name);
#ifdef FORTRAN_
                       forcls_(&lun);
#else
                       forcls(&lun);
#endif
                       free(indices);
                       free(indims);
                       return 0;
                     }
                 }
             }
        }
      else
      /* opstat is 0 or (opstat is EOF and isMGrid is true) */
        {
          fprintf(stderr, "Unable to Read Dimension Values in %s\n", qptr->name);
#ifdef FORTRAN_
              forcls_(&lun);
#else
              forcls(&lun);
#endif
          free(indices);
          free(indims);
          return 0;
        }

      for(i = 0; i < ngrid; i++)
	{
          long size, count;
          float *slvals;
	  ObjPtr density, pressure, dataset;
	  char densityname[MAXNAMELEN];
	  char pressurename[MAXNAMELEN];
	  char datasetname[MAXNAMELEN];
	  float time;
	  int whichcomponent;

	  /* get the time data of the current grid solutions */
          opstat = 0;
#ifdef FORTRAN_
          rdtime_(&lun, &time, &opstat);
#else
          rdtime(&lun, &time, &opstat);
#endif
          if (!opstat)
	    {
	      fprintf(stderr, "Error in %s, invalid FAMACH...TIME value\n",
		      qptr->name);
#ifdef FORTRAN_
              forcls_(&lun);
#else
              forcls(&lun);
#endif
              free(indices);
              free(indims);
              return 0;
	    }

          /* calculate size of one component */
          size=1;
          for(j = 0; j < ndim; j++)
           {
             size *= dimsptr[i][j];
           }
	  /* read in solution, density, and pressure values */
          if (!(slvals = (float *) malloc((ndim+2)*size*sizeof(float))))
	    {
                 fprintf(stderr, "Unable to alloc mem, aborted\n");
#ifdef FORTRAN_
                 forcls_(&lun);
#else
                 forcls(&lun);
#endif
                 free(indims);
	         free(indices);
                 return 0;
	    }
	  opstat=0;
#ifdef FORTRAN_
          rdsolu_(&lun, &ndim, indims+i*ndim, &(qptr->permutation), 
		  slvals, &size, &opstat);
#else
          rdsolu(&lun, &ndim, indims+i*ndim, &(qptr->permutation), 
		  slvals, &size, &opstat);
#endif
          if (!opstat)
	    {
	      fprintf(stderr, "Read error on file %s\n", qptr->name);
#ifdef FORTRAN_
              forcls_(&lun);
#else
              forcls(&lun);
#endif
              free(indims);
	      free(indices);
	      free(slvals);
              return 0;
	    }

	  /* create datasets for solution, density, pressure */
          strncpy(datasetname, name, namelen);
	  datasetname[namelen] = '\0';
	  if (isMGrid)
	    sprintf(datasetname + namelen, "%d", i);
          sprintf(densityname, "%s%s", datasetname, " Density");
          sprintf(pressurename, "%s%s", datasetname, " Pressure");
          density=NewStructuredDataset(densityname, ndim, dimsptr[i], 0);
          pressure=NewStructuredDataset(pressurename, ndim, dimsptr[i], 0);
          dataset=NewStructuredDataset(datasetname, ndim, dimsptr[i], ndim);

	  /* assign slvals to density, pressure, and dataset */
          for(whichcomponent = 0; whichcomponent < ndim + 2; whichcomponent++)
	    {
	      ObjPtr whichdataset;

	      if (whichcomponent == 0)
		/* for density */
		{
		  whichdataset = density;
	        }
              else if (whichcomponent == 1)
		/* for pressure */
		{
		  whichdataset = pressure;
		}
              else
	        /* for solution */
		{
		  whichdataset = dataset;
		}

	      if (!SetCurField(FIELD1, whichdataset))
	        {
                  fprintf(stderr, "Unable to SETCURFIELD, aborted\n");
#ifdef FORTRAN_
                  forcls_(&lun);
#else
                  forcls(&lun);
#endif
                  free(indims);
	          free(indices);
		  free(slvals);
                  return 0;
	        }
              for(j = 0; j < ndim; j++)
	        {
	          indices[j] = 0;
                }
              for(count = 0; count < size; count++)
	        {
	          int k, iblank = 1;
		  real rval;

	          rval = (real) slvals[whichcomponent*size + count];
	          /* do iblank if needed */
	          if (blank == P3D_BLANK)
	            {
	              getIblank(&iblank, ipp, indices, dimsptr[i], ndim, i);
		    }
	          /* do check of negative values of density or pressure 
		     if required */
		  if (whichcomponent < 2 && qptr->check == P3D_CHECK && 
		       rval < (real) 0.0)
		    {
		      rval = (real) 0.0;
		    }
		  PutFieldComponent(FIELD1, 
		     whichcomponent < 2 ? 0 : whichcomponent - 2, indices, 
		     iblank == 0 ? (real) missingData : rval);
	          /* update indices */
		  /* row major way */
                  for(k = ndim - 1; k >= 0; k--)
		    {
		      indices[k]++;
		      if (indices[k] == dimsptr[i][k])
		        {
		          indices[k] = 0;
		          continue;
		        }
		      break;
		    }
		} /* for count = 0 ~ size */
	    } /* for whichcomponent = 0 ~ ndim+2 */

          free(slvals);
	  SetDatasetForm(density, formptr[i]);
	  SetDatasetForm(pressure, formptr[i]);
	  SetDatasetForm(dataset, formptr[i]);
	  if ( qptr->isMDataset )
	    {
	      RegisterTimeDataset(density, (real) time);
	      RegisterTimeDataset(pressure, (real) time);
	      RegisterTimeDataset(dataset, (real) time);
	    }
          else
	    {
	      RegisterDataset(density);
	      RegisterDataset(pressure);
	      RegisterDataset(dataset);
	    }
	}/* for loop for i = 0, ngrid - 1 */
      numsets++;
    } while(qptr->isMDataset);

/* close file with fortran subroutine */
#ifdef FORTRAN_
  forcls_(&lun);
#else
  forcls(&lun);
#endif

  free(indims); 
  free(indices);
  return ngrid;
} /* RdUnfmtSol */

/* for reading fortran unformatted function file */
#ifdef PROTO
static int RdUnfmtFun(int ndim, int isMGrid, int ngrid, int blank, long **dimsptr,
		      p3d_func *funcptr, ObjPtr *formptr, int **ipp)
#else
static int RdUnfmtFun(ndim, isMGrid, ngrid, blank, dimsptr, funcptr, formptr, ipp)
int ndim;
int isMGrid;
int ngrid;
int blank;
long **dimsptr;
p3d_func *funcptr;
ObjPtr *formptr;
int **ipp;
#endif
{
  int ins[MAXNAMELEN]; /* ascii coding of file name */
  int namelen;         /* file name length */
  int lun = 2;         /* logical unit number of fortran opened file */
  int opstat=0;        /* operation status of fortran file op subroutine */
  int *indims;
  int i, j;
  int myngrid;         /* the ngrid read from the solution file */
  int nvardim;         /* number of dimensions + 1 */
  long *indices;
  char *name;   /* dataset name, extracted from file name */


/* try to open the solution file, ascii coding of the solution file name */
  namelen = (int) strlen(funcptr->name);
  for (i = 0; i <= namelen; i++)
     {
       ins[i] = funcptr->name[i];
     }
/* open file with fortran subroutine */
#ifdef FORTRAN_
  foropn_(&lun, ins, &namelen, &opstat);
#else
  foropn(&lun, ins, &namelen, &opstat);
#endif
  if (!opstat)
    {
      fprintf(stderr, "Unable to open file %s, aborted\n", funcptr->name);
      return 0;
    }

  /* read myngrid */
  if (isMGrid)
    {
      opstat = 0;
#ifdef FORTRAN_
      rngrid_(&lun, &myngrid, &opstat);
#else
      rngrid(&lun, &myngrid, &opstat);
#endif
      if (opstat <= 0 || myngrid <=0)
        {
	  fprintf(stderr, "%s format error, invalid NGRID value\n", funcptr->name);
#ifdef FORTRAN_
          forcls_(&lun);
#else
          forcls(&lun);
#endif
	  return 0;
        }
    }
  else
    {
      myngrid = 1;
    }

  /* if myngrid is not the same as ngrid then error */
  if (myngrid != ngrid)
    {
      fprintf(stderr, "Error in %s: NGRID value does not match that"
	      "of its XYZ file\n", funcptr->name);
#ifdef FORTRAN_
      forcls_(&lun);
#else
      forcls(&lun);
#endif
      return 0;
    }

  /* extracting the dataset name from file name */
  for(i = namelen -1; i >= 0 && funcptr->name[i] != '/'; i--)
    ;
  if (i == -1 || funcptr->name[i] == '/')
    i++;
  name = funcptr->name + i;

  for (namelen = 0; 
       name[namelen] != '\0' && name[namelen] != '.';
       namelen++) ;

  /* allocate storage for indices */
  if (!(indices = (long *) malloc(ndim*sizeof(long))))
    {
      fprintf(stderr, "Unable to alloc memory, aborted\n");
#ifdef FORTRAN_
      forcls_(&lun);
#else
      forcls(&lun);
#endif
      return 0;
    }

  /* reading dimensions */
  indims = (int *) 0;
  nvardim = ndim + 1;
  if (!(indims = (int *) malloc(nvardim*myngrid*sizeof(int))))
    {
      fprintf(stderr, "Unable to alloc mem, aborted\n");
#ifdef FORTRAN_
      forcls_(&lun);
#else
      forcls(&lun);
#endif
      free(indices);
      return 0;
    }
  opstat=0;
#ifdef FORTRAN_
  rddims_(&lun, &nvardim, &ngrid, indims, &opstat);
#else
  rddims(&lun, &nvardim, &ngrid, indims, &opstat);
#endif
  if (opstat > 0)
    {
      /* Check dimension consistency with dims read from XYZ file */
      for (i = 0; i < ngrid; i++)
	 {
	   for (j = 0; j < ndim; j++)
             {
	       if (dimsptr[i][j] != (long) indims[i*nvardim + j])
		 {
		   fprintf(stderr, "Dimensions mismatch between %s "
		   "and its XYZ file\n", funcptr->name);
#ifdef FORTRAN_
                   forcls_(&lun);
#else
                   forcls(&lun);
#endif
                   free(indices);
                   free(indims);
                   return 0;
                 }
             }
         }
    }
  else
  /* opstat <= 0 */
    {
      fprintf(stderr, "Unable to Read Dimension Values in %s\n", funcptr->name);
#ifdef FORTRAN_
          forcls_(&lun);
#else
          forcls(&lun);
#endif
      free(indices);
      free(indims);
      return 0;
    }

      for(i = 0; i < ngrid; i++)
	{
          long size, count;
          float *fnvals;
	  ObjPtr dataset;
	  char datasetname[MAXNAMELEN];

          /* calculate size of one component */
          size=1;
          for(j = 0; j < ndim; j++)
           {
             size *= dimsptr[i][j];
           }
	  /* read in function values */
          if (!(fnvals = (float *) malloc(nvardim*size*sizeof(float))))
	    {
                 fprintf(stderr, "Unable to alloc mem, aborted\n");
#ifdef FORTRAN_
                 forcls_(&lun);
#else
                 forcls(&lun);
#endif
                 free(indims);
	         free(indices);
                 return 0;
	    }
	  opstat=0;
#ifdef FORTRAN_
          rdfunc_(&lun, &ndim, indims+i*nvardim, indims+i*nvardim+ndim, 
	           &(funcptr->permutation), fnvals, &size, &opstat);
#else
          rdfunc(&lun, &ndim, indims+i*nvardim, indims+i*nvardim+ndim, 
	           &(funcptr->permutation), fnvals, &size, &opstat);
#endif
          if (!opstat)
	    {
	      fprintf(stderr, "Read error on file %s\n", funcptr->name);
#ifdef FORTRAN_
              forcls_(&lun);
#else
              forcls(&lun);
#endif
              free(indims);
	      free(indices);
	      free(fnvals);
              return 0;
	    }

	  /* create datasets for function */
          strncpy(datasetname, name, namelen);
	  datasetname[namelen] = '\0';
	  if (isMGrid)
	    sprintf(datasetname + namelen, "%d", i);
          dataset=NewStructuredDataset(datasetname, ndim, dimsptr[i], 
		   indims[i*nvardim+ndim] == 1 ? 0 : indims[i*nvardim+ndim]);

	  /* assign fnvals to dataset */
          for(j = 0; j < ndim; j++)
	    {
	      indices[j] = 0;
            }
          if (!SetCurField(FIELD1, dataset))
            {
              fprintf(stderr, "Unable to SETCURFIELD, aborted\n");
#ifdef FORTRAN_
              forcls_(&lun);
#else
              forcls(&lun);
#endif
              free(indims);
              free(indices);
              free(fnvals);
              return 0;
	    }
          for(count = 0; count < size; count++)
	    {
	      int whichcomponent, k;
	      int iblank = 1;

	      /* do iblank if needed */
	      if (blank == P3D_BLANK)
	        {
	          getIblank(&iblank, ipp, indices, dimsptr[i], ndim, i);
		}
	      /* assign solution values */
	      for(whichcomponent = 0; whichcomponent < indims[i*nvardim+ndim];
		  whichcomponent++)
		{
		  real rval;

		  rval = (real) fnvals[whichcomponent*size + count];

		  PutFieldComponent(FIELD1, whichcomponent, indices, 
		  iblank == 0 ? (real) missingData : rval);
		}
	      /* update indices */
	      /* row major way */
              for(k = ndim - 1; k >= 0; k--)
		{
		  indices[k]++;
		  if (indices[k] == dimsptr[i][k])
		    {
		      indices[k] = 0;
		      continue;
		    }
		  break;
		}
            }
          free(fnvals);
          SetDatasetForm(dataset, formptr[i]);
       	  RegisterDataset(dataset);
	}/* for loop for i = 0, ngrid - 1 */

/* close file with fortran subroutine */
#ifdef FORTRAN_
  forcls_(&lun);
#else
  forcls(&lun);
#endif

  free(indims); 
  free(indices);
  return ngrid;
} /* RdUnfmtFun */

#endif /* for ifdef FORTRAN */
/*********************unformatted p3d reading routines, end ***********************/

#ifdef PROTO
static void parseDataFiles(int nSets, p3d_set *sets)
#else
static void parseDataFiles(nSets, sets)
int nSets;
p3d_set *sets;
#endif
{
  int i, j;

/* if no fortran compiler, then the reader is limited to process free
   formatted p3d data files only */
  for (i = 0; i < nSets; i++)
     {
       p3d_set *curset = sets + i;
       ObjPtr *formptr; /* an array of ngrid dataforms */
       int **ipp; /* points to ngrid arrays of iblank ints */ 
       long **dimsptr; /* points to ngrid arrays of dims */
       int ngrid;

       if (curset->grid->fileType == P3D_FMT)
	 {
           ngrid = RdFmtXYZ(curset->ndim, curset->isMGrid, &dimsptr, curset->grid, 
			    &formptr, &ipp);
	 }
       else
	 {
#ifdef FORTRAN
           if (curset->grid->fileType != P3D_DAT)
	     {
               fprintf(stderr, "Error in %s, %s data format is not implemented\n",
	                 curset->grid->name, "Binary");
               return;
	     }
           ngrid = RdUnfmtXYZ(curset->ndim, curset->isMGrid, &dimsptr, curset->grid, 
			    &formptr, &ipp);
#else
           fprintf(stderr, "Error in %s, %s data format is not implemented\n",
		   curset->grid->name, 
	           curset->grid->fileType == P3D_BIN ? "Binary" : "Unformatted");
           return;
#endif
         }
       if (!ngrid)
         {
           FileFormatError("parseDataFiles", curset->grid->name);
           return;  /* something wrong with the grid file */
         }

       /* read all the q files of this set and construct datasets for them */
       for (j = 0; j < curset->nQ; j++)
          {
	    int status;

            if ((curset->qlist + j)->fileType == P3D_FMT)
	      {
                status = RdFmtSol(curset->ndim, curset->isMGrid, ngrid,
                  curset->grid->blank, dimsptr, curset->qlist + j, formptr, ipp);
	      }
            else
	      {
#ifdef FORTRAN
                if ((curset->qlist + j)->fileType != P3D_DAT)
	          {
                    fprintf(stderr, 
			    "Error in %s, %s data format is not implemented\n", 
			    (curset->qlist + j)->name, "Binary");
                    return;
	          }
                status = RdUnfmtSol(curset->ndim, curset->isMGrid, ngrid,
                      curset->grid->blank, dimsptr, curset->qlist + j, formptr, ipp);
#else
                fprintf(stderr, "Error in %s, %s data format is not implemented\n",
		(curset->qlist + j)->name, 
	        (curset->qlist+j)->fileType == P3D_BIN ? "Binary" : "Unformatted");
                return;
#endif
              }
            /* return a value of 0 in status if failed */
            if (!status)
              {
                FileFormatError("Q file", curset->qlist[j].name);
                free(formptr);
                freedims(ngrid, dimsptr);
                if (curset->grid->blank == P3D_BLANK)
                  freeiblank(ngrid, ipp);
                return;
              }
          }

       for (j = 0; j < curset->nFunc; j++)
          {
	    int status;

            if ((curset->qlist + j)->fileType == P3D_FMT)
	      {
                status = RdFmtFun(curset->ndim, curset->isMGrid, ngrid,
                  curset->grid->blank, dimsptr, curset->funclist + j, formptr, ipp);
	      }
            else
	      {
#ifdef FORTRAN
                if ((curset->qlist + j)->fileType != P3D_DAT)
	          {
                    fprintf(stderr, 
			    "Error in %s, %s data format is not implemented\n", 
			    (curset->funclist + j)->name, "Binary");
                    return;
	          }
                status = RdUnfmtFun(curset->ndim, curset->isMGrid, ngrid,
                  curset->grid->blank, dimsptr, curset->funclist + j, formptr, ipp);
#else
                fprintf(stderr, "Error in %s, %s data format is not implemented\n",
		(curset->funclist + j)->name, 
		(curset->funclist+j)->fileType == P3D_BIN ? "Binary" : "Unformatted");
                return;
#endif
              }
            /* return a value of 0 in status if failed */
            if (!status)
              {
                FileFormatError("Function file", curset->funclist[j].name);
                free(formptr);
                freedims(ngrid, dimsptr);
                if (curset->grid->blank == P3D_BLANK)
                  freeiblank(ngrid, ipp);
                return;
              }
          }

       /* clean up */
       if (curset->grid->blank == P3D_BLANK)
         {
           freeiblank(ngrid, ipp);
           ipp = NULL;
         }
       freedims(ngrid, dimsptr);
       free(formptr);
       dimsptr = NULL;
       formptr = NULL;
    } /* outer for */
  return;
} /* parseDataFiles */

#ifdef PROTO
static ObjPtr ReadP3DFile(char *p3dname)
#else
static ObjPtr ReadP3DFile(p3dname)
char *p3dname;
#endif
{
  int nSets = 0; /* number of p3d sets */
  p3d_set *sets = NULL; /* pointer to an array of p3d sets */ 

  /* parse p3d meta file */
  if (!parseP3DMeta(p3dname, &nSets, &sets))
    {
      FileFormatError("ReadP3DFile", p3dname);
    }
  else
    {
      /* find out if any of the sets using the same XYZ file */
      compress(&nSets, &sets);
      parseDataFiles(nSets, sets);
    }

  cleanup(nSets, sets);
  return NULLOBJ;
} /* ReadP3DFile */

/*******************************************************************************/
/*******************************************************************************/
/*******************************************************************************/
#ifdef PROTO
void InitHwuFiles(void)
#else
void InitHwuFiles()
#endif
{
  DefineFormat("STF", "stf", ReadSTFFile, 0);
  DefineFormat("P3D", "p3d", ReadP3DFile, 0);
}

#ifdef PROTO
void KillHwuFiles(void)
#else
void KillHwuFiles()
#endif
{
}
