/* *******************************
 * *                             *
 * *  UF format viewer program   *
 * *                             *
 * *******************************
 * File: iris/examiners/ufview.C
 *
 *              COPYRIGHT (c) 2000, 2001, 2002, 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 take the filename of a UF file and prints out diagnostic
 * information.
 */

#ifndef LINUX
#include <arpa/nameser.h>  /* Defines BYTE_ORDER on HP and SGI */
#endif

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

#include "sigtypes.h"
#include "headers.h"
#include "uf.h"

#include "user_lib.h"

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

static void Usage( void );

static void PrintMandatoryHeader
( struct uf_mandatory_header2 *pMHeader_a,
const struct ufview_options *pOptions_a );

static char *sTailString
(const char *sString_a,
 SINT4 iMaxSize_a );

static void PrintOptionalHeader
( struct uf_optional_header *pOpHeader_a,  /* Strings are byte swapped correctly */
  const struct ufview_options *pOptions_a,
  SINT2 iNoDataValue_a );

static void ReadDataHeader
(FILE  *pStream_a,         /* Stream to read from */
 SINT4 *pPosition_a,       /* Position within the record, must be updated */
 struct uf_data_header2 *pDataHeader_a,  
 const struct ufview_options *pOptions_a );

static void ReadFieldHeader
(FILE  *pStream_a,         /* Stream to read from */
 SINT4 *pPosition_a,       /* Position within the record, must be updated */
 struct uf_field_header2 *pFieldHeader_a,  
 const struct ufview_options *pOptions_a,
 const char sDataType_a[2] );

static void ReadFieldData
(FILE  *pStream_a,         /* Stream to read from */
 SINT4 *pPosition_a,       /* Position within the record, must be updated */
 const struct uf_field_header2 *pFieldHeader_a,  
 const struct ufview_options *pOptions_a,
 const char sDataType_a[2] );

static void PrintUfData
( SINT2 iData_a[],
  SINT2 iBinCount_a,
  SINT2 iScaleFactor_a,
  SINT2 iNoDataValue_a,
  SINT4 iLineLength_a );

static void swap2
(void *word);
static void swap4
(void *word);

static void swap2_array
(SINT2 *buf, 
 SINT4 iCount_a );

struct ufview_options
{
  char sPath[PATHNAME_SIZE];
  UINT1 lVerbose;      /* Print full header info */
  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 iCount, iRecordLength, iReadRayCount, iPrintRayCount, iPosition;
  struct ufview_options Options;
  struct uf_mandatory_header2 UfHeader;
  struct uf_optional_header  OpHeader;
  struct uf_data_header2      DataHeader;
  FILE *stream;

  setlocale( LC_ALL, "" ) ;

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

  /* Read in the header */
  stream = fopen( Options.sPath, "r" );

  /* Loop reading in mandatory headers, and displaying the results */
  iReadRayCount = 0;
  iPrintRayCount = 0;
  iCount = fread( &iRecordLength, 1, 4, stream );
  iPosition = 0;
  while( iCount==4 )
    {
      SINT4 iSeekSize, iMoment;
      if (LITTLE_END) swap4( &iRecordLength );
      iReadRayCount++;
      if (iReadRayCount<=Options.iRaySkip) goto SKIP_THIS_RAY;
      iPrintRayCount++;
      if ((Options.iRayCount) &&(iPrintRayCount>Options.iRayCount)) goto DONE;
      if (Options.lVerbose) printf( "Master record length:%d\n", iRecordLength );

      /* Read and process mandatory header */
      iCount = fread( &UfHeader, 1, sizeof(UfHeader), stream );
      iPosition += sizeof(UfHeader);
      PrintMandatoryHeader(&UfHeader, &Options );

      /* Read and process optional header */
      if (UfHeader.iOptionalHeaderPosition != UfHeader.iLocalUseHeaderPosition)
	{
	  iCount = fread( &OpHeader, 1, sizeof(OpHeader), stream );
	  iPosition += sizeof(OpHeader);
	  PrintOptionalHeader(&OpHeader, &Options, UfHeader.iNoDataValue );
	}

      /* Read and process data header, maybe skip local use header first */
      iSeekSize = 2*(UfHeader.iDataHeaderPosition-1) - iPosition;
      if (iSeekSize !=0) iCount = fseek( stream, iSeekSize, SEEK_CUR );
      iPosition += iSeekSize;
      ReadDataHeader( stream, &iPosition, &DataHeader, &Options );

      /* Read and process data headers, maybe skip some local data each time */
      for (iMoment=0; iMoment<DataHeader.iFieldsThisRecord; iMoment++)
	{
	  struct uf_field_header2 FieldHeader;
	  iSeekSize = 2*(DataHeader.Dsi[iMoment].iFieldHeaderPosition-1) - iPosition;
	  if (iSeekSize !=0) iCount = fseek( stream, iSeekSize, SEEK_CUR );
	  iPosition += iSeekSize;
	  ReadFieldHeader( stream, &iPosition, &FieldHeader, &Options,
			   DataHeader.Dsi[iMoment].sDataType );
	  ReadFieldData( stream, &iPosition, &FieldHeader, &Options,
			 DataHeader.Dsi[iMoment].sDataType );
	}

    SKIP_THIS_RAY:
      iSeekSize = iRecordLength + 4 - iPosition;
      if (iSeekSize>0) iCount = fseek( stream, iSeekSize, SEEK_CUR );
      iCount = fread( &iRecordLength, 1, 4, stream );
      iPosition = 0;
    }
  if (iCount !=0) 
    {
      printf( "Bad read, got%d, wanted%d bytes\n", iCount, sizeof(UfHeader));
    }
  else
    {
      if (ferror(stream)) printf( "Read error.\n" );
    }

 DONE:

  fclose( stream );

  exit( EXIT_SUCCESS );
}
/* ======================================================================
 * Function to process the command line arguments.
 */
static void ProcessCommandLine
(int iArgc_a, 
 char *sArgv_a[],
 struct ufview_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 == strncmp( sArg, "-v", 2 ))
	    {
	      pOptions_a->lVerbose=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: -count:N  (only print N rays)\n" );
  fprintf( stderr, "         -data     (print data values)\n" );
  fprintf( stderr, "         -help     (print this list and exit)\n" );
  fprintf( stderr, "         -length:N (max line length to use)\n" );
  fprintf( stderr, "         -skip:N   (skip the first N rays)\n" );
  fprintf( stderr, "         -verbose  (print full header info)\n" );
  fprintf( stderr, "         pathname\n" );
  fprintf( stderr, "         (all other arguments ignored)\n" );
}

/* =====================================================
 * Print the mandatory heaer
 */
static void PrintMandatoryHeader
( struct uf_mandatory_header2 *pMHeader_a,  /* Strings are byte swapped correctly */
  const struct ufview_options *pOptions_a )
{
  FLT4 fAz, fEl;
  SINT2 iYear;
  char sTimeBuffer[21];
  if (LITTLE_END)
    {
      swap2_array( (SINT2*)pMHeader_a, sizeof(*pMHeader_a)/2 );
      swap2( pMHeader_a->sID );
      swap2_array( (SINT2 *)pMHeader_a->sRadarName, 8/2 );
      swap2_array( (SINT2 *)pMHeader_a->sSiteName, 8/2 );
      swap2( pMHeader_a->sTimeZone );
      swap2_array( (SINT2 *)pMHeader_a->sConvertName, 8/2 );
    }

  fAz = ((FLT4)pMHeader_a->iAzimuth)/64.0;
  if (fAz<0.0) fAz+= 360.0;
  fEl = ((FLT4)pMHeader_a->iElevation)/64.0;
  printf( "%2d:%03d: Az:%6.2f, El:%5.2f, Time:%02d:%02d:%02d\n", 
	  pMHeader_a->iSweepNumber, pMHeader_a->iRayNumber, fAz, fEl,
	  pMHeader_a->iHour, pMHeader_a->iMinute, pMHeader_a->iSecond );

  if (!pOptions_a->lVerbose) return;

  printf( "==========UF Mandatory Header=========\n" );
  printf( "                  ID:%-2.2s\n", pMHeader_a->sID );
  printf( "         Record size:%d words\n", pMHeader_a->iRecordSize);
  printf( " Optional Header Pos:%d\n", pMHeader_a->iOptionalHeaderPosition);
  printf( "Local Use Header Pos:%d\n", pMHeader_a->iLocalUseHeaderPosition);
  printf( "     Data Header Pos:%d\n", pMHeader_a->iDataHeaderPosition);
  printf( "       Record Number:%d\n", pMHeader_a->iRecordNumber );
  printf( "       Volume Number:%d\n", pMHeader_a->iVolumeNumber );
  printf( "          Ray Number:%d\n", pMHeader_a->iRayNumber );
  printf( "       Record in Ray:%d\n", pMHeader_a->iRecordInRay );
  printf( "        Sweep number:%d\n", pMHeader_a->iSweepNumber );
  printf( "          Radar name:%-8.8s\n", pMHeader_a->sRadarName );
  printf( "           Site name:'%s'\n", sTailString(pMHeader_a->sSiteName,8) );

  /* Convert signed degrees to D:M:S, all fields have the same sign */
  {
    FLT8 fAngle;
    fAngle  = (FLT8)pMHeader_a->iLatDegrees;
    fAngle += ((FLT8)pMHeader_a->iLatMinutes)/60.0;
    fAngle += ((FLT8)pMHeader_a->iLatSeconds)/(60.0*60.0*64.0);
    printf( "            Latitude:%s (%dD %dM %4.2fS)\n", srdeg_to_lat(fAngle),
	    pMHeader_a->iLatDegrees, pMHeader_a->iLatMinutes, 
	    ((FLT8)pMHeader_a->iLatSeconds)/64.0 );

    fAngle  = (FLT8)pMHeader_a->iLonDegrees;
    fAngle += ((FLT8)pMHeader_a->iLonMinutes)/60.0;
    fAngle += ((FLT8)pMHeader_a->iLonSeconds)/(60.0*60.0*64.0);
    printf( "           Longitude:%s (%dD %dM %4.2fS)\n", srdeg_to_lon(fAngle),
	    pMHeader_a->iLonDegrees, pMHeader_a->iLonMinutes, 
	    ((FLT8)pMHeader_a->iLonSeconds)/64.0 );
  }

  printf( "            Altitude:%d meters\n", pMHeader_a->iAltitude );
  {
    struct ymds_time RayTime;
    memset( &RayTime, 0, sizeof(RayTime) );
    RayTime.iyear = pMHeader_a->iYear;
    RayTime.imon  = pMHeader_a->iMonth;
    RayTime.iday  = pMHeader_a->iDay;
    RayTime.isec  = iPackTime( pMHeader_a->iHour, pMHeader_a->iMinute, pMHeader_a->iSecond );

    /* Year may have unneeded century ambiguity */
    iYear = RayTime.iyear;
    if (iYear<50) 
      iYear+=2000;
    else if (iYear<1900)
      iYear+=1900;

    printf( "                Time:%s UTC", shhmmssddmonyyyy_r( &RayTime, sTimeBuffer ) );
    if (RayTime.iyear!=iYear)
      printf( " (correctable to %d)\n", iYear );
    else
      printf( "\n" );
  }
  printf( "            Timezone:%-2.2s\n", pMHeader_a->sTimeZone ); 
  printf( "             Azimuth:%4.2f degrees\n", fAz );
  printf( "           Elevation:%4.2f degrees\n", fEl );
  printf( "          Sweep Mode:%d\n", pMHeader_a->iSweepMode );
  printf( "         Fixed angle:%4.2f degrees\n", ((FLT8)pMHeader_a->iFixedAngle)/64.0 );
  printf( "          Sweep Rate:%d\n", pMHeader_a->iSweepRate );
  iYear = pMHeader_a->iConvertYear;
  if (iYear<50) 
    iYear+=2000;
  else if (iYear<1900)
    iYear+=1900;
  printf( "        Convert Date:%s", 
	  sddmonyyyy_r( pMHeader_a->iConvertYear, pMHeader_a->iConvertMonth, 
			pMHeader_a->iConvertDay, sTimeBuffer ) );
  if (iYear!=pMHeader_a->iConvertYear)
    printf( " (correctable to %d)\n", iYear );
  else
    printf( "\n" );
  printf( "    Convert Facility:%-8.8s\n", pMHeader_a->sConvertName );
  printf( "       No Data Value:0x%04hX\n", pMHeader_a->iNoDataValue);
  printf("\n" );
  return;

}
/* =====================================================
 * Return a string having a guarenteed null termination after
 * the specified number of characters.
 */
static char *sTailString
(const char *sString_a,
 SINT4 iMaxSize_a )
{
  static char sString_c[80];
  SINT4 iSize;
  iSize = MIN( 79, iMaxSize_a );
  strncpy( sString_c, sString_a, iSize );
  sString_c[iSize] = 0;

  return sString_c;

}
/* =====================================================
 * Print the optional header.  Will modify the input to byte-swap
 * the strings, if needed.
 */
static void PrintOptionalHeader
( struct uf_optional_header *pOpHeader_a,  /* Strings are byte swapped correctly */
  const struct ufview_options *pOptions_a,
  SINT2 iNoDataValue_a )
{
  if (LITTLE_END)
    {
      swap2_array( (SINT2*)pOpHeader_a, sizeof(*pOpHeader_a)/2 );
      swap2_array( (SINT2 *)pOpHeader_a->sProjectName, 8/2 );
      swap2_array( (SINT2 *)pOpHeader_a->sFieldTapeName, 8/2 );
    }
  if (!pOptions_a->lVerbose) return;

  printf( "==========UF Optional Header=========\n" );
  printf( "        Project name:%-8.8s\n", pOpHeader_a->sProjectName );
  if (pOpHeader_a->iBaselineAzimuth!=iNoDataValue_a)
    {
      FLT4 fAz;
      fAz = ((FLT4)pOpHeader_a->iBaselineAzimuth)/64.0;
      if (fAz<0.0) fAz+= 360.0;
      printf( "    Baseline azimuth:%5.2f\n", fAz );
    }
  else
    printf( "    Baseline azimuth:NO-DATA\n" );
  if (pOpHeader_a->iBaselineAzimuth!=iNoDataValue_a)
    {
      FLT4 fEl;
      fEl = ((FLT4)pOpHeader_a->iBaselineElevation)/64.0;
      printf( "  Baseline elevation:%5.2f\n", fEl );
    }
  else
    printf( "  Baseline elevation:NO-DATA\n" );
  printf( "Start of volume scan:%02d:%02d:%02d\n", pOpHeader_a->iVolumeScanHour,
	  pOpHeader_a->iVolumeScanMinute, pOpHeader_a->iVolumeScanSecond );
  printf( "     Field Tape Name:%-8.8s\n", pOpHeader_a->sFieldTapeName );
  printf( "                Flag:%d\n", pOpHeader_a->iFlag );
  printf("\n" );
  return;

}
/* =====================================================
 * Read and optionally print the data header.  Will modify the input to byte-swap
 * the strings, if needed.
 */
static void ReadDataHeader
(FILE  *pStream_a,         /* Stream to read from */
 SINT4 *pPosition_a,       /* Position within the record, must be updated */
 struct uf_data_header2 *pDataHeader_a,  
 const struct ufview_options *pOptions_a )
{
  SINT4 iMoment, iCount;

  /* Zero the whole structure because used size is variable */
  memset( pDataHeader_a, 0, sizeof(*pDataHeader_a) );
  iCount = fread( pDataHeader_a, 1, 6, pStream_a );
  if (iCount != 6) perror( "fread" );
  *pPosition_a += 6;
  if (LITTLE_END) swap2_array( (SINT2*)pDataHeader_a, 3 );
  
  if (pDataHeader_a->iFieldsThisRecord > UF_MAX_MOMENTS)
    {
      printf( "Warning: FieldsThisRecord value of %d exceeds max of %d\n",	      
	      pDataHeader_a->iFieldsThisRecord, UF_MAX_MOMENTS);
      pDataHeader_a->iFieldsThisRecord = UF_MAX_MOMENTS;
    }
  if (pOptions_a->lVerbose)
    {
      printf( "==========UF Data Header=========\n" );
      printf( "  Fields in this ray:%d\n", pDataHeader_a->iFieldsThisRay );
      printf( " Records in this ray:%d\n", pDataHeader_a->iRecordsThisRay );
      printf( "  Fields this record:%d\n", pDataHeader_a->iFieldsThisRecord );
    }

  /* Now loop through all the moments */
  for (iMoment=0; iMoment<pDataHeader_a->iFieldsThisRecord; iMoment++)
    {
      iCount = fread( &pDataHeader_a->Dsi[iMoment], 1, 4, pStream_a );
      if (iCount != 4) perror( "fread" );
      *pPosition_a += 4;
      if (LITTLE_END) swap2( &pDataHeader_a->Dsi[iMoment].iFieldHeaderPosition );
      if (pOptions_a->lVerbose)
	{
	  printf( "      Field %2d type:%-2.2s\n", iMoment,
		  pDataHeader_a->Dsi[iMoment].sDataType );
	  printf( "            Position:%d\n", pDataHeader_a->Dsi[iMoment].iFieldHeaderPosition );
	}
    }

  if (pOptions_a->lVerbose) printf("\n" );
  return;

}
/* =====================================================
 * Read and optionally print the field header.  Returns
 * field header correctly byte swapped.
 */
static void ReadFieldHeader
(FILE  *pStream_a,         /* Stream to read from */
 SINT4 *pPosition_a,       /* Position within the record, must be updated */
 struct uf_field_header2 *pFieldHeader_a,  
 const struct ufview_options *pOptions_a,
 const char sDataType_a[2] )
{
  SINT4 iReadSize, iCount;

  iReadSize = 2*19;
  if (0 == strncmp( "VR", sDataType_a, 2 )) iReadSize+=4;

  /* Zero the whole structure because used size is variable */
  memset( pFieldHeader_a, 0, sizeof(*pFieldHeader_a) );
  iCount = fread( pFieldHeader_a, 1, iReadSize, pStream_a );
  if (iCount != iReadSize) perror( "fread" );
  *pPosition_a += iReadSize;
  if (LITTLE_END)
    {
      swap2_array( (SINT2*)pFieldHeader_a, iReadSize/2 );
      swap2( pFieldHeader_a->sThresholdData );
      swap2( pFieldHeader_a->sEditCode );
    }
  
  if (pOptions_a->lVerbose)
    {
      FLT8 fRange, fPulseWidthMicroSec, fPrf;
      printf( "==========UF Field Header for %-2.2s=========\n", sDataType_a );
      printf( "       Data position:%d words\n", pFieldHeader_a->iDataPosition );
      printf( "        Scale factor:%d\n", pFieldHeader_a->iScaleFactor );
      fRange  = (FLT8)pFieldHeader_a->iStartRangeKm;
      fRange += ((FLT8)pFieldHeader_a->iStartRangeMeters)/1000.0;
      printf( "      Starting range:%5.3f km\n", fRange );
      printf( "         Bin spacing:%d meters\n", pFieldHeader_a->iBinSpacing );
      printf( "           Bin count:%d\n", pFieldHeader_a->iBinCount);
      fPulseWidthMicroSec = (1000.*(FLT8)pFieldHeader_a->iPulseWidth) / FSPEED_OF_LIGHT;
      printf( "         Pulse width:%d meters (%3.2f microseconds)\n", 
	      pFieldHeader_a->iPulseWidth, fPulseWidthMicroSec );
      printf( "   Horiz. beam width:%3.2f deg\n", ((FLT8)pFieldHeader_a->iBeamWidthH)/64.0 );
      printf( " Vertical beam width:%3.2f deg\n", ((FLT8)pFieldHeader_a->iBeamWidthV)/64.0 );
      printf( "  Receiver bandwidth:%d MHz\n", pFieldHeader_a->iBandWidth );
      switch(pFieldHeader_a->iPolarization)
	{
	case UF_POL_HORIZONTAL:
	  printf( "        Polarization:Horizontal\n" ); break;
	case UF_POL_VERTICAL:
	  printf( "        Polarization:Vertical\n" ); break;
	case UF_POL_CIRCULAR:
	  printf( "        Polarization:Circular\n" ); break;
	case UF_POL_ELLIPTICAL:
	  printf( "        Polarization:Elliptical\n" ); break;
	default:
	  printf( "        Polarization:UNKNOWN (%d)\n", pFieldHeader_a->iPolarization); break;
	}
      printf( "          Wavelength:%3.2f cm\n", ((FLT8)pFieldHeader_a->iWaveLength)/64.0 );
      printf( "         Sample size:%d\n", pFieldHeader_a->iSampleSize );
      printf( "      Threshold data:%-2.2s\n", pFieldHeader_a->sThresholdData );
      printf( "     Threshold value:%d\n", pFieldHeader_a->iThresholdValue );
      printf( "               Scale:%d\n", pFieldHeader_a->iScale );
      printf( "           Edit code:%-2.2s\n", pFieldHeader_a->sEditCode );
      fPrf = 0;
      if (pFieldHeader_a->iPRT>0) fPrf = 1000000./(FLT8)pFieldHeader_a->iPRT;
      
      printf( "                 PRT:%d microseconds (%3.1f Hertz)\n", pFieldHeader_a->iPRT, fPrf );
      printf( "        Bits per bin:%d\n", pFieldHeader_a->iBitsPerBin );
      if (0 == strncmp( "VR", sDataType_a, 2 ))
	{
	  FLT8 fNyquist;
	  fNyquist = ((FLT8)pFieldHeader_a->Fsi.VE.iNyquistVelocity)/
	    (FLT8)pFieldHeader_a->iScaleFactor;
	  printf( "    Nyquist velocity:%4.2f m/s\n", fNyquist ); 
	}
      printf("\n" );
      }

  return;

}
/* =====================================================
 * Optionally Read print the field data.
 */
static void ReadFieldData
(FILE  *pStream_a,         /* Stream to read from */
 SINT4 *pPosition_a,       /* Position within the record, must be updated */
 const struct uf_field_header2 *pFieldHeader_a,  
 const struct ufview_options *pOptions_a,
 const char sDataType_a[2] )
{
  SINT4 iReadSize, iBinCount, iCount;
  SINT2 iDataArray[MAX_BINS];

  if (!pOptions_a->lPrintData) return;

  /* Clip the maximum number of bins to display */
  iBinCount = pFieldHeader_a->iBinCount;
  if (iBinCount>MAX_BINS) iBinCount=MAX_BINS;

  iReadSize = 2*iBinCount;
  
  iCount = fread( iDataArray, 1, iReadSize, pStream_a );
  if (iCount != iReadSize) perror( "fread" );
  *pPosition_a += iReadSize;

  if (LITTLE_END)
    {
      swap2_array( iDataArray, iReadSize/2 );
    }
  
  printf( "=============UF Field Data for %-2.2s============\n", sDataType_a );
  PrintUfData( iDataArray, iBinCount, pFieldHeader_a->iScaleFactor,
	       UF_NO_DATA, pOptions_a->iLineLength );
  printf("\n" );

  return;

}
/* ===========================================================
 * Print a line of ray data, using formats that vary with the type of the
 * parameter.
 */
static void PrintUfData
( SINT2 iData_a[],
  SINT2 iBinCount_a,
  SINT2 iScaleFactor_a,
  SINT2 iNoDataValue_a,
  SINT4 iLineLength_a )
{
  SINT4 iBin, iValue;
  SINT4 iTotalLength, iThisLength;
  FLT8  fScale;
  char sThreshold[20];    /*String to display for threshold case */
  char sFormat[20];       /*Format string for data printing */
  char sThisString[20];   /*String to print */
  

  strcpy(sThreshold, "  -.- " ) ;
  strcpy(sFormat, "%5.1f " ) ;
  fScale = (FLT8)iScaleFactor_a;

  printf( "%4d:", 0 ); 
  iTotalLength=5;
  for (iBin=0; iBin<iBinCount_a; iBin++)
    {
      iValue = iData_a[iBin];
      if( iValue == iNoDataValue_a )
	strcpy( sThisString, sThreshold ) ;
      else
      	sprintf( sThisString, sFormat, ((FLT8)iValue)/fScale ) ;
      iThisLength = strlen(sThisString);
      if( iTotalLength+iThisLength > iLineLength_a )
	{
	  printf( "\n%4d:", iBin );
	  iTotalLength=5;
	}

      printf( "%s", sThisString );
      iTotalLength += iThisLength;
    }
  
  printf( "\n" ) ;
  return;
}

/* =========================
 * Byte swapping functions.
 */
static void swap2(void *word)
{
  unsigned char *byte;
  unsigned char temp;
  byte    = (unsigned char *)word;
  temp    = byte[0];
  byte[0] = byte[1];
  byte[1] = temp;
}

static void swap4(void *word)
{
  unsigned char *byte;
  unsigned char temp;
  byte    = (unsigned char *)word;
  temp    = byte[0];
  byte[0] = byte[3];
  byte[3] = temp;
  temp    = byte[1];
  byte[1] = byte[2];
  byte[2] = temp;
}

static void swap2_array
(SINT2 *buf, 
 SINT4 iCount_a )
{
  short *end_addr;
  end_addr = buf + iCount_a;
  while (buf < end_addr) 
    {
      swap2(buf);
      buf++;
    }
  return;
}
