/* ieeeflt - converts IEEE floating-point format to or from Unix format
 *
 * Note:  This is the Unix version
 *
 *		Version 1, D. Gudehus, Mar. 26, 2000
 *		Version 2, D. Gudehus, June 7, 2005
 *		Slight additional changes
 *
 * There are two subroutines in this module:  ieee2unix and unix2ieee for 
 * single precision. They are capable of converting a 32-bit ANSI/IEEE-754
 * floating-point number or numbers to standard Unix 32-bit floating format,
 * and vice versa.  This module was inspired by IEEEFLT.C for the VAX written
 * by Patrick Murphy.
 *
 * The calling sequence for a C program is: 
 * Method 1
 * #define MAX 1000
 * void ieee2unix (int ieee[], int *nreals, int *wswap, int *bswap);
 * main() {
 *   int i;
 *   union {
 *     int data_i;
 *     float data_f;
 *   } ieee[MAX];
 *   int nreals, bswap, wswap;
 *
 *   ieee2unix (data_i,&nreals,&bswap,&wswap)
 * }
 *   !  Returned floating point data is in ieee[i].data_f
 * Method 2
 * void ieee_unix(unsigned long int *, int *, int *, int *);
 * main() {
 *   char *buf;
 *   int nreals, bswap, wswap;
 *
 *   ieee2unix ((float *)buf,&nreals,&bswap,&wswap);
 *
 *
 * The calling sequence for a FORTRAN program is:
 *	PARAMETER MAX_NCOL=4096 
 *	INTEGER DATA_I(MAX_NCOL)
 *	INTEGER NREALS,BSWAP,WSWAP
 *	REAL DATA_R(MAX_NCOL)
 * The floating point values should be equivalenced to the integer values 
 * in the calling routine with a statement such as:
 *	EQUIVALENCE (DATA_I(1),DATA_R(1))
 *
 *	CALL IEEE2UNIX(DATA_I,NREALS,BSWAP,WSWAP)
 *
 * and the calling sequence for unix2ieee is identical.  The conversion is
 * done "in place".  If the original data is read as bytes, then the bytes
 * should be equivalenced to the integer array before calling the routines.
 *
 * This module includes optional byte/word swapping.  An IEEE word looks like:
 *  
 *    S EEEEEEEE FFFFFFFFFFFFFFFFFFFFFFF
 *    0 1      8 9                    31
 *
 * where S = the sign bit, E = the exponent bits, and F = the fraction bits.
 * If 0<E<255 then V=(-1)**S * 2 ** (E-127) * (1.F) where "1.F" is intended to 
 * represent the binary number created by prefixing F with an implicit leading 
 * 1 and a binary point.
 *
 *    0 00000000 00000000000000000000000 = 0
 *    1 00000000 00000000000000000000000 = -0
 *    
 *    0 11111111 00000000000000000000000 = Infinity
 *    1 11111111 00000000000000000000000 = -Infinity
 *
 * If E=255 and F is nonzero, then V=NaN (not a number)
 *
 *    0 10000000 00000000000000000000000 = +1 * 2**(128-127) * 1.0 = 2
 *    0 10000001 10100000000000000000000 = +1 * 2**(129-127) * 1.101 = 6.5
 *    1 10000001 10100000000000000000000 = -1 * 2**(129-127) * 1.101 = -6.5
 *
 * Values read in, e.g. from a National Instruments GPIB bus will in
 * general need to be word-swapped.  However, data read from a byte stream,
 * e.g. data read in image mode across a TCP/IP network FTP link, will not
 * have to be word swapped but will need byte-swapped.  Same for tape data.
 *
 *----------------------------------------------------------------------
 */

union fstruc {
  unsigned long int longword;
  short int words[2];			/* for swapping */
  char bytes[4];			/* "   "        */
} ;

void ieee2unix_ (buf, nreals, bswap, wswap)
  unsigned long int *buf;
  int *nreals, *bswap, *wswap;	/* pointers so Fortran calling possible */

{
  float temp;
  int	i;
  short int itemp;		/* for swapping words */
  char ctemp;			/* for swapping bytes */
  union fstruc ieee;

  if (*nreals < 1) 
    return;

  for (i=0; i<*nreals; i++) {
    ieee.longword = buf[i];		/* Uses int (flt can cause fault) */
    if (*bswap == 1) {
      ctemp = ieee.bytes[0];		/* byte swap (4 bytes) */
      ieee.bytes[0] = ieee.bytes[1];
      ieee.bytes[1] = ctemp;
      ctemp = ieee.bytes[2];
      ieee.bytes[2] = ieee.bytes[3];
      ieee.bytes[3] = ctemp;
    }
    if (*wswap == 1) {
      itemp = ieee.words[0];		/* word swap */
      ieee.words[0] = ieee.words[1];
      ieee.words[1] = itemp;
    }

    buf[i] = ieee.longword;		/* puts Unix value back */
  }
}

void unix2ieee_(buf, nreals, wswap, bswap)
  unsigned long int *buf;
  int *nreals, *wswap, *bswap; /* pointers so Fortran calling possible */
{
  float temp;
  int	i;
  short int itemp;		/* for swapping words */
  char ctemp;			/* for swapping bytes */
  union fstruc unixf;

  if (*nreals < 1) 
    return;
  for (i=0; i<*nreals; i++) {
    unixf.longword = buf[i];
    if (*bswap == 1) {		/* byte swap needed */
      ctemp = unixf.bytes[0];
      unixf.bytes[0] = unixf.bytes[1];
      unixf.bytes[1] = ctemp;
      ctemp = unixf.bytes[2];
      unixf.bytes[2] = unixf.bytes[3];
      unixf.bytes[3] = ctemp;
    }
    if (*wswap == 1) {		/* word swap needed */
      itemp = unixf.words[0];
      unixf.words[0] = unixf.words[1];
      unixf.words[1] = itemp;
    }
    buf[i] = unixf.longword;	/* puts IEEE value back */
  }
}
