/* ************************************
 * *                                  *
 * *  ASTERIX format viewer program   *
 * *                                  *
 * ************************************
 * File: utils/asterix/AsterView.C
 *
 *                   COPYRIGHT (c) 2003, 2004  BY
 *          SIGMET INCORPORATED, WESTFORD MASSACHUSETTS, U.S.A.
 * 
 * THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND  COPIED
 * ONLY  IN  ACCORDANCE WITH  THE  TERMS  OF  SUCH  LICENSE  AND WITH THE
 * INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE  OR  ANY OTHER
 * COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
 * OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE  SOFTWARE  IS  HEREBY
 * TRANSFERED.
 */

/* This program takes the filename of an ASTERIX file and prints out diagnostic
 * information.
 */

#include <locale.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "sigtypes.h"
#include "SigAsterix.h"

#include "user_lib.h"

struct read_state
{
  UINT1 iDataArray[256][256];  /* Array to store the data in */
  SINT4 iMinX;
  SINT4 iMaxX;
  SINT4 iMinY;
  SINT4 iMaxY;
  SINT4 iBlockCount;
  SINT4 iBlockOffset;
  SINT4 iRecordCount;
  SINT4 iMaxBlockOffset;
  SINT4 iScaleFactor;
  SINT4 iVectorCount;
};

/* Local function prototypes
 */
static void ProcessCommandLine
(int iArgc, 
 char *sArgv[],
 struct view_options *pOptions_a );

static void Usage( void );

static SINT4 ReadDataBlock
( struct ast_data_block *pDataBlock_a,
  FILE *pStream_a );

static SINT4 ProcessDataRecord
( const UINT1 *pRecord_a,
  struct read_state *pState_a,
  const struct view_options *pOptions_a );

static void InsertCartesianVector
( const struct ast_single_vector *pVector_a,
  UINT1 iVectorQualifier_a,
  struct read_state *pState_a );

static void InsertCartesianPoint
( SINT4 iXComp_a, 
  SINT4 iYComp_a,
  UINT1 iIntensity_a,      /* Only low 3 bits non-zero */
  struct read_state *pState_a );

static void PrintCartesianArray
( const struct read_state *pState_a,
  const struct view_options *pOptions_a );

struct view_options
{
  char sPath[PATHNAME_SIZE];
  UINT1 lVerbose;      /* Print block summary */
  UINT1 lVerbose2;     /* Print record summary */
  UINT1 lVerbose3;     /* Print record details */
  UINT1 lVerbose4;     /* Print individual vectors */
  UINT1 lPrintData;    /* Print full data info */
  SINT4 iRayCount;     /* Only print this many rays */
  SINT4 iRaySkip;      /* Skip this many rays */
  SINT4 iLineLength;   /* Line length to use for data listing */
};

/* ===============================================================
 * Main program starts here.
 */
int main(int iArgc, char *sArgv[])
{
  SINT4 iBlockSize;
  struct view_options Options;
  FILE *stream;
  struct ast_data_block *pDataBlock;
  struct read_state State;

  setlocale( LC_ALL, "" ) ;

  /* Process the command line arguments */
  ProcessCommandLine( iArgc, sArgv, &Options );

  /* Allocate the memory, largest possible block is 16-bits */
  pDataBlock = (struct ast_data_block*)malloc( 65536 );
  if (!pDataBlock) 
    { perror("malloc"); exit(EXIT_FAILURE); }

  /* Initialize the read state */
  memset( &State, 0, sizeof(State) );
  State.iMinX =  1000;
  State.iMaxX = -1000;
  State.iMinY =  1000;
  State.iMaxY = -1000;

  /* Open the file */
  stream = fopen( Options.sPath, "r" );

  /* Loop reading in data blocks, and displaying the results */
  iBlockSize = ReadDataBlock( pDataBlock, stream );
  while( iBlockSize )
    {
      UINT1 *pRecord;
      State.iBlockCount++;
      State.iMaxBlockOffset = iBlockSize-3;
      if (Options.lVerbose) printf( "Data Block #%d: %d bytes\n", State.iBlockCount,
				    iBlockSize );
      State.iBlockOffset=0;
      pRecord = &(pDataBlock->iData[State.iBlockOffset]);
      while( State.iBlockOffset<State.iMaxBlockOffset )
	{
	  SINT4 iErrorSize;
	  iErrorSize=ProcessDataRecord( pRecord, &State, &Options );
	  if (iErrorSize)
	    {
	      printf( "Record error at %d bytes\n", iErrorSize );
	      State.iBlockOffset = iBlockSize-3;
	    }
	  pRecord = &pDataBlock->iData[State.iBlockOffset];
	}
      iBlockSize = ReadDataBlock( pDataBlock, stream );
    }

  fclose( stream );

  /* Now loop printing out the results */
  PrintCartesianArray( &State, &Options );

  exit( EXIT_SUCCESS );
}
/* =================================================================
 * Read a block of data from the stream.  On error, print out 
 * message and return a zero size.
 */
static SINT4 ReadDataBlock
( struct ast_data_block *pDataBlock_a,
  FILE *pStream_a )
{
  SINT4 iCount, iBlockSize;
  iCount = fread( pDataBlock_a, 1, 3, pStream_a );
  if (iCount!=3)
    {
      if (iCount!=0) fprintf( stderr, "fread returned %d\n", iCount );
      return 0;
    }

  if (pDataBlock_a->iCategory!=8)
    {
      fprintf( stderr, "Invalid block category of %d\n", pDataBlock_a->iCategory );
      return 0;
    }

  iBlockSize = (pDataBlock_a->iLength[0]<<8)|pDataBlock_a->iLength[1];
  if (iBlockSize<3)
    {
      fprintf( stderr, "Invalid block size of %d\n", iBlockSize );
      return 0;
    }
  iCount = fread( pDataBlock_a->iData, 1, iBlockSize-3, pStream_a );
  if (iCount!=(iBlockSize-3))
    {
      fprintf( stderr, "fread returned %d\n", iCount );
      return 0;
    }
  return iBlockSize;
}

/* ========================================================
 * Function to process a single data record.  It will return
 * zero on success, else the number of bytes read before the
 * overflow.  Note that only cartesian vector records are
 * processed for further display.
 */
static SINT4 ProcessDataRecord
( const UINT1 *pRecord_a,
  struct read_state *pState_a,
  const struct view_options *pOptions_a )
{
  const UINT1 *pRecord=pRecord_a;
  UINT1 iFieldSpec[2], iMessageType, iVectorQualifier;
  SINT4 iStartOffset = pState_a->iBlockOffset;

  
  /* First field spec byte */
  iFieldSpec[0] = *pRecord++; pState_a->iBlockOffset++;
  if (pOptions_a->lVerbose2) printf( "Field spec:0x%02x", iFieldSpec[0] );

  /* Possible second field spec byte.
   * We have to continually monitor to make sure we do not run off
   * the end of the block.
   */
  if (iFieldSpec[0]&AST_FRN1_EXTENSION)
    {
      if (pState_a->iBlockOffset+1>pState_a->iMaxBlockOffset) 
	return pState_a->iBlockOffset-iStartOffset;
      iFieldSpec[1] = *pRecord++; pState_a->iBlockOffset++;
      if (pOptions_a->lVerbose2) printf( ", 0x%02x", iFieldSpec[1] );
    }
  if (pOptions_a->lVerbose2) printf( "\n" );
  /* Now process all the fields in order */
  /* Data Source */
  if (iFieldSpec[0]&AST_FRN1_DATA_SOURCE)
    {
      UINT1 iSac, iSic;
      if (pState_a->iBlockOffset+2>pState_a->iMaxBlockOffset) 
	{
	  printf( "BlockOffset:%d, iMaxBlockOffset:%d\n",
		  pState_a->iBlockOffset, pState_a->iMaxBlockOffset);
	  return pState_a->iBlockOffset-iStartOffset;
	}
      iSac = *pRecord++; pState_a->iBlockOffset++;
      iSic = *pRecord++; pState_a->iBlockOffset++;
      if (pOptions_a->lVerbose3) printf( "Data Source, SAC:%d, SIC:%d\n", iSac, iSic );
    }
  /* Message Type */
  if (iFieldSpec[0]&AST_FRN1_MESSAGE_TYPE)
    {
      if (pState_a->iBlockOffset+1>pState_a->iMaxBlockOffset) 
	return pState_a->iBlockOffset-iStartOffset;
      iMessageType = *pRecord++; pState_a->iBlockOffset++;
      if (pOptions_a->lVerbose3) printf( "Message type:%d\n", iMessageType );
    }

  /* Vector qualifier(s) */
  if (iFieldSpec[0]&AST_FRN1_VECTOR_QUALIFIER)
    {
      SINT4 iQualifierCount;
      UINT1 iLastQualifier;
      if (pState_a->iBlockOffset+1>pState_a->iMaxBlockOffset) 
	return pState_a->iBlockOffset-iStartOffset;
      iVectorQualifier = *pRecord++; pState_a->iBlockOffset++;
      iLastQualifier=iVectorQualifier;
      iQualifierCount=1;
      while( iLastQualifier&1)
	{
	  if (pState_a->iBlockOffset+1>pState_a->iMaxBlockOffset) 
	    return pState_a->iBlockOffset-iStartOffset;
	  iLastQualifier = *pRecord++; pState_a->iBlockOffset++;
	  iQualifierCount++;
	}

      if (pOptions_a->lVerbose3) 
	printf( "Vector qualifier:0x%x, %d bytes\n", iVectorQualifier, iQualifierCount );
    }
  else
    {
      iVectorQualifier=0;
    }

  /* Cartesian vectors */
  if (iFieldSpec[0]&AST_FRN1_CARTESIAN_VECTORS)
    {
      SINT4 iRepeats, iIndex;
      if (!(iFieldSpec[0]|AST_FRN1_VECTOR_QUALIFIER))
	{
	  printf( "ERROR, Cartesian vectors require vector qualifiers.\n" );
	  return pState_a->iBlockOffset-iStartOffset;
	}

      if (pState_a->iBlockOffset+1>pState_a->iMaxBlockOffset) 
	return pState_a->iBlockOffset-iStartOffset;
      iRepeats = (SINT4)(UINT4)*pRecord++; pState_a->iBlockOffset++;
      if (pOptions_a->lVerbose3) printf( "Cartesian vectors: %d\n", iRepeats );
      for (iIndex=0; iIndex<iRepeats; iIndex++)
	{
	  struct ast_single_vector Vector;
	  if (pState_a->iBlockOffset+3>pState_a->iMaxBlockOffset) 
	    return pState_a->iBlockOffset-iStartOffset;
	  memcpy( &Vector, pRecord, 3 ); pRecord+=3; pState_a->iBlockOffset+=3;
	  if (pOptions_a->lVerbose4)
	    printf( "Start: (%d,%d), Length:%d\n", Vector.iXComp, Vector.iYComp,
		    Vector.iLength );
	  InsertCartesianVector( &Vector, iVectorQualifier, pState_a );
	}
      pState_a->iVectorCount+=iRepeats;
    }

  /* Polar vectors are read but not processed into a picture */
  if (iFieldSpec[0]&AST_FRN1_POLAR_VECTORS)
    {
      SINT4 iRepeats, iIndex;

      if (pState_a->iBlockOffset+1>pState_a->iMaxBlockOffset) 
	return pState_a->iBlockOffset-iStartOffset;
      iRepeats = (SINT4)(UINT4)*pRecord++; pState_a->iBlockOffset++;
      if (pOptions_a->lVerbose3) printf( "Polar vectors: %d\n", iRepeats );
      for (iIndex=0; iIndex<iRepeats; iIndex++)
	{
	  if (pState_a->iBlockOffset+4>pState_a->iMaxBlockOffset) 
	    return pState_a->iBlockOffset-iStartOffset;
	  pRecord+=4; pState_a->iBlockOffset+=4;
	}
      pState_a->iVectorCount+=iRepeats;
    }

  /* Contour ID, read but not processed */
  if (iFieldSpec[0]&AST_FRN1_CONTOUR_ID)
    {
      if (pState_a->iBlockOffset+2>pState_a->iMaxBlockOffset) 
	return pState_a->iBlockOffset-iStartOffset;
      pRecord+=2; pState_a->iBlockOffset+=2;
      if (pOptions_a->lVerbose3) printf( "Contour ID\n" );
    }

  /* Contour points are read but not processed into a picture */
  if (iFieldSpec[0]&AST_FRN1_CONTOUR_POINTS)
    {
      SINT4 iRepeats, iIndex;

      if (pState_a->iBlockOffset+1>pState_a->iMaxBlockOffset) 
	return pState_a->iBlockOffset-iStartOffset;
      iRepeats = (SINT4)(UINT4)*pRecord++; pState_a->iBlockOffset++;
      if (pOptions_a->lVerbose3) printf( "Contour points: %d\n", iRepeats );
      for (iIndex=0; iIndex<iRepeats; iIndex++)
	{
	  if (pState_a->iBlockOffset+2>pState_a->iMaxBlockOffset) 
	    return pState_a->iBlockOffset-iStartOffset;
	  pRecord+=2; pState_a->iBlockOffset+=2;
	}
      pState_a->iVectorCount+=iRepeats;
    }

  /* Skip second byte of field spec if no extension */
  if (!(iFieldSpec[0]&AST_FRN1_EXTENSION)) goto NO_FRN1_EXTENSION;

  /* Time of day */
  if (iFieldSpec[1]&AST_FRN2_TIME_OF_DAY)
    {
      UINT4 iTime24, iSeconds, iMills;
      if (pState_a->iBlockOffset+3>pState_a->iMaxBlockOffset) 
	return pState_a->iBlockOffset-iStartOffset;
      iTime24  = (*pRecord++)<<16; pState_a->iBlockOffset++;
      iTime24 |= (*pRecord++)<<8;  pState_a->iBlockOffset++;
      iTime24 |= (*pRecord++);     pState_a->iBlockOffset++;
      iSeconds = iTime24>>7;
      iMills   = (1000*(iTime24&0x7f))/128;
      if (pOptions_a->lVerbose3)
	{
	  char sTimeBuf[TIMENAME_SIZE];
	  printf( "Time:%s.%03d\n", shhmmss_r(iSeconds, sTimeBuf),iMills );
	}
    }

  /* Processing status, includes scale factor */
  if (iFieldSpec[1]&AST_FRN2_PROCESSING_STATUS)
    {
      UINT1 iR, iLastValue;
      UINT4 iQ;
      SINT4 iStatusCount;
      if (pState_a->iBlockOffset+3>pState_a->iMaxBlockOffset) 
	return pState_a->iBlockOffset-iStartOffset;
      iLastValue  = *pRecord++; pState_a->iBlockOffset++;
      iR = iLastValue&7;
      pState_a->iScaleFactor = (SINT4)(((SINT1)iLastValue)>>3);
      iLastValue = *pRecord++;  pState_a->iBlockOffset++;
      iQ = ((UINT4)iLastValue)<<7;
      iLastValue = *pRecord++;  pState_a->iBlockOffset++;
      iQ |= ((UINT4)iLastValue)>>1;

      /* Read all possible extents */
      iStatusCount=3;
      while( iLastValue&1)
	{
	  if (pState_a->iBlockOffset+1>pState_a->iMaxBlockOffset) 
	    return pState_a->iBlockOffset-iStartOffset;
	  iLastValue = *pRecord++; pState_a->iBlockOffset++;
	  iStatusCount++;
	}

      if (pOptions_a->lVerbose3) 
	{
	  FLT4  fScaleFactor;
	  fScaleFactor = pow( 2.0, (FLT8)(pState_a->iScaleFactor-6) );
	  printf( "Processing Status %d bytes: Scale:%d, (%5.3f Nm/pixel) R:%d, Q:0x%x\n", 
		  iStatusCount, pState_a->iScaleFactor, fScaleFactor, iR, iQ );
	}
    }

  /* Station config, variable length */
  if (iFieldSpec[1]&AST_FRN2_STATION_CONFIG)
    {
      UINT1 iLastValue;
      SINT4 iCount;
      if (pState_a->iBlockOffset+1>pState_a->iMaxBlockOffset) 
	return pState_a->iBlockOffset-iStartOffset;
      iLastValue  = *pRecord++; pState_a->iBlockOffset++;

      /* Read all possible extents */
      iCount=1;
      while( iLastValue&1)
	{
	  if (pState_a->iBlockOffset+1>pState_a->iMaxBlockOffset) 
	    return pState_a->iBlockOffset-iStartOffset;
	  iLastValue = *pRecord++; pState_a->iBlockOffset++;
	  iCount++;
	}

      if (pOptions_a->lVerbose3) 
	printf( "Station config %d bytes\n", iCount );
    }

  /* Total number of vectors */
  if (iFieldSpec[1]&AST_FRN2_TOTAL_NUMBER)
    {
      UINT4 iTotalNumber;
      if (pState_a->iBlockOffset+2>pState_a->iMaxBlockOffset) 
	return pState_a->iBlockOffset-iStartOffset;
      iTotalNumber  = ((UINT4)(*pRecord++))<<8; pState_a->iBlockOffset++;
      iTotalNumber |=  (UINT4)(*pRecord++);     pState_a->iBlockOffset++;

      if (pOptions_a->lVerbose3) 
	printf( "Total number of vectors:%d\n", iTotalNumber );
      if (iTotalNumber != (UINT4)pState_a->iVectorCount )
	{
	  printf( "WARNING: Total number %d does not match %d found in file.\n",
		  iTotalNumber, pState_a->iVectorCount );
	}
    }

  /* Polar vectors are read but not processed into a picture */
  if (iFieldSpec[1]&AST_FRN2_WEATHER_VECTORS)
    {
      SINT4 iRepeats, iIndex;

      if (pState_a->iBlockOffset+1>pState_a->iMaxBlockOffset) 
	return pState_a->iBlockOffset-iStartOffset;
      iRepeats = (SINT4)(UINT4)*pRecord++; pState_a->iBlockOffset++;
      if (pOptions_a->lVerbose3) printf( "Weather vectors: %d\n", iRepeats );
      for (iIndex=0; iIndex<iRepeats; iIndex++)
	{
	  if (pState_a->iBlockOffset+4>pState_a->iMaxBlockOffset) 
	    return pState_a->iBlockOffset-iStartOffset;
	  pRecord+=4; pState_a->iBlockOffset+=4;
	}
      pState_a->iVectorCount+=iRepeats;
    }

 NO_FRN1_EXTENSION:
  pState_a->iRecordCount++;

  if (pOptions_a->lVerbose2) 
    {
      printf( "Data Record #%d: size:%d, offset:%d\n", pState_a->iRecordCount,
	      pState_a->iBlockOffset-iStartOffset, iStartOffset );
    }
  return 0;
}
/* =====================================================================
 * Insert a cartesian vector into the array.
 */
static void InsertCartesianVector
( const struct ast_single_vector *pVector_a,
  UINT1 iVectorQualifier_a,
  struct read_state *pState_a )
{
  UINT1 iIntensity = 0x7 & (iVectorQualifier_a>>4);
  UINT1 iDirection = 0x7 & (iVectorQualifier_a>>1);
  UINT1 iCount;
  SINT4 iXComp, iYComp;

  iXComp = pVector_a->iXComp;
  iYComp = pVector_a->iYComp;

  for (iCount=0; iCount<pVector_a->iLength; iCount++)
    {
      InsertCartesianPoint( iXComp, iYComp, iIntensity, pState_a );
      /* Only implement 0 and 90 degree directions.  It is not clear
       * what to do in the other directions.
       */
      if (0 == iDirection)
	{
	  iYComp++;
	  if (iYComp>127)
	    { printf( "Error, Vector went off screen\n" ); return; }
	}
      else
	{
	  iXComp++;
	  if (iXComp>127)
	    { printf( "Error, Vector went off screen\n" ); return; }
	}
    }
  return;
}
/* ===================================================================
 * Insert one point into the array.  Position is known to be valid.
 */
static void InsertCartesianPoint
( SINT4 iXComp_a,          /* Range: -128 to +127 */
  SINT4 iYComp_a,
  UINT1 iIntensity_a,      /* Only low 3 bits non-zero */
  struct read_state *pState_a )
{
  UINT1 *pData=&pState_a->iDataArray[iXComp_a+128][iYComp_a+128];
  /* In the data array, each byte contains an insertion count
   * in the top 5 bits, and the last data value in the low 3 bits
   */
  UINT1 iInsertCount = (*pData)>>3;

  if (iInsertCount<31) iInsertCount++;
  *pData = (iInsertCount<<3)|iIntensity_a;

  /* Store limits of data span */
  if (iXComp_a<pState_a->iMinX) pState_a->iMinX=iXComp_a;
  if (iXComp_a>pState_a->iMaxX) pState_a->iMaxX=iXComp_a;
  if (iYComp_a<pState_a->iMinY) pState_a->iMinY=iYComp_a;
  if (iYComp_a>pState_a->iMaxY) pState_a->iMaxY=iYComp_a;

}
/* ===================================================================
 * Function to print out numbers from the array.
 */
static void PrintCartesianArray
( const struct read_state *pState_a,
  const struct view_options *pOptions_a )
{
  SINT4 iSkipFactor, iArrayWidth, iArrayHeight, iArrayStartX, iArrayStartY;
  SINT4 iLine;

  /* If the width of the image will not fit on one line, the use
   * a skip factor.
   */
  iArrayStartX = pState_a->iMinX+128;
  iArrayStartY = pState_a->iMinY+128;
  iArrayWidth  = 1+pState_a->iMaxX-pState_a->iMinX;
  iArrayHeight = 1+pState_a->iMaxY-pState_a->iMinY;
  if (iArrayWidth<=0) return;

  iSkipFactor = (iArrayWidth+pOptions_a->iLineLength-1)/pOptions_a->iLineLength;

  printf( "Array size (%dx%d), display skip factor:%d\n", iArrayWidth, iArrayHeight,
	  iSkipFactor );
  for (iLine=iArrayStartY+iArrayHeight-1; iLine>=iArrayStartY; iLine-=iSkipFactor )
    {
      SINT4 iX;
      for (iX=iArrayStartX; iX<iArrayStartX+iArrayWidth; iX+=iSkipFactor )
	{
	  UINT1 iValue, iCount, iLevel;
	  iValue=pState_a->iDataArray[iX][iLine];
	  iLevel = 0x7&iValue; iCount=iValue>>3;
	  switch( iCount )
	    {
	    case 0:
	      printf(".");
	      break;
	    case 1:
	      printf("%d",iLevel);
	      break;
	    default:
	      printf("%c",96+ iCount);
	      break;
	    }
	}
      printf("\n");

    }

}
/* ======================================================================
 * Function to process the command line arguments.
 */
static void ProcessCommandLine
(int iArgc_a, 
 char *sArgv_a[],
 struct view_options *pOptions_a )
{

  int iArg;
  memset( pOptions_a, 0, sizeof(*pOptions_a) );
  pOptions_a->iLineLength = 80;

  /* Parse command line options
   */
  for( iArg=1 ; iArg<iArgc_a ; iArg++ )
    {
      const char *sArg = sArgv_a[iArg];
      /* fprintf( stderr, "Processing %d: '%s'\n", iArg, sArg ); */

      if ( sArg[0] == '-')
	{
	  if (0 == strncmp( sArg, "-count:", 7 ))
	    {
	      char *sEnd;
	      pOptions_a->iRayCount = strtol( &sArg[7], &sEnd, 10 );
	    }
	  else if (0 == strncmp( sArg, "-d", 2 ))
	    {
	      pOptions_a->lPrintData=TRUE;
	    }
	  else if (0 == strncmp( sArg, "-h", 2 ))
	    {
	      Usage();
	      exit(EXIT_FAILURE) ;
	    }
	  else if (0 == strncmp( sArg, "-length:", 8 ))
	    {
	      char *sEnd;
	      pOptions_a->iLineLength = strtol( &sArg[8], &sEnd, 10 );
	      if (pOptions_a->iLineLength<30) pOptions_a->iLineLength=30;
	    }
	  else if (0 == strncmp( sArg, "-skip:", 6 ))
	    {
	      char *sEnd;
	      pOptions_a->iRaySkip = strtol( &sArg[6], &sEnd, 10 );
	    }
	  else if (0 == strcmp( sArg, "-v" ))
	    {
	      pOptions_a->lVerbose=TRUE;
	    }
	  else if (0 == strcmp( sArg, "-vv" ))
	    {
	      pOptions_a->lVerbose=TRUE;
	      pOptions_a->lVerbose2=TRUE;
	    }
	  else if (0 == strcmp( sArg, "-vvv" ))
	    {
	      pOptions_a->lVerbose=TRUE;
	      pOptions_a->lVerbose2=TRUE;
	      pOptions_a->lVerbose3=TRUE;
	    }
	  else if (0 == strcmp( sArg, "-vvvv" ))
	    {
	      pOptions_a->lVerbose=TRUE;
	      pOptions_a->lVerbose2=TRUE;
	      pOptions_a->lVerbose3=TRUE;
	      pOptions_a->lVerbose4=TRUE;
	    }
	}
      else
	{
	  strncpy( pOptions_a->sPath, sArg, PATHNAME_SIZE-1);
	}
    }
  if (!pOptions_a->sPath[0])
    {
      printf( "ufview requires a pathname arg.\n" );
      exit(EXIT_FAILURE);
    }
  return;
}
/* ==================================================
 */
static void Usage( void )
{
  fprintf( stderr, "Options: \n" );
  fprintf( stderr, "         -help     (print this list and exit)\n" );
  fprintf( stderr, "         -length:N (max line length to use)\n" );
  fprintf( stderr, "         -v        (print summary for each data block)\n" );
  fprintf( stderr, "         -vv       (print summary for each record)\n" );
  fprintf( stderr, "         -vvv      (print details for each record)\n" );
  fprintf( stderr, "         -vvvv     (print details for each vector)\n" );
  fprintf( stderr, "         pathname\n" );
  fprintf( stderr, "         (all other arguments ignored)\n" );
}
